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