(root)/
glibc-2.38/
resolv/
inet_net_pton.c
       1  /*
       2   * Copyright (c) 1996,1999 by Internet Software Consortium.
       3   *
       4   * Permission to use, copy, modify, and distribute this software for any
       5   * purpose with or without fee is hereby granted, provided that the above
       6   * copyright notice and this permission notice appear in all copies.
       7   *
       8   * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
       9   * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
      10   * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
      11   * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
      12   * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
      13   * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
      14   * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
      15   * SOFTWARE.
      16   */
      17  
      18  #include <sys/types.h>
      19  #include <sys/socket.h>
      20  #include <netinet/in.h>
      21  #include <arpa/inet.h>
      22  
      23  #include <assert.h>
      24  #include <ctype.h>
      25  #include <errno.h>
      26  #include <stdio.h>
      27  #include <string.h>
      28  #include <stdlib.h>
      29  
      30  #ifdef SPRINTF_CHAR
      31  # define SPRINTF(x) strlen(sprintf/**/x)
      32  #else
      33  # define SPRINTF(x) ((size_t)sprintf x)
      34  #endif
      35  
      36  static int	inet_net_pton_ipv4 (const char *src, u_char *dst,
      37  				    size_t size) __THROW;
      38  
      39  /*
      40   * static int
      41   * inet_net_pton(af, src, dst, size)
      42   *	convert network number from presentation to network format.
      43   *	accepts hex octets, hex strings, decimal octets, and /CIDR.
      44   *	"size" is in bytes and describes "dst".
      45   * return:
      46   *	number of bits, either imputed classfully or specified with /CIDR,
      47   *	or -1 if some failure occurred (check errno).  ENOENT means it was
      48   *	not a valid network specification.
      49   * author:
      50   *	Paul Vixie (ISC), June 1996
      51   */
      52  int
      53  inet_net_pton (int af, const char *src, void *dst, size_t size)
      54  {
      55  	switch (af) {
      56  	case AF_INET:
      57  		return (inet_net_pton_ipv4(src, dst, size));
      58  	default:
      59  		__set_errno (EAFNOSUPPORT);
      60  		return (-1);
      61  	}
      62  }
      63  
      64  /*
      65   * static int
      66   * inet_net_pton_ipv4(src, dst, size)
      67   *	convert IPv4 network number from presentation to network format.
      68   *	accepts hex octets, hex strings, decimal octets, and /CIDR.
      69   *	"size" is in bytes and describes "dst".
      70   * return:
      71   *	number of bits, either imputed classfully or specified with /CIDR,
      72   *	or -1 if some failure occurred (check errno).  ENOENT means it was
      73   *	not an IPv4 network specification.
      74   * note:
      75   *	network byte order assumed.  this means 192.5.5.240/28 has
      76   *	0b11110000 in its fourth octet.
      77   * author:
      78   *	Paul Vixie (ISC), June 1996
      79   */
      80  static int
      81  inet_net_pton_ipv4 (const char *src, u_char *dst, size_t size)
      82  {
      83  	static const char xdigits[] = "0123456789abcdef";
      84  	int n, ch, tmp, dirty, bits;
      85  	const u_char *odst = dst;
      86  
      87  	ch = *src++;
      88  	if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
      89  	    && isascii(src[1]) && isxdigit(src[1])) {
      90  		/* Hexadecimal: Eat nybble string. */
      91  		if (size <= 0)
      92  			goto emsgsize;
      93  		dirty = 0;
      94  		tmp = 0;	/* To calm down gcc.  */
      95  		src++;	/* skip x or X. */
      96  		while (isxdigit((ch = *src++))) {
      97  			ch = _tolower(ch);
      98  			n = (const char *) __rawmemchr(xdigits, ch) - xdigits;
      99  			assert(n >= 0 && n <= 15);
     100  			if (dirty == 0)
     101  				tmp = n;
     102  			else
     103  				tmp = (tmp << 4) | n;
     104  			if (++dirty == 2) {
     105  				if (size-- <= 0)
     106  					goto emsgsize;
     107  				*dst++ = (u_char) tmp;
     108  				dirty = 0;
     109  			}
     110  		}
     111  		if (dirty) {  /* Odd trailing nybble? */
     112  			if (size-- <= 0)
     113  				goto emsgsize;
     114  			*dst++ = (u_char) (tmp << 4);
     115  		}
     116  	} else if (isascii(ch) && isdigit(ch)) {
     117  		/* Decimal: eat dotted digit string. */
     118  		for (;;) {
     119  			tmp = 0;
     120  			do {
     121  				n = ((const char *) __rawmemchr(xdigits, ch)
     122  				     - xdigits);
     123  				assert(n >= 0 && n <= 9);
     124  				tmp *= 10;
     125  				tmp += n;
     126  				if (tmp > 255)
     127  					goto enoent;
     128  			} while (isascii((ch = *src++)) && isdigit(ch));
     129  			if (size-- <= 0)
     130  				goto emsgsize;
     131  			*dst++ = (u_char) tmp;
     132  			if (ch == '\0' || ch == '/')
     133  				break;
     134  			if (ch != '.')
     135  				goto enoent;
     136  			ch = *src++;
     137  			if (!isascii(ch) || !isdigit(ch))
     138  				goto enoent;
     139  		}
     140  	} else
     141  		goto enoent;
     142  
     143  	bits = -1;
     144  	if (ch == '/' && isascii(src[0]) && isdigit(src[0]) && dst > odst) {
     145  		/* CIDR width specifier.  Nothing can follow it. */
     146  		ch = *src++;	/* Skip over the /. */
     147  		bits = 0;
     148  		do {
     149  			n = (const char *) __rawmemchr(xdigits, ch) - xdigits;
     150  			assert(n >= 0 && n <= 9);
     151  			bits *= 10;
     152  			bits += n;
     153  		} while (isascii((ch = *src++)) && isdigit(ch));
     154  		if (ch != '\0')
     155  			goto enoent;
     156  		if (bits > 32)
     157  			goto emsgsize;
     158  	}
     159  
     160  	/* Fiery death and destruction unless we prefetched EOS. */
     161  	if (ch != '\0')
     162  		goto enoent;
     163  
     164  	/* If nothing was written to the destination, we found no address. */
     165  	if (dst == odst)
     166  		goto enoent;
     167  	/* If no CIDR spec was given, infer width from net class. */
     168  	if (bits == -1) {
     169  		if (*odst >= 240)	/* Class E */
     170  			bits = 32;
     171  		else if (*odst >= 224)	/* Class D */
     172  			bits = 4;
     173  		else if (*odst >= 192)	/* Class C */
     174  			bits = 24;
     175  		else if (*odst >= 128)	/* Class B */
     176  			bits = 16;
     177  		else			/* Class A */
     178  			bits = 8;
     179  		/* If imputed mask is narrower than specified octets, widen. */
     180  		if (bits >= 8 && bits < ((dst - odst) * 8))
     181  			bits = (dst - odst) * 8;
     182  	}
     183  	/* Extend network to cover the actual mask. */
     184  	while (bits > ((dst - odst) * 8)) {
     185  		if (size-- <= 0)
     186  			goto emsgsize;
     187  		*dst++ = '\0';
     188  	}
     189  	return (bits);
     190  
     191   enoent:
     192  	__set_errno (ENOENT);
     193  	return (-1);
     194  
     195   emsgsize:
     196  	__set_errno (EMSGSIZE);
     197  	return (-1);
     198  }