13340d773SGleb Smirnoff /* 23340d773SGleb Smirnoff * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 33340d773SGleb Smirnoff * Copyright (c) 1996,1999 by Internet Software Consortium. 43340d773SGleb Smirnoff * 53340d773SGleb Smirnoff * Permission to use, copy, modify, and distribute this software for any 63340d773SGleb Smirnoff * purpose with or without fee is hereby granted, provided that the above 73340d773SGleb Smirnoff * copyright notice and this permission notice appear in all copies. 83340d773SGleb Smirnoff * 93340d773SGleb Smirnoff * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 103340d773SGleb Smirnoff * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 113340d773SGleb Smirnoff * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 123340d773SGleb Smirnoff * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 133340d773SGleb Smirnoff * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 143340d773SGleb Smirnoff * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 153340d773SGleb Smirnoff * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 163340d773SGleb Smirnoff */ 173340d773SGleb Smirnoff 18*ee67461eSJoseph Mingrone #include <config.h> 193340d773SGleb Smirnoff 20*ee67461eSJoseph Mingrone #include "netdissect-stdinc.h" 213340d773SGleb Smirnoff #include <stddef.h> 223340d773SGleb Smirnoff #include <string.h> 233340d773SGleb Smirnoff 24*ee67461eSJoseph Mingrone #include "netdissect-ctype.h" 25*ee67461eSJoseph Mingrone 263340d773SGleb Smirnoff #include "strtoaddr.h" 273340d773SGleb Smirnoff 283340d773SGleb Smirnoff #ifndef NS_INADDRSZ 293340d773SGleb Smirnoff #define NS_INADDRSZ 4 /* IPv4 T_A */ 303340d773SGleb Smirnoff #endif 313340d773SGleb Smirnoff 323340d773SGleb Smirnoff #ifndef NS_IN6ADDRSZ 333340d773SGleb Smirnoff #define NS_IN6ADDRSZ 16 /* IPv6 T_AAAA */ 343340d773SGleb Smirnoff #endif 353340d773SGleb Smirnoff 363340d773SGleb Smirnoff #ifndef NS_INT16SZ 373340d773SGleb Smirnoff #define NS_INT16SZ 2 /* #/bytes of data in a uint16_t */ 383340d773SGleb Smirnoff #endif 393340d773SGleb Smirnoff 403340d773SGleb Smirnoff /*% 413340d773SGleb Smirnoff * WARNING: Don't even consider trying to compile this on a system where 423340d773SGleb Smirnoff * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. 433340d773SGleb Smirnoff */ 443340d773SGleb Smirnoff 453340d773SGleb Smirnoff /* int 463340d773SGleb Smirnoff * strtoaddr(src, dst) 473340d773SGleb Smirnoff * convert presentation level IPv4 address to network order binary form. 483340d773SGleb Smirnoff * return: 493340d773SGleb Smirnoff * 1 if `src' is a valid input, else 0. 503340d773SGleb Smirnoff * notice: 513340d773SGleb Smirnoff * does not touch `dst' unless it's returning 1. 523340d773SGleb Smirnoff * author: 533340d773SGleb Smirnoff * Paul Vixie, 1996. 543340d773SGleb Smirnoff */ 553340d773SGleb Smirnoff int 563340d773SGleb Smirnoff strtoaddr(const char *src, void *dst) 573340d773SGleb Smirnoff { 583340d773SGleb Smirnoff uint32_t val; 593340d773SGleb Smirnoff u_int digit; 603340d773SGleb Smirnoff ptrdiff_t n; 613340d773SGleb Smirnoff unsigned char c; 623340d773SGleb Smirnoff u_int parts[4]; 633340d773SGleb Smirnoff u_int *pp = parts; 643340d773SGleb Smirnoff 653340d773SGleb Smirnoff c = *src; 663340d773SGleb Smirnoff for (;;) { 673340d773SGleb Smirnoff /* 683340d773SGleb Smirnoff * Collect number up to ``.''. 693340d773SGleb Smirnoff * Values are specified as for C: 703340d773SGleb Smirnoff * 0x=hex, 0=octal, isdigit=decimal. 713340d773SGleb Smirnoff */ 72*ee67461eSJoseph Mingrone if (!ND_ASCII_ISDIGIT(c)) 733340d773SGleb Smirnoff return (0); 743340d773SGleb Smirnoff val = 0; 753340d773SGleb Smirnoff if (c == '0') { 763340d773SGleb Smirnoff c = *++src; 773340d773SGleb Smirnoff if (c == 'x' || c == 'X') 783340d773SGleb Smirnoff return (0); 79*ee67461eSJoseph Mingrone else if (ND_ASCII_ISDIGIT(c) && c != '9') 803340d773SGleb Smirnoff return (0); 813340d773SGleb Smirnoff } 823340d773SGleb Smirnoff for (;;) { 83*ee67461eSJoseph Mingrone if (ND_ASCII_ISDIGIT(c)) { 843340d773SGleb Smirnoff digit = c - '0'; 853340d773SGleb Smirnoff val = (val * 10) + digit; 863340d773SGleb Smirnoff c = *++src; 873340d773SGleb Smirnoff } else 883340d773SGleb Smirnoff break; 893340d773SGleb Smirnoff } 903340d773SGleb Smirnoff if (c == '.') { 913340d773SGleb Smirnoff /* 923340d773SGleb Smirnoff * Internet format: 933340d773SGleb Smirnoff * a.b.c.d 943340d773SGleb Smirnoff * a.b.c (with c treated as 16 bits) 953340d773SGleb Smirnoff * a.b (with b treated as 24 bits) 963340d773SGleb Smirnoff * a (with a treated as 32 bits) 973340d773SGleb Smirnoff */ 983340d773SGleb Smirnoff if (pp >= parts + 3) 993340d773SGleb Smirnoff return (0); 1003340d773SGleb Smirnoff *pp++ = val; 1013340d773SGleb Smirnoff c = *++src; 1023340d773SGleb Smirnoff } else 1033340d773SGleb Smirnoff break; 1043340d773SGleb Smirnoff } 1053340d773SGleb Smirnoff /* 1063340d773SGleb Smirnoff * Check for trailing characters. 1073340d773SGleb Smirnoff */ 108*ee67461eSJoseph Mingrone if (c != '\0' && c != ' ' && c != '\t') 1093340d773SGleb Smirnoff return (0); 1103340d773SGleb Smirnoff /* 1113340d773SGleb Smirnoff * Find the number of parts specified. 1123340d773SGleb Smirnoff * It must be 4; we only support dotted quads, we don't 1133340d773SGleb Smirnoff * support shorthand. 1143340d773SGleb Smirnoff */ 1153340d773SGleb Smirnoff n = pp - parts + 1; 1163340d773SGleb Smirnoff if (n != 4) 1173340d773SGleb Smirnoff return (0); 1183340d773SGleb Smirnoff /* 1193340d773SGleb Smirnoff * parts[0-2] were set to the first 3 parts of the address; 1203340d773SGleb Smirnoff * val was set to the 4th part. 1213340d773SGleb Smirnoff * 1223340d773SGleb Smirnoff * Check if any part is bigger than 255. 1233340d773SGleb Smirnoff */ 1243340d773SGleb Smirnoff if ((parts[0] | parts[1] | parts[2] | val) > 0xff) 1253340d773SGleb Smirnoff return (0); 1263340d773SGleb Smirnoff /* 1273340d773SGleb Smirnoff * Add the other three parts to val. 1283340d773SGleb Smirnoff */ 1293340d773SGleb Smirnoff val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); 1303340d773SGleb Smirnoff if (dst) { 1313340d773SGleb Smirnoff val = htonl(val); 1323340d773SGleb Smirnoff memcpy(dst, &val, NS_INADDRSZ); 1333340d773SGleb Smirnoff } 1343340d773SGleb Smirnoff return (1); 1353340d773SGleb Smirnoff } 1363340d773SGleb Smirnoff 1373340d773SGleb Smirnoff /* int 1383340d773SGleb Smirnoff * strtoaddr6(src, dst) 1393340d773SGleb Smirnoff * convert presentation level IPv6 address to network order binary form. 1403340d773SGleb Smirnoff * return: 1413340d773SGleb Smirnoff * 1 if `src' is a valid [RFC1884 2.2] address, else 0. 1423340d773SGleb Smirnoff * notice: 1433340d773SGleb Smirnoff * (1) does not touch `dst' unless it's returning 1. 1443340d773SGleb Smirnoff * (2) :: in a full address is silently ignored. 1453340d773SGleb Smirnoff * credit: 1463340d773SGleb Smirnoff * inspired by Mark Andrews. 1473340d773SGleb Smirnoff * author: 1483340d773SGleb Smirnoff * Paul Vixie, 1996. 1493340d773SGleb Smirnoff */ 1503340d773SGleb Smirnoff int 1513340d773SGleb Smirnoff strtoaddr6(const char *src, void *dst) 1523340d773SGleb Smirnoff { 1533340d773SGleb Smirnoff static const char xdigits_l[] = "0123456789abcdef", 1543340d773SGleb Smirnoff xdigits_u[] = "0123456789ABCDEF"; 1553340d773SGleb Smirnoff u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; 1563340d773SGleb Smirnoff const char *xdigits, *curtok; 1573340d773SGleb Smirnoff int ch, seen_xdigits; 1583340d773SGleb Smirnoff u_int val; 1593340d773SGleb Smirnoff 1603340d773SGleb Smirnoff memset((tp = tmp), '\0', NS_IN6ADDRSZ); 1613340d773SGleb Smirnoff endp = tp + NS_IN6ADDRSZ; 1623340d773SGleb Smirnoff colonp = NULL; 1633340d773SGleb Smirnoff /* Leading :: requires some special handling. */ 1643340d773SGleb Smirnoff if (*src == ':') 1653340d773SGleb Smirnoff if (*++src != ':') 1663340d773SGleb Smirnoff return (0); 1673340d773SGleb Smirnoff curtok = src; 1683340d773SGleb Smirnoff seen_xdigits = 0; 1693340d773SGleb Smirnoff val = 0; 1703340d773SGleb Smirnoff while ((ch = *src++) != '\0') { 1713340d773SGleb Smirnoff const char *pch; 1723340d773SGleb Smirnoff 1733340d773SGleb Smirnoff if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) 1743340d773SGleb Smirnoff pch = strchr((xdigits = xdigits_u), ch); 1753340d773SGleb Smirnoff if (pch != NULL) { 1763340d773SGleb Smirnoff val <<= 4; 1773340d773SGleb Smirnoff val |= (int)(pch - xdigits); 1783340d773SGleb Smirnoff if (++seen_xdigits > 4) 1793340d773SGleb Smirnoff return (0); 1803340d773SGleb Smirnoff continue; 1813340d773SGleb Smirnoff } 1823340d773SGleb Smirnoff if (ch == ':') { 1833340d773SGleb Smirnoff curtok = src; 1843340d773SGleb Smirnoff if (!seen_xdigits) { 1853340d773SGleb Smirnoff if (colonp) 1863340d773SGleb Smirnoff return (0); 1873340d773SGleb Smirnoff colonp = tp; 1883340d773SGleb Smirnoff continue; 1893340d773SGleb Smirnoff } else if (*src == '\0') 1903340d773SGleb Smirnoff return (0); 1913340d773SGleb Smirnoff if (tp + NS_INT16SZ > endp) 1923340d773SGleb Smirnoff return (0); 1933340d773SGleb Smirnoff *tp++ = (u_char) (val >> 8) & 0xff; 1943340d773SGleb Smirnoff *tp++ = (u_char) val & 0xff; 1953340d773SGleb Smirnoff seen_xdigits = 0; 1963340d773SGleb Smirnoff val = 0; 1973340d773SGleb Smirnoff continue; 1983340d773SGleb Smirnoff } 1993340d773SGleb Smirnoff if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && 2003340d773SGleb Smirnoff strtoaddr(curtok, tp) > 0) { 2013340d773SGleb Smirnoff tp += NS_INADDRSZ; 2023340d773SGleb Smirnoff seen_xdigits = 0; 2033340d773SGleb Smirnoff break; /*%< '\\0' was seen by strtoaddr(). */ 2043340d773SGleb Smirnoff } 2053340d773SGleb Smirnoff return (0); 2063340d773SGleb Smirnoff } 2073340d773SGleb Smirnoff if (seen_xdigits) { 2083340d773SGleb Smirnoff if (tp + NS_INT16SZ > endp) 2093340d773SGleb Smirnoff return (0); 2103340d773SGleb Smirnoff *tp++ = (u_char) (val >> 8) & 0xff; 2113340d773SGleb Smirnoff *tp++ = (u_char) val & 0xff; 2123340d773SGleb Smirnoff } 2133340d773SGleb Smirnoff if (colonp != NULL) { 2143340d773SGleb Smirnoff /* 2153340d773SGleb Smirnoff * Since some memmove()'s erroneously fail to handle 2163340d773SGleb Smirnoff * overlapping regions, we'll do the shift by hand. 2173340d773SGleb Smirnoff */ 2183340d773SGleb Smirnoff const ptrdiff_t n = tp - colonp; 2193340d773SGleb Smirnoff int i; 2203340d773SGleb Smirnoff 2213340d773SGleb Smirnoff if (tp == endp) 2223340d773SGleb Smirnoff return (0); 2233340d773SGleb Smirnoff for (i = 1; i <= n; i++) { 2243340d773SGleb Smirnoff endp[- i] = colonp[n - i]; 2253340d773SGleb Smirnoff colonp[n - i] = 0; 2263340d773SGleb Smirnoff } 2273340d773SGleb Smirnoff tp = endp; 2283340d773SGleb Smirnoff } 2293340d773SGleb Smirnoff if (tp != endp) 2303340d773SGleb Smirnoff return (0); 2313340d773SGleb Smirnoff memcpy(dst, tmp, NS_IN6ADDRSZ); 2323340d773SGleb Smirnoff return (1); 2333340d773SGleb Smirnoff } 234