xref: /freebsd-src/contrib/tcpdump/strtoaddr.c (revision 0a7e5f1f02aad2ff5fff1c60f44c6975fd07e1d9)
13340d773SGleb Smirnoff /*
23340d773SGleb Smirnoff  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
33340d773SGleb Smirnoff  * Copyright (c) 1996,1999 by Internet Software Consortium.
43340d773SGleb Smirnoff  *
53340d773SGleb Smirnoff  * Permission to use, copy, modify, and distribute this software for any
63340d773SGleb Smirnoff  * purpose with or without fee is hereby granted, provided that the above
73340d773SGleb Smirnoff  * copyright notice and this permission notice appear in all copies.
83340d773SGleb Smirnoff  *
93340d773SGleb Smirnoff  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
103340d773SGleb Smirnoff  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
113340d773SGleb Smirnoff  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
123340d773SGleb Smirnoff  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
133340d773SGleb Smirnoff  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
143340d773SGleb Smirnoff  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
153340d773SGleb Smirnoff  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
163340d773SGleb Smirnoff  */
173340d773SGleb Smirnoff 
18*ee67461eSJoseph Mingrone #include <config.h>
193340d773SGleb Smirnoff 
20*ee67461eSJoseph Mingrone #include "netdissect-stdinc.h"
213340d773SGleb Smirnoff #include <stddef.h>
223340d773SGleb Smirnoff #include <string.h>
233340d773SGleb Smirnoff 
24*ee67461eSJoseph Mingrone #include "netdissect-ctype.h"
25*ee67461eSJoseph Mingrone 
263340d773SGleb Smirnoff #include "strtoaddr.h"
273340d773SGleb Smirnoff 
283340d773SGleb Smirnoff #ifndef NS_INADDRSZ
293340d773SGleb Smirnoff #define NS_INADDRSZ	4	/* IPv4 T_A */
303340d773SGleb Smirnoff #endif
313340d773SGleb Smirnoff 
323340d773SGleb Smirnoff #ifndef NS_IN6ADDRSZ
333340d773SGleb Smirnoff #define NS_IN6ADDRSZ	16	/* IPv6 T_AAAA */
343340d773SGleb Smirnoff #endif
353340d773SGleb Smirnoff 
363340d773SGleb Smirnoff #ifndef NS_INT16SZ
373340d773SGleb Smirnoff #define NS_INT16SZ	2	/* #/bytes of data in a uint16_t */
383340d773SGleb Smirnoff #endif
393340d773SGleb Smirnoff 
403340d773SGleb Smirnoff /*%
413340d773SGleb Smirnoff  * WARNING: Don't even consider trying to compile this on a system where
423340d773SGleb Smirnoff  * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
433340d773SGleb Smirnoff  */
443340d773SGleb Smirnoff 
453340d773SGleb Smirnoff /* int
463340d773SGleb Smirnoff  * strtoaddr(src, dst)
473340d773SGleb Smirnoff  *	convert presentation level IPv4 address to network order binary form.
483340d773SGleb Smirnoff  * return:
493340d773SGleb Smirnoff  *	1 if `src' is a valid input, else 0.
503340d773SGleb Smirnoff  * notice:
513340d773SGleb Smirnoff  *	does not touch `dst' unless it's returning 1.
523340d773SGleb Smirnoff  * author:
533340d773SGleb Smirnoff  *	Paul Vixie, 1996.
543340d773SGleb Smirnoff  */
553340d773SGleb Smirnoff int
563340d773SGleb Smirnoff strtoaddr(const char *src, void *dst)
573340d773SGleb Smirnoff {
583340d773SGleb Smirnoff 	uint32_t val;
593340d773SGleb Smirnoff 	u_int digit;
603340d773SGleb Smirnoff 	ptrdiff_t n;
613340d773SGleb Smirnoff 	unsigned char c;
623340d773SGleb Smirnoff 	u_int parts[4];
633340d773SGleb Smirnoff 	u_int *pp = parts;
643340d773SGleb Smirnoff 
653340d773SGleb Smirnoff 	c = *src;
663340d773SGleb Smirnoff 	for (;;) {
673340d773SGleb Smirnoff 		/*
683340d773SGleb Smirnoff 		 * Collect number up to ``.''.
693340d773SGleb Smirnoff 		 * Values are specified as for C:
703340d773SGleb Smirnoff 		 * 0x=hex, 0=octal, isdigit=decimal.
713340d773SGleb Smirnoff 		 */
72*ee67461eSJoseph Mingrone 		if (!ND_ASCII_ISDIGIT(c))
733340d773SGleb Smirnoff 			return (0);
743340d773SGleb Smirnoff 		val = 0;
753340d773SGleb Smirnoff 		if (c == '0') {
763340d773SGleb Smirnoff 			c = *++src;
773340d773SGleb Smirnoff 			if (c == 'x' || c == 'X')
783340d773SGleb Smirnoff 				return (0);
79*ee67461eSJoseph Mingrone 			else if (ND_ASCII_ISDIGIT(c) && c != '9')
803340d773SGleb Smirnoff 				return (0);
813340d773SGleb Smirnoff 		}
823340d773SGleb Smirnoff 		for (;;) {
83*ee67461eSJoseph Mingrone 			if (ND_ASCII_ISDIGIT(c)) {
843340d773SGleb Smirnoff 				digit = c - '0';
853340d773SGleb Smirnoff 				val = (val * 10) + digit;
863340d773SGleb Smirnoff 				c = *++src;
873340d773SGleb Smirnoff 			} else
883340d773SGleb Smirnoff 				break;
893340d773SGleb Smirnoff 		}
903340d773SGleb Smirnoff 		if (c == '.') {
913340d773SGleb Smirnoff 			/*
923340d773SGleb Smirnoff 			 * Internet format:
933340d773SGleb Smirnoff 			 *	a.b.c.d
943340d773SGleb Smirnoff 			 *	a.b.c	(with c treated as 16 bits)
953340d773SGleb Smirnoff 			 *	a.b	(with b treated as 24 bits)
963340d773SGleb Smirnoff 			 *	a	(with a treated as 32 bits)
973340d773SGleb Smirnoff 			 */
983340d773SGleb Smirnoff 			if (pp >= parts + 3)
993340d773SGleb Smirnoff 				return (0);
1003340d773SGleb Smirnoff 			*pp++ = val;
1013340d773SGleb Smirnoff 			c = *++src;
1023340d773SGleb Smirnoff 		} else
1033340d773SGleb Smirnoff 			break;
1043340d773SGleb Smirnoff 	}
1053340d773SGleb Smirnoff 	/*
1063340d773SGleb Smirnoff 	 * Check for trailing characters.
1073340d773SGleb Smirnoff 	 */
108*ee67461eSJoseph Mingrone 	if (c != '\0' && c != ' ' && c != '\t')
1093340d773SGleb Smirnoff 		return (0);
1103340d773SGleb Smirnoff 	/*
1113340d773SGleb Smirnoff 	 * Find the number of parts specified.
1123340d773SGleb Smirnoff 	 * It must be 4; we only support dotted quads, we don't
1133340d773SGleb Smirnoff 	 * support shorthand.
1143340d773SGleb Smirnoff 	 */
1153340d773SGleb Smirnoff 	n = pp - parts + 1;
1163340d773SGleb Smirnoff 	if (n != 4)
1173340d773SGleb Smirnoff 		return (0);
1183340d773SGleb Smirnoff 	/*
1193340d773SGleb Smirnoff 	 * parts[0-2] were set to the first 3 parts of the address;
1203340d773SGleb Smirnoff 	 * val was set to the 4th part.
1213340d773SGleb Smirnoff 	 *
1223340d773SGleb Smirnoff 	 * Check if any part is bigger than 255.
1233340d773SGleb Smirnoff 	 */
1243340d773SGleb Smirnoff 	if ((parts[0] | parts[1] | parts[2] | val) > 0xff)
1253340d773SGleb Smirnoff 		return (0);
1263340d773SGleb Smirnoff 	/*
1273340d773SGleb Smirnoff 	 * Add the other three parts to val.
1283340d773SGleb Smirnoff 	 */
1293340d773SGleb Smirnoff 	val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
1303340d773SGleb Smirnoff 	if (dst) {
1313340d773SGleb Smirnoff 		val = htonl(val);
1323340d773SGleb Smirnoff 		memcpy(dst, &val, NS_INADDRSZ);
1333340d773SGleb Smirnoff 	}
1343340d773SGleb Smirnoff 	return (1);
1353340d773SGleb Smirnoff }
1363340d773SGleb Smirnoff 
1373340d773SGleb Smirnoff /* int
1383340d773SGleb Smirnoff  * strtoaddr6(src, dst)
1393340d773SGleb Smirnoff  *	convert presentation level IPv6 address to network order binary form.
1403340d773SGleb Smirnoff  * return:
1413340d773SGleb Smirnoff  *	1 if `src' is a valid [RFC1884 2.2] address, else 0.
1423340d773SGleb Smirnoff  * notice:
1433340d773SGleb Smirnoff  *	(1) does not touch `dst' unless it's returning 1.
1443340d773SGleb Smirnoff  *	(2) :: in a full address is silently ignored.
1453340d773SGleb Smirnoff  * credit:
1463340d773SGleb Smirnoff  *	inspired by Mark Andrews.
1473340d773SGleb Smirnoff  * author:
1483340d773SGleb Smirnoff  *	Paul Vixie, 1996.
1493340d773SGleb Smirnoff  */
1503340d773SGleb Smirnoff int
1513340d773SGleb Smirnoff strtoaddr6(const char *src, void *dst)
1523340d773SGleb Smirnoff {
1533340d773SGleb Smirnoff 	static const char xdigits_l[] = "0123456789abcdef",
1543340d773SGleb Smirnoff 			  xdigits_u[] = "0123456789ABCDEF";
1553340d773SGleb Smirnoff 	u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
1563340d773SGleb Smirnoff 	const char *xdigits, *curtok;
1573340d773SGleb Smirnoff 	int ch, seen_xdigits;
1583340d773SGleb Smirnoff 	u_int val;
1593340d773SGleb Smirnoff 
1603340d773SGleb Smirnoff 	memset((tp = tmp), '\0', NS_IN6ADDRSZ);
1613340d773SGleb Smirnoff 	endp = tp + NS_IN6ADDRSZ;
1623340d773SGleb Smirnoff 	colonp = NULL;
1633340d773SGleb Smirnoff 	/* Leading :: requires some special handling. */
1643340d773SGleb Smirnoff 	if (*src == ':')
1653340d773SGleb Smirnoff 		if (*++src != ':')
1663340d773SGleb Smirnoff 			return (0);
1673340d773SGleb Smirnoff 	curtok = src;
1683340d773SGleb Smirnoff 	seen_xdigits = 0;
1693340d773SGleb Smirnoff 	val = 0;
1703340d773SGleb Smirnoff 	while ((ch = *src++) != '\0') {
1713340d773SGleb Smirnoff 		const char *pch;
1723340d773SGleb Smirnoff 
1733340d773SGleb Smirnoff 		if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
1743340d773SGleb Smirnoff 			pch = strchr((xdigits = xdigits_u), ch);
1753340d773SGleb Smirnoff 		if (pch != NULL) {
1763340d773SGleb Smirnoff 			val <<= 4;
1773340d773SGleb Smirnoff 			val |= (int)(pch - xdigits);
1783340d773SGleb Smirnoff 			if (++seen_xdigits > 4)
1793340d773SGleb Smirnoff 				return (0);
1803340d773SGleb Smirnoff 			continue;
1813340d773SGleb Smirnoff 		}
1823340d773SGleb Smirnoff 		if (ch == ':') {
1833340d773SGleb Smirnoff 			curtok = src;
1843340d773SGleb Smirnoff 			if (!seen_xdigits) {
1853340d773SGleb Smirnoff 				if (colonp)
1863340d773SGleb Smirnoff 					return (0);
1873340d773SGleb Smirnoff 				colonp = tp;
1883340d773SGleb Smirnoff 				continue;
1893340d773SGleb Smirnoff 			} else if (*src == '\0')
1903340d773SGleb Smirnoff 				return (0);
1913340d773SGleb Smirnoff 			if (tp + NS_INT16SZ > endp)
1923340d773SGleb Smirnoff 				return (0);
1933340d773SGleb Smirnoff 			*tp++ = (u_char) (val >> 8) & 0xff;
1943340d773SGleb Smirnoff 			*tp++ = (u_char) val & 0xff;
1953340d773SGleb Smirnoff 			seen_xdigits = 0;
1963340d773SGleb Smirnoff 			val = 0;
1973340d773SGleb Smirnoff 			continue;
1983340d773SGleb Smirnoff 		}
1993340d773SGleb Smirnoff 		if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
2003340d773SGleb Smirnoff 		    strtoaddr(curtok, tp) > 0) {
2013340d773SGleb Smirnoff 			tp += NS_INADDRSZ;
2023340d773SGleb Smirnoff 			seen_xdigits = 0;
2033340d773SGleb Smirnoff 			break;	/*%< '\\0' was seen by strtoaddr(). */
2043340d773SGleb Smirnoff 		}
2053340d773SGleb Smirnoff 		return (0);
2063340d773SGleb Smirnoff 	}
2073340d773SGleb Smirnoff 	if (seen_xdigits) {
2083340d773SGleb Smirnoff 		if (tp + NS_INT16SZ > endp)
2093340d773SGleb Smirnoff 			return (0);
2103340d773SGleb Smirnoff 		*tp++ = (u_char) (val >> 8) & 0xff;
2113340d773SGleb Smirnoff 		*tp++ = (u_char) val & 0xff;
2123340d773SGleb Smirnoff 	}
2133340d773SGleb Smirnoff 	if (colonp != NULL) {
2143340d773SGleb Smirnoff 		/*
2153340d773SGleb Smirnoff 		 * Since some memmove()'s erroneously fail to handle
2163340d773SGleb Smirnoff 		 * overlapping regions, we'll do the shift by hand.
2173340d773SGleb Smirnoff 		 */
2183340d773SGleb Smirnoff 		const ptrdiff_t n = tp - colonp;
2193340d773SGleb Smirnoff 		int i;
2203340d773SGleb Smirnoff 
2213340d773SGleb Smirnoff 		if (tp == endp)
2223340d773SGleb Smirnoff 			return (0);
2233340d773SGleb Smirnoff 		for (i = 1; i <= n; i++) {
2243340d773SGleb Smirnoff 			endp[- i] = colonp[n - i];
2253340d773SGleb Smirnoff 			colonp[n - i] = 0;
2263340d773SGleb Smirnoff 		}
2273340d773SGleb Smirnoff 		tp = endp;
2283340d773SGleb Smirnoff 	}
2293340d773SGleb Smirnoff 	if (tp != endp)
2303340d773SGleb Smirnoff 		return (0);
2313340d773SGleb Smirnoff 	memcpy(dst, tmp, NS_IN6ADDRSZ);
2323340d773SGleb Smirnoff 	return (1);
2333340d773SGleb Smirnoff }
234