1/* 2 * Copyright (C) 2004, 2005, 2007, 2013, 2014 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 1996-2003 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/*! \file */ 19 20#if defined(LIBC_SCCS) && !defined(lint) 21static char rcsid[] = 22 "$Id: inet_pton.c,v 1.19 2007/06/19 23:47:17 tbox Exp $"; 23#endif /* LIBC_SCCS and not lint */ 24 25#include <config.h> 26 27#include <errno.h> 28#include <string.h> 29 30#include <isc/net.h> 31 32/*% INT16 Size */ 33#define NS_INT16SZ 2 34/*% IPv4 Address Size */ 35#define NS_INADDRSZ 4 36/*% IPv6 Address Size */ 37#define NS_IN6ADDRSZ 16 38 39/* 40 * WARNING: Don't even consider trying to compile this on a system where 41 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. 42 */ 43 44static int inet_pton4(const char *src, unsigned char *dst); 45static int inet_pton6(const char *src, unsigned char *dst); 46 47/*% 48 * convert from presentation format (which usually means ASCII printable) 49 * to network format (which is usually some kind of binary format). 50 * \return 51 * 1 if the address was valid for the specified address family 52 * 0 if the address wasn't valid (`dst' is untouched in this case) 53 * -1 if some other error occurred (`dst' is untouched in this case, too) 54 * \author 55 * Paul Vixie, 1996. 56 */ 57int 58isc_net_pton(int af, const char *src, void *dst) { 59 switch (af) { 60 case AF_INET: 61 return (inet_pton4(src, dst)); 62 case AF_INET6: 63 return (inet_pton6(src, dst)); 64 default: 65 errno = EAFNOSUPPORT; 66 return (-1); 67 } 68 /* NOTREACHED */ 69} 70 71/*!\fn static int inet_pton4(const char *src, unsigned char *dst) 72 * \brief 73 * like inet_aton() but without all the hexadecimal and shorthand. 74 * \return 75 * 1 if `src' is a valid dotted quad, else 0. 76 * \note 77 * does not touch `dst' unless it's returning 1. 78 * \author 79 * Paul Vixie, 1996. 80 */ 81static int 82inet_pton4(const char *src, unsigned char *dst) { 83 static const char digits[] = "0123456789"; 84 int saw_digit, octets, ch; 85 unsigned char tmp[NS_INADDRSZ], *tp; 86 87 saw_digit = 0; 88 octets = 0; 89 *(tp = tmp) = 0; 90 while ((ch = *src++) != '\0') { 91 const char *pch; 92 93 if ((pch = strchr(digits, ch)) != NULL) { 94 unsigned int new = *tp * 10; 95 96 new += (int)(pch - digits); 97 if (saw_digit && *tp == 0) 98 return (0); 99 if (new > 255) 100 return (0); 101 *tp = new; 102 if (!saw_digit) { 103 if (++octets > 4) 104 return (0); 105 saw_digit = 1; 106 } 107 } else if (ch == '.' && saw_digit) { 108 if (octets == 4) 109 return (0); 110 *++tp = 0; 111 saw_digit = 0; 112 } else 113 return (0); 114 } 115 if (octets < 4) 116 return (0); 117 memmove(dst, tmp, NS_INADDRSZ); 118 return (1); 119} 120 121/*% 122 * convert presentation level address to network order binary form. 123 * \return 124 * 1 if `src' is a valid [RFC1884 2.2] address, else 0. 125 * \note 126 * (1) does not touch `dst' unless it's returning 1. 127 * \note 128 * (2) :: in a full address is silently ignored. 129 * \author 130 * inspired by Mark Andrews. 131 * \author 132 * Paul Vixie, 1996. 133 */ 134static int 135inet_pton6(const char *src, unsigned char *dst) { 136 static const char xdigits_l[] = "0123456789abcdef", 137 xdigits_u[] = "0123456789ABCDEF"; 138 unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; 139 const char *xdigits, *curtok; 140 int ch, seen_xdigits; 141 unsigned int val; 142 143 memset((tp = tmp), '\0', NS_IN6ADDRSZ); 144 endp = tp + NS_IN6ADDRSZ; 145 colonp = NULL; 146 /* Leading :: requires some special handling. */ 147 if (*src == ':') 148 if (*++src != ':') 149 return (0); 150 curtok = src; 151 seen_xdigits = 0; 152 val = 0; 153 while ((ch = *src++) != '\0') { 154 const char *pch; 155 156 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) 157 pch = strchr((xdigits = xdigits_u), ch); 158 if (pch != NULL) { 159 val <<= 4; 160 val |= (pch - xdigits); 161 if (++seen_xdigits > 4) 162 return (0); 163 continue; 164 } 165 if (ch == ':') { 166 curtok = src; 167 if (!seen_xdigits) { 168 if (colonp) 169 return (0); 170 colonp = tp; 171 continue; 172 } 173 if (tp + NS_INT16SZ > endp) 174 return (0); 175 *tp++ = (unsigned char) (val >> 8) & 0xff; 176 *tp++ = (unsigned char) val & 0xff; 177 seen_xdigits = 0; 178 val = 0; 179 continue; 180 } 181 if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && 182 inet_pton4(curtok, tp) > 0) { 183 tp += NS_INADDRSZ; 184 seen_xdigits = 0; 185 break; /* '\0' was seen by inet_pton4(). */ 186 } 187 return (0); 188 } 189 if (seen_xdigits) { 190 if (tp + NS_INT16SZ > endp) 191 return (0); 192 *tp++ = (unsigned char) (val >> 8) & 0xff; 193 *tp++ = (unsigned char) val & 0xff; 194 } 195 if (colonp != NULL) { 196 /* 197 * Since some memmove()'s erroneously fail to handle 198 * overlapping regions, we'll do the shift by hand. 199 */ 200 const int n = (int)(tp - colonp); 201 int i; 202 203 if (tp == endp) 204 return (0); 205 for (i = 1; i <= n; i++) { 206 endp[- i] = colonp[n - i]; 207 colonp[n - i] = 0; 208 } 209 tp = endp; 210 } 211 if (tp != endp) 212 return (0); 213 memmove(dst, tmp, NS_IN6ADDRSZ); 214 return (1); 215} 216