1177633Sdfr/*
2177633Sdfr * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3177633Sdfr * Copyright (c) 1996,1999 by Internet Software Consortium.
4177633Sdfr *
5177633Sdfr * Permission to use, copy, modify, and distribute this software for any
6177633Sdfr * purpose with or without fee is hereby granted, provided that the above
7177633Sdfr * copyright notice and this permission notice appear in all copies.
8177633Sdfr *
9177633Sdfr * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10177633Sdfr * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11177633Sdfr * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
12177633Sdfr * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13177633Sdfr * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14177633Sdfr * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15177633Sdfr * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16177633Sdfr */
17177633Sdfr
18177633Sdfr#if defined(LIBC_SCCS) && !defined(lint)
19177633Sdfrstatic const char rcsid[] = "$Id: inet_pton.c,v 1.3.18.2 2005/07/28 07:38:07 marka Exp $";
20177633Sdfr#endif /* LIBC_SCCS and not lint */
21177633Sdfr#include <sys/cdefs.h>
22177633Sdfr__FBSDID("$FreeBSD$");
23177633Sdfr
24177633Sdfr#include <sys/param.h>
25177633Sdfr#include <sys/socket.h>
26177633Sdfr#include <sys/systm.h>
27177633Sdfr
28213103Sattilio#include <netinet/in.h>
29177633Sdfr
30177685Sdfr#if __FreeBSD_version < 700000
31177685Sdfr#define strchr index
32177685Sdfr#endif
33177685Sdfr
34177633Sdfr/*%
35177633Sdfr * WARNING: Don't even consider trying to compile this on a system where
36177633Sdfr * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
37177633Sdfr */
38177633Sdfr
39177633Sdfrstatic int	inet_pton4(const char *src, u_char *dst);
40177633Sdfrstatic int	inet_pton6(const char *src, u_char *dst);
41177633Sdfr
42177633Sdfr/* int
43177633Sdfr * inet_pton(af, src, dst)
44177633Sdfr *	convert from presentation format (which usually means ASCII printable)
45177633Sdfr *	to network format (which is usually some kind of binary format).
46177633Sdfr * return:
47177633Sdfr *	1 if the address was valid for the specified address family
48177633Sdfr *	0 if the address wasn't valid (`dst' is untouched in this case)
49177633Sdfr *	-1 if some other error occurred (`dst' is untouched in this case, too)
50177633Sdfr * author:
51177633Sdfr *	Paul Vixie, 1996.
52177633Sdfr */
53177633Sdfrint
54213103Sattilioinet_pton(int af, const char *src, void *dst)
55177633Sdfr{
56177633Sdfr	switch (af) {
57177633Sdfr	case AF_INET:
58177633Sdfr		return (inet_pton4(src, dst));
59177633Sdfr	case AF_INET6:
60177633Sdfr		return (inet_pton6(src, dst));
61177633Sdfr	default:
62177633Sdfr		return (-1);
63177633Sdfr	}
64177633Sdfr	/* NOTREACHED */
65177633Sdfr}
66177633Sdfr
67177633Sdfr/* int
68177633Sdfr * inet_pton4(src, dst)
69177633Sdfr *	like inet_aton() but without all the hexadecimal and shorthand.
70177633Sdfr * return:
71177633Sdfr *	1 if `src' is a valid dotted quad, else 0.
72177633Sdfr * notice:
73177633Sdfr *	does not touch `dst' unless it's returning 1.
74177633Sdfr * author:
75177633Sdfr *	Paul Vixie, 1996.
76177633Sdfr */
77177633Sdfrstatic int
78177633Sdfrinet_pton4(const char *src, u_char *dst)
79177633Sdfr{
80177633Sdfr	static const char digits[] = "0123456789";
81177633Sdfr	int saw_digit, octets, ch;
82177633Sdfr#define NS_INADDRSZ	4
83177633Sdfr	u_char tmp[NS_INADDRSZ], *tp;
84177633Sdfr
85177633Sdfr	saw_digit = 0;
86177633Sdfr	octets = 0;
87177633Sdfr	*(tp = tmp) = 0;
88177633Sdfr	while ((ch = *src++) != '\0') {
89177633Sdfr		const char *pch;
90177633Sdfr
91177633Sdfr		if ((pch = strchr(digits, ch)) != NULL) {
92177633Sdfr			u_int new = *tp * 10 + (pch - digits);
93177633Sdfr
94177633Sdfr			if (saw_digit && *tp == 0)
95177633Sdfr				return (0);
96177633Sdfr			if (new > 255)
97177633Sdfr				return (0);
98177633Sdfr			*tp = new;
99177633Sdfr			if (!saw_digit) {
100177633Sdfr				if (++octets > 4)
101177633Sdfr					return (0);
102177633Sdfr				saw_digit = 1;
103177633Sdfr			}
104177633Sdfr		} else if (ch == '.' && saw_digit) {
105177633Sdfr			if (octets == 4)
106177633Sdfr				return (0);
107177633Sdfr			*++tp = 0;
108177633Sdfr			saw_digit = 0;
109177633Sdfr		} else
110177633Sdfr			return (0);
111177633Sdfr	}
112177633Sdfr	if (octets < 4)
113177633Sdfr		return (0);
114177633Sdfr	memcpy(dst, tmp, NS_INADDRSZ);
115177633Sdfr	return (1);
116177633Sdfr}
117177633Sdfr
118177633Sdfr/* int
119177633Sdfr * inet_pton6(src, dst)
120177633Sdfr *	convert presentation level address to network order binary form.
121177633Sdfr * return:
122177633Sdfr *	1 if `src' is a valid [RFC1884 2.2] address, else 0.
123177633Sdfr * notice:
124177633Sdfr *	(1) does not touch `dst' unless it's returning 1.
125177633Sdfr *	(2) :: in a full address is silently ignored.
126177633Sdfr * credit:
127177633Sdfr *	inspired by Mark Andrews.
128177633Sdfr * author:
129177633Sdfr *	Paul Vixie, 1996.
130177633Sdfr */
131177633Sdfrstatic int
132177633Sdfrinet_pton6(const char *src, u_char *dst)
133177633Sdfr{
134177633Sdfr	static const char xdigits_l[] = "0123456789abcdef",
135177633Sdfr			  xdigits_u[] = "0123456789ABCDEF";
136177633Sdfr#define NS_IN6ADDRSZ	16
137177633Sdfr#define NS_INT16SZ	2
138177633Sdfr	u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
139177633Sdfr	const char *xdigits, *curtok;
140177633Sdfr	int ch, seen_xdigits;
141177633Sdfr	u_int val;
142177633Sdfr
143177633Sdfr	memset((tp = tmp), '\0', NS_IN6ADDRSZ);
144177633Sdfr	endp = tp + NS_IN6ADDRSZ;
145177633Sdfr	colonp = NULL;
146177633Sdfr	/* Leading :: requires some special handling. */
147177633Sdfr	if (*src == ':')
148177633Sdfr		if (*++src != ':')
149177633Sdfr			return (0);
150177633Sdfr	curtok = src;
151177633Sdfr	seen_xdigits = 0;
152177633Sdfr	val = 0;
153177633Sdfr	while ((ch = *src++) != '\0') {
154177633Sdfr		const char *pch;
155177633Sdfr
156177633Sdfr		if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
157177633Sdfr			pch = strchr((xdigits = xdigits_u), ch);
158177633Sdfr		if (pch != NULL) {
159177633Sdfr			val <<= 4;
160177633Sdfr			val |= (pch - xdigits);
161177633Sdfr			if (++seen_xdigits > 4)
162177633Sdfr				return (0);
163177633Sdfr			continue;
164177633Sdfr		}
165177633Sdfr		if (ch == ':') {
166177633Sdfr			curtok = src;
167177633Sdfr			if (!seen_xdigits) {
168177633Sdfr				if (colonp)
169177633Sdfr					return (0);
170177633Sdfr				colonp = tp;
171177633Sdfr				continue;
172177633Sdfr			} else if (*src == '\0') {
173177633Sdfr				return (0);
174177633Sdfr			}
175177633Sdfr			if (tp + NS_INT16SZ > endp)
176177633Sdfr				return (0);
177177633Sdfr			*tp++ = (u_char) (val >> 8) & 0xff;
178177633Sdfr			*tp++ = (u_char) val & 0xff;
179177633Sdfr			seen_xdigits = 0;
180177633Sdfr			val = 0;
181177633Sdfr			continue;
182177633Sdfr		}
183177633Sdfr		if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
184177633Sdfr		    inet_pton4(curtok, tp) > 0) {
185177633Sdfr			tp += NS_INADDRSZ;
186177633Sdfr			seen_xdigits = 0;
187177633Sdfr			break;	/*%< '\\0' was seen by inet_pton4(). */
188177633Sdfr		}
189177633Sdfr		return (0);
190177633Sdfr	}
191177633Sdfr	if (seen_xdigits) {
192177633Sdfr		if (tp + NS_INT16SZ > endp)
193177633Sdfr			return (0);
194177633Sdfr		*tp++ = (u_char) (val >> 8) & 0xff;
195177633Sdfr		*tp++ = (u_char) val & 0xff;
196177633Sdfr	}
197177633Sdfr	if (colonp != NULL) {
198177633Sdfr		/*
199177633Sdfr		 * Since some memmove()'s erroneously fail to handle
200177633Sdfr		 * overlapping regions, we'll do the shift by hand.
201177633Sdfr		 */
202177633Sdfr		const int n = tp - colonp;
203177633Sdfr		int i;
204177633Sdfr
205177633Sdfr		if (tp == endp)
206177633Sdfr			return (0);
207177633Sdfr		for (i = 1; i <= n; i++) {
208177633Sdfr			endp[- i] = colonp[n - i];
209177633Sdfr			colonp[n - i] = 0;
210177633Sdfr		}
211177633Sdfr		tp = endp;
212177633Sdfr	}
213177633Sdfr	if (tp != endp)
214177633Sdfr		return (0);
215177633Sdfr	memcpy(dst, tmp, NS_IN6ADDRSZ);
216177633Sdfr	return (1);
217177633Sdfr}
218177633Sdfr
219177633Sdfr/*! \file */
220