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