1156952Sume/*
2156952Sume * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3156952Sume * Copyright (c) 1996,1999 by Internet Software Consortium.
4156952Sume *
5156952Sume * Permission to use, copy, modify, and distribute this software for any
6156952Sume * purpose with or without fee is hereby granted, provided that the above
7156952Sume * copyright notice and this permission notice appear in all copies.
8156952Sume *
9156952Sume * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10156952Sume * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11156952Sume * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
12156952Sume * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13156952Sume * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14156952Sume * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15156952Sume * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16156952Sume */
17156952Sume
18156952Sume#if defined(LIBC_SCCS) && !defined(lint)
19170244Sumestatic const char rcsid[] = "$Id: inet_pton.c,v 1.3.18.2 2005/07/28 07:38:07 marka Exp $";
20156952Sume#endif /* LIBC_SCCS and not lint */
21156956Sume#include <sys/cdefs.h>
22156956Sume__FBSDID("$FreeBSD$");
23156952Sume
24156952Sume#include "port_before.h"
25156952Sume#include <sys/param.h>
26156952Sume#include <sys/types.h>
27156952Sume#include <sys/socket.h>
28156952Sume#include <netinet/in.h>
29156952Sume#include <arpa/inet.h>
30156952Sume#include <arpa/nameser.h>
31156952Sume#include <string.h>
32156952Sume#include <errno.h>
33156952Sume#include "port_after.h"
34156952Sume
35170244Sume/*%
36156952Sume * WARNING: Don't even consider trying to compile this on a system where
37156952Sume * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
38156952Sume */
39156952Sume
40156956Sumestatic int	inet_pton4(const char *src, u_char *dst);
41156956Sumestatic int	inet_pton6(const char *src, u_char *dst);
42156952Sume
43156952Sume/* int
44156952Sume * inet_pton(af, src, dst)
45156952Sume *	convert from presentation format (which usually means ASCII printable)
46156952Sume *	to network format (which is usually some kind of binary format).
47156952Sume * return:
48156952Sume *	1 if the address was valid for the specified address family
49156952Sume *	0 if the address wasn't valid (`dst' is untouched in this case)
50156952Sume *	-1 if some other error occurred (`dst' is untouched in this case, too)
51156952Sume * author:
52156952Sume *	Paul Vixie, 1996.
53156952Sume */
54156952Sumeint
55156956Sumeinet_pton(int af, const char * __restrict src, void * __restrict dst)
56156952Sume{
57156952Sume	switch (af) {
58156952Sume	case AF_INET:
59156952Sume		return (inet_pton4(src, dst));
60156952Sume	case AF_INET6:
61156952Sume		return (inet_pton6(src, dst));
62156952Sume	default:
63156952Sume		errno = EAFNOSUPPORT;
64156952Sume		return (-1);
65156952Sume	}
66156952Sume	/* NOTREACHED */
67156952Sume}
68156952Sume
69156952Sume/* int
70156952Sume * inet_pton4(src, dst)
71156952Sume *	like inet_aton() but without all the hexadecimal and shorthand.
72156952Sume * return:
73156952Sume *	1 if `src' is a valid dotted quad, else 0.
74156952Sume * notice:
75156952Sume *	does not touch `dst' unless it's returning 1.
76156952Sume * author:
77156952Sume *	Paul Vixie, 1996.
78156952Sume */
79156952Sumestatic int
80156956Sumeinet_pton4(const char *src, u_char *dst)
81156952Sume{
82156952Sume	static const char digits[] = "0123456789";
83156952Sume	int saw_digit, octets, ch;
84156952Sume	u_char tmp[NS_INADDRSZ], *tp;
85156952Sume
86156952Sume	saw_digit = 0;
87156952Sume	octets = 0;
88156952Sume	*(tp = tmp) = 0;
89156952Sume	while ((ch = *src++) != '\0') {
90156952Sume		const char *pch;
91156952Sume
92156952Sume		if ((pch = strchr(digits, ch)) != NULL) {
93156952Sume			u_int new = *tp * 10 + (pch - digits);
94156952Sume
95156952Sume			if (saw_digit && *tp == 0)
96156952Sume				return (0);
97156952Sume			if (new > 255)
98156952Sume				return (0);
99156952Sume			*tp = new;
100156952Sume			if (!saw_digit) {
101156952Sume				if (++octets > 4)
102156952Sume					return (0);
103156952Sume				saw_digit = 1;
104156952Sume			}
105156952Sume		} else if (ch == '.' && saw_digit) {
106156952Sume			if (octets == 4)
107156952Sume				return (0);
108156952Sume			*++tp = 0;
109156952Sume			saw_digit = 0;
110156952Sume		} else
111156952Sume			return (0);
112156952Sume	}
113156952Sume	if (octets < 4)
114156952Sume		return (0);
115156952Sume	memcpy(dst, tmp, NS_INADDRSZ);
116156952Sume	return (1);
117156952Sume}
118156952Sume
119156952Sume/* int
120156952Sume * inet_pton6(src, dst)
121156952Sume *	convert presentation level address to network order binary form.
122156952Sume * return:
123156952Sume *	1 if `src' is a valid [RFC1884 2.2] address, else 0.
124156952Sume * notice:
125156952Sume *	(1) does not touch `dst' unless it's returning 1.
126156952Sume *	(2) :: in a full address is silently ignored.
127156952Sume * credit:
128156952Sume *	inspired by Mark Andrews.
129156952Sume * author:
130156952Sume *	Paul Vixie, 1996.
131156952Sume */
132156952Sumestatic int
133156956Sumeinet_pton6(const char *src, u_char *dst)
134156952Sume{
135156952Sume	static const char xdigits_l[] = "0123456789abcdef",
136156952Sume			  xdigits_u[] = "0123456789ABCDEF";
137156952Sume	u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
138156952Sume	const char *xdigits, *curtok;
139156952Sume	int ch, seen_xdigits;
140156952Sume	u_int val;
141156952Sume
142156952Sume	memset((tp = tmp), '\0', NS_IN6ADDRSZ);
143156952Sume	endp = tp + NS_IN6ADDRSZ;
144156952Sume	colonp = NULL;
145156952Sume	/* Leading :: requires some special handling. */
146156952Sume	if (*src == ':')
147156952Sume		if (*++src != ':')
148156952Sume			return (0);
149156952Sume	curtok = src;
150156952Sume	seen_xdigits = 0;
151156952Sume	val = 0;
152156952Sume	while ((ch = *src++) != '\0') {
153156952Sume		const char *pch;
154156952Sume
155156952Sume		if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
156156952Sume			pch = strchr((xdigits = xdigits_u), ch);
157156952Sume		if (pch != NULL) {
158156952Sume			val <<= 4;
159156952Sume			val |= (pch - xdigits);
160156952Sume			if (++seen_xdigits > 4)
161156952Sume				return (0);
162156952Sume			continue;
163156952Sume		}
164156952Sume		if (ch == ':') {
165156952Sume			curtok = src;
166156952Sume			if (!seen_xdigits) {
167156952Sume				if (colonp)
168156952Sume					return (0);
169156952Sume				colonp = tp;
170156952Sume				continue;
171156952Sume			} else if (*src == '\0') {
172156952Sume				return (0);
173156952Sume			}
174156952Sume			if (tp + NS_INT16SZ > endp)
175156952Sume				return (0);
176156952Sume			*tp++ = (u_char) (val >> 8) & 0xff;
177156952Sume			*tp++ = (u_char) val & 0xff;
178156952Sume			seen_xdigits = 0;
179156952Sume			val = 0;
180156952Sume			continue;
181156952Sume		}
182156952Sume		if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
183156952Sume		    inet_pton4(curtok, tp) > 0) {
184156952Sume			tp += NS_INADDRSZ;
185156952Sume			seen_xdigits = 0;
186170244Sume			break;	/*%< '\\0' was seen by inet_pton4(). */
187156952Sume		}
188156952Sume		return (0);
189156952Sume	}
190156952Sume	if (seen_xdigits) {
191156952Sume		if (tp + NS_INT16SZ > endp)
192156952Sume			return (0);
193156952Sume		*tp++ = (u_char) (val >> 8) & 0xff;
194156952Sume		*tp++ = (u_char) val & 0xff;
195156952Sume	}
196156952Sume	if (colonp != NULL) {
197156952Sume		/*
198156952Sume		 * Since some memmove()'s erroneously fail to handle
199156952Sume		 * overlapping regions, we'll do the shift by hand.
200156952Sume		 */
201156952Sume		const int n = tp - colonp;
202156952Sume		int i;
203156952Sume
204156952Sume		if (tp == endp)
205156952Sume			return (0);
206156952Sume		for (i = 1; i <= n; i++) {
207156952Sume			endp[- i] = colonp[n - i];
208156952Sume			colonp[n - i] = 0;
209156952Sume		}
210156952Sume		tp = endp;
211156952Sume	}
212156952Sume	if (tp != endp)
213156952Sume		return (0);
214156952Sume	memcpy(dst, tmp, NS_IN6ADDRSZ);
215156952Sume	return (1);
216156952Sume}
217156956Sume
218156956Sume/*
219156956Sume * Weak aliases for applications that use certain private entry points,
220156956Sume * and fail to include <arpa/inet.h>.
221156956Sume */
222156956Sume#undef inet_pton
223156956Sume__weak_reference(__inet_pton, inet_pton);
224170244Sume
225170244Sume/*! \file */
226