1 /* $OpenBSD: inet_pton.c,v 1.9 2015/01/16 16:48:51 deraadt 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 <sys/types.h> 20 #include <sys/socket.h> 21 #include <netinet/in.h> 22 #include <arpa/inet.h> 23 #include <arpa/nameser.h> 24 #include <string.h> 25 #include <errno.h> 26 27 /* 28 * WARNING: Don't even consider trying to compile this on a system where 29 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. 30 */ 31 32 static int inet_pton4(const char *src, u_char *dst); 33 static int inet_pton6(const char *src, u_char *dst); 34 35 /* int 36 * inet_pton(af, src, dst) 37 * convert from presentation format (which usually means ASCII printable) 38 * to network format (which is usually some kind of binary format). 39 * return: 40 * 1 if the address was valid for the specified address family 41 * 0 if the address wasn't valid (`dst' is untouched in this case) 42 * -1 if some other error occurred (`dst' is untouched in this case, too) 43 * author: 44 * Paul Vixie, 1996. 45 */ 46 int 47 inet_pton(int af, const char *src, void *dst) 48 { 49 switch (af) { 50 case AF_INET: 51 return (inet_pton4(src, dst)); 52 case AF_INET6: 53 return (inet_pton6(src, dst)); 54 default: 55 errno = EAFNOSUPPORT; 56 return (-1); 57 } 58 /* NOTREACHED */ 59 } 60 61 /* int 62 * inet_pton4(src, dst) 63 * like inet_aton() but without all the hexadecimal and shorthand. 64 * return: 65 * 1 if `src' is a valid dotted quad, else 0. 66 * notice: 67 * does not touch `dst' unless it's returning 1. 68 * author: 69 * Paul Vixie, 1996. 70 */ 71 static int 72 inet_pton4(const char *src, u_char *dst) 73 { 74 static const char digits[] = "0123456789"; 75 int saw_digit, octets, ch; 76 u_char tmp[INADDRSZ], *tp; 77 78 saw_digit = 0; 79 octets = 0; 80 *(tp = tmp) = 0; 81 while ((ch = *src++) != '\0') { 82 const char *pch; 83 84 if ((pch = strchr(digits, ch)) != NULL) { 85 u_int new = *tp * 10 + (pch - digits); 86 87 if (new > 255) 88 return (0); 89 if (! saw_digit) { 90 if (++octets > 4) 91 return (0); 92 saw_digit = 1; 93 } 94 *tp = new; 95 } else if (ch == '.' && saw_digit) { 96 if (octets == 4) 97 return (0); 98 *++tp = 0; 99 saw_digit = 0; 100 } else 101 return (0); 102 } 103 if (octets < 4) 104 return (0); 105 106 memcpy(dst, tmp, INADDRSZ); 107 return (1); 108 } 109 110 /* int 111 * inet_pton6(src, dst) 112 * convert presentation level address to network order binary form. 113 * return: 114 * 1 if `src' is a valid [RFC1884 2.2] address, else 0. 115 * notice: 116 * does not touch `dst' unless it's returning 1. 117 * credit: 118 * inspired by Mark Andrews. 119 * author: 120 * Paul Vixie, 1996. 121 */ 122 static int 123 inet_pton6(const char *src, u_char *dst) 124 { 125 static const char xdigits_l[] = "0123456789abcdef", 126 xdigits_u[] = "0123456789ABCDEF"; 127 u_char tmp[IN6ADDRSZ], *tp, *endp, *colonp; 128 const char *xdigits, *curtok; 129 int ch, saw_xdigit, count_xdigit; 130 u_int val; 131 132 memset((tp = tmp), '\0', IN6ADDRSZ); 133 endp = tp + IN6ADDRSZ; 134 colonp = NULL; 135 /* Leading :: requires some special handling. */ 136 if (*src == ':') 137 if (*++src != ':') 138 return (0); 139 curtok = src; 140 saw_xdigit = count_xdigit = 0; 141 val = 0; 142 while ((ch = *src++) != '\0') { 143 const char *pch; 144 145 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) 146 pch = strchr((xdigits = xdigits_u), ch); 147 if (pch != NULL) { 148 if (count_xdigit >= 4) 149 return (0); 150 val <<= 4; 151 val |= (pch - xdigits); 152 if (val > 0xffff) 153 return (0); 154 saw_xdigit = 1; 155 count_xdigit++; 156 continue; 157 } 158 if (ch == ':') { 159 curtok = src; 160 if (!saw_xdigit) { 161 if (colonp) 162 return (0); 163 colonp = tp; 164 continue; 165 } else if (*src == '\0') { 166 return (0); 167 } 168 if (tp + INT16SZ > endp) 169 return (0); 170 *tp++ = (u_char) (val >> 8) & 0xff; 171 *tp++ = (u_char) val & 0xff; 172 saw_xdigit = 0; 173 count_xdigit = 0; 174 val = 0; 175 continue; 176 } 177 if (ch == '.' && ((tp + INADDRSZ) <= endp) && 178 inet_pton4(curtok, tp) > 0) { 179 tp += INADDRSZ; 180 saw_xdigit = 0; 181 count_xdigit = 0; 182 break; /* '\0' was seen by inet_pton4(). */ 183 } 184 return (0); 185 } 186 if (saw_xdigit) { 187 if (tp + INT16SZ > endp) 188 return (0); 189 *tp++ = (u_char) (val >> 8) & 0xff; 190 *tp++ = (u_char) val & 0xff; 191 } 192 if (colonp != NULL) { 193 /* 194 * Since some memmove()'s erroneously fail to handle 195 * overlapping regions, we'll do the shift by hand. 196 */ 197 const int n = tp - colonp; 198 int i; 199 200 if (tp == endp) 201 return (0); 202 for (i = 1; i <= n; i++) { 203 endp[- i] = colonp[n - i]; 204 colonp[n - i] = 0; 205 } 206 tp = endp; 207 } 208 if (tp != endp) 209 return (0); 210 memcpy(dst, tmp, IN6ADDRSZ); 211 return (1); 212 } 213