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