1238106Sdes/*	$KAME: inet_pton.c,v 1.5 2001/08/20 02:32:40 itojun Exp $	*/
2238106Sdes
3238106Sdes/* Copyright (c) 1996 by Internet Software Consortium.
4238106Sdes *
5238106Sdes * Permission to use, copy, modify, and distribute this software for any
6238106Sdes * purpose with or without fee is hereby granted, provided that the above
7238106Sdes * copyright notice and this permission notice appear in all copies.
8238106Sdes *
9238106Sdes * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
10238106Sdes * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
11238106Sdes * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
12238106Sdes * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13238106Sdes * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14238106Sdes * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
15238106Sdes * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
16238106Sdes * SOFTWARE.
17238106Sdes */
18238106Sdes
19238106Sdes#include <config.h>
20238106Sdes
21238106Sdes#include <string.h>
22238106Sdes#include <stdio.h>
23238106Sdes#include <errno.h>
24238106Sdes
25238106Sdes/*
26238106Sdes * WARNING: Don't even consider trying to compile this on a system where
27238106Sdes * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
28238106Sdes */
29238106Sdes
30238106Sdesstatic int	inet_pton4 (const char *src, uint8_t *dst);
31238106Sdesstatic int	inet_pton6 (const char *src, uint8_t *dst);
32238106Sdes
33238106Sdes/*
34238106Sdes *
35238106Sdes * The definitions we might miss.
36238106Sdes *
37238106Sdes */
38238106Sdes#ifndef NS_INT16SZ
39238106Sdes#define	NS_INT16SZ	2
40238106Sdes#endif
41238106Sdes
42238106Sdes#ifndef NS_IN6ADDRSZ
43238106Sdes#define NS_IN6ADDRSZ 16
44238106Sdes#endif
45238106Sdes
46238106Sdes#ifndef NS_INADDRSZ
47238106Sdes#define NS_INADDRSZ 4
48238106Sdes#endif
49238106Sdes
50238106Sdes/* int
51238106Sdes * inet_pton(af, src, dst)
52238106Sdes *	convert from presentation format (which usually means ASCII printable)
53238106Sdes *	to network format (which is usually some kind of binary format).
54238106Sdes * return:
55238106Sdes *	1 if the address was valid for the specified address family
56238106Sdes *	0 if the address wasn't valid (`dst' is untouched in this case)
57238106Sdes *	-1 if some other error occurred (`dst' is untouched in this case, too)
58238106Sdes * author:
59238106Sdes *	Paul Vixie, 1996.
60238106Sdes */
61238106Sdesint
62238106Sdesinet_pton(af, src, dst)
63238106Sdes	int af;
64238106Sdes	const char *src;
65238106Sdes	void *dst;
66238106Sdes{
67238106Sdes	switch (af) {
68238106Sdes	case AF_INET:
69238106Sdes		return (inet_pton4(src, dst));
70238106Sdes	case AF_INET6:
71238106Sdes		return (inet_pton6(src, dst));
72238106Sdes	default:
73238106Sdes#ifdef EAFNOSUPPORT
74238106Sdes		errno = EAFNOSUPPORT;
75238106Sdes#else
76238106Sdes		errno = ENOSYS;
77238106Sdes#endif
78238106Sdes		return (-1);
79238106Sdes	}
80238106Sdes	/* NOTREACHED */
81238106Sdes}
82238106Sdes
83238106Sdes/* int
84238106Sdes * inet_pton4(src, dst)
85238106Sdes *	like inet_aton() but without all the hexadecimal and shorthand.
86238106Sdes * return:
87238106Sdes *	1 if `src' is a valid dotted quad, else 0.
88238106Sdes * notice:
89238106Sdes *	does not touch `dst' unless it's returning 1.
90238106Sdes * author:
91238106Sdes *	Paul Vixie, 1996.
92238106Sdes */
93238106Sdesstatic int
94238106Sdesinet_pton4(src, dst)
95238106Sdes	const char *src;
96238106Sdes	uint8_t *dst;
97238106Sdes{
98238106Sdes	static const char digits[] = "0123456789";
99238106Sdes	int saw_digit, octets, ch;
100238106Sdes	uint8_t tmp[NS_INADDRSZ], *tp;
101238106Sdes
102238106Sdes	saw_digit = 0;
103238106Sdes	octets = 0;
104238106Sdes	*(tp = tmp) = 0;
105238106Sdes	while ((ch = *src++) != '\0') {
106238106Sdes		const char *pch;
107238106Sdes
108238106Sdes		if ((pch = strchr(digits, ch)) != NULL) {
109238106Sdes			uint32_t new = *tp * 10 + (pch - digits);
110238106Sdes
111238106Sdes			if (new > 255)
112238106Sdes				return (0);
113238106Sdes			*tp = new;
114238106Sdes			if (! saw_digit) {
115238106Sdes				if (++octets > 4)
116238106Sdes					return (0);
117238106Sdes				saw_digit = 1;
118238106Sdes			}
119238106Sdes		} else if (ch == '.' && saw_digit) {
120238106Sdes			if (octets == 4)
121238106Sdes				return (0);
122238106Sdes			*++tp = 0;
123238106Sdes			saw_digit = 0;
124238106Sdes		} else
125238106Sdes			return (0);
126238106Sdes	}
127238106Sdes	if (octets < 4)
128238106Sdes		return (0);
129238106Sdes
130238106Sdes	memcpy(dst, tmp, NS_INADDRSZ);
131238106Sdes	return (1);
132238106Sdes}
133238106Sdes
134238106Sdes/* int
135238106Sdes * inet_pton6(src, dst)
136238106Sdes *	convert presentation level address to network order binary form.
137238106Sdes * return:
138238106Sdes *	1 if `src' is a valid [RFC1884 2.2] address, else 0.
139238106Sdes * notice:
140238106Sdes *	(1) does not touch `dst' unless it's returning 1.
141238106Sdes *	(2) :: in a full address is silently ignored.
142238106Sdes * credit:
143238106Sdes *	inspired by Mark Andrews.
144238106Sdes * author:
145238106Sdes *	Paul Vixie, 1996.
146238106Sdes */
147238106Sdesstatic int
148238106Sdesinet_pton6(src, dst)
149238106Sdes	const char *src;
150238106Sdes	uint8_t *dst;
151238106Sdes{
152238106Sdes	static const char xdigits_l[] = "0123456789abcdef",
153238106Sdes			  xdigits_u[] = "0123456789ABCDEF";
154238106Sdes	uint8_t tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
155238106Sdes	const char *xdigits, *curtok;
156238106Sdes	int ch, saw_xdigit;
157238106Sdes	uint32_t val;
158238106Sdes
159238106Sdes	memset((tp = tmp), '\0', NS_IN6ADDRSZ);
160238106Sdes	endp = tp + NS_IN6ADDRSZ;
161238106Sdes	colonp = NULL;
162238106Sdes	/* Leading :: requires some special handling. */
163238106Sdes	if (*src == ':')
164238106Sdes		if (*++src != ':')
165238106Sdes			return (0);
166238106Sdes	curtok = src;
167238106Sdes	saw_xdigit = 0;
168238106Sdes	val = 0;
169238106Sdes	while ((ch = *src++) != '\0') {
170238106Sdes		const char *pch;
171238106Sdes
172238106Sdes		if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
173238106Sdes			pch = strchr((xdigits = xdigits_u), ch);
174238106Sdes		if (pch != NULL) {
175238106Sdes			val <<= 4;
176238106Sdes			val |= (pch - xdigits);
177238106Sdes			if (val > 0xffff)
178238106Sdes				return (0);
179238106Sdes			saw_xdigit = 1;
180238106Sdes			continue;
181238106Sdes		}
182238106Sdes		if (ch == ':') {
183238106Sdes			curtok = src;
184238106Sdes			if (!saw_xdigit) {
185238106Sdes				if (colonp)
186238106Sdes					return (0);
187238106Sdes				colonp = tp;
188238106Sdes				continue;
189238106Sdes			}
190238106Sdes			if (tp + NS_INT16SZ > endp)
191238106Sdes				return (0);
192238106Sdes			*tp++ = (uint8_t) (val >> 8) & 0xff;
193238106Sdes			*tp++ = (uint8_t) val & 0xff;
194238106Sdes			saw_xdigit = 0;
195238106Sdes			val = 0;
196238106Sdes			continue;
197238106Sdes		}
198238106Sdes		if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
199238106Sdes		    inet_pton4(curtok, tp) > 0) {
200238106Sdes			tp += NS_INADDRSZ;
201238106Sdes			saw_xdigit = 0;
202238106Sdes			break;	/* '\0' was seen by inet_pton4(). */
203238106Sdes		}
204238106Sdes		return (0);
205238106Sdes	}
206238106Sdes	if (saw_xdigit) {
207238106Sdes		if (tp + NS_INT16SZ > endp)
208238106Sdes			return (0);
209238106Sdes		*tp++ = (uint8_t) (val >> 8) & 0xff;
210238106Sdes		*tp++ = (uint8_t) val & 0xff;
211238106Sdes	}
212238106Sdes	if (colonp != NULL) {
213238106Sdes		/*
214238106Sdes		 * Since some memmove()'s erroneously fail to handle
215238106Sdes		 * overlapping regions, we'll do the shift by hand.
216238106Sdes		 */
217238106Sdes		const int n = tp - colonp;
218238106Sdes		int i;
219238106Sdes
220238106Sdes		for (i = 1; i <= n; i++) {
221238106Sdes			endp[- i] = colonp[n - i];
222238106Sdes			colonp[n - i] = 0;
223238106Sdes		}
224238106Sdes		tp = endp;
225238106Sdes	}
226238106Sdes	if (tp != endp)
227238106Sdes		return (0);
228238106Sdes	memcpy(dst, tmp, NS_IN6ADDRSZ);
229238106Sdes	return (1);
230238106Sdes}
231