(root)/
glibc-2.38/
resolv/
inet_pton.c
       1  /* Copyright (C) 1996-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <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 <arpa/inet.h>
      36  #include <arpa/nameser.h>
      37  #include <ctype.h>
      38  #include <errno.h>
      39  #include <netinet/in.h>
      40  #include <resolv/resolv-internal.h>
      41  #include <string.h>
      42  #include <sys/socket.h>
      43  #include <sys/types.h>
      44  
      45  static int inet_pton4 (const char *src, const char *src_end, u_char *dst);
      46  static int inet_pton6 (const char *src, const char *src_end, u_char *dst);
      47  
      48  int
      49  __inet_pton_length (int af, const char *src, size_t srclen, void *dst)
      50  {
      51    switch (af)
      52      {
      53      case AF_INET:
      54        return inet_pton4 (src, src + srclen, dst);
      55      case AF_INET6:
      56        return inet_pton6 (src, src + srclen, dst);
      57      default:
      58        __set_errno (EAFNOSUPPORT);
      59        return -1;
      60      }
      61  }
      62  libc_hidden_def (__inet_pton_length)
      63  
      64  /* Like __inet_pton_length, but use strlen (SRC) as the length of
      65     SRC.  */
      66  int
      67  __inet_pton (int af, const char *src, void *dst)
      68  {
      69    return __inet_pton_length (af, src, strlen (src), dst);
      70  }
      71  libc_hidden_def (__inet_pton)
      72  weak_alias (__inet_pton, inet_pton)
      73  libc_hidden_weak (inet_pton)
      74  
      75  /* Like inet_aton but without all the hexadecimal, octal and shorthand
      76     (and trailing garbage is not ignored).  Return 1 if SRC is a valid
      77     dotted quad, else 0.  This function does not touch DST unless it's
      78     returning 1.
      79     Author: Paul Vixie, 1996.  */
      80  static int
      81  inet_pton4 (const char *src, const char *end, unsigned char *dst)
      82  {
      83    int saw_digit, octets, ch;
      84    unsigned char tmp[NS_INADDRSZ], *tp;
      85  
      86    saw_digit = 0;
      87    octets = 0;
      88    *(tp = tmp) = 0;
      89    while (src < end)
      90      {
      91        ch = *src++;
      92        if (ch >= '0' && ch <= '9')
      93          {
      94            unsigned int new = *tp * 10 + (ch - '0');
      95  
      96            if (saw_digit && *tp == 0)
      97              return 0;
      98            if (new > 255)
      99              return 0;
     100            *tp = new;
     101            if (! saw_digit)
     102              {
     103                if (++octets > 4)
     104                  return 0;
     105                saw_digit = 1;
     106              }
     107          }
     108        else if (ch == '.' && saw_digit)
     109          {
     110            if (octets == 4)
     111              return 0;
     112            *++tp = 0;
     113            saw_digit = 0;
     114          }
     115        else
     116          return 0;
     117      }
     118    if (octets < 4)
     119      return 0;
     120    memcpy (dst, tmp, NS_INADDRSZ);
     121    return 1;
     122  }
     123  
     124  /* Return the value of CH as a hexadecimal digit, or -1 if it is a
     125     different type of character.  */
     126  static int
     127  hex_digit_value (char ch)
     128  {
     129    if ('0' <= ch && ch <= '9')
     130      return ch - '0';
     131    if ('a' <= ch && ch <= 'f')
     132      return ch - 'a' + 10;
     133    if ('A' <= ch && ch <= 'F')
     134      return ch - 'A' + 10;
     135    return -1;
     136  }
     137  
     138  /* Convert presentation-level IPv6 address to network order binary
     139     form.  Return 1 if SRC is a valid [RFC1884 2.2] address, else 0.
     140     This function does not touch DST unless it's returning 1.
     141     Author: Paul Vixie, 1996.  Inspired by Mark Andrews.  */
     142  static int
     143  inet_pton6 (const char *src, const char *src_endp, unsigned char *dst)
     144  {
     145    unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
     146    const char *curtok;
     147    int ch;
     148    size_t xdigits_seen;	/* Number of hex digits since colon.  */
     149    unsigned int val;
     150  
     151    tp = memset (tmp, '\0', NS_IN6ADDRSZ);
     152    endp = tp + NS_IN6ADDRSZ;
     153    colonp = NULL;
     154  
     155    /* Leading :: requires some special handling.  */
     156    if (src == src_endp)
     157      return 0;
     158    if (*src == ':')
     159      {
     160        ++src;
     161        if (src == src_endp || *src != ':')
     162          return 0;
     163      }
     164  
     165    curtok = src;
     166    xdigits_seen = 0;
     167    val = 0;
     168    while (src < src_endp)
     169      {
     170        ch = *src++;
     171        int digit = hex_digit_value (ch);
     172        if (digit >= 0)
     173  	{
     174  	  if (xdigits_seen == 4)
     175  	    return 0;
     176  	  val <<= 4;
     177  	  val |= digit;
     178  	  if (val > 0xffff)
     179  	    return 0;
     180  	  ++xdigits_seen;
     181  	  continue;
     182  	}
     183        if (ch == ':')
     184  	{
     185  	  curtok = src;
     186  	  if (xdigits_seen == 0)
     187  	    {
     188  	      if (colonp)
     189  		return 0;
     190  	      colonp = tp;
     191  	      continue;
     192  	    }
     193  	  else if (src == src_endp)
     194              return 0;
     195  	  if (tp + NS_INT16SZ > endp)
     196  	    return 0;
     197  	  *tp++ = (unsigned char) (val >> 8) & 0xff;
     198  	  *tp++ = (unsigned char) val & 0xff;
     199  	  xdigits_seen = 0;
     200  	  val = 0;
     201  	  continue;
     202  	}
     203        if (ch == '.' && ((tp + NS_INADDRSZ) <= endp)
     204            && inet_pton4 (curtok, src_endp, tp) > 0)
     205  	{
     206  	  tp += NS_INADDRSZ;
     207  	  xdigits_seen = 0;
     208  	  break;  /* '\0' was seen by inet_pton4.  */
     209  	}
     210        return 0;
     211      }
     212    if (xdigits_seen > 0)
     213      {
     214        if (tp + NS_INT16SZ > endp)
     215  	return 0;
     216        *tp++ = (unsigned char) (val >> 8) & 0xff;
     217        *tp++ = (unsigned char) val & 0xff;
     218      }
     219    if (colonp != NULL)
     220      {
     221        /* Replace :: with zeros.  */
     222        if (tp == endp)
     223          /* :: would expand to a zero-width field.  */
     224          return 0;
     225        size_t n = tp - colonp;
     226        memmove (endp - n, colonp, n);
     227        memset (colonp, 0, endp - n - colonp);
     228        tp = endp;
     229      }
     230    if (tp != endp)
     231      return 0;
     232    memcpy (dst, tmp, NS_IN6ADDRSZ);
     233    return 1;
     234  }