1784088dfSchristos /* 2784088dfSchristos * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 3784088dfSchristos * Copyright (c) 1996,1999 by Internet Software Consortium. 4784088dfSchristos * 5784088dfSchristos * Permission to use, copy, modify, and distribute this software for any 6784088dfSchristos * purpose with or without fee is hereby granted, provided that the above 7784088dfSchristos * copyright notice and this permission notice appear in all copies. 8784088dfSchristos * 9784088dfSchristos * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 10784088dfSchristos * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11784088dfSchristos * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 12784088dfSchristos * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13784088dfSchristos * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14784088dfSchristos * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 15784088dfSchristos * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16784088dfSchristos */ 17784088dfSchristos 18fdccd7e4Schristos #include <sys/cdefs.h> 19fdccd7e4Schristos #ifndef lint 20*26ba0b50Schristos __RCSID("$NetBSD: strtoaddr.c,v 1.5 2024/09/02 16:15:33 christos Exp $"); 21fdccd7e4Schristos #endif 22fdccd7e4Schristos 23c74ad251Schristos #include <config.h> 24784088dfSchristos 25c74ad251Schristos #include "netdissect-stdinc.h" 26784088dfSchristos #include <stddef.h> 27784088dfSchristos #include <string.h> 28784088dfSchristos 29c74ad251Schristos #include "netdissect-ctype.h" 30c74ad251Schristos 31784088dfSchristos #include "strtoaddr.h" 32784088dfSchristos 33784088dfSchristos #ifndef NS_INADDRSZ 34784088dfSchristos #define NS_INADDRSZ 4 /* IPv4 T_A */ 35784088dfSchristos #endif 36784088dfSchristos 37784088dfSchristos #ifndef NS_IN6ADDRSZ 38784088dfSchristos #define NS_IN6ADDRSZ 16 /* IPv6 T_AAAA */ 39784088dfSchristos #endif 40784088dfSchristos 41784088dfSchristos #ifndef NS_INT16SZ 42dc860a36Sspz #define NS_INT16SZ 2 /* #/bytes of data in a uint16_t */ 43784088dfSchristos #endif 44784088dfSchristos 45784088dfSchristos /*% 46784088dfSchristos * WARNING: Don't even consider trying to compile this on a system where 47784088dfSchristos * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. 48784088dfSchristos */ 49784088dfSchristos 50784088dfSchristos /* int 51784088dfSchristos * strtoaddr(src, dst) 52784088dfSchristos * convert presentation level IPv4 address to network order binary form. 53784088dfSchristos * return: 54784088dfSchristos * 1 if `src' is a valid input, else 0. 55784088dfSchristos * notice: 56784088dfSchristos * does not touch `dst' unless it's returning 1. 57784088dfSchristos * author: 58784088dfSchristos * Paul Vixie, 1996. 59784088dfSchristos */ 60784088dfSchristos int 61784088dfSchristos strtoaddr(const char *src, void *dst) 62784088dfSchristos { 63784088dfSchristos uint32_t val; 64784088dfSchristos u_int digit; 65784088dfSchristos ptrdiff_t n; 66784088dfSchristos unsigned char c; 67784088dfSchristos u_int parts[4]; 68784088dfSchristos u_int *pp = parts; 69784088dfSchristos 70784088dfSchristos c = *src; 71784088dfSchristos for (;;) { 72784088dfSchristos /* 73784088dfSchristos * Collect number up to ``.''. 74784088dfSchristos * Values are specified as for C: 75784088dfSchristos * 0x=hex, 0=octal, isdigit=decimal. 76784088dfSchristos */ 77c74ad251Schristos if (!ND_ASCII_ISDIGIT(c)) 78784088dfSchristos return (0); 79784088dfSchristos val = 0; 80784088dfSchristos if (c == '0') { 81784088dfSchristos c = *++src; 82784088dfSchristos if (c == 'x' || c == 'X') 83784088dfSchristos return (0); 84c74ad251Schristos else if (ND_ASCII_ISDIGIT(c) && c != '9') 85784088dfSchristos return (0); 86784088dfSchristos } 87784088dfSchristos for (;;) { 88c74ad251Schristos if (ND_ASCII_ISDIGIT(c)) { 89784088dfSchristos digit = c - '0'; 90784088dfSchristos val = (val * 10) + digit; 91784088dfSchristos c = *++src; 92784088dfSchristos } else 93784088dfSchristos break; 94784088dfSchristos } 95784088dfSchristos if (c == '.') { 96784088dfSchristos /* 97784088dfSchristos * Internet format: 98784088dfSchristos * a.b.c.d 99784088dfSchristos * a.b.c (with c treated as 16 bits) 100784088dfSchristos * a.b (with b treated as 24 bits) 101784088dfSchristos * a (with a treated as 32 bits) 102784088dfSchristos */ 103784088dfSchristos if (pp >= parts + 3) 104784088dfSchristos return (0); 105784088dfSchristos *pp++ = val; 106784088dfSchristos c = *++src; 107784088dfSchristos } else 108784088dfSchristos break; 109784088dfSchristos } 110784088dfSchristos /* 111784088dfSchristos * Check for trailing characters. 112784088dfSchristos */ 113c74ad251Schristos if (c != '\0' && c != ' ' && c != '\t') 114784088dfSchristos return (0); 115784088dfSchristos /* 116784088dfSchristos * Find the number of parts specified. 117784088dfSchristos * It must be 4; we only support dotted quads, we don't 118784088dfSchristos * support shorthand. 119784088dfSchristos */ 120784088dfSchristos n = pp - parts + 1; 121784088dfSchristos if (n != 4) 122784088dfSchristos return (0); 123784088dfSchristos /* 124784088dfSchristos * parts[0-2] were set to the first 3 parts of the address; 125784088dfSchristos * val was set to the 4th part. 126784088dfSchristos * 127784088dfSchristos * Check if any part is bigger than 255. 128784088dfSchristos */ 129784088dfSchristos if ((parts[0] | parts[1] | parts[2] | val) > 0xff) 130784088dfSchristos return (0); 131784088dfSchristos /* 132784088dfSchristos * Add the other three parts to val. 133784088dfSchristos */ 134784088dfSchristos val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); 135784088dfSchristos if (dst) { 136784088dfSchristos val = htonl(val); 137784088dfSchristos memcpy(dst, &val, NS_INADDRSZ); 138784088dfSchristos } 139784088dfSchristos return (1); 140784088dfSchristos } 141784088dfSchristos 142784088dfSchristos /* int 143784088dfSchristos * strtoaddr6(src, dst) 144784088dfSchristos * convert presentation level IPv6 address to network order binary form. 145784088dfSchristos * return: 146784088dfSchristos * 1 if `src' is a valid [RFC1884 2.2] address, else 0. 147784088dfSchristos * notice: 148784088dfSchristos * (1) does not touch `dst' unless it's returning 1. 149784088dfSchristos * (2) :: in a full address is silently ignored. 150784088dfSchristos * credit: 151784088dfSchristos * inspired by Mark Andrews. 152784088dfSchristos * author: 153784088dfSchristos * Paul Vixie, 1996. 154784088dfSchristos */ 155784088dfSchristos int 156784088dfSchristos strtoaddr6(const char *src, void *dst) 157784088dfSchristos { 158784088dfSchristos static const char xdigits_l[] = "0123456789abcdef", 159784088dfSchristos xdigits_u[] = "0123456789ABCDEF"; 160784088dfSchristos u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; 161784088dfSchristos const char *xdigits, *curtok; 162784088dfSchristos int ch, seen_xdigits; 163784088dfSchristos u_int val; 164784088dfSchristos 165784088dfSchristos memset((tp = tmp), '\0', NS_IN6ADDRSZ); 166784088dfSchristos endp = tp + NS_IN6ADDRSZ; 167784088dfSchristos colonp = NULL; 168784088dfSchristos /* Leading :: requires some special handling. */ 169784088dfSchristos if (*src == ':') 170784088dfSchristos if (*++src != ':') 171784088dfSchristos return (0); 172784088dfSchristos curtok = src; 173784088dfSchristos seen_xdigits = 0; 174784088dfSchristos val = 0; 175784088dfSchristos while ((ch = *src++) != '\0') { 176784088dfSchristos const char *pch; 177784088dfSchristos 178784088dfSchristos if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) 179784088dfSchristos pch = strchr((xdigits = xdigits_u), ch); 180784088dfSchristos if (pch != NULL) { 181784088dfSchristos val <<= 4; 182784088dfSchristos val |= (int)(pch - xdigits); 183784088dfSchristos if (++seen_xdigits > 4) 184784088dfSchristos return (0); 185784088dfSchristos continue; 186784088dfSchristos } 187784088dfSchristos if (ch == ':') { 188784088dfSchristos curtok = src; 189784088dfSchristos if (!seen_xdigits) { 190784088dfSchristos if (colonp) 191784088dfSchristos return (0); 192784088dfSchristos colonp = tp; 193784088dfSchristos continue; 194784088dfSchristos } else if (*src == '\0') 195784088dfSchristos return (0); 196784088dfSchristos if (tp + NS_INT16SZ > endp) 197784088dfSchristos return (0); 198784088dfSchristos *tp++ = (u_char) (val >> 8) & 0xff; 199784088dfSchristos *tp++ = (u_char) val & 0xff; 200784088dfSchristos seen_xdigits = 0; 201784088dfSchristos val = 0; 202784088dfSchristos continue; 203784088dfSchristos } 204784088dfSchristos if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && 205784088dfSchristos strtoaddr(curtok, tp) > 0) { 206784088dfSchristos tp += NS_INADDRSZ; 207784088dfSchristos seen_xdigits = 0; 208784088dfSchristos break; /*%< '\\0' was seen by strtoaddr(). */ 209784088dfSchristos } 210784088dfSchristos return (0); 211784088dfSchristos } 212784088dfSchristos if (seen_xdigits) { 213784088dfSchristos if (tp + NS_INT16SZ > endp) 214784088dfSchristos return (0); 215784088dfSchristos *tp++ = (u_char) (val >> 8) & 0xff; 216784088dfSchristos *tp++ = (u_char) val & 0xff; 217784088dfSchristos } 218784088dfSchristos if (colonp != NULL) { 219784088dfSchristos /* 220784088dfSchristos * Since some memmove()'s erroneously fail to handle 221784088dfSchristos * overlapping regions, we'll do the shift by hand. 222784088dfSchristos */ 223784088dfSchristos const ptrdiff_t n = tp - colonp; 224784088dfSchristos int i; 225784088dfSchristos 226784088dfSchristos if (tp == endp) 227784088dfSchristos return (0); 228784088dfSchristos for (i = 1; i <= n; i++) { 229784088dfSchristos endp[- i] = colonp[n - i]; 230784088dfSchristos colonp[n - i] = 0; 231784088dfSchristos } 232784088dfSchristos tp = endp; 233784088dfSchristos } 234784088dfSchristos if (tp != endp) 235784088dfSchristos return (0); 236784088dfSchristos memcpy(dst, tmp, NS_IN6ADDRSZ); 237784088dfSchristos return (1); 238784088dfSchristos } 239