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