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