1258945Sroberto/* 2258945Sroberto * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") 3258945Sroberto * Copyright (C) 1996-2003 Internet Software Consortium. 4258945Sroberto * 5258945Sroberto * Permission to use, copy, modify, and/or distribute this software for any 6258945Sroberto * purpose with or without fee is hereby granted, provided that the above 7258945Sroberto * copyright notice and this permission notice appear in all copies. 8258945Sroberto * 9258945Sroberto * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10258945Sroberto * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11258945Sroberto * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12258945Sroberto * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13258945Sroberto * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14258945Sroberto * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15258945Sroberto * PERFORMANCE OF THIS SOFTWARE. 16258945Sroberto */ 17258945Sroberto 18258945Sroberto/*! \file */ 19258945Sroberto 20258945Sroberto#if defined(LIBC_SCCS) && !defined(lint) 21258945Srobertostatic char rcsid[] = 22258945Sroberto "$Id: inet_pton.c,v 1.19 2007/06/19 23:47:17 tbox Exp $"; 23258945Sroberto#endif /* LIBC_SCCS and not lint */ 24258945Sroberto 25258945Sroberto#include <config.h> 26258945Sroberto 27258945Sroberto#include <errno.h> 28258945Sroberto#include <string.h> 29258945Sroberto 30258945Sroberto#include <isc/net.h> 31258945Sroberto 32258945Sroberto/*% INT16 Size */ 33258945Sroberto#define NS_INT16SZ 2 34258945Sroberto/*% IPv4 Address Size */ 35258945Sroberto#define NS_INADDRSZ 4 36258945Sroberto/*% IPv6 Address Size */ 37258945Sroberto#define NS_IN6ADDRSZ 16 38258945Sroberto 39258945Sroberto/* 40258945Sroberto * WARNING: Don't even consider trying to compile this on a system where 41258945Sroberto * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. 42258945Sroberto */ 43258945Sroberto 44258945Srobertostatic int inet_pton4(const char *src, unsigned char *dst); 45258945Srobertostatic int inet_pton6(const char *src, unsigned char *dst); 46280849Scyint isc_net_pton(int af, const char *src, void *dst); 47258945Sroberto 48258945Sroberto/*% 49258945Sroberto * convert from presentation format (which usually means ASCII printable) 50258945Sroberto * to network format (which is usually some kind of binary format). 51258945Sroberto * \return 52258945Sroberto * 1 if the address was valid for the specified address family 53258945Sroberto * 0 if the address wasn't valid (`dst' is untouched in this case) 54258945Sroberto * -1 if some other error occurred (`dst' is untouched in this case, too) 55258945Sroberto * \author 56258945Sroberto * Paul Vixie, 1996. 57258945Sroberto */ 58258945Srobertoint 59258945Srobertoisc_net_pton(int af, const char *src, void *dst) { 60258945Sroberto switch (af) { 61258945Sroberto case AF_INET: 62258945Sroberto return (inet_pton4(src, dst)); 63258945Sroberto case AF_INET6: 64258945Sroberto return (inet_pton6(src, dst)); 65258945Sroberto default: 66258945Sroberto errno = EAFNOSUPPORT; 67258945Sroberto return (-1); 68258945Sroberto } 69258945Sroberto /* NOTREACHED */ 70258945Sroberto} 71258945Sroberto 72258945Sroberto/*!\fn static int inet_pton4(const char *src, unsigned char *dst) 73258945Sroberto * \brief 74258945Sroberto * like inet_aton() but without all the hexadecimal and shorthand. 75258945Sroberto * \return 76258945Sroberto * 1 if `src' is a valid dotted quad, else 0. 77258945Sroberto * \note 78258945Sroberto * does not touch `dst' unless it's returning 1. 79258945Sroberto * \author 80258945Sroberto * Paul Vixie, 1996. 81258945Sroberto */ 82258945Srobertostatic int 83258945Srobertoinet_pton4(const char *src, unsigned char *dst) { 84258945Sroberto static const char digits[] = "0123456789"; 85258945Sroberto int saw_digit, octets, ch; 86258945Sroberto unsigned char tmp[NS_INADDRSZ], *tp; 87258945Sroberto 88258945Sroberto saw_digit = 0; 89258945Sroberto octets = 0; 90258945Sroberto *(tp = tmp) = 0; 91258945Sroberto while ((ch = *src++) != '\0') { 92258945Sroberto const char *pch; 93258945Sroberto 94258945Sroberto if ((pch = strchr(digits, ch)) != NULL) { 95293423Sdelphij size_t newv = *tp * 10 + (pch - digits); 96258945Sroberto 97258945Sroberto if (saw_digit && *tp == 0) 98258945Sroberto return (0); 99258945Sroberto if (newv > 255) 100258945Sroberto return (0); 101258945Sroberto *tp = (unsigned char)newv; 102258945Sroberto if (!saw_digit) { 103258945Sroberto if (++octets > 4) 104258945Sroberto return (0); 105258945Sroberto saw_digit = 1; 106258945Sroberto } 107258945Sroberto } else if (ch == '.' && saw_digit) { 108258945Sroberto if (octets == 4) 109258945Sroberto return (0); 110258945Sroberto *++tp = 0; 111258945Sroberto saw_digit = 0; 112258945Sroberto } else 113258945Sroberto return (0); 114258945Sroberto } 115258945Sroberto if (octets < 4) 116258945Sroberto return (0); 117258945Sroberto memcpy(dst, tmp, NS_INADDRSZ); 118258945Sroberto return (1); 119258945Sroberto} 120258945Sroberto 121258945Sroberto/*% 122258945Sroberto * convert presentation level address to network order binary form. 123258945Sroberto * \return 124258945Sroberto * 1 if `src' is a valid [RFC1884 2.2] address, else 0. 125258945Sroberto * \note 126258945Sroberto * (1) does not touch `dst' unless it's returning 1. 127258945Sroberto * \note 128258945Sroberto * (2) :: in a full address is silently ignored. 129258945Sroberto * \author 130258945Sroberto * inspired by Mark Andrews. 131258945Sroberto * \author 132258945Sroberto * Paul Vixie, 1996. 133258945Sroberto */ 134258945Srobertostatic int 135258945Srobertoinet_pton6(const char *src, unsigned char *dst) { 136258945Sroberto static const char xdigits_l[] = "0123456789abcdef", 137258945Sroberto xdigits_u[] = "0123456789ABCDEF"; 138258945Sroberto unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; 139258945Sroberto const char *xdigits, *curtok; 140258945Sroberto int ch, seen_xdigits; 141258945Sroberto unsigned int val; 142258945Sroberto 143258945Sroberto memset((tp = tmp), '\0', NS_IN6ADDRSZ); 144258945Sroberto endp = tp + NS_IN6ADDRSZ; 145258945Sroberto colonp = NULL; 146258945Sroberto /* Leading :: requires some special handling. */ 147258945Sroberto if (*src == ':') 148258945Sroberto if (*++src != ':') 149258945Sroberto return (0); 150258945Sroberto curtok = src; 151258945Sroberto seen_xdigits = 0; 152258945Sroberto val = 0; 153258945Sroberto while ((ch = *src++) != '\0') { 154258945Sroberto const char *pch; 155258945Sroberto 156258945Sroberto if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) 157258945Sroberto pch = strchr((xdigits = xdigits_u), ch); 158258945Sroberto if (pch != NULL) { 159258945Sroberto val <<= 4; 160258945Sroberto val |= (pch - xdigits); 161258945Sroberto if (++seen_xdigits > 4) 162258945Sroberto return (0); 163258945Sroberto continue; 164258945Sroberto } 165258945Sroberto if (ch == ':') { 166258945Sroberto curtok = src; 167258945Sroberto if (!seen_xdigits) { 168258945Sroberto if (colonp) 169258945Sroberto return (0); 170258945Sroberto colonp = tp; 171258945Sroberto continue; 172258945Sroberto } 173316068Sdelphij if (NS_INT16SZ > endp - tp) 174258945Sroberto return (0); 175258945Sroberto *tp++ = (unsigned char) (val >> 8) & 0xff; 176258945Sroberto *tp++ = (unsigned char) val & 0xff; 177258945Sroberto seen_xdigits = 0; 178258945Sroberto val = 0; 179258945Sroberto continue; 180258945Sroberto } 181316068Sdelphij if (ch == '.' && (NS_INADDRSZ <= endp - tp) && 182258945Sroberto inet_pton4(curtok, tp) > 0) { 183258945Sroberto tp += NS_INADDRSZ; 184258945Sroberto seen_xdigits = 0; 185258945Sroberto break; /* '\0' was seen by inet_pton4(). */ 186258945Sroberto } 187258945Sroberto return (0); 188258945Sroberto } 189258945Sroberto if (seen_xdigits) { 190316068Sdelphij if (NS_INT16SZ > endp - tp) 191258945Sroberto return (0); 192258945Sroberto *tp++ = (unsigned char) (val >> 8) & 0xff; 193258945Sroberto *tp++ = (unsigned char) val & 0xff; 194258945Sroberto } 195258945Sroberto if (colonp != NULL) { 196258945Sroberto /* 197258945Sroberto * Since some memmove()'s erroneously fail to handle 198258945Sroberto * overlapping regions, we'll do the shift by hand. 199258945Sroberto */ 200293423Sdelphij const size_t n = tp - colonp; 201258945Sroberto int i; 202258945Sroberto 203258945Sroberto if (tp == endp) 204258945Sroberto return (0); 205293423Sdelphij for (i = 1; (size_t)i <= n; i++) { 206258945Sroberto endp[- i] = colonp[n - i]; 207258945Sroberto colonp[n - i] = 0; 208258945Sroberto } 209258945Sroberto tp = endp; 210258945Sroberto } 211258945Sroberto if (tp != endp) 212258945Sroberto return (0); 213258945Sroberto memcpy(dst, tmp, NS_IN6ADDRSZ); 214258945Sroberto return (1); 215258945Sroberto} 216