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