1251875Speter/* Copyright (c) 1996 by Internet Software Consortium.
2251875Speter *
3251875Speter * Permission to use, copy, modify, and distribute this software for any
4251875Speter * purpose with or without fee is hereby granted, provided that the above
5251875Speter * copyright notice and this permission notice appear in all copies.
6251875Speter *
7251875Speter * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
8251875Speter * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
9251875Speter * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
10251875Speter * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
11251875Speter * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
12251875Speter * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
13251875Speter * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
14251875Speter * SOFTWARE.
15251875Speter */
16251875Speter
17251875Speter#include "apr_private.h"
18251875Speter#include "apr_arch_networkio.h"
19251875Speter
20251875Speter#if APR_HAVE_SYS_TYPES_H
21251875Speter#include <sys/types.h>
22251875Speter#endif
23251875Speter#if APR_HAVE_SYS_SOCKET_H
24251875Speter#include <sys/socket.h>
25251875Speter#endif
26251875Speter#if APR_HAVE_NETINET_IN_H
27251875Speter#include <netinet/in.h>
28251875Speter#endif
29251875Speter#if APR_HAVE_ARPA_INET_H
30251875Speter#include <arpa/inet.h>
31251875Speter#endif
32251875Speter#include <string.h>
33251875Speter#if APR_HAVE_ERRNO_H
34251875Speter#include <errno.h>
35251875Speter#endif
36251875Speter
37251875Speter#ifndef IN6ADDRSZ
38251875Speter#define IN6ADDRSZ   16
39251875Speter#endif
40251875Speter
41251875Speter#ifndef INT16SZ
42251875Speter#define INT16SZ sizeof(apr_int16_t)
43251875Speter#endif
44251875Speter
45251875Speter#ifndef INADDRSZ
46251875Speter#define INADDRSZ    4
47251875Speter#endif
48251875Speter
49251875Speter#ifndef __P
50251875Speter#define __P(x) x
51251875Speter#endif
52251875Speter
53251875Speter#if !defined(EAFNOSUPPORT) && defined(WSAEAFNOSUPPORT)
54251875Speter#define EAFNOSUPPORT WSAEAFNOSUPPORT
55251875Speter#endif
56251875Speter
57251875Speter/*
58251875Speter * WARNING: Don't even consider trying to compile this on a system where
59251875Speter * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
60251875Speter */
61251875Speter
62251875Speterstatic int	inet_pton4 __P((const char *src, unsigned char *dst));
63251875Speter#if APR_HAVE_IPV6
64251875Speterstatic int	inet_pton6 __P((const char *src, unsigned char *dst));
65251875Speter#endif
66251875Speter
67251875Speter/* int
68251875Speter * inet_pton(af, src, dst)
69251875Speter *	convert from presentation format (which usually means ASCII printable)
70251875Speter *	to network format (which is usually some kind of binary format).
71251875Speter * return:
72251875Speter *	1 if the address was valid for the specified address family
73251875Speter *	0 if the address wasn't valid (`dst' is untouched in this case)
74251875Speter *	-1 if some other error occurred (`dst' is untouched in this case, too)
75251875Speter * author:
76251875Speter *	Paul Vixie, 1996.
77251875Speter */
78251875Speterint
79251875Speterapr_inet_pton(int af, const char *src, void *dst)
80251875Speter{
81251875Speter	switch (af) {
82251875Speter	case AF_INET:
83251875Speter		return (inet_pton4(src, dst));
84251875Speter#if APR_HAVE_IPV6
85251875Speter	case AF_INET6:
86251875Speter		return (inet_pton6(src, dst));
87251875Speter#endif
88251875Speter	default:
89251875Speter		errno = EAFNOSUPPORT;
90251875Speter		return (-1);
91251875Speter	}
92251875Speter	/* NOTREACHED */
93251875Speter}
94251875Speter
95251875Speter/* int
96251875Speter * inet_pton4(src, dst)
97251875Speter *	like inet_aton() but without all the hexadecimal and shorthand.
98251875Speter * return:
99251875Speter *	1 if `src' is a valid dotted quad, else 0.
100251875Speter * notice:
101251875Speter *	does not touch `dst' unless it's returning 1.
102251875Speter * author:
103251875Speter *	Paul Vixie, 1996.
104251875Speter */
105251875Speterstatic int
106251875Speterinet_pton4(const char *src, unsigned char *dst)
107251875Speter{
108251875Speter    static const char digits[] = "0123456789";
109251875Speter    int saw_digit, octets, ch;
110251875Speter    unsigned char tmp[INADDRSZ], *tp;
111251875Speter
112251875Speter    saw_digit = 0;
113251875Speter    octets = 0;
114251875Speter    *(tp = tmp) = 0;
115251875Speter    while ((ch = *src++) != '\0') {
116251875Speter	const char *pch;
117251875Speter
118251875Speter	if ((pch = strchr(digits, ch)) != NULL) {
119251875Speter	    unsigned int new = *tp * 10 + (unsigned int)(pch - digits);
120251875Speter
121251875Speter	    if (new > 255)
122251875Speter		return (0);
123251875Speter	    *tp = new;
124251875Speter	    if (! saw_digit) {
125251875Speter		if (++octets > 4)
126251875Speter		    return (0);
127251875Speter		saw_digit = 1;
128251875Speter	    }
129251875Speter	} else if (ch == '.' && saw_digit) {
130251875Speter	    if (octets == 4)
131251875Speter		return (0);
132251875Speter	    *++tp = 0;
133251875Speter	    saw_digit = 0;
134251875Speter	} else
135251875Speter		return (0);
136251875Speter    }
137251875Speter    if (octets < 4)
138251875Speter	return (0);
139251875Speter
140251875Speter    memcpy(dst, tmp, INADDRSZ);
141251875Speter    return (1);
142251875Speter}
143251875Speter
144251875Speter#if APR_HAVE_IPV6
145251875Speter/* int
146251875Speter * inet_pton6(src, dst)
147251875Speter *	convert presentation level address to network order binary form.
148251875Speter * return:
149251875Speter *	1 if `src' is a valid [RFC1884 2.2] address, else 0.
150251875Speter * notice:
151251875Speter *	(1) does not touch `dst' unless it's returning 1.
152251875Speter *	(2) :: in a full address is silently ignored.
153251875Speter * credit:
154251875Speter *	inspired by Mark Andrews.
155251875Speter * author:
156251875Speter *	Paul Vixie, 1996.
157251875Speter */
158251875Speterstatic int
159251875Speterinet_pton6(const char *src, unsigned char *dst)
160251875Speter{
161251875Speter	static const char xdigits_l[] = "0123456789abcdef",
162251875Speter			  xdigits_u[] = "0123456789ABCDEF";
163251875Speter	unsigned char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
164251875Speter	const char *xdigits, *curtok;
165251875Speter	int ch, saw_xdigit;
166251875Speter	unsigned int val;
167251875Speter
168251875Speter	memset((tp = tmp), '\0', IN6ADDRSZ);
169251875Speter	endp = tp + IN6ADDRSZ;
170251875Speter	colonp = NULL;
171251875Speter	/* Leading :: requires some special handling. */
172251875Speter	if (*src == ':')
173251875Speter		if (*++src != ':')
174251875Speter			return (0);
175251875Speter	curtok = src;
176251875Speter	saw_xdigit = 0;
177251875Speter	val = 0;
178251875Speter	while ((ch = *src++) != '\0') {
179251875Speter		const char *pch;
180251875Speter
181251875Speter		if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
182251875Speter			pch = strchr((xdigits = xdigits_u), ch);
183251875Speter		if (pch != NULL) {
184251875Speter			val <<= 4;
185251875Speter			val |= (pch - xdigits);
186251875Speter			if (val > 0xffff)
187251875Speter				return (0);
188251875Speter			saw_xdigit = 1;
189251875Speter			continue;
190251875Speter		}
191251875Speter		if (ch == ':') {
192251875Speter			curtok = src;
193251875Speter			if (!saw_xdigit) {
194251875Speter				if (colonp)
195251875Speter					return (0);
196251875Speter				colonp = tp;
197251875Speter				continue;
198251875Speter			}
199251875Speter			if (tp + INT16SZ > endp)
200251875Speter				return (0);
201251875Speter			*tp++ = (unsigned char) (val >> 8) & 0xff;
202251875Speter			*tp++ = (unsigned char) val & 0xff;
203251875Speter			saw_xdigit = 0;
204251875Speter			val = 0;
205251875Speter			continue;
206251875Speter		}
207251875Speter		if (ch == '.' && ((tp + INADDRSZ) <= endp) &&
208251875Speter		    inet_pton4(curtok, tp) > 0) {
209251875Speter			tp += INADDRSZ;
210251875Speter			saw_xdigit = 0;
211251875Speter			break;	/* '\0' was seen by inet_pton4(). */
212251875Speter		}
213251875Speter		return (0);
214251875Speter	}
215251875Speter	if (saw_xdigit) {
216251875Speter		if (tp + INT16SZ > endp)
217251875Speter			return (0);
218251875Speter		*tp++ = (unsigned char) (val >> 8) & 0xff;
219251875Speter		*tp++ = (unsigned char) val & 0xff;
220251875Speter	}
221251875Speter	if (colonp != NULL) {
222251875Speter		/*
223251875Speter		 * Since some memmove()'s erroneously fail to handle
224251875Speter		 * overlapping regions, we'll do the shift by hand.
225251875Speter		 */
226251875Speter		const apr_ssize_t n = tp - colonp;
227251875Speter		apr_ssize_t i;
228251875Speter
229251875Speter		for (i = 1; i <= n; i++) {
230251875Speter			endp[- i] = colonp[n - i];
231251875Speter			colonp[n - i] = 0;
232251875Speter		}
233251875Speter		tp = endp;
234251875Speter	}
235251875Speter	if (tp != endp)
236251875Speter		return (0);
237251875Speter	memcpy(dst, tmp, IN6ADDRSZ);
238251875Speter	return (1);
239251875Speter}
240251875Speter#endif
241