inet_pton.c revision 285612
124139Sjoerg/*
224139Sjoerg * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
324139Sjoerg * Copyright (C) 1996-2003  Internet Software Consortium.
424139Sjoerg *
524139Sjoerg * Permission to use, copy, modify, and/or distribute this software for any
624139Sjoerg * purpose with or without fee is hereby granted, provided that the above
724139Sjoerg * copyright notice and this permission notice appear in all copies.
824139Sjoerg *
924139Sjoerg * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
1024139Sjoerg * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
1124139Sjoerg * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
1289757Sdwmalone * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
1389757Sdwmalone * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
1489757Sdwmalone * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1566641Simp * PERFORMANCE OF THIS SOFTWARE.
1666641Simp */
1724139Sjoerg
1824139Sjoerg/*! \file */
1924139Sjoerg
2024139Sjoerg#if defined(LIBC_SCCS) && !defined(lint)
2124139Sjoergstatic char rcsid[] =
2224139Sjoerg	"$Id: inet_pton.c,v 1.19 2007/06/19 23:47:17 tbox Exp $";
2324139Sjoerg#endif /* LIBC_SCCS and not lint */
2424139Sjoerg
2524139Sjoerg#include <config.h>
2624139Sjoerg
2724139Sjoerg#include <errno.h>
2824139Sjoerg#include <string.h>
2924139Sjoerg
3024139Sjoerg#include <isc/net.h>
3124139Sjoerg
3224139Sjoerg/*% INT16 Size */
3324139Sjoerg#define NS_INT16SZ	 2
3424139Sjoerg/*% IPv4 Address Size */
3524139Sjoerg#define NS_INADDRSZ	 4
3624139Sjoerg/*% IPv6 Address Size */
3786042Sdwmalone#define NS_IN6ADDRSZ	16
3824139Sjoerg
3924139Sjoerg/*
4024139Sjoerg * WARNING: Don't even consider trying to compile this on a system where
41266280Sbdrewery * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
4224139Sjoerg */
43266280Sbdrewery
4424139Sjoergstatic int inet_pton4(const char *src, unsigned char *dst);
4524139Sjoergstatic int inet_pton6(const char *src, unsigned char *dst);
4624139Sjoergint isc_net_pton(int af, const char *src, void *dst);
4724139Sjoerg
4824139Sjoerg/*%
4924139Sjoerg *	convert from presentation format (which usually means ASCII printable)
5024139Sjoerg *	to network format (which is usually some kind of binary format).
5124139Sjoerg * \return
5224139Sjoerg *	1 if the address was valid for the specified address family
5324139Sjoerg *	0 if the address wasn't valid (`dst' is untouched in this case)
5424139Sjoerg *	-1 if some other error occurred (`dst' is untouched in this case, too)
5524139Sjoerg * \author
5624139Sjoerg *	Paul Vixie, 1996.
5724139Sjoerg */
5824139Sjoergint
5924139Sjoergisc_net_pton(int af, const char *src, void *dst) {
6024139Sjoerg	switch (af) {
6124139Sjoerg	case AF_INET:
6224139Sjoerg		return (inet_pton4(src, dst));
6324139Sjoerg	case AF_INET6:
6424139Sjoerg		return (inet_pton6(src, dst));
6524139Sjoerg	default:
6624139Sjoerg		errno = EAFNOSUPPORT;
6724139Sjoerg		return (-1);
6824139Sjoerg	}
6924139Sjoerg	/* NOTREACHED */
70168710Sstas}
71175420Speter
72168710Sstas/*!\fn static int inet_pton4(const char *src, unsigned char *dst)
7324139Sjoerg * \brief
7424139Sjoerg *	like inet_aton() but without all the hexadecimal and shorthand.
7524139Sjoerg * \return
7624139Sjoerg *	1 if `src' is a valid dotted quad, else 0.
7724139Sjoerg * \note
7824139Sjoerg *	does not touch `dst' unless it's returning 1.
7924139Sjoerg * \author
8081187Skris *	Paul Vixie, 1996.
8181187Skris */
8281187Skrisstatic int
8381187Skrisinet_pton4(const char *src, unsigned char *dst) {
8424139Sjoerg	static const char digits[] = "0123456789";
8524139Sjoerg	int saw_digit, octets, ch;
8624139Sjoerg	unsigned char tmp[NS_INADDRSZ], *tp;
8724139Sjoerg
8824139Sjoerg	saw_digit = 0;
8924139Sjoerg	octets = 0;
9024139Sjoerg	*(tp = tmp) = 0;
91145073Skeramida	while ((ch = *src++) != '\0') {
9224139Sjoerg		const char *pch;
9324139Sjoerg
9424139Sjoerg		if ((pch = strchr(digits, ch)) != NULL) {
9524139Sjoerg			unsigned int newv = *tp * 10 + (pch - digits);
9624139Sjoerg
9724139Sjoerg			if (saw_digit && *tp == 0)
9824139Sjoerg				return (0);
9924139Sjoerg			if (newv > 255)
10024139Sjoerg				return (0);
10124139Sjoerg			*tp = (unsigned char)newv;
10224139Sjoerg			if (!saw_digit) {
103133817Salfred				if (++octets > 4)
10424139Sjoerg					return (0);
10524139Sjoerg				saw_digit = 1;
106131829Skeramida			}
10724139Sjoerg		} else if (ch == '.' && saw_digit) {
10824139Sjoerg			if (octets == 4)
10924139Sjoerg				return (0);
11024139Sjoerg			*++tp = 0;
11124139Sjoerg			saw_digit = 0;
11224139Sjoerg		} else
11324139Sjoerg			return (0);
11424139Sjoerg	}
11524139Sjoerg	if (octets < 4)
11624139Sjoerg		return (0);
11724139Sjoerg	memcpy(dst, tmp, NS_INADDRSZ);
11824139Sjoerg	return (1);
11924139Sjoerg}
12024139Sjoerg
12124139Sjoerg/*%
12224139Sjoerg *	convert presentation level address to network order binary form.
12324139Sjoerg * \return
12424139Sjoerg *	1 if `src' is a valid [RFC1884 2.2] address, else 0.
12524139Sjoerg * \note
126237656Sjhb *	(1) does not touch `dst' unless it's returning 1.
127237656Sjhb * \note
12824142Sjoerg *	(2) :: in a full address is silently ignored.
12924142Sjoerg * \author
13024139Sjoerg *	inspired by Mark Andrews.
13124139Sjoerg * \author
13224139Sjoerg *	Paul Vixie, 1996.
13324139Sjoerg */
13424139Sjoergstatic int
13524139Sjoerginet_pton6(const char *src, unsigned char *dst) {
13624139Sjoerg	static const char xdigits_l[] = "0123456789abcdef",
13724139Sjoerg			  xdigits_u[] = "0123456789ABCDEF";
13824139Sjoerg	unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
13924139Sjoerg	const char *xdigits, *curtok;
14024139Sjoerg	int ch, seen_xdigits;
14124139Sjoerg	unsigned int val;
142237656Sjhb
14324142Sjoerg	memset((tp = tmp), '\0', NS_IN6ADDRSZ);
14424139Sjoerg	endp = tp + NS_IN6ADDRSZ;
14524139Sjoerg	colonp = NULL;
14624139Sjoerg	/* Leading :: requires some special handling. */
14724139Sjoerg	if (*src == ':')
14824139Sjoerg		if (*++src != ':')
14924139Sjoerg			return (0);
15024139Sjoerg	curtok = src;
15124139Sjoerg	seen_xdigits = 0;
15224139Sjoerg	val = 0;
15324139Sjoerg	while ((ch = *src++) != '\0') {
15424139Sjoerg		const char *pch;
15524139Sjoerg
15624139Sjoerg		if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
15724139Sjoerg			pch = strchr((xdigits = xdigits_u), ch);
15824139Sjoerg		if (pch != NULL) {
15924139Sjoerg			val <<= 4;
16024139Sjoerg			val |= (pch - xdigits);
16124139Sjoerg			if (++seen_xdigits > 4)
16224139Sjoerg				return (0);
16324139Sjoerg			continue;
16424139Sjoerg		}
16524139Sjoerg		if (ch == ':') {
16624139Sjoerg			curtok = src;
16724139Sjoerg			if (!seen_xdigits) {
16824139Sjoerg				if (colonp)
16986042Sdwmalone					return (0);
17024139Sjoerg				colonp = tp;
17124139Sjoerg				continue;
17224139Sjoerg			}
17324139Sjoerg			if (tp + NS_INT16SZ > endp)
17424139Sjoerg				return (0);
17524139Sjoerg			*tp++ = (unsigned char) (val >> 8) & 0xff;
17624139Sjoerg			*tp++ = (unsigned char) val & 0xff;
17724139Sjoerg			seen_xdigits = 0;
17824139Sjoerg			val = 0;
17924139Sjoerg			continue;
18024139Sjoerg		}
18124139Sjoerg		if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
18224139Sjoerg		    inet_pton4(curtok, tp) > 0) {
18324139Sjoerg			tp += NS_INADDRSZ;
18424139Sjoerg			seen_xdigits = 0;
18524139Sjoerg			break;	/* '\0' was seen by inet_pton4(). */
18624139Sjoerg		}
18724139Sjoerg		return (0);
18824139Sjoerg	}
18924139Sjoerg	if (seen_xdigits) {
19024139Sjoerg		if (tp + NS_INT16SZ > endp)
19124139Sjoerg			return (0);
19224139Sjoerg		*tp++ = (unsigned char) (val >> 8) & 0xff;
19324139Sjoerg		*tp++ = (unsigned char) val & 0xff;
19424139Sjoerg	}
19524139Sjoerg	if (colonp != NULL) {
19624139Sjoerg		/*
19724139Sjoerg		 * Since some memmove()'s erroneously fail to handle
19889757Sdwmalone		 * overlapping regions, we'll do the shift by hand.
19924139Sjoerg		 */
20024139Sjoerg		const int n = tp - colonp;
20124139Sjoerg		int i;
20224139Sjoerg
203266280Sbdrewery		if (tp == endp)
20424139Sjoerg			return (0);
205266280Sbdrewery		for (i = 1; i <= n; i++) {
20624139Sjoerg			endp[- i] = colonp[n - i];
20724139Sjoerg			colonp[n - i] = 0;
20824139Sjoerg		}
20924139Sjoerg		tp = endp;
21024139Sjoerg	}
21124139Sjoerg	if (tp != endp)
21224139Sjoerg		return (0);
21324139Sjoerg	memcpy(dst, tmp, NS_IN6ADDRSZ);
21424139Sjoerg	return (1);
21524139Sjoerg}
21624139Sjoerg