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