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