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 <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 errno = EAFNOSUPPORT; 74 return (-1); 75 } 76 /* NOTREACHED */ 77 } 78 79 /* int 80 * inet_pton4(src, dst) 81 * like inet_aton() but without all the hexadecimal and shorthand. 82 * return: 83 * 1 if `src' is a valid dotted quad, else 0. 84 * notice: 85 * does not touch `dst' unless it's returning 1. 86 * author: 87 * Paul Vixie, 1996. 88 */ 89 static int 90 inet_pton4(src, dst) 91 const char *src; 92 uint8_t *dst; 93 { 94 static const char digits[] = "0123456789"; 95 int saw_digit, octets, ch; 96 uint8_t tmp[NS_INADDRSZ], *tp; 97 98 saw_digit = 0; 99 octets = 0; 100 *(tp = tmp) = 0; 101 while ((ch = *src++) != '\0') { 102 const char *pch; 103 104 if ((pch = strchr(digits, ch)) != NULL) { 105 uint32_t new = *tp * 10 + (pch - digits); 106 107 if (new > 255) 108 return (0); 109 *tp = new; 110 if (! saw_digit) { 111 if (++octets > 4) 112 return (0); 113 saw_digit = 1; 114 } 115 } else if (ch == '.' && saw_digit) { 116 if (octets == 4) 117 return (0); 118 *++tp = 0; 119 saw_digit = 0; 120 } else 121 return (0); 122 } 123 if (octets < 4) 124 return (0); 125 126 memcpy(dst, tmp, NS_INADDRSZ); 127 return (1); 128 } 129 130 /* int 131 * inet_pton6(src, dst) 132 * convert presentation level address to network order binary form. 133 * return: 134 * 1 if `src' is a valid [RFC1884 2.2] address, else 0. 135 * notice: 136 * (1) does not touch `dst' unless it's returning 1. 137 * (2) :: in a full address is silently ignored. 138 * credit: 139 * inspired by Mark Andrews. 140 * author: 141 * Paul Vixie, 1996. 142 */ 143 static int 144 inet_pton6(src, dst) 145 const char *src; 146 uint8_t *dst; 147 { 148 static const char xdigits_l[] = "0123456789abcdef", 149 xdigits_u[] = "0123456789ABCDEF"; 150 uint8_t tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; 151 const char *xdigits, *curtok; 152 int ch, saw_xdigit; 153 uint32_t val; 154 155 memset((tp = tmp), '\0', NS_IN6ADDRSZ); 156 endp = tp + NS_IN6ADDRSZ; 157 colonp = NULL; 158 /* Leading :: requires some special handling. */ 159 if (*src == ':') 160 if (*++src != ':') 161 return (0); 162 curtok = src; 163 saw_xdigit = 0; 164 val = 0; 165 while ((ch = *src++) != '\0') { 166 const char *pch; 167 168 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) 169 pch = strchr((xdigits = xdigits_u), ch); 170 if (pch != NULL) { 171 val <<= 4; 172 val |= (pch - xdigits); 173 if (val > 0xffff) 174 return (0); 175 saw_xdigit = 1; 176 continue; 177 } 178 if (ch == ':') { 179 curtok = src; 180 if (!saw_xdigit) { 181 if (colonp) 182 return (0); 183 colonp = tp; 184 continue; 185 } 186 if (tp + NS_INT16SZ > endp) 187 return (0); 188 *tp++ = (uint8_t) (val >> 8) & 0xff; 189 *tp++ = (uint8_t) val & 0xff; 190 saw_xdigit = 0; 191 val = 0; 192 continue; 193 } 194 if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && 195 inet_pton4(curtok, tp) > 0) { 196 tp += NS_INADDRSZ; 197 saw_xdigit = 0; 198 break; /* '\0' was seen by inet_pton4(). */ 199 } 200 return (0); 201 } 202 if (saw_xdigit) { 203 if (tp + NS_INT16SZ > endp) 204 return (0); 205 *tp++ = (uint8_t) (val >> 8) & 0xff; 206 *tp++ = (uint8_t) val & 0xff; 207 } 208 if (colonp != NULL) { 209 /* 210 * Since some memmove()'s erroneously fail to handle 211 * overlapping regions, we'll do the shift by hand. 212 */ 213 const int n = tp - colonp; 214 int i; 215 216 for (i = 1; i <= n; i++) { 217 endp[- i] = colonp[n - i]; 218 colonp[n - i] = 0; 219 } 220 tp = endp; 221 } 222 if (tp != endp) 223 return (0); 224 memcpy(dst, tmp, NS_IN6ADDRSZ); 225 return (1); 226 } 227