diff options
Diffstat (limited to 'compat/inet_pton.c')
| -rw-r--r-- | compat/inet_pton.c | 230 | 
1 files changed, 230 insertions, 0 deletions
diff --git a/compat/inet_pton.c b/compat/inet_pton.c new file mode 100644 index 0000000000000..15780d0b7a174 --- /dev/null +++ b/compat/inet_pton.c @@ -0,0 +1,230 @@ +/*	$KAME: inet_pton.c,v 1.5 2001/08/20 02:32:40 itojun Exp $	*/ + +/* Copyright (c) 1996 by Internet Software Consortium. + * + * 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 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. + */ + +#include <config.h> + +#include <string.h> +#include <stdio.h> +#include <errno.h> + +/* + * WARNING: Don't even consider trying to compile this on a system where + * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX. + */ + +static int	inet_pton4 (const char *src, uint8_t *dst); +static int	inet_pton6 (const char *src, uint8_t *dst); + +/* + * + * The definitions we might miss. + * + */ +#ifndef NS_INT16SZ +#define	NS_INT16SZ	2 +#endif + +#ifndef NS_IN6ADDRSZ +#define NS_IN6ADDRSZ 16 +#endif + +#ifndef NS_INADDRSZ +#define NS_INADDRSZ 4 +#endif + +/* int + * inet_pton(af, src, dst) + *	convert from presentation format (which usually means ASCII printable) + *	to network format (which is usually some kind of binary format). + * return: + *	1 if the address was valid for the specified address family + *	0 if the address wasn't valid (`dst' is untouched in this case) + *	-1 if some other error occurred (`dst' is untouched in this case, too) + * author: + *	Paul Vixie, 1996. + */ +int +inet_pton(af, src, dst) +	int af; +	const char *src; +	void *dst; +{ +	switch (af) { +	case AF_INET: +		return (inet_pton4(src, dst)); +	case AF_INET6: +		return (inet_pton6(src, dst)); +	default: +#ifdef EAFNOSUPPORT +		errno = EAFNOSUPPORT; +#else +		errno = ENOSYS; +#endif +		return (-1); +	} +	/* NOTREACHED */ +} + +/* int + * inet_pton4(src, dst) + *	like inet_aton() but without all the hexadecimal and shorthand. + * return: + *	1 if `src' is a valid dotted quad, else 0. + * notice: + *	does not touch `dst' unless it's returning 1. + * author: + *	Paul Vixie, 1996. + */ +static int +inet_pton4(src, dst) +	const char *src; +	uint8_t *dst; +{ +	static const char digits[] = "0123456789"; +	int saw_digit, octets, ch; +	uint8_t tmp[NS_INADDRSZ], *tp; + +	saw_digit = 0; +	octets = 0; +	*(tp = tmp) = 0; +	while ((ch = *src++) != '\0') { +		const char *pch; + +		if ((pch = strchr(digits, ch)) != NULL) { +			uint32_t new = *tp * 10 + (pch - digits); + +			if (new > 255) +				return (0); +			*tp = new; +			if (! saw_digit) { +				if (++octets > 4) +					return (0); +				saw_digit = 1; +			} +		} else if (ch == '.' && saw_digit) { +			if (octets == 4) +				return (0); +			*++tp = 0; +			saw_digit = 0; +		} else +			return (0); +	} +	if (octets < 4) +		return (0); + +	memcpy(dst, tmp, NS_INADDRSZ); +	return (1); +} + +/* int + * inet_pton6(src, dst) + *	convert presentation level address to network order binary form. + * return: + *	1 if `src' is a valid [RFC1884 2.2] address, else 0. + * notice: + *	(1) does not touch `dst' unless it's returning 1. + *	(2) :: in a full address is silently ignored. + * credit: + *	inspired by Mark Andrews. + * author: + *	Paul Vixie, 1996. + */ +static int +inet_pton6(src, dst) +	const char *src; +	uint8_t *dst; +{ +	static const char xdigits_l[] = "0123456789abcdef", +			  xdigits_u[] = "0123456789ABCDEF"; +	uint8_t tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; +	const char *xdigits, *curtok; +	int ch, saw_xdigit; +	uint32_t val; + +	memset((tp = tmp), '\0', NS_IN6ADDRSZ); +	endp = tp + NS_IN6ADDRSZ; +	colonp = NULL; +	/* Leading :: requires some special handling. */ +	if (*src == ':') +		if (*++src != ':') +			return (0); +	curtok = src; +	saw_xdigit = 0; +	val = 0; +	while ((ch = *src++) != '\0') { +		const char *pch; + +		if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) +			pch = strchr((xdigits = xdigits_u), ch); +		if (pch != NULL) { +			val <<= 4; +			val |= (pch - xdigits); +			if (val > 0xffff) +				return (0); +			saw_xdigit = 1; +			continue; +		} +		if (ch == ':') { +			curtok = src; +			if (!saw_xdigit) { +				if (colonp) +					return (0); +				colonp = tp; +				continue; +			} +			if (tp + NS_INT16SZ > endp) +				return (0); +			*tp++ = (uint8_t) (val >> 8) & 0xff; +			*tp++ = (uint8_t) val & 0xff; +			saw_xdigit = 0; +			val = 0; +			continue; +		} +		if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && +		    inet_pton4(curtok, tp) > 0) { +			tp += NS_INADDRSZ; +			saw_xdigit = 0; +			break;	/* '\0' was seen by inet_pton4(). */ +		} +		return (0); +	} +	if (saw_xdigit) { +		if (tp + NS_INT16SZ > endp) +			return (0); +		*tp++ = (uint8_t) (val >> 8) & 0xff; +		*tp++ = (uint8_t) val & 0xff; +	} +	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; + +		for (i = 1; i <= n; i++) { +			endp[- i] = colonp[n - i]; +			colonp[n - i] = 0; +		} +		tp = endp; +	} +	if (tp != endp) +		return (0); +	memcpy(dst, tmp, NS_IN6ADDRSZ); +	return (1); +}  | 
