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