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