xref: /netbsd-src/external/bsd/libbind/dist/inet/inet_pton.c (revision 5bbd2a12505d72a8177929a37b5cee489d0a1cfd)
1*5bbd2a12Schristos /*	$NetBSD: inet_pton.c,v 1.1.1.2 2012/09/09 16:07:50 christos Exp $	*/
2b5677b36Schristos 
3b5677b36Schristos /*
4b5677b36Schristos  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5b5677b36Schristos  * Copyright (c) 1996,1999 by Internet Software Consortium.
6b5677b36Schristos  *
7b5677b36Schristos  * Permission to use, copy, modify, and distribute this software for any
8b5677b36Schristos  * purpose with or without fee is hereby granted, provided that the above
9b5677b36Schristos  * copyright notice and this permission notice appear in all copies.
10b5677b36Schristos  *
11b5677b36Schristos  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
12b5677b36Schristos  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13b5677b36Schristos  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
14b5677b36Schristos  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15b5677b36Schristos  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16b5677b36Schristos  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17b5677b36Schristos  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18b5677b36Schristos  */
19b5677b36Schristos 
20b5677b36Schristos #if defined(LIBC_SCCS) && !defined(lint)
21b5677b36Schristos static const char rcsid[] = "Id: inet_pton.c,v 1.5 2005/07/28 06:51:47 marka Exp ";
22b5677b36Schristos #endif /* LIBC_SCCS and not lint */
23b5677b36Schristos 
24b5677b36Schristos #include "port_before.h"
25b5677b36Schristos #include <sys/param.h>
26b5677b36Schristos #include <sys/types.h>
27b5677b36Schristos #include <sys/socket.h>
28b5677b36Schristos #include <netinet/in.h>
29b5677b36Schristos #include <arpa/inet.h>
30b5677b36Schristos #include <arpa/nameser.h>
31b5677b36Schristos #include <string.h>
32b5677b36Schristos #include <errno.h>
33b5677b36Schristos #include "port_after.h"
34b5677b36Schristos 
35b5677b36Schristos /*%
36b5677b36Schristos  * WARNING: Don't even consider trying to compile this on a system where
37b5677b36Schristos  * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
38b5677b36Schristos  */
39b5677b36Schristos 
40b5677b36Schristos static int	inet_pton4 __P((const char *src, u_char *dst));
41b5677b36Schristos static int	inet_pton6 __P((const char *src, u_char *dst));
42b5677b36Schristos 
43b5677b36Schristos /* int
44b5677b36Schristos  * inet_pton(af, src, dst)
45b5677b36Schristos  *	convert from presentation format (which usually means ASCII printable)
46b5677b36Schristos  *	to network format (which is usually some kind of binary format).
47b5677b36Schristos  * return:
48b5677b36Schristos  *	1 if the address was valid for the specified address family
49b5677b36Schristos  *	0 if the address wasn't valid (`dst' is untouched in this case)
50b5677b36Schristos  *	-1 if some other error occurred (`dst' is untouched in this case, too)
51b5677b36Schristos  * author:
52b5677b36Schristos  *	Paul Vixie, 1996.
53b5677b36Schristos  */
54b5677b36Schristos int
inet_pton(af,src,dst)55b5677b36Schristos inet_pton(af, src, dst)
56b5677b36Schristos 	int af;
57b5677b36Schristos 	const char *src;
58b5677b36Schristos 	void *dst;
59b5677b36Schristos {
60b5677b36Schristos 	switch (af) {
61b5677b36Schristos 	case AF_INET:
62b5677b36Schristos 		return (inet_pton4(src, dst));
63b5677b36Schristos 	case AF_INET6:
64b5677b36Schristos 		return (inet_pton6(src, dst));
65b5677b36Schristos 	default:
66b5677b36Schristos 		errno = EAFNOSUPPORT;
67b5677b36Schristos 		return (-1);
68b5677b36Schristos 	}
69b5677b36Schristos 	/* NOTREACHED */
70b5677b36Schristos }
71b5677b36Schristos 
72b5677b36Schristos /* int
73b5677b36Schristos  * inet_pton4(src, dst)
74b5677b36Schristos  *	like inet_aton() but without all the hexadecimal and shorthand.
75b5677b36Schristos  * return:
76b5677b36Schristos  *	1 if `src' is a valid dotted quad, else 0.
77b5677b36Schristos  * notice:
78b5677b36Schristos  *	does not touch `dst' unless it's returning 1.
79b5677b36Schristos  * author:
80b5677b36Schristos  *	Paul Vixie, 1996.
81b5677b36Schristos  */
82b5677b36Schristos static int
inet_pton4(src,dst)83b5677b36Schristos inet_pton4(src, dst)
84b5677b36Schristos 	const char *src;
85b5677b36Schristos 	u_char *dst;
86b5677b36Schristos {
87b5677b36Schristos 	static const char digits[] = "0123456789";
88b5677b36Schristos 	int saw_digit, octets, ch;
89b5677b36Schristos 	u_char tmp[NS_INADDRSZ], *tp;
90b5677b36Schristos 
91b5677b36Schristos 	saw_digit = 0;
92b5677b36Schristos 	octets = 0;
93b5677b36Schristos 	*(tp = tmp) = 0;
94b5677b36Schristos 	while ((ch = *src++) != '\0') {
95b5677b36Schristos 		const char *pch;
96b5677b36Schristos 
97b5677b36Schristos 		if ((pch = strchr(digits, ch)) != NULL) {
98b5677b36Schristos 			u_int new = *tp * 10 + (pch - digits);
99b5677b36Schristos 
100b5677b36Schristos 			if (saw_digit && *tp == 0)
101b5677b36Schristos 				return (0);
102b5677b36Schristos 			if (new > 255)
103b5677b36Schristos 				return (0);
104b5677b36Schristos 			*tp = new;
105b5677b36Schristos 			if (!saw_digit) {
106b5677b36Schristos 				if (++octets > 4)
107b5677b36Schristos 					return (0);
108b5677b36Schristos 				saw_digit = 1;
109b5677b36Schristos 			}
110b5677b36Schristos 		} else if (ch == '.' && saw_digit) {
111b5677b36Schristos 			if (octets == 4)
112b5677b36Schristos 				return (0);
113b5677b36Schristos 			*++tp = 0;
114b5677b36Schristos 			saw_digit = 0;
115b5677b36Schristos 		} else
116b5677b36Schristos 			return (0);
117b5677b36Schristos 	}
118b5677b36Schristos 	if (octets < 4)
119b5677b36Schristos 		return (0);
120b5677b36Schristos 	memcpy(dst, tmp, NS_INADDRSZ);
121b5677b36Schristos 	return (1);
122b5677b36Schristos }
123b5677b36Schristos 
124b5677b36Schristos /* int
125b5677b36Schristos  * inet_pton6(src, dst)
126b5677b36Schristos  *	convert presentation level address to network order binary form.
127b5677b36Schristos  * return:
128b5677b36Schristos  *	1 if `src' is a valid [RFC1884 2.2] address, else 0.
129b5677b36Schristos  * notice:
130b5677b36Schristos  *	(1) does not touch `dst' unless it's returning 1.
131b5677b36Schristos  *	(2) :: in a full address is silently ignored.
132b5677b36Schristos  * credit:
133b5677b36Schristos  *	inspired by Mark Andrews.
134b5677b36Schristos  * author:
135b5677b36Schristos  *	Paul Vixie, 1996.
136b5677b36Schristos  */
137b5677b36Schristos static int
inet_pton6(src,dst)138b5677b36Schristos inet_pton6(src, dst)
139b5677b36Schristos 	const char *src;
140b5677b36Schristos 	u_char *dst;
141b5677b36Schristos {
142b5677b36Schristos 	static const char xdigits_l[] = "0123456789abcdef",
143b5677b36Schristos 			  xdigits_u[] = "0123456789ABCDEF";
144b5677b36Schristos 	u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
145b5677b36Schristos 	const char *xdigits, *curtok;
146b5677b36Schristos 	int ch, seen_xdigits;
147b5677b36Schristos 	u_int val;
148b5677b36Schristos 
149b5677b36Schristos 	memset((tp = tmp), '\0', NS_IN6ADDRSZ);
150b5677b36Schristos 	endp = tp + NS_IN6ADDRSZ;
151b5677b36Schristos 	colonp = NULL;
152b5677b36Schristos 	/* Leading :: requires some special handling. */
153b5677b36Schristos 	if (*src == ':')
154b5677b36Schristos 		if (*++src != ':')
155b5677b36Schristos 			return (0);
156b5677b36Schristos 	curtok = src;
157b5677b36Schristos 	seen_xdigits = 0;
158b5677b36Schristos 	val = 0;
159b5677b36Schristos 	while ((ch = *src++) != '\0') {
160b5677b36Schristos 		const char *pch;
161b5677b36Schristos 
162b5677b36Schristos 		if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
163b5677b36Schristos 			pch = strchr((xdigits = xdigits_u), ch);
164b5677b36Schristos 		if (pch != NULL) {
165b5677b36Schristos 			val <<= 4;
166b5677b36Schristos 			val |= (pch - xdigits);
167b5677b36Schristos 			if (++seen_xdigits > 4)
168b5677b36Schristos 				return (0);
169b5677b36Schristos 			continue;
170b5677b36Schristos 		}
171b5677b36Schristos 		if (ch == ':') {
172b5677b36Schristos 			curtok = src;
173b5677b36Schristos 			if (!seen_xdigits) {
174b5677b36Schristos 				if (colonp)
175b5677b36Schristos 					return (0);
176b5677b36Schristos 				colonp = tp;
177b5677b36Schristos 				continue;
178b5677b36Schristos 			} else if (*src == '\0') {
179b5677b36Schristos 				return (0);
180b5677b36Schristos 			}
181b5677b36Schristos 			if (tp + NS_INT16SZ > endp)
182b5677b36Schristos 				return (0);
183b5677b36Schristos 			*tp++ = (u_char) (val >> 8) & 0xff;
184b5677b36Schristos 			*tp++ = (u_char) val & 0xff;
185b5677b36Schristos 			seen_xdigits = 0;
186b5677b36Schristos 			val = 0;
187b5677b36Schristos 			continue;
188b5677b36Schristos 		}
189b5677b36Schristos 		if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
190b5677b36Schristos 		    inet_pton4(curtok, tp) > 0) {
191b5677b36Schristos 			tp += NS_INADDRSZ;
192b5677b36Schristos 			seen_xdigits = 0;
193b5677b36Schristos 			break;	/*%< '\\0' was seen by inet_pton4(). */
194b5677b36Schristos 		}
195b5677b36Schristos 		return (0);
196b5677b36Schristos 	}
197b5677b36Schristos 	if (seen_xdigits) {
198b5677b36Schristos 		if (tp + NS_INT16SZ > endp)
199b5677b36Schristos 			return (0);
200b5677b36Schristos 		*tp++ = (u_char) (val >> 8) & 0xff;
201b5677b36Schristos 		*tp++ = (u_char) val & 0xff;
202b5677b36Schristos 	}
203b5677b36Schristos 	if (colonp != NULL) {
204b5677b36Schristos 		/*
205b5677b36Schristos 		 * Since some memmove()'s erroneously fail to handle
206b5677b36Schristos 		 * overlapping regions, we'll do the shift by hand.
207b5677b36Schristos 		 */
208b5677b36Schristos 		const int n = tp - colonp;
209b5677b36Schristos 		int i;
210b5677b36Schristos 
211b5677b36Schristos 		if (tp == endp)
212b5677b36Schristos 			return (0);
213b5677b36Schristos 		for (i = 1; i <= n; i++) {
214b5677b36Schristos 			endp[- i] = colonp[n - i];
215b5677b36Schristos 			colonp[n - i] = 0;
216b5677b36Schristos 		}
217b5677b36Schristos 		tp = endp;
218b5677b36Schristos 	}
219b5677b36Schristos 	if (tp != endp)
220b5677b36Schristos 		return (0);
221b5677b36Schristos 	memcpy(dst, tmp, NS_IN6ADDRSZ);
222b5677b36Schristos 	return (1);
223b5677b36Schristos }
224b5677b36Schristos 
225b5677b36Schristos /*! \file */
226