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