inet_pton.c revision 177685
1177633Sdfr/*
2177633Sdfr * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3177633Sdfr * Copyright (c) 1996,1999 by Internet Software Consortium.
4177633Sdfr *
5177633Sdfr * Permission to use, copy, modify, and distribute this software for any
6177633Sdfr * purpose with or without fee is hereby granted, provided that the above
7177633Sdfr * copyright notice and this permission notice appear in all copies.
8177633Sdfr *
9177633Sdfr * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10177633Sdfr * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11177633Sdfr * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
12177633Sdfr * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13177633Sdfr * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14177633Sdfr * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15177633Sdfr * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16177633Sdfr */
17177633Sdfr
18177633Sdfr#if defined(LIBC_SCCS) && !defined(lint)
19177633Sdfrstatic const char rcsid[] = "$Id: inet_pton.c,v 1.3.18.2 2005/07/28 07:38:07 marka Exp $";
20177633Sdfr#endif /* LIBC_SCCS and not lint */
21177633Sdfr#include <sys/cdefs.h>
22177633Sdfr__FBSDID("$FreeBSD: head/sys/rpc/inet_pton.c 177685 2008-03-28 09:50:32Z dfr $");
23177633Sdfr
24177633Sdfr#include <sys/param.h>
25177633Sdfr#include <sys/types.h>
26177633Sdfr#include <sys/socket.h>
27177633Sdfr#include <sys/systm.h>
28177633Sdfr
29177633Sdfr#include <rpc/types.h>
30177685Sdfr#include <rpc/rpc_com.h>
31177633Sdfr
32177685Sdfr#if __FreeBSD_version < 700000
33177685Sdfr#define strchr index
34177685Sdfr#endif
35177685Sdfr
36177633Sdfr/*%
37177633Sdfr * WARNING: Don't even consider trying to compile this on a system where
38177633Sdfr * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
39177633Sdfr */
40177633Sdfr
41177633Sdfrstatic int	inet_pton4(const char *src, u_char *dst);
42177633Sdfrstatic int	inet_pton6(const char *src, u_char *dst);
43177633Sdfr
44177633Sdfr/* int
45177633Sdfr * inet_pton(af, src, dst)
46177633Sdfr *	convert from presentation format (which usually means ASCII printable)
47177633Sdfr *	to network format (which is usually some kind of binary format).
48177633Sdfr * return:
49177633Sdfr *	1 if the address was valid for the specified address family
50177633Sdfr *	0 if the address wasn't valid (`dst' is untouched in this case)
51177633Sdfr *	-1 if some other error occurred (`dst' is untouched in this case, too)
52177633Sdfr * author:
53177633Sdfr *	Paul Vixie, 1996.
54177633Sdfr */
55177633Sdfrint
56177633Sdfr__rpc_inet_pton(int af, const char * __restrict src, void * __restrict dst)
57177633Sdfr{
58177633Sdfr	switch (af) {
59177633Sdfr	case AF_INET:
60177633Sdfr		return (inet_pton4(src, dst));
61177633Sdfr	case AF_INET6:
62177633Sdfr		return (inet_pton6(src, dst));
63177633Sdfr	default:
64177633Sdfr		return (-1);
65177633Sdfr	}
66177633Sdfr	/* NOTREACHED */
67177633Sdfr}
68177633Sdfr
69177633Sdfr/* int
70177633Sdfr * inet_pton4(src, dst)
71177633Sdfr *	like inet_aton() but without all the hexadecimal and shorthand.
72177633Sdfr * return:
73177633Sdfr *	1 if `src' is a valid dotted quad, else 0.
74177633Sdfr * notice:
75177633Sdfr *	does not touch `dst' unless it's returning 1.
76177633Sdfr * author:
77177633Sdfr *	Paul Vixie, 1996.
78177633Sdfr */
79177633Sdfrstatic int
80177633Sdfrinet_pton4(const char *src, u_char *dst)
81177633Sdfr{
82177633Sdfr	static const char digits[] = "0123456789";
83177633Sdfr	int saw_digit, octets, ch;
84177633Sdfr#define NS_INADDRSZ	4
85177633Sdfr	u_char tmp[NS_INADDRSZ], *tp;
86177633Sdfr
87177633Sdfr	saw_digit = 0;
88177633Sdfr	octets = 0;
89177633Sdfr	*(tp = tmp) = 0;
90177633Sdfr	while ((ch = *src++) != '\0') {
91177633Sdfr		const char *pch;
92177633Sdfr
93177633Sdfr		if ((pch = strchr(digits, ch)) != NULL) {
94177633Sdfr			u_int new = *tp * 10 + (pch - digits);
95177633Sdfr
96177633Sdfr			if (saw_digit && *tp == 0)
97177633Sdfr				return (0);
98177633Sdfr			if (new > 255)
99177633Sdfr				return (0);
100177633Sdfr			*tp = new;
101177633Sdfr			if (!saw_digit) {
102177633Sdfr				if (++octets > 4)
103177633Sdfr					return (0);
104177633Sdfr				saw_digit = 1;
105177633Sdfr			}
106177633Sdfr		} else if (ch == '.' && saw_digit) {
107177633Sdfr			if (octets == 4)
108177633Sdfr				return (0);
109177633Sdfr			*++tp = 0;
110177633Sdfr			saw_digit = 0;
111177633Sdfr		} else
112177633Sdfr			return (0);
113177633Sdfr	}
114177633Sdfr	if (octets < 4)
115177633Sdfr		return (0);
116177633Sdfr	memcpy(dst, tmp, NS_INADDRSZ);
117177633Sdfr	return (1);
118177633Sdfr}
119177633Sdfr
120177633Sdfr/* int
121177633Sdfr * inet_pton6(src, dst)
122177633Sdfr *	convert presentation level address to network order binary form.
123177633Sdfr * return:
124177633Sdfr *	1 if `src' is a valid [RFC1884 2.2] address, else 0.
125177633Sdfr * notice:
126177633Sdfr *	(1) does not touch `dst' unless it's returning 1.
127177633Sdfr *	(2) :: in a full address is silently ignored.
128177633Sdfr * credit:
129177633Sdfr *	inspired by Mark Andrews.
130177633Sdfr * author:
131177633Sdfr *	Paul Vixie, 1996.
132177633Sdfr */
133177633Sdfrstatic int
134177633Sdfrinet_pton6(const char *src, u_char *dst)
135177633Sdfr{
136177633Sdfr	static const char xdigits_l[] = "0123456789abcdef",
137177633Sdfr			  xdigits_u[] = "0123456789ABCDEF";
138177633Sdfr#define NS_IN6ADDRSZ	16
139177633Sdfr#define NS_INT16SZ	2
140177633Sdfr	u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
141177633Sdfr	const char *xdigits, *curtok;
142177633Sdfr	int ch, seen_xdigits;
143177633Sdfr	u_int val;
144177633Sdfr
145177633Sdfr	memset((tp = tmp), '\0', NS_IN6ADDRSZ);
146177633Sdfr	endp = tp + NS_IN6ADDRSZ;
147177633Sdfr	colonp = NULL;
148177633Sdfr	/* Leading :: requires some special handling. */
149177633Sdfr	if (*src == ':')
150177633Sdfr		if (*++src != ':')
151177633Sdfr			return (0);
152177633Sdfr	curtok = src;
153177633Sdfr	seen_xdigits = 0;
154177633Sdfr	val = 0;
155177633Sdfr	while ((ch = *src++) != '\0') {
156177633Sdfr		const char *pch;
157177633Sdfr
158177633Sdfr		if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
159177633Sdfr			pch = strchr((xdigits = xdigits_u), ch);
160177633Sdfr		if (pch != NULL) {
161177633Sdfr			val <<= 4;
162177633Sdfr			val |= (pch - xdigits);
163177633Sdfr			if (++seen_xdigits > 4)
164177633Sdfr				return (0);
165177633Sdfr			continue;
166177633Sdfr		}
167177633Sdfr		if (ch == ':') {
168177633Sdfr			curtok = src;
169177633Sdfr			if (!seen_xdigits) {
170177633Sdfr				if (colonp)
171177633Sdfr					return (0);
172177633Sdfr				colonp = tp;
173177633Sdfr				continue;
174177633Sdfr			} else if (*src == '\0') {
175177633Sdfr				return (0);
176177633Sdfr			}
177177633Sdfr			if (tp + NS_INT16SZ > endp)
178177633Sdfr				return (0);
179177633Sdfr			*tp++ = (u_char) (val >> 8) & 0xff;
180177633Sdfr			*tp++ = (u_char) val & 0xff;
181177633Sdfr			seen_xdigits = 0;
182177633Sdfr			val = 0;
183177633Sdfr			continue;
184177633Sdfr		}
185177633Sdfr		if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
186177633Sdfr		    inet_pton4(curtok, tp) > 0) {
187177633Sdfr			tp += NS_INADDRSZ;
188177633Sdfr			seen_xdigits = 0;
189177633Sdfr			break;	/*%< '\\0' was seen by inet_pton4(). */
190177633Sdfr		}
191177633Sdfr		return (0);
192177633Sdfr	}
193177633Sdfr	if (seen_xdigits) {
194177633Sdfr		if (tp + NS_INT16SZ > endp)
195177633Sdfr			return (0);
196177633Sdfr		*tp++ = (u_char) (val >> 8) & 0xff;
197177633Sdfr		*tp++ = (u_char) val & 0xff;
198177633Sdfr	}
199177633Sdfr	if (colonp != NULL) {
200177633Sdfr		/*
201177633Sdfr		 * Since some memmove()'s erroneously fail to handle
202177633Sdfr		 * overlapping regions, we'll do the shift by hand.
203177633Sdfr		 */
204177633Sdfr		const int n = tp - colonp;
205177633Sdfr		int i;
206177633Sdfr
207177633Sdfr		if (tp == endp)
208177633Sdfr			return (0);
209177633Sdfr		for (i = 1; i <= n; i++) {
210177633Sdfr			endp[- i] = colonp[n - i];
211177633Sdfr			colonp[n - i] = 0;
212177633Sdfr		}
213177633Sdfr		tp = endp;
214177633Sdfr	}
215177633Sdfr	if (tp != endp)
216177633Sdfr		return (0);
217177633Sdfr	memcpy(dst, tmp, NS_IN6ADDRSZ);
218177633Sdfr	return (1);
219177633Sdfr}
220177633Sdfr
221177633Sdfr/*
222177633Sdfr * Weak aliases for applications that use certain private entry points,
223177633Sdfr * and fail to include <arpa/inet.h>.
224177633Sdfr */
225177633Sdfr#undef inet_pton
226177633Sdfr__weak_reference(__inet_pton, inet_pton);
227177633Sdfr
228177633Sdfr/*! \file */
229