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