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