inet_pton.c revision 285612
124139Sjoerg/* 224139Sjoerg * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") 324139Sjoerg * Copyright (C) 1996-2003 Internet Software Consortium. 424139Sjoerg * 524139Sjoerg * Permission to use, copy, modify, and/or distribute this software for any 624139Sjoerg * purpose with or without fee is hereby granted, provided that the above 724139Sjoerg * copyright notice and this permission notice appear in all copies. 824139Sjoerg * 924139Sjoerg * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 1024139Sjoerg * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 1124139Sjoerg * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 1289757Sdwmalone * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 1389757Sdwmalone * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 1489757Sdwmalone * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 1566641Simp * PERFORMANCE OF THIS SOFTWARE. 1666641Simp */ 1724139Sjoerg 1824139Sjoerg/*! \file */ 1924139Sjoerg 2024139Sjoerg#if defined(LIBC_SCCS) && !defined(lint) 2124139Sjoergstatic char rcsid[] = 2224139Sjoerg "$Id: inet_pton.c,v 1.19 2007/06/19 23:47:17 tbox Exp $"; 2324139Sjoerg#endif /* LIBC_SCCS and not lint */ 2424139Sjoerg 2524139Sjoerg#include <config.h> 2624139Sjoerg 2724139Sjoerg#include <errno.h> 2824139Sjoerg#include <string.h> 2924139Sjoerg 3024139Sjoerg#include <isc/net.h> 3124139Sjoerg 3224139Sjoerg/*% INT16 Size */ 3324139Sjoerg#define NS_INT16SZ 2 3424139Sjoerg/*% IPv4 Address Size */ 3524139Sjoerg#define NS_INADDRSZ 4 3624139Sjoerg/*% IPv6 Address Size */ 3786042Sdwmalone#define NS_IN6ADDRSZ 16 3824139Sjoerg 3924139Sjoerg/* 4024139Sjoerg * WARNING: Don't even consider trying to compile this on a system where 41266280Sbdrewery * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. 4224139Sjoerg */ 43266280Sbdrewery 4424139Sjoergstatic int inet_pton4(const char *src, unsigned char *dst); 4524139Sjoergstatic int inet_pton6(const char *src, unsigned char *dst); 4624139Sjoergint isc_net_pton(int af, const char *src, void *dst); 4724139Sjoerg 4824139Sjoerg/*% 4924139Sjoerg * convert from presentation format (which usually means ASCII printable) 5024139Sjoerg * to network format (which is usually some kind of binary format). 5124139Sjoerg * \return 5224139Sjoerg * 1 if the address was valid for the specified address family 5324139Sjoerg * 0 if the address wasn't valid (`dst' is untouched in this case) 5424139Sjoerg * -1 if some other error occurred (`dst' is untouched in this case, too) 5524139Sjoerg * \author 5624139Sjoerg * Paul Vixie, 1996. 5724139Sjoerg */ 5824139Sjoergint 5924139Sjoergisc_net_pton(int af, const char *src, void *dst) { 6024139Sjoerg switch (af) { 6124139Sjoerg case AF_INET: 6224139Sjoerg return (inet_pton4(src, dst)); 6324139Sjoerg case AF_INET6: 6424139Sjoerg return (inet_pton6(src, dst)); 6524139Sjoerg default: 6624139Sjoerg errno = EAFNOSUPPORT; 6724139Sjoerg return (-1); 6824139Sjoerg } 6924139Sjoerg /* NOTREACHED */ 70168710Sstas} 71175420Speter 72168710Sstas/*!\fn static int inet_pton4(const char *src, unsigned char *dst) 7324139Sjoerg * \brief 7424139Sjoerg * like inet_aton() but without all the hexadecimal and shorthand. 7524139Sjoerg * \return 7624139Sjoerg * 1 if `src' is a valid dotted quad, else 0. 7724139Sjoerg * \note 7824139Sjoerg * does not touch `dst' unless it's returning 1. 7924139Sjoerg * \author 8081187Skris * Paul Vixie, 1996. 8181187Skris */ 8281187Skrisstatic int 8381187Skrisinet_pton4(const char *src, unsigned char *dst) { 8424139Sjoerg static const char digits[] = "0123456789"; 8524139Sjoerg int saw_digit, octets, ch; 8624139Sjoerg unsigned char tmp[NS_INADDRSZ], *tp; 8724139Sjoerg 8824139Sjoerg saw_digit = 0; 8924139Sjoerg octets = 0; 9024139Sjoerg *(tp = tmp) = 0; 91145073Skeramida while ((ch = *src++) != '\0') { 9224139Sjoerg const char *pch; 9324139Sjoerg 9424139Sjoerg if ((pch = strchr(digits, ch)) != NULL) { 9524139Sjoerg unsigned int newv = *tp * 10 + (pch - digits); 9624139Sjoerg 9724139Sjoerg if (saw_digit && *tp == 0) 9824139Sjoerg return (0); 9924139Sjoerg if (newv > 255) 10024139Sjoerg return (0); 10124139Sjoerg *tp = (unsigned char)newv; 10224139Sjoerg if (!saw_digit) { 103133817Salfred if (++octets > 4) 10424139Sjoerg return (0); 10524139Sjoerg saw_digit = 1; 106131829Skeramida } 10724139Sjoerg } else if (ch == '.' && saw_digit) { 10824139Sjoerg if (octets == 4) 10924139Sjoerg return (0); 11024139Sjoerg *++tp = 0; 11124139Sjoerg saw_digit = 0; 11224139Sjoerg } else 11324139Sjoerg return (0); 11424139Sjoerg } 11524139Sjoerg if (octets < 4) 11624139Sjoerg return (0); 11724139Sjoerg memcpy(dst, tmp, NS_INADDRSZ); 11824139Sjoerg return (1); 11924139Sjoerg} 12024139Sjoerg 12124139Sjoerg/*% 12224139Sjoerg * convert presentation level address to network order binary form. 12324139Sjoerg * \return 12424139Sjoerg * 1 if `src' is a valid [RFC1884 2.2] address, else 0. 12524139Sjoerg * \note 126237656Sjhb * (1) does not touch `dst' unless it's returning 1. 127237656Sjhb * \note 12824142Sjoerg * (2) :: in a full address is silently ignored. 12924142Sjoerg * \author 13024139Sjoerg * inspired by Mark Andrews. 13124139Sjoerg * \author 13224139Sjoerg * Paul Vixie, 1996. 13324139Sjoerg */ 13424139Sjoergstatic int 13524139Sjoerginet_pton6(const char *src, unsigned char *dst) { 13624139Sjoerg static const char xdigits_l[] = "0123456789abcdef", 13724139Sjoerg xdigits_u[] = "0123456789ABCDEF"; 13824139Sjoerg unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; 13924139Sjoerg const char *xdigits, *curtok; 14024139Sjoerg int ch, seen_xdigits; 14124139Sjoerg unsigned int val; 142237656Sjhb 14324142Sjoerg memset((tp = tmp), '\0', NS_IN6ADDRSZ); 14424139Sjoerg endp = tp + NS_IN6ADDRSZ; 14524139Sjoerg colonp = NULL; 14624139Sjoerg /* Leading :: requires some special handling. */ 14724139Sjoerg if (*src == ':') 14824139Sjoerg if (*++src != ':') 14924139Sjoerg return (0); 15024139Sjoerg curtok = src; 15124139Sjoerg seen_xdigits = 0; 15224139Sjoerg val = 0; 15324139Sjoerg while ((ch = *src++) != '\0') { 15424139Sjoerg const char *pch; 15524139Sjoerg 15624139Sjoerg if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) 15724139Sjoerg pch = strchr((xdigits = xdigits_u), ch); 15824139Sjoerg if (pch != NULL) { 15924139Sjoerg val <<= 4; 16024139Sjoerg val |= (pch - xdigits); 16124139Sjoerg if (++seen_xdigits > 4) 16224139Sjoerg return (0); 16324139Sjoerg continue; 16424139Sjoerg } 16524139Sjoerg if (ch == ':') { 16624139Sjoerg curtok = src; 16724139Sjoerg if (!seen_xdigits) { 16824139Sjoerg if (colonp) 16986042Sdwmalone return (0); 17024139Sjoerg colonp = tp; 17124139Sjoerg continue; 17224139Sjoerg } 17324139Sjoerg if (tp + NS_INT16SZ > endp) 17424139Sjoerg return (0); 17524139Sjoerg *tp++ = (unsigned char) (val >> 8) & 0xff; 17624139Sjoerg *tp++ = (unsigned char) val & 0xff; 17724139Sjoerg seen_xdigits = 0; 17824139Sjoerg val = 0; 17924139Sjoerg continue; 18024139Sjoerg } 18124139Sjoerg if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && 18224139Sjoerg inet_pton4(curtok, tp) > 0) { 18324139Sjoerg tp += NS_INADDRSZ; 18424139Sjoerg seen_xdigits = 0; 18524139Sjoerg break; /* '\0' was seen by inet_pton4(). */ 18624139Sjoerg } 18724139Sjoerg return (0); 18824139Sjoerg } 18924139Sjoerg if (seen_xdigits) { 19024139Sjoerg if (tp + NS_INT16SZ > endp) 19124139Sjoerg return (0); 19224139Sjoerg *tp++ = (unsigned char) (val >> 8) & 0xff; 19324139Sjoerg *tp++ = (unsigned char) val & 0xff; 19424139Sjoerg } 19524139Sjoerg if (colonp != NULL) { 19624139Sjoerg /* 19724139Sjoerg * Since some memmove()'s erroneously fail to handle 19889757Sdwmalone * overlapping regions, we'll do the shift by hand. 19924139Sjoerg */ 20024139Sjoerg const int n = tp - colonp; 20124139Sjoerg int i; 20224139Sjoerg 203266280Sbdrewery if (tp == endp) 20424139Sjoerg return (0); 205266280Sbdrewery for (i = 1; i <= n; i++) { 20624139Sjoerg endp[- i] = colonp[n - i]; 20724139Sjoerg colonp[n - i] = 0; 20824139Sjoerg } 20924139Sjoerg tp = endp; 21024139Sjoerg } 21124139Sjoerg if (tp != endp) 21224139Sjoerg return (0); 21324139Sjoerg memcpy(dst, tmp, NS_IN6ADDRSZ); 21424139Sjoerg return (1); 21524139Sjoerg} 21624139Sjoerg