blob: 16a24840cb84461fd837625181cb8d455a552700 [file] [log] [blame]
Elliott Hughesb1fd7292011-06-08 17:17:53 -07001/* $NetBSD: inet_pton.c,v 1.6.10.1 2011/01/10 00:42:17 riz Exp $ */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002
Elliott Hughesb1fd7292011-06-08 17:17:53 -07003/*
4 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (c) 1996,1999 by Internet Software Consortium.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08006 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
Elliott Hughesb1fd7292011-06-08 17:17:53 -070011 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080018 */
19
Elliott Hughesb1fd7292011-06-08 17:17:53 -070020#include <sys/cdefs.h>
21#if defined(LIBC_SCCS) && !defined(lint)
22#if 0
23static const char rcsid[] = "Id: inet_pton.c,v 1.5 2005/07/28 06:51:47 marka Exp";
24#else
25__RCSID("$NetBSD: inet_pton.c,v 1.6.10.1 2011/01/10 00:42:17 riz Exp $");
26#endif
27#endif /* LIBC_SCCS and not lint */
28
29// BEGIN android-added
30#define _DIAGASSERT(exp) assert(exp)
31#include "../private/arpa_nameser.h"
32// END android-added
33
34// android-removed: #include "port_before.h"
35
36// android-removed: #include "namespace.h"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080037#include <sys/param.h>
38#include <sys/types.h>
39#include <sys/socket.h>
40#include <netinet/in.h>
41#include <arpa/inet.h>
Elliott Hughesb1fd7292011-06-08 17:17:53 -070042#include <arpa/nameser.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080043#include <string.h>
Elliott Hughesb1fd7292011-06-08 17:17:53 -070044#include <assert.h>
45#include <ctype.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080046#include <errno.h>
47
Elliott Hughesb1fd7292011-06-08 17:17:53 -070048// android-removed: #include "port_after.h"
49
50#ifdef __weak_alias
51__weak_alias(inet_pton,_inet_pton)
52#endif
53
54/*%
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080055 * WARNING: Don't even consider trying to compile this on a system where
56 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
57 */
58
Elliott Hughesb1fd7292011-06-08 17:17:53 -070059static int inet_pton4(const char *src, u_char *dst, int pton);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080060static int inet_pton6(const char *src, u_char *dst);
61
62/* int
63 * inet_pton(af, src, dst)
64 * convert from presentation format (which usually means ASCII printable)
65 * to network format (which is usually some kind of binary format).
66 * return:
67 * 1 if the address was valid for the specified address family
68 * 0 if the address wasn't valid (`dst' is untouched in this case)
69 * -1 if some other error occurred (`dst' is untouched in this case, too)
70 * author:
71 * Paul Vixie, 1996.
72 */
73int
74inet_pton(int af, const char *src, void *dst)
75{
Elliott Hughesb1fd7292011-06-08 17:17:53 -070076
77 _DIAGASSERT(src != NULL);
78 _DIAGASSERT(dst != NULL);
79
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080080 switch (af) {
81 case AF_INET:
Elliott Hughesb1fd7292011-06-08 17:17:53 -070082 return (inet_pton4(src, dst, 1));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080083 case AF_INET6:
84 return (inet_pton6(src, dst));
85 default:
86 errno = EAFNOSUPPORT;
87 return (-1);
88 }
89 /* NOTREACHED */
90}
91
92/* int
Elliott Hughesb1fd7292011-06-08 17:17:53 -070093 * inet_pton4(src, dst, pton)
94 * when last arg is 0: inet_aton(). with hexadecimal, octal and shorthand.
95 * when last arg is 1: inet_pton(). decimal dotted-quad only.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080096 * return:
Elliott Hughesb1fd7292011-06-08 17:17:53 -070097 * 1 if `src' is a valid input, else 0.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080098 * notice:
99 * does not touch `dst' unless it's returning 1.
100 * author:
101 * Paul Vixie, 1996.
102 */
103static int
Elliott Hughesb1fd7292011-06-08 17:17:53 -0700104inet_pton4(const char *src, u_char *dst, int pton)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800105{
Elliott Hughesb1fd7292011-06-08 17:17:53 -0700106 u_int32_t val;
107 u_int digit, base;
108 int n;
109 unsigned char c;
110 u_int parts[4];
111 register u_int *pp = parts;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800112
Elliott Hughesb1fd7292011-06-08 17:17:53 -0700113 _DIAGASSERT(src != NULL);
114 _DIAGASSERT(dst != NULL);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800115
Elliott Hughesb1fd7292011-06-08 17:17:53 -0700116 c = *src;
117 for (;;) {
118 /*
119 * Collect number up to ``.''.
120 * Values are specified as for C:
121 * 0x=hex, 0=octal, isdigit=decimal.
122 */
123 if (!isdigit(c))
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800124 return (0);
Elliott Hughesb1fd7292011-06-08 17:17:53 -0700125 val = 0; base = 10;
126 if (c == '0') {
127 c = *++src;
128 if (c == 'x' || c == 'X')
129 base = 16, c = *++src;
130 else if (isdigit(c) && c != '9')
131 base = 8;
132 }
133 /* inet_pton() takes decimal only */
134 if (pton && base != 10)
135 return (0);
136 for (;;) {
137 if (isdigit(c)) {
138 digit = c - '0';
139 if (digit >= base)
140 break;
141 val = (val * base) + digit;
142 c = *++src;
143 } else if (base == 16 && isxdigit(c)) {
144 digit = c + 10 - (islower(c) ? 'a' : 'A');
145 if (digit >= 16)
146 break;
147 val = (val << 4) | digit;
148 c = *++src;
149 } else
150 break;
151 }
152 if (c == '.') {
153 /*
154 * Internet format:
155 * a.b.c.d
156 * a.b.c (with c treated as 16 bits)
157 * a.b (with b treated as 24 bits)
158 * a (with a treated as 32 bits)
159 */
160 if (pp >= parts + 3)
161 return (0);
162 *pp++ = val;
163 c = *++src;
164 } else
165 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800166 }
Elliott Hughesb1fd7292011-06-08 17:17:53 -0700167 /*
168 * Check for trailing characters.
169 */
170 if (c != '\0' && !isspace(c))
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800171 return (0);
Elliott Hughesb1fd7292011-06-08 17:17:53 -0700172 /*
173 * Concoct the address according to
174 * the number of parts specified.
175 */
176 n = pp - parts + 1;
177 /* inet_pton() takes dotted-quad only. it does not take shorthand. */
178 if (pton && n != 4)
179 return (0);
180 switch (n) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800181
Elliott Hughesb1fd7292011-06-08 17:17:53 -0700182 case 0:
183 return (0); /* initial nondigit */
184
185 case 1: /* a -- 32 bits */
186 break;
187
188 case 2: /* a.b -- 8.24 bits */
189 if (parts[0] > 0xff || val > 0xffffff)
190 return (0);
191 val |= parts[0] << 24;
192 break;
193
194 case 3: /* a.b.c -- 8.8.16 bits */
195 if ((parts[0] | parts[1]) > 0xff || val > 0xffff)
196 return (0);
197 val |= (parts[0] << 24) | (parts[1] << 16);
198 break;
199
200 case 4: /* a.b.c.d -- 8.8.8.8 bits */
201 if ((parts[0] | parts[1] | parts[2] | val) > 0xff)
202 return (0);
203 val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
204 break;
205 }
206 if (dst) {
207 val = htonl(val);
208 memcpy(dst, &val, NS_INADDRSZ);
209 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800210 return (1);
211}
212
213/* int
214 * inet_pton6(src, dst)
215 * convert presentation level address to network order binary form.
216 * return:
217 * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
218 * notice:
219 * (1) does not touch `dst' unless it's returning 1.
220 * (2) :: in a full address is silently ignored.
221 * credit:
222 * inspired by Mark Andrews.
223 * author:
224 * Paul Vixie, 1996.
225 */
226static int
227inet_pton6(const char *src, u_char *dst)
228{
229 static const char xdigits_l[] = "0123456789abcdef",
230 xdigits_u[] = "0123456789ABCDEF";
Elliott Hughesb1fd7292011-06-08 17:17:53 -0700231 u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800232 const char *xdigits, *curtok;
Elliott Hughesb1fd7292011-06-08 17:17:53 -0700233 int ch, seen_xdigits;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800234 u_int val;
235
Elliott Hughesb1fd7292011-06-08 17:17:53 -0700236 _DIAGASSERT(src != NULL);
237 _DIAGASSERT(dst != NULL);
238
239 memset((tp = tmp), '\0', NS_IN6ADDRSZ);
240 endp = tp + NS_IN6ADDRSZ;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800241 colonp = NULL;
242 /* Leading :: requires some special handling. */
243 if (*src == ':')
244 if (*++src != ':')
245 return (0);
246 curtok = src;
Elliott Hughesb1fd7292011-06-08 17:17:53 -0700247 seen_xdigits = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800248 val = 0;
249 while ((ch = *src++) != '\0') {
250 const char *pch;
251
252 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
253 pch = strchr((xdigits = xdigits_u), ch);
254 if (pch != NULL) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800255 val <<= 4;
256 val |= (pch - xdigits);
Elliott Hughesb1fd7292011-06-08 17:17:53 -0700257 if (++seen_xdigits > 4)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800258 return (0);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800259 continue;
260 }
261 if (ch == ':') {
262 curtok = src;
Elliott Hughesb1fd7292011-06-08 17:17:53 -0700263 if (!seen_xdigits) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800264 if (colonp)
265 return (0);
266 colonp = tp;
267 continue;
Elliott Hughesb1fd7292011-06-08 17:17:53 -0700268 } else if (*src == '\0')
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800269 return (0);
Elliott Hughesb1fd7292011-06-08 17:17:53 -0700270 if (tp + NS_INT16SZ > endp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800271 return (0);
272 *tp++ = (u_char) (val >> 8) & 0xff;
273 *tp++ = (u_char) val & 0xff;
Elliott Hughesb1fd7292011-06-08 17:17:53 -0700274 seen_xdigits = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800275 val = 0;
276 continue;
277 }
Elliott Hughesb1fd7292011-06-08 17:17:53 -0700278 if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
279 inet_pton4(curtok, tp, 1) > 0) {
280 tp += NS_INADDRSZ;
281 seen_xdigits = 0;
282 break; /*%< '\\0' was seen by inet_pton4(). */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800283 }
284 return (0);
285 }
Elliott Hughesb1fd7292011-06-08 17:17:53 -0700286 if (seen_xdigits) {
287 if (tp + NS_INT16SZ > endp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800288 return (0);
289 *tp++ = (u_char) (val >> 8) & 0xff;
290 *tp++ = (u_char) val & 0xff;
291 }
292 if (colonp != NULL) {
293 /*
294 * Since some memmove()'s erroneously fail to handle
295 * overlapping regions, we'll do the shift by hand.
296 */
297 const int n = tp - colonp;
298 int i;
299
Elliott Hughesb1fd7292011-06-08 17:17:53 -0700300 if (tp == endp)
301 return (0);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800302 for (i = 1; i <= n; i++) {
303 endp[- i] = colonp[n - i];
304 colonp[n - i] = 0;
305 }
306 tp = endp;
307 }
308 if (tp != endp)
309 return (0);
Elliott Hughesb1fd7292011-06-08 17:17:53 -0700310 memcpy(dst, tmp, NS_IN6ADDRSZ);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800311 return (1);
312}
Elliott Hughesb1fd7292011-06-08 17:17:53 -0700313
314/*! \file */