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