1 /* 2 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (c) 1996,1999 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 ISC DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 15 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #if defined(LIBC_SCCS) && !defined(lint) 19 static const char rcsid[] = "$Id: inet_net_pton.c,v 1.7.18.2 2008/08/26 04:42:43 marka Exp $"; 20 #endif 21 #include <sys/cdefs.h> 22 __FBSDID("$FreeBSD$"); 23 24 #include "port_before.h" 25 26 #include <sys/types.h> 27 #include <sys/socket.h> 28 #include <netinet/in.h> 29 #include <arpa/nameser.h> 30 #include <arpa/inet.h> 31 32 #include <assert.h> 33 #include <ctype.h> 34 #include <errno.h> 35 #include <stdio.h> 36 #include <string.h> 37 #include <stdlib.h> 38 39 #include "port_after.h" 40 41 #ifdef SPRINTF_CHAR 42 # define SPRINTF(x) strlen(sprintf/**/x) 43 #else 44 # define SPRINTF(x) ((size_t)sprintf x) 45 #endif 46 47 /*% 48 * static int 49 * inet_net_pton_ipv4(src, dst, size) 50 * convert IPv4 network number from presentation to network format. 51 * accepts hex octets, hex strings, decimal octets, and /CIDR. 52 * "size" is in bytes and describes "dst". 53 * return: 54 * number of bits, either imputed classfully or specified with /CIDR, 55 * or -1 if some failure occurred (check errno). ENOENT means it was 56 * not an IPv4 network specification. 57 * note: 58 * network byte order assumed. this means 192.5.5.240/28 has 59 * 0b11110000 in its fourth octet. 60 * author: 61 * Paul Vixie (ISC), June 1996 62 */ 63 static int 64 inet_net_pton_ipv4(const char *src, u_char *dst, size_t size) { 65 static const char xdigits[] = "0123456789abcdef"; 66 static const char digits[] = "0123456789"; 67 int n, ch, tmp = 0, dirty, bits; 68 const u_char *odst = dst; 69 70 ch = *src++; 71 if (ch == '0' && (src[0] == 'x' || src[0] == 'X') 72 && isascii((unsigned char)(src[1])) 73 && isxdigit((unsigned char)(src[1]))) { 74 /* Hexadecimal: Eat nybble string. */ 75 if (size <= 0U) 76 goto emsgsize; 77 dirty = 0; 78 src++; /*%< skip x or X. */ 79 while ((ch = *src++) != '\0' && isascii(ch) && isxdigit(ch)) { 80 if (isupper(ch)) 81 ch = tolower(ch); 82 n = strchr(xdigits, ch) - xdigits; 83 assert(n >= 0 && n <= 15); 84 if (dirty == 0) 85 tmp = n; 86 else 87 tmp = (tmp << 4) | n; 88 if (++dirty == 2) { 89 if (size-- <= 0U) 90 goto emsgsize; 91 *dst++ = (u_char) tmp; 92 dirty = 0; 93 } 94 } 95 if (dirty) { /*%< Odd trailing nybble? */ 96 if (size-- <= 0U) 97 goto emsgsize; 98 *dst++ = (u_char) (tmp << 4); 99 } 100 } else if (isascii(ch) && isdigit(ch)) { 101 /* Decimal: eat dotted digit string. */ 102 for (;;) { 103 tmp = 0; 104 do { 105 n = strchr(digits, ch) - digits; 106 assert(n >= 0 && n <= 9); 107 tmp *= 10; 108 tmp += n; 109 if (tmp > 255) 110 goto enoent; 111 } while ((ch = *src++) != '\0' && 112 isascii(ch) && isdigit(ch)); 113 if (size-- <= 0U) 114 goto emsgsize; 115 *dst++ = (u_char) tmp; 116 if (ch == '\0' || ch == '/') 117 break; 118 if (ch != '.') 119 goto enoent; 120 ch = *src++; 121 if (!isascii(ch) || !isdigit(ch)) 122 goto enoent; 123 } 124 } else 125 goto enoent; 126 127 bits = -1; 128 if (ch == '/' && isascii((unsigned char)(src[0])) && 129 isdigit((unsigned char)(src[0])) && dst > odst) { 130 /* CIDR width specifier. Nothing can follow it. */ 131 ch = *src++; /*%< Skip over the /. */ 132 bits = 0; 133 do { 134 n = strchr(digits, ch) - digits; 135 assert(n >= 0 && n <= 9); 136 bits *= 10; 137 bits += n; 138 if (bits > 32) 139 goto enoent; 140 } while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch)); 141 if (ch != '\0') 142 goto enoent; 143 } 144 145 /* Firey death and destruction unless we prefetched EOS. */ 146 if (ch != '\0') 147 goto enoent; 148 149 /* If nothing was written to the destination, we found no address. */ 150 if (dst == odst) 151 goto enoent; 152 /* If no CIDR spec was given, infer width from net class. */ 153 if (bits == -1) { 154 if (*odst >= 240) /*%< Class E */ 155 bits = 32; 156 else if (*odst >= 224) /*%< Class D */ 157 bits = 8; 158 else if (*odst >= 192) /*%< Class C */ 159 bits = 24; 160 else if (*odst >= 128) /*%< Class B */ 161 bits = 16; 162 else /*%< Class A */ 163 bits = 8; 164 /* If imputed mask is narrower than specified octets, widen. */ 165 if (bits < ((dst - odst) * 8)) 166 bits = (dst - odst) * 8; 167 /* 168 * If there are no additional bits specified for a class D 169 * address adjust bits to 4. 170 */ 171 if (bits == 8 && *odst == 224) 172 bits = 4; 173 } 174 /* Extend network to cover the actual mask. */ 175 while (bits > ((dst - odst) * 8)) { 176 if (size-- <= 0U) 177 goto emsgsize; 178 *dst++ = '\0'; 179 } 180 return (bits); 181 182 enoent: 183 errno = ENOENT; 184 return (-1); 185 186 emsgsize: 187 errno = EMSGSIZE; 188 return (-1); 189 } 190 191 static int 192 getbits(const char *src, int *bitsp) { 193 static const char digits[] = "0123456789"; 194 int n; 195 int val; 196 char ch; 197 198 val = 0; 199 n = 0; 200 while ((ch = *src++) != '\0') { 201 const char *pch; 202 203 pch = strchr(digits, ch); 204 if (pch != NULL) { 205 if (n++ != 0 && val == 0) /*%< no leading zeros */ 206 return (0); 207 val *= 10; 208 val += (pch - digits); 209 if (val > 128) /*%< range */ 210 return (0); 211 continue; 212 } 213 return (0); 214 } 215 if (n == 0) 216 return (0); 217 *bitsp = val; 218 return (1); 219 } 220 221 static int 222 getv4(const char *src, u_char *dst, int *bitsp) { 223 static const char digits[] = "0123456789"; 224 u_char *odst = dst; 225 int n; 226 u_int val; 227 char ch; 228 229 val = 0; 230 n = 0; 231 while ((ch = *src++) != '\0') { 232 const char *pch; 233 234 pch = strchr(digits, ch); 235 if (pch != NULL) { 236 if (n++ != 0 && val == 0) /*%< no leading zeros */ 237 return (0); 238 val *= 10; 239 val += (pch - digits); 240 if (val > 255) /*%< range */ 241 return (0); 242 continue; 243 } 244 if (ch == '.' || ch == '/') { 245 if (dst - odst > 3) /*%< too many octets? */ 246 return (0); 247 *dst++ = val; 248 if (ch == '/') 249 return (getbits(src, bitsp)); 250 val = 0; 251 n = 0; 252 continue; 253 } 254 return (0); 255 } 256 if (n == 0) 257 return (0); 258 if (dst - odst > 3) /*%< too many octets? */ 259 return (0); 260 *dst++ = val; 261 return (1); 262 } 263 264 static int 265 inet_net_pton_ipv6(const char *src, u_char *dst, size_t size) { 266 static const char xdigits_l[] = "0123456789abcdef", 267 xdigits_u[] = "0123456789ABCDEF"; 268 u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; 269 const char *xdigits, *curtok; 270 int ch, saw_xdigit; 271 u_int val; 272 int digits; 273 int bits; 274 size_t bytes; 275 int words; 276 int ipv4; 277 278 memset((tp = tmp), '\0', NS_IN6ADDRSZ); 279 endp = tp + NS_IN6ADDRSZ; 280 colonp = NULL; 281 /* Leading :: requires some special handling. */ 282 if (*src == ':') 283 if (*++src != ':') 284 goto enoent; 285 curtok = src; 286 saw_xdigit = 0; 287 val = 0; 288 digits = 0; 289 bits = -1; 290 ipv4 = 0; 291 while ((ch = *src++) != '\0') { 292 const char *pch; 293 294 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) 295 pch = strchr((xdigits = xdigits_u), ch); 296 if (pch != NULL) { 297 val <<= 4; 298 val |= (pch - xdigits); 299 if (++digits > 4) 300 goto enoent; 301 saw_xdigit = 1; 302 continue; 303 } 304 if (ch == ':') { 305 curtok = src; 306 if (!saw_xdigit) { 307 if (colonp) 308 goto enoent; 309 colonp = tp; 310 continue; 311 } else if (*src == '\0') 312 goto enoent; 313 if (tp + NS_INT16SZ > endp) 314 return (0); 315 *tp++ = (u_char) (val >> 8) & 0xff; 316 *tp++ = (u_char) val & 0xff; 317 saw_xdigit = 0; 318 digits = 0; 319 val = 0; 320 continue; 321 } 322 if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && 323 getv4(curtok, tp, &bits) > 0) { 324 tp += NS_INADDRSZ; 325 saw_xdigit = 0; 326 ipv4 = 1; 327 break; /*%< '\\0' was seen by inet_pton4(). */ 328 } 329 if (ch == '/' && getbits(src, &bits) > 0) 330 break; 331 goto enoent; 332 } 333 if (saw_xdigit) { 334 if (tp + NS_INT16SZ > endp) 335 goto enoent; 336 *tp++ = (u_char) (val >> 8) & 0xff; 337 *tp++ = (u_char) val & 0xff; 338 } 339 if (bits == -1) 340 bits = 128; 341 342 words = (bits + 15) / 16; 343 if (words < 2) 344 words = 2; 345 if (ipv4) 346 words = 8; 347 endp = tmp + 2 * words; 348 349 if (colonp != NULL) { 350 /* 351 * Since some memmove()'s erroneously fail to handle 352 * overlapping regions, we'll do the shift by hand. 353 */ 354 const int n = tp - colonp; 355 int i; 356 357 if (tp == endp) 358 goto enoent; 359 for (i = 1; i <= n; i++) { 360 endp[- i] = colonp[n - i]; 361 colonp[n - i] = 0; 362 } 363 tp = endp; 364 } 365 if (tp != endp) 366 goto enoent; 367 368 bytes = (bits + 7) / 8; 369 if (bytes > size) 370 goto emsgsize; 371 memcpy(dst, tmp, bytes); 372 return (bits); 373 374 enoent: 375 errno = ENOENT; 376 return (-1); 377 378 emsgsize: 379 errno = EMSGSIZE; 380 return (-1); 381 } 382 383 /*% 384 * int 385 * inet_net_pton(af, src, dst, size) 386 * convert network number from presentation to network format. 387 * accepts hex octets, hex strings, decimal octets, and /CIDR. 388 * "size" is in bytes and describes "dst". 389 * return: 390 * number of bits, either imputed classfully or specified with /CIDR, 391 * or -1 if some failure occurred (check errno). ENOENT means it was 392 * not a valid network specification. 393 * author: 394 * Paul Vixie (ISC), June 1996 395 */ 396 int 397 inet_net_pton(int af, const char *src, void *dst, size_t size) { 398 switch (af) { 399 case AF_INET: 400 return (inet_net_pton_ipv4(src, dst, size)); 401 case AF_INET6: 402 return (inet_net_pton_ipv6(src, dst, size)); 403 default: 404 errno = EAFNOSUPPORT; 405 return (-1); 406 } 407 } 408 409 /* 410 * Weak aliases for applications that use certain private entry points, 411 * and fail to include <arpa/inet.h>. 412 */ 413 #undef inet_net_pton 414 __weak_reference(__inet_net_pton, inet_net_pton); 415 416 /*! \file */ 417