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