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