Blame support/support_format_addrinfo.c

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