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