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