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