1 /* $NetBSD: inet_pton.c,v 1.6.10.1 2011/01/10 00:42:17 riz Exp $ */ 2 3 /* 4 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (c) 1996,1999 by Internet Software Consortium. 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 * 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. 18 */ 19 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" 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> 42 #include <arpa/nameser.h> 43 #include <string.h> 44 #include <assert.h> 45 #include <ctype.h> 46 #include <errno.h> 47 48 // android-removed: #include "port_after.h" 49 50 // BEGIN android-removed 51 // #ifdef __weak_alias 52 // __weak_alias(inet_pton,_inet_pton) 53 // #endif 54 // END android-removed 55 56 /*% 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 61 static int inet_pton4(const char *src, u_char *dst, int pton); 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 { 78 79 _DIAGASSERT(src != NULL); 80 _DIAGASSERT(dst != NULL); 81 82 switch (af) { 83 case AF_INET: 84 return (inet_pton4(src, dst, 1)); 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 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. 98 * return: 99 * 1 if `src' is a valid input, else 0. 100 * notice: 101 * does not touch `dst' unless it's returning 1. 102 * author: 103 * Paul Vixie, 1996. 104 */ 105 static int 106 inet_pton4(const char *src, u_char *dst, int pton) 107 { 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; 114 115 _DIAGASSERT(src != NULL); 116 _DIAGASSERT(dst != NULL); 117 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)) 126 return (0); 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; 168 } 169 /* 170 * Check for trailing characters. 171 */ 172 if (c != '\0' && !isspace(c)) 173 return (0); 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) { 183 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 } 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"; 233 u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; 234 const char *xdigits, *curtok; 235 int ch, seen_xdigits; 236 u_int val; 237 238 _DIAGASSERT(src != NULL); 239 _DIAGASSERT(dst != NULL); 240 241 memset((tp = tmp), '\0', NS_IN6ADDRSZ); 242 endp = tp + NS_IN6ADDRSZ; 243 colonp = NULL; 244 /* Leading :: requires some special handling. */ 245 if (*src == ':') 246 if (*++src != ':') 247 return (0); 248 curtok = src; 249 seen_xdigits = 0; 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) { 257 val <<= 4; 258 val |= (pch - xdigits); 259 if (++seen_xdigits > 4) 260 return (0); 261 continue; 262 } 263 if (ch == ':') { 264 curtok = src; 265 if (!seen_xdigits) { 266 if (colonp) 267 return (0); 268 colonp = tp; 269 continue; 270 } else if (*src == '\0') 271 return (0); 272 if (tp + NS_INT16SZ > endp) 273 return (0); 274 *tp++ = (u_char) (val >> 8) & 0xff; 275 *tp++ = (u_char) val & 0xff; 276 seen_xdigits = 0; 277 val = 0; 278 continue; 279 } 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(). */ 285 } 286 return (0); 287 } 288 if (seen_xdigits) { 289 if (tp + NS_INT16SZ > endp) 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 302 if (tp == endp) 303 return (0); 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); 312 memcpy(dst, tmp, NS_IN6ADDRSZ); 313 return (1); 314 } 315 316 /*! \file */ 317