1
2 /*
3 * Copyright (c) 2012 by Gilles Chehade <gilles@openbsd.org>
4 * Copyright (c) 1996,1999 by 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 DISCLAIMS
11 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
12 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
13 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
16 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
17 * SOFTWARE.
18 */
19
20 #include "ares_setup.h"
21
22 #ifdef HAVE_NETINET_IN_H
23 # include <netinet/in.h>
24 #endif
25 #ifdef HAVE_ARPA_INET_H
26 # include <arpa/inet.h>
27 #endif
28
29 #include "ares_nameser.h"
30
31 #include "ares.h"
32 #include "ares_ipv6.h"
33 #include "ares_nowarn.h"
34 #include "ares_inet_net_pton.h"
35
36
37 const struct ares_in6_addr ares_in6addr_any = { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } };
38
39 /*
40 * static int
41 * inet_net_pton_ipv4(src, dst, size)
42 * convert IPv4 network number from presentation to network format.
43 * accepts hex octets, hex strings, decimal octets, and /CIDR.
44 * "size" is in bytes and describes "dst".
45 * return:
46 * number of bits, either imputed classfully or specified with /CIDR,
47 * or -1 if some failure occurred (check errno). ENOENT means it was
48 * not an IPv4 network specification.
49 * note:
50 * network byte order assumed. this means 192.5.5.240/28 has
51 * 0b11110000 in its fourth octet.
52 * note:
53 * On Windows we store the error in the thread errno, not
54 * in the winsock error code. This is to avoid loosing the
55 * actual last winsock error. So use macro ERRNO to fetch the
56 * errno this funtion sets when returning (-1), not SOCKERRNO.
57 * author:
58 * Paul Vixie (ISC), June 1996
59 */
60 static int
ares_inet_net_pton_ipv4(const char * src,unsigned char * dst,size_t size)61 ares_inet_net_pton_ipv4(const char *src, unsigned char *dst, size_t size)
62 {
63 static const char xdigits[] = "0123456789abcdef";
64 static const char digits[] = "0123456789";
65 int n, ch, tmp = 0, dirty, bits;
66 const unsigned char *odst = dst;
67
68 ch = *src++;
69 if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
70 && ISASCII(src[1])
71 && ISXDIGIT(src[1])) {
72 /* Hexadecimal: Eat nybble string. */
73 if (!size)
74 goto emsgsize;
75 dirty = 0;
76 src++; /* skip x or X. */
77 while ((ch = *src++) != '\0' && ISASCII(ch) && ISXDIGIT(ch)) {
78 if (ISUPPER(ch))
79 ch = tolower(ch);
80 n = aresx_sztosi(strchr(xdigits, ch) - xdigits);
81 if (dirty == 0)
82 tmp = n;
83 else
84 tmp = (tmp << 4) | n;
85 if (++dirty == 2) {
86 if (!size--)
87 goto emsgsize;
88 *dst++ = (unsigned char) tmp;
89 dirty = 0;
90 }
91 }
92 if (dirty) { /* Odd trailing nybble? */
93 if (!size--)
94 goto emsgsize;
95 *dst++ = (unsigned char) (tmp << 4);
96 }
97 } else if (ISASCII(ch) && ISDIGIT(ch)) {
98 /* Decimal: eat dotted digit string. */
99 for (;;) {
100 tmp = 0;
101 do {
102 n = aresx_sztosi(strchr(digits, ch) - digits);
103 tmp *= 10;
104 tmp += n;
105 if (tmp > 255)
106 goto enoent;
107 } while ((ch = *src++) != '\0' &&
108 ISASCII(ch) && ISDIGIT(ch));
109 if (!size--)
110 goto emsgsize;
111 *dst++ = (unsigned char) tmp;
112 if (ch == '\0' || ch == '/')
113 break;
114 if (ch != '.')
115 goto enoent;
116 ch = *src++;
117 if (!ISASCII(ch) || !ISDIGIT(ch))
118 goto enoent;
119 }
120 } else
121 goto enoent;
122
123 bits = -1;
124 if (ch == '/' && ISASCII(src[0]) &&
125 ISDIGIT(src[0]) && dst > odst) {
126 /* CIDR width specifier. Nothing can follow it. */
127 ch = *src++; /* Skip over the /. */
128 bits = 0;
129 do {
130 n = aresx_sztosi(strchr(digits, ch) - digits);
131 bits *= 10;
132 bits += n;
133 if (bits > 32)
134 goto enoent;
135 } while ((ch = *src++) != '\0' && ISASCII(ch) && ISDIGIT(ch));
136 if (ch != '\0')
137 goto enoent;
138 }
139
140 /* Firey death and destruction unless we prefetched EOS. */
141 if (ch != '\0')
142 goto enoent;
143
144 /* If nothing was written to the destination, we found no address. */
145 if (dst == odst)
146 goto enoent; /* LCOV_EXCL_LINE: all valid paths above increment dst */
147 /* If no CIDR spec was given, infer width from net class. */
148 if (bits == -1) {
149 if (*odst >= 240) /* Class E */
150 bits = 32;
151 else if (*odst >= 224) /* Class D */
152 bits = 8;
153 else if (*odst >= 192) /* Class C */
154 bits = 24;
155 else if (*odst >= 128) /* Class B */
156 bits = 16;
157 else /* Class A */
158 bits = 8;
159 /* If imputed mask is narrower than specified octets, widen. */
160 if (bits < ((dst - odst) * 8))
161 bits = aresx_sztosi(dst - odst) * 8;
162 /*
163 * If there are no additional bits specified for a class D
164 * address adjust bits to 4.
165 */
166 if (bits == 8 && *odst == 224)
167 bits = 4;
168 }
169 /* Extend network to cover the actual mask. */
170 while (bits > ((dst - odst) * 8)) {
171 if (!size--)
172 goto emsgsize;
173 *dst++ = '\0';
174 }
175 return (bits);
176
177 enoent:
178 SET_ERRNO(ENOENT);
179 return (-1);
180
181 emsgsize:
182 SET_ERRNO(EMSGSIZE);
183 return (-1);
184 }
185
186 static int
getbits(const char * src,int * bitsp)187 getbits(const char *src, int *bitsp)
188 {
189 static const char digits[] = "0123456789";
190 int n;
191 int val;
192 char ch;
193
194 val = 0;
195 n = 0;
196 while ((ch = *src++) != '\0') {
197 const char *pch;
198
199 pch = strchr(digits, ch);
200 if (pch != NULL) {
201 if (n++ != 0 && val == 0) /* no leading zeros */
202 return (0);
203 val *= 10;
204 val += aresx_sztosi(pch - digits);
205 if (val > 128) /* range */
206 return (0);
207 continue;
208 }
209 return (0);
210 }
211 if (n == 0)
212 return (0);
213 *bitsp = val;
214 return (1);
215 }
216
217
218 static int
ares_inet_pton6(const char * src,unsigned char * dst)219 ares_inet_pton6(const char *src, unsigned char *dst)
220 {
221 static const char xdigits_l[] = "0123456789abcdef",
222 xdigits_u[] = "0123456789ABCDEF";
223 unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
224 const char *xdigits, *curtok;
225 int ch, saw_xdigit, count_xdigit;
226 unsigned int val;
227
228 memset((tp = tmp), '\0', NS_IN6ADDRSZ);
229 endp = tp + NS_IN6ADDRSZ;
230 colonp = NULL;
231 /* Leading :: requires some special handling. */
232 if (*src == ':')
233 if (*++src != ':')
234 goto enoent;
235 curtok = src;
236 saw_xdigit = count_xdigit = 0;
237 val = 0;
238 while ((ch = *src++) != '\0') {
239 const char *pch;
240
241 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
242 pch = strchr((xdigits = xdigits_u), ch);
243 if (pch != NULL) {
244 if (count_xdigit >= 4)
245 goto enoent;
246 val <<= 4;
247 val |= (unsigned int)(pch - xdigits);
248 if (val > 0xffff)
249 goto enoent;
250 saw_xdigit = 1;
251 count_xdigit++;
252 continue;
253 }
254 if (ch == ':') {
255 curtok = src;
256 if (!saw_xdigit) {
257 if (colonp)
258 goto enoent;
259 colonp = tp;
260 continue;
261 } else if (*src == '\0') {
262 goto enoent;
263 }
264 if (tp + NS_INT16SZ > endp)
265 goto enoent;
266 *tp++ = (unsigned char) (val >> 8) & 0xff;
267 *tp++ = (unsigned char) val & 0xff;
268 saw_xdigit = 0;
269 count_xdigit = 0;
270 val = 0;
271 continue;
272 }
273 if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
274 ares_inet_net_pton_ipv4(curtok, tp, NS_INADDRSZ) > 0) {
275 tp += NS_INADDRSZ;
276 saw_xdigit = 0;
277 break; /* '\0' was seen by inet_pton4(). */
278 }
279 goto enoent;
280 }
281 if (saw_xdigit) {
282 if (tp + NS_INT16SZ > endp)
283 goto enoent;
284 *tp++ = (unsigned char) (val >> 8) & 0xff;
285 *tp++ = (unsigned char) val & 0xff;
286 }
287 if (colonp != NULL) {
288 /*
289 * Since some memmove()'s erroneously fail to handle
290 * overlapping regions, we'll do the shift by hand.
291 */
292 const int n = (int)(tp - colonp);
293 int i;
294
295 if (tp == endp)
296 goto enoent;
297 for (i = 1; i <= n; i++) {
298 endp[- i] = colonp[n - i];
299 colonp[n - i] = 0;
300 }
301 tp = endp;
302 }
303 if (tp != endp)
304 goto enoent;
305
306 memcpy(dst, tmp, NS_IN6ADDRSZ);
307 return (1);
308
309 enoent:
310 SET_ERRNO(ENOENT);
311 return (-1);
312 }
313
314 static int
ares_inet_net_pton_ipv6(const char * src,unsigned char * dst,size_t size)315 ares_inet_net_pton_ipv6(const char *src, unsigned char *dst, size_t size)
316 {
317 struct ares_in6_addr in6;
318 int ret;
319 int bits;
320 size_t bytes;
321 char buf[INET6_ADDRSTRLEN + sizeof("/128")];
322 char *sep;
323
324 if (strlen(src) >= sizeof buf) {
325 SET_ERRNO(EMSGSIZE);
326 return (-1);
327 }
328 strncpy(buf, src, sizeof buf);
329
330 sep = strchr(buf, '/');
331 if (sep != NULL)
332 *sep++ = '\0';
333
334 ret = ares_inet_pton6(buf, (unsigned char *)&in6);
335 if (ret != 1)
336 return (-1);
337
338 if (sep == NULL)
339 bits = 128;
340 else {
341 if (!getbits(sep, &bits)) {
342 SET_ERRNO(ENOENT);
343 return (-1);
344 }
345 }
346
347 bytes = (bits + 7) / 8;
348 if (bytes > size) {
349 SET_ERRNO(EMSGSIZE);
350 return (-1);
351 }
352 memcpy(dst, &in6, bytes);
353 return (bits);
354 }
355
356 /*
357 * int
358 * inet_net_pton(af, src, dst, size)
359 * convert network number from presentation to network format.
360 * accepts hex octets, hex strings, decimal octets, and /CIDR.
361 * "size" is in bytes and describes "dst".
362 * return:
363 * number of bits, either imputed classfully or specified with /CIDR,
364 * or -1 if some failure occurred (check errno). ENOENT means it was
365 * not a valid network specification.
366 * note:
367 * On Windows we store the error in the thread errno, not
368 * in the winsock error code. This is to avoid loosing the
369 * actual last winsock error. So use macro ERRNO to fetch the
370 * errno this funtion sets when returning (-1), not SOCKERRNO.
371 * author:
372 * Paul Vixie (ISC), June 1996
373 */
374 int
ares_inet_net_pton(int af,const char * src,void * dst,size_t size)375 ares_inet_net_pton(int af, const char *src, void *dst, size_t size)
376 {
377 switch (af) {
378 case AF_INET:
379 return (ares_inet_net_pton_ipv4(src, dst, size));
380 case AF_INET6:
381 return (ares_inet_net_pton_ipv6(src, dst, size));
382 default:
383 SET_ERRNO(EAFNOSUPPORT);
384 return (-1);
385 }
386 }
387
ares_inet_pton(int af,const char * src,void * dst)388 int ares_inet_pton(int af, const char *src, void *dst)
389 {
390 int result;
391 size_t size;
392
393 if (af == AF_INET)
394 size = sizeof(struct in_addr);
395 else if (af == AF_INET6)
396 size = sizeof(struct ares_in6_addr);
397 else
398 {
399 SET_ERRNO(EAFNOSUPPORT);
400 return -1;
401 }
402 result = ares_inet_net_pton(af, src, dst, size);
403 if (result == -1 && ERRNO == ENOENT)
404 return 0;
405 return (result > -1 ? 1 : -1);
406 }
407