xref: /freebsd-src/sys/libkern/inet_pton.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
1*109c1de8SAttilio Rao /*
2*109c1de8SAttilio Rao  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3*109c1de8SAttilio Rao  * Copyright (c) 1996,1999 by Internet Software Consortium.
4*109c1de8SAttilio Rao  *
5*109c1de8SAttilio Rao  * Permission to use, copy, modify, and distribute this software for any
6*109c1de8SAttilio Rao  * purpose with or without fee is hereby granted, provided that the above
7*109c1de8SAttilio Rao  * copyright notice and this permission notice appear in all copies.
8*109c1de8SAttilio Rao  *
9*109c1de8SAttilio Rao  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10*109c1de8SAttilio Rao  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11*109c1de8SAttilio Rao  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
12*109c1de8SAttilio Rao  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13*109c1de8SAttilio Rao  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14*109c1de8SAttilio Rao  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15*109c1de8SAttilio Rao  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16*109c1de8SAttilio Rao  */
17*109c1de8SAttilio Rao 
18*109c1de8SAttilio Rao #include <sys/param.h>
19*109c1de8SAttilio Rao #include <sys/socket.h>
20*109c1de8SAttilio Rao #include <sys/systm.h>
21*109c1de8SAttilio Rao 
22*109c1de8SAttilio Rao #include <netinet/in.h>
23*109c1de8SAttilio Rao 
24*109c1de8SAttilio Rao /*%
25*109c1de8SAttilio Rao  * WARNING: Don't even consider trying to compile this on a system where
26*109c1de8SAttilio Rao  * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
27*109c1de8SAttilio Rao  */
28*109c1de8SAttilio Rao 
29*109c1de8SAttilio Rao static int	inet_pton4(const char *src, u_char *dst);
30*109c1de8SAttilio Rao static int	inet_pton6(const char *src, u_char *dst);
31*109c1de8SAttilio Rao 
32*109c1de8SAttilio Rao /* int
33*109c1de8SAttilio Rao  * inet_pton(af, src, dst)
34*109c1de8SAttilio Rao  *	convert from presentation format (which usually means ASCII printable)
35*109c1de8SAttilio Rao  *	to network format (which is usually some kind of binary format).
36*109c1de8SAttilio Rao  * return:
37*109c1de8SAttilio Rao  *	1 if the address was valid for the specified address family
38*109c1de8SAttilio Rao  *	0 if the address wasn't valid (`dst' is untouched in this case)
39*109c1de8SAttilio Rao  *	-1 if some other error occurred (`dst' is untouched in this case, too)
40*109c1de8SAttilio Rao  * author:
41*109c1de8SAttilio Rao  *	Paul Vixie, 1996.
42*109c1de8SAttilio Rao  */
43*109c1de8SAttilio Rao int
inet_pton(int af,const char * src,void * dst)44*109c1de8SAttilio Rao inet_pton(int af, const char *src, void *dst)
45*109c1de8SAttilio Rao {
46*109c1de8SAttilio Rao 	switch (af) {
47*109c1de8SAttilio Rao 	case AF_INET:
48*109c1de8SAttilio Rao 		return (inet_pton4(src, dst));
49*109c1de8SAttilio Rao 	case AF_INET6:
50*109c1de8SAttilio Rao 		return (inet_pton6(src, dst));
51*109c1de8SAttilio Rao 	default:
52*109c1de8SAttilio Rao 		return (-1);
53*109c1de8SAttilio Rao 	}
54*109c1de8SAttilio Rao 	/* NOTREACHED */
55*109c1de8SAttilio Rao }
56*109c1de8SAttilio Rao 
57*109c1de8SAttilio Rao /* int
58*109c1de8SAttilio Rao  * inet_pton4(src, dst)
59*109c1de8SAttilio Rao  *	like inet_aton() but without all the hexadecimal and shorthand.
60*109c1de8SAttilio Rao  * return:
61*109c1de8SAttilio Rao  *	1 if `src' is a valid dotted quad, else 0.
62*109c1de8SAttilio Rao  * notice:
63*109c1de8SAttilio Rao  *	does not touch `dst' unless it's returning 1.
64*109c1de8SAttilio Rao  * author:
65*109c1de8SAttilio Rao  *	Paul Vixie, 1996.
66*109c1de8SAttilio Rao  */
67*109c1de8SAttilio Rao static int
inet_pton4(const char * src,u_char * dst)68*109c1de8SAttilio Rao inet_pton4(const char *src, u_char *dst)
69*109c1de8SAttilio Rao {
70*109c1de8SAttilio Rao 	static const char digits[] = "0123456789";
71*109c1de8SAttilio Rao 	int saw_digit, octets, ch;
72*109c1de8SAttilio Rao #define NS_INADDRSZ	4
73*109c1de8SAttilio Rao 	u_char tmp[NS_INADDRSZ], *tp;
74*109c1de8SAttilio Rao 
75*109c1de8SAttilio Rao 	saw_digit = 0;
76*109c1de8SAttilio Rao 	octets = 0;
77*109c1de8SAttilio Rao 	*(tp = tmp) = 0;
78*109c1de8SAttilio Rao 	while ((ch = *src++) != '\0') {
79*109c1de8SAttilio Rao 		const char *pch;
80*109c1de8SAttilio Rao 
81*109c1de8SAttilio Rao 		if ((pch = strchr(digits, ch)) != NULL) {
82*109c1de8SAttilio Rao 			u_int new = *tp * 10 + (pch - digits);
83*109c1de8SAttilio Rao 
84*109c1de8SAttilio Rao 			if (saw_digit && *tp == 0)
85*109c1de8SAttilio Rao 				return (0);
86*109c1de8SAttilio Rao 			if (new > 255)
87*109c1de8SAttilio Rao 				return (0);
88*109c1de8SAttilio Rao 			*tp = new;
89*109c1de8SAttilio Rao 			if (!saw_digit) {
90*109c1de8SAttilio Rao 				if (++octets > 4)
91*109c1de8SAttilio Rao 					return (0);
92*109c1de8SAttilio Rao 				saw_digit = 1;
93*109c1de8SAttilio Rao 			}
94*109c1de8SAttilio Rao 		} else if (ch == '.' && saw_digit) {
95*109c1de8SAttilio Rao 			if (octets == 4)
96*109c1de8SAttilio Rao 				return (0);
97*109c1de8SAttilio Rao 			*++tp = 0;
98*109c1de8SAttilio Rao 			saw_digit = 0;
99*109c1de8SAttilio Rao 		} else
100*109c1de8SAttilio Rao 			return (0);
101*109c1de8SAttilio Rao 	}
102*109c1de8SAttilio Rao 	if (octets < 4)
103*109c1de8SAttilio Rao 		return (0);
104*109c1de8SAttilio Rao 	memcpy(dst, tmp, NS_INADDRSZ);
105*109c1de8SAttilio Rao 	return (1);
106*109c1de8SAttilio Rao }
107*109c1de8SAttilio Rao 
108*109c1de8SAttilio Rao /* int
109*109c1de8SAttilio Rao  * inet_pton6(src, dst)
110*109c1de8SAttilio Rao  *	convert presentation level address to network order binary form.
111*109c1de8SAttilio Rao  * return:
112*109c1de8SAttilio Rao  *	1 if `src' is a valid [RFC1884 2.2] address, else 0.
113*109c1de8SAttilio Rao  * notice:
114*109c1de8SAttilio Rao  *	(1) does not touch `dst' unless it's returning 1.
115*109c1de8SAttilio Rao  *	(2) :: in a full address is silently ignored.
116*109c1de8SAttilio Rao  * credit:
117*109c1de8SAttilio Rao  *	inspired by Mark Andrews.
118*109c1de8SAttilio Rao  * author:
119*109c1de8SAttilio Rao  *	Paul Vixie, 1996.
120*109c1de8SAttilio Rao  */
121*109c1de8SAttilio Rao static int
inet_pton6(const char * src,u_char * dst)122*109c1de8SAttilio Rao inet_pton6(const char *src, u_char *dst)
123*109c1de8SAttilio Rao {
124*109c1de8SAttilio Rao 	static const char xdigits_l[] = "0123456789abcdef",
125*109c1de8SAttilio Rao 			  xdigits_u[] = "0123456789ABCDEF";
126*109c1de8SAttilio Rao #define NS_IN6ADDRSZ	16
127*109c1de8SAttilio Rao #define NS_INT16SZ	2
128*109c1de8SAttilio Rao 	u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
129*109c1de8SAttilio Rao 	const char *xdigits, *curtok;
130*109c1de8SAttilio Rao 	int ch, seen_xdigits;
131*109c1de8SAttilio Rao 	u_int val;
132*109c1de8SAttilio Rao 
133*109c1de8SAttilio Rao 	memset((tp = tmp), '\0', NS_IN6ADDRSZ);
134*109c1de8SAttilio Rao 	endp = tp + NS_IN6ADDRSZ;
135*109c1de8SAttilio Rao 	colonp = NULL;
136*109c1de8SAttilio Rao 	/* Leading :: requires some special handling. */
137*109c1de8SAttilio Rao 	if (*src == ':')
138*109c1de8SAttilio Rao 		if (*++src != ':')
139*109c1de8SAttilio Rao 			return (0);
140*109c1de8SAttilio Rao 	curtok = src;
141*109c1de8SAttilio Rao 	seen_xdigits = 0;
142*109c1de8SAttilio Rao 	val = 0;
143*109c1de8SAttilio Rao 	while ((ch = *src++) != '\0') {
144*109c1de8SAttilio Rao 		const char *pch;
145*109c1de8SAttilio Rao 
146*109c1de8SAttilio Rao 		if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
147*109c1de8SAttilio Rao 			pch = strchr((xdigits = xdigits_u), ch);
148*109c1de8SAttilio Rao 		if (pch != NULL) {
149*109c1de8SAttilio Rao 			val <<= 4;
150*109c1de8SAttilio Rao 			val |= (pch - xdigits);
151*109c1de8SAttilio Rao 			if (++seen_xdigits > 4)
152*109c1de8SAttilio Rao 				return (0);
153*109c1de8SAttilio Rao 			continue;
154*109c1de8SAttilio Rao 		}
155*109c1de8SAttilio Rao 		if (ch == ':') {
156*109c1de8SAttilio Rao 			curtok = src;
157*109c1de8SAttilio Rao 			if (!seen_xdigits) {
158*109c1de8SAttilio Rao 				if (colonp)
159*109c1de8SAttilio Rao 					return (0);
160*109c1de8SAttilio Rao 				colonp = tp;
161*109c1de8SAttilio Rao 				continue;
162*109c1de8SAttilio Rao 			} else if (*src == '\0') {
163*109c1de8SAttilio Rao 				return (0);
164*109c1de8SAttilio Rao 			}
165*109c1de8SAttilio Rao 			if (tp + NS_INT16SZ > endp)
166*109c1de8SAttilio Rao 				return (0);
167*109c1de8SAttilio Rao 			*tp++ = (u_char) (val >> 8) & 0xff;
168*109c1de8SAttilio Rao 			*tp++ = (u_char) val & 0xff;
169*109c1de8SAttilio Rao 			seen_xdigits = 0;
170*109c1de8SAttilio Rao 			val = 0;
171*109c1de8SAttilio Rao 			continue;
172*109c1de8SAttilio Rao 		}
173*109c1de8SAttilio Rao 		if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
174*109c1de8SAttilio Rao 		    inet_pton4(curtok, tp) > 0) {
175*109c1de8SAttilio Rao 			tp += NS_INADDRSZ;
176*109c1de8SAttilio Rao 			seen_xdigits = 0;
177*109c1de8SAttilio Rao 			break;	/*%< '\\0' was seen by inet_pton4(). */
178*109c1de8SAttilio Rao 		}
179*109c1de8SAttilio Rao 		return (0);
180*109c1de8SAttilio Rao 	}
181*109c1de8SAttilio Rao 	if (seen_xdigits) {
182*109c1de8SAttilio Rao 		if (tp + NS_INT16SZ > endp)
183*109c1de8SAttilio Rao 			return (0);
184*109c1de8SAttilio Rao 		*tp++ = (u_char) (val >> 8) & 0xff;
185*109c1de8SAttilio Rao 		*tp++ = (u_char) val & 0xff;
186*109c1de8SAttilio Rao 	}
187*109c1de8SAttilio Rao 	if (colonp != NULL) {
188*109c1de8SAttilio Rao 		/*
189*109c1de8SAttilio Rao 		 * Since some memmove()'s erroneously fail to handle
190*109c1de8SAttilio Rao 		 * overlapping regions, we'll do the shift by hand.
191*109c1de8SAttilio Rao 		 */
192*109c1de8SAttilio Rao 		const int n = tp - colonp;
193*109c1de8SAttilio Rao 		int i;
194*109c1de8SAttilio Rao 
195*109c1de8SAttilio Rao 		if (tp == endp)
196*109c1de8SAttilio Rao 			return (0);
197*109c1de8SAttilio Rao 		for (i = 1; i <= n; i++) {
198*109c1de8SAttilio Rao 			endp[- i] = colonp[n - i];
199*109c1de8SAttilio Rao 			colonp[n - i] = 0;
200*109c1de8SAttilio Rao 		}
201*109c1de8SAttilio Rao 		tp = endp;
202*109c1de8SAttilio Rao 	}
203*109c1de8SAttilio Rao 	if (tp != endp)
204*109c1de8SAttilio Rao 		return (0);
205*109c1de8SAttilio Rao 	memcpy(dst, tmp, NS_IN6ADDRSZ);
206*109c1de8SAttilio Rao 	return (1);
207*109c1de8SAttilio Rao }
208*109c1de8SAttilio Rao 
209*109c1de8SAttilio Rao /*! \file */
210