1/*	$NetBSD: inet_pton.c,v 1.1.1.1 2009/04/12 15:33:35 christos 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#if defined(LIBC_SCCS) && !defined(lint)
21static const char rcsid[] = "Id: inet_pton.c,v 1.5 2005/07/28 06:51:47 marka Exp";
22#endif /* LIBC_SCCS and not lint */
23
24#include "port_before.h"
25#include <sys/param.h>
26#include <sys/types.h>
27#include <sys/socket.h>
28#include <netinet/in.h>
29#include <arpa/inet.h>
30#include <arpa/nameser.h>
31#include <string.h>
32#include <errno.h>
33#include "port_after.h"
34
35/*%
36 * WARNING: Don't even consider trying to compile this on a system where
37 * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
38 */
39
40static int	inet_pton4 __P((const char *src, u_char *dst));
41static int	inet_pton6 __P((const char *src, u_char *dst));
42
43/* int
44 * inet_pton(af, src, dst)
45 *	convert from presentation format (which usually means ASCII printable)
46 *	to network format (which is usually some kind of binary format).
47 * return:
48 *	1 if the address was valid for the specified address family
49 *	0 if the address wasn't valid (`dst' is untouched in this case)
50 *	-1 if some other error occurred (`dst' is untouched in this case, too)
51 * author:
52 *	Paul Vixie, 1996.
53 */
54int
55inet_pton(af, src, dst)
56	int af;
57	const char *src;
58	void *dst;
59{
60	switch (af) {
61	case AF_INET:
62		return (inet_pton4(src, dst));
63	case AF_INET6:
64		return (inet_pton6(src, dst));
65	default:
66		errno = EAFNOSUPPORT;
67		return (-1);
68	}
69	/* NOTREACHED */
70}
71
72/* int
73 * inet_pton4(src, dst)
74 *	like inet_aton() but without all the hexadecimal and shorthand.
75 * return:
76 *	1 if `src' is a valid dotted quad, else 0.
77 * notice:
78 *	does not touch `dst' unless it's returning 1.
79 * author:
80 *	Paul Vixie, 1996.
81 */
82static int
83inet_pton4(src, dst)
84	const char *src;
85	u_char *dst;
86{
87	static const char digits[] = "0123456789";
88	int saw_digit, octets, ch;
89	u_char tmp[NS_INADDRSZ], *tp;
90
91	saw_digit = 0;
92	octets = 0;
93	*(tp = tmp) = 0;
94	while ((ch = *src++) != '\0') {
95		const char *pch;
96
97		if ((pch = strchr(digits, ch)) != NULL) {
98			u_int new = *tp * 10 + (pch - digits);
99
100			if (saw_digit && *tp == 0)
101				return (0);
102			if (new > 255)
103				return (0);
104			*tp = new;
105			if (!saw_digit) {
106				if (++octets > 4)
107					return (0);
108				saw_digit = 1;
109			}
110		} else if (ch == '.' && saw_digit) {
111			if (octets == 4)
112				return (0);
113			*++tp = 0;
114			saw_digit = 0;
115		} else
116			return (0);
117	}
118	if (octets < 4)
119		return (0);
120	memcpy(dst, tmp, NS_INADDRSZ);
121	return (1);
122}
123
124/* int
125 * inet_pton6(src, dst)
126 *	convert presentation level address to network order binary form.
127 * return:
128 *	1 if `src' is a valid [RFC1884 2.2] address, else 0.
129 * notice:
130 *	(1) does not touch `dst' unless it's returning 1.
131 *	(2) :: in a full address is silently ignored.
132 * credit:
133 *	inspired by Mark Andrews.
134 * author:
135 *	Paul Vixie, 1996.
136 */
137static int
138inet_pton6(src, dst)
139	const char *src;
140	u_char *dst;
141{
142	static const char xdigits_l[] = "0123456789abcdef",
143			  xdigits_u[] = "0123456789ABCDEF";
144	u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
145	const char *xdigits, *curtok;
146	int ch, seen_xdigits;
147	u_int val;
148
149	memset((tp = tmp), '\0', NS_IN6ADDRSZ);
150	endp = tp + NS_IN6ADDRSZ;
151	colonp = NULL;
152	/* Leading :: requires some special handling. */
153	if (*src == ':')
154		if (*++src != ':')
155			return (0);
156	curtok = src;
157	seen_xdigits = 0;
158	val = 0;
159	while ((ch = *src++) != '\0') {
160		const char *pch;
161
162		if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
163			pch = strchr((xdigits = xdigits_u), ch);
164		if (pch != NULL) {
165			val <<= 4;
166			val |= (pch - xdigits);
167			if (++seen_xdigits > 4)
168				return (0);
169			continue;
170		}
171		if (ch == ':') {
172			curtok = src;
173			if (!seen_xdigits) {
174				if (colonp)
175					return (0);
176				colonp = tp;
177				continue;
178			} else if (*src == '\0') {
179				return (0);
180			}
181			if (tp + NS_INT16SZ > endp)
182				return (0);
183			*tp++ = (u_char) (val >> 8) & 0xff;
184			*tp++ = (u_char) val & 0xff;
185			seen_xdigits = 0;
186			val = 0;
187			continue;
188		}
189		if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
190		    inet_pton4(curtok, tp) > 0) {
191			tp += NS_INADDRSZ;
192			seen_xdigits = 0;
193			break;	/*%< '\\0' was seen by inet_pton4(). */
194		}
195		return (0);
196	}
197	if (seen_xdigits) {
198		if (tp + NS_INT16SZ > endp)
199			return (0);
200		*tp++ = (u_char) (val >> 8) & 0xff;
201		*tp++ = (u_char) val & 0xff;
202	}
203	if (colonp != NULL) {
204		/*
205		 * Since some memmove()'s erroneously fail to handle
206		 * overlapping regions, we'll do the shift by hand.
207		 */
208		const int n = tp - colonp;
209		int i;
210
211		if (tp == endp)
212			return (0);
213		for (i = 1; i <= n; i++) {
214			endp[- i] = colonp[n - i];
215			colonp[n - i] = 0;
216		}
217		tp = endp;
218	}
219	if (tp != endp)
220		return (0);
221	memcpy(dst, tmp, NS_IN6ADDRSZ);
222	return (1);
223}
224
225/*! \file */
226