(root)/
glibc-2.38/
support/
support_format_addrinfo.c
       1  /* Convert struct addrinfo values to a string.
       2     Copyright (C) 2016-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <support/format_nss.h>
      20  
      21  #include <arpa/inet.h>
      22  #include <errno.h>
      23  #include <stdio.h>
      24  #include <stdlib.h>
      25  #include <support/support.h>
      26  #include <support/xmemstream.h>
      27  
      28  static size_t
      29  socket_address_length (int family)
      30  {
      31    switch (family)
      32      {
      33      case AF_INET:
      34        return sizeof (struct sockaddr_in);
      35      case AF_INET6:
      36        return sizeof (struct sockaddr_in6);
      37      default:
      38        return -1;
      39      }
      40  }
      41  
      42  static void
      43  format_ai_flags_1 (FILE *out, struct addrinfo *ai, int flag, const char *name,
      44                     int * flags_printed)
      45  {
      46    if ((ai->ai_flags & flag) != 0)
      47      fprintf (out, " %s", name);
      48    *flags_printed |= flag;
      49  }
      50  
      51  static void
      52  format_ai_flags (FILE *out, struct addrinfo *ai)
      53  {
      54    if (ai == NULL)
      55      return;
      56  
      57    if (ai->ai_flags != 0)
      58      {
      59        fprintf (out, "flags:");
      60        int flags_printed = 0;
      61  #define FLAG(flag) format_ai_flags_1 (out, ai, flag, #flag, &flags_printed)
      62        FLAG (AI_PASSIVE);
      63        FLAG (AI_CANONNAME);
      64        FLAG (AI_NUMERICHOST);
      65        FLAG (AI_V4MAPPED);
      66        FLAG (AI_ALL);
      67        FLAG (AI_ADDRCONFIG);
      68        FLAG (AI_IDN);
      69        FLAG (AI_CANONIDN);
      70        FLAG (AI_NUMERICSERV);
      71  #undef FLAG
      72        int remaining = ai->ai_flags & ~flags_printed;
      73        if (remaining != 0)
      74          fprintf (out, " %08x", remaining);
      75        fprintf (out, "\n");
      76      }
      77  
      78    /* Report flag mismatches within the list.  */
      79    int flags = ai->ai_flags;
      80    int index = 1;
      81    ai = ai->ai_next;
      82    while (ai != NULL)
      83      {
      84        if (ai->ai_flags != flags)
      85          fprintf (out, "error: flags at %d: 0x%x expected, 0x%x actual\n",
      86                   index, flags, ai->ai_flags);
      87        ai = ai->ai_next;
      88        ++index;
      89      }
      90  }
      91  
      92  static void
      93  format_ai_canonname (FILE *out, struct addrinfo *ai)
      94  {
      95    if (ai == NULL)
      96      return;
      97    if (ai->ai_canonname != NULL)
      98      fprintf (out, "canonname: %s\n", ai->ai_canonname);
      99  
     100    /* Report incorrectly set ai_canonname fields on subsequent list
     101       entries.  */
     102    int index = 1;
     103    ai = ai->ai_next;
     104    while (ai != NULL)
     105      {
     106        if (ai->ai_canonname != NULL)
     107          fprintf (out, "error: canonname set at %d: %s\n",
     108                   index, ai->ai_canonname);
     109        ai = ai->ai_next;
     110        ++index;
     111      }
     112  }
     113  
     114  static void
     115  format_ai_one (FILE *out, struct addrinfo *ai)
     116  {
     117    {
     118      char type_buf[32];
     119      const char *type_str;
     120      char proto_buf[32];
     121      const char *proto_str;
     122  
     123      /* ai_socktype */
     124      switch (ai->ai_socktype)
     125        {
     126        case SOCK_RAW:
     127          type_str = "RAW";
     128          break;
     129        case SOCK_DGRAM:
     130          type_str = "DGRAM";
     131          break;
     132        case SOCK_STREAM:
     133          type_str = "STREAM";
     134          break;
     135        default:
     136          snprintf (type_buf, sizeof (type_buf), "%d", ai->ai_socktype);
     137          type_str = type_buf;
     138        }
     139  
     140      /* ai_protocol */
     141      switch (ai->ai_protocol)
     142        {
     143        case IPPROTO_IP:
     144          proto_str = "IP";
     145          break;
     146        case IPPROTO_UDP:
     147          proto_str = "UDP";
     148          break;
     149        case IPPROTO_TCP:
     150          proto_str = "TCP";
     151          break;
     152        default:
     153          snprintf (proto_buf, sizeof (proto_buf), "%d", ai->ai_protocol);
     154          proto_str = proto_buf;
     155        }
     156      fprintf (out, "address: %s/%s", type_str, proto_str);
     157    }
     158  
     159    /* ai_addrlen */
     160    if (ai->ai_addrlen != socket_address_length (ai->ai_family))
     161      {
     162        char *family = support_format_address_family (ai->ai_family);
     163        fprintf (out, "error: invalid address length %d for %s\n",
     164                 ai->ai_addrlen, family);
     165        free (family);
     166      }
     167  
     168    /* ai_addr */
     169    {
     170      char buf[128];
     171      uint16_t port;
     172      const char *ret;
     173      switch (ai->ai_family)
     174        {
     175        case AF_INET:
     176          {
     177            struct sockaddr_in *sin = (struct sockaddr_in *) ai->ai_addr;
     178            ret = inet_ntop (AF_INET, &sin->sin_addr, buf, sizeof (buf));
     179            port = sin->sin_port;
     180          }
     181          break;
     182        case AF_INET6:
     183          {
     184            struct sockaddr_in6 *sin = (struct sockaddr_in6 *) ai->ai_addr;
     185            ret = inet_ntop (AF_INET6, &sin->sin6_addr, buf, sizeof (buf));
     186            port = sin->sin6_port;
     187          }
     188          break;
     189        default:
     190          errno = EAFNOSUPPORT;
     191          ret = NULL;
     192        }
     193      if (ret == NULL)
     194          fprintf (out, "error: inet_top failed: %m\n");
     195      else
     196        fprintf (out, " %s %u\n", buf, ntohs (port));
     197    }
     198  }
     199  
     200  /* Format all the addresses in one address family.  */
     201  static void
     202  format_ai_family (FILE *out, struct addrinfo *ai, int family)
     203  {
     204    while (ai)
     205      {
     206        if (ai->ai_family == family)
     207          format_ai_one (out, ai);
     208        ai = ai->ai_next;
     209      }
     210  }
     211  
     212  char *
     213  support_format_addrinfo (struct addrinfo *ai, int ret)
     214  {
     215    int errno_copy = errno;
     216  
     217    struct xmemstream mem;
     218    xopen_memstream (&mem);
     219    if (ret != 0)
     220      {
     221        const char *errmsg = gai_strerror (ret);
     222        if (strcmp (errmsg, "Unknown error") == 0)
     223          fprintf (mem.out, "error: Unknown error %d\n", ret);
     224        else
     225          fprintf (mem.out, "error: %s\n", errmsg);
     226        if (ret == EAI_SYSTEM)
     227          {
     228            errno = errno_copy;
     229            fprintf (mem.out, "error: %m\n");
     230          }
     231      }
     232    else
     233      {
     234        format_ai_flags (mem.out, ai);
     235        format_ai_canonname (mem.out, ai);
     236        format_ai_family (mem.out, ai, AF_INET);
     237        format_ai_family (mem.out, ai, AF_INET6);
     238      }
     239  
     240    xfclose_memstream (&mem);
     241    return mem.buffer;
     242  }