1 /* ==========================================================================
2 * dns.c - Recursive, Reentrant DNS Resolver.
3 * --------------------------------------------------------------------------
4 * Copyright (c) 2008, 2009, 2010, 2012-2016 William Ahern
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to permit
11 * persons to whom the Software is furnished to do so, subject to the
12 * following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
20 * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
21 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
23 * USE OR OTHER DEALINGS IN THE SOFTWARE.
24 * ==========================================================================
25 */
26 #if !defined(__FreeBSD__) && !defined(__sun) && !defined(__DragonFly__)
27 #ifndef _XOPEN_SOURCE
28 #define _XOPEN_SOURCE 600
29 #endif
30
31 #undef _DEFAULT_SOURCE
32 #define _DEFAULT_SOURCE
33
34 #undef _BSD_SOURCE
35 #define _BSD_SOURCE
36
37 #undef _DARWIN_C_SOURCE
38 #define _DARWIN_C_SOURCE
39
40 #undef _NETBSD_SOURCE
41 #define _NETBSD_SOURCE
42 #endif
43
44 #include <limits.h> /* INT_MAX */
45 #include <stddef.h> /* offsetof() */
46 #ifdef _WIN32
47 #define uint32_t unsigned int
48 #else
49 #include <stdint.h> /* uint32_t */
50 #endif
51 #include <stdlib.h> /* malloc(3) realloc(3) free(3) rand(3) random(3) arc4random(3) */
52 #include <stdio.h> /* FILE fopen(3) fclose(3) getc(3) rewind(3) */
53 #include <string.h> /* memcpy(3) strlen(3) memmove(3) memchr(3) memcmp(3) strchr(3) strsep(3) strcspn(3) */
54 #include <strings.h> /* strcasecmp(3) strncasecmp(3) */
55 #include <ctype.h> /* isspace(3) isdigit(3) */
56 #include <time.h> /* time_t time(2) difftime(3) */
57 #include <signal.h> /* SIGPIPE sigemptyset(3) sigaddset(3) sigpending(2) sigprocmask(2) pthread_sigmask(3) sigtimedwait(2) */
58 #include <errno.h> /* errno EINVAL ENOENT */
59 #undef NDEBUG
60 #include <assert.h> /* assert(3) */
61
62 #if _WIN32
63 #ifndef FD_SETSIZE
64 #define FD_SETSIZE 256
65 #endif
66 #include <winsock2.h>
67 #include <ws2tcpip.h>
68 #else
69 #include <sys/types.h> /* FD_SETSIZE socklen_t */
70 #include <sys/select.h> /* FD_ZERO FD_SET fd_set select(2) */
71 #include <sys/socket.h> /* AF_INET AF_INET6 AF_UNIX struct sockaddr struct sockaddr_in struct sockaddr_in6 socket(2) */
72 #if defined(AF_UNIX)
73 #include <sys/un.h> /* struct sockaddr_un */
74 #endif
75 #include <fcntl.h> /* F_SETFD F_GETFL F_SETFL O_NONBLOCK fcntl(2) */
76 #include <unistd.h> /* _POSIX_THREADS gethostname(3) close(2) */
77 #include <poll.h> /* POLLIN POLLOUT */
78 #include <netinet/in.h> /* struct sockaddr_in struct sockaddr_in6 */
79 #include <arpa/inet.h> /* inet_pton(3) inet_ntop(3) htons(3) ntohs(3) */
80 #include <netdb.h> /* struct addrinfo */
81 #endif
82
83 #include "dns.h"
84
85
86 /*
87 * C O M P I L E R V E R S I O N & F E A T U R E D E T E C T I O N
88 *
89 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
90
91 #define DNS_GNUC_2VER(M, m, p) (((M) * 10000) + ((m) * 100) + (p))
92 #define DNS_GNUC_PREREQ(M, m, p) (__GNUC__ > 0 && DNS_GNUC_2VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) >= DNS_GNUC_2VER((M), (m), (p)))
93
94 #define DNS_MSC_2VER(M, m, p) ((((M) + 6) * 10000000) + ((m) * 1000000) + (p))
95 #define DNS_MSC_PREREQ(M, m, p) (_MSC_VER_FULL > 0 && _MSC_VER_FULL >= DNS_MSC_2VER((M), (m), (p)))
96
97 #define DNS_SUNPRO_PREREQ(M, m, p) (__SUNPRO_C > 0 && __SUNPRO_C >= 0x ## M ## m ## p)
98
99 #if defined __has_builtin
100 #define dns_has_builtin(x) __has_builtin(x)
101 #else
102 #define dns_has_builtin(x) 0
103 #endif
104
105 #if defined __has_extension
106 #define dns_has_extension(x) __has_extension(x)
107 #else
108 #define dns_has_extension(x) 0
109 #endif
110
111 #ifndef HAVE___ASSUME
112 #define HAVE___ASSUME DNS_MSC_PREREQ(8,0,0)
113 #endif
114
115 #ifndef HAVE___BUILTIN_TYPES_COMPATIBLE_P
116 #define HAVE___BUILTIN_TYPES_COMPATIBLE_P (DNS_GNUC_PREREQ(3,1,1) || __clang__)
117 #endif
118
119 #ifndef HAVE___BUILTIN_UNREACHABLE
120 #define HAVE___BUILTIN_UNREACHABLE (DNS_GNUC_PREREQ(4,5,0) || dns_has_builtin(__builtin_unreachable))
121 #endif
122
123 #ifndef HAVE_PRAGMA_MESSAGE
124 #define HAVE_PRAGMA_MESSAGE (DNS_GNUC_PREREQ(4,4,0) || __clang__ || _MSC_VER)
125 #endif
126
127
128 /*
129 * C O M P I L E R A N N O T A T I O N S
130 *
131 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
132
133 #if __GNUC__
134 #define DNS_NOTUSED __attribute__((unused))
135 #define DNS_NORETURN __attribute__((noreturn))
136 #else
137 #define DNS_NOTUSED
138 #define DNS_NORETURN
139 #endif
140
141 #if __clang__
142 #pragma clang diagnostic push
143 #pragma clang diagnostic ignored "-Wunused-parameter"
144 #pragma clang diagnostic ignored "-Wmissing-field-initializers"
145 #elif DNS_GNUC_PREREQ(4,6,0)
146 #pragma GCC diagnostic push
147 #pragma GCC diagnostic ignored "-Wunused-parameter"
148 #pragma GCC diagnostic ignored "-Wmissing-field-initializers"
149 #endif
150
151
152 /*
153 * S T A N D A R D M A C R O S
154 *
155 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
156
157 #if HAVE___BUILTIN_TYPES_COMPATIBLE_P
158 #define dns_same_type(a, b, def) __builtin_types_compatible_p(__typeof__ (a), __typeof__ (b))
159 #else
160 #define dns_same_type(a, b, def) (def)
161 #endif
162 #define dns_isarray(a) (!dns_same_type((a), (&(a)[0]), 0))
163 /* NB: "_" field silences Sun Studio "zero-sized struct/union" error diagnostic */
164 #define dns_inline_assert(cond) ((void)(sizeof (struct { int:-!(cond); int _; })))
165
166 #if HAVE___ASSUME
167 #define dns_assume(cond) __assume(cond)
168 #elif HAVE___BUILTIN_UNREACHABLE
169 #define dns_assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0)
170 #else
171 #define dns_assume(cond) do { (void)(cond); } while (0)
172 #endif
173
174 #ifndef lengthof
175 #define lengthof(a) (dns_inline_assert(dns_isarray(a)), (sizeof (a) / sizeof (a)[0]))
176 #endif
177
178 #ifndef endof
179 #define endof(a) (dns_inline_assert(dns_isarray(a)), &(a)[lengthof((a))])
180 #endif
181
182
183 /*
184 * M I S C E L L A N E O U S C O M P A T
185 *
186 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
187
188 #if _WIN32 || _WIN64
189 #define PRIuZ "Iu"
190 #else
191 #define PRIuZ "zu"
192 #endif
193
194 #ifndef DNS_THREAD_SAFE
195 #if (defined _REENTRANT || defined _THREAD_SAFE) && _POSIX_THREADS > 0
196 #define DNS_THREAD_SAFE 1
197 #else
198 #define DNS_THREAD_SAFE 0
199 #endif
200 #endif
201
202 #ifndef HAVE__STATIC_ASSERT
203 #define HAVE__STATIC_ASSERT \
204 (dns_has_extension(c_static_assert) || DNS_GNUC_PREREQ(4,6,0) || \
205 __C11FEATURES__ || __STDC_VERSION__ >= 201112L)
206 #endif
207
208 #ifndef HAVE_STATIC_ASSERT
209 #if (defined static_assert) && \
210 (!DNS_GNUC_PREREQ(0,0,0) || DNS_GNUC_PREREQ(4,6,0)) /* glibc doesn't check GCC version */
211 #define HAVE_STATIC_ASSERT 1
212 #else
213 #define HAVE_STATIC_ASSERT 0
214 #endif
215 #endif
216
217 #if HAVE_STATIC_ASSERT
218 #define dns_static_assert(cond, msg) static_assert(cond, msg)
219 #elif HAVE__STATIC_ASSERT
220 #define dns_static_assert(cond, msg) _Static_assert(cond, msg)
221 #else
222 #define dns_static_assert(cond, msg) extern char DNS_PP_XPASTE(dns_assert_, __LINE__)[sizeof (int[1 - 2*!(cond)])]
223 #endif
224
225
226 /*
227 * D E B U G M A C R O S
228 *
229 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
230
dns_debug_p(void)231 int *dns_debug_p(void) {
232 static int debug;
233
234 return &debug;
235 } /* dns_debug_p() */
236
237 #if DNS_DEBUG
238
239 #undef DNS_DEBUG
240 #define DNS_DEBUG dns_debug
241
242 #define DNS_SAY_(fmt, ...) \
243 do { if (DNS_DEBUG > 0) fprintf(stderr, fmt "%.1s", __func__, __LINE__, __VA_ARGS__); } while (0)
244 #define DNS_SAY(...) DNS_SAY_("@@ (%s:%d) " __VA_ARGS__, "\n")
245 #define DNS_HAI DNS_SAY("HAI")
246
247 #define DNS_SHOW_(P, fmt, ...) do { \
248 if (DNS_DEBUG > 1) { \
249 fprintf(stderr, "@@ BEGIN * * * * * * * * * * * *\n"); \
250 fprintf(stderr, "@@ " fmt "%.0s\n", __VA_ARGS__); \
251 dns_p_dump((P), stderr); \
252 fprintf(stderr, "@@ END * * * * * * * * * * * * *\n\n"); \
253 } \
254 } while (0)
255
256 #define DNS_SHOW(...) DNS_SHOW_(__VA_ARGS__, "")
257
258 #else /* !DNS_DEBUG */
259
260 #undef DNS_DEBUG
261 #define DNS_DEBUG 0
262
263 #define DNS_SAY(...)
264 #define DNS_HAI
265 #define DNS_SHOW(...)
266
267 #endif /* DNS_DEBUG */
268
269 #define DNS_CARP(...) DNS_SAY(__VA_ARGS__)
270
271
272 /*
273 * V E R S I O N R O U T I N E S
274 *
275 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
276
dns_vendor(void)277 const char *dns_vendor(void) {
278 return DNS_VENDOR;
279 } /* dns_vendor() */
280
281
dns_v_rel(void)282 int dns_v_rel(void) {
283 return DNS_V_REL;
284 } /* dns_v_rel() */
285
286
dns_v_abi(void)287 int dns_v_abi(void) {
288 return DNS_V_ABI;
289 } /* dns_v_abi() */
290
291
dns_v_api(void)292 int dns_v_api(void) {
293 return DNS_V_API;
294 } /* dns_v_api() */
295
296
297 /*
298 * E R R O R R O U T I N E S
299 *
300 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
301
302 #if _WIN32
303
304 #define DNS_EINTR WSAEINTR
305 #define DNS_EINPROGRESS WSAEINPROGRESS
306 #define DNS_EISCONN WSAEISCONN
307 #define DNS_EWOULDBLOCK WSAEWOULDBLOCK
308 #define DNS_EALREADY WSAEALREADY
309 #define DNS_EAGAIN EAGAIN
310 #define DNS_ETIMEDOUT WSAETIMEDOUT
311
312 #define dns_syerr() ((int)GetLastError())
313 #define dns_soerr() ((int)WSAGetLastError())
314
315 #else
316
317 #define DNS_EINTR EINTR
318 #define DNS_EINPROGRESS EINPROGRESS
319 #define DNS_EISCONN EISCONN
320 #define DNS_EWOULDBLOCK EWOULDBLOCK
321 #define DNS_EALREADY EALREADY
322 #define DNS_EAGAIN EAGAIN
323 #define DNS_ETIMEDOUT ETIMEDOUT
324
325 #define dns_syerr() errno
326 #define dns_soerr() errno
327
328 #endif
329
330
dns_strerror(int error)331 const char *dns_strerror(int error) {
332 switch (error) {
333 case DNS_ENOBUFS:
334 return "DNS packet buffer too small";
335 case DNS_EILLEGAL:
336 return "Illegal DNS RR name or data";
337 case DNS_EORDER:
338 return "Attempt to push RR out of section order";
339 case DNS_ESECTION:
340 return "Invalid section specified";
341 case DNS_EUNKNOWN:
342 return "Unknown DNS error";
343 case DNS_EADDRESS:
344 return "Invalid textual address form";
345 case DNS_ENOQUERY:
346 return "Bad execution state (missing query packet)";
347 case DNS_ENOANSWER:
348 return "Bad execution state (missing answer packet)";
349 case DNS_EFETCHED:
350 return "Answer already fetched";
351 case DNS_ESERVICE:
352 return "The service passed was not recognized for the specified socket type";
353 case DNS_ENONAME:
354 return "The name does not resolve for the supplied parameters";
355 case DNS_EFAIL:
356 return "A non-recoverable error occurred when attempting to resolve the name";
357 default:
358 return strerror(error);
359 } /* switch() */
360 } /* dns_strerror() */
361
362
363 /*
364 * A T O M I C R O U T I N E S
365 *
366 * Use GCC's __atomic built-ins if possible. Unlike the __sync built-ins, we
367 * can use the preprocessor to detect API and, more importantly, ISA
368 * support. We want to avoid linking headaches where the API depends on an
369 * external library if the ISA (e.g. i386) doesn't support lockless
370 * operation.
371 *
372 * TODO: Support C11's atomic API. Although that may require some finesse
373 * with how we define some public types, such as dns_atomic_t and struct
374 * dns_resolv_conf.
375 *
376 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
377
378 #ifndef HAVE___ATOMIC_FETCH_ADD
379 #ifdef __ATOMIC_RELAXED
380 #define HAVE___ATOMIC_FETCH_ADD 1
381 #else
382 #define HAVE___ATOMIC_FETCH_ADD 0
383 #endif
384 #endif
385
386 #ifndef HAVE___ATOMIC_FETCH_SUB
387 #define HAVE___ATOMIC_FETCH_SUB HAVE___ATOMIC_FETCH_ADD
388 #endif
389
390 #ifndef DNS_ATOMIC_FETCH_ADD
391 #if HAVE___ATOMIC_FETCH_ADD && __GCC_ATOMIC_LONG_LOCK_FREE == 2
392 #define DNS_ATOMIC_FETCH_ADD(i) __atomic_fetch_add((i), 1, __ATOMIC_RELAXED)
393 #else
394 #pragma message("no atomic_fetch_add available")
395 #define DNS_ATOMIC_FETCH_ADD(i) ((*(i))++)
396 #endif
397 #endif
398
399 #ifndef DNS_ATOMIC_FETCH_SUB
400 #if HAVE___ATOMIC_FETCH_SUB && __GCC_ATOMIC_LONG_LOCK_FREE == 2
401 #define DNS_ATOMIC_FETCH_SUB(i) __atomic_fetch_sub((i), 1, __ATOMIC_RELAXED)
402 #else
403 #pragma message("no atomic_fetch_sub available")
404 #define DNS_ATOMIC_FETCH_SUB(i) ((*(i))--)
405 #endif
406 #endif
407
dns_atomic_fetch_add(dns_atomic_t * i)408 static inline unsigned dns_atomic_fetch_add(dns_atomic_t *i) {
409 return DNS_ATOMIC_FETCH_ADD(i);
410 } /* dns_atomic_fetch_add() */
411
412
dns_atomic_fetch_sub(dns_atomic_t * i)413 static inline unsigned dns_atomic_fetch_sub(dns_atomic_t *i) {
414 return DNS_ATOMIC_FETCH_SUB(i);
415 } /* dns_atomic_fetch_sub() */
416
417
418 /*
419 * C R Y P T O R O U T I N E S
420 *
421 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
422
423 /*
424 * P R N G
425 */
426
427 #ifndef DNS_RANDOM
428 #if defined(HAVE_ARC4RANDOM) \
429 || defined(__OpenBSD__) \
430 || defined(__FreeBSD__) \
431 || defined(__NetBSD__) \
432 || defined(__APPLE__)
433 #define DNS_RANDOM arc4random
434 #elif __linux
435 #define DNS_RANDOM random
436 #else
437 #define DNS_RANDOM rand
438 #endif
439 #endif
440
441 #define DNS_RANDOM_arc4random 1
442 #define DNS_RANDOM_random 2
443 #define DNS_RANDOM_rand 3
444 #define DNS_RANDOM_RAND_bytes 4
445
446 #define DNS_RANDOM_OPENSSL (DNS_RANDOM_RAND_bytes == DNS_PP_XPASTE(DNS_RANDOM_, DNS_RANDOM))
447
448 #if DNS_RANDOM_OPENSSL
449 #include <openssl/rand.h>
450 #endif
451
dns_random_(void)452 static unsigned dns_random_(void) {
453 #if DNS_RANDOM_OPENSSL
454 unsigned r;
455 _Bool ok;
456
457 ok = (1 == RAND_bytes((unsigned char *)&r, sizeof r));
458 assert(ok && "1 == RAND_bytes()");
459
460 return r;
461 #else
462 return DNS_RANDOM();
463 #endif
464 } /* dns_random_() */
465
dns_random_p(void)466 dns_random_f **dns_random_p(void) {
467 static dns_random_f *random_f = &dns_random_;
468
469 return &random_f;
470 } /* dns_random_p() */
471
472
473 /*
474 * P E R M U T A T I O N G E N E R A T O R
475 */
476
477 #define DNS_K_TEA_KEY_SIZE 16
478 #define DNS_K_TEA_BLOCK_SIZE 8
479 #define DNS_K_TEA_CYCLES 32
480 #define DNS_K_TEA_MAGIC 0x9E3779B9U
481
482 struct dns_k_tea {
483 uint32_t key[DNS_K_TEA_KEY_SIZE / sizeof (uint32_t)];
484 unsigned cycles;
485 }; /* struct dns_k_tea */
486
487
dns_k_tea_init(struct dns_k_tea * tea,uint32_t key[],unsigned cycles)488 static void dns_k_tea_init(struct dns_k_tea *tea, uint32_t key[], unsigned cycles) {
489 memcpy(tea->key, key, sizeof tea->key);
490
491 tea->cycles = (cycles)? cycles : DNS_K_TEA_CYCLES;
492 } /* dns_k_tea_init() */
493
494
dns_k_tea_encrypt(struct dns_k_tea * tea,uint32_t v[],uint32_t * w)495 static void dns_k_tea_encrypt(struct dns_k_tea *tea, uint32_t v[], uint32_t *w) {
496 uint32_t y, z, sum, n;
497
498 y = v[0];
499 z = v[1];
500 sum = 0;
501
502 for (n = 0; n < tea->cycles; n++) {
503 sum += DNS_K_TEA_MAGIC;
504 y += ((z << 4) + tea->key[0]) ^ (z + sum) ^ ((z >> 5) + tea->key[1]);
505 z += ((y << 4) + tea->key[2]) ^ (y + sum) ^ ((y >> 5) + tea->key[3]);
506 }
507
508 w[0] = y;
509 w[1] = z;
510
511 return /* void */;
512 } /* dns_k_tea_encrypt() */
513
514
515 /*
516 * Permutation generator, based on a Luby-Rackoff Feistel construction.
517 *
518 * Specifically, this is a generic balanced Feistel block cipher using TEA
519 * (another block cipher) as the pseudo-random function, F. At best it's as
520 * strong as F (TEA), notwithstanding the seeding. F could be AES, SHA-1, or
521 * perhaps Bernstein's Salsa20 core; I am naively trying to keep things
522 * simple.
523 *
524 * The generator can create a permutation of any set of numbers, as long as
525 * the size of the set is an even power of 2. This limitation arises either
526 * out of an inherent property of balanced Feistel constructions, or by my
527 * own ignorance. I'll tackle an unbalanced construction after I wrap my
528 * head around Schneier and Kelsey's paper.
529 *
530 * CAVEAT EMPTOR. IANAC.
531 */
532 #define DNS_K_PERMUTOR_ROUNDS 8
533
534 struct dns_k_permutor {
535 unsigned stepi, length, limit;
536 unsigned shift, mask, rounds;
537
538 struct dns_k_tea tea;
539 }; /* struct dns_k_permutor */
540
541
dns_k_permutor_powof(unsigned n)542 static inline unsigned dns_k_permutor_powof(unsigned n) {
543 unsigned m, i = 0;
544
545 for (m = 1; m < n; m <<= 1, i++)
546 ;;
547
548 return i;
549 } /* dns_k_permutor_powof() */
550
dns_k_permutor_init(struct dns_k_permutor * p,unsigned low,unsigned high)551 static void dns_k_permutor_init(struct dns_k_permutor *p, unsigned low, unsigned high) {
552 uint32_t key[DNS_K_TEA_KEY_SIZE / sizeof (uint32_t)];
553 unsigned width, i;
554
555 p->stepi = 0;
556
557 p->length = (high - low) + 1;
558 p->limit = high;
559
560 width = dns_k_permutor_powof(p->length);
561 width += width % 2;
562
563 p->shift = width / 2;
564 p->mask = (1U << p->shift) - 1;
565 p->rounds = DNS_K_PERMUTOR_ROUNDS;
566
567 for (i = 0; i < lengthof(key); i++)
568 key[i] = dns_random();
569
570 dns_k_tea_init(&p->tea, key, 0);
571
572 return /* void */;
573 } /* dns_k_permutor_init() */
574
575
dns_k_permutor_F(struct dns_k_permutor * p,unsigned k,unsigned x)576 static unsigned dns_k_permutor_F(struct dns_k_permutor *p, unsigned k, unsigned x) {
577 uint32_t in[DNS_K_TEA_BLOCK_SIZE / sizeof (uint32_t)], out[DNS_K_TEA_BLOCK_SIZE / sizeof (uint32_t)];
578
579 memset(in, '\0', sizeof in);
580
581 in[0] = k;
582 in[1] = x;
583
584 dns_k_tea_encrypt(&p->tea, in, out);
585
586 return p->mask & out[0];
587 } /* dns_k_permutor_F() */
588
589
dns_k_permutor_E(struct dns_k_permutor * p,unsigned n)590 static unsigned dns_k_permutor_E(struct dns_k_permutor *p, unsigned n) {
591 unsigned l[2], r[2];
592 unsigned i;
593
594 i = 0;
595 l[i] = p->mask & (n >> p->shift);
596 r[i] = p->mask & (n >> 0);
597
598 do {
599 l[(i + 1) % 2] = r[i % 2];
600 r[(i + 1) % 2] = l[i % 2] ^ dns_k_permutor_F(p, i, r[i % 2]);
601
602 i++;
603 } while (i < p->rounds - 1);
604
605 return ((l[i % 2] & p->mask) << p->shift) | ((r[i % 2] & p->mask) << 0);
606 } /* dns_k_permutor_E() */
607
608
dns_k_permutor_D(struct dns_k_permutor * p,unsigned n)609 DNS_NOTUSED static unsigned dns_k_permutor_D(struct dns_k_permutor *p, unsigned n) {
610 unsigned l[2], r[2];
611 unsigned i;
612
613 i = p->rounds - 1;
614 l[i % 2] = p->mask & (n >> p->shift);
615 r[i % 2] = p->mask & (n >> 0);
616
617 do {
618 i--;
619
620 r[i % 2] = l[(i + 1) % 2];
621 l[i % 2] = r[(i + 1) % 2] ^ dns_k_permutor_F(p, i, l[(i + 1) % 2]);
622 } while (i > 0);
623
624 return ((l[i % 2] & p->mask) << p->shift) | ((r[i % 2] & p->mask) << 0);
625 } /* dns_k_permutor_D() */
626
627
dns_k_permutor_step(struct dns_k_permutor * p)628 static unsigned dns_k_permutor_step(struct dns_k_permutor *p) {
629 unsigned n;
630
631 do {
632 n = dns_k_permutor_E(p, p->stepi++);
633 } while (n >= p->length);
634
635 return n + (p->limit + 1 - p->length);
636 } /* dns_k_permutor_step() */
637
638
639 /*
640 * Simple permutation box. Useful for shuffling rrsets from an iterator.
641 * Uses AES s-box to provide good diffusion.
642 *
643 * Seems to pass muster under runs test.
644 *
645 * $ for i in 0 1 2 3 4 5 6 7 8 9; do ./dns shuffle-16 > /tmp/out; done
646 * $ R -q -f /dev/stdin 2>/dev/null <<-EOF | awk '/p-value/{ print $8 }'
647 * library(lawstat)
648 * runs.test(scan(file="/tmp/out"))
649 * EOF
650 */
dns_k_shuffle16(unsigned short n,unsigned s)651 static unsigned short dns_k_shuffle16(unsigned short n, unsigned s) {
652 static const unsigned char sbox[256] =
653 { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
654 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
655 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
656 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
657 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
658 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
659 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
660 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
661 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
662 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
663 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
664 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
665 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
666 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
667 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
668 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
669 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
670 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
671 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
672 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
673 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
674 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
675 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
676 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
677 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
678 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
679 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
680 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
681 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
682 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
683 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
684 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };
685 unsigned char a, b;
686 unsigned i;
687
688 a = 0xff & (n >> 0);
689 b = 0xff & (n >> 8);
690
691 for (i = 0; i < 4; i++) {
692 a ^= 0xff & s;
693 a = sbox[a] ^ b;
694 b = sbox[b] ^ a;
695 s >>= 8;
696 }
697
698 return ((0xff00 & (a << 8)) | (0x00ff & (b << 0)));
699 } /* dns_k_shuffle16() */
700
701 /*
702 * S T A T E M A C H I N E R O U T I N E S
703 *
704 * Application code should define DNS_SM_RESTORE and DNS_SM_SAVE, and the
705 * local variable pc.
706 *
707 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
708
709 #define DNS_SM_ENTER \
710 do { \
711 static const int pc0 = __LINE__; \
712 DNS_SM_RESTORE; \
713 switch (pc0 + pc) { \
714 case __LINE__: (void)0
715
716 #define DNS_SM_SAVE_AND_DO(do_statement) \
717 do { \
718 pc = __LINE__ - pc0; \
719 DNS_SM_SAVE; \
720 do_statement; \
721 case __LINE__: (void)0; \
722 } while (0)
723
724 #define DNS_SM_YIELD(rv) \
725 DNS_SM_SAVE_AND_DO(return (rv))
726
727 #define DNS_SM_EXIT \
728 do { goto leave; } while (0)
729
730 #define DNS_SM_LEAVE \
731 leave: (void)0; \
732 DNS_SM_SAVE_AND_DO(break); \
733 } \
734 } while (0)
735
736 /*
737 * U T I L I T Y R O U T I N E S
738 *
739 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
740
741 #define DNS_MAXINTERVAL 300
742
743 struct dns_clock {
744 time_t sample, elapsed;
745 }; /* struct dns_clock */
746
dns_begin(struct dns_clock * clk)747 static void dns_begin(struct dns_clock *clk) {
748 clk->sample = time(0);
749 clk->elapsed = 0;
750 } /* dns_begin() */
751
dns_elapsed(struct dns_clock * clk)752 static time_t dns_elapsed(struct dns_clock *clk) {
753 time_t curtime;
754
755 if ((time_t)-1 == time(&curtime))
756 return clk->elapsed;
757
758 if (curtime > clk->sample)
759 clk->elapsed += (time_t)DNS_PP_MIN(difftime(curtime, clk->sample), DNS_MAXINTERVAL);
760
761 clk->sample = curtime;
762
763 return clk->elapsed;
764 } /* dns_elapsed() */
765
766
dns_strnlen(const char * src,size_t m)767 DNS_NOTUSED static size_t dns_strnlen(const char *src, size_t m) {
768 size_t n = 0;
769
770 while (*src++ && n < m)
771 ++n;
772
773 return n;
774 } /* dns_strnlen() */
775
776
dns_strnlcpy(char * dst,size_t lim,const char * src,size_t max)777 DNS_NOTUSED static size_t dns_strnlcpy(char *dst, size_t lim, const char *src, size_t max) {
778 size_t len = dns_strnlen(src, max), n;
779
780 if (lim > 0) {
781 n = DNS_PP_MIN(lim - 1, len);
782 memcpy(dst, src, n);
783 dst[n] = '\0';
784 }
785
786 return len;
787 } /* dns_strnlcpy() */
788
789
790 #if (defined AF_UNIX && !defined _WIN32)
791 #define DNS_HAVE_SOCKADDR_UN 1
792 #else
793 #define DNS_HAVE_SOCKADDR_UN 0
794 #endif
795
dns_af_len(int af)796 static size_t dns_af_len(int af) {
797 static const size_t table[AF_MAX] = {
798 [AF_INET6] = sizeof (struct sockaddr_in6),
799 [AF_INET] = sizeof (struct sockaddr_in),
800 #if DNS_HAVE_SOCKADDR_UN
801 [AF_UNIX] = sizeof (struct sockaddr_un),
802 #endif
803 };
804
805 return table[af];
806 } /* dns_af_len() */
807
808 #define dns_sa_family(sa) (((struct sockaddr *)(sa))->sa_family)
809
810 #define dns_sa_len(sa) dns_af_len(dns_sa_family(sa))
811
812
813 #define DNS_SA_NOPORT &dns_sa_noport
814 static unsigned short dns_sa_noport;
815
dns_sa_port(int af,void * sa)816 static unsigned short *dns_sa_port(int af, void *sa) {
817 switch (af) {
818 case AF_INET6:
819 return &((struct sockaddr_in6 *)sa)->sin6_port;
820 case AF_INET:
821 return &((struct sockaddr_in *)sa)->sin_port;
822 default:
823 return DNS_SA_NOPORT;
824 }
825 } /* dns_sa_port() */
826
827
dns_sa_addr(int af,const void * sa,socklen_t * size)828 static void *dns_sa_addr(int af, const void *sa, socklen_t *size) {
829 switch (af) {
830 case AF_INET6: {
831 struct in6_addr *in6 = &((struct sockaddr_in6 *)sa)->sin6_addr;
832
833 if (size)
834 *size = sizeof *in6;
835
836 return in6;
837 }
838 case AF_INET: {
839 struct in_addr *in = &((struct sockaddr_in *)sa)->sin_addr;
840
841 if (size)
842 *size = sizeof *in;
843
844 return in;
845 }
846 default:
847 if (size)
848 *size = 0;
849
850 return 0;
851 }
852 } /* dns_sa_addr() */
853
854
855 #if DNS_HAVE_SOCKADDR_UN
856 #define DNS_SUNPATHMAX (sizeof ((struct sockaddr_un *)0)->sun_path)
857 #endif
858
dns_sa_path(void * sa,socklen_t * size)859 DNS_NOTUSED static void *dns_sa_path(void *sa, socklen_t *size) {
860 switch (dns_sa_family(sa)) {
861 #if DNS_HAVE_SOCKADDR_UN
862 case AF_UNIX: {
863 char *path = ((struct sockaddr_un *)sa)->sun_path;
864
865 if (size)
866 *size = dns_strnlen(path, DNS_SUNPATHMAX);
867
868 return path;
869 }
870 #endif
871 default:
872 if (size)
873 *size = 0;
874
875 return NULL;
876 }
877 } /* dns_sa_path() */
878
879
dns_sa_cmp(void * a,void * b)880 static int dns_sa_cmp(void *a, void *b) {
881 int cmp, af;
882
883 if ((cmp = dns_sa_family(a) - dns_sa_family(b)))
884 return cmp;
885
886 switch ((af = dns_sa_family(a))) {
887 case AF_INET: {
888 struct in_addr *a4, *b4;
889
890 if ((cmp = htons(*dns_sa_port(af, a)) - htons(*dns_sa_port(af, b))))
891 return cmp;
892
893 a4 = dns_sa_addr(af, a, NULL);
894 b4 = dns_sa_addr(af, b, NULL);
895
896 if (ntohl(a4->s_addr) < ntohl(b4->s_addr))
897 return -1;
898 if (ntohl(a4->s_addr) > ntohl(b4->s_addr))
899 return 1;
900
901 return 0;
902 }
903 case AF_INET6: {
904 struct in6_addr *a6, *b6;
905 size_t i;
906
907 if ((cmp = htons(*dns_sa_port(af, a)) - htons(*dns_sa_port(af, b))))
908 return cmp;
909
910 a6 = dns_sa_addr(af, a, NULL);
911 b6 = dns_sa_addr(af, b, NULL);
912
913 /* XXX: do we need to use in6_clearscope()? */
914 for (i = 0; i < sizeof a6->s6_addr; i++) {
915 if ((cmp = a6->s6_addr[i] - b6->s6_addr[i]))
916 return cmp;
917 }
918
919 return 0;
920 }
921 #if DNS_HAVE_SOCKADDR_UN
922 case AF_UNIX: {
923 char a_path[DNS_SUNPATHMAX + 1], b_path[sizeof a_path];
924
925 dns_strnlcpy(a_path, sizeof a_path, dns_sa_path(a, NULL), DNS_SUNPATHMAX);
926 dns_strnlcpy(b_path, sizeof b_path, dns_sa_path(b, NULL), DNS_SUNPATHMAX);
927
928 return strcmp(a_path, b_path);
929 }
930 #endif
931 default:
932 return -1;
933 }
934 } /* dns_sa_cmp() */
935
936
937 #if _WIN32
dns_inet_pton(int af,const void * src,void * dst)938 static int dns_inet_pton(int af, const void *src, void *dst) {
939 union { struct sockaddr_in sin; struct sockaddr_in6 sin6; } u;
940
941 u.sin.sin_family = af;
942
943 if (0 != WSAStringToAddressA((void *)src, af, (void *)0, (struct sockaddr *)&u, &(int){ sizeof u }))
944 return -1;
945
946 switch (af) {
947 case AF_INET6:
948 *(struct in6_addr *)dst = u.sin6.sin6_addr;
949
950 return 1;
951 case AF_INET:
952 *(struct in_addr *)dst = u.sin.sin_addr;
953
954 return 1;
955 default:
956 return 0;
957 }
958 } /* dns_inet_pton() */
959
dns_inet_ntop(int af,const void * src,void * dst,unsigned long lim)960 static const char *dns_inet_ntop(int af, const void *src, void *dst, unsigned long lim) {
961 union { struct sockaddr_in sin; struct sockaddr_in6 sin6; } u;
962
963 /* NOTE: WSAAddressToString will print .sin_port unless zeroed. */
964 memset(&u, 0, sizeof u);
965
966 u.sin.sin_family = af;
967
968 switch (af) {
969 case AF_INET6:
970 u.sin6.sin6_addr = *(struct in6_addr *)src;
971 break;
972 case AF_INET:
973 u.sin.sin_addr = *(struct in_addr *)src;
974
975 break;
976 default:
977 return 0;
978 }
979
980 if (0 != WSAAddressToStringA((struct sockaddr *)&u, dns_sa_len(&u), (void *)0, dst, &lim))
981 return 0;
982
983 return dst;
984 } /* dns_inet_ntop() */
985 #else
986 #define dns_inet_pton(...) inet_pton(__VA_ARGS__)
987 #define dns_inet_ntop(...) inet_ntop(__VA_ARGS__)
988 #endif
989
990
dns_pton(int af,const void * src,void * dst)991 static dns_error_t dns_pton(int af, const void *src, void *dst) {
992 switch (dns_inet_pton(af, src, dst)) {
993 case 1:
994 return 0;
995 case -1:
996 return dns_soerr();
997 default:
998 return DNS_EADDRESS;
999 }
1000 } /* dns_pton() */
1001
1002
dns_ntop(int af,const void * src,void * dst,unsigned long lim)1003 static dns_error_t dns_ntop(int af, const void *src, void *dst, unsigned long lim) {
1004 return (dns_inet_ntop(af, src, dst, lim))? 0 : dns_soerr();
1005 } /* dns_ntop() */
1006
1007
dns_strlcpy(char * dst,const char * src,size_t lim)1008 size_t dns_strlcpy(char *dst, const char *src, size_t lim) {
1009 char *d = dst;
1010 char *e = &dst[lim];
1011 const char *s = src;
1012
1013 if (d < e) {
1014 do {
1015 if ('\0' == (*d++ = *s++))
1016 return s - src - 1;
1017 } while (d < e);
1018
1019 d[-1] = '\0';
1020 }
1021
1022 while (*s++ != '\0')
1023 ;;
1024
1025 return s - src - 1;
1026 } /* dns_strlcpy() */
1027
1028
dns_strlcat(char * dst,const char * src,size_t lim)1029 size_t dns_strlcat(char *dst, const char *src, size_t lim) {
1030 char *d = memchr(dst, '\0', lim);
1031 char *e = &dst[lim];
1032 const char *s = src;
1033 const char *p;
1034
1035 if (d && d < e) {
1036 do {
1037 if ('\0' == (*d++ = *s++))
1038 return d - dst - 1;
1039 } while (d < e);
1040
1041 d[-1] = '\0';
1042 }
1043
1044 p = s;
1045
1046 while (*s++ != '\0')
1047 ;;
1048
1049 return lim + (s - p - 1);
1050 } /* dns_strlcat() */
1051
1052
1053 #if _WIN32
1054
dns_strsep(char ** sp,const char * delim)1055 static char *dns_strsep(char **sp, const char *delim) {
1056 char *p;
1057
1058 if (!(p = *sp))
1059 return 0;
1060
1061 *sp += strcspn(p, delim);
1062
1063 if (**sp != '\0') {
1064 **sp = '\0';
1065 ++*sp;
1066 } else
1067 *sp = NULL;
1068
1069 return p;
1070 } /* dns_strsep() */
1071
1072 #else
1073 #define dns_strsep(...) strsep(__VA_ARGS__)
1074 #endif
1075
1076
1077 #if _WIN32
1078 #define strcasecmp(...) _stricmp(__VA_ARGS__)
1079 #define strncasecmp(...) _strnicmp(__VA_ARGS__)
1080 #endif
1081
1082
dns_isalpha(unsigned char c)1083 static inline _Bool dns_isalpha(unsigned char c) {
1084 return isalpha(c);
1085 } /* dns_isalpha() */
1086
dns_isdigit(unsigned char c)1087 static inline _Bool dns_isdigit(unsigned char c) {
1088 return isdigit(c);
1089 } /* dns_isdigit() */
1090
dns_isalnum(unsigned char c)1091 static inline _Bool dns_isalnum(unsigned char c) {
1092 return isalnum(c);
1093 } /* dns_isalnum() */
1094
dns_isspace(unsigned char c)1095 static inline _Bool dns_isspace(unsigned char c) {
1096 return isspace(c);
1097 } /* dns_isspace() */
1098
1099
dns_poll(int fd,short events,int timeout)1100 static int dns_poll(int fd, short events, int timeout) {
1101 fd_set rset, wset;
1102
1103 if (!events)
1104 return 0;
1105
1106 assert(fd >= 0 && (unsigned)fd < FD_SETSIZE);
1107
1108 FD_ZERO(&rset);
1109 FD_ZERO(&wset);
1110
1111 if (events & DNS_POLLIN)
1112 FD_SET(fd, &rset);
1113
1114 if (events & DNS_POLLOUT)
1115 FD_SET(fd, &wset);
1116
1117 select(fd + 1, &rset, &wset, 0, (timeout >= 0)? &(struct timeval){ timeout, 0 } : NULL);
1118
1119 return 0;
1120 } /* dns_poll() */
1121
1122
1123 #if !_WIN32
dns_sigmask(int how,const sigset_t * set,sigset_t * oset)1124 DNS_NOTUSED static int dns_sigmask(int how, const sigset_t *set, sigset_t *oset) {
1125 #if DNS_THREAD_SAFE
1126 return pthread_sigmask(how, set, oset);
1127 #else
1128 return (0 == sigprocmask(how, set, oset))? 0 : errno;
1129 #endif
1130 } /* dns_sigmask() */
1131 #endif
1132
1133
dns_send(int fd,const void * src,size_t lim,int flags)1134 static long dns_send(int fd, const void *src, size_t lim, int flags) {
1135 #if _WIN32 || !defined SIGPIPE || defined SO_NOSIGPIPE
1136 return send(fd, src, lim, flags);
1137 #elif defined MSG_NOSIGNAL
1138 return send(fd, src, lim, flags|MSG_NOSIGNAL);
1139 #elif _POSIX_REALTIME_SIGNALS > 0 /* require sigtimedwait */
1140 /*
1141 * SIGPIPE handling similar to the approach described in
1142 * http://krokisplace.blogspot.com/2010/02/suppressing-sigpipe-in-library.html
1143 */
1144 sigset_t pending, blocked, piped;
1145 long count;
1146 int saved, error;
1147
1148 sigemptyset(&pending);
1149 sigpending(&pending);
1150
1151 if (!sigismember(&pending, SIGPIPE)) {
1152 sigemptyset(&piped);
1153 sigaddset(&piped, SIGPIPE);
1154 sigemptyset(&blocked);
1155
1156 if ((error = dns_sigmask(SIG_BLOCK, &piped, &blocked)))
1157 goto error;
1158 }
1159
1160 count = send(fd, src, lim, flags);
1161
1162 if (!sigismember(&pending, SIGPIPE)) {
1163 saved = errno;
1164
1165 if (count == -1 && errno == EPIPE) {
1166 while (-1 == sigtimedwait(&piped, NULL, &(struct timespec){ 0, 0 }) && errno == EINTR)
1167 ;;
1168 }
1169
1170 if ((error = dns_sigmask(SIG_SETMASK, &blocked, NULL)))
1171 goto error;
1172
1173 errno = saved;
1174 }
1175
1176 return count;
1177 error:
1178 errno = error;
1179
1180 return -1;
1181 #else
1182 #error "unable to suppress SIGPIPE"
1183 return send(fd, src, lim, flags);
1184 #endif
1185 } /* dns_send() */
1186
1187
1188 #define DNS_FOPEN_STDFLAGS "rwabt+"
1189
dns_fopen_addflag(char * dst,const char * src,size_t lim,int fc)1190 static dns_error_t dns_fopen_addflag(char *dst, const char *src, size_t lim, int fc) {
1191 char *p = dst, *pe = dst + lim;
1192
1193 /* copy standard flags */
1194 while (*src && strchr(DNS_FOPEN_STDFLAGS, *src)) {
1195 if (!(p < pe))
1196 return ENOMEM;
1197 *p++ = *src++;
1198 }
1199
1200 /* append flag to standard flags */
1201 if (!(p < pe))
1202 return ENOMEM;
1203 *p++ = fc;
1204
1205 /* copy remaining mode string, including '\0' */
1206 do {
1207 if (!(p < pe))
1208 return ENOMEM;
1209 } while ((*p++ = *src++));
1210
1211 return 0;
1212 } /* dns_fopen_addflag() */
1213
dns_fopen(const char * path,const char * mode,dns_error_t * _error)1214 static FILE *dns_fopen(const char *path, const char *mode, dns_error_t *_error) {
1215 FILE *fp;
1216 char mode_cloexec[32];
1217 int error;
1218
1219 assert(path && mode && *mode);
1220 if (!*path) {
1221 error = EINVAL;
1222 goto error;
1223 }
1224
1225 #if _WIN32 || _WIN64
1226 if ((error = dns_fopen_addflag(mode_cloexec, mode, sizeof mode_cloexec, 'N')))
1227 goto error;
1228 if (!(fp = fopen(path, mode_cloexec)))
1229 goto syerr;
1230 #else
1231 if ((error = dns_fopen_addflag(mode_cloexec, mode, sizeof mode_cloexec, 'e')))
1232 goto error;
1233 if (!(fp = fopen(path, mode_cloexec))) {
1234 if (errno != EINVAL)
1235 goto syerr;
1236 if (!(fp = fopen(path, mode)))
1237 goto syerr;
1238 }
1239 #endif
1240
1241 return fp;
1242 syerr:
1243 error = dns_syerr();
1244 error:
1245 *_error = error;
1246
1247 return NULL;
1248 } /* dns_fopen() */
1249
1250
1251 /*
1252 * F I X E D - S I Z E D B U F F E R R O U T I N E S
1253 *
1254 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1255
1256 #define DNS_B_INIT(src, n) { \
1257 (unsigned char *)(src), \
1258 (unsigned char *)(src), \
1259 (unsigned char *)(src) + (n), \
1260 }
1261
1262 #define DNS_B_FROM(src, n) DNS_B_INIT((src), (n))
1263 #define DNS_B_INTO(src, n) DNS_B_INIT((src), (n))
1264
1265 struct dns_buf {
1266 const unsigned char *base;
1267 unsigned char *p;
1268 const unsigned char *pe;
1269 dns_error_t error;
1270 size_t overflow;
1271 }; /* struct dns_buf */
1272
1273 static inline size_t
dns_b_tell(struct dns_buf * b)1274 dns_b_tell(struct dns_buf *b)
1275 {
1276 return b->p - b->base;
1277 }
1278
1279 static inline dns_error_t
dns_b_setoverflow(struct dns_buf * b,size_t n,dns_error_t error)1280 dns_b_setoverflow(struct dns_buf *b, size_t n, dns_error_t error)
1281 {
1282 b->overflow += n;
1283 return b->error = error;
1284 }
1285
1286 DNS_NOTUSED static struct dns_buf *
dns_b_into(struct dns_buf * b,void * src,size_t n)1287 dns_b_into(struct dns_buf *b, void *src, size_t n)
1288 {
1289 *b = (struct dns_buf)DNS_B_INTO(src, n);
1290
1291 return b;
1292 }
1293
1294 static dns_error_t
dns_b_putc(struct dns_buf * b,unsigned char uc)1295 dns_b_putc(struct dns_buf *b, unsigned char uc)
1296 {
1297 if (!(b->p < b->pe))
1298 return dns_b_setoverflow(b, 1, DNS_ENOBUFS);
1299
1300 *b->p++ = uc;
1301
1302 return 0;
1303 }
1304
1305 static dns_error_t
dns_b_pputc(struct dns_buf * b,unsigned char uc,size_t p)1306 dns_b_pputc(struct dns_buf *b, unsigned char uc, size_t p)
1307 {
1308 size_t pe = b->pe - b->base;
1309 if (pe <= p)
1310 return dns_b_setoverflow(b, p - pe + 1, DNS_ENOBUFS);
1311
1312 *((unsigned char *)b->base + p) = uc;
1313
1314 return 0;
1315 }
1316
1317 static inline dns_error_t
dns_b_put16(struct dns_buf * b,uint16_t u)1318 dns_b_put16(struct dns_buf *b, uint16_t u)
1319 {
1320 return dns_b_putc(b, u >> 8), dns_b_putc(b, u >> 0);
1321 }
1322
1323 static inline dns_error_t
dns_b_pput16(struct dns_buf * b,uint16_t u,size_t p)1324 dns_b_pput16(struct dns_buf *b, uint16_t u, size_t p)
1325 {
1326 if (dns_b_pputc(b, u >> 8, p) || dns_b_pputc(b, u >> 0, p + 1))
1327 return b->error;
1328
1329 return 0;
1330 }
1331
1332 DNS_NOTUSED static inline dns_error_t
dns_b_put32(struct dns_buf * b,uint32_t u)1333 dns_b_put32(struct dns_buf *b, uint32_t u)
1334 {
1335 return dns_b_putc(b, u >> 24), dns_b_putc(b, u >> 16),
1336 dns_b_putc(b, u >> 8), dns_b_putc(b, u >> 0);
1337 }
1338
1339 static dns_error_t
dns_b_put(struct dns_buf * b,const void * src,size_t len)1340 dns_b_put(struct dns_buf *b, const void *src, size_t len)
1341 {
1342 size_t n = DNS_PP_MIN((size_t)(b->pe - b->p), len);
1343
1344 memcpy(b->p, src, n);
1345 b->p += n;
1346
1347 if (n < len)
1348 return dns_b_setoverflow(b, len - n, DNS_ENOBUFS);
1349
1350 return 0;
1351 }
1352
1353 static dns_error_t
dns_b_puts(struct dns_buf * b,const void * src)1354 dns_b_puts(struct dns_buf *b, const void *src)
1355 {
1356 return dns_b_put(b, src, strlen(src));
1357 }
1358
1359 DNS_NOTUSED static inline dns_error_t
dns_b_fmtju(struct dns_buf * b,const uintmax_t u,const unsigned width)1360 dns_b_fmtju(struct dns_buf *b, const uintmax_t u, const unsigned width)
1361 {
1362 size_t digits, padding, overflow;
1363 uintmax_t r;
1364 unsigned char *tp, *te, tc;
1365
1366 digits = 0;
1367 r = u;
1368 do {
1369 digits++;
1370 r /= 10;
1371 } while (r);
1372
1373 padding = width - DNS_PP_MIN(digits, width);
1374 overflow = (digits + padding) - DNS_PP_MIN((size_t)(b->pe - b->p), (digits + padding));
1375
1376 while (padding--) {
1377 dns_b_putc(b, '0');
1378 }
1379
1380 digits = 0;
1381 tp = b->p;
1382 r = u;
1383 do {
1384 if (overflow < ++digits)
1385 dns_b_putc(b, '0' + (r % 10));
1386 r /= 10;
1387 } while (r);
1388
1389 te = b->p;
1390 while (tp < te) {
1391 tc = *--te;
1392 *te = *tp;
1393 *tp++ = tc;
1394 }
1395
1396 return b->error;
1397 }
1398
1399 static void
dns_b_popc(struct dns_buf * b)1400 dns_b_popc(struct dns_buf *b)
1401 {
1402 if (b->overflow && !--b->overflow)
1403 b->error = 0;
1404 if (b->p > b->base)
1405 b->p--;
1406 }
1407
1408 static inline const char *
dns_b_tolstring(struct dns_buf * b,size_t * n)1409 dns_b_tolstring(struct dns_buf *b, size_t *n)
1410 {
1411 if (b->p < b->pe) {
1412 *b->p = '\0';
1413 *n = b->p - b->base;
1414
1415 return (const char *)b->base;
1416 } else if (b->p > b->base) {
1417 if (b->p[-1] != '\0') {
1418 dns_b_setoverflow(b, 1, DNS_ENOBUFS);
1419 b->p[-1] = '\0';
1420 }
1421 *n = &b->p[-1] - b->base;
1422
1423 return (const char *)b->base;
1424 } else {
1425 *n = 0;
1426
1427 return "";
1428 }
1429 }
1430
1431 static inline const char *
dns_b_tostring(struct dns_buf * b)1432 dns_b_tostring(struct dns_buf *b)
1433 {
1434 size_t n;
1435 return dns_b_tolstring(b, &n);
1436 }
1437
1438 static inline size_t
dns_b_strlen(struct dns_buf * b)1439 dns_b_strlen(struct dns_buf *b)
1440 {
1441 size_t n;
1442 dns_b_tolstring(b, &n);
1443 return n;
1444 }
1445
1446 static inline size_t
dns_b_strllen(struct dns_buf * b)1447 dns_b_strllen(struct dns_buf *b)
1448 {
1449 size_t n = dns_b_strlen(b);
1450 return n + b->overflow;
1451 }
1452
1453 DNS_NOTUSED static const struct dns_buf *
dns_b_from(const struct dns_buf * b,const void * src,size_t n)1454 dns_b_from(const struct dns_buf *b, const void *src, size_t n)
1455 {
1456 *(struct dns_buf *)b = (struct dns_buf)DNS_B_FROM(src, n);
1457
1458 return b;
1459 }
1460
1461 static inline int
dns_b_getc(const struct dns_buf * _b,const int eof)1462 dns_b_getc(const struct dns_buf *_b, const int eof)
1463 {
1464 struct dns_buf *b = (struct dns_buf *)_b;
1465
1466 if (!(b->p < b->pe))
1467 return dns_b_setoverflow(b, 1, DNS_EILLEGAL), eof;
1468
1469 return *b->p++;
1470 }
1471
1472 static inline intmax_t
dns_b_get16(const struct dns_buf * b,const intmax_t eof)1473 dns_b_get16(const struct dns_buf *b, const intmax_t eof)
1474 {
1475 intmax_t n;
1476
1477 n = (dns_b_getc(b, 0) << 8);
1478 n |= (dns_b_getc(b, 0) << 0);
1479
1480 return (!b->overflow)? n : eof;
1481 }
1482
1483 DNS_NOTUSED static inline intmax_t
dns_b_get32(const struct dns_buf * b,const intmax_t eof)1484 dns_b_get32(const struct dns_buf *b, const intmax_t eof)
1485 {
1486 intmax_t n;
1487
1488 n = (dns_b_get16(b, 0) << 16);
1489 n |= (dns_b_get16(b, 0) << 0);
1490
1491 return (!b->overflow)? n : eof;
1492 }
1493
1494 static inline dns_error_t
dns_b_move(struct dns_buf * dst,const struct dns_buf * _src,size_t n)1495 dns_b_move(struct dns_buf *dst, const struct dns_buf *_src, size_t n)
1496 {
1497 struct dns_buf *src = (struct dns_buf *)_src;
1498 size_t src_n = DNS_PP_MIN((size_t)(src->pe - src->p), n);
1499 size_t src_r = n - src_n;
1500
1501 dns_b_put(dst, src->p, src_n);
1502 src->p += src_n;
1503
1504 if (src_r)
1505 return dns_b_setoverflow(src, src_r, DNS_EILLEGAL);
1506
1507 return dst->error;
1508 }
1509
1510
1511 /*
1512 * P A C K E T R O U T I N E S
1513 *
1514 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1515
dns_p_count(struct dns_packet * P,enum dns_section section)1516 unsigned dns_p_count(struct dns_packet *P, enum dns_section section) {
1517 unsigned count;
1518
1519 switch (section) {
1520 case DNS_S_QD:
1521 return ntohs(dns_header(P)->qdcount);
1522 case DNS_S_AN:
1523 return ntohs(dns_header(P)->ancount);
1524 case DNS_S_NS:
1525 return ntohs(dns_header(P)->nscount);
1526 case DNS_S_AR:
1527 return ntohs(dns_header(P)->arcount);
1528 default:
1529 count = 0;
1530
1531 if (section & DNS_S_QD)
1532 count += ntohs(dns_header(P)->qdcount);
1533 if (section & DNS_S_AN)
1534 count += ntohs(dns_header(P)->ancount);
1535 if (section & DNS_S_NS)
1536 count += ntohs(dns_header(P)->nscount);
1537 if (section & DNS_S_AR)
1538 count += ntohs(dns_header(P)->arcount);
1539
1540 return count;
1541 }
1542 } /* dns_p_count() */
1543
1544
dns_p_init(struct dns_packet * P,size_t size)1545 struct dns_packet *dns_p_init(struct dns_packet *P, size_t size) {
1546 if (!P)
1547 return 0;
1548
1549 assert(size >= offsetof(struct dns_packet, data) + 12);
1550
1551 memset(P, 0, sizeof *P);
1552 P->size = size - offsetof(struct dns_packet, data);
1553 P->end = 12;
1554
1555 memset(P->data, '\0', 12);
1556
1557 return P;
1558 } /* dns_p_init() */
1559
1560
dns_p_reset(struct dns_packet * P)1561 static struct dns_packet *dns_p_reset(struct dns_packet *P) {
1562 return dns_p_init(P, offsetof(struct dns_packet, data) + P->size);
1563 } /* dns_p_reset() */
1564
1565
dns_p_qend(struct dns_packet * P)1566 static unsigned short dns_p_qend(struct dns_packet *P) {
1567 unsigned short qend = 12;
1568 unsigned i, count = dns_p_count(P, DNS_S_QD);
1569
1570 for (i = 0; i < count && qend < P->end; i++) {
1571 if (P->end == (qend = dns_d_skip(qend, P)))
1572 goto invalid;
1573
1574 if (P->end - qend < 4)
1575 goto invalid;
1576
1577 qend += 4;
1578 }
1579
1580 return DNS_PP_MIN(qend, P->end);
1581 invalid:
1582 return P->end;
1583 } /* dns_p_qend() */
1584
1585
dns_p_make(size_t len,int * error)1586 struct dns_packet *dns_p_make(size_t len, int *error) {
1587 struct dns_packet *P;
1588 size_t size = dns_p_calcsize(len);
1589
1590 if (!(P = dns_p_init(malloc(size), size)))
1591 *error = dns_syerr();
1592
1593 return P;
1594 } /* dns_p_make() */
1595
1596
dns_p_free(struct dns_packet * P)1597 static void dns_p_free(struct dns_packet *P) {
1598 free(P);
1599 } /* dns_p_free() */
1600
1601
1602 /* convience routine to free any existing packet before storing new packet */
dns_p_setptr(struct dns_packet ** dst,struct dns_packet * src)1603 static struct dns_packet *dns_p_setptr(struct dns_packet **dst, struct dns_packet *src) {
1604 dns_p_free(*dst);
1605
1606 *dst = src;
1607
1608 return src;
1609 } /* dns_p_setptr() */
1610
1611
dns_p_movptr(struct dns_packet ** dst,struct dns_packet ** src)1612 static struct dns_packet *dns_p_movptr(struct dns_packet **dst, struct dns_packet **src) {
1613 dns_p_setptr(dst, *src);
1614
1615 *src = NULL;
1616
1617 return *dst;
1618 } /* dns_p_movptr() */
1619
1620
dns_p_grow(struct dns_packet ** P)1621 int dns_p_grow(struct dns_packet **P) {
1622 struct dns_packet *tmp;
1623 size_t size;
1624 int error;
1625
1626 if (!*P) {
1627 if (!(*P = dns_p_make(DNS_P_QBUFSIZ, &error)))
1628 return error;
1629
1630 return 0;
1631 }
1632
1633 size = dns_p_sizeof(*P);
1634 size |= size >> 1;
1635 size |= size >> 2;
1636 size |= size >> 4;
1637 size |= size >> 8;
1638 size++;
1639
1640 if (size > 65536)
1641 return DNS_ENOBUFS;
1642
1643 if (!(tmp = realloc(*P, dns_p_calcsize(size))))
1644 return dns_syerr();
1645
1646 tmp->size = size;
1647 *P = tmp;
1648
1649 return 0;
1650 } /* dns_p_grow() */
1651
1652
dns_p_copy(struct dns_packet * P,const struct dns_packet * P0)1653 struct dns_packet *dns_p_copy(struct dns_packet *P, const struct dns_packet *P0) {
1654 if (!P)
1655 return 0;
1656
1657 P->end = DNS_PP_MIN(P->size, P0->end);
1658
1659 memcpy(P->data, P0->data, P->end);
1660
1661 return P;
1662 } /* dns_p_copy() */
1663
1664
dns_p_merge(struct dns_packet * A,enum dns_section Amask,struct dns_packet * B,enum dns_section Bmask,int * error_)1665 struct dns_packet *dns_p_merge(struct dns_packet *A, enum dns_section Amask, struct dns_packet *B, enum dns_section Bmask, int *error_) {
1666 size_t bufsiz = DNS_PP_MIN(65535, ((A)? A->end : 0) + ((B)? B->end : 0));
1667 struct dns_packet *M;
1668 enum dns_section section;
1669 struct dns_rr rr, mr;
1670 int error, copy;
1671
1672 if (!A && B) {
1673 A = B;
1674 Amask = Bmask;
1675 B = 0;
1676 }
1677
1678 merge:
1679 if (!(M = dns_p_make(bufsiz, &error)))
1680 goto error;
1681
1682 for (section = DNS_S_QD; (DNS_S_ALL & section); section <<= 1) {
1683 if (A && (section & Amask)) {
1684 dns_rr_foreach(&rr, A, .section = section) {
1685 if ((error = dns_rr_copy(M, &rr, A)))
1686 goto error;
1687 }
1688 }
1689
1690 if (B && (section & Bmask)) {
1691 dns_rr_foreach(&rr, B, .section = section) {
1692 copy = 1;
1693
1694 dns_rr_foreach(&mr, M, .type = rr.type, .section = DNS_S_ALL) {
1695 if (!(copy = dns_rr_cmp(&rr, B, &mr, M)))
1696 break;
1697 }
1698
1699 if (copy && (error = dns_rr_copy(M, &rr, B)))
1700 goto error;
1701 }
1702 }
1703 }
1704
1705 return M;
1706 error:
1707 dns_p_setptr(&M, NULL);
1708
1709 if (error == DNS_ENOBUFS && bufsiz < 65535) {
1710 bufsiz = DNS_PP_MIN(65535, bufsiz * 2);
1711
1712 goto merge;
1713 }
1714
1715 *error_ = error;
1716
1717 return 0;
1718 } /* dns_p_merge() */
1719
1720
1721 static unsigned short dns_l_skip(unsigned short, const unsigned char *, size_t);
1722
dns_p_dictadd(struct dns_packet * P,unsigned short dn)1723 void dns_p_dictadd(struct dns_packet *P, unsigned short dn) {
1724 unsigned short lp, lptr, i;
1725
1726 lp = dn;
1727
1728 while (lp < P->end) {
1729 if (0xc0 == (0xc0 & P->data[lp]) && P->end - lp >= 2 && lp != dn) {
1730 lptr = ((0x3f & P->data[lp + 0]) << 8)
1731 | ((0xff & P->data[lp + 1]) << 0);
1732
1733 for (i = 0; i < lengthof(P->dict) && P->dict[i]; i++) {
1734 if (P->dict[i] == lptr) {
1735 P->dict[i] = dn;
1736
1737 return;
1738 }
1739 }
1740 }
1741
1742 lp = dns_l_skip(lp, P->data, P->end);
1743 }
1744
1745 for (i = 0; i < lengthof(P->dict); i++) {
1746 if (!P->dict[i]) {
1747 P->dict[i] = dn;
1748
1749 break;
1750 }
1751 }
1752 } /* dns_p_dictadd() */
1753
1754
dns_p_push(struct dns_packet * P,enum dns_section section,const void * dn,size_t dnlen,enum dns_type type,enum dns_class class,unsigned ttl,const void * any)1755 int dns_p_push(struct dns_packet *P, enum dns_section section, const void *dn, size_t dnlen, enum dns_type type, enum dns_class class, unsigned ttl, const void *any) {
1756 size_t end = P->end;
1757 int error;
1758
1759 if ((error = dns_d_push(P, dn, dnlen)))
1760 goto error;
1761
1762 if (P->size - P->end < 4)
1763 goto nobufs;
1764
1765 P->data[P->end++] = 0xff & (type >> 8);
1766 P->data[P->end++] = 0xff & (type >> 0);
1767
1768 P->data[P->end++] = 0xff & (class >> 8);
1769 P->data[P->end++] = 0xff & (class >> 0);
1770
1771 if (section == DNS_S_QD)
1772 goto update;
1773
1774 if (P->size - P->end < 6)
1775 goto nobufs;
1776
1777 if (type != DNS_T_OPT)
1778 ttl = DNS_PP_MIN(ttl, 0x7fffffffU);
1779 P->data[P->end++] = ttl >> 24;
1780 P->data[P->end++] = ttl >> 16;
1781 P->data[P->end++] = ttl >> 8;
1782 P->data[P->end++] = ttl >> 0;
1783
1784 if ((error = dns_any_push(P, (union dns_any *)any, type)))
1785 goto error;
1786
1787 update:
1788 switch (section) {
1789 case DNS_S_QD:
1790 if (dns_p_count(P, DNS_S_AN|DNS_S_NS|DNS_S_AR))
1791 goto order;
1792
1793 if (!P->memo.qd.base && (error = dns_p_study(P)))
1794 goto error;
1795
1796 dns_header(P)->qdcount = htons(ntohs(dns_header(P)->qdcount) + 1);
1797
1798 P->memo.qd.end = P->end;
1799 P->memo.an.base = P->end;
1800 P->memo.an.end = P->end;
1801 P->memo.ns.base = P->end;
1802 P->memo.ns.end = P->end;
1803 P->memo.ar.base = P->end;
1804 P->memo.ar.end = P->end;
1805
1806 break;
1807 case DNS_S_AN:
1808 if (dns_p_count(P, DNS_S_NS|DNS_S_AR))
1809 goto order;
1810
1811 if (!P->memo.an.base && (error = dns_p_study(P)))
1812 goto error;
1813
1814 dns_header(P)->ancount = htons(ntohs(dns_header(P)->ancount) + 1);
1815
1816 P->memo.an.end = P->end;
1817 P->memo.ns.base = P->end;
1818 P->memo.ns.end = P->end;
1819 P->memo.ar.base = P->end;
1820 P->memo.ar.end = P->end;
1821
1822 break;
1823 case DNS_S_NS:
1824 if (dns_p_count(P, DNS_S_AR))
1825 goto order;
1826
1827 if (!P->memo.ns.base && (error = dns_p_study(P)))
1828 goto error;
1829
1830 dns_header(P)->nscount = htons(ntohs(dns_header(P)->nscount) + 1);
1831
1832 P->memo.ns.end = P->end;
1833 P->memo.ar.base = P->end;
1834 P->memo.ar.end = P->end;
1835
1836 break;
1837 case DNS_S_AR:
1838 if (!P->memo.ar.base && (error = dns_p_study(P)))
1839 goto error;
1840
1841 dns_header(P)->arcount = htons(ntohs(dns_header(P)->arcount) + 1);
1842
1843 P->memo.ar.end = P->end;
1844
1845 if (type == DNS_T_OPT && !P->memo.opt.p) {
1846 P->memo.opt.p = end;
1847 P->memo.opt.maxudp = class;
1848 P->memo.opt.ttl = ttl;
1849 }
1850
1851 break;
1852 default:
1853 error = DNS_ESECTION;
1854
1855 goto error;
1856 } /* switch() */
1857
1858 return 0;
1859 nobufs:
1860 error = DNS_ENOBUFS;
1861
1862 goto error;
1863 order:
1864 error = DNS_EORDER;
1865
1866 goto error;
1867 error:
1868 P->end = end;
1869
1870 return error;
1871 } /* dns_p_push() */
1872
1873
dns_p_dump3(struct dns_packet * P,struct dns_rr_i * I,FILE * fp)1874 static void dns_p_dump3(struct dns_packet *P, struct dns_rr_i *I, FILE *fp) {
1875 enum dns_section section;
1876 struct dns_rr rr;
1877 int error;
1878 union dns_any any;
1879 char pretty[sizeof any * 2];
1880 size_t len;
1881
1882 fputs(";; [HEADER]\n", fp);
1883 fprintf(fp, ";; qid : %d\n", ntohs(dns_header(P)->qid));
1884 fprintf(fp, ";; qr : %s(%d)\n", (dns_header(P)->qr)? "RESPONSE" : "QUERY", dns_header(P)->qr);
1885 fprintf(fp, ";; opcode : %s(%d)\n", dns_stropcode(dns_header(P)->opcode), dns_header(P)->opcode);
1886 fprintf(fp, ";; aa : %s(%d)\n", (dns_header(P)->aa)? "AUTHORITATIVE" : "NON-AUTHORITATIVE", dns_header(P)->aa);
1887 fprintf(fp, ";; tc : %s(%d)\n", (dns_header(P)->tc)? "TRUNCATED" : "NOT-TRUNCATED", dns_header(P)->tc);
1888 fprintf(fp, ";; rd : %s(%d)\n", (dns_header(P)->rd)? "RECURSION-DESIRED" : "RECURSION-NOT-DESIRED", dns_header(P)->rd);
1889 fprintf(fp, ";; ra : %s(%d)\n", (dns_header(P)->ra)? "RECURSION-ALLOWED" : "RECURSION-NOT-ALLOWED", dns_header(P)->ra);
1890 fprintf(fp, ";; rcode : %s(%d)\n", dns_strrcode(dns_p_rcode(P)), dns_p_rcode(P));
1891
1892 section = 0;
1893
1894 while (dns_rr_grep(&rr, 1, I, P, &error)) {
1895 if (section != rr.section)
1896 fprintf(fp, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(P, rr.section));
1897
1898 if ((len = dns_rr_print(pretty, sizeof pretty, &rr, P, &error)))
1899 fprintf(fp, "%s\n", pretty);
1900
1901 section = rr.section;
1902 }
1903 } /* dns_p_dump3() */
1904
1905
dns_p_dump(struct dns_packet * P,FILE * fp)1906 void dns_p_dump(struct dns_packet *P, FILE *fp) {
1907 dns_p_dump3(P, dns_rr_i_new(P, .section = 0), fp);
1908 } /* dns_p_dump() */
1909
1910
dns_s_unstudy(struct dns_s_memo * m)1911 static void dns_s_unstudy(struct dns_s_memo *m)
1912 { m->base = 0; m->end = 0; }
1913
dns_m_unstudy(struct dns_p_memo * m)1914 static void dns_m_unstudy(struct dns_p_memo *m) {
1915 dns_s_unstudy(&m->qd);
1916 dns_s_unstudy(&m->an);
1917 dns_s_unstudy(&m->ns);
1918 dns_s_unstudy(&m->ar);
1919 m->opt.p = 0;
1920 m->opt.maxudp = 0;
1921 m->opt.ttl = 0;
1922 } /* dns_m_unstudy() */
1923
dns_s_study(struct dns_s_memo * m,enum dns_section section,unsigned short base,struct dns_packet * P)1924 static int dns_s_study(struct dns_s_memo *m, enum dns_section section, unsigned short base, struct dns_packet *P) {
1925 unsigned short count, rp;
1926
1927 count = dns_p_count(P, section);
1928
1929 for (rp = base; count && rp < P->end; count--)
1930 rp = dns_rr_skip(rp, P);
1931
1932 m->base = base;
1933 m->end = rp;
1934
1935 return 0;
1936 } /* dns_s_study() */
1937
dns_m_study(struct dns_p_memo * m,struct dns_packet * P)1938 static int dns_m_study(struct dns_p_memo *m, struct dns_packet *P) {
1939 struct dns_rr rr;
1940 int error;
1941
1942 if ((error = dns_s_study(&m->qd, DNS_S_QD, 12, P)))
1943 goto error;
1944 if ((error = dns_s_study(&m->an, DNS_S_AN, m->qd.end, P)))
1945 goto error;
1946 if ((error = dns_s_study(&m->ns, DNS_S_NS, m->an.end, P)))
1947 goto error;
1948 if ((error = dns_s_study(&m->ar, DNS_S_AR, m->ns.end, P)))
1949 goto error;
1950
1951 m->opt.p = 0;
1952 m->opt.maxudp = 0;
1953 m->opt.ttl = 0;
1954 dns_rr_foreach(&rr, P, .type = DNS_T_OPT, .section = DNS_S_AR) {
1955 m->opt.p = rr.dn.p;
1956 m->opt.maxudp = rr.class;
1957 m->opt.ttl = rr.ttl;
1958 break;
1959 }
1960
1961 return 0;
1962 error:
1963 dns_m_unstudy(m);
1964
1965 return error;
1966 } /* dns_m_study() */
1967
dns_p_study(struct dns_packet * P)1968 int dns_p_study(struct dns_packet *P) {
1969 return dns_m_study(&P->memo, P);
1970 } /* dns_p_study() */
1971
1972
dns_p_rcode(struct dns_packet * P)1973 enum dns_rcode dns_p_rcode(struct dns_packet *P) {
1974 return 0xfff & ((P->memo.opt.ttl >> 20) | dns_header(P)->rcode);
1975 } /* dns_p_rcode() */
1976
1977
1978 /*
1979 * Q U E R Y P A C K E T R O U T I N E S
1980 *
1981 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1982
1983 #define DNS_Q_RD 0x1 /* recursion desired */
1984 #define DNS_Q_EDNS0 0x2 /* include OPT RR */
1985
1986 static dns_error_t
dns_q_make2(struct dns_packet ** _Q,const char * qname,size_t qlen,enum dns_type qtype,enum dns_class qclass,int qflags)1987 dns_q_make2(struct dns_packet **_Q, const char *qname, size_t qlen, enum dns_type qtype, enum dns_class qclass, int qflags)
1988 {
1989 struct dns_packet *Q = NULL;
1990 int error;
1991
1992 if (dns_p_movptr(&Q, _Q)) {
1993 dns_p_reset(Q);
1994 } else if (!(Q = dns_p_make(DNS_P_QBUFSIZ, &error))) {
1995 goto error;
1996 }
1997
1998 if ((error = dns_p_push(Q, DNS_S_QD, qname, qlen, qtype, qclass, 0, 0)))
1999 goto error;
2000
2001 dns_header(Q)->rd = !!(qflags & DNS_Q_RD);
2002
2003 if (qflags & DNS_Q_EDNS0) {
2004 struct dns_opt opt = DNS_OPT_INIT(&opt);
2005
2006 opt.version = 0; /* RFC 6891 version */
2007 opt.maxudp = 4096;
2008
2009 if ((error = dns_p_push(Q, DNS_S_AR, ".", 1, DNS_T_OPT, dns_opt_class(&opt), dns_opt_ttl(&opt), &opt)))
2010 goto error;
2011 }
2012
2013 *_Q = Q;
2014
2015 return 0;
2016 error:
2017 dns_p_free(Q);
2018
2019 return error;
2020 }
2021
2022 static dns_error_t
dns_q_make(struct dns_packet ** Q,const char * qname,enum dns_type qtype,enum dns_class qclass,int qflags)2023 dns_q_make(struct dns_packet **Q, const char *qname, enum dns_type qtype, enum dns_class qclass, int qflags)
2024 {
2025 return dns_q_make2(Q, qname, strlen(qname), qtype, qclass, qflags);
2026 }
2027
2028 static dns_error_t
dns_q_remake(struct dns_packet ** Q,int qflags)2029 dns_q_remake(struct dns_packet **Q, int qflags)
2030 {
2031 char qname[DNS_D_MAXNAME + 1];
2032 size_t qlen;
2033 struct dns_rr rr;
2034 int error;
2035
2036 assert(Q && *Q);
2037 if ((error = dns_rr_parse(&rr, 12, *Q)))
2038 return error;
2039 if (!(qlen = dns_d_expand(qname, sizeof qname, rr.dn.p, *Q, &error)))
2040 return error;
2041 if (qlen >= sizeof qname)
2042 return DNS_EILLEGAL;
2043 return dns_q_make2(Q, qname, qlen, rr.type, rr.class, qflags);
2044 }
2045
2046 /*
2047 * D O M A I N N A M E R O U T I N E S
2048 *
2049 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2050
2051 #ifndef DNS_D_MAXPTRS
2052 #define DNS_D_MAXPTRS 127 /* Arbitrary; possible, valid depth is something like packet size / 2 + fudge. */
2053 #endif
2054
dns_l_expand(unsigned char * dst,size_t lim,unsigned short src,unsigned short * nxt,const unsigned char * data,size_t end)2055 static size_t dns_l_expand(unsigned char *dst, size_t lim, unsigned short src, unsigned short *nxt, const unsigned char *data, size_t end) {
2056 unsigned short len;
2057 unsigned nptrs = 0;
2058
2059 retry:
2060 if (src >= end)
2061 goto invalid;
2062
2063 switch (0x03 & (data[src] >> 6)) {
2064 case 0x00:
2065 len = (0x3f & (data[src++]));
2066
2067 if (end - src < len)
2068 goto invalid;
2069
2070 if (lim > 0) {
2071 memcpy(dst, &data[src], DNS_PP_MIN(lim, len));
2072
2073 dst[DNS_PP_MIN(lim - 1, len)] = '\0';
2074 }
2075
2076 *nxt = src + len;
2077
2078 return len;
2079 case 0x01:
2080 goto invalid;
2081 case 0x02:
2082 goto invalid;
2083 case 0x03:
2084 if (++nptrs > DNS_D_MAXPTRS)
2085 goto invalid;
2086
2087 if (end - src < 2)
2088 goto invalid;
2089
2090 src = ((0x3f & data[src + 0]) << 8)
2091 | ((0xff & data[src + 1]) << 0);
2092
2093 goto retry;
2094 } /* switch() */
2095
2096 /* NOT REACHED */
2097 invalid:
2098 *nxt = end;
2099
2100 return 0;
2101 } /* dns_l_expand() */
2102
2103
dns_l_skip(unsigned short src,const unsigned char * data,size_t end)2104 static unsigned short dns_l_skip(unsigned short src, const unsigned char *data, size_t end) {
2105 unsigned short len;
2106
2107 if (src >= end)
2108 goto invalid;
2109
2110 switch (0x03 & (data[src] >> 6)) {
2111 case 0x00:
2112 len = (0x3f & (data[src++]));
2113
2114 if (end - src < len)
2115 goto invalid;
2116
2117 return (len)? src + len : end;
2118 case 0x01:
2119 goto invalid;
2120 case 0x02:
2121 goto invalid;
2122 case 0x03:
2123 return end;
2124 } /* switch() */
2125
2126 /* NOT REACHED */
2127 invalid:
2128 return end;
2129 } /* dns_l_skip() */
2130
2131
dns_d_isanchored(const void * _src,size_t len)2132 static _Bool dns_d_isanchored(const void *_src, size_t len) {
2133 const unsigned char *src = _src;
2134 return len > 0 && src[len - 1] == '.';
2135 } /* dns_d_isanchored() */
2136
2137
dns_d_ndots(const void * _src,size_t len)2138 static size_t dns_d_ndots(const void *_src, size_t len) {
2139 const unsigned char *p = _src, *pe = p + len;
2140 size_t ndots = 0;
2141
2142 while ((p = memchr(p, '.', pe - p))) {
2143 ndots++;
2144 p++;
2145 }
2146
2147 return ndots;
2148 } /* dns_d_ndots() */
2149
2150
dns_d_trim(void * dst_,size_t lim,const void * src_,size_t len,int flags)2151 static size_t dns_d_trim(void *dst_, size_t lim, const void *src_, size_t len, int flags) {
2152 unsigned char *dst = dst_;
2153 const unsigned char *src = src_;
2154 size_t dp = 0, sp = 0;
2155 int lc;
2156
2157 /* trim any leading dot(s) */
2158 while (sp < len && src[sp] == '.')
2159 sp++;
2160
2161 for (lc = 0; sp < len; lc = src[sp++]) {
2162 /* trim extra dot(s) */
2163 if (src[sp] == '.' && lc == '.')
2164 continue;
2165
2166 if (dp < lim)
2167 dst[dp] = src[sp];
2168
2169 dp++;
2170 }
2171
2172 if ((flags & DNS_D_ANCHOR) && lc != '.') {
2173 if (dp < lim)
2174 dst[dp] = '.';
2175
2176 dp++;
2177 }
2178
2179 if (lim > 0)
2180 dst[DNS_PP_MIN(dp, lim - 1)] = '\0';
2181
2182 return dp;
2183 } /* dns_d_trim() */
2184
2185
dns_d_init(void * dst,size_t lim,const void * src,size_t len,int flags)2186 char *dns_d_init(void *dst, size_t lim, const void *src, size_t len, int flags) {
2187 if (flags & DNS_D_TRIM) {
2188 dns_d_trim(dst, lim, src, len, flags);
2189 } if (flags & DNS_D_ANCHOR) {
2190 dns_d_anchor(dst, lim, src, len);
2191 } else {
2192 memmove(dst, src, DNS_PP_MIN(lim, len));
2193
2194 if (lim > 0)
2195 ((char *)dst)[DNS_PP_MIN(len, lim - 1)] = '\0';
2196 }
2197
2198 return dst;
2199 } /* dns_d_init() */
2200
2201
dns_d_anchor(void * dst,size_t lim,const void * src,size_t len)2202 size_t dns_d_anchor(void *dst, size_t lim, const void *src, size_t len) {
2203 if (len == 0)
2204 return 0;
2205
2206 memmove(dst, src, DNS_PP_MIN(lim, len));
2207
2208 if (((const char *)src)[len - 1] != '.') {
2209 if (len < lim)
2210 ((char *)dst)[len] = '.';
2211 len++;
2212 }
2213
2214 if (lim > 0)
2215 ((char *)dst)[DNS_PP_MIN(lim - 1, len)] = '\0';
2216
2217 return len;
2218 } /* dns_d_anchor() */
2219
2220
dns_d_cleave(void * dst,size_t lim,const void * src,size_t len)2221 size_t dns_d_cleave(void *dst, size_t lim, const void *src, size_t len) {
2222 const char *dot;
2223
2224 /* XXX: Skip any leading dot. Handles cleaving root ".". */
2225 if (len == 0 || !(dot = memchr((const char *)src + 1, '.', len - 1)))
2226 return 0;
2227
2228 len -= dot - (const char *)src;
2229
2230 /* XXX: Unless root, skip the label's trailing dot. */
2231 if (len > 1) {
2232 src = ++dot;
2233 len--;
2234 } else
2235 src = dot;
2236
2237 memmove(dst, src, DNS_PP_MIN(lim, len));
2238
2239 if (lim > 0)
2240 ((char *)dst)[DNS_PP_MIN(lim - 1, len)] = '\0';
2241
2242 return len;
2243 } /* dns_d_cleave() */
2244
2245
dns_d_comp(void * dst_,size_t lim,const void * src_,size_t len,struct dns_packet * P,int * error)2246 size_t dns_d_comp(void *dst_, size_t lim, const void *src_, size_t len, struct dns_packet *P, int *error) {
2247 struct { unsigned char *b; size_t p, x; } dst, src;
2248 unsigned char ch = '.';
2249
2250 dst.b = dst_;
2251 dst.p = 0;
2252 dst.x = 1;
2253
2254 src.b = (unsigned char *)src_;
2255 src.p = 0;
2256 src.x = 0;
2257
2258 while (src.x < len) {
2259 ch = src.b[src.x];
2260
2261 if (ch == '.') {
2262 if (dst.p < lim)
2263 dst.b[dst.p] = (0x3f & (src.x - src.p));
2264
2265 dst.p = dst.x++;
2266 src.p = ++src.x;
2267 } else {
2268 if (dst.x < lim)
2269 dst.b[dst.x] = ch;
2270
2271 dst.x++;
2272 src.x++;
2273 }
2274 } /* while() */
2275
2276 if (src.x > src.p) {
2277 if (dst.p < lim)
2278 dst.b[dst.p] = (0x3f & (src.x - src.p));
2279
2280 dst.p = dst.x;
2281 }
2282
2283 if (dst.p > 1) {
2284 if (dst.p < lim)
2285 dst.b[dst.p] = 0x00;
2286
2287 dst.p++;
2288 }
2289
2290 #if 1
2291 if (dst.p < lim) {
2292 struct { unsigned char label[DNS_D_MAXLABEL + 1]; size_t len; unsigned short p, x, y; } a, b;
2293 unsigned i;
2294
2295 a.p = 0;
2296
2297 while ((a.len = dns_l_expand(a.label, sizeof a.label, a.p, &a.x, dst.b, lim))) {
2298 for (i = 0; i < lengthof(P->dict) && P->dict[i]; i++) {
2299 b.p = P->dict[i];
2300
2301 while ((b.len = dns_l_expand(b.label, sizeof b.label, b.p, &b.x, P->data, P->end))) {
2302 a.y = a.x;
2303 b.y = b.x;
2304
2305 while (a.len && b.len && 0 == strcasecmp((char *)a.label, (char *)b.label)) {
2306 a.len = dns_l_expand(a.label, sizeof a.label, a.y, &a.y, dst.b, lim);
2307 b.len = dns_l_expand(b.label, sizeof b.label, b.y, &b.y, P->data, P->end);
2308 }
2309
2310 if (a.len == 0 && b.len == 0 && b.p <= 0x3fff) {
2311 dst.b[a.p++] = 0xc0
2312 | (0x3f & (b.p >> 8));
2313 dst.b[a.p++] = (0xff & (b.p >> 0));
2314
2315 /* silence static analyzers */
2316 dns_assume(a.p > 0);
2317
2318 return a.p;
2319 }
2320
2321 b.p = b.x;
2322 } /* while() */
2323 } /* for() */
2324
2325 a.p = a.x;
2326 } /* while() */
2327 } /* if () */
2328 #endif
2329
2330 if (!dst.p)
2331 *error = DNS_EILLEGAL;
2332
2333 return dst.p;
2334 } /* dns_d_comp() */
2335
2336
dns_d_skip(unsigned short src,struct dns_packet * P)2337 unsigned short dns_d_skip(unsigned short src, struct dns_packet *P) {
2338 unsigned short len;
2339
2340 while (src < P->end) {
2341 switch (0x03 & (P->data[src] >> 6)) {
2342 case 0x00: /* FOLLOWS */
2343 len = (0x3f & P->data[src++]);
2344
2345 if (0 == len) {
2346 /* success ==> */ return src;
2347 } else if (P->end - src > len) {
2348 src += len;
2349
2350 break;
2351 } else
2352 goto invalid;
2353
2354 /* NOT REACHED */
2355 case 0x01: /* RESERVED */
2356 goto invalid;
2357 case 0x02: /* RESERVED */
2358 goto invalid;
2359 case 0x03: /* POINTER */
2360 if (P->end - src < 2)
2361 goto invalid;
2362
2363 src += 2;
2364
2365 /* success ==> */ return src;
2366 } /* switch() */
2367 } /* while() */
2368
2369 invalid:
2370 return P->end;
2371 } /* dns_d_skip() */
2372
2373
2374 #include <stdio.h>
2375
dns_d_expand(void * dst,size_t lim,unsigned short src,struct dns_packet * P,int * error)2376 size_t dns_d_expand(void *dst, size_t lim, unsigned short src, struct dns_packet *P, int *error) {
2377 size_t dstp = 0;
2378 unsigned nptrs = 0;
2379 unsigned char len;
2380
2381 while (src < P->end) {
2382 switch ((0x03 & (P->data[src] >> 6))) {
2383 case 0x00: /* FOLLOWS */
2384 len = (0x3f & P->data[src]);
2385
2386 if (0 == len) {
2387 if (dstp == 0) {
2388 if (dstp < lim)
2389 ((unsigned char *)dst)[dstp] = '.';
2390
2391 dstp++;
2392 }
2393
2394 /* NUL terminate */
2395 if (lim > 0)
2396 ((unsigned char *)dst)[DNS_PP_MIN(dstp, lim - 1)] = '\0';
2397
2398 /* success ==> */ return dstp;
2399 }
2400
2401 src++;
2402
2403 if (P->end - src < len)
2404 goto toolong;
2405
2406 if (dstp < lim)
2407 memcpy(&((unsigned char *)dst)[dstp], &P->data[src], DNS_PP_MIN(len, lim - dstp));
2408
2409 src += len;
2410 dstp += len;
2411
2412 if (dstp < lim)
2413 ((unsigned char *)dst)[dstp] = '.';
2414
2415 dstp++;
2416
2417 nptrs = 0;
2418
2419 continue;
2420 case 0x01: /* RESERVED */
2421 goto reserved;
2422 case 0x02: /* RESERVED */
2423 goto reserved;
2424 case 0x03: /* POINTER */
2425 if (++nptrs > DNS_D_MAXPTRS)
2426 goto toolong;
2427
2428 if (P->end - src < 2)
2429 goto toolong;
2430
2431 src = ((0x3f & P->data[src + 0]) << 8)
2432 | ((0xff & P->data[src + 1]) << 0);
2433
2434 continue;
2435 } /* switch() */
2436 } /* while() */
2437
2438 toolong:
2439 *error = DNS_EILLEGAL;
2440
2441 if (lim > 0)
2442 ((unsigned char *)dst)[DNS_PP_MIN(dstp, lim - 1)] = '\0';
2443
2444 return 0;
2445 reserved:
2446 *error = DNS_EILLEGAL;
2447
2448 if (lim > 0)
2449 ((unsigned char *)dst)[DNS_PP_MIN(dstp, lim - 1)] = '\0';
2450
2451 return 0;
2452 } /* dns_d_expand() */
2453
2454
dns_d_push(struct dns_packet * P,const void * dn,size_t len)2455 int dns_d_push(struct dns_packet *P, const void *dn, size_t len) {
2456 size_t lim = P->size - P->end;
2457 unsigned dp = P->end;
2458 int error = DNS_EILLEGAL; /* silence compiler */
2459
2460 len = dns_d_comp(&P->data[dp], lim, dn, len, P, &error);
2461
2462 if (len == 0)
2463 return error;
2464 if (len > lim)
2465 return DNS_ENOBUFS;
2466
2467 P->end += len;
2468
2469 dns_p_dictadd(P, dp);
2470
2471 return 0;
2472 } /* dns_d_push() */
2473
2474
dns_d_cname(void * dst,size_t lim,const void * dn,size_t len,struct dns_packet * P,int * error_)2475 size_t dns_d_cname(void *dst, size_t lim, const void *dn, size_t len, struct dns_packet *P, int *error_) {
2476 char host[DNS_D_MAXNAME + 1];
2477 struct dns_rr_i i;
2478 struct dns_rr rr;
2479 unsigned depth;
2480 int error;
2481
2482 if (sizeof host <= dns_d_anchor(host, sizeof host, dn, len))
2483 { error = ENAMETOOLONG; goto error; }
2484
2485 for (depth = 0; depth < 7; depth++) {
2486 dns_rr_i_init(memset(&i, 0, sizeof i), P);
2487
2488 i.section = DNS_S_ALL & ~DNS_S_QD;
2489 i.name = host;
2490 i.type = DNS_T_CNAME;
2491
2492 if (!dns_rr_grep(&rr, 1, &i, P, &error))
2493 break;
2494
2495 if ((error = dns_cname_parse((struct dns_cname *)host, &rr, P)))
2496 goto error;
2497 }
2498
2499 return dns_strlcpy(dst, host, lim);
2500 error:
2501 *error_ = error;
2502
2503 return 0;
2504 } /* dns_d_cname() */
2505
2506
2507 /*
2508 * R E S O U R C E R E C O R D R O U T I N E S
2509 *
2510 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2511
dns_rr_copy(struct dns_packet * P,struct dns_rr * rr,struct dns_packet * Q)2512 int dns_rr_copy(struct dns_packet *P, struct dns_rr *rr, struct dns_packet *Q) {
2513 unsigned char dn[DNS_D_MAXNAME + 1];
2514 union dns_any any;
2515 size_t len;
2516 int error;
2517
2518 if (!(len = dns_d_expand(dn, sizeof dn, rr->dn.p, Q, &error)))
2519 return error;
2520 else if (len >= sizeof dn)
2521 return DNS_EILLEGAL;
2522
2523 if (rr->section != DNS_S_QD && (error = dns_any_parse(dns_any_init(&any, sizeof any), rr, Q)))
2524 return error;
2525
2526 return dns_p_push(P, rr->section, dn, len, rr->type, rr->class, rr->ttl, &any);
2527 } /* dns_rr_copy() */
2528
2529
dns_rr_parse(struct dns_rr * rr,unsigned short src,struct dns_packet * P)2530 int dns_rr_parse(struct dns_rr *rr, unsigned short src, struct dns_packet *P) {
2531 unsigned short p = src;
2532
2533 if (src >= P->end)
2534 goto invalid;
2535
2536 rr->dn.p = p;
2537 rr->dn.len = (p = dns_d_skip(p, P)) - rr->dn.p;
2538
2539 if (P->end - p < 4)
2540 goto invalid;
2541
2542 rr->type = ((0xff & P->data[p + 0]) << 8)
2543 | ((0xff & P->data[p + 1]) << 0);
2544
2545 rr->class = ((0xff & P->data[p + 2]) << 8)
2546 | ((0xff & P->data[p + 3]) << 0);
2547
2548 p += 4;
2549
2550 if (src < dns_p_qend(P)) {
2551 rr->section = DNS_S_QUESTION;
2552
2553 rr->ttl = 0;
2554 rr->rd.p = 0;
2555 rr->rd.len = 0;
2556
2557 return 0;
2558 }
2559
2560 if (P->end - p < 4)
2561 goto invalid;
2562
2563 rr->ttl = ((0xff & P->data[p + 0]) << 24)
2564 | ((0xff & P->data[p + 1]) << 16)
2565 | ((0xff & P->data[p + 2]) << 8)
2566 | ((0xff & P->data[p + 3]) << 0);
2567 if (rr->type != DNS_T_OPT)
2568 rr->ttl = DNS_PP_MIN(rr->ttl, 0x7fffffffU);
2569
2570 p += 4;
2571
2572 if (P->end - p < 2)
2573 goto invalid;
2574
2575 rr->rd.len = ((0xff & P->data[p + 0]) << 8)
2576 | ((0xff & P->data[p + 1]) << 0);
2577 rr->rd.p = p + 2;
2578
2579 p += 2;
2580
2581 if (P->end - p < rr->rd.len)
2582 goto invalid;
2583
2584 return 0;
2585 invalid:
2586 return DNS_EILLEGAL;
2587 } /* dns_rr_parse() */
2588
2589
dns_rr_len(const unsigned short src,struct dns_packet * P)2590 static unsigned short dns_rr_len(const unsigned short src, struct dns_packet *P) {
2591 unsigned short rp, rdlen;
2592
2593 rp = dns_d_skip(src, P);
2594
2595 if (P->end - rp < 4)
2596 return P->end - src;
2597
2598 rp += 4; /* TYPE, CLASS */
2599
2600 if (rp <= dns_p_qend(P))
2601 return rp - src;
2602
2603 if (P->end - rp < 6)
2604 return P->end - src;
2605
2606 rp += 6; /* TTL, RDLEN */
2607
2608 rdlen = ((0xff & P->data[rp - 2]) << 8)
2609 | ((0xff & P->data[rp - 1]) << 0);
2610
2611 if (P->end - rp < rdlen)
2612 return P->end - src;
2613
2614 rp += rdlen;
2615
2616 return rp - src;
2617 } /* dns_rr_len() */
2618
2619
dns_rr_skip(unsigned short src,struct dns_packet * P)2620 unsigned short dns_rr_skip(unsigned short src, struct dns_packet *P) {
2621 return src + dns_rr_len(src, P);
2622 } /* dns_rr_skip() */
2623
2624
dns_rr_section(unsigned short src,struct dns_packet * P)2625 static enum dns_section dns_rr_section(unsigned short src, struct dns_packet *P) {
2626 enum dns_section section;
2627 unsigned count, index;
2628 unsigned short rp;
2629
2630 if (src >= P->memo.qd.base && src < P->memo.qd.end)
2631 return DNS_S_QD;
2632 if (src >= P->memo.an.base && src < P->memo.an.end)
2633 return DNS_S_AN;
2634 if (src >= P->memo.ns.base && src < P->memo.ns.end)
2635 return DNS_S_NS;
2636 if (src >= P->memo.ar.base && src < P->memo.ar.end)
2637 return DNS_S_AR;
2638
2639 /* NOTE: Possibly bad memoization. Try it the hard-way. */
2640
2641 for (rp = 12, index = 0; rp < src && rp < P->end; index++)
2642 rp = dns_rr_skip(rp, P);
2643
2644 section = DNS_S_QD;
2645 count = dns_p_count(P, section);
2646
2647 while (index >= count && section <= DNS_S_AR) {
2648 section <<= 1;
2649 count += dns_p_count(P, section);
2650 }
2651
2652 return DNS_S_ALL & section;
2653 } /* dns_rr_section() */
2654
2655
dns_rr_type(unsigned short src,struct dns_packet * P)2656 static enum dns_type dns_rr_type(unsigned short src, struct dns_packet *P) {
2657 struct dns_rr rr;
2658 int error;
2659
2660 if ((error = dns_rr_parse(&rr, src, P)))
2661 return 0;
2662
2663 return rr.type;
2664 } /* dns_rr_type() */
2665
2666
dns_rr_cmp(struct dns_rr * r0,struct dns_packet * P0,struct dns_rr * r1,struct dns_packet * P1)2667 int dns_rr_cmp(struct dns_rr *r0, struct dns_packet *P0, struct dns_rr *r1, struct dns_packet *P1) {
2668 char host0[DNS_D_MAXNAME + 1], host1[DNS_D_MAXNAME + 1];
2669 union dns_any any0, any1;
2670 int cmp, error;
2671 size_t len;
2672
2673 if ((cmp = r0->type - r1->type))
2674 return cmp;
2675
2676 if ((cmp = r0->class - r1->class))
2677 return cmp;
2678
2679 /*
2680 * FIXME: Do label-by-label comparison to handle illegally long names?
2681 */
2682
2683 if (!(len = dns_d_expand(host0, sizeof host0, r0->dn.p, P0, &error))
2684 || len >= sizeof host0)
2685 return -1;
2686
2687 if (!(len = dns_d_expand(host1, sizeof host1, r1->dn.p, P1, &error))
2688 || len >= sizeof host1)
2689 return 1;
2690
2691 if ((cmp = strcasecmp(host0, host1)))
2692 return cmp;
2693
2694 if (DNS_S_QD & (r0->section | r1->section)) {
2695 if (r0->section == r1->section)
2696 return 0;
2697
2698 return (r0->section == DNS_S_QD)? -1 : 1;
2699 }
2700
2701 if ((error = dns_any_parse(&any0, r0, P0)))
2702 return -1;
2703
2704 if ((error = dns_any_parse(&any1, r1, P1)))
2705 return 1;
2706
2707 return dns_any_cmp(&any0, r0->type, &any1, r1->type);
2708 } /* dns_rr_cmp() */
2709
2710
dns_rr_exists(struct dns_rr * rr0,struct dns_packet * P0,struct dns_packet * P1)2711 static _Bool dns_rr_exists(struct dns_rr *rr0, struct dns_packet *P0, struct dns_packet *P1) {
2712 struct dns_rr rr1;
2713
2714 dns_rr_foreach(&rr1, P1, .section = rr0->section, .type = rr0->type) {
2715 if (0 == dns_rr_cmp(rr0, P0, &rr1, P1))
2716 return 1;
2717 }
2718
2719 return 0;
2720 } /* dns_rr_exists() */
2721
2722
dns_rr_offset(struct dns_rr * rr)2723 static unsigned short dns_rr_offset(struct dns_rr *rr) {
2724 return rr->dn.p;
2725 } /* dns_rr_offset() */
2726
2727
dns_rr_i_match(struct dns_rr * rr,struct dns_rr_i * i,struct dns_packet * P)2728 static _Bool dns_rr_i_match(struct dns_rr *rr, struct dns_rr_i *i, struct dns_packet *P) {
2729 if (i->section && !(rr->section & i->section))
2730 return 0;
2731
2732 if (i->type && rr->type != i->type && i->type != DNS_T_ALL)
2733 return 0;
2734
2735 if (i->class && rr->class != i->class && i->class != DNS_C_ANY)
2736 return 0;
2737
2738 if (i->name) {
2739 char dn[DNS_D_MAXNAME + 1];
2740 size_t len;
2741 int error;
2742
2743 if (!(len = dns_d_expand(dn, sizeof dn, rr->dn.p, P, &error))
2744 || len >= sizeof dn)
2745 return 0;
2746
2747 if (0 != strcasecmp(dn, i->name))
2748 return 0;
2749 }
2750
2751 if (i->data && i->type && rr->section > DNS_S_QD) {
2752 union dns_any rd;
2753 int error;
2754
2755 if ((error = dns_any_parse(&rd, rr, P)))
2756 return 0;
2757
2758 if (0 != dns_any_cmp(&rd, rr->type, i->data, i->type))
2759 return 0;
2760 }
2761
2762 return 1;
2763 } /* dns_rr_i_match() */
2764
2765
dns_rr_i_start(struct dns_rr_i * i,struct dns_packet * P)2766 static unsigned short dns_rr_i_start(struct dns_rr_i *i, struct dns_packet *P) {
2767 unsigned short rp;
2768 struct dns_rr r0, rr;
2769 int error;
2770
2771 if ((i->section & DNS_S_QD) && P->memo.qd.base)
2772 rp = P->memo.qd.base;
2773 else if ((i->section & DNS_S_AN) && P->memo.an.base)
2774 rp = P->memo.an.base;
2775 else if ((i->section & DNS_S_NS) && P->memo.ns.base)
2776 rp = P->memo.ns.base;
2777 else if ((i->section & DNS_S_AR) && P->memo.ar.base)
2778 rp = P->memo.ar.base;
2779 else
2780 rp = 12;
2781
2782 for (; rp < P->end; rp = dns_rr_skip(rp, P)) {
2783 if ((error = dns_rr_parse(&rr, rp, P)))
2784 continue;
2785
2786 rr.section = dns_rr_section(rp, P);
2787
2788 if (!dns_rr_i_match(&rr, i, P))
2789 continue;
2790
2791 r0 = rr;
2792
2793 goto lower;
2794 }
2795
2796 return P->end;
2797 lower:
2798 if (i->sort == &dns_rr_i_packet)
2799 return dns_rr_offset(&r0);
2800
2801 while ((rp = dns_rr_skip(rp, P)) < P->end) {
2802 if ((error = dns_rr_parse(&rr, rp, P)))
2803 continue;
2804
2805 rr.section = dns_rr_section(rp, P);
2806
2807 if (!dns_rr_i_match(&rr, i, P))
2808 continue;
2809
2810 if (i->sort(&rr, &r0, i, P) < 0)
2811 r0 = rr;
2812 }
2813
2814 return dns_rr_offset(&r0);
2815 } /* dns_rr_i_start() */
2816
2817
dns_rr_i_skip(unsigned short rp,struct dns_rr_i * i,struct dns_packet * P)2818 static unsigned short dns_rr_i_skip(unsigned short rp, struct dns_rr_i *i, struct dns_packet *P) {
2819 struct dns_rr r0, r1, rr;
2820 int error;
2821
2822 if ((error = dns_rr_parse(&r0, rp, P)))
2823 return P->end;
2824
2825 r0.section = dns_rr_section(rp, P);
2826
2827 rp = (i->sort == &dns_rr_i_packet)? dns_rr_skip(rp, P) : 12;
2828
2829 for (; rp < P->end; rp = dns_rr_skip(rp, P)) {
2830 if ((error = dns_rr_parse(&rr, rp, P)))
2831 continue;
2832
2833 rr.section = dns_rr_section(rp, P);
2834
2835 if (!dns_rr_i_match(&rr, i, P))
2836 continue;
2837
2838 if (i->sort(&rr, &r0, i, P) <= 0)
2839 continue;
2840
2841 r1 = rr;
2842
2843 goto lower;
2844 }
2845
2846 return P->end;
2847 lower:
2848 if (i->sort == &dns_rr_i_packet)
2849 return dns_rr_offset(&r1);
2850
2851 while ((rp = dns_rr_skip(rp, P)) < P->end) {
2852 if ((error = dns_rr_parse(&rr, rp, P)))
2853 continue;
2854
2855 rr.section = dns_rr_section(rp, P);
2856
2857 if (!dns_rr_i_match(&rr, i, P))
2858 continue;
2859
2860 if (i->sort(&rr, &r0, i, P) <= 0)
2861 continue;
2862
2863 if (i->sort(&rr, &r1, i, P) >= 0)
2864 continue;
2865
2866 r1 = rr;
2867 }
2868
2869 return dns_rr_offset(&r1);
2870 } /* dns_rr_i_skip() */
2871
2872
dns_rr_i_packet(struct dns_rr * a,struct dns_rr * b,struct dns_rr_i * i,struct dns_packet * P)2873 int dns_rr_i_packet(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) {
2874 (void)i;
2875 (void)P;
2876
2877 return (int)a->dn.p - (int)b->dn.p;
2878 } /* dns_rr_i_packet() */
2879
2880
dns_rr_i_order(struct dns_rr * a,struct dns_rr * b,struct dns_rr_i * i,struct dns_packet * P)2881 int dns_rr_i_order(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) {
2882 int cmp;
2883
2884 (void)i;
2885
2886 if ((cmp = a->section - b->section))
2887 return cmp;
2888
2889 if (a->type != b->type)
2890 return (int)a->dn.p - (int)b->dn.p;
2891
2892 return dns_rr_cmp(a, P, b, P);
2893 } /* dns_rr_i_order() */
2894
2895
dns_rr_i_shuffle(struct dns_rr * a,struct dns_rr * b,struct dns_rr_i * i,struct dns_packet * P)2896 int dns_rr_i_shuffle(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) {
2897 int cmp;
2898
2899 (void)i;
2900 (void)P;
2901
2902 while (!i->state.regs[0])
2903 i->state.regs[0] = dns_random();
2904
2905 if ((cmp = a->section - b->section))
2906 return cmp;
2907
2908 return dns_k_shuffle16(a->dn.p, i->state.regs[0]) - dns_k_shuffle16(b->dn.p, i->state.regs[0]);
2909 } /* dns_rr_i_shuffle() */
2910
2911
dns_rr_i_init(struct dns_rr_i * i,struct dns_packet * P)2912 struct dns_rr_i *dns_rr_i_init(struct dns_rr_i *i, struct dns_packet *P) {
2913 static const struct dns_rr_i i_initializer;
2914
2915 (void)P;
2916
2917 i->state = i_initializer.state;
2918 i->saved = i->state;
2919
2920 return i;
2921 } /* dns_rr_i_init() */
2922
2923
dns_rr_grep(struct dns_rr * rr,unsigned lim,struct dns_rr_i * i,struct dns_packet * P,int * error_)2924 unsigned dns_rr_grep(struct dns_rr *rr, unsigned lim, struct dns_rr_i *i, struct dns_packet *P, int *error_) {
2925 unsigned count = 0;
2926 int error;
2927
2928 switch (i->state.exec) {
2929 case 0:
2930 if (!i->sort)
2931 i->sort = &dns_rr_i_packet;
2932
2933 i->state.next = dns_rr_i_start(i, P);
2934 i->state.exec++;
2935
2936 /* FALL THROUGH */
2937 case 1:
2938 while (count < lim && i->state.next < P->end) {
2939 if ((error = dns_rr_parse(rr, i->state.next, P)))
2940 goto error;
2941
2942 rr->section = dns_rr_section(i->state.next, P);
2943
2944 rr++;
2945 count++;
2946 i->state.count++;
2947
2948 i->state.next = dns_rr_i_skip(i->state.next, i, P);
2949 } /* while() */
2950
2951 break;
2952 } /* switch() */
2953
2954 return count;
2955 error:
2956 *error_ = error;
2957
2958 return count;
2959 } /* dns_rr_grep() */
2960
2961
dns_rr_print(void * _dst,size_t lim,struct dns_rr * rr,struct dns_packet * P,int * _error)2962 size_t dns_rr_print(void *_dst, size_t lim, struct dns_rr *rr, struct dns_packet *P, int *_error) {
2963 struct dns_buf dst = DNS_B_INTO(_dst, lim);
2964 union dns_any any;
2965 size_t n;
2966 int error;
2967
2968 if (rr->section == DNS_S_QD)
2969 dns_b_putc(&dst, ';');
2970
2971 if (!(n = dns_d_expand(any.ns.host, sizeof any.ns.host, rr->dn.p, P, &error)))
2972 goto error;
2973 dns_b_put(&dst, any.ns.host, DNS_PP_MIN(n, sizeof any.ns.host - 1));
2974
2975 if (rr->section != DNS_S_QD) {
2976 dns_b_putc(&dst, ' ');
2977 dns_b_fmtju(&dst, rr->ttl, 0);
2978 }
2979
2980 dns_b_putc(&dst, ' ');
2981 dns_b_puts(&dst, dns_strclass(rr->class));
2982 dns_b_putc(&dst, ' ');
2983 dns_b_puts(&dst, dns_strtype(rr->type));
2984
2985 if (rr->section == DNS_S_QD)
2986 goto epilog;
2987
2988 dns_b_putc(&dst, ' ');
2989
2990 if ((error = dns_any_parse(dns_any_init(&any, sizeof any), rr, P)))
2991 goto error;
2992
2993 n = dns_any_print(dst.p, dst.pe - dst.p, &any, rr->type);
2994 dst.p += DNS_PP_MIN(n, (size_t)(dst.pe - dst.p));
2995 epilog:
2996 return dns_b_strllen(&dst);
2997 error:
2998 *_error = error;
2999
3000 return 0;
3001 } /* dns_rr_print() */
3002
3003
dns_a_parse(struct dns_a * a,struct dns_rr * rr,struct dns_packet * P)3004 int dns_a_parse(struct dns_a *a, struct dns_rr *rr, struct dns_packet *P) {
3005 unsigned long addr;
3006
3007 if (rr->rd.len != 4)
3008 return DNS_EILLEGAL;
3009
3010 addr = ((0xffU & P->data[rr->rd.p + 0]) << 24)
3011 | ((0xffU & P->data[rr->rd.p + 1]) << 16)
3012 | ((0xffU & P->data[rr->rd.p + 2]) << 8)
3013 | ((0xffU & P->data[rr->rd.p + 3]) << 0);
3014
3015 a->addr.s_addr = htonl(addr);
3016
3017 return 0;
3018 } /* dns_a_parse() */
3019
3020
dns_a_push(struct dns_packet * P,struct dns_a * a)3021 int dns_a_push(struct dns_packet *P, struct dns_a *a) {
3022 unsigned long addr;
3023
3024 if (P->size - P->end < 6)
3025 return DNS_ENOBUFS;
3026
3027 P->data[P->end++] = 0x00;
3028 P->data[P->end++] = 0x04;
3029
3030 addr = ntohl(a->addr.s_addr);
3031
3032 P->data[P->end++] = 0xffU & (addr >> 24);
3033 P->data[P->end++] = 0xffU & (addr >> 16);
3034 P->data[P->end++] = 0xffU & (addr >> 8);
3035 P->data[P->end++] = 0xffU & (addr >> 0);
3036
3037 return 0;
3038 } /* dns_a_push() */
3039
3040
dns_a_arpa(void * _dst,size_t lim,const struct dns_a * a)3041 size_t dns_a_arpa(void *_dst, size_t lim, const struct dns_a *a) {
3042 struct dns_buf dst = DNS_B_INTO(_dst, lim);
3043 unsigned long octets = ntohl(a->addr.s_addr);
3044 unsigned i;
3045
3046 for (i = 0; i < 4; i++) {
3047 dns_b_fmtju(&dst, 0xff & octets, 0);
3048 dns_b_putc(&dst, '.');
3049 octets >>= 8;
3050 }
3051
3052 dns_b_puts(&dst, "in-addr.arpa.");
3053
3054 return dns_b_strllen(&dst);
3055 } /* dns_a_arpa() */
3056
3057
dns_a_cmp(const struct dns_a * a,const struct dns_a * b)3058 int dns_a_cmp(const struct dns_a *a, const struct dns_a *b) {
3059 if (ntohl(a->addr.s_addr) < ntohl(b->addr.s_addr))
3060 return -1;
3061 if (ntohl(a->addr.s_addr) > ntohl(b->addr.s_addr))
3062 return 1;
3063
3064 return 0;
3065 } /* dns_a_cmp() */
3066
3067
dns_a_print(void * dst,size_t lim,struct dns_a * a)3068 size_t dns_a_print(void *dst, size_t lim, struct dns_a *a) {
3069 char addr[INET_ADDRSTRLEN + 1] = "0.0.0.0";
3070
3071 dns_inet_ntop(AF_INET, &a->addr, addr, sizeof addr);
3072
3073 return dns_strlcpy(dst, addr, lim);
3074 } /* dns_a_print() */
3075
3076
dns_aaaa_parse(struct dns_aaaa * aaaa,struct dns_rr * rr,struct dns_packet * P)3077 int dns_aaaa_parse(struct dns_aaaa *aaaa, struct dns_rr *rr, struct dns_packet *P) {
3078 if (rr->rd.len != sizeof aaaa->addr.s6_addr)
3079 return DNS_EILLEGAL;
3080
3081 memcpy(aaaa->addr.s6_addr, &P->data[rr->rd.p], sizeof aaaa->addr.s6_addr);
3082
3083 return 0;
3084 } /* dns_aaaa_parse() */
3085
3086
dns_aaaa_push(struct dns_packet * P,struct dns_aaaa * aaaa)3087 int dns_aaaa_push(struct dns_packet *P, struct dns_aaaa *aaaa) {
3088 if (P->size - P->end < 2 + sizeof aaaa->addr.s6_addr)
3089 return DNS_ENOBUFS;
3090
3091 P->data[P->end++] = 0x00;
3092 P->data[P->end++] = 0x10;
3093
3094 memcpy(&P->data[P->end], aaaa->addr.s6_addr, sizeof aaaa->addr.s6_addr);
3095
3096 P->end += sizeof aaaa->addr.s6_addr;
3097
3098 return 0;
3099 } /* dns_aaaa_push() */
3100
3101
dns_aaaa_cmp(const struct dns_aaaa * a,const struct dns_aaaa * b)3102 int dns_aaaa_cmp(const struct dns_aaaa *a, const struct dns_aaaa *b) {
3103 unsigned i;
3104 int cmp;
3105
3106 for (i = 0; i < lengthof(a->addr.s6_addr); i++) {
3107 if ((cmp = (a->addr.s6_addr[i] - b->addr.s6_addr[i])))
3108 return cmp;
3109 }
3110
3111 return 0;
3112 } /* dns_aaaa_cmp() */
3113
3114
dns_aaaa_arpa(void * _dst,size_t lim,const struct dns_aaaa * aaaa)3115 size_t dns_aaaa_arpa(void *_dst, size_t lim, const struct dns_aaaa *aaaa) {
3116 static const unsigned char hex[16] = "0123456789abcdef";
3117 struct dns_buf dst = DNS_B_INTO(_dst, lim);
3118 unsigned nyble;
3119 int i, j;
3120
3121 for (i = sizeof aaaa->addr.s6_addr - 1; i >= 0; i--) {
3122 nyble = aaaa->addr.s6_addr[i];
3123
3124 for (j = 0; j < 2; j++) {
3125 dns_b_putc(&dst, hex[0x0f & nyble]);
3126 dns_b_putc(&dst, '.');
3127 nyble >>= 4;
3128 }
3129 }
3130
3131 dns_b_puts(&dst, "ip6.arpa.");
3132
3133 return dns_b_strllen(&dst);
3134 } /* dns_aaaa_arpa() */
3135
3136
dns_aaaa_print(void * dst,size_t lim,struct dns_aaaa * aaaa)3137 size_t dns_aaaa_print(void *dst, size_t lim, struct dns_aaaa *aaaa) {
3138 char addr[INET6_ADDRSTRLEN + 1] = "::";
3139
3140 dns_inet_ntop(AF_INET6, &aaaa->addr, addr, sizeof addr);
3141
3142 return dns_strlcpy(dst, addr, lim);
3143 } /* dns_aaaa_print() */
3144
3145
dns_mx_parse(struct dns_mx * mx,struct dns_rr * rr,struct dns_packet * P)3146 int dns_mx_parse(struct dns_mx *mx, struct dns_rr *rr, struct dns_packet *P) {
3147 size_t len;
3148 int error;
3149
3150 if (rr->rd.len < 3)
3151 return DNS_EILLEGAL;
3152
3153 mx->preference = (0xff00 & (P->data[rr->rd.p + 0] << 8))
3154 | (0x00ff & (P->data[rr->rd.p + 1] << 0));
3155
3156 if (!(len = dns_d_expand(mx->host, sizeof mx->host, rr->rd.p + 2, P, &error)))
3157 return error;
3158 else if (len >= sizeof mx->host)
3159 return DNS_EILLEGAL;
3160
3161 return 0;
3162 } /* dns_mx_parse() */
3163
3164
dns_mx_push(struct dns_packet * P,struct dns_mx * mx)3165 int dns_mx_push(struct dns_packet *P, struct dns_mx *mx) {
3166 size_t end, len;
3167 int error;
3168
3169 if (P->size - P->end < 5)
3170 return DNS_ENOBUFS;
3171
3172 end = P->end;
3173 P->end += 2;
3174
3175 P->data[P->end++] = 0xff & (mx->preference >> 8);
3176 P->data[P->end++] = 0xff & (mx->preference >> 0);
3177
3178 if ((error = dns_d_push(P, mx->host, strlen(mx->host))))
3179 goto error;
3180
3181 len = P->end - end - 2;
3182
3183 P->data[end + 0] = 0xff & (len >> 8);
3184 P->data[end + 1] = 0xff & (len >> 0);
3185
3186 return 0;
3187 error:
3188 P->end = end;
3189
3190 return error;
3191 } /* dns_mx_push() */
3192
3193
dns_mx_cmp(const struct dns_mx * a,const struct dns_mx * b)3194 int dns_mx_cmp(const struct dns_mx *a, const struct dns_mx *b) {
3195 int cmp;
3196
3197 if ((cmp = a->preference - b->preference))
3198 return cmp;
3199
3200 return strcasecmp(a->host, b->host);
3201 } /* dns_mx_cmp() */
3202
3203
dns_mx_print(void * _dst,size_t lim,struct dns_mx * mx)3204 size_t dns_mx_print(void *_dst, size_t lim, struct dns_mx *mx) {
3205 struct dns_buf dst = DNS_B_INTO(_dst, lim);
3206
3207 dns_b_fmtju(&dst, mx->preference, 0);
3208 dns_b_putc(&dst, ' ');
3209 dns_b_puts(&dst, mx->host);
3210
3211 return dns_b_strllen(&dst);
3212 } /* dns_mx_print() */
3213
3214
dns_mx_cname(void * dst,size_t lim,struct dns_mx * mx)3215 size_t dns_mx_cname(void *dst, size_t lim, struct dns_mx *mx) {
3216 return dns_strlcpy(dst, mx->host, lim);
3217 } /* dns_mx_cname() */
3218
3219
dns_ns_parse(struct dns_ns * ns,struct dns_rr * rr,struct dns_packet * P)3220 int dns_ns_parse(struct dns_ns *ns, struct dns_rr *rr, struct dns_packet *P) {
3221 size_t len;
3222 int error;
3223
3224 if (!(len = dns_d_expand(ns->host, sizeof ns->host, rr->rd.p, P, &error)))
3225 return error;
3226 else if (len >= sizeof ns->host)
3227 return DNS_EILLEGAL;
3228
3229 return 0;
3230 } /* dns_ns_parse() */
3231
3232
dns_ns_push(struct dns_packet * P,struct dns_ns * ns)3233 int dns_ns_push(struct dns_packet *P, struct dns_ns *ns) {
3234 size_t end, len;
3235 int error;
3236
3237 if (P->size - P->end < 3)
3238 return DNS_ENOBUFS;
3239
3240 end = P->end;
3241 P->end += 2;
3242
3243 if ((error = dns_d_push(P, ns->host, strlen(ns->host))))
3244 goto error;
3245
3246 len = P->end - end - 2;
3247
3248 P->data[end + 0] = 0xff & (len >> 8);
3249 P->data[end + 1] = 0xff & (len >> 0);
3250
3251 return 0;
3252 error:
3253 P->end = end;
3254
3255 return error;
3256 } /* dns_ns_push() */
3257
3258
dns_ns_cmp(const struct dns_ns * a,const struct dns_ns * b)3259 int dns_ns_cmp(const struct dns_ns *a, const struct dns_ns *b) {
3260 return strcasecmp(a->host, b->host);
3261 } /* dns_ns_cmp() */
3262
3263
dns_ns_print(void * dst,size_t lim,struct dns_ns * ns)3264 size_t dns_ns_print(void *dst, size_t lim, struct dns_ns *ns) {
3265 return dns_strlcpy(dst, ns->host, lim);
3266 } /* dns_ns_print() */
3267
3268
dns_ns_cname(void * dst,size_t lim,struct dns_ns * ns)3269 size_t dns_ns_cname(void *dst, size_t lim, struct dns_ns *ns) {
3270 return dns_strlcpy(dst, ns->host, lim);
3271 } /* dns_ns_cname() */
3272
3273
dns_cname_parse(struct dns_cname * cname,struct dns_rr * rr,struct dns_packet * P)3274 int dns_cname_parse(struct dns_cname *cname, struct dns_rr *rr, struct dns_packet *P) {
3275 return dns_ns_parse((struct dns_ns *)cname, rr, P);
3276 } /* dns_cname_parse() */
3277
3278
dns_cname_push(struct dns_packet * P,struct dns_cname * cname)3279 int dns_cname_push(struct dns_packet *P, struct dns_cname *cname) {
3280 return dns_ns_push(P, (struct dns_ns *)cname);
3281 } /* dns_cname_push() */
3282
3283
dns_cname_cmp(const struct dns_cname * a,const struct dns_cname * b)3284 int dns_cname_cmp(const struct dns_cname *a, const struct dns_cname *b) {
3285 return strcasecmp(a->host, b->host);
3286 } /* dns_cname_cmp() */
3287
3288
dns_cname_print(void * dst,size_t lim,struct dns_cname * cname)3289 size_t dns_cname_print(void *dst, size_t lim, struct dns_cname *cname) {
3290 return dns_ns_print(dst, lim, (struct dns_ns *)cname);
3291 } /* dns_cname_print() */
3292
3293
dns_cname_cname(void * dst,size_t lim,struct dns_cname * cname)3294 size_t dns_cname_cname(void *dst, size_t lim, struct dns_cname *cname) {
3295 return dns_strlcpy(dst, cname->host, lim);
3296 } /* dns_cname_cname() */
3297
3298
dns_soa_parse(struct dns_soa * soa,struct dns_rr * rr,struct dns_packet * P)3299 int dns_soa_parse(struct dns_soa *soa, struct dns_rr *rr, struct dns_packet *P) {
3300 struct { void *dst; size_t lim; } dn[] =
3301 { { soa->mname, sizeof soa->mname },
3302 { soa->rname, sizeof soa->rname } };
3303 unsigned *ts[] =
3304 { &soa->serial, &soa->refresh, &soa->retry, &soa->expire, &soa->minimum };
3305 unsigned short rp;
3306 unsigned i, j, n;
3307 int error;
3308
3309 /* MNAME / RNAME */
3310 if ((rp = rr->rd.p) >= P->end)
3311 return DNS_EILLEGAL;
3312
3313 for (i = 0; i < lengthof(dn); i++) {
3314 if (!(n = dns_d_expand(dn[i].dst, dn[i].lim, rp, P, &error)))
3315 return error;
3316 else if (n >= dn[i].lim)
3317 return DNS_EILLEGAL;
3318
3319 if ((rp = dns_d_skip(rp, P)) >= P->end)
3320 return DNS_EILLEGAL;
3321 }
3322
3323 /* SERIAL / REFRESH / RETRY / EXPIRE / MINIMUM */
3324 for (i = 0; i < lengthof(ts); i++) {
3325 for (j = 0; j < 4; j++, rp++) {
3326 if (rp >= P->end)
3327 return DNS_EILLEGAL;
3328
3329 *ts[i] <<= 8;
3330 *ts[i] |= (0xff & P->data[rp]);
3331 }
3332 }
3333
3334 return 0;
3335 } /* dns_soa_parse() */
3336
3337
dns_soa_push(struct dns_packet * P,struct dns_soa * soa)3338 int dns_soa_push(struct dns_packet *P, struct dns_soa *soa) {
3339 void *dn[] = { soa->mname, soa->rname };
3340 unsigned ts[] = { (0xffffffff & soa->serial),
3341 (0x7fffffff & soa->refresh),
3342 (0x7fffffff & soa->retry),
3343 (0x7fffffff & soa->expire),
3344 (0xffffffff & soa->minimum) };
3345 unsigned i, j;
3346 size_t end, len;
3347 int error;
3348
3349 end = P->end;
3350
3351 if ((P->end += 2) >= P->size)
3352 goto toolong;
3353
3354 /* MNAME / RNAME */
3355 for (i = 0; i < lengthof(dn); i++) {
3356 if ((error = dns_d_push(P, dn[i], strlen(dn[i]))))
3357 goto error;
3358 }
3359
3360 /* SERIAL / REFRESH / RETRY / EXPIRE / MINIMUM */
3361 for (i = 0; i < lengthof(ts); i++) {
3362 if ((P->end += 4) >= P->size)
3363 goto toolong;
3364
3365 for (j = 1; j <= 4; j++) {
3366 P->data[P->end - j] = (0xff & ts[i]);
3367 ts[i] >>= 8;
3368 }
3369 }
3370
3371 len = P->end - end - 2;
3372 P->data[end + 0] = (0xff & (len >> 8));
3373 P->data[end + 1] = (0xff & (len >> 0));
3374
3375 return 0;
3376 toolong:
3377 error = DNS_ENOBUFS;
3378
3379 /* FALL THROUGH */
3380 error:
3381 P->end = end;
3382
3383 return error;
3384 } /* dns_soa_push() */
3385
3386
dns_soa_cmp(const struct dns_soa * a,const struct dns_soa * b)3387 int dns_soa_cmp(const struct dns_soa *a, const struct dns_soa *b) {
3388 int cmp;
3389
3390 if ((cmp = strcasecmp(a->mname, b->mname)))
3391 return cmp;
3392
3393 if ((cmp = strcasecmp(a->rname, b->rname)))
3394 return cmp;
3395
3396 if (a->serial > b->serial)
3397 return -1;
3398 else if (a->serial < b->serial)
3399 return 1;
3400
3401 if (a->refresh > b->refresh)
3402 return -1;
3403 else if (a->refresh < b->refresh)
3404 return 1;
3405
3406 if (a->retry > b->retry)
3407 return -1;
3408 else if (a->retry < b->retry)
3409 return 1;
3410
3411 if (a->expire > b->expire)
3412 return -1;
3413 else if (a->expire < b->expire)
3414 return 1;
3415
3416 if (a->minimum > b->minimum)
3417 return -1;
3418 else if (a->minimum < b->minimum)
3419 return 1;
3420
3421 return 0;
3422 } /* dns_soa_cmp() */
3423
3424
dns_soa_print(void * _dst,size_t lim,struct dns_soa * soa)3425 size_t dns_soa_print(void *_dst, size_t lim, struct dns_soa *soa) {
3426 struct dns_buf dst = DNS_B_INTO(_dst, lim);
3427
3428 dns_b_puts(&dst, soa->mname);
3429 dns_b_putc(&dst, ' ');
3430 dns_b_puts(&dst, soa->rname);
3431 dns_b_putc(&dst, ' ');
3432 dns_b_fmtju(&dst, soa->serial, 0);
3433 dns_b_putc(&dst, ' ');
3434 dns_b_fmtju(&dst, soa->refresh, 0);
3435 dns_b_putc(&dst, ' ');
3436 dns_b_fmtju(&dst, soa->retry, 0);
3437 dns_b_putc(&dst, ' ');
3438 dns_b_fmtju(&dst, soa->expire, 0);
3439 dns_b_putc(&dst, ' ');
3440 dns_b_fmtju(&dst, soa->minimum, 0);
3441
3442 return dns_b_strllen(&dst);
3443 } /* dns_soa_print() */
3444
3445
dns_srv_parse(struct dns_srv * srv,struct dns_rr * rr,struct dns_packet * P)3446 int dns_srv_parse(struct dns_srv *srv, struct dns_rr *rr, struct dns_packet *P) {
3447 unsigned short rp;
3448 unsigned i;
3449 size_t n;
3450 int error;
3451
3452 memset(srv, '\0', sizeof *srv);
3453
3454 rp = rr->rd.p;
3455
3456 if (rr->rd.len < 7)
3457 return DNS_EILLEGAL;
3458
3459 for (i = 0; i < 2; i++, rp++) {
3460 srv->priority <<= 8;
3461 srv->priority |= (0xff & P->data[rp]);
3462 }
3463
3464 for (i = 0; i < 2; i++, rp++) {
3465 srv->weight <<= 8;
3466 srv->weight |= (0xff & P->data[rp]);
3467 }
3468
3469 for (i = 0; i < 2; i++, rp++) {
3470 srv->port <<= 8;
3471 srv->port |= (0xff & P->data[rp]);
3472 }
3473
3474 if (!(n = dns_d_expand(srv->target, sizeof srv->target, rp, P, &error)))
3475 return error;
3476 else if (n >= sizeof srv->target)
3477 return DNS_EILLEGAL;
3478
3479 return 0;
3480 } /* dns_srv_parse() */
3481
3482
dns_srv_push(struct dns_packet * P,struct dns_srv * srv)3483 int dns_srv_push(struct dns_packet *P, struct dns_srv *srv) {
3484 size_t end, len;
3485 int error;
3486
3487 end = P->end;
3488
3489 if (P->size - P->end < 2)
3490 goto toolong;
3491
3492 P->end += 2;
3493
3494 if (P->size - P->end < 6)
3495 goto toolong;
3496
3497 P->data[P->end++] = 0xff & (srv->priority >> 8);
3498 P->data[P->end++] = 0xff & (srv->priority >> 0);
3499
3500 P->data[P->end++] = 0xff & (srv->weight >> 8);
3501 P->data[P->end++] = 0xff & (srv->weight >> 0);
3502
3503 P->data[P->end++] = 0xff & (srv->port >> 8);
3504 P->data[P->end++] = 0xff & (srv->port >> 0);
3505
3506 if (0 == (len = dns_d_comp(&P->data[P->end], P->size - P->end, srv->target, strlen(srv->target), P, &error)))
3507 goto error;
3508 else if (P->size - P->end < len)
3509 goto toolong;
3510
3511 P->end += len;
3512
3513 if (P->end > 65535)
3514 goto toolong;
3515
3516 len = P->end - end - 2;
3517
3518 P->data[end + 0] = 0xff & (len >> 8);
3519 P->data[end + 1] = 0xff & (len >> 0);
3520
3521 return 0;
3522 toolong:
3523 error = DNS_ENOBUFS;
3524
3525 /* FALL THROUGH */
3526 error:
3527 P->end = end;
3528
3529 return error;
3530 } /* dns_srv_push() */
3531
3532
dns_srv_cmp(const struct dns_srv * a,const struct dns_srv * b)3533 int dns_srv_cmp(const struct dns_srv *a, const struct dns_srv *b) {
3534 int cmp;
3535
3536 if ((cmp = a->priority - b->priority))
3537 return cmp;
3538
3539 /*
3540 * FIXME: We need some sort of random seed to implement the dynamic
3541 * weighting required by RFC 2782.
3542 */
3543 if ((cmp = a->weight - b->weight))
3544 return cmp;
3545
3546 if ((cmp = a->port - b->port))
3547 return cmp;
3548
3549 return strcasecmp(a->target, b->target);
3550 } /* dns_srv_cmp() */
3551
3552
dns_srv_print(void * _dst,size_t lim,struct dns_srv * srv)3553 size_t dns_srv_print(void *_dst, size_t lim, struct dns_srv *srv) {
3554 struct dns_buf dst = DNS_B_INTO(_dst, lim);
3555
3556 dns_b_fmtju(&dst, srv->priority, 0);
3557 dns_b_putc(&dst, ' ');
3558 dns_b_fmtju(&dst, srv->weight, 0);
3559 dns_b_putc(&dst, ' ');
3560 dns_b_fmtju(&dst, srv->port, 0);
3561 dns_b_putc(&dst, ' ');
3562 dns_b_puts(&dst, srv->target);
3563
3564 return dns_b_strllen(&dst);
3565 } /* dns_srv_print() */
3566
3567
dns_srv_cname(void * dst,size_t lim,struct dns_srv * srv)3568 size_t dns_srv_cname(void *dst, size_t lim, struct dns_srv *srv) {
3569 return dns_strlcpy(dst, srv->target, lim);
3570 } /* dns_srv_cname() */
3571
3572
dns_opt_ttl(const struct dns_opt * opt)3573 unsigned int dns_opt_ttl(const struct dns_opt *opt) {
3574 unsigned int ttl = 0;
3575
3576 ttl |= (0xffU & opt->rcode) << 24;
3577 ttl |= (0xffU & opt->version) << 16;
3578 ttl |= (0xffffU & opt->flags) << 0;
3579
3580 return ttl;
3581 } /* dns_opt_ttl() */
3582
3583
dns_opt_class(const struct dns_opt * opt)3584 unsigned short dns_opt_class(const struct dns_opt *opt) {
3585 return opt->maxudp;
3586 } /* dns_opt_class() */
3587
3588
dns_opt_init(struct dns_opt * opt,size_t size)3589 struct dns_opt *dns_opt_init(struct dns_opt *opt, size_t size) {
3590 assert(size >= offsetof(struct dns_opt, data));
3591
3592 opt->size = size - offsetof(struct dns_opt, data);
3593 opt->len = 0;
3594
3595 opt->rcode = 0;
3596 opt->version = 0;
3597 opt->maxudp = 0;
3598
3599 return opt;
3600 } /* dns_opt_init() */
3601
3602
dns_opt_initany(union dns_any * any,size_t size)3603 static union dns_any *dns_opt_initany(union dns_any *any, size_t size) {
3604 return dns_opt_init(&any->opt, size), any;
3605 } /* dns_opt_initany() */
3606
3607
dns_opt_parse(struct dns_opt * opt,struct dns_rr * rr,struct dns_packet * P)3608 int dns_opt_parse(struct dns_opt *opt, struct dns_rr *rr, struct dns_packet *P) {
3609 const struct dns_buf src = DNS_B_FROM(&P->data[rr->rd.p], rr->rd.len);
3610 struct dns_buf dst = DNS_B_INTO(opt->data, opt->size);
3611 int error;
3612
3613 opt->rcode = 0xfff & ((rr->ttl >> 20) | dns_header(P)->rcode);
3614 opt->version = 0xff & (rr->ttl >> 16);
3615 opt->flags = 0xffff & rr->ttl;
3616 opt->maxudp = 0xffff & rr->class;
3617
3618 while (src.p < src.pe) {
3619 int code, len;
3620
3621 if (-1 == (code = dns_b_get16(&src, -1)))
3622 return src.error;
3623 if (-1 == (len = dns_b_get16(&src, -1)))
3624 return src.error;
3625
3626 switch (code) {
3627 default:
3628 dns_b_put16(&dst, code);
3629 dns_b_put16(&dst, len);
3630 if ((error = dns_b_move(&dst, &src, len)))
3631 return error;
3632 break;
3633 }
3634 }
3635
3636 return 0;
3637 } /* dns_opt_parse() */
3638
3639
dns_opt_push(struct dns_packet * P,struct dns_opt * opt)3640 int dns_opt_push(struct dns_packet *P, struct dns_opt *opt) {
3641 const struct dns_buf src = DNS_B_FROM(opt->data, opt->len);
3642 struct dns_buf dst = DNS_B_INTO(&P->data[P->end], (P->size - P->end));
3643 int error;
3644
3645 /* rdata length (see below) */
3646 if ((error = dns_b_put16(&dst, 0)))
3647 goto error;
3648
3649 /* ... push known options here */
3650
3651 /* push opaque option data */
3652 if ((error = dns_b_move(&dst, &src, (size_t)(src.pe - src.p))))
3653 goto error;
3654
3655 /* rdata length */
3656 if ((error = dns_b_pput16(&dst, dns_b_tell(&dst) - 2, 0)))
3657 goto error;
3658
3659 #if !DNS_DEBUG_OPT_FORMERR
3660 P->end += dns_b_tell(&dst);
3661 #endif
3662
3663 return 0;
3664 error:
3665 return error;
3666 } /* dns_opt_push() */
3667
3668
dns_opt_cmp(const struct dns_opt * a,const struct dns_opt * b)3669 int dns_opt_cmp(const struct dns_opt *a, const struct dns_opt *b) {
3670 (void)a;
3671 (void)b;
3672
3673 return -1;
3674 } /* dns_opt_cmp() */
3675
3676
dns_opt_print(void * _dst,size_t lim,struct dns_opt * opt)3677 size_t dns_opt_print(void *_dst, size_t lim, struct dns_opt *opt) {
3678 struct dns_buf dst = DNS_B_INTO(_dst, lim);
3679 size_t p;
3680
3681 dns_b_putc(&dst, '"');
3682
3683 for (p = 0; p < opt->len; p++) {
3684 dns_b_putc(&dst, '\\');
3685 dns_b_fmtju(&dst, opt->data[p], 3);
3686 }
3687
3688 dns_b_putc(&dst, '"');
3689
3690 return dns_b_strllen(&dst);
3691 } /* dns_opt_print() */
3692
3693
dns_ptr_parse(struct dns_ptr * ptr,struct dns_rr * rr,struct dns_packet * P)3694 int dns_ptr_parse(struct dns_ptr *ptr, struct dns_rr *rr, struct dns_packet *P) {
3695 return dns_ns_parse((struct dns_ns *)ptr, rr, P);
3696 } /* dns_ptr_parse() */
3697
3698
dns_ptr_push(struct dns_packet * P,struct dns_ptr * ptr)3699 int dns_ptr_push(struct dns_packet *P, struct dns_ptr *ptr) {
3700 return dns_ns_push(P, (struct dns_ns *)ptr);
3701 } /* dns_ptr_push() */
3702
3703
dns_ptr_qname(void * dst,size_t lim,int af,void * addr)3704 size_t dns_ptr_qname(void *dst, size_t lim, int af, void *addr) {
3705 switch (af) {
3706 case AF_INET6:
3707 return dns_aaaa_arpa(dst, lim, addr);
3708 case AF_INET:
3709 return dns_a_arpa(dst, lim, addr);
3710 default: {
3711 struct dns_a a;
3712 a.addr.s_addr = INADDR_NONE;
3713 return dns_a_arpa(dst, lim, &a);
3714 }
3715 }
3716 } /* dns_ptr_qname() */
3717
3718
dns_ptr_cmp(const struct dns_ptr * a,const struct dns_ptr * b)3719 int dns_ptr_cmp(const struct dns_ptr *a, const struct dns_ptr *b) {
3720 return strcasecmp(a->host, b->host);
3721 } /* dns_ptr_cmp() */
3722
3723
dns_ptr_print(void * dst,size_t lim,struct dns_ptr * ptr)3724 size_t dns_ptr_print(void *dst, size_t lim, struct dns_ptr *ptr) {
3725 return dns_ns_print(dst, lim, (struct dns_ns *)ptr);
3726 } /* dns_ptr_print() */
3727
3728
dns_ptr_cname(void * dst,size_t lim,struct dns_ptr * ptr)3729 size_t dns_ptr_cname(void *dst, size_t lim, struct dns_ptr *ptr) {
3730 return dns_strlcpy(dst, ptr->host, lim);
3731 } /* dns_ptr_cname() */
3732
3733
dns_sshfp_parse(struct dns_sshfp * fp,struct dns_rr * rr,struct dns_packet * P)3734 int dns_sshfp_parse(struct dns_sshfp *fp, struct dns_rr *rr, struct dns_packet *P) {
3735 unsigned p = rr->rd.p, pe = rr->rd.p + rr->rd.len;
3736
3737 if (pe - p < 2)
3738 return DNS_EILLEGAL;
3739
3740 fp->algo = P->data[p++];
3741 fp->type = P->data[p++];
3742
3743 switch (fp->type) {
3744 case DNS_SSHFP_SHA1:
3745 if (pe - p < sizeof fp->digest.sha1)
3746 return DNS_EILLEGAL;
3747
3748 memcpy(fp->digest.sha1, &P->data[p], sizeof fp->digest.sha1);
3749
3750 break;
3751 default:
3752 break;
3753 } /* switch() */
3754
3755 return 0;
3756 } /* dns_sshfp_parse() */
3757
3758
dns_sshfp_push(struct dns_packet * P,struct dns_sshfp * fp)3759 int dns_sshfp_push(struct dns_packet *P, struct dns_sshfp *fp) {
3760 unsigned p = P->end, pe = P->size, n;
3761
3762 if (pe - p < 4)
3763 return DNS_ENOBUFS;
3764
3765 p += 2;
3766 P->data[p++] = 0xff & fp->algo;
3767 P->data[p++] = 0xff & fp->type;
3768
3769 switch (fp->type) {
3770 case DNS_SSHFP_SHA1:
3771 if (pe - p < sizeof fp->digest.sha1)
3772 return DNS_ENOBUFS;
3773
3774 memcpy(&P->data[p], fp->digest.sha1, sizeof fp->digest.sha1);
3775 p += sizeof fp->digest.sha1;
3776
3777 break;
3778 default:
3779 return DNS_EILLEGAL;
3780 } /* switch() */
3781
3782 n = p - P->end - 2;
3783 P->data[P->end++] = 0xff & (n >> 8);
3784 P->data[P->end++] = 0xff & (n >> 0);
3785 P->end = p;
3786
3787 return 0;
3788 } /* dns_sshfp_push() */
3789
3790
dns_sshfp_cmp(const struct dns_sshfp * a,const struct dns_sshfp * b)3791 int dns_sshfp_cmp(const struct dns_sshfp *a, const struct dns_sshfp *b) {
3792 int cmp;
3793
3794 if ((cmp = a->algo - b->algo) || (cmp = a->type - b->type))
3795 return cmp;
3796
3797 switch (a->type) {
3798 case DNS_SSHFP_SHA1:
3799 return memcmp(a->digest.sha1, b->digest.sha1, sizeof a->digest.sha1);
3800 default:
3801 return 0;
3802 } /* switch() */
3803
3804 /* NOT REACHED */
3805 } /* dns_sshfp_cmp() */
3806
3807
dns_sshfp_print(void * _dst,size_t lim,struct dns_sshfp * fp)3808 size_t dns_sshfp_print(void *_dst, size_t lim, struct dns_sshfp *fp) {
3809 static const unsigned char hex[16] = "0123456789abcdef";
3810 struct dns_buf dst = DNS_B_INTO(_dst, lim);
3811 size_t i;
3812
3813 dns_b_fmtju(&dst, fp->algo, 0);
3814 dns_b_putc(&dst, ' ');
3815 dns_b_fmtju(&dst, fp->type, 0);
3816 dns_b_putc(&dst, ' ');
3817
3818 switch (fp->type) {
3819 case DNS_SSHFP_SHA1:
3820 for (i = 0; i < sizeof fp->digest.sha1; i++) {
3821 dns_b_putc(&dst, hex[0x0f & (fp->digest.sha1[i] >> 4)]);
3822 dns_b_putc(&dst, hex[0x0f & (fp->digest.sha1[i] >> 0)]);
3823 }
3824
3825 break;
3826 default:
3827 dns_b_putc(&dst, '0');
3828
3829 break;
3830 } /* switch() */
3831
3832 return dns_b_strllen(&dst);
3833 } /* dns_sshfp_print() */
3834
3835
dns_txt_init(struct dns_txt * txt,size_t size)3836 struct dns_txt *dns_txt_init(struct dns_txt *txt, size_t size) {
3837 assert(size > offsetof(struct dns_txt, data));
3838
3839 txt->size = size - offsetof(struct dns_txt, data);
3840 txt->len = 0;
3841
3842 return txt;
3843 } /* dns_txt_init() */
3844
3845
dns_txt_initany(union dns_any * any,size_t size)3846 static union dns_any *dns_txt_initany(union dns_any *any, size_t size) {
3847 /* NB: union dns_any is already initialized as struct dns_txt */
3848 (void)size;
3849 return any;
3850 } /* dns_txt_initany() */
3851
3852
dns_txt_parse(struct dns_txt * txt,struct dns_rr * rr,struct dns_packet * P)3853 int dns_txt_parse(struct dns_txt *txt, struct dns_rr *rr, struct dns_packet *P) {
3854 struct { unsigned char *b; size_t p, end; } dst, src;
3855 unsigned n;
3856
3857 dst.b = txt->data;
3858 dst.p = 0;
3859 dst.end = txt->size;
3860
3861 src.b = P->data;
3862 src.p = rr->rd.p;
3863 src.end = src.p + rr->rd.len;
3864
3865 while (src.p < src.end) {
3866 n = 0xff & P->data[src.p++];
3867
3868 if (src.end - src.p < n || dst.end - dst.p < n)
3869 return DNS_EILLEGAL;
3870
3871 memcpy(&dst.b[dst.p], &src.b[src.p], n);
3872
3873 dst.p += n;
3874 src.p += n;
3875 }
3876
3877 txt->len = dst.p;
3878
3879 return 0;
3880 } /* dns_txt_parse() */
3881
3882
dns_txt_push(struct dns_packet * P,struct dns_txt * txt)3883 int dns_txt_push(struct dns_packet *P, struct dns_txt *txt) {
3884 struct { unsigned char *b; size_t p, end; } dst, src;
3885 unsigned n;
3886
3887 dst.b = P->data;
3888 dst.p = P->end;
3889 dst.end = P->size;
3890
3891 src.b = txt->data;
3892 src.p = 0;
3893 src.end = txt->len;
3894
3895 if (dst.end - dst.p < 2)
3896 return DNS_ENOBUFS;
3897
3898 n = txt->len + ((txt->len + 254) / 255);
3899
3900 dst.b[dst.p++] = 0xff & (n >> 8);
3901 dst.b[dst.p++] = 0xff & (n >> 0);
3902
3903 while (src.p < src.end) {
3904 n = DNS_PP_MIN(255, src.end - src.p);
3905
3906 if (dst.p >= dst.end)
3907 return DNS_ENOBUFS;
3908
3909 dst.b[dst.p++] = n;
3910
3911 if (dst.end - dst.p < n)
3912 return DNS_ENOBUFS;
3913
3914 memcpy(&dst.b[dst.p], &src.b[src.p], n);
3915
3916 dst.p += n;
3917 src.p += n;
3918 }
3919
3920 P->end = dst.p;
3921
3922 return 0;
3923 } /* dns_txt_push() */
3924
3925
dns_txt_cmp(const struct dns_txt * a,const struct dns_txt * b)3926 int dns_txt_cmp(const struct dns_txt *a, const struct dns_txt *b) {
3927 (void)a;
3928 (void)b;
3929
3930 return -1;
3931 } /* dns_txt_cmp() */
3932
3933
dns_txt_print(void * _dst,size_t lim,struct dns_txt * txt)3934 size_t dns_txt_print(void *_dst, size_t lim, struct dns_txt *txt) {
3935 struct dns_buf src = DNS_B_FROM(txt->data, txt->len);
3936 struct dns_buf dst = DNS_B_INTO(_dst, lim);
3937 unsigned i;
3938
3939 if (src.p < src.pe) {
3940 do {
3941 dns_b_putc(&dst, '"');
3942
3943 for (i = 0; i < 256 && src.p < src.pe; i++, src.p++) {
3944 if (*src.p < 32 || *src.p > 126 || *src.p == '"' || *src.p == '\\') {
3945 dns_b_putc(&dst, '\\');
3946 dns_b_fmtju(&dst, *src.p, 3);
3947 } else {
3948 dns_b_putc(&dst, *src.p);
3949 }
3950 }
3951
3952 dns_b_putc(&dst, '"');
3953 dns_b_putc(&dst, ' ');
3954 } while (src.p < src.pe);
3955
3956 dns_b_popc(&dst);
3957 } else {
3958 dns_b_putc(&dst, '"');
3959 dns_b_putc(&dst, '"');
3960 }
3961
3962 return dns_b_strllen(&dst);
3963 } /* dns_txt_print() */
3964
3965
3966 static const struct dns_rrtype {
3967 enum dns_type type;
3968 const char *name;
3969 union dns_any *(*init)(union dns_any *, size_t);
3970 int (*parse)();
3971 int (*push)();
3972 int (*cmp)();
3973 size_t (*print)();
3974 size_t (*cname)();
3975 } dns_rrtypes[] = {
3976 { DNS_T_A, "A", 0, &dns_a_parse, &dns_a_push, &dns_a_cmp, &dns_a_print, 0, },
3977 { DNS_T_AAAA, "AAAA", 0, &dns_aaaa_parse, &dns_aaaa_push, &dns_aaaa_cmp, &dns_aaaa_print, 0, },
3978 { DNS_T_MX, "MX", 0, &dns_mx_parse, &dns_mx_push, &dns_mx_cmp, &dns_mx_print, &dns_mx_cname, },
3979 { DNS_T_NS, "NS", 0, &dns_ns_parse, &dns_ns_push, &dns_ns_cmp, &dns_ns_print, &dns_ns_cname, },
3980 { DNS_T_CNAME, "CNAME", 0, &dns_cname_parse, &dns_cname_push, &dns_cname_cmp, &dns_cname_print, &dns_cname_cname, },
3981 { DNS_T_SOA, "SOA", 0, &dns_soa_parse, &dns_soa_push, &dns_soa_cmp, &dns_soa_print, 0, },
3982 { DNS_T_SRV, "SRV", 0, &dns_srv_parse, &dns_srv_push, &dns_srv_cmp, &dns_srv_print, &dns_srv_cname, },
3983 { DNS_T_OPT, "OPT", &dns_opt_initany, &dns_opt_parse, &dns_opt_push, &dns_opt_cmp, &dns_opt_print, 0, },
3984 { DNS_T_PTR, "PTR", 0, &dns_ptr_parse, &dns_ptr_push, &dns_ptr_cmp, &dns_ptr_print, &dns_ptr_cname, },
3985 { DNS_T_TXT, "TXT", &dns_txt_initany, &dns_txt_parse, &dns_txt_push, &dns_txt_cmp, &dns_txt_print, 0, },
3986 { DNS_T_SPF, "SPF", &dns_txt_initany, &dns_txt_parse, &dns_txt_push, &dns_txt_cmp, &dns_txt_print, 0, },
3987 { DNS_T_SSHFP, "SSHFP", 0, &dns_sshfp_parse, &dns_sshfp_push, &dns_sshfp_cmp, &dns_sshfp_print, 0, },
3988 { DNS_T_AXFR, "AXFR", 0, 0, 0, 0, 0, 0, },
3989 }; /* dns_rrtypes[] */
3990
dns_rrtype(enum dns_type type)3991 static const struct dns_rrtype *dns_rrtype(enum dns_type type) {
3992 const struct dns_rrtype *t;
3993
3994 for (t = dns_rrtypes; t < endof(dns_rrtypes); t++) {
3995 if (t->type == type && t->parse) {
3996 return t;
3997 }
3998 }
3999
4000 return NULL;
4001 } /* dns_rrtype() */
4002
4003
dns_any_init(union dns_any * any,size_t size)4004 union dns_any *dns_any_init(union dns_any *any, size_t size) {
4005 dns_static_assert(dns_same_type(any->txt, any->rdata, 1), "unexpected rdata type");
4006 return (union dns_any *)dns_txt_init(&any->rdata, size);
4007 } /* dns_any_init() */
4008
4009
dns_any_sizeof(union dns_any * any)4010 static size_t dns_any_sizeof(union dns_any *any) {
4011 dns_static_assert(dns_same_type(any->txt, any->rdata, 1), "unexpected rdata type");
4012 return offsetof(struct dns_txt, data) + any->rdata.size;
4013 } /* dns_any_sizeof() */
4014
dns_any_reinit(union dns_any * any,const struct dns_rrtype * t)4015 static union dns_any *dns_any_reinit(union dns_any *any, const struct dns_rrtype *t) {
4016 return (t->init)? t->init(any, dns_any_sizeof(any)) : any;
4017 } /* dns_any_reinit() */
4018
dns_any_parse(union dns_any * any,struct dns_rr * rr,struct dns_packet * P)4019 int dns_any_parse(union dns_any *any, struct dns_rr *rr, struct dns_packet *P) {
4020 const struct dns_rrtype *t;
4021
4022 if ((t = dns_rrtype(rr->type)))
4023 return t->parse(dns_any_reinit(any, t), rr, P);
4024
4025 if (rr->rd.len > any->rdata.size)
4026 return DNS_EILLEGAL;
4027
4028 memcpy(any->rdata.data, &P->data[rr->rd.p], rr->rd.len);
4029 any->rdata.len = rr->rd.len;
4030
4031 return 0;
4032 } /* dns_any_parse() */
4033
4034
dns_any_push(struct dns_packet * P,union dns_any * any,enum dns_type type)4035 int dns_any_push(struct dns_packet *P, union dns_any *any, enum dns_type type) {
4036 const struct dns_rrtype *t;
4037
4038 if ((t = dns_rrtype(type)))
4039 return t->push(P, any);
4040
4041 if (P->size - P->end < any->rdata.len + 2)
4042 return DNS_ENOBUFS;
4043
4044 P->data[P->end++] = 0xff & (any->rdata.len >> 8);
4045 P->data[P->end++] = 0xff & (any->rdata.len >> 0);
4046
4047 memcpy(&P->data[P->end], any->rdata.data, any->rdata.len);
4048 P->end += any->rdata.len;
4049
4050 return 0;
4051 } /* dns_any_push() */
4052
4053
dns_any_cmp(const union dns_any * a,enum dns_type x,const union dns_any * b,enum dns_type y)4054 int dns_any_cmp(const union dns_any *a, enum dns_type x, const union dns_any *b, enum dns_type y) {
4055 const struct dns_rrtype *t;
4056 int cmp;
4057
4058 if ((cmp = x - y))
4059 return cmp;
4060
4061 if ((t = dns_rrtype(x)))
4062 return t->cmp(a, b);
4063
4064 return -1;
4065 } /* dns_any_cmp() */
4066
4067
dns_any_print(void * _dst,size_t lim,union dns_any * any,enum dns_type type)4068 size_t dns_any_print(void *_dst, size_t lim, union dns_any *any, enum dns_type type) {
4069 const struct dns_rrtype *t;
4070 struct dns_buf src, dst;
4071
4072 if ((t = dns_rrtype(type)))
4073 return t->print(_dst, lim, any);
4074
4075 dns_b_from(&src, any->rdata.data, any->rdata.len);
4076 dns_b_into(&dst, _dst, lim);
4077
4078 dns_b_putc(&dst, '"');
4079
4080 while (src.p < src.pe) {
4081 dns_b_putc(&dst, '\\');
4082 dns_b_fmtju(&dst, *src.p++, 3);
4083 }
4084
4085 dns_b_putc(&dst, '"');
4086
4087 return dns_b_strllen(&dst);
4088 } /* dns_any_print() */
4089
4090
dns_any_cname(void * dst,size_t lim,union dns_any * any,enum dns_type type)4091 size_t dns_any_cname(void *dst, size_t lim, union dns_any *any, enum dns_type type) {
4092 const struct dns_rrtype *t;
4093
4094 if ((t = dns_rrtype(type)) && t->cname)
4095 return t->cname(dst, lim, any);
4096
4097 return 0;
4098 } /* dns_any_cname() */
4099
4100
4101 /*
4102 * H O S T S R O U T I N E S
4103 *
4104 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4105
4106 struct dns_hosts {
4107 struct dns_hosts_entry {
4108 char host[DNS_D_MAXNAME + 1];
4109 char arpa[73 + 1];
4110
4111 int af;
4112
4113 union {
4114 struct in_addr a4;
4115 struct in6_addr a6;
4116 } addr;
4117
4118 _Bool alias;
4119
4120 struct dns_hosts_entry *next;
4121 } *head, **tail;
4122
4123 dns_atomic_t refcount;
4124 }; /* struct dns_hosts */
4125
4126
dns_hosts_open(int * error)4127 struct dns_hosts *dns_hosts_open(int *error) {
4128 static const struct dns_hosts hosts_initializer = { .refcount = 1 };
4129 struct dns_hosts *hosts;
4130
4131 if (!(hosts = malloc(sizeof *hosts)))
4132 goto syerr;
4133
4134 *hosts = hosts_initializer;
4135
4136 hosts->tail = &hosts->head;
4137
4138 return hosts;
4139 syerr:
4140 *error = dns_syerr();
4141
4142 free(hosts);
4143
4144 return 0;
4145 } /* dns_hosts_open() */
4146
4147
dns_hosts_close(struct dns_hosts * hosts)4148 void dns_hosts_close(struct dns_hosts *hosts) {
4149 struct dns_hosts_entry *ent, *xnt;
4150
4151 if (!hosts || 1 != dns_hosts_release(hosts))
4152 return;
4153
4154 for (ent = hosts->head; ent; ent = xnt) {
4155 xnt = ent->next;
4156
4157 free(ent);
4158 }
4159
4160 free(hosts);
4161
4162 return;
4163 } /* dns_hosts_close() */
4164
4165
dns_hosts_acquire(struct dns_hosts * hosts)4166 dns_refcount_t dns_hosts_acquire(struct dns_hosts *hosts) {
4167 return dns_atomic_fetch_add(&hosts->refcount);
4168 } /* dns_hosts_acquire() */
4169
4170
dns_hosts_release(struct dns_hosts * hosts)4171 dns_refcount_t dns_hosts_release(struct dns_hosts *hosts) {
4172 return dns_atomic_fetch_sub(&hosts->refcount);
4173 } /* dns_hosts_release() */
4174
4175
dns_hosts_mortal(struct dns_hosts * hosts)4176 struct dns_hosts *dns_hosts_mortal(struct dns_hosts *hosts) {
4177 if (hosts)
4178 dns_hosts_release(hosts);
4179
4180 return hosts;
4181 } /* dns_hosts_mortal() */
4182
4183
dns_hosts_local(int * error_)4184 struct dns_hosts *dns_hosts_local(int *error_) {
4185 struct dns_hosts *hosts;
4186 int error;
4187
4188 if (!(hosts = dns_hosts_open(&error)))
4189 goto error;
4190
4191 if ((error = dns_hosts_loadpath(hosts, "/etc/hosts")))
4192 goto error;
4193
4194 return hosts;
4195 error:
4196 *error_ = error;
4197
4198 dns_hosts_close(hosts);
4199
4200 return 0;
4201 } /* dns_hosts_local() */
4202
4203
4204 #define dns_hosts_issep(ch) (dns_isspace(ch))
4205 #define dns_hosts_iscom(ch) ((ch) == '#' || (ch) == ';')
4206
dns_hosts_loadfile(struct dns_hosts * hosts,FILE * fp)4207 int dns_hosts_loadfile(struct dns_hosts *hosts, FILE *fp) {
4208 struct dns_hosts_entry ent;
4209 char word[DNS_PP_MAX(INET6_ADDRSTRLEN, DNS_D_MAXNAME) + 1];
4210 unsigned wp, wc, skip;
4211 int ch, error;
4212
4213 rewind(fp);
4214
4215 do {
4216 memset(&ent, '\0', sizeof ent);
4217 wc = 0;
4218 skip = 0;
4219
4220 do {
4221 memset(word, '\0', sizeof word);
4222 wp = 0;
4223
4224 while (EOF != (ch = fgetc(fp)) && ch != '\n') {
4225 skip |= !!dns_hosts_iscom(ch);
4226
4227 if (skip)
4228 continue;
4229
4230 if (dns_hosts_issep(ch))
4231 break;
4232
4233 if (wp < sizeof word - 1)
4234 word[wp] = ch;
4235 wp++;
4236 }
4237
4238 if (!wp)
4239 continue;
4240
4241 wc++;
4242
4243 switch (wc) {
4244 case 0:
4245 break;
4246 case 1:
4247 ent.af = (strchr(word, ':'))? AF_INET6 : AF_INET;
4248 skip = (1 != dns_inet_pton(ent.af, word, &ent.addr));
4249
4250 break;
4251 default:
4252 if (!wp)
4253 break;
4254
4255 dns_d_anchor(ent.host, sizeof ent.host, word, wp);
4256
4257 if ((error = dns_hosts_insert(hosts, ent.af, &ent.addr, ent.host, (wc > 2))))
4258 return error;
4259
4260 break;
4261 } /* switch() */
4262 } while (ch != EOF && ch != '\n');
4263 } while (ch != EOF);
4264
4265 return 0;
4266 } /* dns_hosts_loadfile() */
4267
4268
dns_hosts_loadpath(struct dns_hosts * hosts,const char * path)4269 int dns_hosts_loadpath(struct dns_hosts *hosts, const char *path) {
4270 FILE *fp;
4271 int error;
4272
4273 if (!(fp = dns_fopen(path, "rt", &error)))
4274 return error;
4275
4276 error = dns_hosts_loadfile(hosts, fp);
4277
4278 fclose(fp);
4279
4280 return error;
4281 } /* dns_hosts_loadpath() */
4282
4283
dns_hosts_dump(struct dns_hosts * hosts,FILE * fp)4284 int dns_hosts_dump(struct dns_hosts *hosts, FILE *fp) {
4285 struct dns_hosts_entry *ent, *xnt;
4286 char addr[INET6_ADDRSTRLEN + 1];
4287 unsigned i;
4288
4289 for (ent = hosts->head; ent; ent = xnt) {
4290 xnt = ent->next;
4291
4292 dns_inet_ntop(ent->af, &ent->addr, addr, sizeof addr);
4293
4294 fputs(addr, fp);
4295
4296 for (i = strlen(addr); i < INET_ADDRSTRLEN; i++)
4297 fputc(' ', fp);
4298
4299 fputc(' ', fp);
4300
4301 fputs(ent->host, fp);
4302 fputc('\n', fp);
4303 }
4304
4305 return 0;
4306 } /* dns_hosts_dump() */
4307
4308
dns_hosts_insert(struct dns_hosts * hosts,int af,const void * addr,const void * host,_Bool alias)4309 int dns_hosts_insert(struct dns_hosts *hosts, int af, const void *addr, const void *host, _Bool alias) {
4310 struct dns_hosts_entry *ent;
4311 int error;
4312
4313 if (!(ent = malloc(sizeof *ent)))
4314 goto syerr;
4315
4316 dns_d_anchor(ent->host, sizeof ent->host, host, strlen(host));
4317
4318 switch ((ent->af = af)) {
4319 case AF_INET6:
4320 memcpy(&ent->addr.a6, addr, sizeof ent->addr.a6);
4321
4322 dns_aaaa_arpa(ent->arpa, sizeof ent->arpa, addr);
4323
4324 break;
4325 case AF_INET:
4326 memcpy(&ent->addr.a4, addr, sizeof ent->addr.a4);
4327
4328 dns_a_arpa(ent->arpa, sizeof ent->arpa, addr);
4329
4330 break;
4331 default:
4332 error = EINVAL;
4333
4334 goto error;
4335 } /* switch() */
4336
4337 ent->alias = alias;
4338
4339 ent->next = 0;
4340 *hosts->tail = ent;
4341 hosts->tail = &ent->next;
4342
4343 return 0;
4344 syerr:
4345 error = dns_syerr();
4346 error:
4347 free(ent);
4348
4349 return error;
4350 } /* dns_hosts_insert() */
4351
4352
dns_hosts_query(struct dns_hosts * hosts,struct dns_packet * Q,int * error_)4353 struct dns_packet *dns_hosts_query(struct dns_hosts *hosts, struct dns_packet *Q, int *error_) {
4354 struct dns_packet *P = dns_p_new(512);
4355 struct dns_packet *A = 0;
4356 struct dns_rr rr;
4357 struct dns_hosts_entry *ent;
4358 int error, af;
4359 char qname[DNS_D_MAXNAME + 1];
4360 size_t qlen;
4361
4362 if ((error = dns_rr_parse(&rr, 12, Q)))
4363 goto error;
4364
4365 if (!(qlen = dns_d_expand(qname, sizeof qname, rr.dn.p, Q, &error)))
4366 goto error;
4367 else if (qlen >= sizeof qname)
4368 goto toolong;
4369
4370 if ((error = dns_p_push(P, DNS_S_QD, qname, qlen, rr.type, rr.class, 0, 0)))
4371 goto error;
4372
4373 switch (rr.type) {
4374 case DNS_T_PTR:
4375 for (ent = hosts->head; ent; ent = ent->next) {
4376 if (ent->alias || 0 != strcasecmp(qname, ent->arpa))
4377 continue;
4378
4379 if ((error = dns_p_push(P, DNS_S_AN, qname, qlen, rr.type, rr.class, 0, ent->host)))
4380 goto error;
4381 }
4382
4383 break;
4384 case DNS_T_AAAA:
4385 af = AF_INET6;
4386
4387 goto loop;
4388 case DNS_T_A:
4389 af = AF_INET;
4390
4391 loop: for (ent = hosts->head; ent; ent = ent->next) {
4392 if (ent->af != af || 0 != strcasecmp(qname, ent->host))
4393 continue;
4394
4395 if ((error = dns_p_push(P, DNS_S_AN, qname, qlen, rr.type, rr.class, 0, &ent->addr)))
4396 goto error;
4397 }
4398
4399 break;
4400 default:
4401 break;
4402 } /* switch() */
4403
4404
4405 if (!(A = dns_p_copy(dns_p_make(P->end, &error), P)))
4406 goto error;
4407
4408 return A;
4409 toolong:
4410 error = DNS_EILLEGAL;
4411 error:
4412 *error_ = error;
4413
4414 dns_p_free(A);
4415
4416 return 0;
4417 } /* dns_hosts_query() */
4418
4419
4420 /*
4421 * R E S O L V . C O N F R O U T I N E S
4422 *
4423 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4424
dns_resconf_open(int * error)4425 struct dns_resolv_conf *dns_resconf_open(int *error) {
4426 static const struct dns_resolv_conf resconf_initializer = {
4427 .lookup = "bf",
4428 .family = { AF_INET, AF_INET6 },
4429 .options = { .ndots = 1, .timeout = 5, .attempts = 2, .tcp = DNS_RESCONF_TCP_ENABLE, },
4430 .iface = { .ss_family = AF_INET },
4431 };
4432 struct dns_resolv_conf *resconf;
4433 struct sockaddr_in *sin;
4434 size_t len;
4435
4436 if (!(resconf = malloc(sizeof *resconf)))
4437 goto syerr;
4438
4439 *resconf = resconf_initializer;
4440
4441 sin = (struct sockaddr_in *)&resconf->nameserver[0];
4442 sin->sin_family = AF_INET;
4443 sin->sin_addr.s_addr = INADDR_ANY;
4444 sin->sin_port = htons(53);
4445 #if defined(SA_LEN)
4446 sin->sin_len = sizeof *sin;
4447 #endif
4448
4449 if (0 != gethostname(resconf->search[0], sizeof resconf->search[0]))
4450 goto syerr;
4451
4452 len = strlen(resconf->search[0]);
4453 len = dns_d_anchor(resconf->search[0], sizeof resconf->search[0], resconf->search[0], len);
4454 len = dns_d_cleave(resconf->search[0], sizeof resconf->search[0], resconf->search[0], len);
4455 if (1 == len) /* gethostname() returned a string without any label */
4456 resconf->search[0][0] = '\0';
4457
4458 dns_resconf_acquire(resconf);
4459
4460 return resconf;
4461 syerr:
4462 *error = dns_syerr();
4463
4464 free(resconf);
4465
4466 return 0;
4467 } /* dns_resconf_open() */
4468
4469
dns_resconf_close(struct dns_resolv_conf * resconf)4470 void dns_resconf_close(struct dns_resolv_conf *resconf) {
4471 if (!resconf || 1 != dns_resconf_release(resconf))
4472 return /* void */;
4473
4474 free(resconf);
4475 } /* dns_resconf_close() */
4476
4477
dns_resconf_acquire(struct dns_resolv_conf * resconf)4478 dns_refcount_t dns_resconf_acquire(struct dns_resolv_conf *resconf) {
4479 return dns_atomic_fetch_add(&resconf->_.refcount);
4480 } /* dns_resconf_acquire() */
4481
4482
dns_resconf_release(struct dns_resolv_conf * resconf)4483 dns_refcount_t dns_resconf_release(struct dns_resolv_conf *resconf) {
4484 return dns_atomic_fetch_sub(&resconf->_.refcount);
4485 } /* dns_resconf_release() */
4486
4487
dns_resconf_mortal(struct dns_resolv_conf * resconf)4488 struct dns_resolv_conf *dns_resconf_mortal(struct dns_resolv_conf *resconf) {
4489 if (resconf)
4490 dns_resconf_release(resconf);
4491
4492 return resconf;
4493 } /* dns_resconf_mortal() */
4494
4495
dns_resconf_local(int * error_)4496 struct dns_resolv_conf *dns_resconf_local(int *error_) {
4497 struct dns_resolv_conf *resconf;
4498 int error;
4499
4500 if (!(resconf = dns_resconf_open(&error)))
4501 goto error;
4502
4503 if ((error = dns_resconf_loadpath(resconf, "/etc/resolv.conf"))) {
4504 /*
4505 * NOTE: Both the glibc and BIND9 resolvers ignore a missing
4506 * /etc/resolv.conf, defaulting to a nameserver of
4507 * 127.0.0.1. See also dns_hints_insert_resconf, and the
4508 * default initialization of nameserver[0] in
4509 * dns_resconf_open.
4510 */
4511 if (error != ENOENT)
4512 goto error;
4513 }
4514
4515 if ((error = dns_nssconf_loadpath(resconf, "/etc/nsswitch.conf"))) {
4516 if (error != ENOENT)
4517 goto error;
4518 }
4519
4520 return resconf;
4521 error:
4522 *error_ = error;
4523
4524 dns_resconf_close(resconf);
4525
4526 return 0;
4527 } /* dns_resconf_local() */
4528
4529
dns_resconf_root(int * error)4530 struct dns_resolv_conf *dns_resconf_root(int *error) {
4531 struct dns_resolv_conf *resconf;
4532
4533 if ((resconf = dns_resconf_local(error)))
4534 resconf->options.recurse = 1;
4535
4536 return resconf;
4537 } /* dns_resconf_root() */
4538
4539
dns_resconf_timeout(const struct dns_resolv_conf * resconf)4540 static time_t dns_resconf_timeout(const struct dns_resolv_conf *resconf) {
4541 return (time_t)DNS_PP_MIN(INT_MAX, resconf->options.timeout);
4542 } /* dns_resconf_timeout() */
4543
4544
4545 enum dns_resconf_keyword {
4546 DNS_RESCONF_NAMESERVER,
4547 DNS_RESCONF_DOMAIN,
4548 DNS_RESCONF_SEARCH,
4549 DNS_RESCONF_LOOKUP,
4550 DNS_RESCONF_FILE,
4551 DNS_RESCONF_BIND,
4552 DNS_RESCONF_CACHE,
4553 DNS_RESCONF_FAMILY,
4554 DNS_RESCONF_INET4,
4555 DNS_RESCONF_INET6,
4556 DNS_RESCONF_OPTIONS,
4557 DNS_RESCONF_EDNS0,
4558 DNS_RESCONF_NDOTS,
4559 DNS_RESCONF_TIMEOUT,
4560 DNS_RESCONF_ATTEMPTS,
4561 DNS_RESCONF_ROTATE,
4562 DNS_RESCONF_RECURSE,
4563 DNS_RESCONF_SMART,
4564 DNS_RESCONF_TCP,
4565 DNS_RESCONF_TCPx,
4566 DNS_RESCONF_INTERFACE,
4567 DNS_RESCONF_ZERO,
4568 DNS_RESCONF_ONE,
4569 DNS_RESCONF_ENABLE,
4570 DNS_RESCONF_ONLY,
4571 DNS_RESCONF_DISABLE,
4572 }; /* enum dns_resconf_keyword */
4573
dns_resconf_keyword(const char * word)4574 static enum dns_resconf_keyword dns_resconf_keyword(const char *word) {
4575 static const char *words[] = {
4576 [DNS_RESCONF_NAMESERVER] = "nameserver",
4577 [DNS_RESCONF_DOMAIN] = "domain",
4578 [DNS_RESCONF_SEARCH] = "search",
4579 [DNS_RESCONF_LOOKUP] = "lookup",
4580 [DNS_RESCONF_FILE] = "file",
4581 [DNS_RESCONF_BIND] = "bind",
4582 [DNS_RESCONF_CACHE] = "cache",
4583 [DNS_RESCONF_FAMILY] = "family",
4584 [DNS_RESCONF_INET4] = "inet4",
4585 [DNS_RESCONF_INET6] = "inet6",
4586 [DNS_RESCONF_OPTIONS] = "options",
4587 [DNS_RESCONF_EDNS0] = "edns0",
4588 [DNS_RESCONF_ROTATE] = "rotate",
4589 [DNS_RESCONF_RECURSE] = "recurse",
4590 [DNS_RESCONF_SMART] = "smart",
4591 [DNS_RESCONF_TCP] = "tcp",
4592 [DNS_RESCONF_INTERFACE] = "interface",
4593 [DNS_RESCONF_ZERO] = "0",
4594 [DNS_RESCONF_ONE] = "1",
4595 [DNS_RESCONF_ENABLE] = "enable",
4596 [DNS_RESCONF_ONLY] = "only",
4597 [DNS_RESCONF_DISABLE] = "disable",
4598 };
4599 unsigned i;
4600
4601 for (i = 0; i < lengthof(words); i++) {
4602 if (words[i] && 0 == strcasecmp(words[i], word))
4603 return i;
4604 }
4605
4606 if (0 == strncasecmp(word, "ndots:", sizeof "ndots:" - 1))
4607 return DNS_RESCONF_NDOTS;
4608
4609 if (0 == strncasecmp(word, "timeout:", sizeof "timeout:" - 1))
4610 return DNS_RESCONF_TIMEOUT;
4611
4612 if (0 == strncasecmp(word, "attempts:", sizeof "attempts:" - 1))
4613 return DNS_RESCONF_ATTEMPTS;
4614
4615 if (0 == strncasecmp(word, "tcp:", sizeof "tcp:" - 1))
4616 return DNS_RESCONF_TCPx;
4617
4618 return -1;
4619 } /* dns_resconf_keyword() */
4620
4621
4622 /** OpenBSD-style "[1.2.3.4]:53" nameserver syntax */
dns_resconf_pton(struct sockaddr_storage * ss,const char * src)4623 int dns_resconf_pton(struct sockaddr_storage *ss, const char *src) {
4624 struct { char buf[128], *p; } addr = { "", addr.buf };
4625 unsigned short port = 0;
4626 int ch, af = AF_INET, error;
4627
4628 while ((ch = *src++)) {
4629 switch (ch) {
4630 case ' ':
4631 /* FALL THROUGH */
4632 case '\t':
4633 break;
4634 case '[':
4635 break;
4636 case ']':
4637 while ((ch = *src++)) {
4638 if (dns_isdigit(ch)) {
4639 port *= 10;
4640 port += ch - '0';
4641 }
4642 }
4643
4644 goto inet;
4645 case ':':
4646 af = AF_INET6;
4647
4648 /* FALL THROUGH */
4649 default:
4650 if (addr.p < endof(addr.buf) - 1)
4651 *addr.p++ = ch;
4652
4653 break;
4654 } /* switch() */
4655 } /* while() */
4656 inet:
4657
4658 if ((error = dns_pton(af, addr.buf, dns_sa_addr(af, ss, NULL))))
4659 return error;
4660
4661 port = (!port)? 53 : port;
4662 *dns_sa_port(af, ss) = htons(port);
4663 dns_sa_family(ss) = af;
4664
4665 return 0;
4666 } /* dns_resconf_pton() */
4667
4668 #define dns_resconf_issep(ch) (dns_isspace(ch) || (ch) == ',')
4669 #define dns_resconf_iscom(ch) ((ch) == '#' || (ch) == ';')
4670
dns_resconf_loadfile(struct dns_resolv_conf * resconf,FILE * fp)4671 int dns_resconf_loadfile(struct dns_resolv_conf *resconf, FILE *fp) {
4672 unsigned sa_count = 0;
4673 char words[6][DNS_D_MAXNAME + 1];
4674 unsigned wp, wc, i, j, n;
4675 int ch, error;
4676
4677 rewind(fp);
4678
4679 do {
4680 memset(words, '\0', sizeof words);
4681 wp = 0;
4682 wc = 0;
4683
4684 while (EOF != (ch = getc(fp)) && ch != '\n') {
4685 if (dns_resconf_issep(ch)) {
4686 if (wp > 0) {
4687 wp = 0;
4688
4689 if (++wc >= lengthof(words))
4690 goto skip;
4691 }
4692 } else if (dns_resconf_iscom(ch)) {
4693 skip:
4694 do {
4695 ch = getc(fp);
4696 } while (ch != EOF && ch != '\n');
4697
4698 break;
4699 } else if (wp < sizeof words[wc] - 1) {
4700 words[wc][wp++] = ch;
4701 } else {
4702 wp = 0; /* drop word */
4703 goto skip;
4704 }
4705 }
4706
4707 if (wp > 0)
4708 wc++;
4709
4710 if (wc < 2)
4711 continue;
4712
4713 switch (dns_resconf_keyword(words[0])) {
4714 case DNS_RESCONF_NAMESERVER:
4715 if (sa_count >= lengthof(resconf->nameserver))
4716 continue;
4717
4718 if ((error = dns_resconf_pton(&resconf->nameserver[sa_count], words[1])))
4719 continue;
4720
4721 sa_count++;
4722
4723 break;
4724 case DNS_RESCONF_DOMAIN:
4725 case DNS_RESCONF_SEARCH:
4726 memset(resconf->search, '\0', sizeof resconf->search);
4727
4728 for (i = 1, j = 0; i < wc && j < lengthof(resconf->search); i++, j++)
4729 dns_d_anchor(resconf->search[j], sizeof resconf->search[j], words[i], strlen(words[i]));
4730
4731 break;
4732 case DNS_RESCONF_LOOKUP:
4733 for (i = 1, j = 0; i < wc && j < lengthof(resconf->lookup); i++) {
4734 switch (dns_resconf_keyword(words[i])) {
4735 case DNS_RESCONF_FILE:
4736 resconf->lookup[j++] = 'f';
4737
4738 break;
4739 case DNS_RESCONF_BIND:
4740 resconf->lookup[j++] = 'b';
4741
4742 break;
4743 case DNS_RESCONF_CACHE:
4744 resconf->lookup[j++] = 'c';
4745
4746 break;
4747 default:
4748 break;
4749 } /* switch() */
4750 } /* for() */
4751
4752 break;
4753 case DNS_RESCONF_FAMILY:
4754 for (i = 1, j = 0; i < wc && j < lengthof(resconf->family); i++) {
4755 switch (dns_resconf_keyword(words[i])) {
4756 case DNS_RESCONF_INET4:
4757 resconf->family[j++] = AF_INET;
4758
4759 break;
4760 case DNS_RESCONF_INET6:
4761 resconf->family[j++] = AF_INET6;
4762
4763 break;
4764 default:
4765 break;
4766 }
4767 }
4768
4769 break;
4770 case DNS_RESCONF_OPTIONS:
4771 for (i = 1; i < wc; i++) {
4772 switch (dns_resconf_keyword(words[i])) {
4773 case DNS_RESCONF_EDNS0:
4774 resconf->options.edns0 = 1;
4775
4776 break;
4777 case DNS_RESCONF_NDOTS:
4778 for (j = sizeof "ndots:" - 1, n = 0; dns_isdigit(words[i][j]); j++) {
4779 n *= 10;
4780 n += words[i][j] - '0';
4781 } /* for() */
4782
4783 resconf->options.ndots = n;
4784
4785 break;
4786 case DNS_RESCONF_TIMEOUT:
4787 for (j = sizeof "timeout:" - 1, n = 0; dns_isdigit(words[i][j]); j++) {
4788 n *= 10;
4789 n += words[i][j] - '0';
4790 } /* for() */
4791
4792 resconf->options.timeout = n;
4793
4794 break;
4795 case DNS_RESCONF_ATTEMPTS:
4796 for (j = sizeof "attempts:" - 1, n = 0; dns_isdigit(words[i][j]); j++) {
4797 n *= 10;
4798 n += words[i][j] - '0';
4799 } /* for() */
4800
4801 resconf->options.attempts = n;
4802
4803 break;
4804 case DNS_RESCONF_ROTATE:
4805 resconf->options.rotate = 1;
4806
4807 break;
4808 case DNS_RESCONF_RECURSE:
4809 resconf->options.recurse = 1;
4810
4811 break;
4812 case DNS_RESCONF_SMART:
4813 resconf->options.smart = 1;
4814
4815 break;
4816 case DNS_RESCONF_TCP:
4817 resconf->options.tcp = DNS_RESCONF_TCP_ONLY;
4818
4819 break;
4820 case DNS_RESCONF_TCPx:
4821 switch (dns_resconf_keyword(&words[i][sizeof "tcp:" - 1])) {
4822 case DNS_RESCONF_ENABLE:
4823 resconf->options.tcp = DNS_RESCONF_TCP_ENABLE;
4824
4825 break;
4826 case DNS_RESCONF_ONE:
4827 case DNS_RESCONF_ONLY:
4828 resconf->options.tcp = DNS_RESCONF_TCP_ONLY;
4829
4830 break;
4831 case DNS_RESCONF_ZERO:
4832 case DNS_RESCONF_DISABLE:
4833 resconf->options.tcp = DNS_RESCONF_TCP_DISABLE;
4834
4835 break;
4836 default:
4837 break;
4838 } /* switch() */
4839
4840 break;
4841 default:
4842 break;
4843 } /* switch() */
4844 } /* for() */
4845
4846 break;
4847 case DNS_RESCONF_INTERFACE:
4848 for (i = 0, n = 0; dns_isdigit(words[2][i]); i++) {
4849 n *= 10;
4850 n += words[2][i] - '0';
4851 }
4852
4853 dns_resconf_setiface(resconf, words[1], n);
4854
4855 break;
4856 default:
4857 break;
4858 } /* switch() */
4859 } while (ch != EOF);
4860
4861 return 0;
4862 } /* dns_resconf_loadfile() */
4863
4864
dns_resconf_loadpath(struct dns_resolv_conf * resconf,const char * path)4865 int dns_resconf_loadpath(struct dns_resolv_conf *resconf, const char *path) {
4866 FILE *fp;
4867 int error;
4868
4869 if (!(fp = dns_fopen(path, "rt", &error)))
4870 return error;
4871
4872 error = dns_resconf_loadfile(resconf, fp);
4873
4874 fclose(fp);
4875
4876 return error;
4877 } /* dns_resconf_loadpath() */
4878
4879
4880 struct dns_anyconf {
4881 char *token[16];
4882 unsigned count;
4883 char buffer[1024], *tp, *cp;
4884 }; /* struct dns_anyconf */
4885
4886
dns_anyconf_reset(struct dns_anyconf * cf)4887 static void dns_anyconf_reset(struct dns_anyconf *cf) {
4888 cf->count = 0;
4889 cf->tp = cf->cp = cf->buffer;
4890 } /* dns_anyconf_reset() */
4891
4892
dns_anyconf_push(struct dns_anyconf * cf)4893 static int dns_anyconf_push(struct dns_anyconf *cf) {
4894 if (!(cf->cp < endof(cf->buffer) && cf->count < lengthof(cf->token)))
4895 return ENOMEM;
4896
4897 *cf->cp++ = '\0';
4898 cf->token[cf->count++] = cf->tp;
4899 cf->tp = cf->cp;
4900
4901 return 0;
4902 } /* dns_anyconf_push() */
4903
4904
dns_anyconf_pop(struct dns_anyconf * cf)4905 static void dns_anyconf_pop(struct dns_anyconf *cf) {
4906 if (cf->count > 0) {
4907 --cf->count;
4908 cf->tp = cf->cp = cf->token[cf->count];
4909 cf->token[cf->count] = 0;
4910 }
4911 } /* dns_anyconf_pop() */
4912
4913
dns_anyconf_addc(struct dns_anyconf * cf,int ch)4914 static int dns_anyconf_addc(struct dns_anyconf *cf, int ch) {
4915 if (!(cf->cp < endof(cf->buffer)))
4916 return ENOMEM;
4917
4918 *cf->cp++ = ch;
4919
4920 return 0;
4921 } /* dns_anyconf_addc() */
4922
4923
dns_anyconf_match(const char * pat,int mc)4924 static _Bool dns_anyconf_match(const char *pat, int mc) {
4925 _Bool match;
4926 int pc;
4927
4928 if (*pat == '^') {
4929 match = 0;
4930 ++pat;
4931 } else {
4932 match = 1;
4933 }
4934
4935 while ((pc = *(const unsigned char *)pat++)) {
4936 switch (pc) {
4937 case '%':
4938 if (!(pc = *(const unsigned char *)pat++))
4939 return !match;
4940
4941 switch (pc) {
4942 case 'a':
4943 if (dns_isalpha(mc))
4944 return match;
4945 break;
4946 case 'd':
4947 if (dns_isdigit(mc))
4948 return match;
4949 break;
4950 case 'w':
4951 if (dns_isalnum(mc))
4952 return match;
4953 break;
4954 case 's':
4955 if (dns_isspace(mc))
4956 return match;
4957 break;
4958 default:
4959 if (mc == pc)
4960 return match;
4961 break;
4962 } /* switch() */
4963
4964 break;
4965 default:
4966 if (mc == pc)
4967 return match;
4968 break;
4969 } /* switch() */
4970 } /* while() */
4971
4972 return !match;
4973 } /* dns_anyconf_match() */
4974
4975
dns_anyconf_peek(FILE * fp)4976 static int dns_anyconf_peek(FILE *fp) {
4977 int ch;
4978 ch = getc(fp);
4979 ungetc(ch, fp);
4980 return ch;
4981 } /* dns_anyconf_peek() */
4982
4983
dns_anyconf_skip(const char * pat,FILE * fp)4984 static size_t dns_anyconf_skip(const char *pat, FILE *fp) {
4985 size_t count = 0;
4986 int ch;
4987
4988 while (EOF != (ch = getc(fp))) {
4989 if (dns_anyconf_match(pat, ch)) {
4990 count++;
4991 continue;
4992 }
4993
4994 ungetc(ch, fp);
4995
4996 break;
4997 }
4998
4999 return count;
5000 } /* dns_anyconf_skip() */
5001
5002
dns_anyconf_scan(struct dns_anyconf * cf,const char * pat,FILE * fp,int * error)5003 static size_t dns_anyconf_scan(struct dns_anyconf *cf, const char *pat, FILE *fp, int *error) {
5004 size_t len;
5005 int ch;
5006
5007 while (EOF != (ch = getc(fp))) {
5008 if (dns_anyconf_match(pat, ch)) {
5009 if ((*error = dns_anyconf_addc(cf, ch)))
5010 return 0;
5011
5012 continue;
5013 } else {
5014 ungetc(ch, fp);
5015
5016 break;
5017 }
5018 }
5019
5020 if ((len = cf->cp - cf->tp)) {
5021 if ((*error = dns_anyconf_push(cf)))
5022 return 0;
5023
5024 return len;
5025 } else {
5026 *error = 0;
5027
5028 return 0;
5029 }
5030 } /* dns_anyconf_scan() */
5031
5032
dns_anyconf_dump(struct dns_anyconf * cf,FILE * fp)5033 DNS_NOTUSED static void dns_anyconf_dump(struct dns_anyconf *cf, FILE *fp) {
5034 unsigned i;
5035
5036 fprintf(fp, "tokens:");
5037
5038 for (i = 0; i < cf->count; i++) {
5039 fprintf(fp, " %s", cf->token[i]);
5040 }
5041
5042 fputc('\n', fp);
5043 } /* dns_anyconf_dump() */
5044
5045
5046 enum dns_nssconf_keyword {
5047 DNS_NSSCONF_INVALID = 0,
5048 DNS_NSSCONF_HOSTS = 1,
5049 DNS_NSSCONF_SUCCESS,
5050 DNS_NSSCONF_NOTFOUND,
5051 DNS_NSSCONF_UNAVAIL,
5052 DNS_NSSCONF_TRYAGAIN,
5053 DNS_NSSCONF_CONTINUE,
5054 DNS_NSSCONF_RETURN,
5055 DNS_NSSCONF_FILES,
5056 DNS_NSSCONF_DNS,
5057 DNS_NSSCONF_MDNS,
5058
5059 DNS_NSSCONF_LAST,
5060 }; /* enum dns_nssconf_keyword */
5061
dns_nssconf_keyword(const char * word)5062 static enum dns_nssconf_keyword dns_nssconf_keyword(const char *word) {
5063 static const char *list[] = {
5064 [DNS_NSSCONF_HOSTS] = "hosts",
5065 [DNS_NSSCONF_SUCCESS] = "success",
5066 [DNS_NSSCONF_NOTFOUND] = "notfound",
5067 [DNS_NSSCONF_UNAVAIL] = "unavail",
5068 [DNS_NSSCONF_TRYAGAIN] = "tryagain",
5069 [DNS_NSSCONF_CONTINUE] = "continue",
5070 [DNS_NSSCONF_RETURN] = "return",
5071 [DNS_NSSCONF_FILES] = "files",
5072 [DNS_NSSCONF_DNS] = "dns",
5073 [DNS_NSSCONF_MDNS] = "mdns",
5074 };
5075 unsigned i;
5076
5077 for (i = 1; i < lengthof(list); i++) {
5078 if (list[i] && 0 == strcasecmp(list[i], word))
5079 return i;
5080 }
5081
5082 return DNS_NSSCONF_INVALID;
5083 } /* dns_nssconf_keyword() */
5084
5085
dns_nssconf_c2k(int ch)5086 static enum dns_nssconf_keyword dns_nssconf_c2k(int ch) {
5087 static const char map[] = {
5088 ['S'] = DNS_NSSCONF_SUCCESS,
5089 ['N'] = DNS_NSSCONF_NOTFOUND,
5090 ['U'] = DNS_NSSCONF_UNAVAIL,
5091 ['T'] = DNS_NSSCONF_TRYAGAIN,
5092 ['C'] = DNS_NSSCONF_CONTINUE,
5093 ['R'] = DNS_NSSCONF_RETURN,
5094 ['f'] = DNS_NSSCONF_FILES,
5095 ['F'] = DNS_NSSCONF_FILES,
5096 ['d'] = DNS_NSSCONF_DNS,
5097 ['D'] = DNS_NSSCONF_DNS,
5098 ['b'] = DNS_NSSCONF_DNS,
5099 ['B'] = DNS_NSSCONF_DNS,
5100 ['m'] = DNS_NSSCONF_MDNS,
5101 ['M'] = DNS_NSSCONF_MDNS,
5102 };
5103
5104 return (ch >= 0 && ch < (int)lengthof(map))? map[ch] : DNS_NSSCONF_INVALID;
5105 } /* dns_nssconf_c2k() */
5106
5107
5108 DNS_PRAGMA_PUSH
5109 DNS_PRAGMA_QUIET
5110
dns_nssconf_k2c(int k)5111 static int dns_nssconf_k2c(int k) {
5112 static const char map[DNS_NSSCONF_LAST] = {
5113 [DNS_NSSCONF_SUCCESS] = 'S',
5114 [DNS_NSSCONF_NOTFOUND] = 'N',
5115 [DNS_NSSCONF_UNAVAIL] = 'U',
5116 [DNS_NSSCONF_TRYAGAIN] = 'T',
5117 [DNS_NSSCONF_CONTINUE] = 'C',
5118 [DNS_NSSCONF_RETURN] = 'R',
5119 [DNS_NSSCONF_FILES] = 'f',
5120 [DNS_NSSCONF_DNS] = 'b',
5121 [DNS_NSSCONF_MDNS] = 'm',
5122 };
5123
5124 return (k >= 0 && k < (int)lengthof(map))? (map[k]? map[k] : '?') : '?';
5125 } /* dns_nssconf_k2c() */
5126
dns_nssconf_k2s(int k)5127 static const char *dns_nssconf_k2s(int k) {
5128 static const char *const map[DNS_NSSCONF_LAST] = {
5129 [DNS_NSSCONF_SUCCESS] = "SUCCESS",
5130 [DNS_NSSCONF_NOTFOUND] = "NOTFOUND",
5131 [DNS_NSSCONF_UNAVAIL] = "UNAVAIL",
5132 [DNS_NSSCONF_TRYAGAIN] = "TRYAGAIN",
5133 [DNS_NSSCONF_CONTINUE] = "continue",
5134 [DNS_NSSCONF_RETURN] = "return",
5135 [DNS_NSSCONF_FILES] = "files",
5136 [DNS_NSSCONF_DNS] = "dns",
5137 [DNS_NSSCONF_MDNS] = "mdns",
5138 };
5139
5140 return (k >= 0 && k < (int)lengthof(map))? (map[k]? map[k] : "") : "";
5141 } /* dns_nssconf_k2s() */
5142
5143 DNS_PRAGMA_POP
5144
5145
dns_nssconf_loadfile(struct dns_resolv_conf * resconf,FILE * fp)5146 int dns_nssconf_loadfile(struct dns_resolv_conf *resconf, FILE *fp) {
5147 enum dns_nssconf_keyword source, status, action;
5148 char lookup[sizeof resconf->lookup] = "", *lp;
5149 struct dns_anyconf cf;
5150 size_t i;
5151 int error;
5152
5153 while (!feof(fp) && !ferror(fp)) {
5154 dns_anyconf_reset(&cf);
5155
5156 dns_anyconf_skip("%s", fp);
5157
5158 if (!dns_anyconf_scan(&cf, "%w_", fp, &error))
5159 goto nextent;
5160
5161 if (DNS_NSSCONF_HOSTS != dns_nssconf_keyword(cf.token[0]))
5162 goto nextent;
5163
5164 dns_anyconf_pop(&cf);
5165
5166 if (!dns_anyconf_skip(": \t", fp))
5167 goto nextent;
5168
5169 *(lp = lookup) = '\0';
5170
5171 while (dns_anyconf_scan(&cf, "%w_", fp, &error)) {
5172 dns_anyconf_skip(" \t", fp);
5173
5174 if ('[' == dns_anyconf_peek(fp)) {
5175 dns_anyconf_skip("[! \t", fp);
5176
5177 while (dns_anyconf_scan(&cf, "%w_", fp, &error)) {
5178 dns_anyconf_skip("= \t", fp);
5179 if (!dns_anyconf_scan(&cf, "%w_", fp, &error)) {
5180 dns_anyconf_pop(&cf); /* discard status */
5181 dns_anyconf_skip("^#;]\n", fp); /* skip to end of criteria */
5182 break;
5183 }
5184 dns_anyconf_skip(" \t", fp);
5185 }
5186
5187 dns_anyconf_skip("] \t", fp);
5188 }
5189
5190 if ((size_t)(endof(lookup) - lp) < cf.count + 1) /* +1 for '\0' */
5191 goto nextsrc;
5192
5193 source = dns_nssconf_keyword(cf.token[0]);
5194
5195 switch (source) {
5196 case DNS_NSSCONF_DNS:
5197 case DNS_NSSCONF_MDNS:
5198 case DNS_NSSCONF_FILES:
5199 *lp++ = dns_nssconf_k2c(source);
5200 break;
5201 default:
5202 goto nextsrc;
5203 }
5204
5205 for (i = 1; i + 1 < cf.count; i += 2) {
5206 status = dns_nssconf_keyword(cf.token[i]);
5207 action = dns_nssconf_keyword(cf.token[i + 1]);
5208
5209 switch (status) {
5210 case DNS_NSSCONF_SUCCESS:
5211 case DNS_NSSCONF_NOTFOUND:
5212 case DNS_NSSCONF_UNAVAIL:
5213 case DNS_NSSCONF_TRYAGAIN:
5214 *lp++ = dns_nssconf_k2c(status);
5215 break;
5216 default:
5217 continue;
5218 }
5219
5220 switch (action) {
5221 case DNS_NSSCONF_CONTINUE:
5222 case DNS_NSSCONF_RETURN:
5223 break;
5224 default:
5225 action = (status == DNS_NSSCONF_SUCCESS)
5226 ? DNS_NSSCONF_RETURN
5227 : DNS_NSSCONF_CONTINUE;
5228 break;
5229 }
5230
5231 *lp++ = dns_nssconf_k2c(action);
5232 }
5233 nextsrc:
5234 *lp = '\0';
5235 dns_anyconf_reset(&cf);
5236 }
5237 nextent:
5238 dns_anyconf_skip("^\n", fp);
5239 }
5240
5241 if (*lookup)
5242 strncpy(resconf->lookup, lookup, sizeof resconf->lookup);
5243
5244 return 0;
5245 } /* dns_nssconf_loadfile() */
5246
5247
dns_nssconf_loadpath(struct dns_resolv_conf * resconf,const char * path)5248 int dns_nssconf_loadpath(struct dns_resolv_conf *resconf, const char *path) {
5249 FILE *fp;
5250 int error;
5251
5252 if (!(fp = dns_fopen(path, "rt", &error)))
5253 return error;
5254
5255 error = dns_nssconf_loadfile(resconf, fp);
5256
5257 fclose(fp);
5258
5259 return error;
5260 } /* dns_nssconf_loadpath() */
5261
5262
5263 struct dns_nssconf_source {
5264 enum dns_nssconf_keyword source, success, notfound, unavail, tryagain;
5265 }; /* struct dns_nssconf_source */
5266
5267 typedef unsigned dns_nssconf_i;
5268
dns_nssconf_peek(const struct dns_resolv_conf * resconf,dns_nssconf_i state)5269 static inline int dns_nssconf_peek(const struct dns_resolv_conf *resconf, dns_nssconf_i state) {
5270 return (state < lengthof(resconf->lookup) && resconf->lookup[state])? resconf->lookup[state] : 0;
5271 } /* dns_nssconf_peek() */
5272
dns_nssconf_next(struct dns_nssconf_source * src,const struct dns_resolv_conf * resconf,dns_nssconf_i * state)5273 static _Bool dns_nssconf_next(struct dns_nssconf_source *src, const struct dns_resolv_conf *resconf, dns_nssconf_i *state) {
5274 int source, status, action;
5275
5276 src->source = DNS_NSSCONF_INVALID;
5277 src->success = DNS_NSSCONF_RETURN;
5278 src->notfound = DNS_NSSCONF_CONTINUE;
5279 src->unavail = DNS_NSSCONF_CONTINUE;
5280 src->tryagain = DNS_NSSCONF_CONTINUE;
5281
5282 while ((source = dns_nssconf_peek(resconf, *state))) {
5283 source = dns_nssconf_c2k(source);
5284 ++*state;
5285
5286 switch (source) {
5287 case DNS_NSSCONF_FILES:
5288 case DNS_NSSCONF_DNS:
5289 case DNS_NSSCONF_MDNS:
5290 src->source = source;
5291 break;
5292 default:
5293 continue;
5294 }
5295
5296 while ((status = dns_nssconf_peek(resconf, *state)) && (action = dns_nssconf_peek(resconf, *state + 1))) {
5297 status = dns_nssconf_c2k(status);
5298 action = dns_nssconf_c2k(action);
5299
5300 switch (action) {
5301 case DNS_NSSCONF_RETURN:
5302 case DNS_NSSCONF_CONTINUE:
5303 break;
5304 default:
5305 goto done;
5306 }
5307
5308 switch (status) {
5309 case DNS_NSSCONF_SUCCESS:
5310 src->success = action;
5311 break;
5312 case DNS_NSSCONF_NOTFOUND:
5313 src->notfound = action;
5314 break;
5315 case DNS_NSSCONF_UNAVAIL:
5316 src->unavail = action;
5317 break;
5318 case DNS_NSSCONF_TRYAGAIN:
5319 src->tryagain = action;
5320 break;
5321 default:
5322 goto done;
5323 }
5324
5325 *state += 2;
5326 }
5327
5328 break;
5329 }
5330 done:
5331 return src->source != DNS_NSSCONF_INVALID;
5332 } /* dns_nssconf_next() */
5333
5334
dns_nssconf_dump_status(int status,int action,unsigned * count,FILE * fp)5335 static int dns_nssconf_dump_status(int status, int action, unsigned *count, FILE *fp) {
5336 switch (status) {
5337 case DNS_NSSCONF_SUCCESS:
5338 if (action == DNS_NSSCONF_RETURN)
5339 return 0;
5340 break;
5341 default:
5342 if (action == DNS_NSSCONF_CONTINUE)
5343 return 0;
5344 break;
5345 }
5346
5347 fputc(' ', fp);
5348
5349 if (!*count)
5350 fputc('[', fp);
5351
5352 fprintf(fp, "%s=%s", dns_nssconf_k2s(status), dns_nssconf_k2s(action));
5353
5354 ++*count;
5355
5356 return 0;
5357 } /* dns_nssconf_dump_status() */
5358
5359
dns_nssconf_dump(struct dns_resolv_conf * resconf,FILE * fp)5360 int dns_nssconf_dump(struct dns_resolv_conf *resconf, FILE *fp) {
5361 struct dns_nssconf_source src;
5362 dns_nssconf_i i = 0;
5363
5364 fputs("hosts:", fp);
5365
5366 while (dns_nssconf_next(&src, resconf, &i)) {
5367 unsigned n = 0;
5368
5369 fprintf(fp, " %s", dns_nssconf_k2s(src.source));
5370
5371 dns_nssconf_dump_status(DNS_NSSCONF_SUCCESS, src.success, &n, fp);
5372 dns_nssconf_dump_status(DNS_NSSCONF_NOTFOUND, src.notfound, &n, fp);
5373 dns_nssconf_dump_status(DNS_NSSCONF_UNAVAIL, src.unavail, &n, fp);
5374 dns_nssconf_dump_status(DNS_NSSCONF_TRYAGAIN, src.tryagain, &n, fp);
5375
5376 if (n)
5377 fputc(']', fp);
5378 }
5379
5380 fputc('\n', fp);
5381
5382 return 0;
5383 } /* dns_nssconf_dump() */
5384
5385
dns_resconf_setiface(struct dns_resolv_conf * resconf,const char * addr,unsigned short port)5386 int dns_resconf_setiface(struct dns_resolv_conf *resconf, const char *addr, unsigned short port) {
5387 int af = (strchr(addr, ':'))? AF_INET6 : AF_INET;
5388 int error;
5389
5390 if ((error = dns_pton(af, addr, dns_sa_addr(af, &resconf->iface, NULL))))
5391 return error;
5392
5393 *dns_sa_port(af, &resconf->iface) = htons(port);
5394 resconf->iface.ss_family = af;
5395
5396 return 0;
5397 } /* dns_resconf_setiface() */
5398
5399
5400 #define DNS_SM_RESTORE \
5401 do { \
5402 pc = 0xff & (*state >> 0); \
5403 srchi = 0xff & (*state >> 8); \
5404 ndots = 0xff & (*state >> 16); \
5405 } while (0)
5406
5407 #define DNS_SM_SAVE \
5408 do { \
5409 *state = ((0xff & pc) << 0) \
5410 | ((0xff & srchi) << 8) \
5411 | ((0xff & ndots) << 16); \
5412 } while (0)
5413
dns_resconf_search(void * dst,size_t lim,const void * qname,size_t qlen,struct dns_resolv_conf * resconf,dns_resconf_i_t * state)5414 size_t dns_resconf_search(void *dst, size_t lim, const void *qname, size_t qlen, struct dns_resolv_conf *resconf, dns_resconf_i_t *state) {
5415 unsigned pc, srchi, ndots, len;
5416
5417 DNS_SM_ENTER;
5418
5419 /* if FQDN then return as-is and finish */
5420 if (dns_d_isanchored(qname, qlen)) {
5421 len = dns_d_anchor(dst, lim, qname, qlen);
5422 DNS_SM_YIELD(len);
5423 DNS_SM_EXIT;
5424 }
5425
5426 ndots = dns_d_ndots(qname, qlen);
5427
5428 if (ndots >= resconf->options.ndots) {
5429 len = dns_d_anchor(dst, lim, qname, qlen);
5430 DNS_SM_YIELD(len);
5431 }
5432
5433 while (srchi < lengthof(resconf->search) && resconf->search[srchi][0]) {
5434 struct dns_buf buf = DNS_B_INTO(dst, lim);
5435 const char *dn = resconf->search[srchi++];
5436
5437 dns_b_put(&buf, qname, qlen);
5438 dns_b_putc(&buf, '.');
5439 dns_b_puts(&buf, dn);
5440 if (!dns_d_isanchored(dn, strlen(dn)))
5441 dns_b_putc(&buf, '.');
5442 len = dns_b_strllen(&buf);
5443 DNS_SM_YIELD(len);
5444 }
5445
5446 if (ndots < resconf->options.ndots) {
5447 len = dns_d_anchor(dst, lim, qname, qlen);
5448 DNS_SM_YIELD(len);
5449 }
5450
5451 DNS_SM_LEAVE;
5452
5453 return dns_strlcpy(dst, "", lim);
5454 } /* dns_resconf_search() */
5455
5456 #undef DNS_SM_SAVE
5457 #undef DNS_SM_RESTORE
5458
5459
dns_resconf_dump(struct dns_resolv_conf * resconf,FILE * fp)5460 int dns_resconf_dump(struct dns_resolv_conf *resconf, FILE *fp) {
5461 unsigned i;
5462 int af;
5463
5464 for (i = 0; i < lengthof(resconf->nameserver) && (af = resconf->nameserver[i].ss_family) != AF_UNSPEC; i++) {
5465 char addr[INET6_ADDRSTRLEN + 1] = "[INVALID]";
5466 unsigned short port;
5467
5468 dns_inet_ntop(af, dns_sa_addr(af, &resconf->nameserver[i], NULL), addr, sizeof addr);
5469 port = ntohs(*dns_sa_port(af, &resconf->nameserver[i]));
5470
5471 if (port == 53)
5472 fprintf(fp, "nameserver %s\n", addr);
5473 else
5474 fprintf(fp, "nameserver [%s]:%hu\n", addr, port);
5475 }
5476
5477
5478 fprintf(fp, "search");
5479
5480 for (i = 0; i < lengthof(resconf->search) && resconf->search[i][0]; i++)
5481 fprintf(fp, " %s", resconf->search[i]);
5482
5483 fputc('\n', fp);
5484
5485
5486 fputs("; ", fp);
5487 dns_nssconf_dump(resconf, fp);
5488
5489 fprintf(fp, "lookup");
5490
5491 for (i = 0; i < lengthof(resconf->lookup) && resconf->lookup[i]; i++) {
5492 switch (resconf->lookup[i]) {
5493 case 'b':
5494 fprintf(fp, " bind"); break;
5495 case 'f':
5496 fprintf(fp, " file"); break;
5497 case 'c':
5498 fprintf(fp, " cache"); break;
5499 }
5500 }
5501
5502 fputc('\n', fp);
5503
5504
5505 fprintf(fp, "options ndots:%u timeout:%u attempts:%u", resconf->options.ndots, resconf->options.timeout, resconf->options.attempts);
5506
5507 if (resconf->options.edns0)
5508 fprintf(fp, " edns0");
5509 if (resconf->options.rotate)
5510 fprintf(fp, " rotate");
5511 if (resconf->options.recurse)
5512 fprintf(fp, " recurse");
5513 if (resconf->options.smart)
5514 fprintf(fp, " smart");
5515
5516 switch (resconf->options.tcp) {
5517 case DNS_RESCONF_TCP_ENABLE:
5518 break;
5519 case DNS_RESCONF_TCP_ONLY:
5520 fprintf(fp, " tcp");
5521 break;
5522 case DNS_RESCONF_TCP_DISABLE:
5523 fprintf(fp, " tcp:disable");
5524 break;
5525 }
5526
5527 fputc('\n', fp);
5528
5529
5530 if ((af = resconf->iface.ss_family) != AF_UNSPEC) {
5531 char addr[INET6_ADDRSTRLEN + 1] = "[INVALID]";
5532
5533 dns_inet_ntop(af, dns_sa_addr(af, &resconf->iface, NULL), addr, sizeof addr);
5534
5535 fprintf(fp, "interface %s %hu\n", addr, ntohs(*dns_sa_port(af, &resconf->iface)));
5536 }
5537
5538 return 0;
5539 } /* dns_resconf_dump() */
5540
5541
5542 /*
5543 * H I N T S E R V E R R O U T I N E S
5544 *
5545 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5546
5547 struct dns_hints_soa {
5548 unsigned char zone[DNS_D_MAXNAME + 1];
5549
5550 struct {
5551 struct sockaddr_storage ss;
5552 unsigned priority;
5553 } addrs[16];
5554
5555 unsigned count;
5556
5557 struct dns_hints_soa *next;
5558 }; /* struct dns_hints_soa */
5559
5560
5561 struct dns_hints {
5562 dns_atomic_t refcount;
5563
5564 struct dns_hints_soa *head;
5565 }; /* struct dns_hints */
5566
5567
dns_hints_open(struct dns_resolv_conf * resconf,int * error)5568 struct dns_hints *dns_hints_open(struct dns_resolv_conf *resconf, int *error) {
5569 static const struct dns_hints H_initializer;
5570 struct dns_hints *H;
5571
5572 (void)resconf;
5573
5574 if (!(H = malloc(sizeof *H)))
5575 goto syerr;
5576
5577 *H = H_initializer;
5578
5579 dns_hints_acquire(H);
5580
5581 return H;
5582 syerr:
5583 *error = dns_syerr();
5584
5585 free(H);
5586
5587 return 0;
5588 } /* dns_hints_open() */
5589
5590
dns_hints_close(struct dns_hints * H)5591 void dns_hints_close(struct dns_hints *H) {
5592 struct dns_hints_soa *soa, *nxt;
5593
5594 if (!H || 1 != dns_hints_release(H))
5595 return /* void */;
5596
5597 for (soa = H->head; soa; soa = nxt) {
5598 nxt = soa->next;
5599
5600 free(soa);
5601 }
5602
5603 free(H);
5604
5605 return /* void */;
5606 } /* dns_hints_close() */
5607
5608
dns_hints_acquire(struct dns_hints * H)5609 dns_refcount_t dns_hints_acquire(struct dns_hints *H) {
5610 return dns_atomic_fetch_add(&H->refcount);
5611 } /* dns_hints_acquire() */
5612
5613
dns_hints_release(struct dns_hints * H)5614 dns_refcount_t dns_hints_release(struct dns_hints *H) {
5615 return dns_atomic_fetch_sub(&H->refcount);
5616 } /* dns_hints_release() */
5617
5618
dns_hints_mortal(struct dns_hints * hints)5619 struct dns_hints *dns_hints_mortal(struct dns_hints *hints) {
5620 if (hints)
5621 dns_hints_release(hints);
5622
5623 return hints;
5624 } /* dns_hints_mortal() */
5625
5626
dns_hints_local(struct dns_resolv_conf * resconf,int * error_)5627 struct dns_hints *dns_hints_local(struct dns_resolv_conf *resconf, int *error_) {
5628 struct dns_hints *hints = 0;
5629 int error;
5630
5631 if (resconf)
5632 dns_resconf_acquire(resconf);
5633 else if (!(resconf = dns_resconf_local(&error)))
5634 goto error;
5635
5636 if (!(hints = dns_hints_open(resconf, &error)))
5637 goto error;
5638
5639 error = 0;
5640
5641 if (0 == dns_hints_insert_resconf(hints, ".", resconf, &error) && error)
5642 goto error;
5643
5644 dns_resconf_close(resconf);
5645
5646 return hints;
5647 error:
5648 *error_ = error;
5649
5650 dns_resconf_close(resconf);
5651 dns_hints_close(hints);
5652
5653 return 0;
5654 } /* dns_hints_local() */
5655
5656
dns_hints_root(struct dns_resolv_conf * resconf,int * error_)5657 struct dns_hints *dns_hints_root(struct dns_resolv_conf *resconf, int *error_) {
5658 static const struct {
5659 int af;
5660 char addr[INET6_ADDRSTRLEN];
5661 } root_hints[] = {
5662 { AF_INET, "198.41.0.4" }, /* A.ROOT-SERVERS.NET. */
5663 { AF_INET6, "2001:503:ba3e::2:30" }, /* A.ROOT-SERVERS.NET. */
5664 { AF_INET, "192.228.79.201" }, /* B.ROOT-SERVERS.NET. */
5665 { AF_INET6, "2001:500:84::b" }, /* B.ROOT-SERVERS.NET. */
5666 { AF_INET, "192.33.4.12" }, /* C.ROOT-SERVERS.NET. */
5667 { AF_INET6, "2001:500:2::c" }, /* C.ROOT-SERVERS.NET. */
5668 { AF_INET, "199.7.91.13" }, /* D.ROOT-SERVERS.NET. */
5669 { AF_INET6, "2001:500:2d::d" }, /* D.ROOT-SERVERS.NET. */
5670 { AF_INET, "192.203.230.10" }, /* E.ROOT-SERVERS.NET. */
5671 { AF_INET, "192.5.5.241" }, /* F.ROOT-SERVERS.NET. */
5672 { AF_INET6, "2001:500:2f::f" }, /* F.ROOT-SERVERS.NET. */
5673 { AF_INET, "192.112.36.4" }, /* G.ROOT-SERVERS.NET. */
5674 { AF_INET, "128.63.2.53" }, /* H.ROOT-SERVERS.NET. */
5675 { AF_INET6, "2001:500:1::803f:235" }, /* H.ROOT-SERVERS.NET. */
5676 { AF_INET, "192.36.148.17" }, /* I.ROOT-SERVERS.NET. */
5677 { AF_INET6, "2001:7FE::53" }, /* I.ROOT-SERVERS.NET. */
5678 { AF_INET, "192.58.128.30" }, /* J.ROOT-SERVERS.NET. */
5679 { AF_INET6, "2001:503:c27::2:30" }, /* J.ROOT-SERVERS.NET. */
5680 { AF_INET, "193.0.14.129" }, /* K.ROOT-SERVERS.NET. */
5681 { AF_INET6, "2001:7FD::1" }, /* K.ROOT-SERVERS.NET. */
5682 { AF_INET, "199.7.83.42" }, /* L.ROOT-SERVERS.NET. */
5683 { AF_INET6, "2001:500:3::42" }, /* L.ROOT-SERVERS.NET. */
5684 { AF_INET, "202.12.27.33" }, /* M.ROOT-SERVERS.NET. */
5685 { AF_INET6, "2001:DC3::35" }, /* M.ROOT-SERVERS.NET. */
5686 };
5687 struct dns_hints *hints = 0;
5688 struct sockaddr_storage ss;
5689 unsigned i;
5690 int error, af;
5691
5692 if (!(hints = dns_hints_open(resconf, &error)))
5693 goto error;
5694
5695 for (i = 0; i < lengthof(root_hints); i++) {
5696 af = root_hints[i].af;
5697
5698 if ((error = dns_pton(af, root_hints[i].addr, dns_sa_addr(af, &ss, NULL))))
5699 goto error;
5700
5701 *dns_sa_port(af, &ss) = htons(53);
5702 ss.ss_family = af;
5703
5704 if ((error = dns_hints_insert(hints, ".", (struct sockaddr *)&ss, 1)))
5705 goto error;
5706 }
5707
5708 return hints;
5709 error:
5710 *error_ = error;
5711
5712 dns_hints_close(hints);
5713
5714 return 0;
5715 } /* dns_hints_root() */
5716
5717
dns_hints_fetch(struct dns_hints * H,const char * zone)5718 static struct dns_hints_soa *dns_hints_fetch(struct dns_hints *H, const char *zone) {
5719 struct dns_hints_soa *soa;
5720
5721 for (soa = H->head; soa; soa = soa->next) {
5722 if (0 == strcasecmp(zone, (char *)soa->zone))
5723 return soa;
5724 }
5725
5726 return 0;
5727 } /* dns_hints_fetch() */
5728
5729
dns_hints_insert(struct dns_hints * H,const char * zone,const struct sockaddr * sa,unsigned priority)5730 int dns_hints_insert(struct dns_hints *H, const char *zone, const struct sockaddr *sa, unsigned priority) {
5731 static const struct dns_hints_soa soa_initializer;
5732 struct dns_hints_soa *soa;
5733 unsigned i;
5734
5735 if (!(soa = dns_hints_fetch(H, zone))) {
5736 if (!(soa = malloc(sizeof *soa)))
5737 return dns_syerr();
5738 *soa = soa_initializer;
5739 dns_strlcpy((char *)soa->zone, zone, sizeof soa->zone);
5740
5741 soa->next = H->head;
5742 H->head = soa;
5743 }
5744
5745 i = soa->count % lengthof(soa->addrs);
5746
5747 memcpy(&soa->addrs[i].ss, sa, dns_sa_len(sa));
5748
5749 soa->addrs[i].priority = DNS_PP_MAX(1, priority);
5750
5751 if (soa->count < lengthof(soa->addrs))
5752 soa->count++;
5753
5754 return 0;
5755 } /* dns_hints_insert() */
5756
5757
dns_hints_isinaddr_any(const void * sa)5758 static _Bool dns_hints_isinaddr_any(const void *sa) {
5759 struct in_addr *addr;
5760
5761 if (dns_sa_family(sa) != AF_INET)
5762 return 0;
5763
5764 addr = dns_sa_addr(AF_INET, sa, NULL);
5765 return addr->s_addr == htonl(INADDR_ANY);
5766 }
5767
dns_hints_insert_resconf(struct dns_hints * H,const char * zone,const struct dns_resolv_conf * resconf,int * error_)5768 unsigned dns_hints_insert_resconf(struct dns_hints *H, const char *zone, const struct dns_resolv_conf *resconf, int *error_) {
5769 unsigned i, n, p;
5770 int error;
5771
5772 for (i = 0, n = 0, p = 1; i < lengthof(resconf->nameserver) && resconf->nameserver[i].ss_family != AF_UNSPEC; i++, n++) {
5773 union { struct sockaddr_in sin; } tmp;
5774 struct sockaddr *ns;
5775
5776 /*
5777 * dns_resconf_open initializes nameserver[0] to INADDR_ANY.
5778 *
5779 * Traditionally the semantics of 0.0.0.0 meant the default
5780 * interface, which evolved to mean the loopback interface.
5781 * See comment block preceding resolv/res_init.c:res_init in
5782 * glibc 2.23. As of 2.23, glibc no longer translates
5783 * 0.0.0.0 despite the code comment, but it does default to
5784 * 127.0.0.1 when no nameservers are present.
5785 *
5786 * BIND9 as of 9.10.3 still translates 0.0.0.0 to 127.0.0.1.
5787 * See lib/lwres/lwconfig.c:lwres_create_addr and the
5788 * convert_zero flag. 127.0.0.1 is also the default when no
5789 * nameservers are present.
5790 */
5791 if (dns_hints_isinaddr_any(&resconf->nameserver[i])) {
5792 memcpy(&tmp.sin, &resconf->nameserver[i], sizeof tmp.sin);
5793 tmp.sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
5794 ns = (struct sockaddr *)&tmp.sin;
5795 } else {
5796 ns = (struct sockaddr *)&resconf->nameserver[i];
5797 }
5798
5799 if ((error = dns_hints_insert(H, zone, ns, p)))
5800 goto error;
5801
5802 p += !resconf->options.rotate;
5803 }
5804
5805 return n;
5806 error:
5807 *error_ = error;
5808
5809 return n;
5810 } /* dns_hints_insert_resconf() */
5811
5812
dns_hints_i_cmp(unsigned a,unsigned b,struct dns_hints_i * i,struct dns_hints_soa * soa)5813 static int dns_hints_i_cmp(unsigned a, unsigned b, struct dns_hints_i *i, struct dns_hints_soa *soa) {
5814 int cmp;
5815
5816 if ((cmp = soa->addrs[a].priority - soa->addrs[b].priority))
5817 return cmp;
5818
5819 return dns_k_shuffle16(a, i->state.seed) - dns_k_shuffle16(b, i->state.seed);
5820 } /* dns_hints_i_cmp() */
5821
5822
dns_hints_i_start(struct dns_hints_i * i,struct dns_hints_soa * soa)5823 static unsigned dns_hints_i_start(struct dns_hints_i *i, struct dns_hints_soa *soa) {
5824 unsigned p0, p;
5825
5826 p0 = 0;
5827
5828 for (p = 1; p < soa->count; p++) {
5829 if (dns_hints_i_cmp(p, p0, i, soa) < 0)
5830 p0 = p;
5831 }
5832
5833 return p0;
5834 } /* dns_hints_i_start() */
5835
5836
dns_hints_i_skip(unsigned p0,struct dns_hints_i * i,struct dns_hints_soa * soa)5837 static unsigned dns_hints_i_skip(unsigned p0, struct dns_hints_i *i, struct dns_hints_soa *soa) {
5838 unsigned pZ, p;
5839
5840 for (pZ = 0; pZ < soa->count; pZ++) {
5841 if (dns_hints_i_cmp(pZ, p0, i, soa) > 0)
5842 goto cont;
5843 }
5844
5845 return soa->count;
5846 cont:
5847 for (p = pZ + 1; p < soa->count; p++) {
5848 if (dns_hints_i_cmp(p, p0, i, soa) <= 0)
5849 continue;
5850
5851 if (dns_hints_i_cmp(p, pZ, i, soa) >= 0)
5852 continue;
5853
5854 pZ = p;
5855 }
5856
5857
5858 return pZ;
5859 } /* dns_hints_i_skip() */
5860
5861
dns_hints_i_init(struct dns_hints_i * i,struct dns_hints * hints)5862 static struct dns_hints_i *dns_hints_i_init(struct dns_hints_i *i, struct dns_hints *hints) {
5863 static const struct dns_hints_i i_initializer;
5864 struct dns_hints_soa *soa;
5865
5866 i->state = i_initializer.state;
5867
5868 do {
5869 i->state.seed = dns_random();
5870 } while (0 == i->state.seed);
5871
5872 if ((soa = dns_hints_fetch(hints, i->zone))) {
5873 i->state.next = dns_hints_i_start(i, soa);
5874 }
5875
5876 return i;
5877 } /* dns_hints_i_init() */
5878
5879
dns_hints_grep(struct sockaddr ** sa,socklen_t * sa_len,unsigned lim,struct dns_hints_i * i,struct dns_hints * H)5880 unsigned dns_hints_grep(struct sockaddr **sa, socklen_t *sa_len, unsigned lim, struct dns_hints_i *i, struct dns_hints *H) {
5881 struct dns_hints_soa *soa;
5882 unsigned n;
5883
5884 if (!(soa = dns_hints_fetch(H, i->zone)))
5885 return 0;
5886
5887 n = 0;
5888
5889 while (i->state.next < soa->count && n < lim) {
5890 *sa = (struct sockaddr *)&soa->addrs[i->state.next].ss;
5891 *sa_len = dns_sa_len(*sa);
5892
5893 sa++;
5894 sa_len++;
5895 n++;
5896
5897 i->state.next = dns_hints_i_skip(i->state.next, i, soa);
5898 }
5899
5900 return n;
5901 } /* dns_hints_grep() */
5902
5903
dns_hints_query(struct dns_hints * hints,struct dns_packet * Q,int * error_)5904 struct dns_packet *dns_hints_query(struct dns_hints *hints, struct dns_packet *Q, int *error_) {
5905 struct dns_packet *A, *P;
5906 struct dns_rr rr;
5907 char zone[DNS_D_MAXNAME + 1];
5908 size_t zlen;
5909 struct dns_hints_i i;
5910 struct sockaddr *sa;
5911 socklen_t slen;
5912 int error;
5913
5914 if (!dns_rr_grep(&rr, 1, dns_rr_i_new(Q, .section = DNS_S_QUESTION), Q, &error))
5915 goto error;
5916
5917 if (!(zlen = dns_d_expand(zone, sizeof zone, rr.dn.p, Q, &error)))
5918 goto error;
5919 else if (zlen >= sizeof zone)
5920 goto toolong;
5921
5922 P = dns_p_new(512);
5923 dns_header(P)->qr = 1;
5924
5925 if ((error = dns_rr_copy(P, &rr, Q)))
5926 goto error;
5927
5928 if ((error = dns_p_push(P, DNS_S_AUTHORITY, ".", strlen("."), DNS_T_NS, DNS_C_IN, 0, "hints.local.")))
5929 goto error;
5930
5931 do {
5932 i.zone = zone;
5933
5934 dns_hints_i_init(&i, hints);
5935
5936 while (dns_hints_grep(&sa, &slen, 1, &i, hints)) {
5937 int af = sa->sa_family;
5938 int rtype = (af == AF_INET6)? DNS_T_AAAA : DNS_T_A;
5939
5940 if ((error = dns_p_push(P, DNS_S_ADDITIONAL, "hints.local.", strlen("hints.local."), rtype, DNS_C_IN, 0, dns_sa_addr(af, sa, NULL))))
5941 goto error;
5942 }
5943 } while ((zlen = dns_d_cleave(zone, sizeof zone, zone, zlen)));
5944
5945 if (!(A = dns_p_copy(dns_p_make(P->end, &error), P)))
5946 goto error;
5947
5948 return A;
5949 toolong:
5950 error = DNS_EILLEGAL;
5951 error:
5952 *error_ = error;
5953
5954 return 0;
5955 } /* dns_hints_query() */
5956
5957
5958 /** ugly hack to support specifying ports other than 53 in resolv.conf. */
dns_hints_port(struct dns_hints * hints,int af,void * addr)5959 static unsigned short dns_hints_port(struct dns_hints *hints, int af, void *addr) {
5960 struct dns_hints_soa *soa;
5961 void *addrsoa;
5962 socklen_t addrlen;
5963 unsigned short port;
5964 unsigned i;
5965
5966 for (soa = hints->head; soa; soa = soa->next) {
5967 for (i = 0; i < soa->count; i++) {
5968 if (af != soa->addrs[i].ss.ss_family)
5969 continue;
5970
5971 if (!(addrsoa = dns_sa_addr(af, &soa->addrs[i].ss, &addrlen)))
5972 continue;
5973
5974 if (memcmp(addr, addrsoa, addrlen))
5975 continue;
5976
5977 port = *dns_sa_port(af, &soa->addrs[i].ss);
5978
5979 return (port)? port : htons(53);
5980 }
5981 }
5982
5983 return htons(53);
5984 } /* dns_hints_port() */
5985
5986
dns_hints_dump(struct dns_hints * hints,FILE * fp)5987 int dns_hints_dump(struct dns_hints *hints, FILE *fp) {
5988 struct dns_hints_soa *soa;
5989 char addr[INET6_ADDRSTRLEN];
5990 unsigned i;
5991 int af, error;
5992
5993 for (soa = hints->head; soa; soa = soa->next) {
5994 fprintf(fp, "ZONE \"%s\"\n", soa->zone);
5995
5996 for (i = 0; i < soa->count; i++) {
5997 af = soa->addrs[i].ss.ss_family;
5998
5999 if ((error = dns_ntop(af, dns_sa_addr(af, &soa->addrs[i].ss, NULL), addr, sizeof addr)))
6000 return error;
6001
6002 fprintf(fp, "\t(%d) [%s]:%hu\n", (int)soa->addrs[i].priority, addr, ntohs(*dns_sa_port(af, &soa->addrs[i].ss)));
6003 }
6004 }
6005
6006 return 0;
6007 } /* dns_hints_dump() */
6008
6009
6010 /*
6011 * C A C H E R O U T I N E S
6012 *
6013 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6014
dns_cache_acquire(struct dns_cache * cache)6015 static dns_refcount_t dns_cache_acquire(struct dns_cache *cache) {
6016 return dns_atomic_fetch_add(&cache->_.refcount);
6017 } /* dns_cache_acquire() */
6018
6019
dns_cache_release(struct dns_cache * cache)6020 static dns_refcount_t dns_cache_release(struct dns_cache *cache) {
6021 return dns_atomic_fetch_sub(&cache->_.refcount);
6022 } /* dns_cache_release() */
6023
6024
dns_cache_query(struct dns_packet * query,struct dns_cache * cache,int * error)6025 static struct dns_packet *dns_cache_query(struct dns_packet *query, struct dns_cache *cache, int *error) {
6026 (void)query;
6027 (void)cache;
6028 (void)error;
6029
6030 return NULL;
6031 } /* dns_cache_query() */
6032
6033
dns_cache_submit(struct dns_packet * query,struct dns_cache * cache)6034 static int dns_cache_submit(struct dns_packet *query, struct dns_cache *cache) {
6035 (void)query;
6036 (void)cache;
6037
6038 return 0;
6039 } /* dns_cache_submit() */
6040
6041
dns_cache_check(struct dns_cache * cache)6042 static int dns_cache_check(struct dns_cache *cache) {
6043 (void)cache;
6044
6045 return 0;
6046 } /* dns_cache_check() */
6047
6048
dns_cache_fetch(struct dns_cache * cache,int * error)6049 static struct dns_packet *dns_cache_fetch(struct dns_cache *cache, int *error) {
6050 (void)cache;
6051 (void)error;
6052
6053 return NULL;
6054 } /* dns_cache_fetch() */
6055
6056
dns_cache_pollfd(struct dns_cache * cache)6057 static int dns_cache_pollfd(struct dns_cache *cache) {
6058 (void)cache;
6059
6060 return -1;
6061 } /* dns_cache_pollfd() */
6062
6063
dns_cache_events(struct dns_cache * cache)6064 static short dns_cache_events(struct dns_cache *cache) {
6065 (void)cache;
6066
6067 return 0;
6068 } /* dns_cache_events() */
6069
6070
dns_cache_clear(struct dns_cache * cache)6071 static void dns_cache_clear(struct dns_cache *cache) {
6072 (void)cache;
6073
6074 return;
6075 } /* dns_cache_clear() */
6076
6077
dns_cache_init(struct dns_cache * cache)6078 struct dns_cache *dns_cache_init(struct dns_cache *cache) {
6079 static const struct dns_cache c_init = {
6080 .acquire = &dns_cache_acquire,
6081 .release = &dns_cache_release,
6082 .query = &dns_cache_query,
6083 .submit = &dns_cache_submit,
6084 .check = &dns_cache_check,
6085 .fetch = &dns_cache_fetch,
6086 .pollfd = &dns_cache_pollfd,
6087 .events = &dns_cache_events,
6088 .clear = &dns_cache_clear,
6089 ._ = { .refcount = 1, },
6090 };
6091
6092 *cache = c_init;
6093
6094 return cache;
6095 } /* dns_cache_init() */
6096
6097
dns_cache_close(struct dns_cache * cache)6098 void dns_cache_close(struct dns_cache *cache) {
6099 if (cache)
6100 cache->release(cache);
6101 } /* dns_cache_close() */
6102
6103
6104 /*
6105 * S O C K E T R O U T I N E S
6106 *
6107 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6108
dns_socketclose(int * fd,const struct dns_options * opts)6109 static void dns_socketclose(int *fd, const struct dns_options *opts) {
6110 if (opts && opts->closefd.cb)
6111 opts->closefd.cb(fd, opts->closefd.arg);
6112
6113 if (*fd != -1) {
6114 #if _WIN32
6115 closesocket(*fd);
6116 #else
6117 close(*fd);
6118 #endif
6119 *fd = -1;
6120 }
6121 } /* dns_socketclose() */
6122
6123
6124 #ifndef HAVE_IOCTLSOCKET
6125 #define HAVE_IOCTLSOCKET (_WIN32 || _WIN64)
6126 #endif
6127
6128 #ifndef HAVE_SOCK_CLOEXEC
6129 #ifdef SOCK_CLOEXEC
6130 #define HAVE_SOCK_CLOEXEC 1
6131 #else
6132 #define HAVE_SOCK_CLOEXEC 0
6133 #endif
6134 #endif
6135
6136 #ifndef HAVE_SOCK_NONBLOCK
6137 #ifdef SOCK_NONBLOCK
6138 #define HAVE_SOCK_NONBLOCK 1
6139 #else
6140 #define HAVE_SOCK_NONBLOCK 0
6141 #endif
6142 #endif
6143
6144 #define DNS_SO_MAXTRY 7
6145
dns_socket(struct sockaddr * local,int type,int * error_)6146 static int dns_socket(struct sockaddr *local, int type, int *error_) {
6147 int fd = -1, flags, error;
6148 #if defined FIONBIO
6149 unsigned long opt;
6150 #endif
6151
6152 flags = 0;
6153 #if HAVE_SOCK_CLOEXEC
6154 flags |= SOCK_CLOEXEC;
6155 #endif
6156 #if HAVE_SOCK_NONBLOCK
6157 flags |= SOCK_NONBLOCK;
6158 #endif
6159 if (-1 == (fd = socket(local->sa_family, type|flags, 0)))
6160 goto soerr;
6161
6162 #if defined F_SETFD && !HAVE_SOCK_CLOEXEC
6163 if (-1 == fcntl(fd, F_SETFD, 1))
6164 goto syerr;
6165 #endif
6166
6167 #if defined O_NONBLOCK && !HAVE_SOCK_NONBLOCK
6168 if (-1 == (flags = fcntl(fd, F_GETFL)))
6169 goto syerr;
6170 if (-1 == fcntl(fd, F_SETFL, flags | O_NONBLOCK))
6171 goto syerr;
6172 #elif defined FIONBIO && HAVE_IOCTLSOCKET
6173 opt = 1;
6174 if (0 != ioctlsocket(fd, FIONBIO, &opt))
6175 goto soerr;
6176 #endif
6177
6178 #if defined SO_NOSIGPIPE
6179 if (type != SOCK_DGRAM) {
6180 if (0 != setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &(int){ 1 }, sizeof (int)))
6181 goto soerr;
6182 }
6183 #endif
6184
6185 if (local->sa_family != AF_INET && local->sa_family != AF_INET6)
6186 return fd;
6187
6188 if (type != SOCK_DGRAM)
6189 return fd;
6190
6191 /*
6192 * FreeBSD, Linux, OpenBSD, OS X, and Solaris use random ports by
6193 * default. Though the ephemeral range is quite small on OS X
6194 * (49152-65535 on 10.10) and Linux (32768-60999 on 4.4.0, Ubuntu
6195 * Xenial). See also RFC 6056.
6196 *
6197 * TODO: Optionally rely on the kernel to select a random port.
6198 */
6199 if (*dns_sa_port(local->sa_family, local) == 0) {
6200 struct sockaddr_storage tmp;
6201 unsigned i, port;
6202
6203 memcpy(&tmp, local, dns_sa_len(local));
6204
6205 for (i = 0; i < DNS_SO_MAXTRY; i++) {
6206 port = 1025 + (dns_random() % 64510);
6207
6208 *dns_sa_port(tmp.ss_family, &tmp) = htons(port);
6209
6210 if (0 == bind(fd, (struct sockaddr *)&tmp, dns_sa_len(&tmp)))
6211 return fd;
6212 }
6213
6214 /* NB: continue to next bind statement */
6215 }
6216
6217 if (0 == bind(fd, local, dns_sa_len(local)))
6218 return fd;
6219
6220 /* FALL THROUGH */
6221 soerr:
6222 error = dns_soerr();
6223
6224 goto error;
6225 #if (defined F_SETFD && !HAVE_SOCK_CLOEXEC) || (defined O_NONBLOCK && !HAVE_SOCK_NONBLOCK)
6226 syerr:
6227 error = dns_syerr();
6228
6229 goto error;
6230 #endif
6231 error:
6232 *error_ = error;
6233
6234 dns_socketclose(&fd, NULL);
6235
6236 return -1;
6237 } /* dns_socket() */
6238
6239
6240 enum {
6241 DNS_SO_UDP_INIT = 1,
6242 DNS_SO_UDP_CONN,
6243 DNS_SO_UDP_SEND,
6244 DNS_SO_UDP_RECV,
6245 DNS_SO_UDP_DONE,
6246
6247 DNS_SO_TCP_INIT,
6248 DNS_SO_TCP_CONN,
6249 DNS_SO_TCP_SEND,
6250 DNS_SO_TCP_RECV,
6251 DNS_SO_TCP_DONE,
6252 };
6253
6254 struct dns_socket {
6255 struct dns_options opts;
6256
6257 int udp;
6258 int tcp;
6259
6260 int *old;
6261 unsigned onum, olim;
6262
6263 int type;
6264
6265 struct sockaddr_storage local, remote;
6266
6267 struct dns_k_permutor qids;
6268
6269 struct dns_stat stat;
6270
6271 /*
6272 * NOTE: dns_so_reset() zeroes everything from here down.
6273 */
6274 int state;
6275
6276 unsigned short qid;
6277 char qname[DNS_D_MAXNAME + 1];
6278 size_t qlen;
6279 enum dns_type qtype;
6280 enum dns_class qclass;
6281
6282 struct dns_packet *query;
6283 size_t qout;
6284
6285 struct dns_clock elapsed;
6286
6287 struct dns_packet *answer;
6288 size_t alen, apos;
6289 }; /* struct dns_socket */
6290
6291
6292 /*
6293 * NOTE: Actual closure delayed so that kqueue(2) and epoll(2) callers have
6294 * a chance to recognize a state change after installing a persistent event
6295 * and where sequential descriptors with the same integer value returned
6296 * from _pollfd() would be ambiguous. See dns_so_closefds().
6297 */
dns_so_closefd(struct dns_socket * so,int * fd)6298 static int dns_so_closefd(struct dns_socket *so, int *fd) {
6299 int error;
6300
6301 if (*fd == -1)
6302 return 0;
6303
6304 if (so->opts.closefd.cb) {
6305 if ((error = so->opts.closefd.cb(fd, so->opts.closefd.arg))) {
6306 return error;
6307 } else if (*fd == -1)
6308 return 0;
6309 }
6310
6311 if (!(so->onum < so->olim)) {
6312 unsigned olim = DNS_PP_MAX(4, so->olim * 2);
6313 void *old;
6314
6315 if (!(old = realloc(so->old, sizeof so->old[0] * olim)))
6316 return dns_syerr();
6317
6318 so->old = old;
6319 so->olim = olim;
6320 }
6321
6322 so->old[so->onum++] = *fd;
6323 *fd = -1;
6324
6325 return 0;
6326 } /* dns_so_closefd() */
6327
6328
6329 #define DNS_SO_CLOSE_UDP 0x01
6330 #define DNS_SO_CLOSE_TCP 0x02
6331 #define DNS_SO_CLOSE_OLD 0x04
6332 #define DNS_SO_CLOSE_ALL (DNS_SO_CLOSE_UDP|DNS_SO_CLOSE_TCP|DNS_SO_CLOSE_OLD)
6333
dns_so_closefds(struct dns_socket * so,int which)6334 static void dns_so_closefds(struct dns_socket *so, int which) {
6335 if (DNS_SO_CLOSE_UDP & which)
6336 dns_socketclose(&so->udp, &so->opts);
6337 if (DNS_SO_CLOSE_TCP & which)
6338 dns_socketclose(&so->tcp, &so->opts);
6339 if (DNS_SO_CLOSE_OLD & which) {
6340 unsigned i;
6341 for (i = 0; i < so->onum; i++)
6342 dns_socketclose(&so->old[i], &so->opts);
6343 so->onum = 0;
6344 free(so->old);
6345 so->old = 0;
6346 so->olim = 0;
6347 }
6348 } /* dns_so_closefds() */
6349
6350
6351 static void dns_so_destroy(struct dns_socket *);
6352
dns_so_init(struct dns_socket * so,const struct sockaddr * local,int type,const struct dns_options * opts,int * error)6353 static struct dns_socket *dns_so_init(struct dns_socket *so, const struct sockaddr *local, int type, const struct dns_options *opts, int *error) {
6354 static const struct dns_socket so_initializer = { .opts = DNS_OPTS_INITIALIZER, .udp = -1, .tcp = -1, };
6355
6356 *so = so_initializer;
6357 so->type = type;
6358
6359 if (opts)
6360 so->opts = *opts;
6361
6362 if (local)
6363 memcpy(&so->local, local, dns_sa_len(local));
6364
6365 if (-1 == (so->udp = dns_socket((struct sockaddr *)&so->local, SOCK_DGRAM, error)))
6366 goto error;
6367
6368 dns_k_permutor_init(&so->qids, 1, 65535);
6369
6370 return so;
6371 error:
6372 dns_so_destroy(so);
6373
6374 return 0;
6375 } /* dns_so_init() */
6376
6377
dns_so_open(const struct sockaddr * local,int type,const struct dns_options * opts,int * error)6378 struct dns_socket *dns_so_open(const struct sockaddr *local, int type, const struct dns_options *opts, int *error) {
6379 struct dns_socket *so;
6380
6381 if (!(so = malloc(sizeof *so)))
6382 goto syerr;
6383
6384 if (!dns_so_init(so, local, type, opts, error))
6385 goto error;
6386
6387 return so;
6388 syerr:
6389 *error = dns_syerr();
6390 error:
6391 dns_so_close(so);
6392
6393 return 0;
6394 } /* dns_so_open() */
6395
6396
dns_so_destroy(struct dns_socket * so)6397 static void dns_so_destroy(struct dns_socket *so) {
6398 dns_so_reset(so);
6399 dns_so_closefds(so, DNS_SO_CLOSE_ALL);
6400 } /* dns_so_destroy() */
6401
6402
dns_so_close(struct dns_socket * so)6403 void dns_so_close(struct dns_socket *so) {
6404 if (!so)
6405 return;
6406
6407 dns_so_destroy(so);
6408
6409 free(so);
6410 } /* dns_so_close() */
6411
6412
dns_so_reset(struct dns_socket * so)6413 void dns_so_reset(struct dns_socket *so) {
6414 dns_p_setptr(&so->answer, NULL);
6415
6416 memset(&so->state, '\0', sizeof *so - offsetof(struct dns_socket, state));
6417 } /* dns_so_reset() */
6418
6419
dns_so_mkqid(struct dns_socket * so)6420 unsigned short dns_so_mkqid(struct dns_socket *so) {
6421 return dns_k_permutor_step(&so->qids);
6422 } /* dns_so_mkqid() */
6423
6424
6425 #define DNS_SO_MINBUF 768
6426
dns_so_newanswer(struct dns_socket * so,size_t len)6427 static int dns_so_newanswer(struct dns_socket *so, size_t len) {
6428 size_t size = offsetof(struct dns_packet, data) + DNS_PP_MAX(len, DNS_SO_MINBUF);
6429 void *p;
6430
6431 if (!(p = realloc(so->answer, size)))
6432 return dns_syerr();
6433
6434 so->answer = dns_p_init(p, size);
6435
6436 return 0;
6437 } /* dns_so_newanswer() */
6438
6439
dns_so_submit(struct dns_socket * so,struct dns_packet * Q,struct sockaddr * host)6440 int dns_so_submit(struct dns_socket *so, struct dns_packet *Q, struct sockaddr *host) {
6441 struct dns_rr rr;
6442 int error = DNS_EUNKNOWN;
6443
6444 dns_so_reset(so);
6445
6446 if ((error = dns_rr_parse(&rr, 12, Q)))
6447 goto error;
6448
6449 if (!(so->qlen = dns_d_expand(so->qname, sizeof so->qname, rr.dn.p, Q, &error)))
6450 goto error;
6451 /*
6452 * NOTE: Don't bail if expansion is too long; caller may be
6453 * intentionally sending long names. However, we won't be able to
6454 * verify it on return.
6455 */
6456
6457 so->qtype = rr.type;
6458 so->qclass = rr.class;
6459
6460 if ((error = dns_so_newanswer(so, (Q->memo.opt.maxudp)? Q->memo.opt.maxudp : DNS_SO_MINBUF)))
6461 goto syerr;
6462
6463 memcpy(&so->remote, host, dns_sa_len(host));
6464
6465 so->query = Q;
6466 so->qout = 0;
6467
6468 dns_begin(&so->elapsed);
6469
6470 if (dns_header(so->query)->qid == 0)
6471 dns_header(so->query)->qid = dns_so_mkqid(so);
6472
6473 so->qid = dns_header(so->query)->qid;
6474 so->state = (so->type == SOCK_STREAM)? DNS_SO_TCP_INIT : DNS_SO_UDP_INIT;
6475
6476 so->stat.queries++;
6477
6478 return 0;
6479 syerr:
6480 error = dns_syerr();
6481 error:
6482 dns_so_reset(so);
6483
6484 return error;
6485 } /* dns_so_submit() */
6486
6487
dns_so_verify(struct dns_socket * so,struct dns_packet * P)6488 static int dns_so_verify(struct dns_socket *so, struct dns_packet *P) {
6489 char qname[DNS_D_MAXNAME + 1];
6490 size_t qlen;
6491 struct dns_rr rr;
6492 int error = -1;
6493
6494 if (so->qid != dns_header(so->answer)->qid)
6495 goto reject;
6496
6497 if (!dns_p_count(so->answer, DNS_S_QD))
6498 goto reject;
6499
6500 if (0 != dns_rr_parse(&rr, 12, so->answer))
6501 goto reject;
6502
6503 if (rr.type != so->qtype || rr.class != so->qclass)
6504 goto reject;
6505
6506 if (!(qlen = dns_d_expand(qname, sizeof qname, rr.dn.p, P, &error)))
6507 goto error;
6508 else if (qlen >= sizeof qname || qlen != so->qlen)
6509 goto reject;
6510
6511 if (0 != strcasecmp(so->qname, qname))
6512 goto reject;
6513
6514 return 0;
6515 reject:
6516 error = DNS_EUNKNOWN;
6517 error:
6518 DNS_SHOW(P, "rejecting packet (%s)", dns_strerror(error));
6519
6520 return error;
6521 } /* dns_so_verify() */
6522
6523
dns_so_tcp_keep(struct dns_socket * so)6524 static _Bool dns_so_tcp_keep(struct dns_socket *so) {
6525 struct sockaddr_storage remote;
6526
6527 if (so->tcp == -1)
6528 return 0;
6529
6530 if (0 != getpeername(so->tcp, (struct sockaddr *)&remote, &(socklen_t){ sizeof remote }))
6531 return 0;
6532
6533 return 0 == dns_sa_cmp(&remote, &so->remote);
6534 } /* dns_so_tcp_keep() */
6535
6536
6537 #if defined __clang__
6538 #pragma clang diagnostic push
6539 #pragma clang diagnostic ignored "-Warray-bounds"
6540 #endif
6541
dns_so_tcp_send(struct dns_socket * so)6542 static int dns_so_tcp_send(struct dns_socket *so) {
6543 unsigned char *qsrc;
6544 size_t qend;
6545 long n;
6546
6547 so->query->data[-2] = 0xff & (so->query->end >> 8);
6548 so->query->data[-1] = 0xff & (so->query->end >> 0);
6549
6550 qsrc = &so->query->data[-2] + so->qout;
6551 qend = so->query->end + 2;
6552
6553 while (so->qout < qend) {
6554 if (0 > (n = dns_send(so->tcp, (void *)&qsrc[so->qout], qend - so->qout, 0)))
6555 return dns_soerr();
6556
6557 so->qout += n;
6558 so->stat.tcp.sent.bytes += n;
6559 }
6560
6561 so->stat.tcp.sent.count++;
6562
6563 return 0;
6564 } /* dns_so_tcp_send() */
6565
6566
dns_so_tcp_recv(struct dns_socket * so)6567 static int dns_so_tcp_recv(struct dns_socket *so) {
6568 unsigned char *asrc;
6569 size_t aend, alen;
6570 int error;
6571 long n;
6572
6573 aend = so->alen + 2;
6574
6575 while (so->apos < aend) {
6576 asrc = &so->answer->data[-2];
6577
6578 if (0 > (n = recv(so->tcp, (void *)&asrc[so->apos], aend - so->apos, 0)))
6579 return dns_soerr();
6580 else if (n == 0)
6581 return DNS_EUNKNOWN; /* FIXME */
6582
6583 so->apos += n;
6584 so->stat.tcp.rcvd.bytes += n;
6585
6586 if (so->alen == 0 && so->apos >= 2) {
6587 alen = ((0xff & so->answer->data[-2]) << 8)
6588 | ((0xff & so->answer->data[-1]) << 0);
6589
6590 if ((error = dns_so_newanswer(so, alen)))
6591 return error;
6592
6593 so->alen = alen;
6594 aend = alen + 2;
6595 }
6596 }
6597
6598 so->answer->end = so->alen;
6599 so->stat.tcp.rcvd.count++;
6600
6601 return 0;
6602 } /* dns_so_tcp_recv() */
6603
6604 #if __clang__
6605 #pragma clang diagnostic pop
6606 #endif
6607
6608
dns_so_check(struct dns_socket * so)6609 int dns_so_check(struct dns_socket *so) {
6610 int error;
6611 long n;
6612
6613 retry:
6614 switch (so->state) {
6615 case DNS_SO_UDP_INIT:
6616 so->state++;
6617 /* FALL THROUGH */
6618 case DNS_SO_UDP_CONN:
6619 if (0 != connect(so->udp, (struct sockaddr *)&so->remote, dns_sa_len(&so->remote)))
6620 goto soerr;
6621
6622 so->state++;
6623 /* FALL THROUGH */
6624 case DNS_SO_UDP_SEND:
6625 if (0 > (n = send(so->udp, (void *)so->query->data, so->query->end, 0)))
6626 goto soerr;
6627
6628 so->stat.udp.sent.bytes += n;
6629 so->stat.udp.sent.count++;
6630
6631 so->state++;
6632 /* FALL THROUGH */
6633 case DNS_SO_UDP_RECV:
6634 if (0 > (n = recv(so->udp, (void *)so->answer->data, so->answer->size, 0)))
6635 goto soerr;
6636
6637 so->stat.udp.rcvd.bytes += n;
6638 so->stat.udp.rcvd.count++;
6639
6640 if ((so->answer->end = n) < 12)
6641 goto trash;
6642
6643 if ((error = dns_so_verify(so, so->answer)))
6644 goto trash;
6645
6646 so->state++;
6647 /* FALL THROUGH */
6648 case DNS_SO_UDP_DONE:
6649 if (!dns_header(so->answer)->tc || so->type == SOCK_DGRAM)
6650 return 0;
6651
6652 so->state++;
6653 /* FALL THROUGH */
6654 case DNS_SO_TCP_INIT:
6655 if (dns_so_tcp_keep(so)) {
6656 so->state = DNS_SO_TCP_SEND;
6657
6658 goto retry;
6659 }
6660
6661 if ((error = dns_so_closefd(so, &so->tcp)))
6662 goto error;
6663
6664 if (-1 == (so->tcp = dns_socket((struct sockaddr *)&so->local, SOCK_STREAM, &error)))
6665 goto error;
6666
6667 so->state++;
6668 /* FALL THROUGH */
6669 case DNS_SO_TCP_CONN:
6670 if (0 != connect(so->tcp, (struct sockaddr *)&so->remote, dns_sa_len(&so->remote))) {
6671 if (dns_soerr() != DNS_EISCONN)
6672 goto soerr;
6673 }
6674
6675 so->state++;
6676 /* FALL THROUGH */
6677 case DNS_SO_TCP_SEND:
6678 if ((error = dns_so_tcp_send(so)))
6679 goto error;
6680
6681 so->state++;
6682 /* FALL THROUGH */
6683 case DNS_SO_TCP_RECV:
6684 if ((error = dns_so_tcp_recv(so)))
6685 goto error;
6686
6687 so->state++;
6688 /* FALL THROUGH */
6689 case DNS_SO_TCP_DONE:
6690 /* close unless DNS_RESCONF_TCP_ONLY (see dns_res_tcp2type) */
6691 if (so->type != SOCK_STREAM) {
6692 if ((error = dns_so_closefd(so, &so->tcp)))
6693 goto error;
6694 }
6695
6696 if (so->answer->end < 12)
6697 return DNS_EILLEGAL;
6698
6699 if ((error = dns_so_verify(so, so->answer)))
6700 goto error;
6701
6702 return 0;
6703 default:
6704 error = DNS_EUNKNOWN;
6705
6706 goto error;
6707 } /* switch() */
6708
6709 trash:
6710 DNS_CARP("discarding packet");
6711 goto retry;
6712 soerr:
6713 error = dns_soerr();
6714
6715 goto error;
6716 error:
6717 switch (error) {
6718 case DNS_EINTR:
6719 goto retry;
6720 case DNS_EINPROGRESS:
6721 /* FALL THROUGH */
6722 case DNS_EALREADY:
6723 /* FALL THROUGH */
6724 #if DNS_EWOULDBLOCK != DNS_EAGAIN
6725 case DNS_EWOULDBLOCK:
6726 /* FALL THROUGH */
6727 #endif
6728 error = DNS_EAGAIN;
6729
6730 break;
6731 } /* switch() */
6732
6733 return error;
6734 } /* dns_so_check() */
6735
6736
dns_so_fetch(struct dns_socket * so,int * error)6737 struct dns_packet *dns_so_fetch(struct dns_socket *so, int *error) {
6738 struct dns_packet *answer;
6739
6740 switch (so->state) {
6741 case DNS_SO_UDP_DONE:
6742 case DNS_SO_TCP_DONE:
6743 answer = so->answer;
6744 so->answer = 0;
6745
6746 return answer;
6747 default:
6748 *error = DNS_EUNKNOWN;
6749
6750 return 0;
6751 }
6752 } /* dns_so_fetch() */
6753
6754
dns_so_query(struct dns_socket * so,struct dns_packet * Q,struct sockaddr * host,int * error_)6755 struct dns_packet *dns_so_query(struct dns_socket *so, struct dns_packet *Q, struct sockaddr *host, int *error_) {
6756 struct dns_packet *A;
6757 int error;
6758
6759 if (!so->state) {
6760 if ((error = dns_so_submit(so, Q, host)))
6761 goto error;
6762 }
6763
6764 if ((error = dns_so_check(so)))
6765 goto error;
6766
6767 if (!(A = dns_so_fetch(so, &error)))
6768 goto error;
6769
6770 dns_so_reset(so);
6771
6772 return A;
6773 error:
6774 *error_ = error;
6775
6776 return 0;
6777 } /* dns_so_query() */
6778
6779
dns_so_elapsed(struct dns_socket * so)6780 time_t dns_so_elapsed(struct dns_socket *so) {
6781 return dns_elapsed(&so->elapsed);
6782 } /* dns_so_elapsed() */
6783
6784
dns_so_clear(struct dns_socket * so)6785 void dns_so_clear(struct dns_socket *so) {
6786 dns_so_closefds(so, DNS_SO_CLOSE_OLD);
6787 } /* dns_so_clear() */
6788
6789
dns_so_events2(struct dns_socket * so,enum dns_events type)6790 static int dns_so_events2(struct dns_socket *so, enum dns_events type) {
6791 int events = 0;
6792
6793 switch (so->state) {
6794 case DNS_SO_UDP_CONN:
6795 case DNS_SO_UDP_SEND:
6796 events |= DNS_POLLOUT;
6797
6798 break;
6799 case DNS_SO_UDP_RECV:
6800 events |= DNS_POLLIN;
6801
6802 break;
6803 case DNS_SO_TCP_CONN:
6804 case DNS_SO_TCP_SEND:
6805 events |= DNS_POLLOUT;
6806
6807 break;
6808 case DNS_SO_TCP_RECV:
6809 events |= DNS_POLLIN;
6810
6811 break;
6812 } /* switch() */
6813
6814 switch (type) {
6815 case DNS_LIBEVENT:
6816 return DNS_POLL2EV(events);
6817 default:
6818 return events;
6819 } /* switch() */
6820 } /* dns_so_events2() */
6821
6822
dns_so_events(struct dns_socket * so)6823 int dns_so_events(struct dns_socket *so) {
6824 return dns_so_events2(so, so->opts.events);
6825 } /* dns_so_events() */
6826
6827
dns_so_pollfd(struct dns_socket * so)6828 int dns_so_pollfd(struct dns_socket *so) {
6829 switch (so->state) {
6830 case DNS_SO_UDP_CONN:
6831 case DNS_SO_UDP_SEND:
6832 case DNS_SO_UDP_RECV:
6833 return so->udp;
6834 case DNS_SO_TCP_CONN:
6835 case DNS_SO_TCP_SEND:
6836 case DNS_SO_TCP_RECV:
6837 return so->tcp;
6838 } /* switch() */
6839
6840 return -1;
6841 } /* dns_so_pollfd() */
6842
6843
dns_so_poll(struct dns_socket * so,int timeout)6844 int dns_so_poll(struct dns_socket *so, int timeout) {
6845 return dns_poll(dns_so_pollfd(so), dns_so_events2(so, DNS_SYSPOLL), timeout);
6846 } /* dns_so_poll() */
6847
6848
dns_so_stat(struct dns_socket * so)6849 const struct dns_stat *dns_so_stat(struct dns_socket *so) {
6850 return &so->stat;
6851 } /* dns_so_stat() */
6852
6853
6854 /*
6855 * R E S O L V E R R O U T I N E S
6856 *
6857 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6858
6859 enum dns_res_state {
6860 DNS_R_INIT,
6861 DNS_R_GLUE,
6862 DNS_R_SWITCH, /* (B)IND, (F)ILE, (C)ACHE */
6863
6864 DNS_R_FILE, /* Lookup in local hosts database */
6865
6866 DNS_R_CACHE, /* Lookup in application cache */
6867 DNS_R_SUBMIT,
6868 DNS_R_CHECK,
6869 DNS_R_FETCH,
6870
6871 DNS_R_BIND, /* Lookup in the network */
6872 DNS_R_SEARCH,
6873 DNS_R_HINTS,
6874 DNS_R_ITERATE,
6875 DNS_R_FOREACH_NS,
6876 DNS_R_RESOLV0_NS, /* Prologue: Setup next frame and recurse */
6877 DNS_R_RESOLV1_NS, /* Epilog: Inspect answer */
6878 DNS_R_FOREACH_A,
6879 DNS_R_QUERY_A,
6880 DNS_R_CNAME0_A,
6881 DNS_R_CNAME1_A,
6882
6883 DNS_R_FINISH,
6884 DNS_R_SMART0_A,
6885 DNS_R_SMART1_A,
6886 DNS_R_DONE,
6887 DNS_R_SERVFAIL,
6888 }; /* enum dns_res_state */
6889
6890
6891 #define DNS_R_MAXDEPTH 8
6892 #define DNS_R_ENDFRAME (DNS_R_MAXDEPTH - 1)
6893
6894 struct dns_resolver {
6895 struct dns_socket so;
6896
6897 struct dns_resolv_conf *resconf;
6898 struct dns_hosts *hosts;
6899 struct dns_hints *hints;
6900 struct dns_cache *cache;
6901
6902 dns_atomic_t refcount;
6903
6904 /* Reset zeroes everything below here. */
6905
6906 char qname[DNS_D_MAXNAME + 1];
6907 size_t qlen;
6908
6909 enum dns_type qtype;
6910 enum dns_class qclass;
6911
6912 struct dns_clock elapsed;
6913
6914 dns_resconf_i_t search;
6915
6916 struct dns_rr_i smart;
6917
6918 struct dns_packet *nodata; /* answer if nothing better */
6919
6920 unsigned sp;
6921
6922 struct dns_res_frame {
6923 enum dns_res_state state;
6924
6925 int error;
6926 int which; /* (B)IND, (F)ILE; index into resconf->lookup */
6927 int qflags;
6928
6929 unsigned attempts;
6930
6931 struct dns_packet *query, *answer, *hints;
6932
6933 struct dns_rr_i hints_i, hints_j;
6934 struct dns_rr hints_ns, ans_cname;
6935 } stack[DNS_R_MAXDEPTH];
6936 }; /* struct dns_resolver */
6937
6938
dns_res_tcp2type(int tcp)6939 static int dns_res_tcp2type(int tcp) {
6940 switch (tcp) {
6941 case DNS_RESCONF_TCP_ONLY:
6942 return SOCK_STREAM;
6943 case DNS_RESCONF_TCP_DISABLE:
6944 return SOCK_DGRAM;
6945 default:
6946 return 0;
6947 }
6948 } /* dns_res_tcp2type() */
6949
dns_res_open(struct dns_resolv_conf * resconf,struct dns_hosts * hosts,struct dns_hints * hints,struct dns_cache * cache,const struct dns_options * opts,int * _error)6950 struct dns_resolver *dns_res_open(struct dns_resolv_conf *resconf, struct dns_hosts *hosts, struct dns_hints *hints, struct dns_cache *cache, const struct dns_options *opts, int *_error) {
6951 static const struct dns_resolver R_initializer
6952 = { .refcount = 1, };
6953 struct dns_resolver *R = 0;
6954 int type, error;
6955
6956 /*
6957 * Grab ref count early because the caller may have passed us a mortal
6958 * reference, and we want to do the right thing if we return early
6959 * from an error.
6960 */
6961 if (resconf)
6962 dns_resconf_acquire(resconf);
6963 if (hosts)
6964 dns_hosts_acquire(hosts);
6965 if (hints)
6966 dns_hints_acquire(hints);
6967 if (cache)
6968 dns_cache_acquire(cache);
6969
6970 /*
6971 * Don't try to load it ourselves because a NULL object might be an
6972 * error from, say, dns_resconf_root(), and loading
6973 * dns_resconf_local() by default would create undesirable surpises.
6974 */
6975 if (!resconf || !hosts || !hints) {
6976 if (!*_error)
6977 *_error = EINVAL;
6978 goto _error;
6979 }
6980
6981 if (!(R = malloc(sizeof *R)))
6982 goto syerr;
6983
6984 *R = R_initializer;
6985 type = dns_res_tcp2type(resconf->options.tcp);
6986
6987 if (!dns_so_init(&R->so, (struct sockaddr *)&resconf->iface, type, opts, &error))
6988 goto error;
6989
6990 R->resconf = resconf;
6991 R->hosts = hosts;
6992 R->hints = hints;
6993 R->cache = cache;
6994
6995 return R;
6996 syerr:
6997 error = dns_syerr();
6998 error:
6999 *_error = error;
7000 _error:
7001 dns_res_close(R);
7002
7003 dns_resconf_close(resconf);
7004 dns_hosts_close(hosts);
7005 dns_hints_close(hints);
7006 dns_cache_close(cache);
7007
7008 return 0;
7009 } /* dns_res_open() */
7010
7011
dns_res_stub(const struct dns_options * opts,int * error)7012 struct dns_resolver *dns_res_stub(const struct dns_options *opts, int *error) {
7013 struct dns_resolv_conf *resconf = 0;
7014 struct dns_hosts *hosts = 0;
7015 struct dns_hints *hints = 0;
7016 struct dns_resolver *res = 0;
7017
7018 if (!(resconf = dns_resconf_local(error)))
7019 goto epilog;
7020
7021 if (!(hosts = dns_hosts_local(error)))
7022 goto epilog;
7023
7024 if (!(hints = dns_hints_local(resconf, error)))
7025 goto epilog;
7026
7027 if (!(res = dns_res_open(resconf, hosts, hints, NULL, opts, error)))
7028 goto epilog;
7029
7030 epilog:
7031 dns_resconf_close(resconf);
7032 dns_hosts_close(hosts);
7033 dns_hints_close(hints);
7034
7035 return res;
7036 } /* dns_res_stub() */
7037
7038
dns_res_frame_destroy(struct dns_resolver * R,struct dns_res_frame * frame)7039 static void dns_res_frame_destroy(struct dns_resolver *R, struct dns_res_frame *frame) {
7040 (void)R;
7041
7042 dns_p_setptr(&frame->query, NULL);
7043 dns_p_setptr(&frame->answer, NULL);
7044 dns_p_setptr(&frame->hints, NULL);
7045 } /* dns_res_frame_destroy() */
7046
7047
dns_res_frame_init(struct dns_resolver * R,struct dns_res_frame * frame)7048 static void dns_res_frame_init(struct dns_resolver *R, struct dns_res_frame *frame) {
7049 memset(frame, '\0', sizeof *frame);
7050
7051 /*
7052 * NB: Can be invoked from dns_res_open, before R->resconf has been
7053 * initialized.
7054 */
7055 if (R->resconf) {
7056 if (!R->resconf->options.recurse)
7057 frame->qflags |= DNS_Q_RD;
7058 if (R->resconf->options.edns0)
7059 frame->qflags |= DNS_Q_EDNS0;
7060 }
7061 } /* dns_res_frame_init() */
7062
7063
dns_res_frame_reset(struct dns_resolver * R,struct dns_res_frame * frame)7064 static void dns_res_frame_reset(struct dns_resolver *R, struct dns_res_frame *frame) {
7065 dns_res_frame_destroy(R, frame);
7066 dns_res_frame_init(R, frame);
7067 } /* dns_res_frame_reset() */
7068
7069
dns_res_frame_prepare(struct dns_resolver * R,struct dns_res_frame * F,const char * qname,enum dns_type qtype,enum dns_class qclass)7070 static dns_error_t dns_res_frame_prepare(struct dns_resolver *R, struct dns_res_frame *F, const char *qname, enum dns_type qtype, enum dns_class qclass) {
7071 struct dns_packet *P = NULL;
7072
7073 if (!(F < endof(R->stack)))
7074 return DNS_EUNKNOWN;
7075
7076 dns_p_movptr(&P, &F->query);
7077 dns_res_frame_reset(R, F);
7078 dns_p_movptr(&F->query, &P);
7079
7080 return dns_q_make(&F->query, qname, qtype, qclass, F->qflags);
7081 } /* dns_res_frame_prepare() */
7082
7083
dns_res_reset(struct dns_resolver * R)7084 void dns_res_reset(struct dns_resolver *R) {
7085 unsigned i;
7086
7087 dns_so_reset(&R->so);
7088 dns_p_setptr(&R->nodata, NULL);
7089
7090 for (i = 0; i < lengthof(R->stack); i++)
7091 dns_res_frame_destroy(R, &R->stack[i]);
7092
7093 memset(&R->qname, '\0', sizeof *R - offsetof(struct dns_resolver, qname));
7094
7095 for (i = 0; i < lengthof(R->stack); i++)
7096 dns_res_frame_init(R, &R->stack[i]);
7097 } /* dns_res_reset() */
7098
7099
dns_res_close(struct dns_resolver * R)7100 void dns_res_close(struct dns_resolver *R) {
7101 if (!R || 1 < dns_res_release(R))
7102 return;
7103
7104 dns_res_reset(R);
7105
7106 dns_so_destroy(&R->so);
7107
7108 dns_hints_close(R->hints);
7109 dns_hosts_close(R->hosts);
7110 dns_resconf_close(R->resconf);
7111 dns_cache_close(R->cache);
7112
7113 free(R);
7114 } /* dns_res_close() */
7115
7116
dns_res_acquire(struct dns_resolver * R)7117 dns_refcount_t dns_res_acquire(struct dns_resolver *R) {
7118 return dns_atomic_fetch_add(&R->refcount);
7119 } /* dns_res_acquire() */
7120
7121
dns_res_release(struct dns_resolver * R)7122 dns_refcount_t dns_res_release(struct dns_resolver *R) {
7123 return dns_atomic_fetch_sub(&R->refcount);
7124 } /* dns_res_release() */
7125
7126
dns_res_mortal(struct dns_resolver * res)7127 struct dns_resolver *dns_res_mortal(struct dns_resolver *res) {
7128 if (res)
7129 dns_res_release(res);
7130 return res;
7131 } /* dns_res_mortal() */
7132
7133
dns_res_merge(struct dns_packet * P0,struct dns_packet * P1,int * error_)7134 static struct dns_packet *dns_res_merge(struct dns_packet *P0, struct dns_packet *P1, int *error_) {
7135 size_t bufsiz = P0->end + P1->end;
7136 struct dns_packet *P[3] = { P0, P1, 0 };
7137 struct dns_rr rr[3];
7138 int error, copy, i;
7139 enum dns_section section;
7140
7141 retry:
7142 if (!(P[2] = dns_p_make(bufsiz, &error)))
7143 goto error;
7144
7145 dns_rr_foreach(&rr[0], P[0], .section = DNS_S_QD) {
7146 if ((error = dns_rr_copy(P[2], &rr[0], P[0])))
7147 goto error;
7148 }
7149
7150 for (section = DNS_S_AN; (DNS_S_ALL & section); section <<= 1) {
7151 for (i = 0; i < 2; i++) {
7152 dns_rr_foreach(&rr[i], P[i], .section = section) {
7153 copy = 1;
7154
7155 dns_rr_foreach(&rr[2], P[2], .type = rr[i].type, .section = (DNS_S_ALL & ~DNS_S_QD)) {
7156 if (0 == dns_rr_cmp(&rr[i], P[i], &rr[2], P[2])) {
7157 copy = 0;
7158
7159 break;
7160 }
7161 }
7162
7163 if (copy && (error = dns_rr_copy(P[2], &rr[i], P[i]))) {
7164 if (error == DNS_ENOBUFS && bufsiz < 65535) {
7165 dns_p_setptr(&P[2], NULL);
7166
7167 bufsiz = DNS_PP_MAX(65535, bufsiz * 2);
7168
7169 goto retry;
7170 }
7171
7172 goto error;
7173 }
7174 } /* foreach(rr) */
7175 } /* foreach(packet) */
7176 } /* foreach(section) */
7177
7178 return P[2];
7179 error:
7180 *error_ = error;
7181
7182 dns_p_free(P[2]);
7183
7184 return 0;
7185 } /* dns_res_merge() */
7186
7187
dns_res_glue(struct dns_resolver * R,struct dns_packet * Q)7188 static struct dns_packet *dns_res_glue(struct dns_resolver *R, struct dns_packet *Q) {
7189 struct dns_packet *P = dns_p_new(512);
7190 char qname[DNS_D_MAXNAME + 1];
7191 size_t qlen;
7192 enum dns_type qtype;
7193 struct dns_rr rr;
7194 unsigned sp;
7195 int error;
7196
7197 if (!(qlen = dns_d_expand(qname, sizeof qname, 12, Q, &error))
7198 || qlen >= sizeof qname)
7199 return 0;
7200
7201 if (!(qtype = dns_rr_type(12, Q)))
7202 return 0;
7203
7204 if ((error = dns_p_push(P, DNS_S_QD, qname, strlen(qname), qtype, DNS_C_IN, 0, 0)))
7205 return 0;
7206
7207 for (sp = 0; sp <= R->sp; sp++) {
7208 if (!R->stack[sp].answer)
7209 continue;
7210
7211 dns_rr_foreach(&rr, R->stack[sp].answer, .name = qname, .type = qtype, .section = (DNS_S_ALL & ~DNS_S_QD)) {
7212 rr.section = DNS_S_AN;
7213
7214 if ((error = dns_rr_copy(P, &rr, R->stack[sp].answer)))
7215 return 0;
7216 }
7217 }
7218
7219 if (dns_p_count(P, DNS_S_AN) > 0)
7220 goto copy;
7221
7222 /* Otherwise, look for a CNAME */
7223 for (sp = 0; sp <= R->sp; sp++) {
7224 if (!R->stack[sp].answer)
7225 continue;
7226
7227 dns_rr_foreach(&rr, R->stack[sp].answer, .name = qname, .type = DNS_T_CNAME, .section = (DNS_S_ALL & ~DNS_S_QD)) {
7228 rr.section = DNS_S_AN;
7229
7230 if ((error = dns_rr_copy(P, &rr, R->stack[sp].answer)))
7231 return 0;
7232 }
7233 }
7234
7235 if (!dns_p_count(P, DNS_S_AN))
7236 return 0;
7237
7238 copy:
7239 return dns_p_copy(dns_p_make(P->end, &error), P);
7240 } /* dns_res_glue() */
7241
7242
7243 /*
7244 * Sort NS records by three criteria:
7245 *
7246 * 1) Whether glue is present.
7247 * 2) Whether glue record is original or of recursive lookup.
7248 * 3) Randomly shuffle records which share the above criteria.
7249 *
7250 * NOTE: Assumes only NS records passed, AND ASSUMES no new NS records will
7251 * be added during an iteration.
7252 *
7253 * FIXME: Only groks A glue, not AAAA glue.
7254 */
dns_res_nameserv_cmp(struct dns_rr * a,struct dns_rr * b,struct dns_rr_i * i,struct dns_packet * P)7255 static int dns_res_nameserv_cmp(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) {
7256 _Bool glued[2] = { 0 };
7257 struct dns_rr x = { 0 }, y = { 0 };
7258 struct dns_ns ns;
7259 int cmp, error;
7260
7261 if (!(error = dns_ns_parse(&ns, a, P)))
7262 glued[0] = !!dns_rr_grep(&x, 1, dns_rr_i_new(P, .section = (DNS_S_ALL & ~DNS_S_QD), .name = ns.host, .type = DNS_T_A), P, &error);
7263
7264 if (!(error = dns_ns_parse(&ns, b, P)))
7265 glued[1] = !!dns_rr_grep(&y, 1, dns_rr_i_new(P, .section = (DNS_S_ALL & ~DNS_S_QD), .name = ns.host, .type = DNS_T_A), P, &error);
7266
7267 if ((cmp = glued[1] - glued[0])) {
7268 return cmp;
7269 } else if ((cmp = (dns_rr_offset(&y) < i->args[0]) - (dns_rr_offset(&x) < i->args[0]))) {
7270 return cmp;
7271 } else {
7272 return dns_rr_i_shuffle(a, b, i, P);
7273 }
7274 } /* dns_res_nameserv_cmp() */
7275
7276
7277 #define dgoto(sp, i) \
7278 do { R->stack[(sp)].state = (i); goto exec; } while (0)
7279
dns_res_exec(struct dns_resolver * R)7280 static int dns_res_exec(struct dns_resolver *R) {
7281 struct dns_res_frame *F;
7282 struct dns_packet *P;
7283 union {
7284 char host[DNS_D_MAXNAME + 1];
7285 char name[DNS_D_MAXNAME + 1];
7286 struct dns_ns ns;
7287 struct dns_cname cname;
7288 } u;
7289 size_t len;
7290 struct dns_rr rr;
7291 int error;
7292
7293 exec:
7294
7295 F = &R->stack[R->sp];
7296
7297 switch (F->state) {
7298 case DNS_R_INIT:
7299 F->state++;
7300 /* FALL THROUGH */
7301 case DNS_R_GLUE:
7302 if (R->sp == 0)
7303 dgoto(R->sp, DNS_R_SWITCH);
7304
7305 if (!F->query)
7306 goto noquery;
7307
7308 if (!(F->answer = dns_res_glue(R, F->query)))
7309 dgoto(R->sp, DNS_R_SWITCH);
7310
7311 if (!(len = dns_d_expand(u.name, sizeof u.name, 12, F->query, &error)))
7312 goto error;
7313 else if (len >= sizeof u.name)
7314 goto toolong;
7315
7316 dns_rr_foreach(&rr, F->answer, .name = u.name, .type = dns_rr_type(12, F->query), .section = DNS_S_AN) {
7317 dgoto(R->sp, DNS_R_FINISH);
7318 }
7319
7320 dns_rr_foreach(&rr, F->answer, .name = u.name, .type = DNS_T_CNAME, .section = DNS_S_AN) {
7321 F->ans_cname = rr;
7322
7323 dgoto(R->sp, DNS_R_CNAME0_A);
7324 }
7325
7326 F->state++;
7327 /* FALL THROUGH */
7328 case DNS_R_SWITCH:
7329 while (F->which < (int)sizeof R->resconf->lookup && R->resconf->lookup[F->which]) {
7330 switch (R->resconf->lookup[F->which++]) {
7331 case 'b': case 'B':
7332 dgoto(R->sp, DNS_R_BIND);
7333 case 'f': case 'F':
7334 dgoto(R->sp, DNS_R_FILE);
7335 case 'c': case 'C':
7336 if (R->cache)
7337 dgoto(R->sp, DNS_R_CACHE);
7338
7339 break;
7340 default:
7341 break;
7342 }
7343 }
7344
7345 /*
7346 * FIXME: Examine more closely whether our logic is correct
7347 * and DNS_R_SERVFAIL is the correct default response.
7348 *
7349 * Case 1: We got here because we never got an answer on the
7350 * wire. All queries timed-out and we reached maximum
7351 * attempts count. See DNS_R_FOREACH_NS. In that case
7352 * DNS_R_SERVFAIL is the correct state, unless we want to
7353 * return DNS_ETIMEDOUT.
7354 *
7355 * Case 2: We were a stub resolver and got an unsatisfactory
7356 * answer (empty ANSWER section) which caused us to jump
7357 * back to DNS_R_SEARCH and ultimately to DNS_R_SWITCH. We
7358 * return the answer returned from the wire, which we
7359 * stashed in R->nodata.
7360 *
7361 * Case 3: We reached maximum attempts count as in case #1,
7362 * but never got an authoritative response which caused us
7363 * to short-circuit. See end of DNS_R_QUERY_A case. We
7364 * should probably prepare R->nodata as in case #2.
7365 */
7366 if (R->sp == 0 && R->nodata) { /* XXX: can we just return nodata regardless? */
7367 dns_p_movptr(&F->answer, &R->nodata);
7368 dgoto(R->sp, DNS_R_FINISH);
7369 }
7370
7371 dgoto(R->sp, DNS_R_SERVFAIL);
7372 case DNS_R_FILE:
7373 if (R->sp > 0) {
7374 if (!dns_p_setptr(&F->answer, dns_hosts_query(R->hosts, F->query, &error)))
7375 goto error;
7376
7377 if (dns_p_count(F->answer, DNS_S_AN) > 0)
7378 dgoto(R->sp, DNS_R_FINISH);
7379
7380 dns_p_setptr(&F->answer, NULL);
7381 } else {
7382 R->search = 0;
7383
7384 while ((len = dns_resconf_search(u.name, sizeof u.name, R->qname, R->qlen, R->resconf, &R->search))) {
7385 if ((error = dns_q_make2(&F->query, u.name, len, R->qtype, R->qclass, F->qflags)))
7386 goto error;
7387
7388 if (!dns_p_setptr(&F->answer, dns_hosts_query(R->hosts, F->query, &error)))
7389 goto error;
7390
7391 if (dns_p_count(F->answer, DNS_S_AN) > 0)
7392 dgoto(R->sp, DNS_R_FINISH);
7393
7394 dns_p_setptr(&F->answer, NULL);
7395 }
7396 }
7397
7398 dgoto(R->sp, DNS_R_SWITCH);
7399 case DNS_R_CACHE:
7400 error = 0;
7401
7402 if (!F->query && (error = dns_q_make(&F->query, R->qname, R->qtype, R->qclass, F->qflags)))
7403 goto error;
7404
7405 if (dns_p_setptr(&F->answer, R->cache->query(F->query, R->cache, &error))) {
7406 if (dns_p_count(F->answer, DNS_S_AN) > 0)
7407 dgoto(R->sp, DNS_R_FINISH);
7408
7409 dns_p_setptr(&F->answer, NULL);
7410
7411 dgoto(R->sp, DNS_R_SWITCH);
7412 } else if (error)
7413 goto error;
7414
7415 F->state++;
7416 /* FALL THROUGH */
7417 case DNS_R_SUBMIT:
7418 if ((error = R->cache->submit(F->query, R->cache)))
7419 goto error;
7420
7421 F->state++;
7422 /* FALL THROUGH */
7423 case DNS_R_CHECK:
7424 if ((error = R->cache->check(R->cache)))
7425 goto error;
7426
7427 F->state++;
7428 /* FALL THROUGH */
7429 case DNS_R_FETCH:
7430 error = 0;
7431
7432 if (dns_p_setptr(&F->answer, R->cache->fetch(R->cache, &error))) {
7433 if (dns_p_count(F->answer, DNS_S_AN) > 0)
7434 dgoto(R->sp, DNS_R_FINISH);
7435
7436 dns_p_setptr(&F->answer, NULL);
7437
7438 dgoto(R->sp, DNS_R_SWITCH);
7439 } else if (error)
7440 goto error;
7441
7442 dgoto(R->sp, DNS_R_SWITCH);
7443 case DNS_R_BIND:
7444 if (R->sp > 0) {
7445 if (!F->query)
7446 goto noquery;
7447
7448 dgoto(R->sp, DNS_R_HINTS);
7449 }
7450
7451 R->search = 0;
7452
7453 F->state++;
7454 /* FALL THROUGH */
7455 case DNS_R_SEARCH:
7456 /*
7457 * XXX: We probably should only apply the domain search
7458 * algorithm if R->sp == 0.
7459 */
7460 if (!(len = dns_resconf_search(u.name, sizeof u.name, R->qname, R->qlen, R->resconf, &R->search)))
7461 dgoto(R->sp, DNS_R_SWITCH);
7462
7463 if ((error = dns_q_make2(&F->query, u.name, len, R->qtype, R->qclass, F->qflags)))
7464 goto error;
7465
7466 F->state++;
7467 /* FALL THROUGH */
7468 case DNS_R_HINTS:
7469 if (!dns_p_setptr(&F->hints, dns_hints_query(R->hints, F->query, &error)))
7470 goto error;
7471
7472 F->state++;
7473 /* FALL THROUGH */
7474 case DNS_R_ITERATE:
7475 dns_rr_i_init(&F->hints_i, F->hints);
7476
7477 F->hints_i.section = DNS_S_AUTHORITY;
7478 F->hints_i.type = DNS_T_NS;
7479 F->hints_i.sort = &dns_res_nameserv_cmp;
7480 F->hints_i.args[0] = F->hints->end;
7481
7482 F->state++;
7483 /* FALL THROUGH */
7484 case DNS_R_FOREACH_NS:
7485 dns_rr_i_save(&F->hints_i);
7486
7487 /* Load our next nameserver host. */
7488 if (!dns_rr_grep(&F->hints_ns, 1, &F->hints_i, F->hints, &error)) {
7489 if (++F->attempts < R->resconf->options.attempts)
7490 dgoto(R->sp, DNS_R_ITERATE);
7491
7492 dgoto(R->sp, DNS_R_SWITCH);
7493 }
7494
7495 dns_rr_i_init(&F->hints_j, F->hints);
7496
7497 /* Assume there are glue records */
7498 dgoto(R->sp, DNS_R_FOREACH_A);
7499 case DNS_R_RESOLV0_NS:
7500 /* Have we reached our max depth? */
7501 if (&F[1] >= endof(R->stack))
7502 dgoto(R->sp, DNS_R_FOREACH_NS);
7503
7504 if ((error = dns_ns_parse(&u.ns, &F->hints_ns, F->hints)))
7505 goto error;
7506 if ((error = dns_res_frame_prepare(R, &F[1], u.ns.host, DNS_T_A, DNS_C_IN)))
7507 goto error;
7508
7509 F->state++;
7510
7511 dgoto(++R->sp, DNS_R_INIT);
7512 case DNS_R_RESOLV1_NS:
7513 if (!(len = dns_d_expand(u.host, sizeof u.host, 12, F[1].query, &error)))
7514 goto error;
7515 else if (len >= sizeof u.host)
7516 goto toolong;
7517
7518 dns_rr_foreach(&rr, F[1].answer, .name = u.host, .type = DNS_T_A, .section = (DNS_S_ALL & ~DNS_S_QD)) {
7519 rr.section = DNS_S_AR;
7520
7521 if ((error = dns_rr_copy(F->hints, &rr, F[1].answer)))
7522 goto error;
7523
7524 dns_rr_i_rewind(&F->hints_i); /* Now there's glue. */
7525 }
7526
7527 dgoto(R->sp, DNS_R_FOREACH_NS);
7528 case DNS_R_FOREACH_A: {
7529 struct dns_a a;
7530 struct sockaddr_in sin;
7531
7532 /*
7533 * NOTE: Iterator initialized in DNS_R_FOREACH_NS because
7534 * this state is re-entrant, but we need to reset
7535 * .name to a valid pointer each time.
7536 */
7537 if ((error = dns_ns_parse(&u.ns, &F->hints_ns, F->hints)))
7538 goto error;
7539
7540 F->hints_j.name = u.ns.host;
7541 F->hints_j.type = DNS_T_A;
7542 F->hints_j.section = DNS_S_ALL & ~DNS_S_QD;
7543
7544 if (!dns_rr_grep(&rr, 1, &F->hints_j, F->hints, &error)) {
7545 if (!dns_rr_i_count(&F->hints_j))
7546 dgoto(R->sp, DNS_R_RESOLV0_NS);
7547
7548 dgoto(R->sp, DNS_R_FOREACH_NS);
7549 }
7550
7551 if ((error = dns_a_parse(&a, &rr, F->hints)))
7552 goto error;
7553
7554 sin.sin_family = AF_INET;
7555 sin.sin_addr = a.addr;
7556 if (R->sp == 0)
7557 sin.sin_port = dns_hints_port(R->hints, AF_INET, &sin.sin_addr);
7558 else
7559 sin.sin_port = htons(53);
7560
7561 if (DNS_DEBUG) {
7562 char addr[INET_ADDRSTRLEN + 1];
7563 dns_a_print(addr, sizeof addr, &a);
7564 dns_header(F->query)->qid = dns_so_mkqid(&R->so);
7565 DNS_SHOW(F->query, "ASKING: %s/%s @ DEPTH: %u)", u.ns.host, addr, R->sp);
7566 }
7567
7568 if ((error = dns_so_submit(&R->so, F->query, (struct sockaddr *)&sin)))
7569 goto error;
7570
7571 F->state++;
7572 }
7573 /* FALL THROUGH */
7574 case DNS_R_QUERY_A:
7575 if (dns_so_elapsed(&R->so) >= dns_resconf_timeout(R->resconf))
7576 dgoto(R->sp, DNS_R_FOREACH_A);
7577
7578 if ((error = dns_so_check(&R->so)))
7579 goto error;
7580
7581 if (!dns_p_setptr(&F->answer, dns_so_fetch(&R->so, &error)))
7582 goto error;
7583
7584 if (DNS_DEBUG) {
7585 DNS_SHOW(F->answer, "ANSWER @ DEPTH: %u)", R->sp);
7586 }
7587
7588 if (dns_p_rcode(F->answer) == DNS_RC_FORMERR ||
7589 dns_p_rcode(F->answer) == DNS_RC_NOTIMP ||
7590 dns_p_rcode(F->answer) == DNS_RC_BADVERS) {
7591 /* Temporarily disable EDNS0 and try again. */
7592 if (F->qflags & DNS_Q_EDNS0) {
7593 F->qflags &= ~DNS_Q_EDNS0;
7594 if ((error = dns_q_remake(&F->query, F->qflags)))
7595 goto error;
7596
7597 dgoto(R->sp, DNS_R_FOREACH_A);
7598 }
7599 }
7600
7601 if ((error = dns_rr_parse(&rr, 12, F->query)))
7602 goto error;
7603
7604 if (!(len = dns_d_expand(u.name, sizeof u.name, rr.dn.p, F->query, &error)))
7605 goto error;
7606 else if (len >= sizeof u.name)
7607 goto toolong;
7608
7609 dns_rr_foreach(&rr, F->answer, .section = DNS_S_AN, .name = u.name, .type = rr.type) {
7610 dgoto(R->sp, DNS_R_FINISH); /* Found */
7611 }
7612
7613 dns_rr_foreach(&rr, F->answer, .section = DNS_S_AN, .name = u.name, .type = DNS_T_CNAME) {
7614 F->ans_cname = rr;
7615
7616 dgoto(R->sp, DNS_R_CNAME0_A);
7617 }
7618
7619 /*
7620 * XXX: The condition here should probably check whether
7621 * R->sp == 0, because DNS_R_SEARCH runs regardless of
7622 * options.recurse. See DNS_R_BIND.
7623 */
7624 if (!R->resconf->options.recurse) {
7625 /* Make first answer our tentative answer */
7626 if (!R->nodata)
7627 dns_p_movptr(&R->nodata, &F->answer);
7628
7629 dgoto(R->sp, DNS_R_SEARCH);
7630 }
7631
7632 dns_rr_foreach(&rr, F->answer, .section = DNS_S_NS, .type = DNS_T_NS) {
7633 dns_p_movptr(&F->hints, &F->answer);
7634
7635 dgoto(R->sp, DNS_R_ITERATE);
7636 }
7637
7638 /* XXX: Should this go further up? */
7639 if (dns_header(F->answer)->aa)
7640 dgoto(R->sp, DNS_R_FINISH);
7641
7642 /* XXX: Should we copy F->answer to R->nodata? */
7643
7644 dgoto(R->sp, DNS_R_FOREACH_A);
7645 case DNS_R_CNAME0_A:
7646 if (&F[1] >= endof(R->stack))
7647 dgoto(R->sp, DNS_R_FINISH);
7648
7649 if ((error = dns_cname_parse(&u.cname, &F->ans_cname, F->answer)))
7650 goto error;
7651 if ((error = dns_res_frame_prepare(R, &F[1], u.cname.host, dns_rr_type(12, F->query), DNS_C_IN)))
7652 goto error;
7653
7654 F->state++;
7655
7656 dgoto(++R->sp, DNS_R_INIT);
7657 case DNS_R_CNAME1_A:
7658 if (!(P = dns_res_merge(F->answer, F[1].answer, &error)))
7659 goto error;
7660
7661 dns_p_setptr(&F->answer, P);
7662
7663 dgoto(R->sp, DNS_R_FINISH);
7664 case DNS_R_FINISH:
7665 if (!F->answer)
7666 goto noanswer;
7667
7668 if (!R->resconf->options.smart || R->sp > 0)
7669 dgoto(R->sp, DNS_R_DONE);
7670
7671 R->smart.section = DNS_S_AN;
7672 R->smart.type = R->qtype;
7673
7674 dns_rr_i_init(&R->smart, F->answer);
7675
7676 F->state++;
7677 /* FALL THROUGH */
7678 case DNS_R_SMART0_A:
7679 if (&F[1] >= endof(R->stack))
7680 dgoto(R->sp, DNS_R_DONE);
7681
7682 while (dns_rr_grep(&rr, 1, &R->smart, F->answer, &error)) {
7683 union {
7684 struct dns_ns ns;
7685 struct dns_mx mx;
7686 struct dns_srv srv;
7687 } rd;
7688 const char *qname;
7689 enum dns_type qtype;
7690 enum dns_class qclass;
7691
7692 switch (rr.type) {
7693 case DNS_T_NS:
7694 if ((error = dns_ns_parse(&rd.ns, &rr, F->answer)))
7695 goto error;
7696
7697 qname = rd.ns.host;
7698 qtype = DNS_T_A;
7699 qclass = DNS_C_IN;
7700
7701 break;
7702 case DNS_T_MX:
7703 if ((error = dns_mx_parse(&rd.mx, &rr, F->answer)))
7704 goto error;
7705
7706 qname = rd.mx.host;
7707 qtype = DNS_T_A;
7708 qclass = DNS_C_IN;
7709
7710 break;
7711 case DNS_T_SRV:
7712 if ((error = dns_srv_parse(&rd.srv, &rr, F->answer)))
7713 goto error;
7714
7715 qname = rd.srv.target;
7716 qtype = DNS_T_A;
7717 qclass = DNS_C_IN;
7718
7719 break;
7720 default:
7721 continue;
7722 } /* switch() */
7723
7724 if ((error = dns_res_frame_prepare(R, &F[1], qname, qtype, qclass)))
7725 goto error;
7726
7727 F->state++;
7728
7729 dgoto(++R->sp, DNS_R_INIT);
7730 } /* while() */
7731
7732 /*
7733 * NOTE: SMTP specification says to fallback to A record.
7734 *
7735 * XXX: Should we add a mock MX answer?
7736 */
7737 if (R->qtype == DNS_T_MX && R->smart.state.count == 0) {
7738 if ((error = dns_res_frame_prepare(R, &F[1], R->qname, DNS_T_A, DNS_C_IN)))
7739 goto error;
7740
7741 R->smart.state.count++;
7742 F->state++;
7743
7744 dgoto(++R->sp, DNS_R_INIT);
7745 }
7746
7747 dgoto(R->sp, DNS_R_DONE);
7748 case DNS_R_SMART1_A:
7749 if (!F[1].answer)
7750 goto noanswer;
7751
7752 /*
7753 * FIXME: For CNAME chains (which are typically illegal in
7754 * this context), we should rewrite the record host name
7755 * to the original smart qname. All the user cares about
7756 * is locating that A/AAAA record.
7757 */
7758 dns_rr_foreach(&rr, F[1].answer, .section = DNS_S_AN, .type = DNS_T_A) {
7759 rr.section = DNS_S_AR;
7760
7761 if (dns_rr_exists(&rr, F[1].answer, F->answer))
7762 continue;
7763
7764 while ((error = dns_rr_copy(F->answer, &rr, F[1].answer))) {
7765 if (error != DNS_ENOBUFS)
7766 goto error;
7767 if ((error = dns_p_grow(&F->answer)))
7768 goto error;
7769 }
7770 }
7771
7772 dgoto(R->sp, DNS_R_SMART0_A);
7773 case DNS_R_DONE:
7774 if (!F->answer)
7775 goto noanswer;
7776
7777 if (R->sp > 0)
7778 dgoto(--R->sp, F[-1].state);
7779
7780 break;
7781 case DNS_R_SERVFAIL:
7782 if (!dns_p_setptr(&F->answer, dns_p_make(DNS_P_QBUFSIZ, &error)))
7783 goto error;
7784
7785 dns_header(F->answer)->qr = 1;
7786 dns_header(F->answer)->rcode = DNS_RC_SERVFAIL;
7787
7788 if ((error = dns_p_push(F->answer, DNS_S_QD, R->qname, strlen(R->qname), R->qtype, R->qclass, 0, 0)))
7789 goto error;
7790
7791 dgoto(R->sp, DNS_R_DONE);
7792 default:
7793 error = EINVAL;
7794
7795 goto error;
7796 } /* switch () */
7797
7798 return 0;
7799 noquery:
7800 error = DNS_ENOQUERY;
7801
7802 goto error;
7803 noanswer:
7804 error = DNS_ENOANSWER;
7805
7806 goto error;
7807 toolong:
7808 error = DNS_EILLEGAL;
7809
7810 /* FALL THROUGH */
7811 error:
7812 return error;
7813 } /* dns_res_exec() */
7814
7815 #undef goto
7816
7817
dns_res_clear(struct dns_resolver * R)7818 void dns_res_clear(struct dns_resolver *R) {
7819 switch (R->stack[R->sp].state) {
7820 case DNS_R_CHECK:
7821 R->cache->clear(R->cache);
7822 break;
7823 default:
7824 dns_so_clear(&R->so);
7825 break;
7826 }
7827 } /* dns_res_clear() */
7828
7829
dns_res_events2(struct dns_resolver * R,enum dns_events type)7830 static int dns_res_events2(struct dns_resolver *R, enum dns_events type) {
7831 int events;
7832
7833 switch (R->stack[R->sp].state) {
7834 case DNS_R_CHECK:
7835 events = R->cache->events(R->cache);
7836
7837 return (type == DNS_LIBEVENT)? DNS_POLL2EV(events) : events;
7838 default:
7839 return dns_so_events2(&R->so, type);
7840 }
7841 } /* dns_res_events2() */
7842
7843
dns_res_events(struct dns_resolver * R)7844 int dns_res_events(struct dns_resolver *R) {
7845 return dns_res_events2(R, R->so.opts.events);
7846 } /* dns_res_events() */
7847
7848
dns_res_pollfd(struct dns_resolver * R)7849 int dns_res_pollfd(struct dns_resolver *R) {
7850 switch (R->stack[R->sp].state) {
7851 case DNS_R_CHECK:
7852 return R->cache->pollfd(R->cache);
7853 default:
7854 return dns_so_pollfd(&R->so);
7855 }
7856 } /* dns_res_pollfd() */
7857
7858
dns_res_timeout(struct dns_resolver * R)7859 time_t dns_res_timeout(struct dns_resolver *R) {
7860 time_t elapsed;
7861
7862 switch (R->stack[R->sp].state) {
7863 #if 0
7864 case DNS_R_QUERY_AAAA:
7865 #endif
7866 case DNS_R_QUERY_A:
7867 elapsed = dns_so_elapsed(&R->so);
7868
7869 if (elapsed <= dns_resconf_timeout(R->resconf))
7870 return R->resconf->options.timeout - elapsed;
7871
7872 break;
7873 default:
7874 break;
7875 } /* switch() */
7876
7877 /*
7878 * NOTE: We're not in a pollable state, or the user code hasn't
7879 * called dns_res_check properly. The calling code is probably
7880 * broken. Put them into a slow-burn pattern.
7881 */
7882 return 1;
7883 } /* dns_res_timeout() */
7884
7885
dns_res_elapsed(struct dns_resolver * R)7886 time_t dns_res_elapsed(struct dns_resolver *R) {
7887 return dns_elapsed(&R->elapsed);
7888 } /* dns_res_elapsed() */
7889
7890
dns_res_poll(struct dns_resolver * R,int timeout)7891 int dns_res_poll(struct dns_resolver *R, int timeout) {
7892 return dns_poll(dns_res_pollfd(R), dns_res_events2(R, DNS_SYSPOLL), timeout);
7893 } /* dns_res_poll() */
7894
7895
dns_res_submit2(struct dns_resolver * R,const char * qname,size_t qlen,enum dns_type qtype,enum dns_class qclass)7896 int dns_res_submit2(struct dns_resolver *R, const char *qname, size_t qlen, enum dns_type qtype, enum dns_class qclass) {
7897 dns_res_reset(R);
7898
7899 /* Don't anchor; that can conflict with searchlist generation. */
7900 dns_d_init(R->qname, sizeof R->qname, qname, (R->qlen = qlen), 0);
7901
7902 R->qtype = qtype;
7903 R->qclass = qclass;
7904
7905 dns_begin(&R->elapsed);
7906
7907 return 0;
7908 } /* dns_res_submit2() */
7909
7910
dns_res_submit(struct dns_resolver * R,const char * qname,enum dns_type qtype,enum dns_class qclass)7911 int dns_res_submit(struct dns_resolver *R, const char *qname, enum dns_type qtype, enum dns_class qclass) {
7912 return dns_res_submit2(R, qname, strlen(qname), qtype, qclass);
7913 } /* dns_res_submit() */
7914
7915
dns_res_check(struct dns_resolver * R)7916 int dns_res_check(struct dns_resolver *R) {
7917 int error;
7918
7919 if (R->stack[0].state != DNS_R_DONE) {
7920 if ((error = dns_res_exec(R)))
7921 return error;
7922 }
7923
7924 return 0;
7925 } /* dns_res_check() */
7926
7927
dns_res_fetch(struct dns_resolver * R,int * error)7928 struct dns_packet *dns_res_fetch(struct dns_resolver *R, int *error) {
7929 struct dns_packet *P = NULL;
7930
7931 if (R->stack[0].state != DNS_R_DONE)
7932 return *error = DNS_EUNKNOWN, (void *)0;
7933
7934 if (!dns_p_movptr(&P, &R->stack[0].answer))
7935 return *error = DNS_EFETCHED, (void *)0;
7936
7937 return P;
7938 } /* dns_res_fetch() */
7939
7940
dns_res_fetch_and_study(struct dns_resolver * R,int * _error)7941 static struct dns_packet *dns_res_fetch_and_study(struct dns_resolver *R, int *_error) {
7942 struct dns_packet *P = NULL;
7943 int error;
7944
7945 if (!(P = dns_res_fetch(R, &error)))
7946 goto error;
7947 if ((error = dns_p_study(P)))
7948 goto error;
7949
7950 return P;
7951 error:
7952 *_error = error;
7953
7954 dns_p_free(P);
7955
7956 return NULL;
7957 } /* dns_res_fetch_and_study() */
7958
7959
dns_res_query(struct dns_resolver * res,const char * qname,enum dns_type qtype,enum dns_class qclass,int timeout,int * error_)7960 struct dns_packet *dns_res_query(struct dns_resolver *res, const char *qname, enum dns_type qtype, enum dns_class qclass, int timeout, int *error_) {
7961 int error;
7962
7963 if ((error = dns_res_submit(res, qname, qtype, qclass)))
7964 goto error;
7965
7966 while ((error = dns_res_check(res))) {
7967 if (dns_res_elapsed(res) > timeout)
7968 error = DNS_ETIMEDOUT;
7969
7970 if (error != DNS_EAGAIN)
7971 goto error;
7972
7973 if ((error = dns_res_poll(res, 1)))
7974 goto error;
7975 }
7976
7977 return dns_res_fetch(res, error_);
7978 error:
7979 *error_ = error;
7980
7981 return 0;
7982 } /* dns_res_query() */
7983
7984
dns_res_stat(struct dns_resolver * res)7985 const struct dns_stat *dns_res_stat(struct dns_resolver *res) {
7986 return dns_so_stat(&res->so);
7987 } /* dns_res_stat() */
7988
7989
dns_res_sethints(struct dns_resolver * res,struct dns_hints * hints)7990 void dns_res_sethints(struct dns_resolver *res, struct dns_hints *hints) {
7991 dns_hints_acquire(hints); /* acquire first in case same hints object */
7992 dns_hints_close(res->hints);
7993 res->hints = hints;
7994 } /* dns_res_sethints() */
7995
7996
7997 /*
7998 * A D D R I N F O R O U T I N E S
7999 *
8000 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8001
8002 struct dns_addrinfo {
8003 struct addrinfo hints;
8004 struct dns_resolver *res;
8005
8006 char qname[DNS_D_MAXNAME + 1];
8007 enum dns_type qtype;
8008 unsigned short qport, port;
8009
8010 struct {
8011 unsigned long todo;
8012 int state;
8013 int atype;
8014 enum dns_type qtype;
8015 } af;
8016
8017 struct dns_packet *answer;
8018 struct dns_packet *glue;
8019
8020 struct dns_rr_i i, g;
8021 struct dns_rr rr;
8022
8023 char cname[DNS_D_MAXNAME + 1];
8024 char i_cname[DNS_D_MAXNAME + 1], g_cname[DNS_D_MAXNAME + 1];
8025
8026 int g_depth;
8027
8028 int state;
8029 int found;
8030
8031 struct dns_stat st;
8032 }; /* struct dns_addrinfo */
8033
8034
8035 #define DNS_AI_AFMAX 32
8036 #define DNS_AI_AF2INDEX(af) (1UL << ((af) - 1))
8037
dns_ai_af2index(int af)8038 static inline unsigned long dns_ai_af2index(int af) {
8039 dns_static_assert(dns_same_type(unsigned long, DNS_AI_AF2INDEX(1), 1), "internal type mismatch");
8040 dns_static_assert(dns_same_type(unsigned long, ((struct dns_addrinfo *)0)->af.todo, 1), "internal type mismatch");
8041
8042 return (af > 0 && af <= DNS_AI_AFMAX)? DNS_AI_AF2INDEX(af) : 0;
8043 }
8044
dns_ai_setaf(struct dns_addrinfo * ai,int af,int qtype)8045 static int dns_ai_setaf(struct dns_addrinfo *ai, int af, int qtype) {
8046 ai->af.atype = af;
8047 ai->af.qtype = qtype;
8048
8049 ai->af.todo &= ~dns_ai_af2index(af);
8050
8051 return af;
8052 } /* dns_ai_setaf() */
8053
8054 #define DNS_SM_RESTORE \
8055 do { pc = 0xff & (ai->af.state >> 0); i = 0xff & (ai->af.state >> 8); } while (0)
8056 #define DNS_SM_SAVE \
8057 do { ai->af.state = ((0xff & pc) << 0) | ((0xff & i) << 8); } while (0)
8058
dns_ai_nextaf(struct dns_addrinfo * ai)8059 static int dns_ai_nextaf(struct dns_addrinfo *ai) {
8060 int i, pc;
8061
8062 dns_static_assert(AF_UNSPEC == 0, "AF_UNSPEC constant not 0");
8063 dns_static_assert(AF_INET <= DNS_AI_AFMAX, "AF_INET constant too large");
8064 dns_static_assert(AF_INET6 <= DNS_AI_AFMAX, "AF_INET6 constant too large");
8065
8066 DNS_SM_ENTER;
8067
8068 if (ai->res) {
8069 /*
8070 * NB: On OpenBSD, at least, the types of entries resolved
8071 * is the intersection of the /etc/resolv.conf families and
8072 * the families permitted by the .ai_type hint. So if
8073 * /etc/resolv.conf has "family inet4" and .ai_type
8074 * is AF_INET6, then the address ::1 will return 0 entries
8075 * even if AI_NUMERICHOST is specified in .ai_flags.
8076 */
8077 while (i < (int)lengthof(ai->res->resconf->family)) {
8078 int af = ai->res->resconf->family[i++];
8079
8080 if (af == AF_UNSPEC) {
8081 DNS_SM_EXIT;
8082 } else if (af < 0 || af > DNS_AI_AFMAX) {
8083 continue;
8084 } else if (!(DNS_AI_AF2INDEX(af) & ai->af.todo)) {
8085 continue;
8086 } else if (af == AF_INET) {
8087 DNS_SM_YIELD(dns_ai_setaf(ai, AF_INET, DNS_T_A));
8088 } else if (af == AF_INET6) {
8089 DNS_SM_YIELD(dns_ai_setaf(ai, AF_INET6, DNS_T_AAAA));
8090 }
8091 }
8092 } else {
8093 /*
8094 * NB: If we get here than AI_NUMERICFLAGS should be set and
8095 * order shouldn't matter.
8096 */
8097 if (DNS_AI_AF2INDEX(AF_INET) & ai->af.todo)
8098 DNS_SM_YIELD(dns_ai_setaf(ai, AF_INET, DNS_T_A));
8099 if (DNS_AI_AF2INDEX(AF_INET6) & ai->af.todo)
8100 DNS_SM_YIELD(dns_ai_setaf(ai, AF_INET6, DNS_T_AAAA));
8101 }
8102
8103 DNS_SM_LEAVE;
8104
8105 return dns_ai_setaf(ai, AF_UNSPEC, 0);
8106 } /* dns_ai_nextaf() */
8107
8108 #undef DNS_SM_RESTORE
8109 #undef DNS_SM_SAVE
8110
dns_ai_qtype(struct dns_addrinfo * ai)8111 static enum dns_type dns_ai_qtype(struct dns_addrinfo *ai) {
8112 return (ai->qtype)? ai->qtype : ai->af.qtype;
8113 } /* dns_ai_qtype() */
8114
8115
dns_ai_parseport(unsigned short * port,const char * serv,const struct addrinfo * hints)8116 static dns_error_t dns_ai_parseport(unsigned short *port, const char *serv, const struct addrinfo *hints) {
8117 const char *cp = serv;
8118 unsigned long n = 0;
8119
8120 while (*cp >= '0' && *cp <= '9' && n < 65536) {
8121 n *= 10;
8122 n += *cp++ - '0';
8123 }
8124
8125 if (*cp == '\0') {
8126 if (cp == serv || n >= 65536)
8127 return DNS_ESERVICE;
8128
8129 *port = n;
8130
8131 return 0;
8132 }
8133
8134 if (hints->ai_flags & AI_NUMERICSERV)
8135 return DNS_ESERVICE;
8136
8137 /* TODO: try getaddrinfo(NULL, serv, { .ai_flags = AI_NUMERICSERV }) */
8138
8139 return DNS_ESERVICE;
8140 } /* dns_ai_parseport() */
8141
8142
dns_ai_open(const char * host,const char * serv,enum dns_type qtype,const struct addrinfo * hints,struct dns_resolver * res,int * _error)8143 struct dns_addrinfo *dns_ai_open(const char *host, const char *serv, enum dns_type qtype, const struct addrinfo *hints, struct dns_resolver *res, int *_error) {
8144 static const struct dns_addrinfo ai_initializer;
8145 struct dns_addrinfo *ai;
8146 int error;
8147
8148 if (res) {
8149 dns_res_acquire(res);
8150 } else if (!(hints->ai_flags & AI_NUMERICHOST)) {
8151 /*
8152 * NOTE: it's assumed that *_error is set from a previous
8153 * API function call, such as dns_res_stub(). Should change
8154 * this semantic, but it's applied elsewhere, too.
8155 */
8156 if (!*_error)
8157 *_error = EINVAL;
8158 return NULL;
8159 }
8160
8161 if (!(ai = malloc(sizeof *ai)))
8162 goto syerr;
8163
8164 *ai = ai_initializer;
8165 ai->hints = *hints;
8166
8167 ai->res = res;
8168 res = NULL;
8169
8170 if (sizeof ai->qname <= dns_strlcpy(ai->qname, host, sizeof ai->qname))
8171 { error = ENAMETOOLONG; goto error; }
8172
8173 ai->qtype = qtype;
8174 ai->qport = 0;
8175
8176 if (serv && (error = dns_ai_parseport(&ai->qport, serv, hints)))
8177 goto error;
8178 ai->port = ai->qport;
8179
8180 /*
8181 * FIXME: If an explicit A or AAAA record type conflicts with
8182 * .ai_family or with resconf.family (i.e. AAAA specified but
8183 * AF_INET6 not in interection of .ai_family and resconf.family),
8184 * then what?
8185 */
8186 switch (ai->qtype) {
8187 case DNS_T_A:
8188 ai->af.todo = DNS_AI_AF2INDEX(AF_INET);
8189 break;
8190 case DNS_T_AAAA:
8191 ai->af.todo = DNS_AI_AF2INDEX(AF_INET6);
8192 break;
8193 default: /* 0, MX, SRV, etc */
8194 switch (ai->hints.ai_family) {
8195 case AF_UNSPEC:
8196 ai->af.todo = DNS_AI_AF2INDEX(AF_INET) | DNS_AI_AF2INDEX(AF_INET6);
8197 break;
8198 case AF_INET:
8199 ai->af.todo = DNS_AI_AF2INDEX(AF_INET);
8200 break;
8201 case AF_INET6:
8202 ai->af.todo = DNS_AI_AF2INDEX(AF_INET6);
8203 break;
8204 default:
8205 break;
8206 }
8207 }
8208
8209 return ai;
8210 syerr:
8211 error = dns_syerr();
8212 error:
8213 *_error = error;
8214
8215 dns_ai_close(ai);
8216 dns_res_close(res);
8217
8218 return NULL;
8219 } /* dns_ai_open() */
8220
8221
dns_ai_close(struct dns_addrinfo * ai)8222 void dns_ai_close(struct dns_addrinfo *ai) {
8223 if (!ai)
8224 return;
8225
8226 dns_res_close(ai->res);
8227
8228 if (ai->answer != ai->glue)
8229 dns_p_free(ai->glue);
8230
8231 dns_p_free(ai->answer);
8232 free(ai);
8233 } /* dns_ai_close() */
8234
8235
dns_ai_setent(struct addrinfo ** ent,union dns_any * any,enum dns_type type,struct dns_addrinfo * ai)8236 static int dns_ai_setent(struct addrinfo **ent, union dns_any *any, enum dns_type type, struct dns_addrinfo *ai) {
8237 union { struct sockaddr saddr; struct sockaddr_in sin; struct sockaddr_in6 sin6; } saddr = {0};
8238 const char *cname;
8239 size_t clen;
8240
8241 switch (type) {
8242 case DNS_T_A:
8243 saddr.sin.sin_family = AF_INET;
8244 saddr.sin.sin_port = htons(ai->port);
8245
8246 memcpy(&saddr.sin.sin_addr, any, sizeof saddr.sin.sin_addr);
8247
8248 break;
8249 case DNS_T_AAAA:
8250 saddr.sin6.sin6_family = AF_INET6;
8251 saddr.sin6.sin6_port = htons(ai->port);
8252
8253 memcpy(&saddr.sin6.sin6_addr, any, sizeof saddr.sin6.sin6_addr);
8254
8255 break;
8256 default:
8257 return EINVAL;
8258 } /* switch() */
8259
8260 if (ai->hints.ai_flags & AI_CANONNAME) {
8261 cname = (*ai->cname)? ai->cname : ai->qname;
8262 clen = strlen(cname);
8263 } else {
8264 cname = NULL;
8265 clen = 0;
8266 }
8267
8268 if (!(*ent = malloc(sizeof **ent + dns_sa_len(&saddr) + ((ai->hints.ai_flags & AI_CANONNAME)? clen + 1 : 0))))
8269 return dns_syerr();
8270
8271 memset(*ent, '\0', sizeof **ent);
8272
8273 (*ent)->ai_family = saddr.saddr.sa_family;
8274 (*ent)->ai_socktype = ai->hints.ai_socktype;
8275 (*ent)->ai_protocol = ai->hints.ai_protocol;
8276
8277 (*ent)->ai_addr = memcpy((unsigned char *)*ent + sizeof **ent, &saddr, dns_sa_len(&saddr));
8278 (*ent)->ai_addrlen = dns_sa_len(&saddr);
8279
8280 if (ai->hints.ai_flags & AI_CANONNAME)
8281 (*ent)->ai_canonname = memcpy((unsigned char *)*ent + sizeof **ent + dns_sa_len(&saddr), cname, clen + 1);
8282
8283 ai->found++;
8284
8285 return 0;
8286 } /* dns_ai_setent() */
8287
8288
8289 enum dns_ai_state {
8290 DNS_AI_S_INIT,
8291 DNS_AI_S_NEXTAF,
8292 DNS_AI_S_NUMERIC,
8293 DNS_AI_S_SUBMIT,
8294 DNS_AI_S_CHECK,
8295 DNS_AI_S_FETCH,
8296 DNS_AI_S_FOREACH_I,
8297 DNS_AI_S_INIT_G,
8298 DNS_AI_S_ITERATE_G,
8299 DNS_AI_S_FOREACH_G,
8300 DNS_AI_S_SUBMIT_G,
8301 DNS_AI_S_CHECK_G,
8302 DNS_AI_S_FETCH_G,
8303 DNS_AI_S_DONE,
8304 }; /* enum dns_ai_state */
8305
8306 #define dns_ai_goto(which) do { ai->state = (which); goto exec; } while (0)
8307
dns_ai_nextent(struct addrinfo ** ent,struct dns_addrinfo * ai)8308 int dns_ai_nextent(struct addrinfo **ent, struct dns_addrinfo *ai) {
8309 struct dns_packet *ans, *glue;
8310 struct dns_rr rr;
8311 char qname[DNS_D_MAXNAME + 1];
8312 union dns_any any;
8313 size_t qlen, clen;
8314 int error;
8315
8316 *ent = 0;
8317
8318 exec:
8319
8320 switch (ai->state) {
8321 case DNS_AI_S_INIT:
8322 ai->state++;
8323 /* FALL THROUGH */
8324 case DNS_AI_S_NEXTAF:
8325 if (!dns_ai_nextaf(ai))
8326 dns_ai_goto(DNS_AI_S_DONE);
8327
8328 ai->state++;
8329 /* FALL THROUGH */
8330 case DNS_AI_S_NUMERIC:
8331 if (1 == dns_inet_pton(AF_INET, ai->qname, &any.a)) {
8332 if (ai->af.atype == AF_INET) {
8333 ai->state = DNS_AI_S_NEXTAF;
8334 return dns_ai_setent(ent, &any, DNS_T_A, ai);
8335 } else {
8336 dns_ai_goto(DNS_AI_S_NEXTAF);
8337 }
8338 }
8339
8340 if (1 == dns_inet_pton(AF_INET6, ai->qname, &any.aaaa)) {
8341 if (ai->af.atype == AF_INET6) {
8342 ai->state = DNS_AI_S_NEXTAF;
8343 return dns_ai_setent(ent, &any, DNS_T_AAAA, ai);
8344 } else {
8345 dns_ai_goto(DNS_AI_S_NEXTAF);
8346 }
8347 }
8348
8349 if (ai->hints.ai_flags & AI_NUMERICHOST)
8350 dns_ai_goto(DNS_AI_S_NEXTAF);
8351
8352 ai->state++;
8353 /* FALL THROUGH */
8354 case DNS_AI_S_SUBMIT:
8355 assert(ai->res);
8356
8357 if ((error = dns_res_submit(ai->res, ai->qname, dns_ai_qtype(ai), DNS_C_IN)))
8358 return error;
8359
8360 ai->state++;
8361 /* FALL THROUGH */
8362 case DNS_AI_S_CHECK:
8363 if ((error = dns_res_check(ai->res)))
8364 return error;
8365
8366 ai->state++;
8367 /* FALL THROUGH */
8368 case DNS_AI_S_FETCH:
8369 if (!(ans = dns_res_fetch_and_study(ai->res, &error)))
8370 return error;
8371 if (ai->glue != ai->answer)
8372 dns_p_free(ai->glue);
8373 ai->glue = dns_p_movptr(&ai->answer, &ans);
8374
8375 /* Search generator may have changed the qname. */
8376 if (!(qlen = dns_d_expand(qname, sizeof qname, 12, ai->answer, &error)))
8377 return error;
8378 else if (qlen >= sizeof qname)
8379 return DNS_EILLEGAL;
8380 if (!dns_d_cname(ai->cname, sizeof ai->cname, qname, qlen, ai->answer, &error))
8381 return error;
8382
8383 dns_strlcpy(ai->i_cname, ai->cname, sizeof ai->i_cname);
8384 dns_rr_i_init(&ai->i, ai->answer);
8385 ai->i.section = DNS_S_AN;
8386 ai->i.name = ai->i_cname;
8387 ai->i.type = dns_ai_qtype(ai);
8388 ai->i.sort = &dns_rr_i_order;
8389
8390 ai->state++;
8391 /* FALL THROUGH */
8392 case DNS_AI_S_FOREACH_I:
8393 if (!dns_rr_grep(&rr, 1, &ai->i, ai->answer, &error))
8394 dns_ai_goto(DNS_AI_S_NEXTAF);
8395
8396 if ((error = dns_any_parse(&any, &rr, ai->answer)))
8397 return error;
8398
8399 ai->port = ai->qport;
8400
8401 switch (rr.type) {
8402 case DNS_T_A:
8403 case DNS_T_AAAA:
8404 return dns_ai_setent(ent, &any, rr.type, ai);
8405 default:
8406 if (!(clen = dns_any_cname(ai->cname, sizeof ai->cname, &any, rr.type)))
8407 dns_ai_goto(DNS_AI_S_FOREACH_I);
8408
8409 /*
8410 * Find the "real" canonical name. Some authorities
8411 * publish aliases where an RFC defines a canonical
8412 * name. We trust that the resolver followed any
8413 * CNAME chains on it's own, regardless of whether
8414 * the "smart" option is enabled.
8415 */
8416 if (!dns_d_cname(ai->cname, sizeof ai->cname, ai->cname, clen, ai->answer, &error))
8417 return error;
8418
8419 if (rr.type == DNS_T_SRV)
8420 ai->port = any.srv.port;
8421
8422 break;
8423 } /* switch() */
8424
8425 ai->state++;
8426 /* FALL THROUGH */
8427 case DNS_AI_S_INIT_G:
8428 ai->g_depth = 0;
8429
8430 ai->state++;
8431 /* FALL THROUGH */
8432 case DNS_AI_S_ITERATE_G:
8433 dns_strlcpy(ai->g_cname, ai->cname, sizeof ai->g_cname);
8434 dns_rr_i_init(&ai->g, ai->glue);
8435 ai->g.section = DNS_S_ALL & ~DNS_S_QD;
8436 ai->g.name = ai->g_cname;
8437 ai->g.type = ai->af.qtype;
8438
8439 ai->state++;
8440 /* FALL THROUGH */
8441 case DNS_AI_S_FOREACH_G:
8442 if (!dns_rr_grep(&rr, 1, &ai->g, ai->glue, &error)) {
8443 if (dns_rr_i_count(&ai->g) > 0)
8444 dns_ai_goto(DNS_AI_S_FOREACH_I);
8445 else
8446 dns_ai_goto(DNS_AI_S_SUBMIT_G);
8447 }
8448
8449 if ((error = dns_any_parse(&any, &rr, ai->glue)))
8450 return error;
8451
8452 return dns_ai_setent(ent, &any, rr.type, ai);
8453 case DNS_AI_S_SUBMIT_G:
8454 /* skip if already queried */
8455 if (dns_rr_grep(&rr, 1, dns_rr_i_new(ai->glue, .section = DNS_S_QD, .name = ai->g.name, .type = ai->g.type), ai->glue, &error))
8456 dns_ai_goto(DNS_AI_S_FOREACH_I);
8457 /* skip if we recursed (CNAME chains should have been handled in the resolver) */
8458 if (++ai->g_depth > 1)
8459 dns_ai_goto(DNS_AI_S_FOREACH_I);
8460
8461 if ((error = dns_res_submit(ai->res, ai->g.name, ai->g.type, DNS_C_IN)))
8462 return error;
8463
8464 ai->state++;
8465 /* FALL THROUGH */
8466 case DNS_AI_S_CHECK_G:
8467 if ((error = dns_res_check(ai->res)))
8468 return error;
8469
8470 ai->state++;
8471 /* FALL THROUGH */
8472 case DNS_AI_S_FETCH_G:
8473 if (!(ans = dns_res_fetch_and_study(ai->res, &error)))
8474 return error;
8475
8476 glue = dns_p_merge(ai->glue, DNS_S_ALL, ans, DNS_S_ALL, &error);
8477 dns_p_setptr(&ans, NULL);
8478 if (!glue)
8479 return error;
8480
8481 if (ai->glue != ai->answer)
8482 dns_p_free(ai->glue);
8483 ai->glue = glue;
8484
8485 if (!dns_d_cname(ai->cname, sizeof ai->cname, ai->g.name, strlen(ai->g.name), ai->glue, &error))
8486 dns_ai_goto(DNS_AI_S_FOREACH_I);
8487
8488 dns_ai_goto(DNS_AI_S_ITERATE_G);
8489 case DNS_AI_S_DONE:
8490 if (ai->found) {
8491 return ENOENT; /* TODO: Just return 0 */
8492 } else if (ai->answer) {
8493 switch (dns_p_rcode(ai->answer)) {
8494 case DNS_RC_NOERROR:
8495 /* FALL THROUGH */
8496 case DNS_RC_NXDOMAIN:
8497 return DNS_ENONAME;
8498 default:
8499 return DNS_EFAIL;
8500 }
8501 } else {
8502 return DNS_EFAIL;
8503 }
8504 default:
8505 return EINVAL;
8506 } /* switch() */
8507 } /* dns_ai_nextent() */
8508
8509
dns_ai_elapsed(struct dns_addrinfo * ai)8510 time_t dns_ai_elapsed(struct dns_addrinfo *ai) {
8511 return (ai->res)? dns_res_elapsed(ai->res) : 0;
8512 } /* dns_ai_elapsed() */
8513
8514
dns_ai_clear(struct dns_addrinfo * ai)8515 void dns_ai_clear(struct dns_addrinfo *ai) {
8516 if (ai->res)
8517 dns_res_clear(ai->res);
8518 } /* dns_ai_clear() */
8519
8520
dns_ai_events(struct dns_addrinfo * ai)8521 int dns_ai_events(struct dns_addrinfo *ai) {
8522 return (ai->res)? dns_res_events(ai->res) : 0;
8523 } /* dns_ai_events() */
8524
8525
dns_ai_pollfd(struct dns_addrinfo * ai)8526 int dns_ai_pollfd(struct dns_addrinfo *ai) {
8527 return (ai->res)? dns_res_pollfd(ai->res) : -1;
8528 } /* dns_ai_pollfd() */
8529
8530
dns_ai_timeout(struct dns_addrinfo * ai)8531 time_t dns_ai_timeout(struct dns_addrinfo *ai) {
8532 return (ai->res)? dns_res_timeout(ai->res) : 0;
8533 } /* dns_ai_timeout() */
8534
8535
dns_ai_poll(struct dns_addrinfo * ai,int timeout)8536 int dns_ai_poll(struct dns_addrinfo *ai, int timeout) {
8537 return (ai->res)? dns_res_poll(ai->res, timeout) : 0;
8538 } /* dns_ai_poll() */
8539
8540
dns_ai_print(void * _dst,size_t lim,struct addrinfo * ent,struct dns_addrinfo * ai)8541 size_t dns_ai_print(void *_dst, size_t lim, struct addrinfo *ent, struct dns_addrinfo *ai) {
8542 struct dns_buf dst = DNS_B_INTO(_dst, lim);
8543 char addr[DNS_PP_MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) + 1];
8544
8545 dns_b_puts(&dst, "[ ");
8546 dns_b_puts(&dst, ai->qname);
8547 dns_b_puts(&dst, " IN ");
8548 if (ai->qtype) {
8549 dns_b_puts(&dst, dns_strtype(ai->qtype));
8550 } else if (ent->ai_family == AF_INET) {
8551 dns_b_puts(&dst, dns_strtype(DNS_T_A));
8552 } else if (ent->ai_family == AF_INET6) {
8553 dns_b_puts(&dst, dns_strtype(DNS_T_AAAA));
8554 } else {
8555 dns_b_puts(&dst, "0");
8556 }
8557 dns_b_puts(&dst, " ]\n");
8558
8559 dns_b_puts(&dst, ".ai_family = ");
8560 switch (ent->ai_family) {
8561 case AF_INET:
8562 dns_b_puts(&dst, "AF_INET");
8563 break;
8564 case AF_INET6:
8565 dns_b_puts(&dst, "AF_INET6");
8566 break;
8567 default:
8568 dns_b_fmtju(&dst, ent->ai_family, 0);
8569 break;
8570 }
8571 dns_b_putc(&dst, '\n');
8572
8573 dns_b_puts(&dst, ".ai_socktype = ");
8574 switch (ent->ai_socktype) {
8575 case SOCK_STREAM:
8576 dns_b_puts(&dst, "SOCK_STREAM");
8577 break;
8578 case SOCK_DGRAM:
8579 dns_b_puts(&dst, "SOCK_DGRAM");
8580 break;
8581 default:
8582 dns_b_fmtju(&dst, ent->ai_socktype, 0);
8583 break;
8584 }
8585 dns_b_putc(&dst, '\n');
8586
8587 dns_inet_ntop(dns_sa_family(ent->ai_addr), dns_sa_addr(dns_sa_family(ent->ai_addr), ent->ai_addr, NULL), addr, sizeof addr);
8588 dns_b_puts(&dst, ".ai_addr = [");
8589 dns_b_puts(&dst, addr);
8590 dns_b_puts(&dst, "]:");
8591 dns_b_fmtju(&dst, ntohs(*dns_sa_port(dns_sa_family(ent->ai_addr), ent->ai_addr)), 0);
8592 dns_b_putc(&dst, '\n');
8593
8594 dns_b_puts(&dst, ".ai_canonname = ");
8595 dns_b_puts(&dst, (ent->ai_canonname)? ent->ai_canonname : "[NULL]");
8596 dns_b_putc(&dst, '\n');
8597
8598 return dns_b_strllen(&dst);
8599 } /* dns_ai_print() */
8600
8601
dns_ai_stat(struct dns_addrinfo * ai)8602 const struct dns_stat *dns_ai_stat(struct dns_addrinfo *ai) {
8603 return (ai->res)? dns_res_stat(ai->res) : &ai->st;
8604 } /* dns_ai_stat() */
8605
8606
8607 /*
8608 * M I S C E L L A N E O U S R O U T I N E S
8609 *
8610 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8611
8612 static const struct {
8613 char name[16];
8614 enum dns_section type;
8615 } dns_sections[] = {
8616 { "QUESTION", DNS_S_QUESTION },
8617 { "QD", DNS_S_QUESTION },
8618 { "ANSWER", DNS_S_ANSWER },
8619 { "AN", DNS_S_ANSWER },
8620 { "AUTHORITY", DNS_S_AUTHORITY },
8621 { "NS", DNS_S_AUTHORITY },
8622 { "ADDITIONAL", DNS_S_ADDITIONAL },
8623 { "AR", DNS_S_ADDITIONAL },
8624 };
8625
8626 const char *(dns_strsection)(enum dns_section section, void *_dst, size_t lim) {
8627 struct dns_buf dst = DNS_B_INTO(_dst, lim);
8628 unsigned i;
8629
8630 for (i = 0; i < lengthof(dns_sections); i++) {
8631 if (dns_sections[i].type & section) {
8632 dns_b_puts(&dst, dns_sections[i].name);
8633 section &= ~dns_sections[i].type;
8634 if (section)
8635 dns_b_putc(&dst, '|');
8636 }
8637 }
8638
8639 if (section || dst.p == dst.base)
8640 dns_b_fmtju(&dst, (0xffff & section), 0);
8641
8642 return dns_b_tostring(&dst);
8643 } /* dns_strsection() */
8644
8645
dns_isection(const char * src)8646 enum dns_section dns_isection(const char *src) {
8647 enum dns_section section = 0;
8648 char sbuf[128];
8649 char *name, *next;
8650 unsigned i;
8651
8652 dns_strlcpy(sbuf, src, sizeof sbuf);
8653 next = sbuf;
8654
8655 while ((name = dns_strsep(&next, "|+, \t"))) {
8656 for (i = 0; i < lengthof(dns_sections); i++) {
8657 if (!strcasecmp(dns_sections[i].name, name)) {
8658 section |= dns_sections[i].type;
8659 break;
8660 }
8661 }
8662 }
8663
8664 return section;
8665 } /* dns_isection() */
8666
8667
8668 static const struct {
8669 char name[8];
8670 enum dns_class type;
8671 } dns_classes[] = {
8672 { "IN", DNS_C_IN },
8673 };
8674
8675 const char *(dns_strclass)(enum dns_class type, void *_dst, size_t lim) {
8676 struct dns_buf dst = DNS_B_INTO(_dst, lim);
8677 unsigned i;
8678
8679 for (i = 0; i < lengthof(dns_classes); i++) {
8680 if (dns_classes[i].type == type) {
8681 dns_b_puts(&dst, dns_classes[i].name);
8682 break;
8683 }
8684 }
8685
8686 if (dst.p == dst.base)
8687 dns_b_fmtju(&dst, (0xffff & type), 0);
8688
8689 return dns_b_tostring(&dst);
8690 } /* dns_strclass() */
8691
8692
dns_iclass(const char * name)8693 enum dns_class dns_iclass(const char *name) {
8694 unsigned i, class;
8695
8696 for (i = 0; i < lengthof(dns_classes); i++) {
8697 if (!strcasecmp(dns_classes[i].name, name))
8698 return dns_classes[i].type;
8699 }
8700
8701 class = 0;
8702 while (dns_isdigit(*name)) {
8703 class *= 10;
8704 class += *name++ - '0';
8705 }
8706
8707 return DNS_PP_MIN(class, 0xffff);
8708 } /* dns_iclass() */
8709
8710
8711 const char *(dns_strtype)(enum dns_type type, void *_dst, size_t lim) {
8712 struct dns_buf dst = DNS_B_INTO(_dst, lim);
8713 unsigned i;
8714
8715 for (i = 0; i < lengthof(dns_rrtypes); i++) {
8716 if (dns_rrtypes[i].type == type) {
8717 dns_b_puts(&dst, dns_rrtypes[i].name);
8718 break;
8719 }
8720 }
8721
8722 if (dst.p == dst.base)
8723 dns_b_fmtju(&dst, (0xffff & type), 0);
8724
8725 return dns_b_tostring(&dst);
8726 } /* dns_strtype() */
8727
8728
dns_itype(const char * name)8729 enum dns_type dns_itype(const char *name) {
8730 unsigned i, type;
8731
8732 for (i = 0; i < lengthof(dns_rrtypes); i++) {
8733 if (!strcasecmp(dns_rrtypes[i].name, name))
8734 return dns_rrtypes[i].type;
8735 }
8736
8737 type = 0;
8738 while (dns_isdigit(*name)) {
8739 type *= 10;
8740 type += *name++ - '0';
8741 }
8742
8743 return DNS_PP_MIN(type, 0xffff);
8744 } /* dns_itype() */
8745
8746
8747 static char dns_opcodes[16][16] = {
8748 [DNS_OP_QUERY] = "QUERY",
8749 [DNS_OP_IQUERY] = "IQUERY",
8750 [DNS_OP_STATUS] = "STATUS",
8751 [DNS_OP_NOTIFY] = "NOTIFY",
8752 [DNS_OP_UPDATE] = "UPDATE",
8753 };
8754
dns__strcode(int code,volatile char * dst,size_t lim)8755 static const char *dns__strcode(int code, volatile char *dst, size_t lim) {
8756 char _tmp[48] = "";
8757 struct dns_buf tmp;
8758 size_t p;
8759
8760 assert(lim > 0);
8761 dns_b_fmtju(dns_b_into(&tmp, _tmp, DNS_PP_MIN(sizeof _tmp, lim - 1)), code, 0);
8762
8763 /* copy downwards so first byte is copied last (see below) */
8764 p = (size_t)(tmp.p - tmp.base);
8765 dst[p] = '\0';
8766 while (p--)
8767 dst[p] = _tmp[p];
8768
8769 return (const char *)dst;
8770 }
8771
dns_stropcode(enum dns_opcode opcode)8772 const char *dns_stropcode(enum dns_opcode opcode) {
8773 opcode = (unsigned)opcode % lengthof(dns_opcodes);
8774
8775 if ('\0' == dns_opcodes[opcode][0])
8776 return dns__strcode(opcode, dns_opcodes[opcode], sizeof dns_opcodes[opcode]);
8777
8778 return dns_opcodes[opcode];
8779 } /* dns_stropcode() */
8780
8781
dns_iopcode(const char * name)8782 enum dns_opcode dns_iopcode(const char *name) {
8783 unsigned opcode;
8784
8785 for (opcode = 0; opcode < lengthof(dns_opcodes); opcode++) {
8786 if (!strcasecmp(name, dns_opcodes[opcode]))
8787 return opcode;
8788 }
8789
8790 opcode = 0;
8791 while (dns_isdigit(*name)) {
8792 opcode *= 10;
8793 opcode += *name++ - '0';
8794 }
8795
8796 return DNS_PP_MIN(opcode, 0x0f);
8797 } /* dns_iopcode() */
8798
8799
8800 static char dns_rcodes[32][16] = {
8801 [DNS_RC_NOERROR] = "NOERROR",
8802 [DNS_RC_FORMERR] = "FORMERR",
8803 [DNS_RC_SERVFAIL] = "SERVFAIL",
8804 [DNS_RC_NXDOMAIN] = "NXDOMAIN",
8805 [DNS_RC_NOTIMP] = "NOTIMP",
8806 [DNS_RC_REFUSED] = "REFUSED",
8807 [DNS_RC_YXDOMAIN] = "YXDOMAIN",
8808 [DNS_RC_YXRRSET] = "YXRRSET",
8809 [DNS_RC_NXRRSET] = "NXRRSET",
8810 [DNS_RC_NOTAUTH] = "NOTAUTH",
8811 [DNS_RC_NOTZONE] = "NOTZONE",
8812 /* EDNS(0) extended RCODEs ... */
8813 [DNS_RC_BADVERS] = "BADVERS",
8814 };
8815
dns_strrcode(enum dns_rcode rcode)8816 const char *dns_strrcode(enum dns_rcode rcode) {
8817 rcode = (unsigned)rcode % lengthof(dns_rcodes);
8818
8819 if ('\0' == dns_rcodes[rcode][0])
8820 return dns__strcode(rcode, dns_rcodes[rcode], sizeof dns_rcodes[rcode]);
8821
8822 return dns_rcodes[rcode];
8823 } /* dns_strrcode() */
8824
8825
dns_ircode(const char * name)8826 enum dns_rcode dns_ircode(const char *name) {
8827 unsigned rcode;
8828
8829 for (rcode = 0; rcode < lengthof(dns_rcodes); rcode++) {
8830 if (!strcasecmp(name, dns_rcodes[rcode]))
8831 return rcode;
8832 }
8833
8834 rcode = 0;
8835 while (dns_isdigit(*name)) {
8836 rcode *= 10;
8837 rcode += *name++ - '0';
8838 }
8839
8840 return DNS_PP_MIN(rcode, 0xfff);
8841 } /* dns_ircode() */
8842
8843
8844
8845 /*
8846 * C O M M A N D - L I N E / R E G R E S S I O N R O U T I N E S
8847 *
8848 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8849 #if DNS_MAIN
8850
8851 #include <stdarg.h>
8852 #include <stdlib.h>
8853 #include <stdio.h>
8854
8855 #include <ctype.h>
8856
8857 #if _WIN32
8858 #include <getopt.h>
8859 #endif
8860
8861 #if !_WIN32
8862 #include <err.h>
8863 #endif
8864
8865
8866 struct {
8867 struct {
8868 const char *path[8];
8869 unsigned count;
8870 } resconf, nssconf, hosts, cache;
8871
8872 const char *qname;
8873 enum dns_type qtype;
8874
8875 int (*sort)();
8876
8877 int verbose;
8878 } MAIN = {
8879 .sort = &dns_rr_i_packet,
8880 };
8881
8882
hexdump(const unsigned char * src,size_t len,FILE * fp)8883 static void hexdump(const unsigned char *src, size_t len, FILE *fp) {
8884 static const unsigned char hex[] = "0123456789abcdef";
8885 static const unsigned char tmpl[] = " | |\n";
8886 unsigned char ln[sizeof tmpl];
8887 const unsigned char *sp, *se;
8888 unsigned char *h, *g;
8889 unsigned i, n;
8890
8891 sp = src;
8892 se = sp + len;
8893
8894 while (sp < se) {
8895 memcpy(ln, tmpl, sizeof ln);
8896
8897 h = &ln[2];
8898 g = &ln[53];
8899
8900 for (n = 0; n < 2; n++) {
8901 for (i = 0; i < 8 && se - sp > 0; i++, sp++) {
8902 h[0] = hex[0x0f & (*sp >> 4)];
8903 h[1] = hex[0x0f & (*sp >> 0)];
8904 h += 3;
8905
8906 *g++ = (isgraph(*sp))? *sp : '.';
8907 }
8908
8909 h++;
8910 }
8911
8912 fputs((char *)ln, fp);
8913 }
8914
8915 return /* void */;
8916 } /* hexdump() */
8917
8918
panic(const char * fmt,...)8919 DNS_NORETURN static void panic(const char *fmt, ...) {
8920 va_list ap;
8921
8922 va_start(ap, fmt);
8923
8924 #if _WIN32
8925 vfprintf(stderr, fmt, ap);
8926
8927 exit(EXIT_FAILURE);
8928 #else
8929 verrx(EXIT_FAILURE, fmt, ap);
8930 #endif
8931 } /* panic() */
8932
8933 #define panic_(fn, ln, fmt, ...) \
8934 panic(fmt "%0s", (fn), (ln), __VA_ARGS__)
8935 #define panic(...) \
8936 panic_(__func__, __LINE__, "(%s:%d) " __VA_ARGS__, "")
8937
8938
grow(unsigned char * p,size_t size)8939 static void *grow(unsigned char *p, size_t size) {
8940 void *tmp;
8941
8942 if (!(tmp = realloc(p, size)))
8943 panic("realloc(%"PRIuZ"): %s", size, dns_strerror(errno));
8944
8945 return tmp;
8946 } /* grow() */
8947
8948
add(size_t a,size_t b)8949 static size_t add(size_t a, size_t b) {
8950 if (~a < b)
8951 panic("%"PRIuZ" + %"PRIuZ": integer overflow", a, b);
8952
8953 return a + b;
8954 } /* add() */
8955
8956
append(unsigned char ** dst,size_t osize,const void * src,size_t len)8957 static size_t append(unsigned char **dst, size_t osize, const void *src, size_t len) {
8958 size_t size = add(osize, len);
8959
8960 *dst = grow(*dst, size);
8961 memcpy(*dst + osize, src, len);
8962
8963 return size;
8964 } /* append() */
8965
8966
slurp(unsigned char ** dst,size_t osize,FILE * fp,const char * path)8967 static size_t slurp(unsigned char **dst, size_t osize, FILE *fp, const char *path) {
8968 size_t size = osize;
8969 unsigned char buf[1024];
8970 size_t count;
8971
8972 while ((count = fread(buf, 1, sizeof buf, fp)))
8973 size = append(dst, size, buf, count);
8974
8975 if (ferror(fp))
8976 panic("%s: %s", path, dns_strerror(errno));
8977
8978 return size;
8979 } /* slurp() */
8980
8981
resconf(void)8982 static struct dns_resolv_conf *resconf(void) {
8983 static struct dns_resolv_conf *resconf;
8984 const char *path;
8985 unsigned i;
8986 int error;
8987
8988 if (resconf)
8989 return resconf;
8990
8991 if (!(resconf = dns_resconf_open(&error)))
8992 panic("dns_resconf_open: %s", dns_strerror(error));
8993
8994 if (!MAIN.resconf.count)
8995 MAIN.resconf.path[MAIN.resconf.count++] = "/etc/resolv.conf";
8996
8997 for (i = 0; i < MAIN.resconf.count; i++) {
8998 path = MAIN.resconf.path[i];
8999
9000 if (0 == strcmp(path, "-"))
9001 error = dns_resconf_loadfile(resconf, stdin);
9002 else
9003 error = dns_resconf_loadpath(resconf, path);
9004
9005 if (error)
9006 panic("%s: %s", path, dns_strerror(error));
9007 }
9008
9009 for (i = 0; i < MAIN.nssconf.count; i++) {
9010 path = MAIN.nssconf.path[i];
9011
9012 if (0 == strcmp(path, "-"))
9013 error = dns_nssconf_loadfile(resconf, stdin);
9014 else
9015 error = dns_nssconf_loadpath(resconf, path);
9016
9017 if (error)
9018 panic("%s: %s", path, dns_strerror(error));
9019 }
9020
9021 if (!MAIN.nssconf.count) {
9022 path = "/etc/nsswitch.conf";
9023
9024 if (!(error = dns_nssconf_loadpath(resconf, path)))
9025 MAIN.nssconf.path[MAIN.nssconf.count++] = path;
9026 else if (error != ENOENT)
9027 panic("%s: %s", path, dns_strerror(error));
9028 }
9029
9030 return resconf;
9031 } /* resconf() */
9032
9033
hosts(void)9034 static struct dns_hosts *hosts(void) {
9035 static struct dns_hosts *hosts;
9036 const char *path;
9037 unsigned i;
9038 int error;
9039
9040 if (hosts)
9041 return hosts;
9042
9043 if (!MAIN.hosts.count) {
9044 MAIN.hosts.path[MAIN.hosts.count++] = "/etc/hosts";
9045
9046 /* Explicitly test dns_hosts_local() */
9047 if (!(hosts = dns_hosts_local(&error)))
9048 panic("%s: %s", "/etc/hosts", dns_strerror(error));
9049
9050 return hosts;
9051 }
9052
9053 if (!(hosts = dns_hosts_open(&error)))
9054 panic("dns_hosts_open: %s", dns_strerror(error));
9055
9056 for (i = 0; i < MAIN.hosts.count; i++) {
9057 path = MAIN.hosts.path[i];
9058
9059 if (0 == strcmp(path, "-"))
9060 error = dns_hosts_loadfile(hosts, stdin);
9061 else
9062 error = dns_hosts_loadpath(hosts, path);
9063
9064 if (error)
9065 panic("%s: %s", path, dns_strerror(error));
9066 }
9067
9068 return hosts;
9069 } /* hosts() */
9070
9071
9072 #if DNS_CACHE
9073 #include "cache.h"
9074
cache(void)9075 static struct dns_cache *cache(void) {
9076 static struct cache *cache;
9077 const char *path;
9078 unsigned i;
9079 int error;
9080
9081 if (cache)
9082 return cache_resi(cache);
9083 if (!MAIN.cache.count)
9084 return NULL;
9085
9086 if (!(cache = cache_open(&error)))
9087 panic("%s: %s", MAIN.cache.path[0], dns_strerror(error));
9088
9089 for (i = 0; i < MAIN.cache.count; i++) {
9090 path = MAIN.cache.path[i];
9091
9092 if (!strcmp(path, "-")) {
9093 if ((error = cache_loadfile(cache, stdin, NULL, 0)))
9094 panic("%s: %s", path, dns_strerror(error));
9095 } else if ((error = cache_loadpath(cache, path, NULL, 0)))
9096 panic("%s: %s", path, dns_strerror(error));
9097 }
9098
9099 return cache_resi(cache);
9100 } /* cache() */
9101 #else
cache(void)9102 static struct dns_cache *cache(void) { return NULL; }
9103 #endif
9104
9105
print_packet(struct dns_packet * P,FILE * fp)9106 static void print_packet(struct dns_packet *P, FILE *fp) {
9107 dns_p_dump3(P, dns_rr_i_new(P, .sort = MAIN.sort), fp);
9108
9109 if (MAIN.verbose > 2)
9110 hexdump(P->data, P->end, fp);
9111 } /* print_packet() */
9112
9113
parse_packet(int argc DNS_NOTUSED,char * argv[]DNS_NOTUSED)9114 static int parse_packet(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
9115 struct dns_packet *P = dns_p_new(512);
9116 struct dns_packet *Q = dns_p_new(512);
9117 enum dns_section section;
9118 struct dns_rr rr;
9119 int error;
9120 union dns_any any;
9121 char pretty[sizeof any * 2];
9122 size_t len;
9123
9124 P->end = fread(P->data, 1, P->size, stdin);
9125
9126 fputs(";; [HEADER]\n", stdout);
9127 fprintf(stdout, ";; qr : %s(%d)\n", (dns_header(P)->qr)? "RESPONSE" : "QUERY", dns_header(P)->qr);
9128 fprintf(stdout, ";; opcode : %s(%d)\n", dns_stropcode(dns_header(P)->opcode), dns_header(P)->opcode);
9129 fprintf(stdout, ";; aa : %s(%d)\n", (dns_header(P)->aa)? "AUTHORITATIVE" : "NON-AUTHORITATIVE", dns_header(P)->aa);
9130 fprintf(stdout, ";; tc : %s(%d)\n", (dns_header(P)->tc)? "TRUNCATED" : "NOT-TRUNCATED", dns_header(P)->tc);
9131 fprintf(stdout, ";; rd : %s(%d)\n", (dns_header(P)->rd)? "RECURSION-DESIRED" : "RECURSION-NOT-DESIRED", dns_header(P)->rd);
9132 fprintf(stdout, ";; ra : %s(%d)\n", (dns_header(P)->ra)? "RECURSION-ALLOWED" : "RECURSION-NOT-ALLOWED", dns_header(P)->ra);
9133 fprintf(stdout, ";; rcode : %s(%d)\n", dns_strrcode(dns_p_rcode(P)), dns_p_rcode(P));
9134
9135 section = 0;
9136
9137 dns_rr_foreach(&rr, P, .sort = MAIN.sort) {
9138 if (section != rr.section)
9139 fprintf(stdout, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(P, rr.section));
9140
9141 if ((len = dns_rr_print(pretty, sizeof pretty, &rr, P, &error)))
9142 fprintf(stdout, "%s\n", pretty);
9143
9144 dns_rr_copy(Q, &rr, P);
9145
9146 section = rr.section;
9147 }
9148
9149 fputs("; ; ; ; ; ; ; ;\n\n", stdout);
9150
9151 section = 0;
9152
9153 #if 0
9154 dns_rr_foreach(&rr, Q, .name = "ns8.yahoo.com.") {
9155 #else
9156 struct dns_rr rrset[32];
9157 struct dns_rr_i *rri = dns_rr_i_new(Q, .name = dns_d_new("ns8.yahoo.com", DNS_D_ANCHOR), .sort = MAIN.sort);
9158 unsigned rrcount = dns_rr_grep(rrset, lengthof(rrset), rri, Q, &error);
9159
9160 for (unsigned i = 0; i < rrcount; i++) {
9161 rr = rrset[i];
9162 #endif
9163 if (section != rr.section)
9164 fprintf(stdout, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(Q, rr.section));
9165
9166 if ((len = dns_rr_print(pretty, sizeof pretty, &rr, Q, &error)))
9167 fprintf(stdout, "%s\n", pretty);
9168
9169 section = rr.section;
9170 }
9171
9172 if (MAIN.verbose > 1) {
9173 fprintf(stderr, "orig:%"PRIuZ"\n", P->end);
9174 hexdump(P->data, P->end, stdout);
9175
9176 fprintf(stderr, "copy:%"PRIuZ"\n", Q->end);
9177 hexdump(Q->data, Q->end, stdout);
9178 }
9179
9180 return 0;
9181 } /* parse_packet() */
9182
9183
9184 static int parse_domain(int argc, char *argv[]) {
9185 char *dn;
9186
9187 dn = (argc > 1)? argv[1] : "f.l.google.com";
9188
9189 printf("[%s]\n", dn);
9190
9191 dn = dns_d_new(dn);
9192
9193 do {
9194 puts(dn);
9195 } while (dns_d_cleave(dn, strlen(dn) + 1, dn, strlen(dn)));
9196
9197 return 0;
9198 } /* parse_domain() */
9199
9200
9201 static int trim_domain(int argc, char **argv) {
9202 for (argc--, argv++; argc > 0; argc--, argv++) {
9203 char name[DNS_D_MAXNAME + 1];
9204
9205 dns_d_trim(name, sizeof name, *argv, strlen(*argv), DNS_D_ANCHOR);
9206
9207 puts(name);
9208 }
9209
9210 return 0;
9211 } /* trim_domain() */
9212
9213
9214 static int expand_domain(int argc, char *argv[]) {
9215 unsigned short rp = 0;
9216 unsigned char *src = NULL;
9217 unsigned char *dst;
9218 struct dns_packet *pkt;
9219 size_t lim = 0, len;
9220 int error;
9221
9222 if (argc > 1)
9223 rp = atoi(argv[1]);
9224
9225 len = slurp(&src, 0, stdin, "-");
9226
9227 if (!(pkt = dns_p_make(len, &error)))
9228 panic("malloc(%"PRIuZ"): %s", len, dns_strerror(error));
9229
9230 memcpy(pkt->data, src, len);
9231 pkt->end = len;
9232
9233 lim = 1;
9234 dst = grow(NULL, lim);
9235
9236 while (lim <= (len = dns_d_expand(dst, lim, rp, pkt, &error))) {
9237 lim = add(len, 1);
9238 dst = grow(dst, lim);
9239 }
9240
9241 if (!len)
9242 panic("expand: %s", dns_strerror(error));
9243
9244 fwrite(dst, 1, len, stdout);
9245 fflush(stdout);
9246
9247 free(src);
9248 free(dst);
9249 free(pkt);
9250
9251 return 0;
9252 } /* expand_domain() */
9253
9254
9255 static int show_resconf(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
9256 unsigned i;
9257
9258 resconf(); /* load it */
9259
9260 fputs("; SOURCES\n", stdout);
9261
9262 for (i = 0; i < MAIN.resconf.count; i++)
9263 fprintf(stdout, "; %s\n", MAIN.resconf.path[i]);
9264
9265 for (i = 0; i < MAIN.nssconf.count; i++)
9266 fprintf(stdout, "; %s\n", MAIN.nssconf.path[i]);
9267
9268 fputs(";\n", stdout);
9269
9270 dns_resconf_dump(resconf(), stdout);
9271
9272 return 0;
9273 } /* show_resconf() */
9274
9275
9276 static int show_nssconf(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
9277 unsigned i;
9278
9279 resconf();
9280
9281 fputs("# SOURCES\n", stdout);
9282
9283 for (i = 0; i < MAIN.resconf.count; i++)
9284 fprintf(stdout, "# %s\n", MAIN.resconf.path[i]);
9285
9286 for (i = 0; i < MAIN.nssconf.count; i++)
9287 fprintf(stdout, "# %s\n", MAIN.nssconf.path[i]);
9288
9289 fputs("#\n", stdout);
9290
9291 dns_nssconf_dump(resconf(), stdout);
9292
9293 return 0;
9294 } /* show_nssconf() */
9295
9296
9297 static int show_hosts(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
9298 unsigned i;
9299
9300 hosts();
9301
9302 fputs("# SOURCES\n", stdout);
9303
9304 for (i = 0; i < MAIN.hosts.count; i++)
9305 fprintf(stdout, "# %s\n", MAIN.hosts.path[i]);
9306
9307 fputs("#\n", stdout);
9308
9309 dns_hosts_dump(hosts(), stdout);
9310
9311 return 0;
9312 } /* show_hosts() */
9313
9314
9315 static int query_hosts(int argc, char *argv[]) {
9316 struct dns_packet *Q = dns_p_new(512);
9317 struct dns_packet *A;
9318 char qname[DNS_D_MAXNAME + 1];
9319 size_t qlen;
9320 int error;
9321
9322 if (!MAIN.qname)
9323 MAIN.qname = (argc > 1)? argv[1] : "localhost";
9324 if (!MAIN.qtype)
9325 MAIN.qtype = DNS_T_A;
9326
9327 hosts();
9328
9329 if (MAIN.qtype == DNS_T_PTR && !strstr(MAIN.qname, "arpa")) {
9330 union { struct in_addr a; struct in6_addr a6; } addr;
9331 int af = (strchr(MAIN.qname, ':'))? AF_INET6 : AF_INET;
9332
9333 if ((error = dns_pton(af, MAIN.qname, &addr)))
9334 panic("%s: %s", MAIN.qname, dns_strerror(error));
9335
9336 qlen = dns_ptr_qname(qname, sizeof qname, af, &addr);
9337 } else
9338 qlen = dns_strlcpy(qname, MAIN.qname, sizeof qname);
9339
9340 if ((error = dns_p_push(Q, DNS_S_QD, qname, qlen, MAIN.qtype, DNS_C_IN, 0, 0)))
9341 panic("%s: %s", qname, dns_strerror(error));
9342
9343 if (!(A = dns_hosts_query(hosts(), Q, &error)))
9344 panic("%s: %s", qname, dns_strerror(error));
9345
9346 print_packet(A, stdout);
9347
9348 free(A);
9349
9350 return 0;
9351 } /* query_hosts() */
9352
9353
9354 static int search_list(int argc, char *argv[]) {
9355 const char *qname = (argc > 1)? argv[1] : "f.l.google.com";
9356 unsigned long i = 0;
9357 char name[DNS_D_MAXNAME + 1];
9358
9359 printf("[%s]\n", qname);
9360
9361 while (dns_resconf_search(name, sizeof name, qname, strlen(qname), resconf(), &i))
9362 puts(name);
9363
9364 return 0;
9365 } /* search_list() */
9366
9367
9368 static int permute_set(int argc, char *argv[]) {
9369 unsigned lo, hi, i;
9370 struct dns_k_permutor p;
9371
9372 hi = (--argc > 0)? atoi(argv[argc]) : 8;
9373 lo = (--argc > 0)? atoi(argv[argc]) : 0;
9374
9375 fprintf(stderr, "[%u .. %u]\n", lo, hi);
9376
9377 dns_k_permutor_init(&p, lo, hi);
9378
9379 for (i = lo; i <= hi; i++)
9380 fprintf(stdout, "%u\n", dns_k_permutor_step(&p));
9381 // printf("%u -> %u -> %u\n", i, dns_k_permutor_E(&p, i), dns_k_permutor_D(&p, dns_k_permutor_E(&p, i)));
9382
9383 return 0;
9384 } /* permute_set() */
9385
9386
9387 static int shuffle_16(int argc, char *argv[]) {
9388 unsigned n, r;
9389
9390 if (--argc > 0) {
9391 n = 0xffff & atoi(argv[argc]);
9392 r = (--argc > 0)? (unsigned)atoi(argv[argc]) : dns_random();
9393
9394 fprintf(stdout, "%hu\n", dns_k_shuffle16(n, r));
9395 } else {
9396 r = dns_random();
9397
9398 for (n = 0; n < 65536; n++)
9399 fprintf(stdout, "%hu\n", dns_k_shuffle16(n, r));
9400 }
9401
9402 return 0;
9403 } /* shuffle_16() */
9404
9405
9406 static int dump_random(int argc, char *argv[]) {
9407 unsigned char b[32];
9408 unsigned i, j, n, r;
9409
9410 n = (argc > 1)? atoi(argv[1]) : 32;
9411
9412 while (n) {
9413 i = 0;
9414
9415 do {
9416 r = dns_random();
9417
9418 for (j = 0; j < sizeof r && i < n && i < sizeof b; i++, j++) {
9419 b[i] = 0xff & r;
9420 r >>= 8;
9421 }
9422 } while (i < n && i < sizeof b);
9423
9424 hexdump(b, i, stdout);
9425
9426 n -= i;
9427 }
9428
9429 return 0;
9430 } /* dump_random() */
9431
9432
9433 static int send_query(int argc, char *argv[]) {
9434 struct dns_packet *A, *Q = dns_p_new(512);
9435 char host[INET6_ADDRSTRLEN + 1];
9436 struct sockaddr_storage ss;
9437 struct dns_socket *so;
9438 int error, type;
9439
9440 if (argc > 1) {
9441 ss.ss_family = (strchr(argv[1], ':'))? AF_INET6 : AF_INET;
9442
9443 if ((error = dns_pton(ss.ss_family, argv[1], dns_sa_addr(ss.ss_family, &ss, NULL))))
9444 panic("%s: %s", argv[1], dns_strerror(error));
9445
9446 *dns_sa_port(ss.ss_family, &ss) = htons(53);
9447 } else
9448 memcpy(&ss, &resconf()->nameserver[0], dns_sa_len(&resconf()->nameserver[0]));
9449
9450 if (!dns_inet_ntop(ss.ss_family, dns_sa_addr(ss.ss_family, &ss, NULL), host, sizeof host))
9451 panic("bad host address, or none provided");
9452
9453 if (!MAIN.qname)
9454 MAIN.qname = "ipv6.google.com";
9455 if (!MAIN.qtype)
9456 MAIN.qtype = DNS_T_AAAA;
9457
9458 if ((error = dns_p_push(Q, DNS_S_QD, MAIN.qname, strlen(MAIN.qname), MAIN.qtype, DNS_C_IN, 0, 0)))
9459 panic("dns_p_push: %s", dns_strerror(error));
9460
9461 dns_header(Q)->rd = 1;
9462
9463 if (strstr(argv[0], "udp"))
9464 type = SOCK_DGRAM;
9465 else if (strstr(argv[0], "tcp"))
9466 type = SOCK_STREAM;
9467 else
9468 type = dns_res_tcp2type(resconf()->options.tcp);
9469
9470 fprintf(stderr, "querying %s for %s IN %s\n", host, MAIN.qname, dns_strtype(MAIN.qtype));
9471
9472 if (!(so = dns_so_open((struct sockaddr *)&resconf()->iface, type, dns_opts(), &error)))
9473 panic("dns_so_open: %s", dns_strerror(error));
9474
9475 while (!(A = dns_so_query(so, Q, (struct sockaddr *)&ss, &error))) {
9476 if (error != DNS_EAGAIN)
9477 panic("dns_so_query: %s (%d)", dns_strerror(error), error);
9478 if (dns_so_elapsed(so) > 10)
9479 panic("query timed-out");
9480
9481 dns_so_poll(so, 1);
9482 }
9483
9484 print_packet(A, stdout);
9485
9486 dns_so_close(so);
9487
9488 return 0;
9489 } /* send_query() */
9490
9491
9492 static int print_arpa(int argc, char *argv[]) {
9493 const char *ip = (argc > 1)? argv[1] : "::1";
9494 int af = (strchr(ip, ':'))? AF_INET6 : AF_INET;
9495 union { struct in_addr a4; struct in6_addr a6; } addr;
9496 char host[DNS_D_MAXNAME + 1];
9497
9498 if (1 != dns_inet_pton(af, ip, &addr) || 0 == dns_ptr_qname(host, sizeof host, af, &addr))
9499 panic("%s: invalid address", ip);
9500
9501 fprintf(stdout, "%s\n", host);
9502
9503 return 0;
9504 } /* print_arpa() */
9505
9506
9507 static int show_hints(int argc, char *argv[]) {
9508 struct dns_hints *(*load)(struct dns_resolv_conf *, int *);
9509 const char *which, *how, *who;
9510 struct dns_hints *hints;
9511 int error;
9512
9513 which = (argc > 1)? argv[1] : "local";
9514 how = (argc > 2)? argv[2] : "plain";
9515 who = (argc > 3)? argv[3] : "google.com";
9516
9517 load = (0 == strcmp(which, "local"))
9518 ? &dns_hints_local
9519 : &dns_hints_root;
9520
9521 if (!(hints = load(resconf(), &error)))
9522 panic("%s: %s", argv[0], dns_strerror(error));
9523
9524 if (0 == strcmp(how, "plain")) {
9525 dns_hints_dump(hints, stdout);
9526 } else {
9527 struct dns_packet *query, *answer;
9528
9529 query = dns_p_new(512);
9530
9531 if ((error = dns_p_push(query, DNS_S_QUESTION, who, strlen(who), DNS_T_A, DNS_C_IN, 0, 0)))
9532 panic("%s: %s", who, dns_strerror(error));
9533
9534 if (!(answer = dns_hints_query(hints, query, &error)))
9535 panic("%s: %s", who, dns_strerror(error));
9536
9537 print_packet(answer, stdout);
9538
9539 free(answer);
9540 }
9541
9542 dns_hints_close(hints);
9543
9544 return 0;
9545 } /* show_hints() */
9546
9547
9548 static int resolve_query(int argc DNS_NOTUSED, char *argv[]) {
9549 _Bool recurse = !!strstr(argv[0], "recurse");
9550 struct dns_hints *(*hints)() = (recurse)? &dns_hints_root : &dns_hints_local;
9551 struct dns_resolver *R;
9552 struct dns_packet *ans;
9553 const struct dns_stat *st;
9554 int error;
9555
9556 if (!MAIN.qname)
9557 MAIN.qname = "www.google.com";
9558 if (!MAIN.qtype)
9559 MAIN.qtype = DNS_T_A;
9560
9561 resconf()->options.recurse = recurse;
9562
9563 if (!(R = dns_res_open(resconf(), hosts(), dns_hints_mortal(hints(resconf(), &error)), cache(), dns_opts(), &error)))
9564 panic("%s: %s", MAIN.qname, dns_strerror(error));
9565
9566 if ((error = dns_res_submit(R, MAIN.qname, MAIN.qtype, DNS_C_IN)))
9567 panic("%s: %s", MAIN.qname, dns_strerror(error));
9568
9569 while ((error = dns_res_check(R))) {
9570 if (error != DNS_EAGAIN)
9571 panic("dns_res_check: %s (%d)", dns_strerror(error), error);
9572 if (dns_res_elapsed(R) > 30)
9573 panic("query timed-out");
9574
9575 dns_res_poll(R, 1);
9576 }
9577
9578 ans = dns_res_fetch(R, &error);
9579 print_packet(ans, stdout);
9580 free(ans);
9581
9582 st = dns_res_stat(R);
9583 putchar('\n');
9584 printf(";; queries: %"PRIuZ"\n", st->queries);
9585 printf(";; udp sent: %"PRIuZ" in %"PRIuZ" bytes\n", st->udp.sent.count, st->udp.sent.bytes);
9586 printf(";; udp rcvd: %"PRIuZ" in %"PRIuZ" bytes\n", st->udp.rcvd.count, st->udp.rcvd.bytes);
9587 printf(";; tcp sent: %"PRIuZ" in %"PRIuZ" bytes\n", st->tcp.sent.count, st->tcp.sent.bytes);
9588 printf(";; tcp rcvd: %"PRIuZ" in %"PRIuZ" bytes\n", st->tcp.rcvd.count, st->tcp.rcvd.bytes);
9589
9590 dns_res_close(R);
9591
9592 return 0;
9593 } /* resolve_query() */
9594
9595
9596 static int resolve_addrinfo(int argc DNS_NOTUSED, char *argv[]) {
9597 _Bool recurse = !!strstr(argv[0], "recurse");
9598 struct dns_hints *(*hints)() = (recurse)? &dns_hints_root : &dns_hints_local;
9599 struct dns_resolver *res = NULL;
9600 struct dns_addrinfo *ai = NULL;
9601 struct addrinfo ai_hints = { .ai_family = PF_UNSPEC, .ai_socktype = SOCK_STREAM, .ai_flags = AI_CANONNAME };
9602 struct addrinfo *ent;
9603 char pretty[512];
9604 int error;
9605
9606 if (!MAIN.qname)
9607 MAIN.qname = "www.google.com";
9608 /* NB: MAIN.qtype of 0 means obey hints.ai_family */
9609
9610 resconf()->options.recurse = recurse;
9611
9612 if (!(res = dns_res_open(resconf(), hosts(), dns_hints_mortal(hints(resconf(), &error)), cache(), dns_opts(), &error)))
9613 panic("%s: %s", MAIN.qname, dns_strerror(error));
9614
9615 if (!(ai = dns_ai_open(MAIN.qname, "80", MAIN.qtype, &ai_hints, res, &error)))
9616 panic("%s: %s", MAIN.qname, dns_strerror(error));
9617
9618 do {
9619 switch (error = dns_ai_nextent(&ent, ai)) {
9620 case 0:
9621 dns_ai_print(pretty, sizeof pretty, ent, ai);
9622
9623 fputs(pretty, stdout);
9624
9625 free(ent);
9626
9627 break;
9628 case ENOENT:
9629 break;
9630 case DNS_EAGAIN:
9631 if (dns_ai_elapsed(ai) > 30)
9632 panic("query timed-out");
9633
9634 dns_ai_poll(ai, 1);
9635
9636 break;
9637 default:
9638 panic("dns_ai_nextent: %s (%d)", dns_strerror(error), error);
9639 }
9640 } while (error != ENOENT);
9641
9642 dns_res_close(res);
9643 dns_ai_close(ai);
9644
9645 return 0;
9646 } /* resolve_addrinfo() */
9647
9648
9649 static int echo_port(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
9650 union {
9651 struct sockaddr sa;
9652 struct sockaddr_in sin;
9653 } port;
9654 int fd;
9655
9656 memset(&port, 0, sizeof port);
9657 port.sin.sin_family = AF_INET;
9658 port.sin.sin_port = htons(5354);
9659 port.sin.sin_addr.s_addr = inet_addr("127.0.0.1");
9660
9661 if (-1 == (fd = socket(PF_INET, SOCK_DGRAM, 0)))
9662 panic("socket: %s", strerror(errno));
9663
9664 if (0 != bind(fd, &port.sa, sizeof port.sa))
9665 panic("127.0.0.1:5353: %s", dns_strerror(errno));
9666
9667 for (;;) {
9668 struct dns_packet *pkt = dns_p_new(512);
9669 struct sockaddr_storage ss;
9670 socklen_t slen = sizeof ss;
9671 ssize_t count;
9672 #if defined(MSG_WAITALL) /* MinGW issue */
9673 int rflags = MSG_WAITALL;
9674 #else
9675 int rflags = 0;
9676 #endif
9677
9678 count = recvfrom(fd, (char *)pkt->data, pkt->size, rflags, (struct sockaddr *)&ss, &slen);
9679
9680 if (!count || count < 0)
9681 panic("recvfrom: %s", strerror(errno));
9682
9683 pkt->end = count;
9684
9685 dns_p_dump(pkt, stdout);
9686
9687 (void)sendto(fd, (char *)pkt->data, pkt->end, 0, (struct sockaddr *)&ss, slen);
9688 }
9689
9690 return 0;
9691 } /* echo_port() */
9692
9693
9694 static int isection(int argc, char *argv[]) {
9695 const char *name = (argc > 1)? argv[1] : "";
9696 int type;
9697
9698 type = dns_isection(name);
9699 name = dns_strsection(type);
9700
9701 printf("%s (%d)\n", name, type);
9702
9703 return 0;
9704 } /* isection() */
9705
9706
9707 static int iclass(int argc, char *argv[]) {
9708 const char *name = (argc > 1)? argv[1] : "";
9709 int type;
9710
9711 type = dns_iclass(name);
9712 name = dns_strclass(type);
9713
9714 printf("%s (%d)\n", name, type);
9715
9716 return 0;
9717 } /* iclass() */
9718
9719
9720 static int itype(int argc, char *argv[]) {
9721 const char *name = (argc > 1)? argv[1] : "";
9722 int type;
9723
9724 type = dns_itype(name);
9725 name = dns_strtype(type);
9726
9727 printf("%s (%d)\n", name, type);
9728
9729 return 0;
9730 } /* itype() */
9731
9732
9733 static int iopcode(int argc, char *argv[]) {
9734 const char *name = (argc > 1)? argv[1] : "";
9735 int type;
9736
9737 type = dns_iopcode(name);
9738 name = dns_stropcode(type);
9739
9740 printf("%s (%d)\n", name, type);
9741
9742 return 0;
9743 } /* iopcode() */
9744
9745
9746 static int ircode(int argc, char *argv[]) {
9747 const char *name = (argc > 1)? argv[1] : "";
9748 int type;
9749
9750 type = dns_ircode(name);
9751 name = dns_strrcode(type);
9752
9753 printf("%s (%d)\n", name, type);
9754
9755 return 0;
9756 } /* ircode() */
9757
9758
9759 #define SIZE1(x) { DNS_PP_STRINGIFY(x), sizeof (x) }
9760 #define SIZE2(x, ...) SIZE1(x), SIZE1(__VA_ARGS__)
9761 #define SIZE3(x, ...) SIZE1(x), SIZE2(__VA_ARGS__)
9762 #define SIZE4(x, ...) SIZE1(x), SIZE3(__VA_ARGS__)
9763 #define SIZE(...) DNS_PP_CALL(DNS_PP_XPASTE(SIZE, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__)
9764
9765 static int sizes(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
9766 static const struct { const char *name; size_t size; } type[] = {
9767 SIZE(struct dns_header, struct dns_packet, struct dns_rr, struct dns_rr_i),
9768 SIZE(struct dns_a, struct dns_aaaa, struct dns_mx, struct dns_ns),
9769 SIZE(struct dns_cname, struct dns_soa, struct dns_ptr, struct dns_srv),
9770 SIZE(struct dns_sshfp, struct dns_txt, union dns_any),
9771 SIZE(struct dns_resolv_conf, struct dns_hosts, struct dns_hints, struct dns_hints_i),
9772 SIZE(struct dns_options, struct dns_socket, struct dns_resolver, struct dns_addrinfo),
9773 SIZE(struct dns_cache), SIZE(size_t), SIZE(void *), SIZE(long)
9774 };
9775 unsigned i, max;
9776
9777 for (i = 0, max = 0; i < lengthof(type); i++)
9778 max = DNS_PP_MAX(max, strlen(type[i].name));
9779
9780 for (i = 0; i < lengthof(type); i++)
9781 printf("%*s : %"PRIuZ"\n", max, type[i].name, type[i].size);
9782
9783 return 0;
9784 } /* sizes() */
9785
9786
9787 static const struct { const char *cmd; int (*run)(); const char *help; } cmds[] = {
9788 { "parse-packet", &parse_packet, "parse binary packet from stdin" },
9789 { "parse-domain", &parse_domain, "anchor and iteratively cleave domain" },
9790 { "trim-domain", &trim_domain, "trim and anchor domain name" },
9791 { "expand-domain", &expand_domain, "expand domain at offset NN in packet from stdin" },
9792 { "show-resconf", &show_resconf, "show resolv.conf data" },
9793 { "show-hosts", &show_hosts, "show hosts data" },
9794 { "show-nssconf", &show_nssconf, "show nsswitch.conf data" },
9795 { "query-hosts", &query_hosts, "query A, AAAA or PTR in hosts data" },
9796 { "search-list", &search_list, "generate query search list from domain" },
9797 { "permute-set", &permute_set, "generate random permutation -> (0 .. N or N .. M)" },
9798 { "shuffle-16", &shuffle_16, "simple 16-bit permutation" },
9799 { "dump-random", &dump_random, "generate random bytes" },
9800 { "send-query", &send_query, "send query to host" },
9801 { "send-query-udp", &send_query, "send udp query to host" },
9802 { "send-query-tcp", &send_query, "send tcp query to host" },
9803 { "print-arpa", &print_arpa, "print arpa. zone name of address" },
9804 { "show-hints", &show_hints, "print hints: show-hints [local|root] [plain|packet]" },
9805 { "resolve-stub", &resolve_query, "resolve as stub resolver" },
9806 { "resolve-recurse", &resolve_query, "resolve as recursive resolver" },
9807 { "addrinfo-stub", &resolve_addrinfo, "resolve through getaddrinfo clone" },
9808 { "addrinfo-recurse", &resolve_addrinfo, "resolve through getaddrinfo clone" },
9809 /* { "resolve-nameinfo", &resolve_query, "resolve as recursive resolver" }, */
9810 { "echo", &echo_port, "server echo mode, for nmap fuzzing" },
9811 { "isection", &isection, "parse section string" },
9812 { "iclass", &iclass, "parse class string" },
9813 { "itype", &itype, "parse type string" },
9814 { "iopcode", &iopcode, "parse opcode string" },
9815 { "ircode", &ircode, "parse rcode string" },
9816 { "sizes", &sizes, "print data structure sizes" },
9817 };
9818
9819
9820 static void print_usage(const char *progname, FILE *fp) {
9821 static const char *usage =
9822 " [OPTIONS] COMMAND [ARGS]\n"
9823 " -c PATH Path to resolv.conf\n"
9824 " -n PATH Path to nsswitch.conf\n"
9825 " -l PATH Path to local hosts\n"
9826 " -z PATH Path to zone cache\n"
9827 " -q QNAME Query name\n"
9828 " -t QTYPE Query type\n"
9829 " -s HOW Sort records\n"
9830 " -v Be more verbose (-vv show packets; -vvv hexdump packets)\n"
9831 " -V Print version info\n"
9832 " -h Print this usage message\n"
9833 "\n";
9834 unsigned i, n, m;
9835
9836 fputs(progname, fp);
9837 fputs(usage, fp);
9838
9839 for (i = 0, m = 0; i < lengthof(cmds); i++) {
9840 if (strlen(cmds[i].cmd) > m)
9841 m = strlen(cmds[i].cmd);
9842 }
9843
9844 for (i = 0; i < lengthof(cmds); i++) {
9845 fprintf(fp, " %s ", cmds[i].cmd);
9846
9847 for (n = strlen(cmds[i].cmd); n < m; n++)
9848 putc(' ', fp);
9849
9850 fputs(cmds[i].help, fp);
9851 putc('\n', fp);
9852 }
9853
9854 fputs("\nReport bugs to William Ahern <william@25thandClement.com>\n", fp);
9855 } /* print_usage() */
9856
9857
9858 static void print_version(const char *progname, FILE *fp) {
9859 fprintf(fp, "%s (dns.c) %.8X\n", progname, dns_v_rel());
9860 fprintf(fp, "vendor %s\n", dns_vendor());
9861 fprintf(fp, "release %.8X\n", dns_v_rel());
9862 fprintf(fp, "abi %.8X\n", dns_v_abi());
9863 fprintf(fp, "api %.8X\n", dns_v_api());
9864 } /* print_version() */
9865
9866
9867 int main(int argc, char **argv) {
9868 extern int optind;
9869 extern char *optarg;
9870 const char *progname = argv[0];
9871 unsigned i;
9872 int ch;
9873
9874 while (-1 != (ch = getopt(argc, argv, "q:t:c:n:l:z:s:vVh"))) {
9875 switch (ch) {
9876 case 'c':
9877 assert(MAIN.resconf.count < lengthof(MAIN.resconf.path));
9878
9879 MAIN.resconf.path[MAIN.resconf.count++] = optarg;
9880
9881 break;
9882 case 'n':
9883 assert(MAIN.nssconf.count < lengthof(MAIN.nssconf.path));
9884
9885 MAIN.nssconf.path[MAIN.nssconf.count++] = optarg;
9886
9887 break;
9888 case 'l':
9889 assert(MAIN.hosts.count < lengthof(MAIN.hosts.path));
9890
9891 MAIN.hosts.path[MAIN.hosts.count++] = optarg;
9892
9893 break;
9894 case 'z':
9895 assert(MAIN.cache.count < lengthof(MAIN.cache.path));
9896
9897 MAIN.cache.path[MAIN.cache.count++] = optarg;
9898
9899 break;
9900 case 'q':
9901 MAIN.qname = optarg;
9902
9903 break;
9904 case 't':
9905 for (i = 0; i < lengthof(dns_rrtypes); i++) {
9906 if (0 == strcasecmp(dns_rrtypes[i].name, optarg))
9907 { MAIN.qtype = dns_rrtypes[i].type; break; }
9908 }
9909
9910 if (MAIN.qtype)
9911 break;
9912
9913 for (i = 0; dns_isdigit(optarg[i]); i++) {
9914 MAIN.qtype *= 10;
9915 MAIN.qtype += optarg[i] - '0';
9916 }
9917
9918 if (!MAIN.qtype)
9919 panic("%s: invalid query type", optarg);
9920
9921 break;
9922 case 's':
9923 if (0 == strcasecmp(optarg, "packet"))
9924 MAIN.sort = &dns_rr_i_packet;
9925 else if (0 == strcasecmp(optarg, "shuffle"))
9926 MAIN.sort = &dns_rr_i_shuffle;
9927 else if (0 == strcasecmp(optarg, "order"))
9928 MAIN.sort = &dns_rr_i_order;
9929 else
9930 panic("%s: invalid sort method", optarg);
9931
9932 break;
9933 case 'v':
9934 dns_debug = ++MAIN.verbose;
9935
9936 break;
9937 case 'V':
9938 print_version(progname, stdout);
9939
9940 return 0;
9941 case 'h':
9942 print_usage(progname, stdout);
9943
9944 return 0;
9945 default:
9946 print_usage(progname, stderr);
9947
9948 return EXIT_FAILURE;
9949 } /* switch() */
9950 } /* while() */
9951
9952 argc -= optind;
9953 argv += optind;
9954
9955 for (i = 0; i < lengthof(cmds) && argv[0]; i++) {
9956 if (0 == strcmp(cmds[i].cmd, argv[0]))
9957 return cmds[i].run(argc, argv);
9958 }
9959
9960 print_usage(progname, stderr);
9961
9962 return EXIT_FAILURE;
9963 } /* main() */
9964
9965
9966 #endif /* DNS_MAIN */
9967
9968
9969 /*
9970 * pop file-scoped compiler annotations
9971 */
9972 #if __clang__
9973 #pragma clang diagnostic pop
9974 #elif DNS_GNUC_PREREQ(4,6,0)
9975 #pragma GCC diagnostic pop
9976 #endif
9977
9978