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