diff options
Diffstat (limited to 'lib/libc/inet/inet_net_pton.c')
| -rw-r--r-- | lib/libc/inet/inet_net_pton.c | 363 | 
1 files changed, 105 insertions, 258 deletions
| diff --git a/lib/libc/inet/inet_net_pton.c b/lib/libc/inet/inet_net_pton.c index 970dde8f1f35..18a5fbc4b1d2 100644 --- a/lib/libc/inet/inet_net_pton.c +++ b/lib/libc/inet/inet_net_pton.c @@ -1,20 +1,23 @@ -/*- - * SPDX-License-Identifier: ISC +/*	$OpenBSD: inet_net_pton.c,v 1.14 2022/12/27 17:10:06 jmc Exp $	*/ + +/* + * Copyright (c) 2012 by Gilles Chehade <gilles@openbsd.org> + * Copyright (c) 1996,1999 by Internet Software Consortium.   * - * Copyright (C) 2004, 2005, 2008  Internet Systems Consortium, Inc. ("ISC") - * Copyright (C) 1996, 1998, 1999, 2001, 2003  Internet Software Consortium. + * SPDX-License-Identifier: ISC   * - * Permission to use, copy, modify, and/or distribute this software for any + * Permission to use, copy, modify, and distribute this software for any   * purpose with or without fee is hereby granted, provided that the above   * copyright notice and this permission notice appear in all copies.   * - * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH - * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, - * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE - * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE.   */  #if defined(LIBC_SCCS) && !defined(lint) @@ -25,7 +28,6 @@ static const char rcsid[] = "$Id: inet_net_pton.c,v 1.10 2008/11/14 02:36:51 mar  #include <sys/types.h>  #include <sys/socket.h>  #include <netinet/in.h> -#include <arpa/nameser.h>  #include <arpa/inet.h>  #include <assert.h> @@ -37,13 +39,37 @@ static const char rcsid[] = "$Id: inet_net_pton.c,v 1.10 2008/11/14 02:36:51 mar  #include "port_after.h" -#ifdef SPRINTF_CHAR -# define SPRINTF(x) strlen(sprintf/**/x) -#else -# define SPRINTF(x) ((size_t)sprintf x) -#endif +static int	inet_net_pton_ipv4(const char *, u_char *, size_t); +static int	inet_net_pton_ipv6(const char *, u_char *, size_t); -/*% +/* + * static int + * inet_net_pton(af, src, dst, size) + *	convert network number from presentation to network format. + *	accepts hex octets, hex strings, decimal octets, and /CIDR. + *	"size" is in bytes and describes "dst". + * return: + *	number of bits, either imputed classfully or specified with /CIDR, + *	or -1 if some failure occurred (check errno).  ENOENT means it was + *	not a valid network specification. + * author: + *	Paul Vixie (ISC), June 1996 + */ +int +inet_net_pton(int af, const char *src, void *dst, size_t size) +{ +	switch (af) { +	case AF_INET: +		return (inet_net_pton_ipv4(src, dst, size)); +	case AF_INET6: +		return (inet_net_pton_ipv6(src, dst, size)); +	default: +		errno = EAFNOSUPPORT; +		return (-1); +	} +} + +/*   * static int   * inet_net_pton_ipv4(src, dst, size)   *	convert IPv4 network number from presentation to network format. @@ -60,22 +86,24 @@ static const char rcsid[] = "$Id: inet_net_pton.c,v 1.10 2008/11/14 02:36:51 mar   *	Paul Vixie (ISC), June 1996   */  static int -inet_net_pton_ipv4(const char *src, u_char *dst, size_t size) { -	static const char xdigits[] = "0123456789abcdef"; -	static const char digits[] = "0123456789"; -	int n, ch, tmp = 0, dirty, bits; +inet_net_pton_ipv4(const char *src, u_char *dst, size_t size) +{ +	static const char +		xdigits[] = "0123456789abcdef", +		digits[] = "0123456789"; +	int n, ch, tmp, dirty, bits;  	const u_char *odst = dst; -	ch = *src++; +	ch = (unsigned char)*src++;  	if (ch == '0' && (src[0] == 'x' || src[0] == 'X') -	    && isascii((unsigned char)(src[1])) -	    && isxdigit((unsigned char)(src[1]))) { +	    && isascii((unsigned char)src[1]) && isxdigit((unsigned char)src[1])) {  		/* Hexadecimal: Eat nybble string. */ -		if (size <= 0U) +		if (size == 0)  			goto emsgsize; -		dirty = 0; -		src++;	/*%< skip x or X. */ -		while ((ch = *src++) != '\0' && isascii(ch) && isxdigit(ch)) { +		tmp = 0, dirty = 0; +		src++;	/* skip x or X. */ +		while ((ch = (unsigned char)*src++) != '\0' && +		    isascii(ch) && isxdigit(ch)) {  			if (isupper(ch))  				ch = tolower(ch);  			n = strchr(xdigits, ch) - xdigits; @@ -85,14 +113,14 @@ inet_net_pton_ipv4(const char *src, u_char *dst, size_t size) {  			else  				tmp = (tmp << 4) | n;  			if (++dirty == 2) { -				if (size-- <= 0U) +				if (size-- == 0)  					goto emsgsize;  				*dst++ = (u_char) tmp;  				dirty = 0;  			}  		} -		if (dirty) {  /*%< Odd trailing nybble? */ -			if (size-- <= 0U) +		if (dirty) {  /* Odd trailing nybble? */ +			if (size-- == 0)  				goto emsgsize;  			*dst++ = (u_char) (tmp << 4);  		} @@ -107,16 +135,16 @@ inet_net_pton_ipv4(const char *src, u_char *dst, size_t size) {  				tmp += n;  				if (tmp > 255)  					goto enoent; -			} while ((ch = *src++) != '\0' && +			} while ((ch = (unsigned char)*src++) != '\0' &&  				 isascii(ch) && isdigit(ch)); -			if (size-- <= 0U) +			if (size-- == 0)  				goto emsgsize;  			*dst++ = (u_char) tmp;  			if (ch == '\0' || ch == '/')  				break;  			if (ch != '.')  				goto enoent; -			ch = *src++; +			ch = (unsigned char)*src++;  			if (!isascii(ch) || !isdigit(ch))  				goto enoent;  		} @@ -124,10 +152,10 @@ inet_net_pton_ipv4(const char *src, u_char *dst, size_t size) {  		goto enoent;  	bits = -1; -	if (ch == '/' && isascii((unsigned char)(src[0])) && -	    isdigit((unsigned char)(src[0])) && dst > odst) { +	if (ch == '/' && isascii((unsigned char)src[0]) && +	    isdigit((unsigned char)src[0]) && dst > odst) {  		/* CIDR width specifier.  Nothing can follow it. */ -		ch = *src++;	/*%< Skip over the /. */ +		ch = (unsigned char)*src++;	/* Skip over the /. */  		bits = 0;  		do {  			n = strchr(digits, ch) - digits; @@ -135,8 +163,9 @@ inet_net_pton_ipv4(const char *src, u_char *dst, size_t size) {  			bits *= 10;  			bits += n;  			if (bits > 32) -				goto enoent; -		} while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch)); +				goto emsgsize; +		} while ((ch = (unsigned char)*src++) != '\0' && +			 isascii(ch) && isdigit(ch));  		if (ch != '\0')  			goto enoent;  	} @@ -150,29 +179,23 @@ inet_net_pton_ipv4(const char *src, u_char *dst, size_t size) {  		goto enoent;  	/* If no CIDR spec was given, infer width from net class. */  	if (bits == -1) { -		if (*odst >= 240)	/*%< Class E */ +		if (*odst >= 240)	/* Class E */  			bits = 32; -		else if (*odst >= 224)	/*%< Class D */ -			bits = 8; -		else if (*odst >= 192)	/*%< Class C */ +		else if (*odst >= 224)	/* Class D */ +			bits = 4; +		else if (*odst >= 192)	/* Class C */  			bits = 24; -		else if (*odst >= 128)	/*%< Class B */ +		else if (*odst >= 128)	/* Class B */  			bits = 16; -		else			/*%< Class A */ +		else			/* Class A */  			bits = 8;  		/* If imputed mask is narrower than specified octets, widen. */  		if (bits < ((dst - odst) * 8))  			bits = (dst - odst) * 8; -		/* -		 * If there are no additional bits specified for a class D -		 * address adjust bits to 4. -		 */ -		if (bits == 8 && *odst == 224) -			bits = 4;  	}  	/* Extend network to cover the actual mask. */  	while (bits > ((dst - odst) * 8)) { -		if (size-- <= 0U) +		if (size-- == 0)  			goto emsgsize;  		*dst++ = '\0';  	} @@ -187,222 +210,48 @@ inet_net_pton_ipv4(const char *src, u_char *dst, size_t size) {  	return (-1);  } -static int -getbits(const char *src, int *bitsp) { -	static const char digits[] = "0123456789"; -	int n; -	int val; -	char ch; - -	val = 0; -	n = 0; -	while ((ch = *src++) != '\0') { -		const char *pch; - -		pch = strchr(digits, ch); -		if (pch != NULL) { -			if (n++ != 0 && val == 0)	/*%< no leading zeros */ -				return (0); -			val *= 10; -			val += (pch - digits); -			if (val > 128)			/*%< range */ -				return (0); -			continue; -		} -		return (0); -	} -	if (n == 0) -		return (0); -	*bitsp = val; -	return (1); -}  static int -getv4(const char *src, u_char *dst, int *bitsp) { -	static const char digits[] = "0123456789"; -	u_char *odst = dst; -	int n; -	u_int val; -	char ch; - -	val = 0; -	n = 0; -	while ((ch = *src++) != '\0') { -		const char *pch; +inet_net_pton_ipv6(const char *src, u_char *dst, size_t size) +{ +	struct in6_addr	 in6; +	int		 ret; +	int		 bits; +	size_t		 bytes; +	char		 buf[INET6_ADDRSTRLEN + sizeof("/128")]; +	char		*sep; +	const char	*errstr; -		pch = strchr(digits, ch); -		if (pch != NULL) { -			if (n++ != 0 && val == 0)	/*%< no leading zeros */ -				return (0); -			val *= 10; -			val += (pch - digits); -			if (val > 255)			/*%< range */ -				return (0); -			continue; -		} -		if (ch == '.' || ch == '/') { -			if (dst - odst > 3)		/*%< too many octets? */ -				return (0); -			*dst++ = val; -			if (ch == '/') -				return (getbits(src, bitsp)); -			val = 0; -			n = 0; -			continue; -		} -		return (0); +	if (strlcpy(buf, src, sizeof buf) >= sizeof buf) { +		errno = EMSGSIZE; +		return (-1);  	} -	if (n == 0) -		return (0); -	if (dst - odst > 3)		/*%< too many octets? */ -		return (0); -	*dst++ = val; -	return (1); -} -static int -inet_net_pton_ipv6(const char *src, u_char *dst, size_t size) { -	static const char xdigits_l[] = "0123456789abcdef", -			  xdigits_u[] = "0123456789ABCDEF"; -	u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; -	const char *xdigits, *curtok; -	int ch, saw_xdigit; -	u_int val; -	int digits; -	int bits; -	size_t bytes; -	int words; -	int ipv4; +	sep = strchr(buf, '/'); +	if (sep != NULL) +		*sep++ = '\0'; -	memset((tp = tmp), '\0', NS_IN6ADDRSZ); -	endp = tp + NS_IN6ADDRSZ; -	colonp = NULL; -	/* Leading :: requires some special handling. */ -	if (*src == ':') -		if (*++src != ':') -			goto enoent; -	curtok = src; -	saw_xdigit = 0; -	val = 0; -	digits = 0; -	bits = -1; -	ipv4 = 0; -	while ((ch = *src++) != '\0') { -		const char *pch; +	ret = inet_pton(AF_INET6, buf, &in6); +	if (ret != 1) +		return (-1); -		if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) -			pch = strchr((xdigits = xdigits_u), ch); -		if (pch != NULL) { -			val <<= 4; -			val |= (pch - xdigits); -			if (++digits > 4) -				goto enoent; -			saw_xdigit = 1; -			continue; -		} -		if (ch == ':') { -			curtok = src; -			if (!saw_xdigit) { -				if (colonp) -					goto enoent; -				colonp = tp; -				continue; -			} else if (*src == '\0') -				goto enoent; -			if (tp + NS_INT16SZ > endp) -				return (0); -			*tp++ = (u_char) (val >> 8) & 0xff; -			*tp++ = (u_char) val & 0xff; -			saw_xdigit = 0; -			digits = 0; -			val = 0; -			continue; -		} -		if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && -		     getv4(curtok, tp, &bits) > 0) { -			tp += NS_INADDRSZ; -			saw_xdigit = 0; -			ipv4 = 1; -			break;	/*%< '\\0' was seen by inet_pton4(). */ -		} -		if (ch == '/' && getbits(src, &bits) > 0) -			break; -		goto enoent; -	} -	if (saw_xdigit) { -		if (tp + NS_INT16SZ > endp) -			goto enoent; -		*tp++ = (u_char) (val >> 8) & 0xff; -		*tp++ = (u_char) val & 0xff; -	} -	if (bits == -1) +	if (sep == NULL)  		bits = 128; - -	words = (bits + 15) / 16; -	if (words < 2) -		words = 2; -	if (ipv4) -		words = 8; -	endp =  tmp + 2 * words; - -	if (colonp != NULL) { -		/* -		 * Since some memmove()'s erroneously fail to handle -		 * overlapping regions, we'll do the shift by hand. -		 */ -		const int n = tp - colonp; -		int i; - -		if (tp == endp) -			goto enoent; -		for (i = 1; i <= n; i++) { -			endp[- i] = colonp[n - i]; -			colonp[n - i] = 0; +	else { +		bits = strtonum(sep, 0, 128, &errstr); +		if (errstr) { +			errno = EINVAL; +			return (-1);  		} -		tp = endp;  	} -	if (tp != endp) -		goto enoent;  	bytes = (bits + 7) / 8; -	if (bytes > size) -		goto emsgsize; -	memcpy(dst, tmp, bytes); -	return (bits); - - enoent: -	errno = ENOENT; -	return (-1); - - emsgsize: -	errno = EMSGSIZE; -	return (-1); -} - -/*% - * int - * inet_net_pton(af, src, dst, size) - *	convert network number from presentation to network format. - *	accepts hex octets, hex strings, decimal octets, and /CIDR. - *	"size" is in bytes and describes "dst". - * return: - *	number of bits, either imputed classfully or specified with /CIDR, - *	or -1 if some failure occurred (check errno).  ENOENT means it was - *	not a valid network specification. - * author: - *	Paul Vixie (ISC), June 1996 - */ -int -inet_net_pton(int af, const char *src, void *dst, size_t size) { -	switch (af) { -	case AF_INET: -		return (inet_net_pton_ipv4(src, dst, size)); -	case AF_INET6: -		return (inet_net_pton_ipv6(src, dst, size)); -	default: -		errno = EAFNOSUPPORT; +	if (bytes > size) { +		errno = EMSGSIZE;  		return (-1);  	} +	memcpy(dst, &in6.s6_addr, bytes); +	return (bits);  }  /* @@ -411,5 +260,3 @@ inet_net_pton(int af, const char *src, void *dst, size_t size) {   */  #undef inet_net_pton  __weak_reference(__inet_net_pton, inet_net_pton); - -/*! \file */ | 
