1 /* 2 * Copyright 1997-2002 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * Copyright (c) 1996,1999 by Internet Software Consortium. 8 * 9 * Permission to use, copy, modify, and distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS 14 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 15 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 16 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 17 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 18 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 19 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 20 * SOFTWARE. 21 */ 22 23 #pragma ident "%Z%%M% %I% %E% SMI" 24 25 #if defined(LIBC_SCCS) && !defined(lint) 26 static const char rcsid[] = "$Id: inet_net_pton.c,v 1.13 2001/09/27 15:08:38 marka Exp $"; 27 #endif 28 29 #include "port_before.h" 30 31 #include <sys/types.h> 32 #include <sys/socket.h> 33 #include <netinet/in.h> 34 #include <arpa/nameser.h> 35 #include <arpa/inet.h> 36 37 #include <isc/assertions.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 SPRINTF_CHAR 47 # define SPRINTF(x) strlen(sprintf/**/x) 48 #else 49 # define SPRINTF(x) ((size_t)sprintf x) 50 #endif 51 52 /* 53 * static int 54 * inet_net_pton_ipv4(src, dst, size) 55 * convert IPv4 network number from presentation to network format. 56 * accepts hex octets, hex strings, decimal octets, and /CIDR. 57 * "size" is in bytes and describes "dst". 58 * return: 59 * number of bits, either imputed classfully or specified with /CIDR, 60 * or -1 if some failure occurred (check errno). ENOENT means it was 61 * not an IPv4 network specification. 62 * note: 63 * network byte order assumed. this means 192.5.5.240/28 has 64 * 0b11110000 in its fourth octet. 65 * author: 66 * Paul Vixie (ISC), June 1996 67 */ 68 static int 69 inet_net_pton_ipv4( const char *src, u_char *dst, size_t size) { 70 static const char xdigits[] = "0123456789abcdef"; 71 static const char digits[] = "0123456789"; 72 int n, ch, tmp = 0, dirty, bits; 73 const u_char *odst = dst; 74 75 ch = *src++; 76 if (ch == '0' && (src[0] == 'x' || src[0] == 'X') 77 && isascii((unsigned char)(src[1])) 78 && isxdigit((unsigned char)(src[1]))) { 79 /* Hexadecimal: Eat nybble string. */ 80 if (size <= 0) 81 goto emsgsize; 82 dirty = 0; 83 src++; /* skip x or X. */ 84 while ((ch = *src++) != '\0' && isascii(ch) && isxdigit(ch)) { 85 if (isupper(ch)) 86 ch = tolower(ch); 87 n = strchr(xdigits, ch) - xdigits; 88 INSIST(n >= 0 && n <= 15); 89 if (dirty == 0) 90 tmp = n; 91 else 92 tmp = (tmp << 4) | n; 93 if (++dirty == 2) { 94 if (size-- <= 0) 95 goto emsgsize; 96 *dst++ = (u_char) tmp; 97 dirty = 0; 98 } 99 } 100 if (dirty) { /* Odd trailing nybble? */ 101 if (size-- <= 0) 102 goto emsgsize; 103 *dst++ = (u_char) (tmp << 4); 104 } 105 } else if (isascii(ch) && isdigit(ch)) { 106 /* Decimal: eat dotted digit string. */ 107 for (;;) { 108 tmp = 0; 109 do { 110 n = strchr(digits, ch) - digits; 111 INSIST(n >= 0 && n <= 9); 112 tmp *= 10; 113 tmp += n; 114 if (tmp > 255) 115 goto enoent; 116 } while ((ch = *src++) != '\0' && 117 isascii(ch) && isdigit(ch)); 118 if (size-- <= 0) 119 goto emsgsize; 120 *dst++ = (u_char) tmp; 121 if (ch == '\0' || ch == '/') 122 break; 123 if (ch != '.') 124 goto enoent; 125 ch = *src++; 126 if (!isascii(ch) || !isdigit(ch)) 127 goto enoent; 128 } 129 } else 130 goto enoent; 131 132 bits = -1; 133 if (ch == '/' && isascii((unsigned char)(src[0])) && 134 isdigit((unsigned char)(src[0])) && dst > odst) { 135 /* CIDR width specifier. Nothing can follow it. */ 136 ch = *src++; /* Skip over the /. */ 137 bits = 0; 138 do { 139 n = strchr(digits, ch) - digits; 140 INSIST(n >= 0 && n <= 9); 141 bits *= 10; 142 bits += n; 143 } while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch)); 144 if (ch != '\0') 145 goto enoent; 146 if (bits > 32) 147 goto emsgsize; 148 } 149 150 /* Firey death and destruction unless we prefetched EOS. */ 151 if (ch != '\0') 152 goto enoent; 153 154 /* If nothing was written to the destination, we found no address. */ 155 if (dst == odst) 156 goto enoent; 157 /* If no CIDR spec was given, infer width from net class. */ 158 if (bits == -1) { 159 if (*odst >= 240) /* Class E */ 160 bits = 32; 161 else if (*odst >= 224) /* Class D */ 162 bits = 4; 163 else if (*odst >= 192) /* Class C */ 164 bits = 24; 165 else if (*odst >= 128) /* Class B */ 166 bits = 16; 167 else /* Class A */ 168 bits = 8; 169 /* If imputed mask is narrower than specified octets, widen. */ 170 if (bits >= 8 && bits < ((dst - odst) * 8)) 171 bits = (dst - odst) * 8; 172 } 173 /* Extend network to cover the actual mask. */ 174 while (bits > ((dst - odst) * 8)) { 175 if (size-- <= 0) 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