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