1 | /* $NetBSD: inet_pton.c,v 1.16 2000/02/07 18:51:02 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 <sys/cdefs.h>*/ 20 | #define __P(a) a 21 | 22 | #if defined(LIBC_SCCS) && !defined(lint) 23 | #if 0 24 | static char rcsid[] = "Id: inet_pton.c,v 8.7 1996/08/05 08:31:35 vixie Exp "; 25 | #else 26 | __RCSID("$NetBSD: inet_pton.c,v 1.16 2000/02/07 18:51:02 itojun Exp $"); 27 | #endif 28 | #endif /* LIBC_SCCS and not lint */ 29 | 30 | /*#include "namespace.h"*/ 31 | #include <sys/param.h> 32 | #include <sys/types.h> 33 | #include <sys/socket.h> 34 | #include <netinet/in.h> 35 | #include <arpa/inet.h> 36 | #include <arpa/nameser.h> 37 | 38 | #include <assert.h> 39 | #include <ctype.h> 40 | #include <errno.h> 41 | #include <stdlib.h> 42 | #include <string.h> 43 | 44 | #include "inet6def.h" 45 | 46 | /* 47 | * WARNING: Don't even consider trying to compile this on a system where 48 | * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. 49 | */ 50 | 51 | static int inet_pton4 __P((const char *src, u_char *dst, int pton)); 52 | static int inet_pton6 __P((const char *src, u_char *dst)); 53 | 54 | /* int 55 | * inet_pton(af, src, dst) 56 | * convert from presentation format (which usually means ASCII printable) 57 | * to network format (which is usually some kind of binary format). 58 | * return: 59 | * 1 if the address was valid for the specified address family 60 | * 0 if the address wasn't valid (`dst' is untouched in this case) 61 | * -1 if some other error occurred (`dst' is untouched in this case, too) 62 | * author: 63 | * Paul Vixie, 1996. 64 | */ 65 | int 66 | inet_pton(af, src, dst) 67 | int af; 68 | const char *src; 69 | void *dst; 70 | { 71 | 72 | if(src == NULL || dst == NULL) { 73 | return 0; 74 | } 75 | 76 | switch (af) { 77 | case AF_INET: 78 | return (inet_pton4(src, dst, 1)); 79 | case AF_INET6: 80 | return (inet_pton6(src, dst)); 81 | default: 82 | errno = EAFNOSUPPORT; 83 | return (-1); 84 | } 85 | /* NOTREACHED */ 86 | } 87 | 88 | /* int 89 | * inet_pton4(src, dst, pton) 90 | * when last arg is 0: inet_aton(). with hexadecimal, octal and shorthand. 91 | * when last arg is 1: inet_pton(). decimal dotted-quad only. 92 | * return: 93 | * 1 if `src' is a valid input, else 0. 94 | * notice: 95 | * does not touch `dst' unless it's returning 1. 96 | * author: 97 | * Paul Vixie, 1996. 98 | */ 99 | static int 100 | inet_pton4(src, dst, pton) 101 | const char *src; 102 | u_char *dst; 103 | int pton; 104 | { 105 | uint32_t val; 106 | u_int digit; 107 | int base, n; 108 | unsigned char c; 109 | u_int parts[4]; 110 | register u_int *pp = parts; 111 | 112 | if(src == NULL || dst == NULL) { 113 | return 0; 114 | } 115 | 116 | c = *src; 117 | for (;;) { 118 | /* 119 | * Collect number up to ``.''. 120 | * Values are specified as for C: 121 | * 0x=hex, 0=octal, isdigit=decimal. 122 | */ 123 | if (!isdigit(c)) 124 | return (0); 125 | val = 0; base = 10; 126 | if (c == '0') { 127 | c = *++src; 128 | if (c == 'x' || c == 'X') 129 | base = 16, c = *++src; 130 | else if (isdigit(c) && c != '9') 131 | base = 8; 132 | } 133 | /* inet_pton() takes decimal only */ 134 | if (pton && base != 10) 135 | return (0); 136 | for (;;) { 137 | if (isdigit(c)) { 138 | digit = c - '0'; 139 | if (digit >= base) 140 | break; 141 | val = (val * base) + digit; 142 | c = *++src; 143 | } else if (base == 16 && isxdigit(c)) { 144 | digit = c + 10 - (islower(c) ? 'a' : 'A'); 145 | if (digit >= 16) 146 | break; 147 | val = (val << 4) | digit; 148 | c = *++src; 149 | } else 150 | break; 151 | } 152 | if (c == '.') { 153 | /* 154 | * Internet format: 155 | * a.b.c.d 156 | * a.b.c (with c treated as 16 bits) 157 | * a.b (with b treated as 24 bits) 158 | * a (with a treated as 32 bits) 159 | */ 160 | if (pp >= parts + 3) 161 | return (0); 162 | *pp++ = val; 163 | c = *++src; 164 | } else 165 | break; 166 | } 167 | /* 168 | * Check for trailing characters. 169 | */ 170 | if (c != '\0' && !isspace(c)) 171 | return (0); 172 | /* 173 | * Concoct the address according to 174 | * the number of parts specified. 175 | */ 176 | n = pp - parts + 1; 177 | /* inet_pton() takes dotted-quad only. it does not take shorthand. */ 178 | if (pton && n != 4) 179 | return (0); 180 | switch (n) { 181 | 182 | case 0: 183 | return (0); /* initial nondigit */ 184 | 185 | case 1: /* a -- 32 bits */ 186 | break; 187 | 188 | case 2: /* a.b -- 8.24 bits */ 189 | if (parts[0] > 0xff || val > 0xffffff) 190 | return (0); 191 | val |= parts[0] << 24; 192 | break; 193 | 194 | case 3: /* a.b.c -- 8.8.16 bits */ 195 | if ((parts[0] | parts[1]) > 0xff || val > 0xffff) 196 | return (0); 197 | val |= (parts[0] << 24) | (parts[1] << 16); 198 | break; 199 | 200 | case 4: /* a.b.c.d -- 8.8.8.8 bits */ 201 | if ((parts[0] | parts[1] | parts[2] | val) > 0xff) 202 | return (0); 203 | val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); 204 | break; 205 | } 206 | if (dst) { 207 | val = htonl(val); 208 | memcpy(dst, &val, INADDRSZ); 209 | } 210 | return (1); 211 | } 212 | 213 | /* int 214 | * inet_pton6(src, dst) 215 | * convert presentation level address to network order binary form. 216 | * return: 217 | * 1 if `src' is a valid [RFC1884 2.2] address, else 0. 218 | * notice: 219 | * (1) does not touch `dst' unless it's returning 1. 220 | * (2) :: in a full address is silently ignored. 221 | * credit: 222 | * inspired by Mark Andrews. 223 | * author: 224 | * Paul Vixie, 1996. 225 | */ 226 | static int 227 | inet_pton6(src, dst) 228 | const char *src; 229 | u_char *dst; 230 | { 231 | static const char xdigits_l[] = "0123456789abcdef", 232 | xdigits_u[] = "0123456789ABCDEF"; 233 | u_char tmp[IN6ADDRSZ], *tp, *endp, *colonp; 234 | const char *xdigits, *curtok; 235 | int ch, saw_xdigit; 236 | u_int val; 237 | 238 | if(src == NULL || dst == NULL) { 239 | return 0; 240 | } 241 | 242 | memset((tp = tmp), '\0', IN6ADDRSZ); 243 | endp = tp + IN6ADDRSZ; 244 | colonp = NULL; 245 | /* Leading :: requires some special handling. */ 246 | if (*src == ':') 247 | if (*++src != ':') 248 | return (0); 249 | curtok = src; 250 | saw_xdigit = 0; 251 | val = 0; 252 | while ((ch = *src++) != '\0') { 253 | const char *pch; 254 | 255 | if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) 256 | pch = strchr((xdigits = xdigits_u), ch); 257 | if (pch != NULL) { 258 | val <<= 4; 259 | val |= (pch - xdigits); 260 | if (val > 0xffff) 261 | return (0); 262 | saw_xdigit = 1; 263 | continue; 264 | } 265 | if (ch == ':') { 266 | curtok = src; 267 | if (!saw_xdigit) { 268 | if (colonp) 269 | return (0); 270 | colonp = tp; 271 | continue; 272 | } else if (*src == '\0') 273 | return (0); 274 | if (tp + INT16SZ > endp) 275 | return (0); 276 | *tp++ = (u_char) (val >> 8) & 0xff; 277 | *tp++ = (u_char) val & 0xff; 278 | saw_xdigit = 0; 279 | val = 0; 280 | continue; 281 | } 282 | if (ch == '.' && ((tp + INADDRSZ) <= endp) && 283 | inet_pton4(curtok, tp, 1) > 0) { 284 | tp += INADDRSZ; 285 | saw_xdigit = 0; 286 | break; /* '\0' was seen by inet_pton4(). */ 287 | } 288 | return (0); 289 | } 290 | if (saw_xdigit) { 291 | if (tp + INT16SZ > endp) 292 | return (0); 293 | *tp++ = (u_char) (val >> 8) & 0xff; 294 | *tp++ = (u_char) val & 0xff; 295 | } 296 | if (colonp != NULL) { 297 | /* 298 | * Since some memmove()'s erroneously fail to handle 299 | * overlapping regions, we'll do the shift by hand. 300 | */ 301 | const int n = tp - colonp; 302 | int i; 303 | 304 | if (tp == endp) 305 | return (0); 306 | for (i = 1; i <= n; i++) { 307 | endp[- i] = colonp[n - i]; 308 | colonp[n - i] = 0; 309 | } 310 | tp = endp; 311 | } 312 | if (tp != endp) 313 | return (0); 314 | memcpy(dst, tmp, IN6ADDRSZ); 315 | return (1); 316 | } 317 |