xref: /aosp_15_r20/external/tcpdump/strtoaddr.c (revision 05b00f6010a2396e3db2409989fc67270046269f)
1*05b00f60SXin Li /*
2*05b00f60SXin Li  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3*05b00f60SXin Li  * Copyright (c) 1996,1999 by Internet Software Consortium.
4*05b00f60SXin Li  *
5*05b00f60SXin Li  * Permission to use, copy, modify, and distribute this software for any
6*05b00f60SXin Li  * purpose with or without fee is hereby granted, provided that the above
7*05b00f60SXin Li  * copyright notice and this permission notice appear in all copies.
8*05b00f60SXin Li  *
9*05b00f60SXin Li  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10*05b00f60SXin Li  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11*05b00f60SXin Li  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
12*05b00f60SXin Li  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13*05b00f60SXin Li  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14*05b00f60SXin Li  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15*05b00f60SXin Li  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16*05b00f60SXin Li  */
17*05b00f60SXin Li 
18*05b00f60SXin Li #ifdef HAVE_CONFIG_H
19*05b00f60SXin Li #include <config.h>
20*05b00f60SXin Li #endif
21*05b00f60SXin Li 
22*05b00f60SXin Li #include "netdissect-stdinc.h"
23*05b00f60SXin Li #include <stddef.h>
24*05b00f60SXin Li #include <string.h>
25*05b00f60SXin Li 
26*05b00f60SXin Li #include "netdissect-ctype.h"
27*05b00f60SXin Li 
28*05b00f60SXin Li #include "strtoaddr.h"
29*05b00f60SXin Li 
30*05b00f60SXin Li #ifndef NS_INADDRSZ
31*05b00f60SXin Li #define NS_INADDRSZ	4	/* IPv4 T_A */
32*05b00f60SXin Li #endif
33*05b00f60SXin Li 
34*05b00f60SXin Li #ifndef NS_IN6ADDRSZ
35*05b00f60SXin Li #define NS_IN6ADDRSZ	16	/* IPv6 T_AAAA */
36*05b00f60SXin Li #endif
37*05b00f60SXin Li 
38*05b00f60SXin Li #ifndef NS_INT16SZ
39*05b00f60SXin Li #define NS_INT16SZ	2	/* #/bytes of data in a uint16_t */
40*05b00f60SXin Li #endif
41*05b00f60SXin Li 
42*05b00f60SXin Li /*%
43*05b00f60SXin Li  * WARNING: Don't even consider trying to compile this on a system where
44*05b00f60SXin Li  * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
45*05b00f60SXin Li  */
46*05b00f60SXin Li 
47*05b00f60SXin Li /* int
48*05b00f60SXin Li  * strtoaddr(src, dst)
49*05b00f60SXin Li  *	convert presentation level IPv4 address to network order binary form.
50*05b00f60SXin Li  * return:
51*05b00f60SXin Li  *	1 if `src' is a valid input, else 0.
52*05b00f60SXin Li  * notice:
53*05b00f60SXin Li  *	does not touch `dst' unless it's returning 1.
54*05b00f60SXin Li  * author:
55*05b00f60SXin Li  *	Paul Vixie, 1996.
56*05b00f60SXin Li  */
57*05b00f60SXin Li int
strtoaddr(const char * src,void * dst)58*05b00f60SXin Li strtoaddr(const char *src, void *dst)
59*05b00f60SXin Li {
60*05b00f60SXin Li 	uint32_t val;
61*05b00f60SXin Li 	u_int digit;
62*05b00f60SXin Li 	ptrdiff_t n;
63*05b00f60SXin Li 	unsigned char c;
64*05b00f60SXin Li 	u_int parts[4];
65*05b00f60SXin Li 	u_int *pp = parts;
66*05b00f60SXin Li 
67*05b00f60SXin Li 	c = *src;
68*05b00f60SXin Li 	for (;;) {
69*05b00f60SXin Li 		/*
70*05b00f60SXin Li 		 * Collect number up to ``.''.
71*05b00f60SXin Li 		 * Values are specified as for C:
72*05b00f60SXin Li 		 * 0x=hex, 0=octal, isdigit=decimal.
73*05b00f60SXin Li 		 */
74*05b00f60SXin Li 		if (!ND_ASCII_ISDIGIT(c))
75*05b00f60SXin Li 			return (0);
76*05b00f60SXin Li 		val = 0;
77*05b00f60SXin Li 		if (c == '0') {
78*05b00f60SXin Li 			c = *++src;
79*05b00f60SXin Li 			if (c == 'x' || c == 'X')
80*05b00f60SXin Li 				return (0);
81*05b00f60SXin Li 			else if (ND_ASCII_ISDIGIT(c) && c != '9')
82*05b00f60SXin Li 				return (0);
83*05b00f60SXin Li 		}
84*05b00f60SXin Li 		for (;;) {
85*05b00f60SXin Li 			if (ND_ASCII_ISDIGIT(c)) {
86*05b00f60SXin Li 				digit = c - '0';
87*05b00f60SXin Li 				val = (val * 10) + digit;
88*05b00f60SXin Li 				c = *++src;
89*05b00f60SXin Li 			} else
90*05b00f60SXin Li 				break;
91*05b00f60SXin Li 		}
92*05b00f60SXin Li 		if (c == '.') {
93*05b00f60SXin Li 			/*
94*05b00f60SXin Li 			 * Internet format:
95*05b00f60SXin Li 			 *	a.b.c.d
96*05b00f60SXin Li 			 *	a.b.c	(with c treated as 16 bits)
97*05b00f60SXin Li 			 *	a.b	(with b treated as 24 bits)
98*05b00f60SXin Li 			 *	a	(with a treated as 32 bits)
99*05b00f60SXin Li 			 */
100*05b00f60SXin Li 			if (pp >= parts + 3)
101*05b00f60SXin Li 				return (0);
102*05b00f60SXin Li 			*pp++ = val;
103*05b00f60SXin Li 			c = *++src;
104*05b00f60SXin Li 		} else
105*05b00f60SXin Li 			break;
106*05b00f60SXin Li 	}
107*05b00f60SXin Li 	/*
108*05b00f60SXin Li 	 * Check for trailing characters.
109*05b00f60SXin Li 	 */
110*05b00f60SXin Li 	if (c != '\0' && c != ' ' && c != '\t')
111*05b00f60SXin Li 		return (0);
112*05b00f60SXin Li 	/*
113*05b00f60SXin Li 	 * Find the number of parts specified.
114*05b00f60SXin Li 	 * It must be 4; we only support dotted quads, we don't
115*05b00f60SXin Li 	 * support shorthand.
116*05b00f60SXin Li 	 */
117*05b00f60SXin Li 	n = pp - parts + 1;
118*05b00f60SXin Li 	if (n != 4)
119*05b00f60SXin Li 		return (0);
120*05b00f60SXin Li 	/*
121*05b00f60SXin Li 	 * parts[0-2] were set to the first 3 parts of the address;
122*05b00f60SXin Li 	 * val was set to the 4th part.
123*05b00f60SXin Li 	 *
124*05b00f60SXin Li 	 * Check if any part is bigger than 255.
125*05b00f60SXin Li 	 */
126*05b00f60SXin Li 	if ((parts[0] | parts[1] | parts[2] | val) > 0xff)
127*05b00f60SXin Li 		return (0);
128*05b00f60SXin Li 	/*
129*05b00f60SXin Li 	 * Add the other three parts to val.
130*05b00f60SXin Li 	 */
131*05b00f60SXin Li 	val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
132*05b00f60SXin Li 	if (dst) {
133*05b00f60SXin Li 		val = htonl(val);
134*05b00f60SXin Li 		memcpy(dst, &val, NS_INADDRSZ);
135*05b00f60SXin Li 	}
136*05b00f60SXin Li 	return (1);
137*05b00f60SXin Li }
138*05b00f60SXin Li 
139*05b00f60SXin Li /* int
140*05b00f60SXin Li  * strtoaddr6(src, dst)
141*05b00f60SXin Li  *	convert presentation level IPv6 address to network order binary form.
142*05b00f60SXin Li  * return:
143*05b00f60SXin Li  *	1 if `src' is a valid [RFC1884 2.2] address, else 0.
144*05b00f60SXin Li  * notice:
145*05b00f60SXin Li  *	(1) does not touch `dst' unless it's returning 1.
146*05b00f60SXin Li  *	(2) :: in a full address is silently ignored.
147*05b00f60SXin Li  * credit:
148*05b00f60SXin Li  *	inspired by Mark Andrews.
149*05b00f60SXin Li  * author:
150*05b00f60SXin Li  *	Paul Vixie, 1996.
151*05b00f60SXin Li  */
152*05b00f60SXin Li int
strtoaddr6(const char * src,void * dst)153*05b00f60SXin Li strtoaddr6(const char *src, void *dst)
154*05b00f60SXin Li {
155*05b00f60SXin Li 	static const char xdigits_l[] = "0123456789abcdef",
156*05b00f60SXin Li 			  xdigits_u[] = "0123456789ABCDEF";
157*05b00f60SXin Li 	u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
158*05b00f60SXin Li 	const char *xdigits, *curtok;
159*05b00f60SXin Li 	int ch, seen_xdigits;
160*05b00f60SXin Li 	u_int val;
161*05b00f60SXin Li 
162*05b00f60SXin Li 	memset((tp = tmp), '\0', NS_IN6ADDRSZ);
163*05b00f60SXin Li 	endp = tp + NS_IN6ADDRSZ;
164*05b00f60SXin Li 	colonp = NULL;
165*05b00f60SXin Li 	/* Leading :: requires some special handling. */
166*05b00f60SXin Li 	if (*src == ':')
167*05b00f60SXin Li 		if (*++src != ':')
168*05b00f60SXin Li 			return (0);
169*05b00f60SXin Li 	curtok = src;
170*05b00f60SXin Li 	seen_xdigits = 0;
171*05b00f60SXin Li 	val = 0;
172*05b00f60SXin Li 	while ((ch = *src++) != '\0') {
173*05b00f60SXin Li 		const char *pch;
174*05b00f60SXin Li 
175*05b00f60SXin Li 		if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
176*05b00f60SXin Li 			pch = strchr((xdigits = xdigits_u), ch);
177*05b00f60SXin Li 		if (pch != NULL) {
178*05b00f60SXin Li 			val <<= 4;
179*05b00f60SXin Li 			val |= (int)(pch - xdigits);
180*05b00f60SXin Li 			if (++seen_xdigits > 4)
181*05b00f60SXin Li 				return (0);
182*05b00f60SXin Li 			continue;
183*05b00f60SXin Li 		}
184*05b00f60SXin Li 		if (ch == ':') {
185*05b00f60SXin Li 			curtok = src;
186*05b00f60SXin Li 			if (!seen_xdigits) {
187*05b00f60SXin Li 				if (colonp)
188*05b00f60SXin Li 					return (0);
189*05b00f60SXin Li 				colonp = tp;
190*05b00f60SXin Li 				continue;
191*05b00f60SXin Li 			} else if (*src == '\0')
192*05b00f60SXin Li 				return (0);
193*05b00f60SXin Li 			if (tp + NS_INT16SZ > endp)
194*05b00f60SXin Li 				return (0);
195*05b00f60SXin Li 			*tp++ = (u_char) (val >> 8) & 0xff;
196*05b00f60SXin Li 			*tp++ = (u_char) val & 0xff;
197*05b00f60SXin Li 			seen_xdigits = 0;
198*05b00f60SXin Li 			val = 0;
199*05b00f60SXin Li 			continue;
200*05b00f60SXin Li 		}
201*05b00f60SXin Li 		if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
202*05b00f60SXin Li 		    strtoaddr(curtok, tp) > 0) {
203*05b00f60SXin Li 			tp += NS_INADDRSZ;
204*05b00f60SXin Li 			seen_xdigits = 0;
205*05b00f60SXin Li 			break;	/*%< '\\0' was seen by strtoaddr(). */
206*05b00f60SXin Li 		}
207*05b00f60SXin Li 		return (0);
208*05b00f60SXin Li 	}
209*05b00f60SXin Li 	if (seen_xdigits) {
210*05b00f60SXin Li 		if (tp + NS_INT16SZ > endp)
211*05b00f60SXin Li 			return (0);
212*05b00f60SXin Li 		*tp++ = (u_char) (val >> 8) & 0xff;
213*05b00f60SXin Li 		*tp++ = (u_char) val & 0xff;
214*05b00f60SXin Li 	}
215*05b00f60SXin Li 	if (colonp != NULL) {
216*05b00f60SXin Li 		/*
217*05b00f60SXin Li 		 * Since some memmove()'s erroneously fail to handle
218*05b00f60SXin Li 		 * overlapping regions, we'll do the shift by hand.
219*05b00f60SXin Li 		 */
220*05b00f60SXin Li 		const ptrdiff_t n = tp - colonp;
221*05b00f60SXin Li 		int i;
222*05b00f60SXin Li 
223*05b00f60SXin Li 		if (tp == endp)
224*05b00f60SXin Li 			return (0);
225*05b00f60SXin Li 		for (i = 1; i <= n; i++) {
226*05b00f60SXin Li 			endp[- i] = colonp[n - i];
227*05b00f60SXin Li 			colonp[n - i] = 0;
228*05b00f60SXin Li 		}
229*05b00f60SXin Li 		tp = endp;
230*05b00f60SXin Li 	}
231*05b00f60SXin Li 	if (tp != endp)
232*05b00f60SXin Li 		return (0);
233*05b00f60SXin Li 	memcpy(dst, tmp, NS_IN6ADDRSZ);
234*05b00f60SXin Li 	return (1);
235*05b00f60SXin Li }
236