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