1 /* 2 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (c) 1996,1999 by Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 15 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #ifdef HAVE_CONFIG_H 19 #include <config.h> 20 #endif 21 22 #include "netdissect-stdinc.h" 23 #include <stddef.h> 24 #include <string.h> 25 26 #include "netdissect-ctype.h" 27 28 #include "strtoaddr.h" 29 30 #ifndef NS_INADDRSZ 31 #define NS_INADDRSZ 4 /* IPv4 T_A */ 32 #endif 33 34 #ifndef NS_IN6ADDRSZ 35 #define NS_IN6ADDRSZ 16 /* IPv6 T_AAAA */ 36 #endif 37 38 #ifndef NS_INT16SZ 39 #define NS_INT16SZ 2 /* #/bytes of data in a uint16_t */ 40 #endif 41 42 /*% 43 * WARNING: Don't even consider trying to compile this on a system where 44 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. 45 */ 46 47 /* int 48 * strtoaddr(src, dst) 49 * convert presentation level IPv4 address to network order binary form. 50 * return: 51 * 1 if `src' is a valid input, else 0. 52 * notice: 53 * does not touch `dst' unless it's returning 1. 54 * author: 55 * Paul Vixie, 1996. 56 */ 57 int 58 strtoaddr(const char *src, void *dst) 59 { 60 uint32_t val; 61 u_int digit; 62 ptrdiff_t n; 63 unsigned char c; 64 u_int parts[4]; 65 u_int *pp = parts; 66 67 c = *src; 68 for (;;) { 69 /* 70 * Collect number up to ``.''. 71 * Values are specified as for C: 72 * 0x=hex, 0=octal, isdigit=decimal. 73 */ 74 if (!ND_ASCII_ISDIGIT(c)) 75 return (0); 76 val = 0; 77 if (c == '0') { 78 c = *++src; 79 if (c == 'x' || c == 'X') 80 return (0); 81 else if (ND_ASCII_ISDIGIT(c) && c != '9') 82 return (0); 83 } 84 for (;;) { 85 if (ND_ASCII_ISDIGIT(c)) { 86 digit = c - '0'; 87 val = (val * 10) + digit; 88 c = *++src; 89 } else 90 break; 91 } 92 if (c == '.') { 93 /* 94 * Internet format: 95 * a.b.c.d 96 * a.b.c (with c treated as 16 bits) 97 * a.b (with b treated as 24 bits) 98 * a (with a treated as 32 bits) 99 */ 100 if (pp >= parts + 3) 101 return (0); 102 *pp++ = val; 103 c = *++src; 104 } else 105 break; 106 } 107 /* 108 * Check for trailing characters. 109 */ 110 if (c != '\0' && c != ' ' && c != '\t') 111 return (0); 112 /* 113 * Find the number of parts specified. 114 * It must be 4; we only support dotted quads, we don't 115 * support shorthand. 116 */ 117 n = pp - parts + 1; 118 if (n != 4) 119 return (0); 120 /* 121 * parts[0-2] were set to the first 3 parts of the address; 122 * val was set to the 4th part. 123 * 124 * Check if any part is bigger than 255. 125 */ 126 if ((parts[0] | parts[1] | parts[2] | val) > 0xff) 127 return (0); 128 /* 129 * Add the other three parts to val. 130 */ 131 val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); 132 if (dst) { 133 val = htonl(val); 134 memcpy(dst, &val, NS_INADDRSZ); 135 } 136 return (1); 137 } 138 139 /* int 140 * strtoaddr6(src, dst) 141 * convert presentation level IPv6 address to network order binary form. 142 * return: 143 * 1 if `src' is a valid [RFC1884 2.2] address, else 0. 144 * notice: 145 * (1) does not touch `dst' unless it's returning 1. 146 * (2) :: in a full address is silently ignored. 147 * credit: 148 * inspired by Mark Andrews. 149 * author: 150 * Paul Vixie, 1996. 151 */ 152 int 153 strtoaddr6(const char *src, void *dst) 154 { 155 static const char xdigits_l[] = "0123456789abcdef", 156 xdigits_u[] = "0123456789ABCDEF"; 157 u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; 158 const char *xdigits, *curtok; 159 int ch, seen_xdigits; 160 u_int val; 161 162 memset((tp = tmp), '\0', NS_IN6ADDRSZ); 163 endp = tp + NS_IN6ADDRSZ; 164 colonp = NULL; 165 /* Leading :: requires some special handling. */ 166 if (*src == ':') 167 if (*++src != ':') 168 return (0); 169 curtok = src; 170 seen_xdigits = 0; 171 val = 0; 172 while ((ch = *src++) != '\0') { 173 const char *pch; 174 175 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) 176 pch = strchr((xdigits = xdigits_u), ch); 177 if (pch != NULL) { 178 val <<= 4; 179 val |= (int)(pch - xdigits); 180 if (++seen_xdigits > 4) 181 return (0); 182 continue; 183 } 184 if (ch == ':') { 185 curtok = src; 186 if (!seen_xdigits) { 187 if (colonp) 188 return (0); 189 colonp = tp; 190 continue; 191 } else if (*src == '\0') 192 return (0); 193 if (tp + NS_INT16SZ > endp) 194 return (0); 195 *tp++ = (u_char) (val >> 8) & 0xff; 196 *tp++ = (u_char) val & 0xff; 197 seen_xdigits = 0; 198 val = 0; 199 continue; 200 } 201 if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && 202 strtoaddr(curtok, tp) > 0) { 203 tp += NS_INADDRSZ; 204 seen_xdigits = 0; 205 break; /*%< '\\0' was seen by strtoaddr(). */ 206 } 207 return (0); 208 } 209 if (seen_xdigits) { 210 if (tp + NS_INT16SZ > endp) 211 return (0); 212 *tp++ = (u_char) (val >> 8) & 0xff; 213 *tp++ = (u_char) val & 0xff; 214 } 215 if (colonp != NULL) { 216 /* 217 * Since some memmove()'s erroneously fail to handle 218 * overlapping regions, we'll do the shift by hand. 219 */ 220 const ptrdiff_t n = tp - colonp; 221 int i; 222 223 if (tp == endp) 224 return (0); 225 for (i = 1; i <= n; i++) { 226 endp[- i] = colonp[n - i]; 227 colonp[n - i] = 0; 228 } 229 tp = endp; 230 } 231 if (tp != endp) 232 return (0); 233 memcpy(dst, tmp, NS_IN6ADDRSZ); 234 return (1); 235 } 236