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