1/*	$NetBSD: inet_pton.c,v 1.6.10.1 2011/01/10 00:42:17 riz Exp $	*/
2
3/*
4 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (c) 1996,1999 by Internet Software Consortium.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include <sys/cdefs.h>
21#if defined(LIBC_SCCS) && !defined(lint)
22#if 0
23static const char rcsid[] = "Id: inet_pton.c,v 1.5 2005/07/28 06:51:47 marka Exp";
24#else
25__RCSID("$NetBSD: inet_pton.c,v 1.6.10.1 2011/01/10 00:42:17 riz Exp $");
26#endif
27#endif /* LIBC_SCCS and not lint */
28
29// BEGIN android-added
30#define _DIAGASSERT(exp) assert(exp)
31#include "../private/arpa_nameser.h"
32// END android-added
33
34// android-removed: #include "port_before.h"
35
36// android-removed: #include "namespace.h"
37#include <sys/param.h>
38#include <sys/types.h>
39#include <sys/socket.h>
40#include <netinet/in.h>
41#include <arpa/inet.h>
42#include <arpa/nameser.h>
43#include <string.h>
44#include <assert.h>
45#include <ctype.h>
46#include <errno.h>
47
48// android-removed: #include "port_after.h"
49
50// BEGIN android-removed
51// #ifdef __weak_alias
52// __weak_alias(inet_pton,_inet_pton)
53// #endif
54// END android-removed
55
56/*%
57 * WARNING: Don't even consider trying to compile this on a system where
58 * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
59 */
60
61static int	inet_pton4(const char *src, u_char *dst, int pton);
62static int	inet_pton6(const char *src, u_char *dst);
63
64/* int
65 * inet_pton(af, src, dst)
66 *	convert from presentation format (which usually means ASCII printable)
67 *	to network format (which is usually some kind of binary format).
68 * return:
69 *	1 if the address was valid for the specified address family
70 *	0 if the address wasn't valid (`dst' is untouched in this case)
71 *	-1 if some other error occurred (`dst' is untouched in this case, too)
72 * author:
73 *	Paul Vixie, 1996.
74 */
75int
76inet_pton(int af, const char *src, void *dst)
77{
78
79	_DIAGASSERT(src != NULL);
80	_DIAGASSERT(dst != NULL);
81
82	switch (af) {
83	case AF_INET:
84		return (inet_pton4(src, dst, 1));
85	case AF_INET6:
86		return (inet_pton6(src, dst));
87	default:
88		errno = EAFNOSUPPORT;
89		return (-1);
90	}
91	/* NOTREACHED */
92}
93
94/* int
95 * inet_pton4(src, dst, pton)
96 *	when last arg is 0: inet_aton(). with hexadecimal, octal and shorthand.
97 *	when last arg is 1: inet_pton(). decimal dotted-quad only.
98 * return:
99 *	1 if `src' is a valid input, else 0.
100 * notice:
101 *	does not touch `dst' unless it's returning 1.
102 * author:
103 *	Paul Vixie, 1996.
104 */
105static int
106inet_pton4(const char *src, u_char *dst, int pton)
107{
108	u_int32_t val;
109	u_int digit, base;
110	int n;
111	unsigned char c;
112	u_int parts[4];
113	register u_int *pp = parts;
114
115	_DIAGASSERT(src != NULL);
116	_DIAGASSERT(dst != NULL);
117
118	c = *src;
119	for (;;) {
120		/*
121		 * Collect number up to ``.''.
122		 * Values are specified as for C:
123		 * 0x=hex, 0=octal, isdigit=decimal.
124		 */
125		if (!isdigit(c))
126			return (0);
127		val = 0; base = 10;
128		if (c == '0') {
129			c = *++src;
130			if (c == 'x' || c == 'X')
131				base = 16, c = *++src;
132			else if (isdigit(c) && c != '9')
133				base = 8;
134		}
135		/* inet_pton() takes decimal only */
136		if (pton && base != 10)
137			return (0);
138		for (;;) {
139			if (isdigit(c)) {
140				digit = c - '0';
141				if (digit >= base)
142					break;
143				val = (val * base) + digit;
144				c = *++src;
145			} else if (base == 16 && isxdigit(c)) {
146				digit = c + 10 - (islower(c) ? 'a' : 'A');
147				if (digit >= 16)
148					break;
149				val = (val << 4) | digit;
150				c = *++src;
151			} else
152				break;
153		}
154		if (c == '.') {
155			/*
156			 * Internet format:
157			 *	a.b.c.d
158			 *	a.b.c	(with c treated as 16 bits)
159			 *	a.b	(with b treated as 24 bits)
160			 *	a	(with a treated as 32 bits)
161			 */
162			if (pp >= parts + 3)
163				return (0);
164			*pp++ = val;
165			c = *++src;
166		} else
167			break;
168	}
169	/*
170	 * Check for trailing characters.
171	 */
172	if (c != '\0' && !isspace(c))
173		return (0);
174	/*
175	 * Concoct the address according to
176	 * the number of parts specified.
177	 */
178	n = pp - parts + 1;
179	/* inet_pton() takes dotted-quad only.  it does not take shorthand. */
180	if (pton && n != 4)
181		return (0);
182	switch (n) {
183
184	case 0:
185		return (0);		/* initial nondigit */
186
187	case 1:				/* a -- 32 bits */
188		break;
189
190	case 2:				/* a.b -- 8.24 bits */
191		if (parts[0] > 0xff || val > 0xffffff)
192			return (0);
193		val |= parts[0] << 24;
194		break;
195
196	case 3:				/* a.b.c -- 8.8.16 bits */
197		if ((parts[0] | parts[1]) > 0xff || val > 0xffff)
198			return (0);
199		val |= (parts[0] << 24) | (parts[1] << 16);
200		break;
201
202	case 4:				/* a.b.c.d -- 8.8.8.8 bits */
203		if ((parts[0] | parts[1] | parts[2] | val) > 0xff)
204			return (0);
205		val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
206		break;
207	}
208	if (dst) {
209		val = htonl(val);
210		memcpy(dst, &val, NS_INADDRSZ);
211	}
212	return (1);
213}
214
215/* int
216 * inet_pton6(src, dst)
217 *	convert presentation level address to network order binary form.
218 * return:
219 *	1 if `src' is a valid [RFC1884 2.2] address, else 0.
220 * notice:
221 *	(1) does not touch `dst' unless it's returning 1.
222 *	(2) :: in a full address is silently ignored.
223 * credit:
224 *	inspired by Mark Andrews.
225 * author:
226 *	Paul Vixie, 1996.
227 */
228static int
229inet_pton6(const char *src, u_char *dst)
230{
231	static const char xdigits_l[] = "0123456789abcdef",
232			  xdigits_u[] = "0123456789ABCDEF";
233	u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
234	const char *xdigits, *curtok;
235	int ch, seen_xdigits;
236	u_int val;
237
238	_DIAGASSERT(src != NULL);
239	_DIAGASSERT(dst != NULL);
240
241	memset((tp = tmp), '\0', NS_IN6ADDRSZ);
242	endp = tp + NS_IN6ADDRSZ;
243	colonp = NULL;
244	/* Leading :: requires some special handling. */
245	if (*src == ':')
246		if (*++src != ':')
247			return (0);
248	curtok = src;
249	seen_xdigits = 0;
250	val = 0;
251	while ((ch = *src++) != '\0') {
252		const char *pch;
253
254		if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
255			pch = strchr((xdigits = xdigits_u), ch);
256		if (pch != NULL) {
257			val <<= 4;
258			val |= (pch - xdigits);
259			if (++seen_xdigits > 4)
260				return (0);
261			continue;
262		}
263		if (ch == ':') {
264			curtok = src;
265			if (!seen_xdigits) {
266				if (colonp)
267					return (0);
268				colonp = tp;
269				continue;
270			} else if (*src == '\0')
271				return (0);
272			if (tp + NS_INT16SZ > endp)
273				return (0);
274			*tp++ = (u_char) (val >> 8) & 0xff;
275			*tp++ = (u_char) val & 0xff;
276			seen_xdigits = 0;
277			val = 0;
278			continue;
279		}
280		if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
281		    inet_pton4(curtok, tp, 1) > 0) {
282			tp += NS_INADDRSZ;
283			seen_xdigits = 0;
284			break;	/*%< '\\0' was seen by inet_pton4(). */
285		}
286		return (0);
287	}
288	if (seen_xdigits) {
289		if (tp + NS_INT16SZ > endp)
290			return (0);
291		*tp++ = (u_char) (val >> 8) & 0xff;
292		*tp++ = (u_char) val & 0xff;
293	}
294	if (colonp != NULL) {
295		/*
296		 * Since some memmove()'s erroneously fail to handle
297		 * overlapping regions, we'll do the shift by hand.
298		 */
299		const int n = tp - colonp;
300		int i;
301
302		if (tp == endp)
303			return (0);
304		for (i = 1; i <= n; i++) {
305			endp[- i] = colonp[n - i];
306			colonp[n - i] = 0;
307		}
308		tp = endp;
309	}
310	if (tp != endp)
311		return (0);
312	memcpy(dst, tmp, NS_IN6ADDRSZ);
313	return (1);
314}
315
316/*! \file */
317