xref: /freebsd/sys/libkern/inet_pton.c (revision fdafd315)
1109c1de8SAttilio Rao /*
2109c1de8SAttilio Rao  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3109c1de8SAttilio Rao  * Copyright (c) 1996,1999 by Internet Software Consortium.
4109c1de8SAttilio Rao  *
5109c1de8SAttilio Rao  * Permission to use, copy, modify, and distribute this software for any
6109c1de8SAttilio Rao  * purpose with or without fee is hereby granted, provided that the above
7109c1de8SAttilio Rao  * copyright notice and this permission notice appear in all copies.
8109c1de8SAttilio Rao  *
9109c1de8SAttilio Rao  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10109c1de8SAttilio Rao  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11109c1de8SAttilio Rao  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
12109c1de8SAttilio Rao  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13109c1de8SAttilio Rao  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14109c1de8SAttilio Rao  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15109c1de8SAttilio Rao  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16109c1de8SAttilio Rao  */
17109c1de8SAttilio Rao 
18109c1de8SAttilio Rao #include <sys/param.h>
19109c1de8SAttilio Rao #include <sys/socket.h>
20109c1de8SAttilio Rao #include <sys/systm.h>
21109c1de8SAttilio Rao 
22109c1de8SAttilio Rao #include <netinet/in.h>
23109c1de8SAttilio Rao 
24109c1de8SAttilio Rao /*%
25109c1de8SAttilio Rao  * WARNING: Don't even consider trying to compile this on a system where
26109c1de8SAttilio Rao  * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
27109c1de8SAttilio Rao  */
28109c1de8SAttilio Rao 
29109c1de8SAttilio Rao static int	inet_pton4(const char *src, u_char *dst);
30109c1de8SAttilio Rao static int	inet_pton6(const char *src, u_char *dst);
31109c1de8SAttilio Rao 
32109c1de8SAttilio Rao /* int
33109c1de8SAttilio Rao  * inet_pton(af, src, dst)
34109c1de8SAttilio Rao  *	convert from presentation format (which usually means ASCII printable)
35109c1de8SAttilio Rao  *	to network format (which is usually some kind of binary format).
36109c1de8SAttilio Rao  * return:
37109c1de8SAttilio Rao  *	1 if the address was valid for the specified address family
38109c1de8SAttilio Rao  *	0 if the address wasn't valid (`dst' is untouched in this case)
39109c1de8SAttilio Rao  *	-1 if some other error occurred (`dst' is untouched in this case, too)
40109c1de8SAttilio Rao  * author:
41109c1de8SAttilio Rao  *	Paul Vixie, 1996.
42109c1de8SAttilio Rao  */
43109c1de8SAttilio Rao int
inet_pton(int af,const char * src,void * dst)44109c1de8SAttilio Rao inet_pton(int af, const char *src, void *dst)
45109c1de8SAttilio Rao {
46109c1de8SAttilio Rao 	switch (af) {
47109c1de8SAttilio Rao 	case AF_INET:
48109c1de8SAttilio Rao 		return (inet_pton4(src, dst));
49109c1de8SAttilio Rao 	case AF_INET6:
50109c1de8SAttilio Rao 		return (inet_pton6(src, dst));
51109c1de8SAttilio Rao 	default:
52109c1de8SAttilio Rao 		return (-1);
53109c1de8SAttilio Rao 	}
54109c1de8SAttilio Rao 	/* NOTREACHED */
55109c1de8SAttilio Rao }
56109c1de8SAttilio Rao 
57109c1de8SAttilio Rao /* int
58109c1de8SAttilio Rao  * inet_pton4(src, dst)
59109c1de8SAttilio Rao  *	like inet_aton() but without all the hexadecimal and shorthand.
60109c1de8SAttilio Rao  * return:
61109c1de8SAttilio Rao  *	1 if `src' is a valid dotted quad, else 0.
62109c1de8SAttilio Rao  * notice:
63109c1de8SAttilio Rao  *	does not touch `dst' unless it's returning 1.
64109c1de8SAttilio Rao  * author:
65109c1de8SAttilio Rao  *	Paul Vixie, 1996.
66109c1de8SAttilio Rao  */
67109c1de8SAttilio Rao static int
inet_pton4(const char * src,u_char * dst)68109c1de8SAttilio Rao inet_pton4(const char *src, u_char *dst)
69109c1de8SAttilio Rao {
70109c1de8SAttilio Rao 	static const char digits[] = "0123456789";
71109c1de8SAttilio Rao 	int saw_digit, octets, ch;
72109c1de8SAttilio Rao #define NS_INADDRSZ	4
73109c1de8SAttilio Rao 	u_char tmp[NS_INADDRSZ], *tp;
74109c1de8SAttilio Rao 
75109c1de8SAttilio Rao 	saw_digit = 0;
76109c1de8SAttilio Rao 	octets = 0;
77109c1de8SAttilio Rao 	*(tp = tmp) = 0;
78109c1de8SAttilio Rao 	while ((ch = *src++) != '\0') {
79109c1de8SAttilio Rao 		const char *pch;
80109c1de8SAttilio Rao 
81109c1de8SAttilio Rao 		if ((pch = strchr(digits, ch)) != NULL) {
82109c1de8SAttilio Rao 			u_int new = *tp * 10 + (pch - digits);
83109c1de8SAttilio Rao 
84109c1de8SAttilio Rao 			if (saw_digit && *tp == 0)
85109c1de8SAttilio Rao 				return (0);
86109c1de8SAttilio Rao 			if (new > 255)
87109c1de8SAttilio Rao 				return (0);
88109c1de8SAttilio Rao 			*tp = new;
89109c1de8SAttilio Rao 			if (!saw_digit) {
90109c1de8SAttilio Rao 				if (++octets > 4)
91109c1de8SAttilio Rao 					return (0);
92109c1de8SAttilio Rao 				saw_digit = 1;
93109c1de8SAttilio Rao 			}
94109c1de8SAttilio Rao 		} else if (ch == '.' && saw_digit) {
95109c1de8SAttilio Rao 			if (octets == 4)
96109c1de8SAttilio Rao 				return (0);
97109c1de8SAttilio Rao 			*++tp = 0;
98109c1de8SAttilio Rao 			saw_digit = 0;
99109c1de8SAttilio Rao 		} else
100109c1de8SAttilio Rao 			return (0);
101109c1de8SAttilio Rao 	}
102109c1de8SAttilio Rao 	if (octets < 4)
103109c1de8SAttilio Rao 		return (0);
104109c1de8SAttilio Rao 	memcpy(dst, tmp, NS_INADDRSZ);
105109c1de8SAttilio Rao 	return (1);
106109c1de8SAttilio Rao }
107109c1de8SAttilio Rao 
108109c1de8SAttilio Rao /* int
109109c1de8SAttilio Rao  * inet_pton6(src, dst)
110109c1de8SAttilio Rao  *	convert presentation level address to network order binary form.
111109c1de8SAttilio Rao  * return:
112109c1de8SAttilio Rao  *	1 if `src' is a valid [RFC1884 2.2] address, else 0.
113109c1de8SAttilio Rao  * notice:
114109c1de8SAttilio Rao  *	(1) does not touch `dst' unless it's returning 1.
115109c1de8SAttilio Rao  *	(2) :: in a full address is silently ignored.
116109c1de8SAttilio Rao  * credit:
117109c1de8SAttilio Rao  *	inspired by Mark Andrews.
118109c1de8SAttilio Rao  * author:
119109c1de8SAttilio Rao  *	Paul Vixie, 1996.
120109c1de8SAttilio Rao  */
121109c1de8SAttilio Rao static int
inet_pton6(const char * src,u_char * dst)122109c1de8SAttilio Rao inet_pton6(const char *src, u_char *dst)
123109c1de8SAttilio Rao {
124109c1de8SAttilio Rao 	static const char xdigits_l[] = "0123456789abcdef",
125109c1de8SAttilio Rao 			  xdigits_u[] = "0123456789ABCDEF";
126109c1de8SAttilio Rao #define NS_IN6ADDRSZ	16
127109c1de8SAttilio Rao #define NS_INT16SZ	2
128109c1de8SAttilio Rao 	u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
129109c1de8SAttilio Rao 	const char *xdigits, *curtok;
130109c1de8SAttilio Rao 	int ch, seen_xdigits;
131109c1de8SAttilio Rao 	u_int val;
132109c1de8SAttilio Rao 
133109c1de8SAttilio Rao 	memset((tp = tmp), '\0', NS_IN6ADDRSZ);
134109c1de8SAttilio Rao 	endp = tp + NS_IN6ADDRSZ;
135109c1de8SAttilio Rao 	colonp = NULL;
136109c1de8SAttilio Rao 	/* Leading :: requires some special handling. */
137109c1de8SAttilio Rao 	if (*src == ':')
138109c1de8SAttilio Rao 		if (*++src != ':')
139109c1de8SAttilio Rao 			return (0);
140109c1de8SAttilio Rao 	curtok = src;
141109c1de8SAttilio Rao 	seen_xdigits = 0;
142109c1de8SAttilio Rao 	val = 0;
143109c1de8SAttilio Rao 	while ((ch = *src++) != '\0') {
144109c1de8SAttilio Rao 		const char *pch;
145109c1de8SAttilio Rao 
146109c1de8SAttilio Rao 		if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
147109c1de8SAttilio Rao 			pch = strchr((xdigits = xdigits_u), ch);
148109c1de8SAttilio Rao 		if (pch != NULL) {
149109c1de8SAttilio Rao 			val <<= 4;
150109c1de8SAttilio Rao 			val |= (pch - xdigits);
151109c1de8SAttilio Rao 			if (++seen_xdigits > 4)
152109c1de8SAttilio Rao 				return (0);
153109c1de8SAttilio Rao 			continue;
154109c1de8SAttilio Rao 		}
155109c1de8SAttilio Rao 		if (ch == ':') {
156109c1de8SAttilio Rao 			curtok = src;
157109c1de8SAttilio Rao 			if (!seen_xdigits) {
158109c1de8SAttilio Rao 				if (colonp)
159109c1de8SAttilio Rao 					return (0);
160109c1de8SAttilio Rao 				colonp = tp;
161109c1de8SAttilio Rao 				continue;
162109c1de8SAttilio Rao 			} else if (*src == '\0') {
163109c1de8SAttilio Rao 				return (0);
164109c1de8SAttilio Rao 			}
165109c1de8SAttilio Rao 			if (tp + NS_INT16SZ > endp)
166109c1de8SAttilio Rao 				return (0);
167109c1de8SAttilio Rao 			*tp++ = (u_char) (val >> 8) & 0xff;
168109c1de8SAttilio Rao 			*tp++ = (u_char) val & 0xff;
169109c1de8SAttilio Rao 			seen_xdigits = 0;
170109c1de8SAttilio Rao 			val = 0;
171109c1de8SAttilio Rao 			continue;
172109c1de8SAttilio Rao 		}
173109c1de8SAttilio Rao 		if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
174109c1de8SAttilio Rao 		    inet_pton4(curtok, tp) > 0) {
175109c1de8SAttilio Rao 			tp += NS_INADDRSZ;
176109c1de8SAttilio Rao 			seen_xdigits = 0;
177109c1de8SAttilio Rao 			break;	/*%< '\\0' was seen by inet_pton4(). */
178109c1de8SAttilio Rao 		}
179109c1de8SAttilio Rao 		return (0);
180109c1de8SAttilio Rao 	}
181109c1de8SAttilio Rao 	if (seen_xdigits) {
182109c1de8SAttilio Rao 		if (tp + NS_INT16SZ > endp)
183109c1de8SAttilio Rao 			return (0);
184109c1de8SAttilio Rao 		*tp++ = (u_char) (val >> 8) & 0xff;
185109c1de8SAttilio Rao 		*tp++ = (u_char) val & 0xff;
186109c1de8SAttilio Rao 	}
187109c1de8SAttilio Rao 	if (colonp != NULL) {
188109c1de8SAttilio Rao 		/*
189109c1de8SAttilio Rao 		 * Since some memmove()'s erroneously fail to handle
190109c1de8SAttilio Rao 		 * overlapping regions, we'll do the shift by hand.
191109c1de8SAttilio Rao 		 */
192109c1de8SAttilio Rao 		const int n = tp - colonp;
193109c1de8SAttilio Rao 		int i;
194109c1de8SAttilio Rao 
195109c1de8SAttilio Rao 		if (tp == endp)
196109c1de8SAttilio Rao 			return (0);
197109c1de8SAttilio Rao 		for (i = 1; i <= n; i++) {
198109c1de8SAttilio Rao 			endp[- i] = colonp[n - i];
199109c1de8SAttilio Rao 			colonp[n - i] = 0;
200109c1de8SAttilio Rao 		}
201109c1de8SAttilio Rao 		tp = endp;
202109c1de8SAttilio Rao 	}
203109c1de8SAttilio Rao 	if (tp != endp)
204109c1de8SAttilio Rao 		return (0);
205109c1de8SAttilio Rao 	memcpy(dst, tmp, NS_IN6ADDRSZ);
206109c1de8SAttilio Rao 	return (1);
207109c1de8SAttilio Rao }
208109c1de8SAttilio Rao 
209109c1de8SAttilio Rao /*! \file */
210