xref: /dflybsd-src/contrib/tcpdump/strtoaddr.c (revision 59c07fbdf8168fa08c76c515186d561b5a92690c)
1411677aeSAaron LI /*
2411677aeSAaron LI  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3411677aeSAaron LI  * Copyright (c) 1996,1999 by Internet Software Consortium.
4411677aeSAaron LI  *
5411677aeSAaron LI  * Permission to use, copy, modify, and distribute this software for any
6411677aeSAaron LI  * purpose with or without fee is hereby granted, provided that the above
7411677aeSAaron LI  * copyright notice and this permission notice appear in all copies.
8411677aeSAaron LI  *
9411677aeSAaron LI  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10411677aeSAaron LI  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11411677aeSAaron LI  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
12411677aeSAaron LI  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13411677aeSAaron LI  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14411677aeSAaron LI  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15411677aeSAaron LI  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16411677aeSAaron LI  */
17411677aeSAaron LI 
18411677aeSAaron LI #ifdef HAVE_CONFIG_H
19*ed775ee7SAntonio Huete Jimenez #include <config.h>
20411677aeSAaron LI #endif
21411677aeSAaron LI 
22*ed775ee7SAntonio Huete Jimenez #include "netdissect-stdinc.h"
23411677aeSAaron LI #include <stddef.h>
24411677aeSAaron LI #include <string.h>
25411677aeSAaron LI 
26*ed775ee7SAntonio Huete Jimenez #include "netdissect-ctype.h"
27*ed775ee7SAntonio Huete Jimenez 
28411677aeSAaron LI #include "strtoaddr.h"
29411677aeSAaron LI 
30411677aeSAaron LI #ifndef NS_INADDRSZ
31411677aeSAaron LI #define NS_INADDRSZ	4	/* IPv4 T_A */
32411677aeSAaron LI #endif
33411677aeSAaron LI 
34411677aeSAaron LI #ifndef NS_IN6ADDRSZ
35411677aeSAaron LI #define NS_IN6ADDRSZ	16	/* IPv6 T_AAAA */
36411677aeSAaron LI #endif
37411677aeSAaron LI 
38411677aeSAaron LI #ifndef NS_INT16SZ
39411677aeSAaron LI #define NS_INT16SZ	2	/* #/bytes of data in a uint16_t */
40411677aeSAaron LI #endif
41411677aeSAaron LI 
42411677aeSAaron LI /*%
43411677aeSAaron LI  * WARNING: Don't even consider trying to compile this on a system where
44411677aeSAaron LI  * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
45411677aeSAaron LI  */
46411677aeSAaron LI 
47411677aeSAaron LI /* int
48411677aeSAaron LI  * strtoaddr(src, dst)
49411677aeSAaron LI  *	convert presentation level IPv4 address to network order binary form.
50411677aeSAaron LI  * return:
51411677aeSAaron LI  *	1 if `src' is a valid input, else 0.
52411677aeSAaron LI  * notice:
53411677aeSAaron LI  *	does not touch `dst' unless it's returning 1.
54411677aeSAaron LI  * author:
55411677aeSAaron LI  *	Paul Vixie, 1996.
56411677aeSAaron LI  */
57411677aeSAaron LI int
strtoaddr(const char * src,void * dst)58411677aeSAaron LI strtoaddr(const char *src, void *dst)
59411677aeSAaron LI {
60411677aeSAaron LI 	uint32_t val;
61411677aeSAaron LI 	u_int digit;
62411677aeSAaron LI 	ptrdiff_t n;
63411677aeSAaron LI 	unsigned char c;
64411677aeSAaron LI 	u_int parts[4];
65411677aeSAaron LI 	u_int *pp = parts;
66411677aeSAaron LI 
67411677aeSAaron LI 	c = *src;
68411677aeSAaron LI 	for (;;) {
69411677aeSAaron LI 		/*
70411677aeSAaron LI 		 * Collect number up to ``.''.
71411677aeSAaron LI 		 * Values are specified as for C:
72411677aeSAaron LI 		 * 0x=hex, 0=octal, isdigit=decimal.
73411677aeSAaron LI 		 */
74*ed775ee7SAntonio Huete Jimenez 		if (!ND_ASCII_ISDIGIT(c))
75411677aeSAaron LI 			return (0);
76411677aeSAaron LI 		val = 0;
77411677aeSAaron LI 		if (c == '0') {
78411677aeSAaron LI 			c = *++src;
79411677aeSAaron LI 			if (c == 'x' || c == 'X')
80411677aeSAaron LI 				return (0);
81*ed775ee7SAntonio Huete Jimenez 			else if (ND_ASCII_ISDIGIT(c) && c != '9')
82411677aeSAaron LI 				return (0);
83411677aeSAaron LI 		}
84411677aeSAaron LI 		for (;;) {
85*ed775ee7SAntonio Huete Jimenez 			if (ND_ASCII_ISDIGIT(c)) {
86411677aeSAaron LI 				digit = c - '0';
87411677aeSAaron LI 				val = (val * 10) + digit;
88411677aeSAaron LI 				c = *++src;
89411677aeSAaron LI 			} else
90411677aeSAaron LI 				break;
91411677aeSAaron LI 		}
92411677aeSAaron LI 		if (c == '.') {
93411677aeSAaron LI 			/*
94411677aeSAaron LI 			 * Internet format:
95411677aeSAaron LI 			 *	a.b.c.d
96411677aeSAaron LI 			 *	a.b.c	(with c treated as 16 bits)
97411677aeSAaron LI 			 *	a.b	(with b treated as 24 bits)
98411677aeSAaron LI 			 *	a	(with a treated as 32 bits)
99411677aeSAaron LI 			 */
100411677aeSAaron LI 			if (pp >= parts + 3)
101411677aeSAaron LI 				return (0);
102411677aeSAaron LI 			*pp++ = val;
103411677aeSAaron LI 			c = *++src;
104411677aeSAaron LI 		} else
105411677aeSAaron LI 			break;
106411677aeSAaron LI 	}
107411677aeSAaron LI 	/*
108411677aeSAaron LI 	 * Check for trailing characters.
109411677aeSAaron LI 	 */
110*ed775ee7SAntonio Huete Jimenez 	if (c != '\0' && c != ' ' && c != '\t')
111411677aeSAaron LI 		return (0);
112411677aeSAaron LI 	/*
113411677aeSAaron LI 	 * Find the number of parts specified.
114411677aeSAaron LI 	 * It must be 4; we only support dotted quads, we don't
115411677aeSAaron LI 	 * support shorthand.
116411677aeSAaron LI 	 */
117411677aeSAaron LI 	n = pp - parts + 1;
118411677aeSAaron LI 	if (n != 4)
119411677aeSAaron LI 		return (0);
120411677aeSAaron LI 	/*
121411677aeSAaron LI 	 * parts[0-2] were set to the first 3 parts of the address;
122411677aeSAaron LI 	 * val was set to the 4th part.
123411677aeSAaron LI 	 *
124411677aeSAaron LI 	 * Check if any part is bigger than 255.
125411677aeSAaron LI 	 */
126411677aeSAaron LI 	if ((parts[0] | parts[1] | parts[2] | val) > 0xff)
127411677aeSAaron LI 		return (0);
128411677aeSAaron LI 	/*
129411677aeSAaron LI 	 * Add the other three parts to val.
130411677aeSAaron LI 	 */
131411677aeSAaron LI 	val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
132411677aeSAaron LI 	if (dst) {
133411677aeSAaron LI 		val = htonl(val);
134411677aeSAaron LI 		memcpy(dst, &val, NS_INADDRSZ);
135411677aeSAaron LI 	}
136411677aeSAaron LI 	return (1);
137411677aeSAaron LI }
138411677aeSAaron LI 
139411677aeSAaron LI /* int
140411677aeSAaron LI  * strtoaddr6(src, dst)
141411677aeSAaron LI  *	convert presentation level IPv6 address to network order binary form.
142411677aeSAaron LI  * return:
143411677aeSAaron LI  *	1 if `src' is a valid [RFC1884 2.2] address, else 0.
144411677aeSAaron LI  * notice:
145411677aeSAaron LI  *	(1) does not touch `dst' unless it's returning 1.
146411677aeSAaron LI  *	(2) :: in a full address is silently ignored.
147411677aeSAaron LI  * credit:
148411677aeSAaron LI  *	inspired by Mark Andrews.
149411677aeSAaron LI  * author:
150411677aeSAaron LI  *	Paul Vixie, 1996.
151411677aeSAaron LI  */
152411677aeSAaron LI int
strtoaddr6(const char * src,void * dst)153411677aeSAaron LI strtoaddr6(const char *src, void *dst)
154411677aeSAaron LI {
155411677aeSAaron LI 	static const char xdigits_l[] = "0123456789abcdef",
156411677aeSAaron LI 			  xdigits_u[] = "0123456789ABCDEF";
157411677aeSAaron LI 	u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
158411677aeSAaron LI 	const char *xdigits, *curtok;
159411677aeSAaron LI 	int ch, seen_xdigits;
160411677aeSAaron LI 	u_int val;
161411677aeSAaron LI 
162411677aeSAaron LI 	memset((tp = tmp), '\0', NS_IN6ADDRSZ);
163411677aeSAaron LI 	endp = tp + NS_IN6ADDRSZ;
164411677aeSAaron LI 	colonp = NULL;
165411677aeSAaron LI 	/* Leading :: requires some special handling. */
166411677aeSAaron LI 	if (*src == ':')
167411677aeSAaron LI 		if (*++src != ':')
168411677aeSAaron LI 			return (0);
169411677aeSAaron LI 	curtok = src;
170411677aeSAaron LI 	seen_xdigits = 0;
171411677aeSAaron LI 	val = 0;
172411677aeSAaron LI 	while ((ch = *src++) != '\0') {
173411677aeSAaron LI 		const char *pch;
174411677aeSAaron LI 
175411677aeSAaron LI 		if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
176411677aeSAaron LI 			pch = strchr((xdigits = xdigits_u), ch);
177411677aeSAaron LI 		if (pch != NULL) {
178411677aeSAaron LI 			val <<= 4;
179411677aeSAaron LI 			val |= (int)(pch - xdigits);
180411677aeSAaron LI 			if (++seen_xdigits > 4)
181411677aeSAaron LI 				return (0);
182411677aeSAaron LI 			continue;
183411677aeSAaron LI 		}
184411677aeSAaron LI 		if (ch == ':') {
185411677aeSAaron LI 			curtok = src;
186411677aeSAaron LI 			if (!seen_xdigits) {
187411677aeSAaron LI 				if (colonp)
188411677aeSAaron LI 					return (0);
189411677aeSAaron LI 				colonp = tp;
190411677aeSAaron LI 				continue;
191411677aeSAaron LI 			} else if (*src == '\0')
192411677aeSAaron LI 				return (0);
193411677aeSAaron LI 			if (tp + NS_INT16SZ > endp)
194411677aeSAaron LI 				return (0);
195411677aeSAaron LI 			*tp++ = (u_char) (val >> 8) & 0xff;
196411677aeSAaron LI 			*tp++ = (u_char) val & 0xff;
197411677aeSAaron LI 			seen_xdigits = 0;
198411677aeSAaron LI 			val = 0;
199411677aeSAaron LI 			continue;
200411677aeSAaron LI 		}
201411677aeSAaron LI 		if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
202411677aeSAaron LI 		    strtoaddr(curtok, tp) > 0) {
203411677aeSAaron LI 			tp += NS_INADDRSZ;
204411677aeSAaron LI 			seen_xdigits = 0;
205411677aeSAaron LI 			break;	/*%< '\\0' was seen by strtoaddr(). */
206411677aeSAaron LI 		}
207411677aeSAaron LI 		return (0);
208411677aeSAaron LI 	}
209411677aeSAaron LI 	if (seen_xdigits) {
210411677aeSAaron LI 		if (tp + NS_INT16SZ > endp)
211411677aeSAaron LI 			return (0);
212411677aeSAaron LI 		*tp++ = (u_char) (val >> 8) & 0xff;
213411677aeSAaron LI 		*tp++ = (u_char) val & 0xff;
214411677aeSAaron LI 	}
215411677aeSAaron LI 	if (colonp != NULL) {
216411677aeSAaron LI 		/*
217411677aeSAaron LI 		 * Since some memmove()'s erroneously fail to handle
218411677aeSAaron LI 		 * overlapping regions, we'll do the shift by hand.
219411677aeSAaron LI 		 */
220411677aeSAaron LI 		const ptrdiff_t n = tp - colonp;
221411677aeSAaron LI 		int i;
222411677aeSAaron LI 
223411677aeSAaron LI 		if (tp == endp)
224411677aeSAaron LI 			return (0);
225411677aeSAaron LI 		for (i = 1; i <= n; i++) {
226411677aeSAaron LI 			endp[- i] = colonp[n - i];
227411677aeSAaron LI 			colonp[n - i] = 0;
228411677aeSAaron LI 		}
229411677aeSAaron LI 		tp = endp;
230411677aeSAaron LI 	}
231411677aeSAaron LI 	if (tp != endp)
232411677aeSAaron LI 		return (0);
233411677aeSAaron LI 	memcpy(dst, tmp, NS_IN6ADDRSZ);
234411677aeSAaron LI 	return (1);
235411677aeSAaron LI }
236