1 1.8 christos /* $NetBSD: inet_pton.c,v 1.8 2012/03/13 21:13:38 christos Exp $ */ 2 1.1 christos 3 1.1 christos /* 4 1.1 christos * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 5 1.1 christos * Copyright (c) 1996,1999 by Internet Software Consortium. 6 1.1 christos * 7 1.1 christos * Permission to use, copy, modify, and distribute this software for any 8 1.1 christos * purpose with or without fee is hereby granted, provided that the above 9 1.1 christos * copyright notice and this permission notice appear in all copies. 10 1.1 christos * 11 1.1 christos * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 12 1.1 christos * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 1.1 christos * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 14 1.1 christos * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 1.1 christos * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 1.1 christos * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 17 1.1 christos * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 1.1 christos */ 19 1.1 christos 20 1.2 christos #include <sys/cdefs.h> 21 1.1 christos #if defined(LIBC_SCCS) && !defined(lint) 22 1.2 christos #if 0 23 1.6 christos static const char rcsid[] = "Id: inet_pton.c,v 1.5 2005/07/28 06:51:47 marka Exp"; 24 1.2 christos #else 25 1.8 christos __RCSID("$NetBSD: inet_pton.c,v 1.8 2012/03/13 21:13:38 christos Exp $"); 26 1.2 christos #endif 27 1.1 christos #endif /* LIBC_SCCS and not lint */ 28 1.1 christos 29 1.1 christos #include "port_before.h" 30 1.2 christos 31 1.2 christos #include "namespace.h" 32 1.1 christos #include <sys/param.h> 33 1.1 christos #include <sys/types.h> 34 1.1 christos #include <sys/socket.h> 35 1.1 christos #include <netinet/in.h> 36 1.1 christos #include <arpa/inet.h> 37 1.1 christos #include <arpa/nameser.h> 38 1.8 christos #include <stddef.h> 39 1.1 christos #include <string.h> 40 1.2 christos #include <assert.h> 41 1.2 christos #include <ctype.h> 42 1.1 christos #include <errno.h> 43 1.2 christos 44 1.1 christos #include "port_after.h" 45 1.1 christos 46 1.2 christos #ifdef __weak_alias 47 1.2 christos __weak_alias(inet_pton,_inet_pton) 48 1.2 christos #endif 49 1.2 christos 50 1.4 christos /*% 51 1.1 christos * WARNING: Don't even consider trying to compile this on a system where 52 1.1 christos * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. 53 1.1 christos */ 54 1.1 christos 55 1.2 christos static int inet_pton4(const char *src, u_char *dst, int pton); 56 1.2 christos static int inet_pton6(const char *src, u_char *dst); 57 1.1 christos 58 1.1 christos /* int 59 1.1 christos * inet_pton(af, src, dst) 60 1.1 christos * convert from presentation format (which usually means ASCII printable) 61 1.1 christos * to network format (which is usually some kind of binary format). 62 1.1 christos * return: 63 1.1 christos * 1 if the address was valid for the specified address family 64 1.1 christos * 0 if the address wasn't valid (`dst' is untouched in this case) 65 1.1 christos * -1 if some other error occurred (`dst' is untouched in this case, too) 66 1.1 christos * author: 67 1.1 christos * Paul Vixie, 1996. 68 1.1 christos */ 69 1.1 christos int 70 1.2 christos inet_pton(int af, const char *src, void *dst) 71 1.1 christos { 72 1.2 christos 73 1.2 christos _DIAGASSERT(src != NULL); 74 1.2 christos _DIAGASSERT(dst != NULL); 75 1.2 christos 76 1.1 christos switch (af) { 77 1.1 christos case AF_INET: 78 1.2 christos return (inet_pton4(src, dst, 1)); 79 1.1 christos case AF_INET6: 80 1.1 christos return (inet_pton6(src, dst)); 81 1.1 christos default: 82 1.1 christos errno = EAFNOSUPPORT; 83 1.1 christos return (-1); 84 1.1 christos } 85 1.1 christos /* NOTREACHED */ 86 1.1 christos } 87 1.1 christos 88 1.1 christos /* int 89 1.2 christos * inet_pton4(src, dst, pton) 90 1.2 christos * when last arg is 0: inet_aton(). with hexadecimal, octal and shorthand. 91 1.2 christos * when last arg is 1: inet_pton(). decimal dotted-quad only. 92 1.1 christos * return: 93 1.2 christos * 1 if `src' is a valid input, else 0. 94 1.1 christos * notice: 95 1.1 christos * does not touch `dst' unless it's returning 1. 96 1.1 christos * author: 97 1.1 christos * Paul Vixie, 1996. 98 1.1 christos */ 99 1.1 christos static int 100 1.2 christos inet_pton4(const char *src, u_char *dst, int pton) 101 1.1 christos { 102 1.2 christos u_int32_t val; 103 1.2 christos u_int digit, base; 104 1.8 christos ptrdiff_t n; 105 1.2 christos unsigned char c; 106 1.2 christos u_int parts[4]; 107 1.8 christos u_int *pp = parts; 108 1.1 christos 109 1.2 christos _DIAGASSERT(src != NULL); 110 1.2 christos _DIAGASSERT(dst != NULL); 111 1.1 christos 112 1.2 christos c = *src; 113 1.2 christos for (;;) { 114 1.2 christos /* 115 1.2 christos * Collect number up to ``.''. 116 1.2 christos * Values are specified as for C: 117 1.2 christos * 0x=hex, 0=octal, isdigit=decimal. 118 1.2 christos */ 119 1.2 christos if (!isdigit(c)) 120 1.2 christos return (0); 121 1.2 christos val = 0; base = 10; 122 1.2 christos if (c == '0') { 123 1.2 christos c = *++src; 124 1.2 christos if (c == 'x' || c == 'X') 125 1.2 christos base = 16, c = *++src; 126 1.2 christos else if (isdigit(c) && c != '9') 127 1.2 christos base = 8; 128 1.2 christos } 129 1.2 christos /* inet_pton() takes decimal only */ 130 1.2 christos if (pton && base != 10) 131 1.2 christos return (0); 132 1.2 christos for (;;) { 133 1.2 christos if (isdigit(c)) { 134 1.2 christos digit = c - '0'; 135 1.2 christos if (digit >= base) 136 1.2 christos break; 137 1.2 christos val = (val * base) + digit; 138 1.2 christos c = *++src; 139 1.2 christos } else if (base == 16 && isxdigit(c)) { 140 1.2 christos digit = c + 10 - (islower(c) ? 'a' : 'A'); 141 1.2 christos if (digit >= 16) 142 1.2 christos break; 143 1.2 christos val = (val << 4) | digit; 144 1.2 christos c = *++src; 145 1.2 christos } else 146 1.2 christos break; 147 1.2 christos } 148 1.2 christos if (c == '.') { 149 1.2 christos /* 150 1.2 christos * Internet format: 151 1.2 christos * a.b.c.d 152 1.2 christos * a.b.c (with c treated as 16 bits) 153 1.2 christos * a.b (with b treated as 24 bits) 154 1.2 christos * a (with a treated as 32 bits) 155 1.2 christos */ 156 1.2 christos if (pp >= parts + 3) 157 1.1 christos return (0); 158 1.2 christos *pp++ = val; 159 1.2 christos c = *++src; 160 1.1 christos } else 161 1.2 christos break; 162 1.2 christos } 163 1.2 christos /* 164 1.2 christos * Check for trailing characters. 165 1.2 christos */ 166 1.2 christos if (c != '\0' && !isspace(c)) 167 1.2 christos return (0); 168 1.2 christos /* 169 1.2 christos * Concoct the address according to 170 1.2 christos * the number of parts specified. 171 1.2 christos */ 172 1.2 christos n = pp - parts + 1; 173 1.2 christos /* inet_pton() takes dotted-quad only. it does not take shorthand. */ 174 1.2 christos if (pton && n != 4) 175 1.2 christos return (0); 176 1.2 christos switch (n) { 177 1.2 christos 178 1.2 christos case 0: 179 1.2 christos return (0); /* initial nondigit */ 180 1.2 christos 181 1.2 christos case 1: /* a -- 32 bits */ 182 1.2 christos break; 183 1.2 christos 184 1.2 christos case 2: /* a.b -- 8.24 bits */ 185 1.2 christos if (parts[0] > 0xff || val > 0xffffff) 186 1.1 christos return (0); 187 1.2 christos val |= parts[0] << 24; 188 1.2 christos break; 189 1.2 christos 190 1.2 christos case 3: /* a.b.c -- 8.8.16 bits */ 191 1.2 christos if ((parts[0] | parts[1]) > 0xff || val > 0xffff) 192 1.2 christos return (0); 193 1.2 christos val |= (parts[0] << 24) | (parts[1] << 16); 194 1.2 christos break; 195 1.2 christos 196 1.2 christos case 4: /* a.b.c.d -- 8.8.8.8 bits */ 197 1.2 christos if ((parts[0] | parts[1] | parts[2] | val) > 0xff) 198 1.2 christos return (0); 199 1.2 christos val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); 200 1.2 christos break; 201 1.2 christos } 202 1.2 christos if (dst) { 203 1.2 christos val = htonl(val); 204 1.2 christos memcpy(dst, &val, NS_INADDRSZ); 205 1.1 christos } 206 1.1 christos return (1); 207 1.1 christos } 208 1.1 christos 209 1.1 christos /* int 210 1.1 christos * inet_pton6(src, dst) 211 1.1 christos * convert presentation level address to network order binary form. 212 1.1 christos * return: 213 1.1 christos * 1 if `src' is a valid [RFC1884 2.2] address, else 0. 214 1.1 christos * notice: 215 1.1 christos * (1) does not touch `dst' unless it's returning 1. 216 1.1 christos * (2) :: in a full address is silently ignored. 217 1.1 christos * credit: 218 1.1 christos * inspired by Mark Andrews. 219 1.1 christos * author: 220 1.1 christos * Paul Vixie, 1996. 221 1.1 christos */ 222 1.1 christos static int 223 1.2 christos inet_pton6(const char *src, u_char *dst) 224 1.1 christos { 225 1.1 christos static const char xdigits_l[] = "0123456789abcdef", 226 1.1 christos xdigits_u[] = "0123456789ABCDEF"; 227 1.1 christos u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; 228 1.1 christos const char *xdigits, *curtok; 229 1.4 christos int ch, seen_xdigits; 230 1.1 christos u_int val; 231 1.1 christos 232 1.2 christos _DIAGASSERT(src != NULL); 233 1.2 christos _DIAGASSERT(dst != NULL); 234 1.2 christos 235 1.1 christos memset((tp = tmp), '\0', NS_IN6ADDRSZ); 236 1.1 christos endp = tp + NS_IN6ADDRSZ; 237 1.1 christos colonp = NULL; 238 1.1 christos /* Leading :: requires some special handling. */ 239 1.1 christos if (*src == ':') 240 1.1 christos if (*++src != ':') 241 1.1 christos return (0); 242 1.1 christos curtok = src; 243 1.4 christos seen_xdigits = 0; 244 1.1 christos val = 0; 245 1.1 christos while ((ch = *src++) != '\0') { 246 1.1 christos const char *pch; 247 1.1 christos 248 1.1 christos if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) 249 1.1 christos pch = strchr((xdigits = xdigits_u), ch); 250 1.1 christos if (pch != NULL) { 251 1.1 christos val <<= 4; 252 1.8 christos val |= (int)(pch - xdigits); 253 1.4 christos if (++seen_xdigits > 4) 254 1.1 christos return (0); 255 1.1 christos continue; 256 1.1 christos } 257 1.1 christos if (ch == ':') { 258 1.1 christos curtok = src; 259 1.4 christos if (!seen_xdigits) { 260 1.1 christos if (colonp) 261 1.1 christos return (0); 262 1.1 christos colonp = tp; 263 1.1 christos continue; 264 1.2 christos } else if (*src == '\0') 265 1.1 christos return (0); 266 1.3 lukem if (tp + NS_INT16SZ > endp) 267 1.1 christos return (0); 268 1.1 christos *tp++ = (u_char) (val >> 8) & 0xff; 269 1.1 christos *tp++ = (u_char) val & 0xff; 270 1.4 christos seen_xdigits = 0; 271 1.1 christos val = 0; 272 1.1 christos continue; 273 1.1 christos } 274 1.1 christos if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && 275 1.2 christos inet_pton4(curtok, tp, 1) > 0) { 276 1.1 christos tp += NS_INADDRSZ; 277 1.4 christos seen_xdigits = 0; 278 1.4 christos break; /*%< '\\0' was seen by inet_pton4(). */ 279 1.1 christos } 280 1.1 christos return (0); 281 1.1 christos } 282 1.4 christos if (seen_xdigits) { 283 1.1 christos if (tp + NS_INT16SZ > endp) 284 1.1 christos return (0); 285 1.1 christos *tp++ = (u_char) (val >> 8) & 0xff; 286 1.1 christos *tp++ = (u_char) val & 0xff; 287 1.1 christos } 288 1.1 christos if (colonp != NULL) { 289 1.1 christos /* 290 1.1 christos * Since some memmove()'s erroneously fail to handle 291 1.1 christos * overlapping regions, we'll do the shift by hand. 292 1.1 christos */ 293 1.8 christos const ptrdiff_t n = tp - colonp; 294 1.1 christos int i; 295 1.1 christos 296 1.1 christos if (tp == endp) 297 1.1 christos return (0); 298 1.1 christos for (i = 1; i <= n; i++) { 299 1.1 christos endp[- i] = colonp[n - i]; 300 1.1 christos colonp[n - i] = 0; 301 1.1 christos } 302 1.1 christos tp = endp; 303 1.1 christos } 304 1.1 christos if (tp != endp) 305 1.1 christos return (0); 306 1.1 christos memcpy(dst, tmp, NS_IN6ADDRSZ); 307 1.1 christos return (1); 308 1.1 christos } 309 1.4 christos 310 1.4 christos /*! \file */ 311