(root)/
gettext-0.22.4/
gettext-tools/
gnulib-lib/
inet_ntop.c
       1  /* inet_ntop.c -- convert IPv4 and IPv6 addresses from binary to text form
       2  
       3     Copyright (C) 2005-2006, 2008-2023 Free Software Foundation, Inc.
       4  
       5     This file is free software: you can redistribute it and/or modify
       6     it under the terms of the GNU Lesser General Public License as
       7     published by the Free Software Foundation; either version 2.1 of the
       8     License, or (at your option) any later version.
       9  
      10     This file 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
      13     GNU Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public License
      16     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      17  
      18  /*
      19   * Copyright (c) 1996-1999 by Internet Software Consortium.
      20   *
      21   * Permission to use, copy, modify, and distribute this software for any
      22   * purpose with or without fee is hereby granted, provided that the above
      23   * copyright notice and this permission notice appear in all copies.
      24   *
      25   * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
      26   * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
      27   * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
      28   * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
      29   * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
      30   * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
      31   * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
      32   * SOFTWARE.
      33   */
      34  
      35  #include <config.h>
      36  
      37  /* Specification.  */
      38  #include <arpa/inet.h>
      39  
      40  /* Use this to suppress gcc's "...may be used before initialized" warnings.
      41     Beware: The Code argument must not contain commas.  */
      42  #ifndef IF_LINT
      43  # if defined GCC_LINT || defined lint
      44  #  define IF_LINT(Code) Code
      45  # else
      46  #  define IF_LINT(Code) /* empty */
      47  # endif
      48  #endif
      49  
      50  #if HAVE_DECL_INET_NTOP
      51  
      52  # undef inet_ntop
      53  
      54  const char *
      55  rpl_inet_ntop (int af, const void *restrict src,
      56                 char *restrict dst, socklen_t cnt)
      57  {
      58    return inet_ntop (af, src, dst, cnt);
      59  }
      60  
      61  #else
      62  
      63  # include <stdio.h>
      64  # include <string.h>
      65  # include <errno.h>
      66  
      67  # define NS_IN6ADDRSZ 16
      68  # define NS_INT16SZ 2
      69  
      70  /*
      71   * WARNING: Don't even consider trying to compile this on a system where
      72   * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
      73   */
      74  typedef int verify_int_size[4 <= sizeof (int) ? 1 : -1];
      75  
      76  static const char *inet_ntop4 (const unsigned char *src, char *dst, socklen_t size);
      77  # if HAVE_IPV6
      78  static const char *inet_ntop6 (const unsigned char *src, char *dst, socklen_t size);
      79  # endif
      80  
      81  
      82  /* char *
      83   * inet_ntop(af, src, dst, size)
      84   *      convert a network format address to presentation format.
      85   * return:
      86   *      pointer to presentation format address ('dst'), or NULL (see errno).
      87   * author:
      88   *      Paul Vixie, 1996.
      89   */
      90  const char *
      91  inet_ntop (int af, const void *restrict src,
      92             char *restrict dst, socklen_t cnt)
      93  {
      94    switch (af)
      95      {
      96  # if HAVE_IPV4
      97      case AF_INET:
      98        return (inet_ntop4 (src, dst, cnt));
      99  # endif
     100  
     101  # if HAVE_IPV6
     102      case AF_INET6:
     103        return (inet_ntop6 (src, dst, cnt));
     104  # endif
     105  
     106      default:
     107        errno = EAFNOSUPPORT;
     108        return (NULL);
     109      }
     110    /* NOTREACHED */
     111  }
     112  
     113  /* const char *
     114   * inet_ntop4(src, dst, size)
     115   *      format an IPv4 address
     116   * return:
     117   *      'dst' (as a const)
     118   * notes:
     119   *      (1) uses no statics
     120   *      (2) takes a u_char* not an in_addr as input
     121   * author:
     122   *      Paul Vixie, 1996.
     123   */
     124  static const char *
     125  inet_ntop4 (const unsigned char *src, char *dst, socklen_t size)
     126  {
     127    char tmp[sizeof "255.255.255.255"];
     128    int len;
     129  
     130    len = sprintf (tmp, "%u.%u.%u.%u", src[0], src[1], src[2], src[3]);
     131    if (len < 0)
     132      return NULL;
     133  
     134    if (len > size)
     135      {
     136        errno = ENOSPC;
     137        return NULL;
     138      }
     139  
     140    return strcpy (dst, tmp);
     141  }
     142  
     143  # if HAVE_IPV6
     144  
     145  /* const char *
     146   * inet_ntop6(src, dst, size)
     147   *      convert IPv6 binary address into presentation (printable) format
     148   * author:
     149   *      Paul Vixie, 1996.
     150   */
     151  static const char *
     152  inet_ntop6 (const unsigned char *src, char *dst, socklen_t size)
     153  {
     154    /*
     155     * Note that int32_t and int16_t need only be "at least" large enough
     156     * to contain a value of the specified size.  On some systems, like
     157     * Crays, there is no such thing as an integer variable with 16 bits.
     158     * Keep this in mind if you think this function should have been coded
     159     * to use pointer overlays.  All the world's not a VAX.
     160     */
     161    char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
     162    struct
     163    {
     164      int base, len;
     165    } best, cur;
     166    unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ];
     167    int i;
     168  
     169    /*
     170     * Preprocess:
     171     *      Copy the input (bytewise) array into a wordwise array.
     172     *      Find the longest run of 0x00's in src[] for :: shorthanding.
     173     */
     174    memset (words, '\0', sizeof words);
     175    for (i = 0; i < NS_IN6ADDRSZ; i += 2)
     176      words[i / 2] = (src[i] << 8) | src[i + 1];
     177    best.base = -1;
     178    cur.base = -1;
     179    IF_LINT(best.len = 0);
     180    IF_LINT(cur.len = 0);
     181    for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++)
     182      {
     183        if (words[i] == 0)
     184          {
     185            if (cur.base == -1)
     186              cur.base = i, cur.len = 1;
     187            else
     188              cur.len++;
     189          }
     190        else
     191          {
     192            if (cur.base != -1)
     193              {
     194                if (best.base == -1 || cur.len > best.len)
     195                  best = cur;
     196                cur.base = -1;
     197              }
     198          }
     199      }
     200    if (cur.base != -1)
     201      {
     202        if (best.base == -1 || cur.len > best.len)
     203          best = cur;
     204      }
     205    if (best.base != -1 && best.len < 2)
     206      best.base = -1;
     207  
     208    /*
     209     * Format the result.
     210     */
     211    tp = tmp;
     212    for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++)
     213      {
     214        /* Are we inside the best run of 0x00's? */
     215        if (best.base != -1 && i >= best.base && i < (best.base + best.len))
     216          {
     217            if (i == best.base)
     218              *tp++ = ':';
     219            continue;
     220          }
     221        /* Are we following an initial run of 0x00s or any real hex? */
     222        if (i != 0)
     223          *tp++ = ':';
     224        /* Is this address an encapsulated IPv4? */
     225        if (i == 6 && best.base == 0 &&
     226            (best.len == 6 || (best.len == 5 && words[5] == 0xffff)))
     227          {
     228            if (!inet_ntop4 (src + 12, tp, sizeof tmp - (tp - tmp)))
     229              return (NULL);
     230            tp += strlen (tp);
     231            break;
     232          }
     233        {
     234          int len = sprintf (tp, "%x", words[i]);
     235          if (len < 0)
     236            return NULL;
     237          tp += len;
     238        }
     239      }
     240    /* Was it a trailing run of 0x00's? */
     241    if (best.base != -1 && (best.base + best.len) ==
     242        (NS_IN6ADDRSZ / NS_INT16SZ))
     243      *tp++ = ':';
     244    *tp++ = '\0';
     245  
     246    /*
     247     * Check for overflow, copy, and we're done.
     248     */
     249    if ((socklen_t) (tp - tmp) > size)
     250      {
     251        errno = ENOSPC;
     252        return NULL;
     253      }
     254  
     255    return strcpy (dst, tmp);
     256  }
     257  
     258  # endif
     259  
     260  #endif