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