1135446Strhodes/* 2262706Serwin * Copyright (C) 2004, 2005, 2007, 2013, 2014 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 1996-2003 Internet Software Consortium. 4135446Strhodes * 5193149Sdougb * Permission to use, copy, modify, and/or distribute this software for any 6135446Strhodes * purpose with or without fee is hereby granted, provided that the above 7135446Strhodes * copyright notice and this permission notice appear in all copies. 8135446Strhodes * 9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11135446Strhodes * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15135446Strhodes * PERFORMANCE OF THIS SOFTWARE. 16135446Strhodes */ 17135446Strhodes 18170222Sdougb/*! \file */ 19170222Sdougb 20135446Strhodes#if defined(LIBC_SCCS) && !defined(lint) 21135446Strhodesstatic char rcsid[] = 22234010Sdougb "$Id: inet_pton.c,v 1.19 2007/06/19 23:47:17 tbox Exp $"; 23135446Strhodes#endif /* LIBC_SCCS and not lint */ 24135446Strhodes 25135446Strhodes#include <config.h> 26135446Strhodes 27135446Strhodes#include <errno.h> 28135446Strhodes#include <string.h> 29135446Strhodes 30135446Strhodes#include <isc/net.h> 31135446Strhodes 32170222Sdougb/*% INT16 Size */ 33135446Strhodes#define NS_INT16SZ 2 34170222Sdougb/*% IPv4 Address Size */ 35135446Strhodes#define NS_INADDRSZ 4 36170222Sdougb/*% IPv6 Address Size */ 37135446Strhodes#define NS_IN6ADDRSZ 16 38135446Strhodes 39135446Strhodes/* 40135446Strhodes * WARNING: Don't even consider trying to compile this on a system where 41135446Strhodes * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. 42135446Strhodes */ 43135446Strhodes 44135446Strhodesstatic int inet_pton4(const char *src, unsigned char *dst); 45135446Strhodesstatic int inet_pton6(const char *src, unsigned char *dst); 46135446Strhodes 47262706Serwin/*% 48135446Strhodes * convert from presentation format (which usually means ASCII printable) 49135446Strhodes * to network format (which is usually some kind of binary format). 50170222Sdougb * \return 51135446Strhodes * 1 if the address was valid for the specified address family 52135446Strhodes * 0 if the address wasn't valid (`dst' is untouched in this case) 53135446Strhodes * -1 if some other error occurred (`dst' is untouched in this case, too) 54170222Sdougb * \author 55135446Strhodes * Paul Vixie, 1996. 56135446Strhodes */ 57135446Strhodesint 58135446Strhodesisc_net_pton(int af, const char *src, void *dst) { 59135446Strhodes switch (af) { 60135446Strhodes case AF_INET: 61135446Strhodes return (inet_pton4(src, dst)); 62135446Strhodes case AF_INET6: 63135446Strhodes return (inet_pton6(src, dst)); 64135446Strhodes default: 65135446Strhodes errno = EAFNOSUPPORT; 66135446Strhodes return (-1); 67135446Strhodes } 68135446Strhodes /* NOTREACHED */ 69135446Strhodes} 70135446Strhodes 71170222Sdougb/*!\fn static int inet_pton4(const char *src, unsigned char *dst) 72170222Sdougb * \brief 73135446Strhodes * like inet_aton() but without all the hexadecimal and shorthand. 74170222Sdougb * \return 75135446Strhodes * 1 if `src' is a valid dotted quad, else 0. 76170222Sdougb * \note 77135446Strhodes * does not touch `dst' unless it's returning 1. 78170222Sdougb * \author 79135446Strhodes * Paul Vixie, 1996. 80135446Strhodes */ 81135446Strhodesstatic int 82135446Strhodesinet_pton4(const char *src, unsigned char *dst) { 83135446Strhodes static const char digits[] = "0123456789"; 84135446Strhodes int saw_digit, octets, ch; 85135446Strhodes unsigned char tmp[NS_INADDRSZ], *tp; 86135446Strhodes 87135446Strhodes saw_digit = 0; 88135446Strhodes octets = 0; 89135446Strhodes *(tp = tmp) = 0; 90135446Strhodes while ((ch = *src++) != '\0') { 91135446Strhodes const char *pch; 92135446Strhodes 93135446Strhodes if ((pch = strchr(digits, ch)) != NULL) { 94262706Serwin unsigned int new = *tp * 10; 95135446Strhodes 96262706Serwin new += (int)(pch - digits); 97135446Strhodes if (saw_digit && *tp == 0) 98135446Strhodes return (0); 99135446Strhodes if (new > 255) 100135446Strhodes return (0); 101135446Strhodes *tp = new; 102135446Strhodes if (!saw_digit) { 103135446Strhodes if (++octets > 4) 104135446Strhodes return (0); 105135446Strhodes saw_digit = 1; 106135446Strhodes } 107135446Strhodes } else if (ch == '.' && saw_digit) { 108135446Strhodes if (octets == 4) 109135446Strhodes return (0); 110135446Strhodes *++tp = 0; 111135446Strhodes saw_digit = 0; 112135446Strhodes } else 113135446Strhodes return (0); 114135446Strhodes } 115135446Strhodes if (octets < 4) 116135446Strhodes return (0); 117262706Serwin memmove(dst, tmp, NS_INADDRSZ); 118135446Strhodes return (1); 119135446Strhodes} 120135446Strhodes 121170222Sdougb/*% 122135446Strhodes * convert presentation level address to network order binary form. 123170222Sdougb * \return 124135446Strhodes * 1 if `src' is a valid [RFC1884 2.2] address, else 0. 125170222Sdougb * \note 126135446Strhodes * (1) does not touch `dst' unless it's returning 1. 127170222Sdougb * \note 128135446Strhodes * (2) :: in a full address is silently ignored. 129170222Sdougb * \author 130135446Strhodes * inspired by Mark Andrews. 131170222Sdougb * \author 132135446Strhodes * Paul Vixie, 1996. 133135446Strhodes */ 134135446Strhodesstatic int 135135446Strhodesinet_pton6(const char *src, unsigned char *dst) { 136135446Strhodes static const char xdigits_l[] = "0123456789abcdef", 137135446Strhodes xdigits_u[] = "0123456789ABCDEF"; 138135446Strhodes unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; 139135446Strhodes const char *xdigits, *curtok; 140153816Sdougb int ch, seen_xdigits; 141135446Strhodes unsigned int val; 142135446Strhodes 143135446Strhodes memset((tp = tmp), '\0', NS_IN6ADDRSZ); 144135446Strhodes endp = tp + NS_IN6ADDRSZ; 145135446Strhodes colonp = NULL; 146135446Strhodes /* Leading :: requires some special handling. */ 147135446Strhodes if (*src == ':') 148135446Strhodes if (*++src != ':') 149135446Strhodes return (0); 150135446Strhodes curtok = src; 151153816Sdougb seen_xdigits = 0; 152135446Strhodes val = 0; 153135446Strhodes while ((ch = *src++) != '\0') { 154135446Strhodes const char *pch; 155135446Strhodes 156135446Strhodes if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) 157135446Strhodes pch = strchr((xdigits = xdigits_u), ch); 158135446Strhodes if (pch != NULL) { 159135446Strhodes val <<= 4; 160135446Strhodes val |= (pch - xdigits); 161153816Sdougb if (++seen_xdigits > 4) 162135446Strhodes return (0); 163135446Strhodes continue; 164135446Strhodes } 165135446Strhodes if (ch == ':') { 166135446Strhodes curtok = src; 167153816Sdougb if (!seen_xdigits) { 168135446Strhodes if (colonp) 169135446Strhodes return (0); 170135446Strhodes colonp = tp; 171135446Strhodes continue; 172135446Strhodes } 173135446Strhodes if (tp + NS_INT16SZ > endp) 174135446Strhodes return (0); 175135446Strhodes *tp++ = (unsigned char) (val >> 8) & 0xff; 176135446Strhodes *tp++ = (unsigned char) val & 0xff; 177153816Sdougb seen_xdigits = 0; 178135446Strhodes val = 0; 179135446Strhodes continue; 180135446Strhodes } 181135446Strhodes if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && 182135446Strhodes inet_pton4(curtok, tp) > 0) { 183135446Strhodes tp += NS_INADDRSZ; 184153816Sdougb seen_xdigits = 0; 185135446Strhodes break; /* '\0' was seen by inet_pton4(). */ 186135446Strhodes } 187135446Strhodes return (0); 188135446Strhodes } 189153816Sdougb if (seen_xdigits) { 190135446Strhodes if (tp + NS_INT16SZ > endp) 191135446Strhodes return (0); 192135446Strhodes *tp++ = (unsigned char) (val >> 8) & 0xff; 193135446Strhodes *tp++ = (unsigned char) val & 0xff; 194135446Strhodes } 195135446Strhodes if (colonp != NULL) { 196135446Strhodes /* 197135446Strhodes * Since some memmove()'s erroneously fail to handle 198135446Strhodes * overlapping regions, we'll do the shift by hand. 199135446Strhodes */ 200262706Serwin const int n = (int)(tp - colonp); 201135446Strhodes int i; 202135446Strhodes 203135446Strhodes if (tp == endp) 204135446Strhodes return (0); 205135446Strhodes for (i = 1; i <= n; i++) { 206135446Strhodes endp[- i] = colonp[n - i]; 207135446Strhodes colonp[n - i] = 0; 208135446Strhodes } 209135446Strhodes tp = endp; 210135446Strhodes } 211135446Strhodes if (tp != endp) 212135446Strhodes return (0); 213262706Serwin memmove(dst, tmp, NS_IN6ADDRSZ); 214135446Strhodes return (1); 215135446Strhodes} 216