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