1 /* 2 * Copyright (C) 2004, 2005, 2007 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) 21 static 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 44 static int inet_pton4(const char *src, unsigned char *dst); 45 static int inet_pton6(const char *src, unsigned char *dst); 46 int isc_net_pton(int af, const char *src, void *dst); 47 48 /*% 49 * convert from presentation format (which usually means ASCII printable) 50 * to network format (which is usually some kind of binary format). 51 * \return 52 * 1 if the address was valid for the specified address family 53 * 0 if the address wasn't valid (`dst' is untouched in this case) 54 * -1 if some other error occurred (`dst' is untouched in this case, too) 55 * \author 56 * Paul Vixie, 1996. 57 */ 58 int 59 isc_net_pton(int af, const char *src, void *dst) { 60 switch (af) { 61 case AF_INET: 62 return (inet_pton4(src, dst)); 63 case AF_INET6: 64 return (inet_pton6(src, dst)); 65 default: 66 errno = EAFNOSUPPORT; 67 return (-1); 68 } 69 /* NOTREACHED */ 70 } 71 72 /*!\fn static int inet_pton4(const char *src, unsigned char *dst) 73 * \brief 74 * like inet_aton() but without all the hexadecimal and shorthand. 75 * \return 76 * 1 if `src' is a valid dotted quad, else 0. 77 * \note 78 * does not touch `dst' unless it's returning 1. 79 * \author 80 * Paul Vixie, 1996. 81 */ 82 static int 83 inet_pton4(const char *src, unsigned char *dst) { 84 static const char digits[] = "0123456789"; 85 int saw_digit, octets, ch; 86 unsigned char tmp[NS_INADDRSZ], *tp; 87 88 saw_digit = 0; 89 octets = 0; 90 *(tp = tmp) = 0; 91 while ((ch = *src++) != '\0') { 92 const char *pch; 93 94 if ((pch = strchr(digits, ch)) != NULL) { 95 size_t newv = *tp * 10 + (pch - digits); 96 97 if (saw_digit && *tp == 0) 98 return (0); 99 if (newv > 255) 100 return (0); 101 *tp = (unsigned char)newv; 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 memcpy(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 */ 134 static int 135 inet_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 (NS_INT16SZ > endp - tp) 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 == '.' && (NS_INADDRSZ <= endp - tp) && 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 (NS_INT16SZ > endp - tp) 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 size_t n = tp - colonp; 201 int i; 202 203 if (tp == endp) 204 return (0); 205 for (i = 1; (size_t)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 memcpy(dst, tmp, NS_IN6ADDRSZ); 214 return (1); 215 } 216