Blame support/support_format_addrinfo.c

Packit Service 82fcde
/* Convert struct addrinfo values to a string.
Packit Service 82fcde
   Copyright (C) 2016-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
   License as published by the Free Software Foundation; either
Packit Service 82fcde
   version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library; if not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#include <support/format_nss.h>
Packit Service 82fcde
Packit Service 82fcde
#include <arpa/inet.h>
Packit Service 82fcde
#include <errno.h>
Packit Service 82fcde
#include <stdio.h>
Packit Service 82fcde
#include <stdlib.h>
Packit Service 82fcde
#include <support/support.h>
Packit Service 82fcde
#include <support/xmemstream.h>
Packit Service 82fcde
Packit Service 82fcde
static size_t
Packit Service 82fcde
socket_address_length (int family)
Packit Service 82fcde
{
Packit Service 82fcde
  switch (family)
Packit Service 82fcde
    {
Packit Service 82fcde
    case AF_INET:
Packit Service 82fcde
      return sizeof (struct sockaddr_in);
Packit Service 82fcde
    case AF_INET6:
Packit Service 82fcde
      return sizeof (struct sockaddr_in6);
Packit Service 82fcde
    default:
Packit Service 82fcde
      return -1;
Packit Service 82fcde
    }
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static void
Packit Service 82fcde
format_ai_flags_1 (FILE *out, struct addrinfo *ai, int flag, const char *name,
Packit Service 82fcde
                   int * flags_printed)
Packit Service 82fcde
{
Packit Service 82fcde
  if ((ai->ai_flags & flag) != 0)
Packit Service 82fcde
    fprintf (out, " %s", name);
Packit Service 82fcde
  *flags_printed |= flag;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static void
Packit Service 82fcde
format_ai_flags (FILE *out, struct addrinfo *ai)
Packit Service 82fcde
{
Packit Service 82fcde
  if (ai == NULL)
Packit Service 82fcde
    return;
Packit Service 82fcde
Packit Service 82fcde
  if (ai->ai_flags != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      fprintf (out, "flags:");
Packit Service 82fcde
      int flags_printed = 0;
Packit Service 82fcde
#define FLAG(flag) format_ai_flags_1 (out, ai, flag, #flag, &flags_printed)
Packit Service 82fcde
      FLAG (AI_PASSIVE);
Packit Service 82fcde
      FLAG (AI_CANONNAME);
Packit Service 82fcde
      FLAG (AI_NUMERICHOST);
Packit Service 82fcde
      FLAG (AI_V4MAPPED);
Packit Service 82fcde
      FLAG (AI_ALL);
Packit Service 82fcde
      FLAG (AI_ADDRCONFIG);
Packit Service 82fcde
      FLAG (AI_IDN);
Packit Service 82fcde
      FLAG (AI_CANONIDN);
Packit Service 82fcde
      FLAG (AI_NUMERICSERV);
Packit Service 82fcde
#undef FLAG
Packit Service 82fcde
      int remaining = ai->ai_flags & ~flags_printed;
Packit Service 82fcde
      if (remaining != 0)
Packit Service 82fcde
        fprintf (out, " %08x", remaining);
Packit Service 82fcde
      fprintf (out, "\n");
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Report flag mismatches within the list.  */
Packit Service 82fcde
  int flags = ai->ai_flags;
Packit Service 82fcde
  int index = 1;
Packit Service 82fcde
  ai = ai->ai_next;
