1258945Sroberto/*
2258945Sroberto * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
3258945Sroberto * Copyright (C) 1996-2003  Internet Software Consortium.
4258945Sroberto *
5258945Sroberto * Permission to use, copy, modify, and/or distribute this software for any
6258945Sroberto * purpose with or without fee is hereby granted, provided that the above
7258945Sroberto * copyright notice and this permission notice appear in all copies.
8258945Sroberto *
9258945Sroberto * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10258945Sroberto * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11258945Sroberto * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12258945Sroberto * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13258945Sroberto * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14258945Sroberto * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15258945Sroberto * PERFORMANCE OF THIS SOFTWARE.
16258945Sroberto */
17258945Sroberto
18258945Sroberto/*! \file */
19258945Sroberto
20258945Sroberto#if defined(LIBC_SCCS) && !defined(lint)
21258945Srobertostatic char rcsid[] =
22258945Sroberto	"$Id: inet_pton.c,v 1.19 2007/06/19 23:47:17 tbox Exp $";
23258945Sroberto#endif /* LIBC_SCCS and not lint */
24258945Sroberto
25258945Sroberto#include <config.h>
26258945Sroberto
27258945Sroberto#include <errno.h>
28258945Sroberto#include <string.h>
29258945Sroberto
30258945Sroberto#include <isc/net.h>
31258945Sroberto
32258945Sroberto/*% INT16 Size */
33258945Sroberto#define NS_INT16SZ	 2
34258945Sroberto/*% IPv4 Address Size */
35258945Sroberto#define NS_INADDRSZ	 4
36258945Sroberto/*% IPv6 Address Size */
37258945Sroberto#define NS_IN6ADDRSZ	16
38258945Sroberto
39258945Sroberto/*
40258945Sroberto * WARNING: Don't even consider trying to compile this on a system where
41258945Sroberto * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
42258945Sroberto */
43258945Sroberto
44258945Srobertostatic int inet_pton4(const char *src, unsigned char *dst);
45258945Srobertostatic int inet_pton6(const char *src, unsigned char *dst);
46280849Scyint isc_net_pton(int af, const char *src, void *dst);
47258945Sroberto
48258945Sroberto/*%
49258945Sroberto *	convert from presentation format (which usually means ASCII printable)
50258945Sroberto *	to network format (which is usually some kind of binary format).
51258945Sroberto * \return
52258945Sroberto *	1 if the address was valid for the specified address family
53258945Sroberto *	0 if the address wasn't valid (`dst' is untouched in this case)
54258945Sroberto *	-1 if some other error occurred (`dst' is untouched in this case, too)
55258945Sroberto * \author
56258945Sroberto *	Paul Vixie, 1996.
57258945Sroberto */
58258945Srobertoint
59258945Srobertoisc_net_pton(int af, const char *src, void *dst) {
60258945Sroberto	switch (af) {
61258945Sroberto	case AF_INET:
62258945Sroberto		return (inet_pton4(src, dst));
63258945Sroberto	case AF_INET6:
64258945Sroberto		return (inet_pton6(src, dst));
65258945Sroberto	default:
66258945Sroberto		errno = EAFNOSUPPORT;
67258945Sroberto		return (-1);
68258945Sroberto	}
69258945Sroberto	/* NOTREACHED */
70258945Sroberto}
71258945Sroberto
72258945Sroberto/*!\fn static int inet_pton4(const char *src, unsigned char *dst)
73258945Sroberto * \brief
74258945Sroberto *	like inet_aton() but without all the hexadecimal and shorthand.
75258945Sroberto * \return
76258945Sroberto *	1 if `src' is a valid dotted quad, else 0.
77258945Sroberto * \note
78258945Sroberto *	does not touch `dst' unless it's returning 1.
79258945Sroberto * \author
80258945Sroberto *	Paul Vixie, 1996.
81258945Sroberto */
82258945Srobertostatic int
83258945Srobertoinet_pton4(const char *src, unsigned char *dst) {
84258945Sroberto	static const char digits[] = "0123456789";
85258945Sroberto	int saw_digit, octets, ch;
86258945Sroberto	unsigned char tmp[NS_INADDRSZ], *tp;
87258945Sroberto
88258945Sroberto	saw_digit = 0;
89258945Sroberto	octets = 0;
90258945Sroberto	*(tp = tmp) = 0;
91258945Sroberto	while ((ch = *src++) != '\0') {
92258945Sroberto		const char *pch;
93258945Sroberto
94258945Sroberto		if ((pch = strchr(digits, ch)) != NULL) {
95293423Sdelphij			size_t newv = *tp * 10 + (pch - digits);
96258945Sroberto
97258945Sroberto			if (saw_digit && *tp == 0)
98258945Sroberto				return (0);
99258945Sroberto			if (newv > 255)
100258945Sroberto				return (0);
101258945Sroberto			*tp = (unsigned char)newv;
102258945Sroberto			if (!saw_digit) {
103258945Sroberto				if (++octets > 4)
104258945Sroberto					return (0);
105258945Sroberto				saw_digit = 1;
106258945Sroberto			}
107258945Sroberto		} else if (ch == '.' && saw_digit) {
108258945Sroberto			if (octets == 4)
109258945Sroberto				return (0);
110258945Sroberto			*++tp = 0;
111258945Sroberto			saw_digit = 0;
112258945Sroberto		} else
113258945Sroberto			return (0);
114258945Sroberto	}
115258945Sroberto	if (octets < 4)
116258945Sroberto		return (0);
117258945Sroberto	memcpy(dst, tmp, NS_INADDRSZ);
118258945Sroberto	return (1);
119258945Sroberto}
120258945Sroberto
121258945Sroberto/*%
122258945Sroberto *	convert presentation level address to network order binary form.
123258945Sroberto * \return
124258945Sroberto *	1 if `src' is a valid [RFC1884 2.2] address, else 0.
125258945Sroberto * \note
126258945Sroberto *	(1) does not touch `dst' unless it's returning 1.
127258945Sroberto * \note
128258945Sroberto *	(2) :: in a full address is silently ignored.
129258945Sroberto * \author
130258945Sroberto *	inspired by Mark Andrews.
131258945Sroberto * \author
132258945Sroberto *	Paul Vixie, 1996.
133258945Sroberto */
134258945Srobertostatic int
135258945Srobertoinet_pton6(const char *src, unsigned char *dst) {
136258945Sroberto	static const char xdigits_l[] = "0123456789abcdef",
137258945Sroberto			  xdigits_u[] = "0123456789ABCDEF";
138258945Sroberto	unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
139258945Sroberto	const char *xdigits, *curtok;
140258945Sroberto	int ch, seen_xdigits;
141258945Sroberto	unsigned int val;
142258945Sroberto
143258945Sroberto	memset((tp = tmp), '\0', NS_IN6ADDRSZ);
144258945Sroberto	endp = tp + NS_IN6ADDRSZ;
145258945Sroberto	colonp = NULL;
146258945Sroberto	/* Leading :: requires some special handling. */
147258945Sroberto	if (*src == ':')
148258945Sroberto		if (*++src != ':')
149258945Sroberto			return (0);
150258945Sroberto	curtok = src;
151258945Sroberto	seen_xdigits = 0;
152258945Sroberto	val = 0;
153258945Sroberto	while ((ch = *src++) != '\0') {
154258945Sroberto		const char *pch;
155258945Sroberto
156258945Sroberto		if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
157258945Sroberto			pch = strchr((xdigits = xdigits_u), ch);
158258945Sroberto		if (pch != NULL) {
159258945Sroberto			val <<= 4;
160258945Sroberto			val |= (pch - xdigits);
161258945Sroberto			if (++seen_xdigits > 4)
162258945Sroberto				return (0);
163258945Sroberto			continue;
164258945Sroberto		}
165258945Sroberto		if (ch == ':') {
166258945Sroberto			curtok = src;
167258945Sroberto			if (!seen_xdigits) {
168258945Sroberto				if (colonp)
169258945Sroberto					return (0);
170258945Sroberto				colonp = tp;
171258945Sroberto				continue;
172258945Sroberto			}
173316068Sdelphij			if (NS_INT16SZ > endp - tp)
174258945Sroberto				return (0);
175258945Sroberto			*tp++ = (unsigned char) (val >> 8) & 0xff;
176258945Sroberto			*tp++ = (unsigned char) val & 0xff;
177258945Sroberto			seen_xdigits = 0;
178258945Sroberto			val = 0;
179258945Sroberto			continue;
180258945Sroberto		}
181316068Sdelphij		if (ch == '.' && (NS_INADDRSZ <= endp - tp) &&
182258945Sroberto		    inet_pton4(curtok, tp) > 0) {
183258945Sroberto			tp += NS_INADDRSZ;
184258945Sroberto			seen_xdigits = 0;
185258945Sroberto			break;	/* '\0' was seen by inet_pton4(). */
186258945Sroberto		}
187258945Sroberto		return (0);
188258945Sroberto	}
189258945Sroberto	if (seen_xdigits) {
190316068Sdelphij		if (NS_INT16SZ > endp - tp)
191258945Sroberto			return (0);
192258945Sroberto		*tp++ = (unsigned char) (val >> 8) & 0xff;
193258945Sroberto		*tp++ = (unsigned char) val & 0xff;
194258945Sroberto	}
195258945Sroberto	if (colonp != NULL) {
196258945Sroberto		/*
197258945Sroberto		 * Since some memmove()'s erroneously fail to handle
198258945Sroberto		 * overlapping regions, we'll do the shift by hand.
199258945Sroberto		 */
200293423Sdelphij		const size_t n = tp - colonp;
201258945Sroberto		int i;
202258945Sroberto
203258945Sroberto		if (tp == endp)
204258945Sroberto			return (0);
205293423Sdelphij		for (i = 1; (size_t)i <= n; i++) {
206258945Sroberto			endp[- i] = colonp[n - i];
207258945Sroberto			colonp[n - i] = 0;
208258945Sroberto		}
209258945Sroberto		tp = endp;
210258945Sroberto	}
211258945Sroberto	if (tp != endp)
212258945Sroberto		return (0);
213258945Sroberto	memcpy(dst, tmp, NS_IN6ADDRSZ);
214258945Sroberto	return (1);
215258945Sroberto}
216