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