Packit Service 82fcde
  while (ai != NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      if (ai->ai_flags != flags)
Packit Service 82fcde
        fprintf (out, "error: flags at %d: 0x%x expected, 0x%x actual\n",
Packit Service 82fcde
                 index, flags, ai->ai_flags);
Packit Service 82fcde
      ai = ai->ai_next;
Packit Service 82fcde
      ++index;
Packit Service 82fcde
    }
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static void
Packit Service 82fcde
format_ai_canonname (FILE *out, struct addrinfo *ai)
Packit Service 82fcde
{
Packit Service 82fcde
  if (ai == NULL)
Packit Service 82fcde
    return;
Packit Service 82fcde
  if (ai->ai_canonname != NULL)
Packit Service 82fcde
    fprintf (out, "canonname: %s\n", ai->ai_canonname);
Packit Service 82fcde
Packit Service 82fcde
  /* Report incorrectly set ai_canonname fields on subsequent list
Packit Service 82fcde
     entries.  */
Packit Service 82fcde
  int index = 1;
Packit Service 82fcde
  ai = ai->ai_next;
Packit Service 82fcde
  while (ai != NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      if (ai->ai_canonname != NULL)
Packit Service 82fcde
        fprintf (out, "error: canonname set at %d: %s\n",
Packit Service 82fcde
                 index, ai->ai_canonname);
Packit Service 82fcde
      ai = ai->ai_next;
Packit Service 82fcde
      ++index;
Packit Service 82fcde
    }
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static void
Packit Service 82fcde
format_ai_one (FILE *out, struct addrinfo *ai)
Packit Service 82fcde
{
Packit Service 82fcde
  {
Packit Service 82fcde
    char type_buf[32];
Packit Service 82fcde
    const char *type_str;
Packit Service 82fcde
    char proto_buf[32];
Packit Service 82fcde
    const char *proto_str;
Packit Service 82fcde
Packit Service 82fcde
    /* ai_socktype */
Packit Service 82fcde
    switch (ai->ai_socktype)
Packit Service 82fcde
      {
Packit Service 82fcde
      case SOCK_RAW:
Packit Service 82fcde
        type_str = "RAW";
Packit Service 82fcde
        break;
Packit Service 82fcde
      case SOCK_DGRAM:
Packit Service 82fcde
        type_str = "DGRAM";
Packit Service 82fcde
        break;
Packit Service 82fcde
      case SOCK_STREAM:
Packit Service 82fcde
        type_str = "STREAM";
Packit Service 82fcde
        break;
Packit Service 82fcde
      default:
Packit Service 82fcde
        snprintf (type_buf, sizeof (type_buf), "%d", ai->ai_socktype);
Packit Service 82fcde
        type_str = type_buf;
Packit Service 82fcde
      }
Packit Service 82fcde
Packit Service 82fcde
    /* ai_protocol */
Packit Service 82fcde
    switch (ai->ai_protocol)
Packit Service 82fcde
      {
Packit Service 82fcde
      case IPPROTO_IP:
Packit Service 82fcde
        proto_str = "IP";
Packit Service 82fcde
        break;
Packit Service 82fcde
      case IPPROTO_UDP:
Packit Service 82fcde
        proto_str = "UDP";
Packit Service 82fcde
        break;
Packit Service 82fcde
      case IPPROTO_TCP:
Packit Service 82fcde
        proto_str = "TCP";
Packit Service 82fcde
        break;
Packit Service 82fcde
      default:
Packit Service 82fcde
        snprintf (proto_buf, sizeof (proto_buf), "%d", ai->ai_protocol);
Packit Service 82fcde
        proto_str = proto_buf;
Packit Service 82fcde
      }
Packit Service 82fcde
    fprintf (out, "address: %s/%s", type_str, proto_str);
Packit Service 82fcde
  }
Packit Service 82fcde
Packit Service 82fcde
  /* ai_addrlen */
Packit Service 82fcde
  if (ai->ai_addrlen != socket_address_length (ai->ai_family))
Packit Service 82fcde
    {
Packit Service 82fcde
      char *family = support_format_address_family (ai->ai_family);
Packit Service 82fcde
      fprintf (out, "error: invalid address length %d for %s\n",
Packit Service 82fcde
               ai->ai_addrlen, family);
Packit Service 82fcde
      free (family);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* ai_addr */
Packit Service 82fcde
  {
Packit Service 82fcde
    char buf[128];
Packit Service 82fcde
    uint16_t port;
Packit Service 82fcde
    const char *ret;
Packit Service 82fcde
    switch (ai->ai_family)
Packit Service 82fcde
      {
Packit Service 82fcde
      case AF_INET:
Packit Service 82fcde
        {
Packit Service 82fcde
          struct sockaddr_in *sin = (struct sockaddr_in *) ai->ai_addr;
Packit Service 82fcde
          ret = inet_ntop (AF_INET, &sin->sin_addr, buf, sizeof (buf));
Packit Service 82fcde
          port = sin->sin_port;
Packit Service 82fcde
        }
Packit Service 82fcde
        break;
Packit Service 82fcde
      case AF_INET6:
Packit Service 82fcde
        {
Packit Service 82fcde
          struct sockaddr_in6 *sin = (struct sockaddr_in6 *) ai->ai_addr;
Packit Service 82fcde
          ret = inet_ntop (AF_INET6, &sin->sin6_addr, buf, sizeof (buf));
Packit Service 82fcde
          port = sin->sin6_port;
Packit Service 82fcde
        }
Packit Service 82fcde
        break;
Packit Service 82fcde
      default:
Packit Service 82fcde
        errno = EAFNOSUPPORT;
Packit Service 82fcde
        ret = NULL;
Packit Service 82fcde
      }
Packit Service 82fcde
    if (ret == NULL)
Packit Service 82fcde
        fprintf (out, "error: inet_top failed: %m\n");
Packit Service 82fcde
    else
Packit Service 82fcde
      fprintf (out, " %s %u\n", buf, ntohs (port));
Packit Service 82fcde
  }
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Format all the addresses in one address family.  */
Packit Service 82fcde
static void
Packit Service 82fcde
format_ai_family (FILE *out, struct addrinfo *ai, int family)
Packit Service 82fcde
{
Packit Service 82fcde
  while (ai)
Packit Service 82fcde
    {
Packit Service 82fcde
      if (ai->ai_family == family)
Packit Service 82fcde
        format_ai_one (out, ai);
Packit Service 82fcde
      ai = ai->ai_next;
Packit Service 82fcde
    }
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
char *
Packit Service 82fcde
support_format_addrinfo (struct addrinfo *ai, int ret)
Packit Service 82fcde
{
Packit Service 82fcde
  int errno_copy = errno;
Packit Service 82fcde
Packit Service 82fcde
  struct xmemstream mem;
Packit Service 82fcde
  xopen_memstream (&mem;;
Packit Service 82fcde
  if (ret != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      const char *errmsg = gai_strerror (ret);
Packit Service 82fcde
      if (strcmp (errmsg, "Unknown error") == 0)
Packit Service 82fcde
        fprintf (mem.out, "error: Unknown error %d\n", ret);
Packit Service 82fcde
      else
Packit Service 82fcde
        fprintf (mem.out, "error: %s\n", errmsg);
Packit Service 82fcde
      if (ret == EAI_SYSTEM)
Packit Service 82fcde
        {
Packit Service 82fcde
          errno = errno_copy;
Packit Service 82fcde
          fprintf (mem.out, "error: %m\n");
Packit Service 82fcde
        }
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      format_ai_flags (mem.out, ai);
Packit Service 82fcde
      format_ai_canonname (mem.out, ai);
Packit Service 82fcde
      format_ai_family (mem.out, ai, AF_INET);
Packit Service 82fcde
      format_ai_family (mem.out, ai, AF_INET6);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  xfclose_memstream (&mem;;
Packit Service 82fcde
  return mem.buffer;
Packit Service 82fcde
}