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