| Elliott Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 1 | /*	$NetBSD: inet_pton.c,v 1.6.10.1 2011/01/10 00:42:17 riz Exp $	*/ | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 2 |  | 
| Elliott Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 3 | /* | 
|  | 4 | * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") | 
|  | 5 | * Copyright (c) 1996,1999 by Internet Software Consortium. | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 6 | * | 
|  | 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 Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 11 | * 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 Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 18 | */ | 
|  | 19 |  | 
| Elliott Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 20 | #include <sys/cdefs.h> | 
|  | 21 | #if defined(LIBC_SCCS) && !defined(lint) | 
|  | 22 | #if 0 | 
|  | 23 | static 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 Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 37 | #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 Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 42 | #include <arpa/nameser.h> | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 43 | #include <string.h> | 
| Elliott Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 44 | #include <assert.h> | 
|  | 45 | #include <ctype.h> | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 46 | #include <errno.h> | 
|  | 47 |  | 
| Elliott Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 48 | // android-removed: #include "port_after.h" | 
|  | 49 |  | 
| Elliott Hughes | 3398ee9 | 2011-06-09 13:03:03 -0700 | [diff] [blame] | 50 | // BEGIN android-removed | 
|  | 51 | // #ifdef __weak_alias | 
|  | 52 | // __weak_alias(inet_pton,_inet_pton) | 
|  | 53 | // #endif | 
|  | 54 | // END android-removed | 
| Elliott Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 55 |  | 
|  | 56 | /*% | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 57 | * WARNING: Don't even consider trying to compile this on a system where | 
|  | 58 | * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX. | 
|  | 59 | */ | 
|  | 60 |  | 
| Elliott Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 61 | static int	inet_pton4(const char *src, u_char *dst, int pton); | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 62 | static int	inet_pton6(const char *src, u_char *dst); | 
|  | 63 |  | 
|  | 64 | /* int | 
|  | 65 | * inet_pton(af, src, dst) | 
|  | 66 | *	convert from presentation format (which usually means ASCII printable) | 
|  | 67 | *	to network format (which is usually some kind of binary format). | 
|  | 68 | * return: | 
|  | 69 | *	1 if the address was valid for the specified address family | 
|  | 70 | *	0 if the address wasn't valid (`dst' is untouched in this case) | 
|  | 71 | *	-1 if some other error occurred (`dst' is untouched in this case, too) | 
|  | 72 | * author: | 
|  | 73 | *	Paul Vixie, 1996. | 
|  | 74 | */ | 
|  | 75 | int | 
|  | 76 | inet_pton(int af, const char *src, void *dst) | 
|  | 77 | { | 
| Elliott Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 78 |  | 
|  | 79 | _DIAGASSERT(src != NULL); | 
|  | 80 | _DIAGASSERT(dst != NULL); | 
|  | 81 |  | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 82 | switch (af) { | 
|  | 83 | case AF_INET: | 
| Elliott Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 84 | return (inet_pton4(src, dst, 1)); | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 85 | case AF_INET6: | 
|  | 86 | return (inet_pton6(src, dst)); | 
|  | 87 | default: | 
|  | 88 | errno = EAFNOSUPPORT; | 
|  | 89 | return (-1); | 
|  | 90 | } | 
|  | 91 | /* NOTREACHED */ | 
|  | 92 | } | 
|  | 93 |  | 
|  | 94 | /* int | 
| Elliott Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 95 | * inet_pton4(src, dst, pton) | 
|  | 96 | *	when last arg is 0: inet_aton(). with hexadecimal, octal and shorthand. | 
|  | 97 | *	when last arg is 1: inet_pton(). decimal dotted-quad only. | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 98 | * return: | 
| Elliott Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 99 | *	1 if `src' is a valid input, else 0. | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 100 | * notice: | 
|  | 101 | *	does not touch `dst' unless it's returning 1. | 
|  | 102 | * author: | 
|  | 103 | *	Paul Vixie, 1996. | 
|  | 104 | */ | 
|  | 105 | static int | 
| Elliott Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 106 | inet_pton4(const char *src, u_char *dst, int pton) | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 107 | { | 
| Elliott Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 108 | u_int32_t val; | 
|  | 109 | u_int digit, base; | 
|  | 110 | int n; | 
|  | 111 | unsigned char c; | 
|  | 112 | u_int parts[4]; | 
|  | 113 | register u_int *pp = parts; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 114 |  | 
| Elliott Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 115 | _DIAGASSERT(src != NULL); | 
|  | 116 | _DIAGASSERT(dst != NULL); | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 117 |  | 
| Elliott Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 118 | c = *src; | 
|  | 119 | for (;;) { | 
|  | 120 | /* | 
|  | 121 | * Collect number up to ``.''. | 
|  | 122 | * Values are specified as for C: | 
|  | 123 | * 0x=hex, 0=octal, isdigit=decimal. | 
|  | 124 | */ | 
|  | 125 | if (!isdigit(c)) | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 126 | return (0); | 
| Elliott Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 127 | val = 0; base = 10; | 
|  | 128 | if (c == '0') { | 
|  | 129 | c = *++src; | 
|  | 130 | if (c == 'x' || c == 'X') | 
|  | 131 | base = 16, c = *++src; | 
|  | 132 | else if (isdigit(c) && c != '9') | 
|  | 133 | base = 8; | 
|  | 134 | } | 
|  | 135 | /* inet_pton() takes decimal only */ | 
|  | 136 | if (pton && base != 10) | 
|  | 137 | return (0); | 
|  | 138 | for (;;) { | 
|  | 139 | if (isdigit(c)) { | 
|  | 140 | digit = c - '0'; | 
|  | 141 | if (digit >= base) | 
|  | 142 | break; | 
|  | 143 | val = (val * base) + digit; | 
|  | 144 | c = *++src; | 
|  | 145 | } else if (base == 16 && isxdigit(c)) { | 
|  | 146 | digit = c + 10 - (islower(c) ? 'a' : 'A'); | 
|  | 147 | if (digit >= 16) | 
|  | 148 | break; | 
|  | 149 | val = (val << 4) | digit; | 
|  | 150 | c = *++src; | 
|  | 151 | } else | 
|  | 152 | break; | 
|  | 153 | } | 
|  | 154 | if (c == '.') { | 
|  | 155 | /* | 
|  | 156 | * Internet format: | 
|  | 157 | *	a.b.c.d | 
|  | 158 | *	a.b.c	(with c treated as 16 bits) | 
|  | 159 | *	a.b	(with b treated as 24 bits) | 
|  | 160 | *	a	(with a treated as 32 bits) | 
|  | 161 | */ | 
|  | 162 | if (pp >= parts + 3) | 
|  | 163 | return (0); | 
|  | 164 | *pp++ = val; | 
|  | 165 | c = *++src; | 
|  | 166 | } else | 
|  | 167 | break; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 168 | } | 
| Elliott Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 169 | /* | 
|  | 170 | * Check for trailing characters. | 
|  | 171 | */ | 
|  | 172 | if (c != '\0' && !isspace(c)) | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 173 | return (0); | 
| Elliott Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 174 | /* | 
|  | 175 | * Concoct the address according to | 
|  | 176 | * the number of parts specified. | 
|  | 177 | */ | 
|  | 178 | n = pp - parts + 1; | 
|  | 179 | /* inet_pton() takes dotted-quad only.  it does not take shorthand. */ | 
|  | 180 | if (pton && n != 4) | 
|  | 181 | return (0); | 
|  | 182 | switch (n) { | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 183 |  | 
| Elliott Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 184 | case 0: | 
|  | 185 | return (0);		/* initial nondigit */ | 
|  | 186 |  | 
|  | 187 | case 1:				/* a -- 32 bits */ | 
|  | 188 | break; | 
|  | 189 |  | 
|  | 190 | case 2:				/* a.b -- 8.24 bits */ | 
|  | 191 | if (parts[0] > 0xff || val > 0xffffff) | 
|  | 192 | return (0); | 
|  | 193 | val |= parts[0] << 24; | 
|  | 194 | break; | 
|  | 195 |  | 
|  | 196 | case 3:				/* a.b.c -- 8.8.16 bits */ | 
|  | 197 | if ((parts[0] | parts[1]) > 0xff || val > 0xffff) | 
|  | 198 | return (0); | 
|  | 199 | val |= (parts[0] << 24) | (parts[1] << 16); | 
|  | 200 | break; | 
|  | 201 |  | 
|  | 202 | case 4:				/* a.b.c.d -- 8.8.8.8 bits */ | 
|  | 203 | if ((parts[0] | parts[1] | parts[2] | val) > 0xff) | 
|  | 204 | return (0); | 
|  | 205 | val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); | 
|  | 206 | break; | 
|  | 207 | } | 
|  | 208 | if (dst) { | 
|  | 209 | val = htonl(val); | 
|  | 210 | memcpy(dst, &val, NS_INADDRSZ); | 
|  | 211 | } | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 212 | return (1); | 
|  | 213 | } | 
|  | 214 |  | 
|  | 215 | /* int | 
|  | 216 | * inet_pton6(src, dst) | 
|  | 217 | *	convert presentation level address to network order binary form. | 
|  | 218 | * return: | 
|  | 219 | *	1 if `src' is a valid [RFC1884 2.2] address, else 0. | 
|  | 220 | * notice: | 
|  | 221 | *	(1) does not touch `dst' unless it's returning 1. | 
|  | 222 | *	(2) :: in a full address is silently ignored. | 
|  | 223 | * credit: | 
|  | 224 | *	inspired by Mark Andrews. | 
|  | 225 | * author: | 
|  | 226 | *	Paul Vixie, 1996. | 
|  | 227 | */ | 
|  | 228 | static int | 
|  | 229 | inet_pton6(const char *src, u_char *dst) | 
|  | 230 | { | 
|  | 231 | static const char xdigits_l[] = "0123456789abcdef", | 
|  | 232 | xdigits_u[] = "0123456789ABCDEF"; | 
| Elliott Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 233 | u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 234 | const char *xdigits, *curtok; | 
| Elliott Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 235 | int ch, seen_xdigits; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 236 | u_int val; | 
|  | 237 |  | 
| Elliott Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 238 | _DIAGASSERT(src != NULL); | 
|  | 239 | _DIAGASSERT(dst != NULL); | 
|  | 240 |  | 
|  | 241 | memset((tp = tmp), '\0', NS_IN6ADDRSZ); | 
|  | 242 | endp = tp + NS_IN6ADDRSZ; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 243 | colonp = NULL; | 
|  | 244 | /* Leading :: requires some special handling. */ | 
|  | 245 | if (*src == ':') | 
|  | 246 | if (*++src != ':') | 
|  | 247 | return (0); | 
|  | 248 | curtok = src; | 
| Elliott Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 249 | seen_xdigits = 0; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 250 | val = 0; | 
|  | 251 | while ((ch = *src++) != '\0') { | 
|  | 252 | const char *pch; | 
|  | 253 |  | 
|  | 254 | if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) | 
|  | 255 | pch = strchr((xdigits = xdigits_u), ch); | 
|  | 256 | if (pch != NULL) { | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 257 | val <<= 4; | 
|  | 258 | val |= (pch - xdigits); | 
| Elliott Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 259 | if (++seen_xdigits > 4) | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 260 | return (0); | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 261 | continue; | 
|  | 262 | } | 
|  | 263 | if (ch == ':') { | 
|  | 264 | curtok = src; | 
| Elliott Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 265 | if (!seen_xdigits) { | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 266 | if (colonp) | 
|  | 267 | return (0); | 
|  | 268 | colonp = tp; | 
|  | 269 | continue; | 
| Elliott Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 270 | } else if (*src == '\0') | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 271 | return (0); | 
| Elliott Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 272 | if (tp + NS_INT16SZ > endp) | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 273 | return (0); | 
|  | 274 | *tp++ = (u_char) (val >> 8) & 0xff; | 
|  | 275 | *tp++ = (u_char) val & 0xff; | 
| Elliott Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 276 | seen_xdigits = 0; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 277 | val = 0; | 
|  | 278 | continue; | 
|  | 279 | } | 
| Elliott Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 280 | if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && | 
|  | 281 | inet_pton4(curtok, tp, 1) > 0) { | 
|  | 282 | tp += NS_INADDRSZ; | 
|  | 283 | seen_xdigits = 0; | 
|  | 284 | break;	/*%< '\\0' was seen by inet_pton4(). */ | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 285 | } | 
|  | 286 | return (0); | 
|  | 287 | } | 
| Elliott Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 288 | if (seen_xdigits) { | 
|  | 289 | if (tp + NS_INT16SZ > endp) | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 290 | return (0); | 
|  | 291 | *tp++ = (u_char) (val >> 8) & 0xff; | 
|  | 292 | *tp++ = (u_char) val & 0xff; | 
|  | 293 | } | 
|  | 294 | if (colonp != NULL) { | 
|  | 295 | /* | 
|  | 296 | * Since some memmove()'s erroneously fail to handle | 
|  | 297 | * overlapping regions, we'll do the shift by hand. | 
|  | 298 | */ | 
|  | 299 | const int n = tp - colonp; | 
|  | 300 | int i; | 
|  | 301 |  | 
| Elliott Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 302 | if (tp == endp) | 
|  | 303 | return (0); | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 304 | for (i = 1; i <= n; i++) { | 
|  | 305 | endp[- i] = colonp[n - i]; | 
|  | 306 | colonp[n - i] = 0; | 
|  | 307 | } | 
|  | 308 | tp = endp; | 
|  | 309 | } | 
|  | 310 | if (tp != endp) | 
|  | 311 | return (0); | 
| Elliott Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 312 | memcpy(dst, tmp, NS_IN6ADDRSZ); | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 313 | return (1); | 
|  | 314 | } | 
| Elliott Hughes | b1fd729 | 2011-06-08 17:17:53 -0700 | [diff] [blame] | 315 |  | 
|  | 316 | /*! \file */ |