1156952Sume/* 2156952Sume * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 3156952Sume * Copyright (c) 1996,1999 by Internet Software Consortium. 4156952Sume * 5156952Sume * Permission to use, copy, modify, and distribute this software for any 6156952Sume * purpose with or without fee is hereby granted, provided that the above 7156952Sume * copyright notice and this permission notice appear in all copies. 8156952Sume * 9156952Sume * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 10156952Sume * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11156952Sume * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 12156952Sume * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13156952Sume * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14156952Sume * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 15156952Sume * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16156952Sume */ 17156952Sume 18156952Sume#if defined(LIBC_SCCS) && !defined(lint) 19186090Sumestatic const char rcsid[] = "$Id: inet_net_pton.c,v 1.7.18.2 2008/08/26 04:42:43 marka Exp $"; 20156952Sume#endif 21156956Sume#include <sys/cdefs.h> 22156956Sume__FBSDID("$FreeBSD$"); 23156952Sume 24156952Sume#include "port_before.h" 25156952Sume 26156952Sume#include <sys/types.h> 27156952Sume#include <sys/socket.h> 28156952Sume#include <netinet/in.h> 29156952Sume#include <arpa/nameser.h> 30156952Sume#include <arpa/inet.h> 31156952Sume 32156956Sume#include <assert.h> 33156952Sume#include <ctype.h> 34156952Sume#include <errno.h> 35156952Sume#include <stdio.h> 36156952Sume#include <string.h> 37156952Sume#include <stdlib.h> 38156952Sume 39156952Sume#include "port_after.h" 40156952Sume 41156952Sume#ifdef SPRINTF_CHAR 42156952Sume# define SPRINTF(x) strlen(sprintf/**/x) 43156952Sume#else 44156952Sume# define SPRINTF(x) ((size_t)sprintf x) 45156952Sume#endif 46156952Sume 47170244Sume/*% 48156952Sume * static int 49156952Sume * inet_net_pton_ipv4(src, dst, size) 50156952Sume * convert IPv4 network number from presentation to network format. 51156952Sume * accepts hex octets, hex strings, decimal octets, and /CIDR. 52156952Sume * "size" is in bytes and describes "dst". 53156952Sume * return: 54156952Sume * number of bits, either imputed classfully or specified with /CIDR, 55156952Sume * or -1 if some failure occurred (check errno). ENOENT means it was 56156952Sume * not an IPv4 network specification. 57156952Sume * note: 58156952Sume * network byte order assumed. this means 192.5.5.240/28 has 59156952Sume * 0b11110000 in its fourth octet. 60156952Sume * author: 61156952Sume * Paul Vixie (ISC), June 1996 62156952Sume */ 63156952Sumestatic int 64156952Sumeinet_net_pton_ipv4(const char *src, u_char *dst, size_t size) { 65156952Sume static const char xdigits[] = "0123456789abcdef"; 66156952Sume static const char digits[] = "0123456789"; 67156952Sume int n, ch, tmp = 0, dirty, bits; 68156952Sume const u_char *odst = dst; 69156952Sume 70156952Sume ch = *src++; 71156952Sume if (ch == '0' && (src[0] == 'x' || src[0] == 'X') 72156952Sume && isascii((unsigned char)(src[1])) 73156952Sume && isxdigit((unsigned char)(src[1]))) { 74156952Sume /* Hexadecimal: Eat nybble string. */ 75156952Sume if (size <= 0U) 76156952Sume goto emsgsize; 77156952Sume dirty = 0; 78170244Sume src++; /*%< skip x or X. */ 79156952Sume while ((ch = *src++) != '\0' && isascii(ch) && isxdigit(ch)) { 80156952Sume if (isupper(ch)) 81156952Sume ch = tolower(ch); 82156952Sume n = strchr(xdigits, ch) - xdigits; 83156956Sume assert(n >= 0 && n <= 15); 84156952Sume if (dirty == 0) 85156952Sume tmp = n; 86156952Sume else 87156952Sume tmp = (tmp << 4) | n; 88156952Sume if (++dirty == 2) { 89156952Sume if (size-- <= 0U) 90156952Sume goto emsgsize; 91156952Sume *dst++ = (u_char) tmp; 92156952Sume dirty = 0; 93156952Sume } 94156952Sume } 95170244Sume if (dirty) { /*%< Odd trailing nybble? */ 96156952Sume if (size-- <= 0U) 97156952Sume goto emsgsize; 98156952Sume *dst++ = (u_char) (tmp << 4); 99156952Sume } 100156952Sume } else if (isascii(ch) && isdigit(ch)) { 101156952Sume /* Decimal: eat dotted digit string. */ 102156952Sume for (;;) { 103156952Sume tmp = 0; 104156952Sume do { 105156952Sume n = strchr(digits, ch) - digits; 106156956Sume assert(n >= 0 && n <= 9); 107156952Sume tmp *= 10; 108156952Sume tmp += n; 109156952Sume if (tmp > 255) 110156952Sume goto enoent; 111156952Sume } while ((ch = *src++) != '\0' && 112156952Sume isascii(ch) && isdigit(ch)); 113156952Sume if (size-- <= 0U) 114156952Sume goto emsgsize; 115156952Sume *dst++ = (u_char) tmp; 116156952Sume if (ch == '\0' || ch == '/') 117156952Sume break; 118156952Sume if (ch != '.') 119156952Sume goto enoent; 120156952Sume ch = *src++; 121156952Sume if (!isascii(ch) || !isdigit(ch)) 122156952Sume goto enoent; 123156952Sume } 124156952Sume } else 125156952Sume goto enoent; 126156952Sume 127156952Sume bits = -1; 128156952Sume if (ch == '/' && isascii((unsigned char)(src[0])) && 129156952Sume isdigit((unsigned char)(src[0])) && dst > odst) { 130156952Sume /* CIDR width specifier. Nothing can follow it. */ 131170244Sume ch = *src++; /*%< Skip over the /. */ 132156952Sume bits = 0; 133156952Sume do { 134156952Sume n = strchr(digits, ch) - digits; 135156956Sume assert(n >= 0 && n <= 9); 136156952Sume bits *= 10; 137156952Sume bits += n; 138186090Sume if (bits > 32) 139186090Sume goto enoent; 140156952Sume } while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch)); 141156952Sume if (ch != '\0') 142156952Sume goto enoent; 143156952Sume } 144156952Sume 145156952Sume /* Firey death and destruction unless we prefetched EOS. */ 146156952Sume if (ch != '\0') 147156952Sume goto enoent; 148156952Sume 149156952Sume /* If nothing was written to the destination, we found no address. */ 150156952Sume if (dst == odst) 151156952Sume goto enoent; 152156952Sume /* If no CIDR spec was given, infer width from net class. */ 153156952Sume if (bits == -1) { 154170244Sume if (*odst >= 240) /*%< Class E */ 155156952Sume bits = 32; 156170244Sume else if (*odst >= 224) /*%< Class D */ 157156952Sume bits = 8; 158170244Sume else if (*odst >= 192) /*%< Class C */ 159156952Sume bits = 24; 160170244Sume else if (*odst >= 128) /*%< Class B */ 161156952Sume bits = 16; 162170244Sume else /*%< Class A */ 163156952Sume bits = 8; 164156952Sume /* If imputed mask is narrower than specified octets, widen. */ 165156952Sume if (bits < ((dst - odst) * 8)) 166156952Sume bits = (dst - odst) * 8; 167156952Sume /* 168156952Sume * If there are no additional bits specified for a class D 169156952Sume * address adjust bits to 4. 170156952Sume */ 171156952Sume if (bits == 8 && *odst == 224) 172156952Sume bits = 4; 173156952Sume } 174156952Sume /* Extend network to cover the actual mask. */ 175156952Sume while (bits > ((dst - odst) * 8)) { 176156952Sume if (size-- <= 0U) 177156952Sume goto emsgsize; 178156952Sume *dst++ = '\0'; 179156952Sume } 180156952Sume return (bits); 181156952Sume 182156952Sume enoent: 183156952Sume errno = ENOENT; 184156952Sume return (-1); 185156952Sume 186156952Sume emsgsize: 187156952Sume errno = EMSGSIZE; 188156952Sume return (-1); 189156952Sume} 190156952Sume 191156952Sumestatic int 192156952Sumegetbits(const char *src, int *bitsp) { 193156952Sume static const char digits[] = "0123456789"; 194156952Sume int n; 195156952Sume int val; 196156952Sume char ch; 197156952Sume 198156952Sume val = 0; 199156952Sume n = 0; 200156952Sume while ((ch = *src++) != '\0') { 201156952Sume const char *pch; 202156952Sume 203156952Sume pch = strchr(digits, ch); 204156952Sume if (pch != NULL) { 205170244Sume if (n++ != 0 && val == 0) /*%< no leading zeros */ 206156952Sume return (0); 207156952Sume val *= 10; 208156952Sume val += (pch - digits); 209170244Sume if (val > 128) /*%< range */ 210156952Sume return (0); 211156952Sume continue; 212156952Sume } 213156952Sume return (0); 214156952Sume } 215156952Sume if (n == 0) 216156952Sume return (0); 217156952Sume *bitsp = val; 218156952Sume return (1); 219156952Sume} 220156952Sume 221156952Sumestatic int 222156952Sumegetv4(const char *src, u_char *dst, int *bitsp) { 223156952Sume static const char digits[] = "0123456789"; 224156952Sume u_char *odst = dst; 225156952Sume int n; 226156952Sume u_int val; 227156952Sume char ch; 228156952Sume 229156952Sume val = 0; 230156952Sume n = 0; 231156952Sume while ((ch = *src++) != '\0') { 232156952Sume const char *pch; 233156952Sume 234156952Sume pch = strchr(digits, ch); 235156952Sume if (pch != NULL) { 236170244Sume if (n++ != 0 && val == 0) /*%< no leading zeros */ 237156952Sume return (0); 238156952Sume val *= 10; 239156952Sume val += (pch - digits); 240170244Sume if (val > 255) /*%< range */ 241156952Sume return (0); 242156952Sume continue; 243156952Sume } 244156952Sume if (ch == '.' || ch == '/') { 245170244Sume if (dst - odst > 3) /*%< too many octets? */ 246156952Sume return (0); 247156952Sume *dst++ = val; 248156952Sume if (ch == '/') 249156952Sume return (getbits(src, bitsp)); 250156952Sume val = 0; 251156952Sume n = 0; 252156952Sume continue; 253156952Sume } 254156952Sume return (0); 255156952Sume } 256156952Sume if (n == 0) 257156952Sume return (0); 258170244Sume if (dst - odst > 3) /*%< too many octets? */ 259156952Sume return (0); 260156952Sume *dst++ = val; 261156952Sume return (1); 262156952Sume} 263156952Sume 264156952Sumestatic int 265156952Sumeinet_net_pton_ipv6(const char *src, u_char *dst, size_t size) { 266156952Sume static const char xdigits_l[] = "0123456789abcdef", 267156952Sume xdigits_u[] = "0123456789ABCDEF"; 268156952Sume u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; 269156952Sume const char *xdigits, *curtok; 270156952Sume int ch, saw_xdigit; 271156952Sume u_int val; 272156952Sume int digits; 273156952Sume int bits; 274156952Sume size_t bytes; 275156952Sume int words; 276156952Sume int ipv4; 277156952Sume 278156952Sume memset((tp = tmp), '\0', NS_IN6ADDRSZ); 279156952Sume endp = tp + NS_IN6ADDRSZ; 280156952Sume colonp = NULL; 281156952Sume /* Leading :: requires some special handling. */ 282156952Sume if (*src == ':') 283156952Sume if (*++src != ':') 284156952Sume goto enoent; 285156952Sume curtok = src; 286156952Sume saw_xdigit = 0; 287156952Sume val = 0; 288156952Sume digits = 0; 289156952Sume bits = -1; 290156952Sume ipv4 = 0; 291156952Sume while ((ch = *src++) != '\0') { 292156952Sume const char *pch; 293156952Sume 294156952Sume if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) 295156952Sume pch = strchr((xdigits = xdigits_u), ch); 296156952Sume if (pch != NULL) { 297156952Sume val <<= 4; 298156952Sume val |= (pch - xdigits); 299156952Sume if (++digits > 4) 300156952Sume goto enoent; 301156952Sume saw_xdigit = 1; 302156952Sume continue; 303156952Sume } 304156952Sume if (ch == ':') { 305156952Sume curtok = src; 306156952Sume if (!saw_xdigit) { 307156952Sume if (colonp) 308156952Sume goto enoent; 309156952Sume colonp = tp; 310156952Sume continue; 311156952Sume } else if (*src == '\0') 312156952Sume goto enoent; 313156952Sume if (tp + NS_INT16SZ > endp) 314156952Sume return (0); 315156952Sume *tp++ = (u_char) (val >> 8) & 0xff; 316156952Sume *tp++ = (u_char) val & 0xff; 317156952Sume saw_xdigit = 0; 318156952Sume digits = 0; 319156952Sume val = 0; 320156952Sume continue; 321156952Sume } 322156952Sume if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && 323156952Sume getv4(curtok, tp, &bits) > 0) { 324156952Sume tp += NS_INADDRSZ; 325156952Sume saw_xdigit = 0; 326156952Sume ipv4 = 1; 327170244Sume break; /*%< '\\0' was seen by inet_pton4(). */ 328156952Sume } 329156952Sume if (ch == '/' && getbits(src, &bits) > 0) 330156952Sume break; 331156952Sume goto enoent; 332156952Sume } 333156952Sume if (saw_xdigit) { 334156952Sume if (tp + NS_INT16SZ > endp) 335156952Sume goto enoent; 336156952Sume *tp++ = (u_char) (val >> 8) & 0xff; 337156952Sume *tp++ = (u_char) val & 0xff; 338156952Sume } 339156952Sume if (bits == -1) 340156952Sume bits = 128; 341156952Sume 342156952Sume words = (bits + 15) / 16; 343156952Sume if (words < 2) 344156952Sume words = 2; 345156952Sume if (ipv4) 346156952Sume words = 8; 347156952Sume endp = tmp + 2 * words; 348156952Sume 349156952Sume if (colonp != NULL) { 350156952Sume /* 351156952Sume * Since some memmove()'s erroneously fail to handle 352156952Sume * overlapping regions, we'll do the shift by hand. 353156952Sume */ 354156952Sume const int n = tp - colonp; 355156952Sume int i; 356156952Sume 357156952Sume if (tp == endp) 358156952Sume goto enoent; 359156952Sume for (i = 1; i <= n; i++) { 360156952Sume endp[- i] = colonp[n - i]; 361156952Sume colonp[n - i] = 0; 362156952Sume } 363156952Sume tp = endp; 364156952Sume } 365156952Sume if (tp != endp) 366156952Sume goto enoent; 367156952Sume 368156952Sume bytes = (bits + 7) / 8; 369156952Sume if (bytes > size) 370156952Sume goto emsgsize; 371156952Sume memcpy(dst, tmp, bytes); 372156952Sume return (bits); 373156952Sume 374156952Sume enoent: 375156952Sume errno = ENOENT; 376156952Sume return (-1); 377156952Sume 378156952Sume emsgsize: 379156952Sume errno = EMSGSIZE; 380156952Sume return (-1); 381156952Sume} 382156952Sume 383170244Sume/*% 384156952Sume * int 385156952Sume * inet_net_pton(af, src, dst, size) 386156952Sume * convert network number from presentation to network format. 387156952Sume * accepts hex octets, hex strings, decimal octets, and /CIDR. 388156952Sume * "size" is in bytes and describes "dst". 389156952Sume * return: 390156952Sume * number of bits, either imputed classfully or specified with /CIDR, 391156952Sume * or -1 if some failure occurred (check errno). ENOENT means it was 392156952Sume * not a valid network specification. 393156952Sume * author: 394156952Sume * Paul Vixie (ISC), June 1996 395156952Sume */ 396156952Sumeint 397156952Sumeinet_net_pton(int af, const char *src, void *dst, size_t size) { 398156952Sume switch (af) { 399156952Sume case AF_INET: 400156952Sume return (inet_net_pton_ipv4(src, dst, size)); 401156952Sume case AF_INET6: 402156952Sume return (inet_net_pton_ipv6(src, dst, size)); 403156952Sume default: 404156952Sume errno = EAFNOSUPPORT; 405156952Sume return (-1); 406156952Sume } 407156952Sume} 408156956Sume 409156956Sume/* 410156956Sume * Weak aliases for applications that use certain private entry points, 411156956Sume * and fail to include <arpa/inet.h>. 412156956Sume */ 413156956Sume#undef inet_net_pton 414156956Sume__weak_reference(__inet_net_pton, inet_net_pton); 415170244Sume 416170244Sume/*! \file */ 417