1*eabc0478Schristos /* $NetBSD: inet_pton.c,v 1.2 2024/08/18 20:47:14 christos Exp $ */ 2897be3a4Schristos 3897be3a4Schristos /* 4897be3a4Schristos * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") 5897be3a4Schristos * Copyright (C) 1996-2003 Internet Software Consortium. 6897be3a4Schristos * 7897be3a4Schristos * Permission to use, copy, modify, and/or distribute this software for any 8897be3a4Schristos * purpose with or without fee is hereby granted, provided that the above 9897be3a4Schristos * copyright notice and this permission notice appear in all copies. 10897be3a4Schristos * 11897be3a4Schristos * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 12897be3a4Schristos * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 13897be3a4Schristos * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 14897be3a4Schristos * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 15897be3a4Schristos * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 16897be3a4Schristos * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17897be3a4Schristos * PERFORMANCE OF THIS SOFTWARE. 18897be3a4Schristos */ 19897be3a4Schristos 20897be3a4Schristos /*! \file */ 21897be3a4Schristos 22897be3a4Schristos #if defined(LIBC_SCCS) && !defined(lint) 23897be3a4Schristos static char rcsid[] = 24897be3a4Schristos "Id: inet_pton.c,v 1.19 2007/06/19 23:47:17 tbox Exp "; 25897be3a4Schristos #endif /* LIBC_SCCS and not lint */ 26897be3a4Schristos 27897be3a4Schristos #include <config.h> 28897be3a4Schristos 29897be3a4Schristos #include <errno.h> 30897be3a4Schristos #include <string.h> 31897be3a4Schristos 32897be3a4Schristos #include <isc/net.h> 33897be3a4Schristos 34897be3a4Schristos /*% INT16 Size */ 35897be3a4Schristos #define NS_INT16SZ 2 36897be3a4Schristos /*% IPv4 Address Size */ 37897be3a4Schristos #define NS_INADDRSZ 4 38897be3a4Schristos /*% IPv6 Address Size */ 39897be3a4Schristos #define NS_IN6ADDRSZ 16 40897be3a4Schristos 41897be3a4Schristos /* 42897be3a4Schristos * WARNING: Don't even consider trying to compile this on a system where 43897be3a4Schristos * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. 44897be3a4Schristos */ 45897be3a4Schristos 46897be3a4Schristos static int inet_pton4(const char *src, unsigned char *dst); 47897be3a4Schristos static int inet_pton6(const char *src, unsigned char *dst); 48897be3a4Schristos int isc_net_pton(int af, const char *src, void *dst); 49897be3a4Schristos 50897be3a4Schristos /*% 51897be3a4Schristos * convert from presentation format (which usually means ASCII printable) 52897be3a4Schristos * to network format (which is usually some kind of binary format). 53897be3a4Schristos * \return 54897be3a4Schristos * 1 if the address was valid for the specified address family 55897be3a4Schristos * 0 if the address wasn't valid (`dst' is untouched in this case) 56897be3a4Schristos * -1 if some other error occurred (`dst' is untouched in this case, too) 57897be3a4Schristos * \author 58897be3a4Schristos * Paul Vixie, 1996. 59897be3a4Schristos */ 60897be3a4Schristos int 61897be3a4Schristos isc_net_pton(int af, const char *src, void *dst) { 62897be3a4Schristos switch (af) { 63897be3a4Schristos case AF_INET: 64897be3a4Schristos return (inet_pton4(src, dst)); 65897be3a4Schristos case AF_INET6: 66897be3a4Schristos return (inet_pton6(src, dst)); 67897be3a4Schristos default: 68897be3a4Schristos errno = EAFNOSUPPORT; 69897be3a4Schristos return (-1); 70897be3a4Schristos } 71897be3a4Schristos /* NOTREACHED */ 72897be3a4Schristos } 73897be3a4Schristos 74897be3a4Schristos /*!\fn static int inet_pton4(const char *src, unsigned char *dst) 75897be3a4Schristos * \brief 76897be3a4Schristos * like inet_aton() but without all the hexadecimal and shorthand. 77897be3a4Schristos * \return 78897be3a4Schristos * 1 if `src' is a valid dotted quad, else 0. 79897be3a4Schristos * \note 80897be3a4Schristos * does not touch `dst' unless it's returning 1. 81897be3a4Schristos * \author 82897be3a4Schristos * Paul Vixie, 1996. 83897be3a4Schristos */ 84897be3a4Schristos static int 85897be3a4Schristos inet_pton4(const char *src, unsigned char *dst) { 86897be3a4Schristos static const char digits[] = "0123456789"; 87897be3a4Schristos int saw_digit, octets, ch; 88897be3a4Schristos unsigned char tmp[NS_INADDRSZ], *tp; 89897be3a4Schristos 90897be3a4Schristos saw_digit = 0; 91897be3a4Schristos octets = 0; 92897be3a4Schristos *(tp = tmp) = 0; 93897be3a4Schristos while ((ch = *src++) != '\0') { 94897be3a4Schristos const char *pch; 95897be3a4Schristos 96897be3a4Schristos if ((pch = strchr(digits, ch)) != NULL) { 97897be3a4Schristos size_t newv = *tp * 10 + (pch - digits); 98897be3a4Schristos 99897be3a4Schristos if (saw_digit && *tp == 0) 100897be3a4Schristos return (0); 101897be3a4Schristos if (newv > 255) 102897be3a4Schristos return (0); 103897be3a4Schristos *tp = (unsigned char)newv; 104897be3a4Schristos if (!saw_digit) { 105897be3a4Schristos if (++octets > 4) 106897be3a4Schristos return (0); 107897be3a4Schristos saw_digit = 1; 108897be3a4Schristos } 109897be3a4Schristos } else if (ch == '.' && saw_digit) { 110897be3a4Schristos if (octets == 4) 111897be3a4Schristos return (0); 112897be3a4Schristos *++tp = 0; 113897be3a4Schristos saw_digit = 0; 114897be3a4Schristos } else 115897be3a4Schristos return (0); 116897be3a4Schristos } 117897be3a4Schristos if (octets < 4) 118897be3a4Schristos return (0); 119897be3a4Schristos memcpy(dst, tmp, NS_INADDRSZ); 120897be3a4Schristos return (1); 121897be3a4Schristos } 122897be3a4Schristos 123897be3a4Schristos /*% 124897be3a4Schristos * convert presentation level address to network order binary form. 125897be3a4Schristos * \return 126897be3a4Schristos * 1 if `src' is a valid [RFC1884 2.2] address, else 0. 127897be3a4Schristos * \note 128897be3a4Schristos * (1) does not touch `dst' unless it's returning 1. 129897be3a4Schristos * \note 130897be3a4Schristos * (2) :: in a full address is silently ignored. 131897be3a4Schristos * \author 132897be3a4Schristos * inspired by Mark Andrews. 133897be3a4Schristos * \author 134897be3a4Schristos * Paul Vixie, 1996. 135897be3a4Schristos */ 136897be3a4Schristos static int 137897be3a4Schristos inet_pton6(const char *src, unsigned char *dst) { 138897be3a4Schristos static const char xdigits_l[] = "0123456789abcdef", 139897be3a4Schristos xdigits_u[] = "0123456789ABCDEF"; 140897be3a4Schristos unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; 141897be3a4Schristos const char *xdigits, *curtok; 142897be3a4Schristos int ch, seen_xdigits; 143897be3a4Schristos unsigned int val; 144897be3a4Schristos 145897be3a4Schristos memset((tp = tmp), '\0', NS_IN6ADDRSZ); 146897be3a4Schristos endp = tp + NS_IN6ADDRSZ; 147897be3a4Schristos colonp = NULL; 148897be3a4Schristos /* Leading :: requires some special handling. */ 149897be3a4Schristos if (*src == ':') 150897be3a4Schristos if (*++src != ':') 151897be3a4Schristos return (0); 152897be3a4Schristos curtok = src; 153897be3a4Schristos seen_xdigits = 0; 154897be3a4Schristos val = 0; 155897be3a4Schristos while ((ch = *src++) != '\0') { 156897be3a4Schristos const char *pch; 157897be3a4Schristos 158897be3a4Schristos if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) 159897be3a4Schristos pch = strchr((xdigits = xdigits_u), ch); 160897be3a4Schristos if (pch != NULL) { 161897be3a4Schristos val <<= 4; 162897be3a4Schristos val |= (pch - xdigits); 163897be3a4Schristos if (++seen_xdigits > 4) 164897be3a4Schristos return (0); 165897be3a4Schristos continue; 166897be3a4Schristos } 167897be3a4Schristos if (ch == ':') { 168897be3a4Schristos curtok = src; 169897be3a4Schristos if (!seen_xdigits) { 170897be3a4Schristos if (colonp) 171897be3a4Schristos return (0); 172897be3a4Schristos colonp = tp; 173897be3a4Schristos continue; 174897be3a4Schristos } 175897be3a4Schristos if (NS_INT16SZ > endp - tp) 176897be3a4Schristos return (0); 177897be3a4Schristos *tp++ = (unsigned char) (val >> 8) & 0xff; 178897be3a4Schristos *tp++ = (unsigned char) val & 0xff; 179897be3a4Schristos seen_xdigits = 0; 180897be3a4Schristos val = 0; 181897be3a4Schristos continue; 182897be3a4Schristos } 183897be3a4Schristos if (ch == '.' && (NS_INADDRSZ <= endp - tp) && 184897be3a4Schristos inet_pton4(curtok, tp) > 0) { 185897be3a4Schristos tp += NS_INADDRSZ; 186897be3a4Schristos seen_xdigits = 0; 187897be3a4Schristos break; /* '\0' was seen by inet_pton4(). */ 188897be3a4Schristos } 189897be3a4Schristos return (0); 190897be3a4Schristos } 191897be3a4Schristos if (seen_xdigits) { 192897be3a4Schristos if (NS_INT16SZ > endp - tp) 193897be3a4Schristos return (0); 194897be3a4Schristos *tp++ = (unsigned char) (val >> 8) & 0xff; 195897be3a4Schristos *tp++ = (unsigned char) val & 0xff; 196897be3a4Schristos } 197897be3a4Schristos if (colonp != NULL) { 198897be3a4Schristos /* 199897be3a4Schristos * Since some memmove()'s erroneously fail to handle 200897be3a4Schristos * overlapping regions, we'll do the shift by hand. 201897be3a4Schristos */ 202897be3a4Schristos const size_t n = tp - colonp; 203897be3a4Schristos int i; 204897be3a4Schristos 205897be3a4Schristos if (tp == endp) 206897be3a4Schristos return (0); 207897be3a4Schristos for (i = 1; (size_t)i <= n; i++) { 208897be3a4Schristos endp[- i] = colonp[n - i]; 209897be3a4Schristos colonp[n - i] = 0; 210897be3a4Schristos } 211897be3a4Schristos tp = endp; 212897be3a4Schristos } 213897be3a4Schristos if (tp != endp) 214897be3a4Schristos return (0); 215897be3a4Schristos memcpy(dst, tmp, NS_IN6ADDRSZ); 216897be3a4Schristos return (1); 217897be3a4Schristos } 218