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