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