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