1 /* ==========================================================================
2 * dns.c - Recursive, Reentrant DNS Resolver.
3 * --------------------------------------------------------------------------
4 * Copyright (c) 2008, 2009, 2010, 2012-2016 William Ahern
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:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
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 * ==========================================================================
28 #elif !defined _GNU_SOURCE
32 #include <limits.h> /* INT_MAX */
33 #include <stdarg.h> /* va_list va_start va_end */
34 #include <stddef.h> /* offsetof() */
36 /* JW: This breaks our mingw build: #define uint32_t unsigned int */
38 #include <stdint.h> /* uint32_t */
40 #include <stdlib.h> /* malloc(3) realloc(3) free(3) rand(3) random(3) arc4random(3) */
41 #include <stdio.h> /* FILE fopen(3) fclose(3) getc(3) rewind(3) vsnprintf(3) */
42 #include <string.h> /* memcpy(3) strlen(3) memmove(3) memchr(3) memcmp(3) strchr(3) strsep(3) strcspn(3) */
43 #include <strings.h> /* strcasecmp(3) strncasecmp(3) */
44 #include <ctype.h> /* isspace(3) isdigit(3) */
45 #include <time.h> /* time_t time(2) difftime(3) */
46 #include <signal.h> /* SIGPIPE sigemptyset(3) sigaddset(3) sigpending(2) sigprocmask(2) pthread_sigmask(3) sigtimedwait(2) */
47 #include <errno.h> /* errno EINVAL ENOENT */
49 #include <assert.h> /* assert(3) */
53 #define FD_SETSIZE 1024
58 #include <sys/time.h> /* gettimeofday(2) */
59 #include <sys/types.h> /* FD_SETSIZE socklen_t */
60 #include <sys/select.h> /* FD_ZERO FD_SET fd_set select(2) */
61 #include <sys/socket.h> /* AF_INET AF_INET6 AF_UNIX struct sockaddr struct sockaddr_in struct sockaddr_in6 socket(2) */
63 #include <sys/un.h> /* struct sockaddr_un */
65 #include <fcntl.h> /* F_SETFD F_GETFL F_SETFL O_NONBLOCK fcntl(2) */
66 #include <unistd.h> /* _POSIX_THREADS gethostname(3) close(2) */
67 #include <poll.h> /* POLLIN POLLOUT */
68 #include <netinet/in.h> /* struct sockaddr_in struct sockaddr_in6 */
69 #include <arpa/inet.h> /* inet_pton(3) inet_ntop(3) htons(3) ntohs(3) */
70 #include <netdb.h> /* struct addrinfo */
77 * 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
79 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
81 #define DNS_GNUC_2VER(M, m, p) (((M) * 10000) + ((m) * 100) + (p))
82 #define DNS_GNUC_PREREQ(M, m, p) (__GNUC__ > 0 && DNS_GNUC_2VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) >= DNS_GNUC_2VER((M), (m), (p)))
84 #define DNS_MSC_2VER(M, m, p) ((((M) + 6) * 10000000) + ((m) * 1000000) + (p))
85 #define DNS_MSC_PREREQ(M, m, p) (_MSC_VER_FULL > 0 && _MSC_VER_FULL >= DNS_MSC_2VER((M), (m), (p)))
87 #define DNS_SUNPRO_PREREQ(M, m, p) (__SUNPRO_C > 0 && __SUNPRO_C >= 0x ## M ## m ## p)
89 #if defined __has_builtin
90 #define dns_has_builtin(x) __has_builtin(x)
92 #define dns_has_builtin(x) 0
95 #if defined __has_extension
96 #define dns_has_extension(x) __has_extension(x)
98 #define dns_has_extension(x) 0
101 #ifndef HAVE___ASSUME
102 #define HAVE___ASSUME DNS_MSC_PREREQ(8,0,0)
105 #ifndef HAVE___BUILTIN_TYPES_COMPATIBLE_P
106 #define HAVE___BUILTIN_TYPES_COMPATIBLE_P (DNS_GNUC_PREREQ(3,1,1) || __clang__)
109 #ifndef HAVE___BUILTIN_UNREACHABLE
110 #define HAVE___BUILTIN_UNREACHABLE (DNS_GNUC_PREREQ(4,5,0) || dns_has_builtin(__builtin_unreachable))
113 #ifndef HAVE_PRAGMA_MESSAGE
114 #define HAVE_PRAGMA_MESSAGE (DNS_GNUC_PREREQ(4,4,0) || __clang__ || _MSC_VER)
119 * C O M P I L E R A N N O T A T I O N S
121 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
124 #define DNS_NOTUSED __attribute__((unused))
125 #define DNS_NORETURN __attribute__((noreturn))
132 #pragma clang diagnostic push
133 #pragma clang diagnostic ignored "-Wunused-parameter"
134 #pragma clang diagnostic ignored "-Wmissing-field-initializers"
135 #elif DNS_GNUC_PREREQ(4,6,0)
136 #pragma GCC diagnostic push
137 #pragma GCC diagnostic ignored "-Wunused-parameter"
138 #pragma GCC diagnostic ignored "-Wmissing-field-initializers"
143 * S T A N D A R D M A C R O S
145 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
147 #if HAVE___BUILTIN_TYPES_COMPATIBLE_P
148 #define dns_same_type(a, b, def) __builtin_types_compatible_p(__typeof__ (a), __typeof__ (b))
150 #define dns_same_type(a, b, def) (def)
152 #define dns_isarray(a) (!dns_same_type((a), (&(a)[0]), 0))
153 /* NB: "_" field silences Sun Studio "zero-sized struct/union" error diagnostic */
154 #define dns_inline_assert(cond) ((void)(sizeof (struct { int:-!(cond); int _; })))
157 #define dns_assume(cond) __assume(cond)
158 #elif HAVE___BUILTIN_UNREACHABLE
159 #define dns_assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0)
161 #define dns_assume(cond) do { (void)(cond); } while (0)
165 #define lengthof(a) (dns_inline_assert(dns_isarray(a)), (sizeof (a) / sizeof (a)[0]))
169 #define endof(a) (dns_inline_assert(dns_isarray(a)), &(a)[lengthof((a))])
174 * M I S C E L L A N E O U S C O M P A T
176 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
184 #ifndef DNS_THREAD_SAFE
185 #if (defined _REENTRANT || defined _THREAD_SAFE) && _POSIX_THREADS > 0
186 #define DNS_THREAD_SAFE 1
188 #define DNS_THREAD_SAFE 0
192 #ifndef HAVE__STATIC_ASSERT
193 #define HAVE__STATIC_ASSERT \
194 (dns_has_extension(c_static_assert) || DNS_GNUC_PREREQ(4,6,0) || \
195 __C11FEATURES__ || __STDC_VERSION__ >= 201112L)
198 #ifndef HAVE_STATIC_ASSERT
199 #if DNS_GNUC_PREREQ(0,0,0) && !DNS_GNUC_PREREQ(4,6,0)
200 #define HAVE_STATIC_ASSERT 0 /* glibc doesn't check GCC version */
202 #define HAVE_STATIC_ASSERT (defined static_assert)
206 #if HAVE_STATIC_ASSERT
207 #define dns_static_assert(cond, msg) static_assert(cond, msg)
208 #elif HAVE__STATIC_ASSERT
209 #define dns_static_assert(cond, msg) _Static_assert(cond, msg)
211 #define dns_static_assert(cond, msg) extern char DNS_PP_XPASTE(dns_assert_, __LINE__)[sizeof (int[1 - 2*!(cond)])]
216 * D E B U G M A C R O S
218 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
220 int *dns_debug_p(void) {
224 } /* dns_debug_p() */
229 #define DNS_DEBUG dns_debug
231 #define DNS_SAY_(fmt, ...) \
232 do { if (DNS_DEBUG > 0) fprintf(stderr, fmt "%.1s", __func__, __LINE__, __VA_ARGS__); } while (0)
233 #define DNS_SAY(...) DNS_SAY_("@@ (%s:%d) " __VA_ARGS__, "\n")
234 #define DNS_HAI DNS_SAY("HAI")
236 #define DNS_SHOW_(P, fmt, ...) do { \
237 if (DNS_DEBUG > 1) { \
238 fprintf(stderr, "@@ BEGIN * * * * * * * * * * * *\n"); \
239 fprintf(stderr, "@@ " fmt "%.0s\n", __VA_ARGS__); \
240 dns_p_dump((P), stderr); \
241 fprintf(stderr, "@@ END * * * * * * * * * * * * *\n\n"); \
245 #define DNS_SHOW(...) DNS_SHOW_(__VA_ARGS__, "")
247 #else /* !DNS_DEBUG */
254 #define DNS_SHOW(...)
256 #endif /* DNS_DEBUG */
258 #define DNS_CARP(...) DNS_SAY(__VA_ARGS__)
262 * V E R S I O N R O U T I N E S
264 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
266 const char *dns_vendor(void) {
271 int dns_v_rel(void) {
276 int dns_v_abi(void) {
281 int dns_v_api(void) {
287 * E R R O R R O U T I N E S
289 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
293 #define DNS_EINTR WSAEINTR
294 #define DNS_EINPROGRESS WSAEINPROGRESS
295 #define DNS_EISCONN WSAEISCONN
296 #define DNS_EWOULDBLOCK WSAEWOULDBLOCK
297 #define DNS_EALREADY WSAEALREADY
298 #define DNS_EAGAIN EAGAIN
299 #define DNS_ETIMEDOUT WSAETIMEDOUT
301 #define dns_syerr() ((int)GetLastError())
302 #define dns_soerr() ((int)WSAGetLastError())
306 #define DNS_EINTR EINTR
307 #define DNS_EINPROGRESS EINPROGRESS
308 #define DNS_EISCONN EISCONN
309 #define DNS_EWOULDBLOCK EWOULDBLOCK
310 #define DNS_EALREADY EALREADY
311 #define DNS_EAGAIN EAGAIN
312 #define DNS_ETIMEDOUT ETIMEDOUT
314 #define dns_syerr() errno
315 #define dns_soerr() errno
320 const char *dns_strerror(int error) {
323 return "DNS packet buffer too small";
325 return "Illegal DNS RR name or data";
327 return "Attempt to push RR out of section order";
329 return "Invalid section specified";
331 return "Unknown DNS error";
333 return "Invalid textual address form";
335 return "Bad execution state (missing query packet)";
337 return "Bad execution state (missing answer packet)";
339 return "Answer already fetched";
341 return "The service passed was not recognized for the specified socket type";
343 return "The name does not resolve for the supplied parameters";
345 return "A non-recoverable error occurred when attempting to resolve the name";
347 return "Connection closed";
349 return "Reply failed verification";
351 return strerror(error);
353 } /* dns_strerror() */
357 * A T O M I C R O U T I N E S
359 * Use GCC's __atomic built-ins if possible. Unlike the __sync built-ins, we
360 * can use the preprocessor to detect API and, more importantly, ISA
361 * support. We want to avoid linking headaches where the API depends on an
362 * external library if the ISA (e.g. i386) doesn't support lockless
365 * TODO: Support C11's atomic API. Although that may require some finesse
366 * with how we define some public types, such as dns_atomic_t and struct
369 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
371 #ifndef HAVE___ATOMIC_FETCH_ADD
372 #define HAVE___ATOMIC_FETCH_ADD (defined __ATOMIC_RELAXED)
375 #ifndef HAVE___ATOMIC_FETCH_SUB
376 #define HAVE___ATOMIC_FETCH_SUB HAVE___ATOMIC_FETCH_ADD
379 #ifndef DNS_ATOMIC_FETCH_ADD
380 #if HAVE___ATOMIC_FETCH_ADD && __GCC_ATOMIC_LONG_LOCK_FREE == 2
381 #define DNS_ATOMIC_FETCH_ADD(i) __atomic_fetch_add((i), 1, __ATOMIC_RELAXED)
383 #pragma message("no atomic_fetch_add available")
384 #define DNS_ATOMIC_FETCH_ADD(i) ((*(i))++)
388 #ifndef DNS_ATOMIC_FETCH_SUB
389 #if HAVE___ATOMIC_FETCH_SUB && __GCC_ATOMIC_LONG_LOCK_FREE == 2
390 #define DNS_ATOMIC_FETCH_SUB(i) __atomic_fetch_sub((i), 1, __ATOMIC_RELAXED)
392 #pragma message("no atomic_fetch_sub available")
393 #define DNS_ATOMIC_FETCH_SUB(i) ((*(i))--)
397 static inline unsigned dns_atomic_fetch_add(dns_atomic_t *i) {
398 return DNS_ATOMIC_FETCH_ADD(i);
399 } /* dns_atomic_fetch_add() */
402 static inline unsigned dns_atomic_fetch_sub(dns_atomic_t *i) {
403 return DNS_ATOMIC_FETCH_SUB(i);
404 } /* dns_atomic_fetch_sub() */
408 * C R Y P T O R O U T I N E S
410 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
417 #if defined(HAVE_ARC4RANDOM) \
418 || defined(__OpenBSD__) \
419 || defined(__FreeBSD__) \
420 || defined(__NetBSD__) \
421 || defined(__APPLE__)
422 #define DNS_RANDOM arc4random
424 #define DNS_RANDOM random
426 #define DNS_RANDOM rand
430 #define DNS_RANDOM_arc4random 1
431 #define DNS_RANDOM_random 2
432 #define DNS_RANDOM_rand 3
433 #define DNS_RANDOM_RAND_bytes 4
435 #define DNS_RANDOM_OPENSSL (DNS_RANDOM_RAND_bytes == DNS_PP_XPASTE(DNS_RANDOM_, DNS_RANDOM))
437 #if DNS_RANDOM_OPENSSL
438 #include <openssl/rand.h>
441 static unsigned dns_random_(void) {
442 #if DNS_RANDOM_OPENSSL
446 ok = (1 == RAND_bytes((unsigned char *)&r, sizeof r));
447 assert(ok && "1 == RAND_bytes()");
453 } /* dns_random_() */
455 dns_random_f **dns_random_p(void) {
456 static dns_random_f *random_f = &dns_random_;
459 } /* dns_random_p() */
463 * P E R M U T A T I O N G E N E R A T O R
466 #define DNS_K_TEA_KEY_SIZE 16
467 #define DNS_K_TEA_BLOCK_SIZE 8
468 #define DNS_K_TEA_CYCLES 32
469 #define DNS_K_TEA_MAGIC 0x9E3779B9U
472 uint32_t key[DNS_K_TEA_KEY_SIZE / sizeof (uint32_t)];
474 }; /* struct dns_k_tea */
477 static void dns_k_tea_init(struct dns_k_tea *tea, uint32_t key[], unsigned cycles) {
478 memcpy(tea->key, key, sizeof tea->key);
480 tea->cycles = (cycles)? cycles : DNS_K_TEA_CYCLES;
481 } /* dns_k_tea_init() */
484 static void dns_k_tea_encrypt(struct dns_k_tea *tea, uint32_t v[], uint32_t *w) {
485 uint32_t y, z, sum, n;
491 for (n = 0; n < tea->cycles; n++) {
492 sum += DNS_K_TEA_MAGIC;
493 y += ((z << 4) + tea->key[0]) ^ (z + sum) ^ ((z >> 5) + tea->key[1]);
494 z += ((y << 4) + tea->key[2]) ^ (y + sum) ^ ((y >> 5) + tea->key[3]);
501 } /* dns_k_tea_encrypt() */
505 * Permutation generator, based on a Luby-Rackoff Feistel construction.
507 * Specifically, this is a generic balanced Feistel block cipher using TEA
508 * (another block cipher) as the pseudo-random function, F. At best it's as
509 * strong as F (TEA), notwithstanding the seeding. F could be AES, SHA-1, or
510 * perhaps Bernstein's Salsa20 core; I am naively trying to keep things
513 * The generator can create a permutation of any set of numbers, as long as
514 * the size of the set is an even power of 2. This limitation arises either
515 * out of an inherent property of balanced Feistel constructions, or by my
516 * own ignorance. I'll tackle an unbalanced construction after I wrap my
517 * head around Schneier and Kelsey's paper.
519 * CAVEAT EMPTOR. IANAC.
521 #define DNS_K_PERMUTOR_ROUNDS 8
523 struct dns_k_permutor {
524 unsigned stepi, length, limit;
525 unsigned shift, mask, rounds;
527 struct dns_k_tea tea;
528 }; /* struct dns_k_permutor */
531 static inline unsigned dns_k_permutor_powof(unsigned n) {
534 for (m = 1; m < n; m <<= 1, i++)
538 } /* dns_k_permutor_powof() */
540 static void dns_k_permutor_init(struct dns_k_permutor *p, unsigned low, unsigned high) {
541 uint32_t key[DNS_K_TEA_KEY_SIZE / sizeof (uint32_t)];
546 p->length = (high - low) + 1;
549 width = dns_k_permutor_powof(p->length);
552 p->shift = width / 2;
553 p->mask = (1U << p->shift) - 1;
554 p->rounds = DNS_K_PERMUTOR_ROUNDS;
556 for (i = 0; i < lengthof(key); i++)
557 key[i] = dns_random();
559 dns_k_tea_init(&p->tea, key, 0);
562 } /* dns_k_permutor_init() */
565 static unsigned dns_k_permutor_F(struct dns_k_permutor *p, unsigned k, unsigned x) {
566 uint32_t in[DNS_K_TEA_BLOCK_SIZE / sizeof (uint32_t)], out[DNS_K_TEA_BLOCK_SIZE / sizeof (uint32_t)];
568 memset(in, '\0', sizeof in);
573 dns_k_tea_encrypt(&p->tea, in, out);
575 return p->mask & out[0];
576 } /* dns_k_permutor_F() */
579 static unsigned dns_k_permutor_E(struct dns_k_permutor *p, unsigned n) {
584 l[i] = p->mask & (n >> p->shift);
585 r[i] = p->mask & (n >> 0);
588 l[(i + 1) % 2] = r[i % 2];
589 r[(i + 1) % 2] = l[i % 2] ^ dns_k_permutor_F(p, i, r[i % 2]);
592 } while (i < p->rounds - 1);
594 return ((l[i % 2] & p->mask) << p->shift) | ((r[i % 2] & p->mask) << 0);
595 } /* dns_k_permutor_E() */
598 DNS_NOTUSED static unsigned dns_k_permutor_D(struct dns_k_permutor *p, unsigned n) {
603 l[i % 2] = p->mask & (n >> p->shift);
604 r[i % 2] = p->mask & (n >> 0);
609 r[i % 2] = l[(i + 1) % 2];
610 l[i % 2] = r[(i + 1) % 2] ^ dns_k_permutor_F(p, i, l[(i + 1) % 2]);
613 return ((l[i % 2] & p->mask) << p->shift) | ((r[i % 2] & p->mask) << 0);
614 } /* dns_k_permutor_D() */
617 static unsigned dns_k_permutor_step(struct dns_k_permutor *p) {
621 n = dns_k_permutor_E(p, p->stepi++);
622 } while (n >= p->length);
624 return n + (p->limit + 1 - p->length);
625 } /* dns_k_permutor_step() */
629 * Simple permutation box. Useful for shuffling rrsets from an iterator.
630 * Uses AES s-box to provide good diffusion.
632 * Seems to pass muster under runs test.
634 * $ for i in 0 1 2 3 4 5 6 7 8 9; do ./dns shuffle-16 > /tmp/out; done
635 * $ R -q -f /dev/stdin 2>/dev/null <<-EOF | awk '/p-value/{ print $8 }'
637 * runs.test(scan(file="/tmp/out"))
640 static unsigned short dns_k_shuffle16(unsigned short n, unsigned s) {
641 static const unsigned char sbox[256] =
642 { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
643 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
644 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
645 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
646 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
647 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
648 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
649 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
650 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
651 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
652 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
653 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
654 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
655 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
656 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
657 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
658 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
659 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
660 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
661 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
662 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
663 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
664 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
665 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
666 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
667 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
668 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
669 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
670 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
671 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
672 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
673 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };
680 for (i = 0; i < 4; i++) {
687 return ((0xff00 & (a << 8)) | (0x00ff & (b << 0)));
688 } /* dns_k_shuffle16() */
691 * S T A T E M A C H I N E R O U T I N E S
693 * Application code should define DNS_SM_RESTORE and DNS_SM_SAVE, and the
696 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
698 #define DNS_SM_ENTER \
700 static const int pc0 = __LINE__; \
702 switch (pc0 + pc) { \
703 case __LINE__: (void)0
705 #define DNS_SM_SAVE_AND_DO(do_statement) \
707 pc = __LINE__ - pc0; \
710 case __LINE__: (void)0; \
713 #define DNS_SM_YIELD(rv) \
714 DNS_SM_SAVE_AND_DO(return (rv))
716 #define DNS_SM_EXIT \
717 do { goto leave; } while (0)
719 #define DNS_SM_LEAVE \
721 DNS_SM_SAVE_AND_DO(break); \
726 * U T I L I T Y R O U T I N E S
728 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
730 #define DNS_MAXINTERVAL 300
733 time_t sample, elapsed;
734 }; /* struct dns_clock */
736 static void dns_begin(struct dns_clock *clk) {
737 clk->sample = time(0);
741 static time_t dns_elapsed(struct dns_clock *clk) {
744 if ((time_t)-1 == time(&curtime))
747 if (curtime > clk->sample)
748 clk->elapsed += (time_t)DNS_PP_MIN(difftime(curtime, clk->sample), DNS_MAXINTERVAL);
750 clk->sample = curtime;
753 } /* dns_elapsed() */
756 DNS_NOTUSED static size_t dns_strnlen(const char *src, size_t m) {
759 while (*src++ && n < m)
763 } /* dns_strnlen() */
766 DNS_NOTUSED static size_t dns_strnlcpy(char *dst, size_t lim, const char *src, size_t max) {
767 size_t len = dns_strnlen(src, max), n;
770 n = DNS_PP_MIN(lim - 1, len);
776 } /* dns_strnlcpy() */
779 #define DNS_HAVE_SOCKADDR_UN (defined AF_UNIX && !defined _WIN32)
781 static size_t dns_af_len(int af) {
782 static const size_t table[AF_MAX] = {
783 [AF_INET6] = sizeof (struct sockaddr_in6),
784 [AF_INET] = sizeof (struct sockaddr_in),
785 #if DNS_HAVE_SOCKADDR_UN
786 [AF_UNIX] = sizeof (struct sockaddr_un),
793 #define dns_sa_family(sa) (((struct sockaddr *)(sa))->sa_family)
795 #define dns_sa_len(sa) dns_af_len(dns_sa_family(sa))
798 #define DNS_SA_NOPORT &dns_sa_noport
799 static unsigned short dns_sa_noport;
801 static unsigned short *dns_sa_port(int af, void *sa) {
804 return &((struct sockaddr_in6 *)sa)->sin6_port;
806 return &((struct sockaddr_in *)sa)->sin_port;
808 return DNS_SA_NOPORT;
810 } /* dns_sa_port() */
813 static void *dns_sa_addr(int af, const void *sa, socklen_t *size) {
816 struct in6_addr *in6 = &((struct sockaddr_in6 *)sa)->sin6_addr;
824 struct in_addr *in = &((struct sockaddr_in *)sa)->sin_addr;
837 } /* dns_sa_addr() */
840 #if DNS_HAVE_SOCKADDR_UN
841 #define DNS_SUNPATHMAX (sizeof ((struct sockaddr_un *)0)->sun_path)
844 DNS_NOTUSED static void *dns_sa_path(void *sa, socklen_t *size) {
845 switch (dns_sa_family(sa)) {
846 #if DNS_HAVE_SOCKADDR_UN
848 char *path = ((struct sockaddr_un *)sa)->sun_path;
851 *size = dns_strnlen(path, DNS_SUNPATHMAX);
862 } /* dns_sa_path() */
865 static int dns_sa_cmp(void *a, void *b) {
868 if ((cmp = dns_sa_family(a) - dns_sa_family(b)))
871 switch ((af = dns_sa_family(a))) {
873 struct in_addr *a4, *b4;
875 if ((cmp = htons(*dns_sa_port(af, a)) - htons(*dns_sa_port(af, b))))
878 a4 = dns_sa_addr(af, a, NULL);
879 b4 = dns_sa_addr(af, b, NULL);
881 if (ntohl(a4->s_addr) < ntohl(b4->s_addr))
883 if (ntohl(a4->s_addr) > ntohl(b4->s_addr))
889 struct in6_addr *a6, *b6;
892 if ((cmp = htons(*dns_sa_port(af, a)) - htons(*dns_sa_port(af, b))))
895 a6 = dns_sa_addr(af, a, NULL);
896 b6 = dns_sa_addr(af, b, NULL);
898 /* XXX: do we need to use in6_clearscope()? */
899 for (i = 0; i < sizeof a6->s6_addr; i++) {
900 if ((cmp = a6->s6_addr[i] - b6->s6_addr[i]))
906 #if DNS_HAVE_SOCKADDR_UN
908 char a_path[DNS_SUNPATHMAX + 1], b_path[sizeof a_path];
910 dns_strnlcpy(a_path, sizeof a_path, dns_sa_path(a, NULL), DNS_SUNPATHMAX);
911 dns_strnlcpy(b_path, sizeof b_path, dns_sa_path(b, NULL), DNS_SUNPATHMAX);
913 return strcmp(a_path, b_path);
923 static int dns_inet_pton(int af, const void *src, void *dst) {
924 union { struct sockaddr_in sin; struct sockaddr_in6 sin6; } u;
926 u.sin.sin_family = af;
928 if (0 != WSAStringToAddressA((void *)src, af, (void *)0, (struct sockaddr *)&u, &(int){ sizeof u }))
933 *(struct in6_addr *)dst = u.sin6.sin6_addr;
937 *(struct in_addr *)dst = u.sin.sin_addr;
943 } /* dns_inet_pton() */
945 static const char *dns_inet_ntop(int af, const void *src, void *dst, unsigned long lim) {
946 union { struct sockaddr_in sin; struct sockaddr_in6 sin6; } u;
948 /* NOTE: WSAAddressToString will print .sin_port unless zeroed. */
949 memset(&u, 0, sizeof u);
951 u.sin.sin_family = af;
955 u.sin6.sin6_addr = *(struct in6_addr *)src;
958 u.sin.sin_addr = *(struct in_addr *)src;
965 if (0 != WSAAddressToStringA((struct sockaddr *)&u, dns_sa_len(&u), (void *)0, dst, &lim))
969 } /* dns_inet_ntop() */
971 #define dns_inet_pton(...) inet_pton(__VA_ARGS__)
972 #define dns_inet_ntop(...) inet_ntop(__VA_ARGS__)
976 static dns_error_t dns_pton(int af, const void *src, void *dst) {
977 switch (dns_inet_pton(af, src, dst)) {
988 static dns_error_t dns_ntop(int af, const void *src, void *dst, unsigned long lim) {
989 return (dns_inet_ntop(af, src, dst, lim))? 0 : dns_soerr();
993 size_t dns_strlcpy(char *dst, const char *src, size_t lim) {
1000 if ('\0' == (*d++ = *s++))
1007 while (*s++ != '\0')
1011 } /* dns_strlcpy() */
1014 size_t dns_strlcat(char *dst, const char *src, size_t lim) {
1015 char *d = memchr(dst, '\0', lim);
1016 char *e = &dst[lim];
1017 const char *s = src;
1022 if ('\0' == (*d++ = *s++))
1031 while (*s++ != '\0')
1034 return lim + (s - p - 1);
1035 } /* dns_strlcat() */
1038 static void *dns_reallocarray(void *p, size_t nmemb, size_t size, dns_error_t *error) {
1041 if (nmemb > 0 && SIZE_MAX / nmemb < size) {
1046 if (!(rp = realloc(p, nmemb * size)))
1047 *error = (errno)? errno : EINVAL;
1050 } /* dns_reallocarray() */
1055 static char *dns_strsep(char **sp, const char *delim) {
1061 *sp += strcspn(p, delim);
1070 } /* dns_strsep() */
1073 #define dns_strsep(...) strsep(__VA_ARGS__)
1078 #define strcasecmp(...) _stricmp(__VA_ARGS__)
1079 #define strncasecmp(...) _strnicmp(__VA_ARGS__)
1083 static inline _Bool dns_isalpha(unsigned char c) {
1085 } /* dns_isalpha() */
1087 static inline _Bool dns_isdigit(unsigned char c) {
1089 } /* dns_isdigit() */
1091 static inline _Bool dns_isalnum(unsigned char c) {
1093 } /* dns_isalnum() */
1095 static inline _Bool dns_isspace(unsigned char c) {
1097 } /* dns_isspace() */
1099 static inline _Bool dns_isgraph(unsigned char c) {
1101 } /* dns_isgraph() */
1104 static int dns_poll(int fd, short events, int timeout) {
1110 if (fd < 0 || (unsigned)fd >= FD_SETSIZE)
1116 if (events & DNS_POLLIN)
1119 if (events & DNS_POLLOUT)
1122 select(fd + 1, &rset, &wset, 0, (timeout >= 0)? &(struct timeval){ timeout, 0 } : NULL);
1129 DNS_NOTUSED static int dns_sigmask(int how, const sigset_t *set, sigset_t *oset) {
1131 return pthread_sigmask(how, set, oset);
1133 return (0 == sigprocmask(how, set, oset))? 0 : errno;
1135 } /* dns_sigmask() */
1139 static size_t dns_send(int fd, const void *src, size_t len, int flags, dns_error_t *error) {
1140 long n = send(fd, src, len, flags);
1143 *error = dns_soerr();
1151 static size_t dns_recv(int fd, void *dst, size_t lim, int flags, dns_error_t *error) {
1152 long n = recv(fd, dst, lim, flags);
1155 *error = dns_soerr();
1157 } else if (n == 0) {
1158 *error = (lim > 0)? DNS_ECONNFIN : EINVAL;
1166 static size_t dns_send_nopipe(int fd, const void *src, size_t len, int flags, dns_error_t *_error) {
1167 #if _WIN32 || !defined SIGPIPE || defined SO_NOSIGPIPE
1168 return dns_send(fd, src, len, flags, _error);
1169 #elif defined MSG_NOSIGNAL
1170 return dns_send(fd, src, len, (flags|MSG_NOSIGNAL), _error);
1171 #elif _POSIX_REALTIME_SIGNALS > 0 /* require sigtimedwait */
1173 * SIGPIPE handling similar to the approach described in
1174 * http://krokisplace.blogspot.com/2010/02/suppressing-sigpipe-in-library.html
1176 sigset_t pending, blocked, piped;
1180 sigemptyset(&pending);
1181 sigpending(&pending);
1183 if (!sigismember(&pending, SIGPIPE)) {
1184 sigemptyset(&piped);
1185 sigaddset(&piped, SIGPIPE);
1186 sigemptyset(&blocked);
1188 if ((error = dns_sigmask(SIG_BLOCK, &piped, &blocked)))
1192 count = dns_send(fd, src, len, flags, &error);
1194 if (!sigismember(&pending, SIGPIPE)) {
1197 if (!count && error == EPIPE) {
1198 while (-1 == sigtimedwait(&piped, NULL, &(struct timespec){ 0, 0 }) && errno == EINTR)
1202 if ((error = dns_sigmask(SIG_SETMASK, &blocked, NULL)))
1214 #error "unable to suppress SIGPIPE"
1215 return dns_send(fd, src, len, flags, _error);
1217 } /* dns_send_nopipe() */
1220 static dns_error_t dns_connect(int fd, const struct sockaddr *addr, socklen_t addrlen) {
1221 if (0 != connect(fd, addr, addrlen))
1224 } /* dns_connect() */
1227 #define DNS_FOPEN_STDFLAGS "rwabt+"
1229 static dns_error_t dns_fopen_addflag(char *dst, const char *src, size_t lim, int fc) {
1230 char *p = dst, *pe = dst + lim;
1232 /* copy standard flags */
1233 while (*src && strchr(DNS_FOPEN_STDFLAGS, *src)) {
1239 /* append flag to standard flags */
1244 /* copy remaining mode string, including '\0' */
1248 } while ((*p++ = *src++));
1251 } /* dns_fopen_addflag() */
1253 static FILE *dns_fopen(const char *path, const char *mode, dns_error_t *_error) {
1255 char mode_cloexec[32];
1258 assert(path && mode && *mode);
1264 #if _WIN32 || _WIN64
1265 if ((error = dns_fopen_addflag(mode_cloexec, mode, sizeof mode_cloexec, 'N')))
1267 if (!(fp = fopen(path, mode_cloexec)))
1270 if ((error = dns_fopen_addflag(mode_cloexec, mode, sizeof mode_cloexec, 'e')))
1272 if (!(fp = fopen(path, mode_cloexec))) {
1273 if (errno != EINVAL)
1275 if (!(fp = fopen(path, mode)))
1282 error = dns_syerr();
1290 struct dns_hxd_lines_i {
1295 #define DNS_SM_RESTORE \
1298 sp = src + state->p; \
1301 #define DNS_SM_SAVE \
1303 state->p = sp - src; \
1307 static size_t dns_hxd_lines(void *dst, size_t lim, const unsigned char *src, size_t len, struct dns_hxd_lines_i *state) {
1308 static const unsigned char hex[] = "0123456789abcdef";
1309 static const unsigned char tmpl[] = " | |\n";
1310 unsigned char ln[sizeof tmpl];
1311 const unsigned char *sp, *se;
1312 unsigned char *h, *g;
1319 memcpy(ln, tmpl, sizeof ln);
1324 for (n = 0; n < 2; n++) {
1325 for (i = 0; i < 8 && se - sp > 0; i++, sp++) {
1326 h[0] = hex[0x0f & (*sp >> 4)];
1327 h[1] = hex[0x0f & (*sp >> 0)];
1330 *g++ = (dns_isgraph(*sp))? *sp : '.';
1336 n = dns_strlcpy(dst, (char *)ln, lim);
1347 #undef DNS_SM_RESTORE
1350 * A R I T H M E T I C R O U T I N E S
1352 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1354 #define DNS_CHECK_OVERFLOW(error, r, f, ...) \
1357 *(error) = f(&_r, __VA_ARGS__); \
1361 static dns_error_t dns_clamp_overflow(uintmax_t *r, uintmax_t n, uintmax_t clamp) {
1369 } /* dns_clamp_overflow() */
1371 static dns_error_t dns_add_overflow(uintmax_t *r, uintmax_t a, uintmax_t b, uintmax_t clamp) {
1373 *r = DNS_PP_MIN(clamp, ~UINTMAX_C(0));
1376 return dns_clamp_overflow(r, a + b, clamp);
1378 } /* dns_add_overflow() */
1380 static dns_error_t dns_mul_overflow(uintmax_t *r, uintmax_t a, uintmax_t b, uintmax_t clamp) {
1381 if (a > 0 && UINTMAX_MAX / a < b) {
1382 *r = DNS_PP_MIN(clamp, ~UINTMAX_C(0));
1385 return dns_clamp_overflow(r, a * b, clamp);
1387 } /* dns_mul_overflow() */
1390 * F I X E D - S I Z E D B U F F E R R O U T I N E S
1392 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1394 #define DNS_B_INIT(src, n) { \
1395 (unsigned char *)(src), \
1396 (unsigned char *)(src), \
1397 (unsigned char *)(src) + (n), \
1400 #define DNS_B_FROM(src, n) DNS_B_INIT((src), (n))
1401 #define DNS_B_INTO(src, n) DNS_B_INIT((src), (n))
1404 const unsigned char *base;
1406 const unsigned char *pe;
1409 }; /* struct dns_buf */
1411 static inline size_t
1412 dns_b_tell(struct dns_buf *b)
1414 return b->p - b->base;
1417 static inline dns_error_t
1418 dns_b_setoverflow(struct dns_buf *b, size_t n, dns_error_t error)
1421 return b->error = error;
1424 DNS_NOTUSED static struct dns_buf *
1425 dns_b_into(struct dns_buf *b, void *src, size_t n)
1427 *b = (struct dns_buf)DNS_B_INTO(src, n);
1433 dns_b_putc(struct dns_buf *b, unsigned char uc)
1435 if (!(b->p < b->pe))
1436 return dns_b_setoverflow(b, 1, DNS_ENOBUFS);
1444 dns_b_pputc(struct dns_buf *b, unsigned char uc, size_t p)
1446 size_t pe = b->pe - b->base;
1448 return dns_b_setoverflow(b, p - pe + 1, DNS_ENOBUFS);
1450 *((unsigned char *)b->base + p) = uc;
1455 static inline dns_error_t
1456 dns_b_put16(struct dns_buf *b, uint16_t u)
1458 return dns_b_putc(b, u >> 8), dns_b_putc(b, u >> 0);
1461 static inline dns_error_t
1462 dns_b_pput16(struct dns_buf *b, uint16_t u, size_t p)
1464 if (dns_b_pputc(b, u >> 8, p) || dns_b_pputc(b, u >> 0, p + 1))
1470 DNS_NOTUSED static inline dns_error_t
1471 dns_b_put32(struct dns_buf *b, uint32_t u)
1473 return dns_b_putc(b, u >> 24), dns_b_putc(b, u >> 16),
1474 dns_b_putc(b, u >> 8), dns_b_putc(b, u >> 0);
1478 dns_b_put(struct dns_buf *b, const void *src, size_t len)
1480 size_t n = DNS_PP_MIN((size_t)(b->pe - b->p), len);
1482 memcpy(b->p, src, n);
1486 return dns_b_setoverflow(b, len - n, DNS_ENOBUFS);
1492 dns_b_puts(struct dns_buf *b, const void *src)
1494 return dns_b_put(b, src, strlen(src));
1497 DNS_NOTUSED static inline dns_error_t
1498 dns_b_fmtju(struct dns_buf *b, const uintmax_t u, const unsigned width)
1500 size_t digits, padding, overflow;
1502 unsigned char *tp, *te, tc;
1511 padding = width - DNS_PP_MIN(digits, width);
1512 overflow = (digits + padding) - DNS_PP_MIN((size_t)(b->pe - b->p), (digits + padding));
1522 if (overflow < ++digits)
1523 dns_b_putc(b, '0' + (r % 10));
1538 dns_b_popc(struct dns_buf *b)
1540 if (b->overflow && !--b->overflow)
1546 static inline const char *
1547 dns_b_tolstring(struct dns_buf *b, size_t *n)
1551 *n = b->p - b->base;
1553 return (const char *)b->base;
1554 } else if (b->p > b->base) {
1555 if (b->p[-1] != '\0') {
1556 dns_b_setoverflow(b, 1, DNS_ENOBUFS);
1559 *n = &b->p[-1] - b->base;
1561 return (const char *)b->base;
1569 static inline const char *
1570 dns_b_tostring(struct dns_buf *b)
1573 return dns_b_tolstring(b, &n);
1576 static inline size_t
1577 dns_b_strlen(struct dns_buf *b)
1580 dns_b_tolstring(b, &n);
1584 static inline size_t
1585 dns_b_strllen(struct dns_buf *b)
1587 size_t n = dns_b_strlen(b);
1588 return n + b->overflow;
1591 DNS_NOTUSED static const struct dns_buf *
1592 dns_b_from(const struct dns_buf *b, const void *src, size_t n)
1594 *(struct dns_buf *)b = (struct dns_buf)DNS_B_FROM(src, n);
1600 dns_b_getc(const struct dns_buf *_b, const int eof)
1602 struct dns_buf *b = (struct dns_buf *)_b;
1604 if (!(b->p < b->pe))
1605 return dns_b_setoverflow(b, 1, DNS_EILLEGAL), eof;
1610 static inline intmax_t
1611 dns_b_get16(const struct dns_buf *b, const intmax_t eof)
1615 n = (dns_b_getc(b, 0) << 8);
1616 n |= (dns_b_getc(b, 0) << 0);
1618 return (!b->overflow)? n : eof;
1621 DNS_NOTUSED static inline intmax_t
1622 dns_b_get32(const struct dns_buf *b, const intmax_t eof)
1626 n = (dns_b_get16(b, 0) << 16);
1627 n |= (dns_b_get16(b, 0) << 0);
1629 return (!b->overflow)? n : eof;
1632 static inline dns_error_t
1633 dns_b_move(struct dns_buf *dst, const struct dns_buf *_src, size_t n)
1635 struct dns_buf *src = (struct dns_buf *)_src;
1636 size_t src_n = DNS_PP_MIN((size_t)(src->pe - src->p), n);
1637 size_t src_r = n - src_n;
1639 dns_b_put(dst, src->p, src_n);
1643 return dns_b_setoverflow(src, src_r, DNS_EILLEGAL);
1649 * T I M E R O U T I N E S
1651 * Most functions still rely on the older time routines defined in the
1652 * utility routines section, above.
1654 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1656 #define DNS_TIME_C(n) UINT64_C(n)
1657 #define DNS_TIME_INF (~DNS_TIME_C(0))
1659 typedef uint64_t dns_time_t;
1660 typedef dns_time_t dns_microseconds_t;
1662 static dns_error_t dns_time_add(dns_time_t *r, dns_time_t a, dns_time_t b) {
1664 DNS_CHECK_OVERFLOW(&error, r, dns_add_overflow, a, b, DNS_TIME_INF);
1668 static dns_error_t dns_time_mul(dns_time_t *r, dns_time_t a, dns_time_t b) {
1670 DNS_CHECK_OVERFLOW(&error, r, dns_mul_overflow, a, b, DNS_TIME_INF);
1674 static dns_error_t dns_time_diff(dns_time_t *r, dns_time_t a, dns_time_t b) {
1684 static dns_microseconds_t dns_ts2us(const struct timespec *ts, _Bool rup) {
1686 dns_time_t sec = DNS_PP_MAX(0, ts->tv_sec);
1687 dns_time_t nsec = DNS_PP_MAX(0, ts->tv_nsec);
1688 dns_time_t usec = nsec / 1000;
1689 dns_microseconds_t r;
1691 if (rup && nsec % 1000 > 0)
1693 dns_time_mul(&r, sec, DNS_TIME_C(1000000));
1694 dns_time_add(&r, r, usec);
1698 return DNS_TIME_INF;
1702 static struct timespec *dns_tv2ts(struct timespec *ts, const struct timeval *tv) {
1704 ts->tv_sec = tv->tv_sec;
1705 ts->tv_nsec = tv->tv_usec * 1000;
1713 static size_t dns_utime_print(void *_dst, size_t lim, dns_microseconds_t us) {
1714 struct dns_buf dst = DNS_B_INTO(_dst, lim);
1716 dns_b_fmtju(&dst, us / 1000000, 1);
1717 dns_b_putc(&dst, '.');
1718 dns_b_fmtju(&dst, us % 1000000, 6);
1720 return dns_b_strllen(&dst);
1721 } /* dns_utime_print() */
1724 * P A C K E T R O U T I N E S
1726 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1728 unsigned dns_p_count(struct dns_packet *P, enum dns_section section) {
1733 return ntohs(dns_header(P)->qdcount);
1735 return ntohs(dns_header(P)->ancount);
1737 return ntohs(dns_header(P)->nscount);
1739 return ntohs(dns_header(P)->arcount);
1743 if (section & DNS_S_QD)
1744 count += ntohs(dns_header(P)->qdcount);
1745 if (section & DNS_S_AN)
1746 count += ntohs(dns_header(P)->ancount);
1747 if (section & DNS_S_NS)
1748 count += ntohs(dns_header(P)->nscount);
1749 if (section & DNS_S_AR)
1750 count += ntohs(dns_header(P)->arcount);
1754 } /* dns_p_count() */
1757 struct dns_packet *dns_p_init(struct dns_packet *P, size_t size) {
1761 assert(size >= offsetof(struct dns_packet, data) + 12);
1763 memset(P, 0, sizeof *P);
1764 P->size = size - offsetof(struct dns_packet, data);
1767 memset(P->data, '\0', 12);
1770 } /* dns_p_init() */
1773 static struct dns_packet *dns_p_reset(struct dns_packet *P) {
1774 return dns_p_init(P, offsetof(struct dns_packet, data) + P->size);
1775 } /* dns_p_reset() */
1778 static unsigned short dns_p_qend(struct dns_packet *P) {
1779 unsigned short qend = 12;
1780 unsigned i, count = dns_p_count(P, DNS_S_QD);
1782 for (i = 0; i < count && qend < P->end; i++) {
1783 if (P->end == (qend = dns_d_skip(qend, P)))
1786 if (P->end - qend < 4)
1792 return DNS_PP_MIN(qend, P->end);
1795 } /* dns_p_qend() */
1798 struct dns_packet *dns_p_make(size_t len, int *error) {
1799 struct dns_packet *P;
1800 size_t size = dns_p_calcsize(len);
1802 if (!(P = dns_p_init(malloc(size), size)))
1803 *error = dns_syerr();
1806 } /* dns_p_make() */
1809 static void dns_p_free(struct dns_packet *P) {
1811 } /* dns_p_free() */
1814 /* convience routine to free any existing packet before storing new packet */
1815 static struct dns_packet *dns_p_setptr(struct dns_packet **dst, struct dns_packet *src) {
1821 } /* dns_p_setptr() */
1824 static struct dns_packet *dns_p_movptr(struct dns_packet **dst, struct dns_packet **src) {
1825 dns_p_setptr(dst, *src);
1830 } /* dns_p_movptr() */
1833 int dns_p_grow(struct dns_packet **P) {
1834 struct dns_packet *tmp;
1839 if (!(*P = dns_p_make(DNS_P_QBUFSIZ, &error)))
1845 size = dns_p_sizeof(*P);
1855 if (!(tmp = realloc(*P, dns_p_calcsize(size))))
1862 } /* dns_p_grow() */
1865 struct dns_packet *dns_p_copy(struct dns_packet *P, const struct dns_packet *P0) {
1869 P->end = DNS_PP_MIN(P->size, P0->end);
1871 memcpy(P->data, P0->data, P->end);
1874 } /* dns_p_copy() */
1877 struct dns_packet *dns_p_merge(struct dns_packet *A, enum dns_section Amask, struct dns_packet *B, enum dns_section Bmask, int *error_) {
1878 size_t bufsiz = DNS_PP_MIN(65535, ((A)? A->end : 0) + ((B)? B->end : 0));
1879 struct dns_packet *M;
1880 enum dns_section section;
1881 struct dns_rr rr, mr;
1891 if (!(M = dns_p_make(bufsiz, &error)))
1894 for (section = DNS_S_QD; (DNS_S_ALL & section); section <<= 1) {
1895 if (A && (section & Amask)) {
1896 dns_rr_foreach(&rr, A, .section = section) {
1897 if ((error = dns_rr_copy(M, &rr, A)))
1902 if (B && (section & Bmask)) {
1903 dns_rr_foreach(&rr, B, .section = section) {
1906 dns_rr_foreach(&mr, M, .type = rr.type, .section = DNS_S_ALL) {
1907 if (!(copy = dns_rr_cmp(&rr, B, &mr, M)))
1911 if (copy && (error = dns_rr_copy(M, &rr, B)))
1919 dns_p_setptr(&M, NULL);
1921 if (error == DNS_ENOBUFS && bufsiz < 65535) {
1922 bufsiz = DNS_PP_MIN(65535, bufsiz * 2);
1930 } /* dns_p_merge() */
1933 static unsigned short dns_l_skip(unsigned short, const unsigned char *, size_t);
1935 void dns_p_dictadd(struct dns_packet *P, unsigned short dn) {
1936 unsigned short lp, lptr, i;
1940 while (lp < P->end) {
1941 if (0xc0 == (0xc0 & P->data[lp]) && P->end - lp >= 2 && lp != dn) {
1942 lptr = ((0x3f & P->data[lp + 0]) << 8)
1943 | ((0xff & P->data[lp + 1]) << 0);
1945 for (i = 0; i < lengthof(P->dict) && P->dict[i]; i++) {
1946 if (P->dict[i] == lptr) {
1954 lp = dns_l_skip(lp, P->data, P->end);
1957 for (i = 0; i < lengthof(P->dict); i++) {
1964 } /* dns_p_dictadd() */
1967 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) {
1968 size_t end = P->end;
1971 if ((error = dns_d_push(P, dn, dnlen)))
1974 if (P->size - P->end < 4)
1977 P->data[P->end++] = 0xff & (type >> 8);
1978 P->data[P->end++] = 0xff & (type >> 0);
1980 P->data[P->end++] = 0xff & (class >> 8);
1981 P->data[P->end++] = 0xff & (class >> 0);
1983 if (section == DNS_S_QD)
1986 if (P->size - P->end < 6)
1989 if (type != DNS_T_OPT)
1990 ttl = DNS_PP_MIN(ttl, 0x7fffffffU);
1991 P->data[P->end++] = ttl >> 24;
1992 P->data[P->end++] = ttl >> 16;
1993 P->data[P->end++] = ttl >> 8;
1994 P->data[P->end++] = ttl >> 0;
1996 if ((error = dns_any_push(P, (union dns_any *)any, type)))
2002 if (dns_p_count(P, DNS_S_AN|DNS_S_NS|DNS_S_AR))
2005 if (!P->memo.qd.base && (error = dns_p_study(P)))
2008 dns_header(P)->qdcount = htons(ntohs(dns_header(P)->qdcount) + 1);
2010 P->memo.qd.end = P->end;
2011 P->memo.an.base = P->end;
2012 P->memo.an.end = P->end;
2013 P->memo.ns.base = P->end;
2014 P->memo.ns.end = P->end;
2015 P->memo.ar.base = P->end;
2016 P->memo.ar.end = P->end;
2020 if (dns_p_count(P, DNS_S_NS|DNS_S_AR))
2023 if (!P->memo.an.base && (error = dns_p_study(P)))
2026 dns_header(P)->ancount = htons(ntohs(dns_header(P)->ancount) + 1);
2028 P->memo.an.end = P->end;
2029 P->memo.ns.base = P->end;
2030 P->memo.ns.end = P->end;
2031 P->memo.ar.base = P->end;
2032 P->memo.ar.end = P->end;
2036 if (dns_p_count(P, DNS_S_AR))
2039 if (!P->memo.ns.base && (error = dns_p_study(P)))
2042 dns_header(P)->nscount = htons(ntohs(dns_header(P)->nscount) + 1);
2044 P->memo.ns.end = P->end;
2045 P->memo.ar.base = P->end;
2046 P->memo.ar.end = P->end;
2050 if (!P->memo.ar.base && (error = dns_p_study(P)))
2053 dns_header(P)->arcount = htons(ntohs(dns_header(P)->arcount) + 1);
2055 P->memo.ar.end = P->end;
2057 if (type == DNS_T_OPT && !P->memo.opt.p) {
2058 P->memo.opt.p = end;
2059 P->memo.opt.maxudp = class;
2060 P->memo.opt.ttl = ttl;
2065 error = DNS_ESECTION;
2072 error = DNS_ENOBUFS;
2083 } /* dns_p_push() */
2085 #define DNS_SM_RESTORE do { pc = state->pc; error = state->error; } while (0)
2086 #define DNS_SM_SAVE do { state->error = error; state->pc = pc; } while (0)
2088 struct dns_p_lines_i {
2090 enum dns_section section;
2095 static size_t dns_p_lines_fmt(void *dst, size_t lim, dns_error_t *_error, const char *fmt, ...) {
2100 if ((n = vsnprintf(dst, lim, fmt, ap)) < 0)
2105 return DNS_PP_MAX(n, 0);
2106 } /* dns_p_lines_fmt() */
2108 #define DNS_P_LINE(...) \
2110 len = dns_p_lines_fmt(dst, lim, &error, __VA_ARGS__); \
2111 if (len == 0 && error) \
2113 DNS_SM_YIELD(len); \
2116 static size_t dns_p_lines(void *dst, size_t lim, dns_error_t *_error, struct dns_packet *P, struct dns_rr_i *I, struct dns_p_lines_i *state) {
2124 DNS_P_LINE(";; [HEADER]\n");
2125 DNS_P_LINE(";; qid : %d\n", ntohs(dns_header(P)->qid));
2126 DNS_P_LINE(";; qr : %s(%d)\n", (dns_header(P)->qr)? "RESPONSE" : "QUERY", dns_header(P)->qr);
2127 DNS_P_LINE(";; opcode : %s(%d)\n", dns_stropcode(dns_header(P)->opcode), dns_header(P)->opcode);
2128 DNS_P_LINE(";; aa : %s(%d)\n", (dns_header(P)->aa)? "AUTHORITATIVE" : "NON-AUTHORITATIVE", dns_header(P)->aa);
2129 DNS_P_LINE(";; tc : %s(%d)\n", (dns_header(P)->tc)? "TRUNCATED" : "NOT-TRUNCATED", dns_header(P)->tc);
2130 DNS_P_LINE(";; rd : %s(%d)\n", (dns_header(P)->rd)? "RECURSION-DESIRED" : "RECURSION-NOT-DESIRED", dns_header(P)->rd);
2131 DNS_P_LINE(";; ra : %s(%d)\n", (dns_header(P)->ra)? "RECURSION-ALLOWED" : "RECURSION-NOT-ALLOWED", dns_header(P)->ra);
2132 DNS_P_LINE(";; rcode : %s(%d)\n", dns_strrcode(dns_p_rcode(P)), dns_p_rcode(P));
2134 while (dns_rr_grep(&state->rr, 1, I, P, &error)) {
2135 if (state->section != state->rr.section) {
2137 DNS_P_LINE(";; [%s:%d]\n", dns_strsection(state->rr.section), dns_p_count(P, state->rr.section));
2140 if (!(len = dns_rr_print(dst, lim, &state->rr, P, &error)))
2142 dns_strlcat(dst, "\n", lim);
2143 DNS_SM_YIELD(len + 1);
2145 state->section = state->rr.section;
2162 } /* dns_p_lines() */
2166 #undef DNS_SM_RESTORE
2168 static void dns_p_dump3(struct dns_packet *P, struct dns_rr_i *I, FILE *fp) {
2169 struct dns_p_lines_i lines = { 0 };
2170 char line[sizeof (union dns_any) * 2];
2174 while ((len = dns_p_lines(line, sizeof line, &error, P, I, &lines))) {
2175 if (len < sizeof line) {
2176 fwrite(line, 1, len, fp);
2178 fwrite(line, 1, sizeof line - 1, fp);
2182 } /* dns_p_dump3() */
2185 void dns_p_dump(struct dns_packet *P, FILE *fp) {
2186 dns_p_dump3(P, dns_rr_i_new(P, .section = 0), fp);
2187 } /* dns_p_dump() */
2190 static void dns_s_unstudy(struct dns_s_memo *m)
2191 { m->base = 0; m->end = 0; }
2193 static void dns_m_unstudy(struct dns_p_memo *m) {
2194 dns_s_unstudy(&m->qd);
2195 dns_s_unstudy(&m->an);
2196 dns_s_unstudy(&m->ns);
2197 dns_s_unstudy(&m->ar);
2201 } /* dns_m_unstudy() */
2203 static int dns_s_study(struct dns_s_memo *m, enum dns_section section, unsigned short base, struct dns_packet *P) {
2204 unsigned short count, rp;
2206 count = dns_p_count(P, section);
2208 for (rp = base; count && rp < P->end; count--)
2209 rp = dns_rr_skip(rp, P);
2215 } /* dns_s_study() */
2217 static int dns_m_study(struct dns_p_memo *m, struct dns_packet *P) {
2221 if ((error = dns_s_study(&m->qd, DNS_S_QD, 12, P)))
2223 if ((error = dns_s_study(&m->an, DNS_S_AN, m->qd.end, P)))
2225 if ((error = dns_s_study(&m->ns, DNS_S_NS, m->an.end, P)))
2227 if ((error = dns_s_study(&m->ar, DNS_S_AR, m->ns.end, P)))
2233 dns_rr_foreach(&rr, P, .type = DNS_T_OPT, .section = DNS_S_AR) {
2235 m->opt.maxudp = rr.class;
2236 m->opt.ttl = rr.ttl;
2245 } /* dns_m_study() */
2247 int dns_p_study(struct dns_packet *P) {
2248 return dns_m_study(&P->memo, P);
2249 } /* dns_p_study() */
2252 enum dns_rcode dns_p_rcode(struct dns_packet *P) {
2253 return 0xfff & ((P->memo.opt.ttl >> 20) | dns_header(P)->rcode);
2254 } /* dns_p_rcode() */
2258 * Q U E R Y P A C K E T R O U T I N E S
2260 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2262 #define DNS_Q_RD 0x1 /* recursion desired */
2263 #define DNS_Q_EDNS0 0x2 /* include OPT RR */
2266 dns_q_make2(struct dns_packet **_Q, const char *qname, size_t qlen, enum dns_type qtype, enum dns_class qclass, int qflags)
2268 struct dns_packet *Q = NULL;
2271 if (dns_p_movptr(&Q, _Q)) {
2273 } else if (!(Q = dns_p_make(DNS_P_QBUFSIZ, &error))) {
2277 if ((error = dns_p_push(Q, DNS_S_QD, qname, qlen, qtype, qclass, 0, 0)))
2280 dns_header(Q)->rd = !!(qflags & DNS_Q_RD);
2282 if (qflags & DNS_Q_EDNS0) {
2283 struct dns_opt opt = DNS_OPT_INIT(&opt);
2285 opt.version = 0; /* RFC 6891 version */
2288 if ((error = dns_p_push(Q, DNS_S_AR, ".", 1, DNS_T_OPT, dns_opt_class(&opt), dns_opt_ttl(&opt), &opt)))
2302 dns_q_make(struct dns_packet **Q, const char *qname, enum dns_type qtype, enum dns_class qclass, int qflags)
2304 return dns_q_make2(Q, qname, strlen(qname), qtype, qclass, qflags);
2308 dns_q_remake(struct dns_packet **Q, int qflags)
2310 char qname[DNS_D_MAXNAME + 1];
2316 if ((error = dns_rr_parse(&rr, 12, *Q)))
2318 if (!(qlen = dns_d_expand(qname, sizeof qname, rr.dn.p, *Q, &error)))
2320 if (qlen >= sizeof qname)
2321 return DNS_EILLEGAL;
2322 return dns_q_make2(Q, qname, qlen, rr.type, rr.class, qflags);
2326 * D O M A I N N A M E R O U T I N E S
2328 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2330 #ifndef DNS_D_MAXPTRS
2331 #define DNS_D_MAXPTRS 127 /* Arbitrary; possible, valid depth is something like packet size / 2 + fudge. */
2334 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) {
2342 switch (0x03 & (data[src] >> 6)) {
2344 len = (0x3f & (data[src++]));
2346 if (end - src < len)
2350 memcpy(dst, &data[src], DNS_PP_MIN(lim, len));
2352 dst[DNS_PP_MIN(lim - 1, len)] = '\0';
2363 if (++nptrs > DNS_D_MAXPTRS)
2369 src = ((0x3f & data[src + 0]) << 8)
2370 | ((0xff & data[src + 1]) << 0);
2380 } /* dns_l_expand() */
2383 static unsigned short dns_l_skip(unsigned short src, const unsigned char *data, size_t end) {
2389 switch (0x03 & (data[src] >> 6)) {
2391 len = (0x3f & (data[src++]));
2393 if (end - src < len)
2396 return (len)? src + len : end;
2408 } /* dns_l_skip() */
2411 static _Bool dns_d_isanchored(const void *_src, size_t len) {
2412 const unsigned char *src = _src;
2413 return len > 0 && src[len - 1] == '.';
2414 } /* dns_d_isanchored() */
2417 static size_t dns_d_ndots(const void *_src, size_t len) {
2418 const unsigned char *p = _src, *pe = p + len;
2421 while ((p = memchr(p, '.', pe - p))) {
2427 } /* dns_d_ndots() */
2430 static size_t dns_d_trim(void *dst_, size_t lim, const void *src_, size_t len, int flags) {
2431 unsigned char *dst = dst_;
2432 const unsigned char *src = src_;
2433 size_t dp = 0, sp = 0;
2436 /* trim any leading dot(s) */
2437 while (sp < len && src[sp] == '.')
2440 for (lc = 0; sp < len; lc = src[sp++]) {
2441 /* trim extra dot(s) */
2442 if (src[sp] == '.' && lc == '.')
2451 if ((flags & DNS_D_ANCHOR) && lc != '.') {
2459 dst[DNS_PP_MIN(dp, lim - 1)] = '\0';
2462 } /* dns_d_trim() */
2465 char *dns_d_init(void *dst, size_t lim, const void *src, size_t len, int flags) {
2466 if (flags & DNS_D_TRIM) {
2467 dns_d_trim(dst, lim, src, len, flags);
2468 } if (flags & DNS_D_ANCHOR) {
2469 dns_d_anchor(dst, lim, src, len);
2471 memmove(dst, src, DNS_PP_MIN(lim, len));
2474 ((char *)dst)[DNS_PP_MIN(len, lim - 1)] = '\0';
2478 } /* dns_d_init() */
2481 size_t dns_d_anchor(void *dst, size_t lim, const void *src, size_t len) {
2485 memmove(dst, src, DNS_PP_MIN(lim, len));
2487 if (((const char *)src)[len - 1] != '.') {
2489 ((char *)dst)[len] = '.';
2494 ((char *)dst)[DNS_PP_MIN(lim - 1, len)] = '\0';
2497 } /* dns_d_anchor() */
2500 size_t dns_d_cleave(void *dst, size_t lim, const void *src, size_t len) {
2503 /* XXX: Skip any leading dot. Handles cleaving root ".". */
2504 if (len == 0 || !(dot = memchr((const char *)src + 1, '.', len - 1)))
2507 len -= dot - (const char *)src;
2509 /* XXX: Unless root, skip the label's trailing dot. */
2516 memmove(dst, src, DNS_PP_MIN(lim, len));
2519 ((char *)dst)[DNS_PP_MIN(lim - 1, len)] = '\0';
2522 } /* dns_d_cleave() */
2525 size_t dns_d_comp(void *dst_, size_t lim, const void *src_, size_t len, struct dns_packet *P, int *error) {
2526 struct { unsigned char *b; size_t p, x; } dst, src;
2527 unsigned char ch = '.';
2533 src.b = (unsigned char *)src_;
2537 while (src.x < len) {
2542 dst.b[dst.p] = (0x3f & (src.x - src.p));
2555 if (src.x > src.p) {
2557 dst.b[dst.p] = (0x3f & (src.x - src.p));
2564 dst.b[dst.p] = 0x00;
2571 struct { unsigned char label[DNS_D_MAXLABEL + 1]; size_t len; unsigned short p, x, y; } a, b;
2576 while ((a.len = dns_l_expand(a.label, sizeof a.label, a.p, &a.x, dst.b, lim))) {
2577 for (i = 0; i < lengthof(P->dict) && P->dict[i]; i++) {
2580 while ((b.len = dns_l_expand(b.label, sizeof b.label, b.p, &b.x, P->data, P->end))) {
2584 while (a.len && b.len && 0 == strcasecmp((char *)a.label, (char *)b.label)) {
2585 a.len = dns_l_expand(a.label, sizeof a.label, a.y, &a.y, dst.b, lim);
2586 b.len = dns_l_expand(b.label, sizeof b.label, b.y, &b.y, P->data, P->end);
2589 if (a.len == 0 && b.len == 0 && b.p <= 0x3fff) {
2591 | (0x3f & (b.p >> 8));
2592 dst.b[a.p++] = (0xff & (b.p >> 0));
2594 /* silence static analyzers */
2595 dns_assume(a.p > 0);
2610 *error = DNS_EILLEGAL;
2613 } /* dns_d_comp() */
2616 unsigned short dns_d_skip(unsigned short src, struct dns_packet *P) {
2619 while (src < P->end) {
2620 switch (0x03 & (P->data[src] >> 6)) {
2621 case 0x00: /* FOLLOWS */
2622 len = (0x3f & P->data[src++]);
2625 /* success ==> */ return src;
2626 } else if (P->end - src > len) {
2634 case 0x01: /* RESERVED */
2636 case 0x02: /* RESERVED */
2638 case 0x03: /* POINTER */
2639 if (P->end - src < 2)
2644 /* success ==> */ return src;
2650 } /* dns_d_skip() */
2655 size_t dns_d_expand(void *dst, size_t lim, unsigned short src, struct dns_packet *P, int *error) {
2660 while (src < P->end) {
2661 switch ((0x03 & (P->data[src] >> 6))) {
2662 case 0x00: /* FOLLOWS */
2663 len = (0x3f & P->data[src]);
2668 ((unsigned char *)dst)[dstp] = '.';
2675 ((unsigned char *)dst)[DNS_PP_MIN(dstp, lim - 1)] = '\0';
2677 /* success ==> */ return dstp;
2682 if (P->end - src < len)
2686 memcpy(&((unsigned char *)dst)[dstp], &P->data[src], DNS_PP_MIN(len, lim - dstp));
2692 ((unsigned char *)dst)[dstp] = '.';
2699 case 0x01: /* RESERVED */
2701 case 0x02: /* RESERVED */
2703 case 0x03: /* POINTER */
2704 if (++nptrs > DNS_D_MAXPTRS)
2707 if (P->end - src < 2)
2710 src = ((0x3f & P->data[src + 0]) << 8)
2711 | ((0xff & P->data[src + 1]) << 0);
2718 *error = DNS_EILLEGAL;
2721 ((unsigned char *)dst)[DNS_PP_MIN(dstp, lim - 1)] = '\0';
2725 *error = DNS_EILLEGAL;
2728 ((unsigned char *)dst)[DNS_PP_MIN(dstp, lim - 1)] = '\0';
2731 } /* dns_d_expand() */
2734 int dns_d_push(struct dns_packet *P, const void *dn, size_t len) {
2735 size_t lim = P->size - P->end;
2736 unsigned dp = P->end;
2737 int error = DNS_EILLEGAL; /* silence compiler */
2739 len = dns_d_comp(&P->data[dp], lim, dn, len, P, &error);
2748 dns_p_dictadd(P, dp);
2751 } /* dns_d_push() */
2754 size_t dns_d_cname(void *dst, size_t lim, const void *dn, size_t len, struct dns_packet *P, int *error_) {
2755 char host[DNS_D_MAXNAME + 1];
2761 if (sizeof host <= dns_d_anchor(host, sizeof host, dn, len))
2762 { error = ENAMETOOLONG; goto error; }
2764 for (depth = 0; depth < 7; depth++) {
2765 dns_rr_i_init(memset(&i, 0, sizeof i), P);
2767 i.section = DNS_S_ALL & ~DNS_S_QD;
2769 i.type = DNS_T_CNAME;
2771 if (!dns_rr_grep(&rr, 1, &i, P, &error))
2774 if ((error = dns_cname_parse((struct dns_cname *)host, &rr, P)))
2778 return dns_strlcpy(dst, host, lim);
2783 } /* dns_d_cname() */
2787 * R E S O U R C E R E C O R D R O U T I N E S
2789 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2791 int dns_rr_copy(struct dns_packet *P, struct dns_rr *rr, struct dns_packet *Q) {
2792 unsigned char dn[DNS_D_MAXNAME + 1];
2797 if (!(len = dns_d_expand(dn, sizeof dn, rr->dn.p, Q, &error)))
2799 else if (len >= sizeof dn)
2800 return DNS_EILLEGAL;
2802 if (rr->section != DNS_S_QD && (error = dns_any_parse(dns_any_init(&any, sizeof any), rr, Q)))
2805 return dns_p_push(P, rr->section, dn, len, rr->type, rr->class, rr->ttl, &any);
2806 } /* dns_rr_copy() */
2809 int dns_rr_parse(struct dns_rr *rr, unsigned short src, struct dns_packet *P) {
2810 unsigned short p = src;
2816 rr->dn.len = (p = dns_d_skip(p, P)) - rr->dn.p;
2821 rr->type = ((0xff & P->data[p + 0]) << 8)
2822 | ((0xff & P->data[p + 1]) << 0);
2824 rr->class = ((0xff & P->data[p + 2]) << 8)
2825 | ((0xff & P->data[p + 3]) << 0);
2829 if (src < dns_p_qend(P)) {
2830 rr->section = DNS_S_QUESTION;
2842 rr->ttl = ((0xff & P->data[p + 0]) << 24)
2843 | ((0xff & P->data[p + 1]) << 16)
2844 | ((0xff & P->data[p + 2]) << 8)
2845 | ((0xff & P->data[p + 3]) << 0);
2846 if (rr->type != DNS_T_OPT)
2847 rr->ttl = DNS_PP_MIN(rr->ttl, 0x7fffffffU);
2854 rr->rd.len = ((0xff & P->data[p + 0]) << 8)
2855 | ((0xff & P->data[p + 1]) << 0);
2860 if (P->end - p < rr->rd.len)
2865 return DNS_EILLEGAL;
2866 } /* dns_rr_parse() */
2869 static unsigned short dns_rr_len(const unsigned short src, struct dns_packet *P) {
2870 unsigned short rp, rdlen;
2872 rp = dns_d_skip(src, P);
2874 if (P->end - rp < 4)
2875 return P->end - src;
2877 rp += 4; /* TYPE, CLASS */
2879 if (rp <= dns_p_qend(P))
2882 if (P->end - rp < 6)
2883 return P->end - src;
2885 rp += 6; /* TTL, RDLEN */
2887 rdlen = ((0xff & P->data[rp - 2]) << 8)
2888 | ((0xff & P->data[rp - 1]) << 0);
2890 if (P->end - rp < rdlen)
2891 return P->end - src;
2896 } /* dns_rr_len() */
2899 unsigned short dns_rr_skip(unsigned short src, struct dns_packet *P) {
2900 return src + dns_rr_len(src, P);
2901 } /* dns_rr_skip() */
2904 static enum dns_section dns_rr_section(unsigned short src, struct dns_packet *P) {
2905 enum dns_section section;
2906 unsigned count, index;
2909 if (src >= P->memo.qd.base && src < P->memo.qd.end)
2911 if (src >= P->memo.an.base && src < P->memo.an.end)
2913 if (src >= P->memo.ns.base && src < P->memo.ns.end)
2915 if (src >= P->memo.ar.base && src < P->memo.ar.end)
2918 /* NOTE: Possibly bad memoization. Try it the hard-way. */
2920 for (rp = 12, index = 0; rp < src && rp < P->end; index++)
2921 rp = dns_rr_skip(rp, P);
2924 count = dns_p_count(P, section);
2926 while (index >= count && section <= DNS_S_AR) {
2928 count += dns_p_count(P, section);
2931 return DNS_S_ALL & section;
2932 } /* dns_rr_section() */
2935 static enum dns_type dns_rr_type(unsigned short src, struct dns_packet *P) {
2939 if ((error = dns_rr_parse(&rr, src, P)))
2943 } /* dns_rr_type() */
2946 int dns_rr_cmp(struct dns_rr *r0, struct dns_packet *P0, struct dns_rr *r1, struct dns_packet *P1) {
2947 char host0[DNS_D_MAXNAME + 1], host1[DNS_D_MAXNAME + 1];
2948 union dns_any any0, any1;
2952 if ((cmp = r0->type - r1->type))
2955 if ((cmp = r0->class - r1->class))
2959 * FIXME: Do label-by-label comparison to handle illegally long names?
2962 if (!(len = dns_d_expand(host0, sizeof host0, r0->dn.p, P0, &error))
2963 || len >= sizeof host0)
2966 if (!(len = dns_d_expand(host1, sizeof host1, r1->dn.p, P1, &error))
2967 || len >= sizeof host1)
2970 if ((cmp = strcasecmp(host0, host1)))
2973 if (DNS_S_QD & (r0->section | r1->section)) {
2974 if (r0->section == r1->section)
2977 return (r0->section == DNS_S_QD)? -1 : 1;
2980 if ((error = dns_any_parse(&any0, r0, P0)))
2983 if ((error = dns_any_parse(&any1, r1, P1)))
2986 return dns_any_cmp(&any0, r0->type, &any1, r1->type);
2987 } /* dns_rr_cmp() */
2990 static _Bool dns_rr_exists(struct dns_rr *rr0, struct dns_packet *P0, struct dns_packet *P1) {
2993 dns_rr_foreach(&rr1, P1, .section = rr0->section, .type = rr0->type) {
2994 if (0 == dns_rr_cmp(rr0, P0, &rr1, P1))
2999 } /* dns_rr_exists() */
3002 static unsigned short dns_rr_offset(struct dns_rr *rr) {
3004 } /* dns_rr_offset() */
3007 static _Bool dns_rr_i_match(struct dns_rr *rr, struct dns_rr_i *i, struct dns_packet *P) {
3008 if (i->section && !(rr->section & i->section))
3011 if (i->type && rr->type != i->type && i->type != DNS_T_ALL)
3014 if (i->class && rr->class != i->class && i->class != DNS_C_ANY)
3018 char dn[DNS_D_MAXNAME + 1];
3022 if (!(len = dns_d_expand(dn, sizeof dn, rr->dn.p, P, &error))
3023 || len >= sizeof dn)
3026 if (0 != strcasecmp(dn, i->name))
3030 if (i->data && i->type && rr->section > DNS_S_QD) {
3034 if ((error = dns_any_parse(&rd, rr, P)))
3037 if (0 != dns_any_cmp(&rd, rr->type, i->data, i->type))
3042 } /* dns_rr_i_match() */
3045 static unsigned short dns_rr_i_start(struct dns_rr_i *i, struct dns_packet *P) {
3047 struct dns_rr r0, rr;
3050 if ((i->section & DNS_S_QD) && P->memo.qd.base)
3051 rp = P->memo.qd.base;
3052 else if ((i->section & DNS_S_AN) && P->memo.an.base)
3053 rp = P->memo.an.base;
3054 else if ((i->section & DNS_S_NS) && P->memo.ns.base)
3055 rp = P->memo.ns.base;
3056 else if ((i->section & DNS_S_AR) && P->memo.ar.base)
3057 rp = P->memo.ar.base;
3061 for (; rp < P->end; rp = dns_rr_skip(rp, P)) {
3062 if ((error = dns_rr_parse(&rr, rp, P)))
3065 rr.section = dns_rr_section(rp, P);
3067 if (!dns_rr_i_match(&rr, i, P))
3077 if (i->sort == &dns_rr_i_packet)
3078 return dns_rr_offset(&r0);
3080 while ((rp = dns_rr_skip(rp, P)) < P->end) {
3081 if ((error = dns_rr_parse(&rr, rp, P)))
3084 rr.section = dns_rr_section(rp, P);
3086 if (!dns_rr_i_match(&rr, i, P))
3089 if (i->sort(&rr, &r0, i, P) < 0)
3093 return dns_rr_offset(&r0);
3094 } /* dns_rr_i_start() */
3097 static unsigned short dns_rr_i_skip(unsigned short rp, struct dns_rr_i *i, struct dns_packet *P) {
3098 struct dns_rr r0, r1, rr;
3101 if ((error = dns_rr_parse(&r0, rp, P)))
3104 r0.section = dns_rr_section(rp, P);
3106 rp = (i->sort == &dns_rr_i_packet)? dns_rr_skip(rp, P) : 12;
3108 for (; rp < P->end; rp = dns_rr_skip(rp, P)) {
3109 if ((error = dns_rr_parse(&rr, rp, P)))
3112 rr.section = dns_rr_section(rp, P);
3114 if (!dns_rr_i_match(&rr, i, P))
3117 if (i->sort(&rr, &r0, i, P) <= 0)
3127 if (i->sort == &dns_rr_i_packet)
3128 return dns_rr_offset(&r1);
3130 while ((rp = dns_rr_skip(rp, P)) < P->end) {
3131 if ((error = dns_rr_parse(&rr, rp, P)))
3134 rr.section = dns_rr_section(rp, P);
3136 if (!dns_rr_i_match(&rr, i, P))
3139 if (i->sort(&rr, &r0, i, P) <= 0)
3142 if (i->sort(&rr, &r1, i, P) >= 0)
3148 return dns_rr_offset(&r1);
3149 } /* dns_rr_i_skip() */
3152 int dns_rr_i_packet(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) {
3156 return (int)a->dn.p - (int)b->dn.p;
3157 } /* dns_rr_i_packet() */
3160 int dns_rr_i_order(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) {
3165 if ((cmp = a->section - b->section))
3168 if (a->type != b->type)
3169 return (int)a->dn.p - (int)b->dn.p;
3171 return dns_rr_cmp(a, P, b, P);
3172 } /* dns_rr_i_order() */
3175 int dns_rr_i_shuffle(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) {
3181 while (!i->state.regs[0])
3182 i->state.regs[0] = dns_random();
3184 if ((cmp = a->section - b->section))
3187 return dns_k_shuffle16(a->dn.p, i->state.regs[0]) - dns_k_shuffle16(b->dn.p, i->state.regs[0]);
3188 } /* dns_rr_i_shuffle() */
3191 struct dns_rr_i *dns_rr_i_init(struct dns_rr_i *i, struct dns_packet *P) {
3192 static const struct dns_rr_i i_initializer;
3196 i->state = i_initializer.state;
3197 i->saved = i->state;
3200 } /* dns_rr_i_init() */
3203 unsigned dns_rr_grep(struct dns_rr *rr, unsigned lim, struct dns_rr_i *i, struct dns_packet *P, int *error_) {
3207 switch (i->state.exec) {
3210 i->sort = &dns_rr_i_packet;
3212 i->state.next = dns_rr_i_start(i, P);
3217 while (count < lim && i->state.next < P->end) {
3218 if ((error = dns_rr_parse(rr, i->state.next, P)))
3221 rr->section = dns_rr_section(i->state.next, P);
3227 i->state.next = dns_rr_i_skip(i->state.next, i, P);
3238 } /* dns_rr_grep() */
3241 size_t dns_rr_print(void *_dst, size_t lim, struct dns_rr *rr, struct dns_packet *P, int *_error) {
3242 struct dns_buf dst = DNS_B_INTO(_dst, lim);
3247 if (rr->section == DNS_S_QD)
3248 dns_b_putc(&dst, ';');
3250 if (!(n = dns_d_expand(any.ns.host, sizeof any.ns.host, rr->dn.p, P, &error)))
3252 dns_b_put(&dst, any.ns.host, DNS_PP_MIN(n, sizeof any.ns.host - 1));
3254 if (rr->section != DNS_S_QD) {
3255 dns_b_putc(&dst, ' ');
3256 dns_b_fmtju(&dst, rr->ttl, 0);
3259 dns_b_putc(&dst, ' ');
3260 dns_b_puts(&dst, dns_strclass(rr->class));
3261 dns_b_putc(&dst, ' ');
3262 dns_b_puts(&dst, dns_strtype(rr->type));
3264 if (rr->section == DNS_S_QD)
3267 dns_b_putc(&dst, ' ');
3269 if ((error = dns_any_parse(dns_any_init(&any, sizeof any), rr, P)))
3272 n = dns_any_print(dst.p, dst.pe - dst.p, &any, rr->type);
3273 dst.p += DNS_PP_MIN(n, (size_t)(dst.pe - dst.p));
3275 return dns_b_strllen(&dst);
3280 } /* dns_rr_print() */
3283 int dns_a_parse(struct dns_a *a, struct dns_rr *rr, struct dns_packet *P) {
3286 if (rr->rd.len != 4)
3287 return DNS_EILLEGAL;
3289 addr = ((0xffU & P->data[rr->rd.p + 0]) << 24)
3290 | ((0xffU & P->data[rr->rd.p + 1]) << 16)
3291 | ((0xffU & P->data[rr->rd.p + 2]) << 8)
3292 | ((0xffU & P->data[rr->rd.p + 3]) << 0);
3294 a->addr.s_addr = htonl(addr);
3297 } /* dns_a_parse() */
3300 int dns_a_push(struct dns_packet *P, struct dns_a *a) {
3303 if (P->size - P->end < 6)
3306 P->data[P->end++] = 0x00;
3307 P->data[P->end++] = 0x04;
3309 addr = ntohl(a->addr.s_addr);
3311 P->data[P->end++] = 0xffU & (addr >> 24);
3312 P->data[P->end++] = 0xffU & (addr >> 16);
3313 P->data[P->end++] = 0xffU & (addr >> 8);
3314 P->data[P->end++] = 0xffU & (addr >> 0);
3317 } /* dns_a_push() */
3320 size_t dns_a_arpa(void *_dst, size_t lim, const struct dns_a *a) {
3321 struct dns_buf dst = DNS_B_INTO(_dst, lim);
3322 unsigned long octets = ntohl(a->addr.s_addr);
3325 for (i = 0; i < 4; i++) {
3326 dns_b_fmtju(&dst, 0xff & octets, 0);
3327 dns_b_putc(&dst, '.');
3331 dns_b_puts(&dst, "in-addr.arpa.");
3333 return dns_b_strllen(&dst);
3334 } /* dns_a_arpa() */
3337 int dns_a_cmp(const struct dns_a *a, const struct dns_a *b) {
3338 if (ntohl(a->addr.s_addr) < ntohl(b->addr.s_addr))
3340 if (ntohl(a->addr.s_addr) > ntohl(b->addr.s_addr))
3347 size_t dns_a_print(void *dst, size_t lim, struct dns_a *a) {
3348 char addr[INET_ADDRSTRLEN + 1] = "0.0.0.0";
3350 dns_inet_ntop(AF_INET, &a->addr, addr, sizeof addr);
3352 return dns_strlcpy(dst, addr, lim);
3353 } /* dns_a_print() */
3356 int dns_aaaa_parse(struct dns_aaaa *aaaa, struct dns_rr *rr, struct dns_packet *P) {
3357 if (rr->rd.len != sizeof aaaa->addr.s6_addr)
3358 return DNS_EILLEGAL;
3360 memcpy(aaaa->addr.s6_addr, &P->data[rr->rd.p], sizeof aaaa->addr.s6_addr);
3363 } /* dns_aaaa_parse() */
3366 int dns_aaaa_push(struct dns_packet *P, struct dns_aaaa *aaaa) {
3367 if (P->size - P->end < 2 + sizeof aaaa->addr.s6_addr)
3370 P->data[P->end++] = 0x00;
3371 P->data[P->end++] = 0x10;
3373 memcpy(&P->data[P->end], aaaa->addr.s6_addr, sizeof aaaa->addr.s6_addr);
3375 P->end += sizeof aaaa->addr.s6_addr;
3378 } /* dns_aaaa_push() */
3381 int dns_aaaa_cmp(const struct dns_aaaa *a, const struct dns_aaaa *b) {
3385 for (i = 0; i < lengthof(a->addr.s6_addr); i++) {
3386 if ((cmp = (a->addr.s6_addr[i] - b->addr.s6_addr[i])))
3391 } /* dns_aaaa_cmp() */
3394 size_t dns_aaaa_arpa(void *_dst, size_t lim, const struct dns_aaaa *aaaa) {
3395 static const unsigned char hex[16] = "0123456789abcdef";
3396 struct dns_buf dst = DNS_B_INTO(_dst, lim);
3400 for (i = sizeof aaaa->addr.s6_addr - 1; i >= 0; i--) {
3401 nyble = aaaa->addr.s6_addr[i];
3403 for (j = 0; j < 2; j++) {
3404 dns_b_putc(&dst, hex[0x0f & nyble]);
3405 dns_b_putc(&dst, '.');
3410 dns_b_puts(&dst, "ip6.arpa.");
3412 return dns_b_strllen(&dst);
3413 } /* dns_aaaa_arpa() */
3416 size_t dns_aaaa_print(void *dst, size_t lim, struct dns_aaaa *aaaa) {
3417 char addr[INET6_ADDRSTRLEN + 1] = "::";
3419 dns_inet_ntop(AF_INET6, &aaaa->addr, addr, sizeof addr);
3421 return dns_strlcpy(dst, addr, lim);
3422 } /* dns_aaaa_print() */
3425 int dns_mx_parse(struct dns_mx *mx, struct dns_rr *rr, struct dns_packet *P) {
3430 return DNS_EILLEGAL;
3432 mx->preference = (0xff00 & (P->data[rr->rd.p + 0] << 8))
3433 | (0x00ff & (P->data[rr->rd.p + 1] << 0));
3435 if (!(len = dns_d_expand(mx->host, sizeof mx->host, rr->rd.p + 2, P, &error)))
3437 else if (len >= sizeof mx->host)
3438 return DNS_EILLEGAL;
3441 } /* dns_mx_parse() */
3444 int dns_mx_push(struct dns_packet *P, struct dns_mx *mx) {
3448 if (P->size - P->end < 5)
3454 P->data[P->end++] = 0xff & (mx->preference >> 8);
3455 P->data[P->end++] = 0xff & (mx->preference >> 0);
3457 if ((error = dns_d_push(P, mx->host, strlen(mx->host))))
3460 len = P->end - end - 2;
3462 P->data[end + 0] = 0xff & (len >> 8);
3463 P->data[end + 1] = 0xff & (len >> 0);
3470 } /* dns_mx_push() */
3473 int dns_mx_cmp(const struct dns_mx *a, const struct dns_mx *b) {
3476 if ((cmp = a->preference - b->preference))
3479 return strcasecmp(a->host, b->host);
3480 } /* dns_mx_cmp() */
3483 size_t dns_mx_print(void *_dst, size_t lim, struct dns_mx *mx) {
3484 struct dns_buf dst = DNS_B_INTO(_dst, lim);
3486 dns_b_fmtju(&dst, mx->preference, 0);
3487 dns_b_putc(&dst, ' ');
3488 dns_b_puts(&dst, mx->host);
3490 return dns_b_strllen(&dst);
3491 } /* dns_mx_print() */
3494 size_t dns_mx_cname(void *dst, size_t lim, struct dns_mx *mx) {
3495 return dns_strlcpy(dst, mx->host, lim);
3496 } /* dns_mx_cname() */
3499 int dns_ns_parse(struct dns_ns *ns, struct dns_rr *rr, struct dns_packet *P) {
3503 if (!(len = dns_d_expand(ns->host, sizeof ns->host, rr->rd.p, P, &error)))
3505 else if (len >= sizeof ns->host)
3506 return DNS_EILLEGAL;
3509 } /* dns_ns_parse() */
3512 int dns_ns_push(struct dns_packet *P, struct dns_ns *ns) {
3516 if (P->size - P->end < 3)
3522 if ((error = dns_d_push(P, ns->host, strlen(ns->host))))
3525 len = P->end - end - 2;
3527 P->data[end + 0] = 0xff & (len >> 8);
3528 P->data[end + 1] = 0xff & (len >> 0);
3535 } /* dns_ns_push() */
3538 int dns_ns_cmp(const struct dns_ns *a, const struct dns_ns *b) {
3539 return strcasecmp(a->host, b->host);
3540 } /* dns_ns_cmp() */
3543 size_t dns_ns_print(void *dst, size_t lim, struct dns_ns *ns) {
3544 return dns_strlcpy(dst, ns->host, lim);
3545 } /* dns_ns_print() */
3548 size_t dns_ns_cname(void *dst, size_t lim, struct dns_ns *ns) {
3549 return dns_strlcpy(dst, ns->host, lim);
3550 } /* dns_ns_cname() */
3553 int dns_cname_parse(struct dns_cname *cname, struct dns_rr *rr, struct dns_packet *P) {
3554 return dns_ns_parse((struct dns_ns *)cname, rr, P);
3555 } /* dns_cname_parse() */
3558 int dns_cname_push(struct dns_packet *P, struct dns_cname *cname) {
3559 return dns_ns_push(P, (struct dns_ns *)cname);
3560 } /* dns_cname_push() */
3563 int dns_cname_cmp(const struct dns_cname *a, const struct dns_cname *b) {
3564 return strcasecmp(a->host, b->host);
3565 } /* dns_cname_cmp() */
3568 size_t dns_cname_print(void *dst, size_t lim, struct dns_cname *cname) {
3569 return dns_ns_print(dst, lim, (struct dns_ns *)cname);
3570 } /* dns_cname_print() */
3573 size_t dns_cname_cname(void *dst, size_t lim, struct dns_cname *cname) {
3574 return dns_strlcpy(dst, cname->host, lim);
3575 } /* dns_cname_cname() */
3578 int dns_soa_parse(struct dns_soa *soa, struct dns_rr *rr, struct dns_packet *P) {
3579 struct { void *dst; size_t lim; } dn[] =
3580 { { soa->mname, sizeof soa->mname },
3581 { soa->rname, sizeof soa->rname } };
3583 { &soa->serial, &soa->refresh, &soa->retry, &soa->expire, &soa->minimum };
3589 if ((rp = rr->rd.p) >= P->end)
3590 return DNS_EILLEGAL;
3592 for (i = 0; i < lengthof(dn); i++) {
3593 if (!(n = dns_d_expand(dn[i].dst, dn[i].lim, rp, P, &error)))
3595 else if (n >= dn[i].lim)
3596 return DNS_EILLEGAL;
3598 if ((rp = dns_d_skip(rp, P)) >= P->end)
3599 return DNS_EILLEGAL;
3602 /* SERIAL / REFRESH / RETRY / EXPIRE / MINIMUM */
3603 for (i = 0; i < lengthof(ts); i++) {
3604 for (j = 0; j < 4; j++, rp++) {
3606 return DNS_EILLEGAL;
3609 *ts[i] |= (0xff & P->data[rp]);
3614 } /* dns_soa_parse() */
3617 int dns_soa_push(struct dns_packet *P, struct dns_soa *soa) {
3618 void *dn[] = { soa->mname, soa->rname };
3619 unsigned ts[] = { (0xffffffff & soa->serial),
3620 (0x7fffffff & soa->refresh),
3621 (0x7fffffff & soa->retry),
3622 (0x7fffffff & soa->expire),
3623 (0xffffffff & soa->minimum) };
3630 if ((P->end += 2) >= P->size)
3634 for (i = 0; i < lengthof(dn); i++) {
3635 if ((error = dns_d_push(P, dn[i], strlen(dn[i]))))
3639 /* SERIAL / REFRESH / RETRY / EXPIRE / MINIMUM */
3640 for (i = 0; i < lengthof(ts); i++) {
3641 if ((P->end += 4) >= P->size)
3644 for (j = 1; j <= 4; j++) {
3645 P->data[P->end - j] = (0xff & ts[i]);
3650 len = P->end - end - 2;
3651 P->data[end + 0] = (0xff & (len >> 8));
3652 P->data[end + 1] = (0xff & (len >> 0));
3656 error = DNS_ENOBUFS;
3663 } /* dns_soa_push() */
3666 int dns_soa_cmp(const struct dns_soa *a, const struct dns_soa *b) {
3669 if ((cmp = strcasecmp(a->mname, b->mname)))
3672 if ((cmp = strcasecmp(a->rname, b->rname)))
3675 if (a->serial > b->serial)
3677 else if (a->serial < b->serial)
3680 if (a->refresh > b->refresh)
3682 else if (a->refresh < b->refresh)
3685 if (a->retry > b->retry)
3687 else if (a->retry < b->retry)
3690 if (a->expire > b->expire)
3692 else if (a->expire < b->expire)
3695 if (a->minimum > b->minimum)
3697 else if (a->minimum < b->minimum)
3701 } /* dns_soa_cmp() */
3704 size_t dns_soa_print(void *_dst, size_t lim, struct dns_soa *soa) {
3705 struct dns_buf dst = DNS_B_INTO(_dst, lim);
3707 dns_b_puts(&dst, soa->mname);
3708 dns_b_putc(&dst, ' ');
3709 dns_b_puts(&dst, soa->rname);
3710 dns_b_putc(&dst, ' ');
3711 dns_b_fmtju(&dst, soa->serial, 0);
3712 dns_b_putc(&dst, ' ');
3713 dns_b_fmtju(&dst, soa->refresh, 0);
3714 dns_b_putc(&dst, ' ');
3715 dns_b_fmtju(&dst, soa->retry, 0);
3716 dns_b_putc(&dst, ' ');
3717 dns_b_fmtju(&dst, soa->expire, 0);
3718 dns_b_putc(&dst, ' ');
3719 dns_b_fmtju(&dst, soa->minimum, 0);
3721 return dns_b_strllen(&dst);
3722 } /* dns_soa_print() */
3725 int dns_srv_parse(struct dns_srv *srv, struct dns_rr *rr, struct dns_packet *P) {
3731 memset(srv, '\0', sizeof *srv);
3736 return DNS_EILLEGAL;
3738 for (i = 0; i < 2; i++, rp++) {
3739 srv->priority <<= 8;
3740 srv->priority |= (0xff & P->data[rp]);
3743 for (i = 0; i < 2; i++, rp++) {
3745 srv->weight |= (0xff & P->data[rp]);
3748 for (i = 0; i < 2; i++, rp++) {
3750 srv->port |= (0xff & P->data[rp]);
3753 if (!(n = dns_d_expand(srv->target, sizeof srv->target, rp, P, &error)))
3755 else if (n >= sizeof srv->target)
3756 return DNS_EILLEGAL;
3759 } /* dns_srv_parse() */
3762 int dns_srv_push(struct dns_packet *P, struct dns_srv *srv) {
3768 if (P->size - P->end < 2)
3773 if (P->size - P->end < 6)
3776 P->data[P->end++] = 0xff & (srv->priority >> 8);
3777 P->data[P->end++] = 0xff & (srv->priority >> 0);
3779 P->data[P->end++] = 0xff & (srv->weight >> 8);
3780 P->data[P->end++] = 0xff & (srv->weight >> 0);
3782 P->data[P->end++] = 0xff & (srv->port >> 8);
3783 P->data[P->end++] = 0xff & (srv->port >> 0);
3785 if (0 == (len = dns_d_comp(&P->data[P->end], P->size - P->end, srv->target, strlen(srv->target), P, &error)))
3787 else if (P->size - P->end < len)
3795 len = P->end - end - 2;
3797 P->data[end + 0] = 0xff & (len >> 8);
3798 P->data[end + 1] = 0xff & (len >> 0);
3802 error = DNS_ENOBUFS;
3809 } /* dns_srv_push() */
3812 int dns_srv_cmp(const struct dns_srv *a, const struct dns_srv *b) {
3815 if ((cmp = a->priority - b->priority))
3819 * FIXME: We need some sort of random seed to implement the dynamic
3820 * weighting required by RFC 2782.
3822 if ((cmp = a->weight - b->weight))
3825 if ((cmp = a->port - b->port))
3828 return strcasecmp(a->target, b->target);
3829 } /* dns_srv_cmp() */
3832 size_t dns_srv_print(void *_dst, size_t lim, struct dns_srv *srv) {
3833 struct dns_buf dst = DNS_B_INTO(_dst, lim);
3835 dns_b_fmtju(&dst, srv->priority, 0);
3836 dns_b_putc(&dst, ' ');
3837 dns_b_fmtju(&dst, srv->weight, 0);
3838 dns_b_putc(&dst, ' ');
3839 dns_b_fmtju(&dst, srv->port, 0);
3840 dns_b_putc(&dst, ' ');
3841 dns_b_puts(&dst, srv->target);
3843 return dns_b_strllen(&dst);
3844 } /* dns_srv_print() */
3847 size_t dns_srv_cname(void *dst, size_t lim, struct dns_srv *srv) {
3848 return dns_strlcpy(dst, srv->target, lim);
3849 } /* dns_srv_cname() */
3852 unsigned int dns_opt_ttl(const struct dns_opt *opt) {
3853 unsigned int ttl = 0;
3855 ttl |= (0xffU & opt->rcode) << 24;
3856 ttl |= (0xffU & opt->version) << 16;
3857 ttl |= (0xffffU & opt->flags) << 0;
3860 } /* dns_opt_ttl() */
3863 unsigned short dns_opt_class(const struct dns_opt *opt) {
3865 } /* dns_opt_class() */
3868 struct dns_opt *dns_opt_init(struct dns_opt *opt, size_t size) {
3869 assert(size >= offsetof(struct dns_opt, data));
3871 opt->size = size - offsetof(struct dns_opt, data);
3879 } /* dns_opt_init() */
3882 static union dns_any *dns_opt_initany(union dns_any *any, size_t size) {
3883 return dns_opt_init(&any->opt, size), any;
3884 } /* dns_opt_initany() */
3887 int dns_opt_parse(struct dns_opt *opt, struct dns_rr *rr, struct dns_packet *P) {
3888 const struct dns_buf src = DNS_B_FROM(&P->data[rr->rd.p], rr->rd.len);
3889 struct dns_buf dst = DNS_B_INTO(opt->data, opt->size);
3892 opt->rcode = 0xfff & ((rr->ttl >> 20) | dns_header(P)->rcode);
3893 opt->version = 0xff & (rr->ttl >> 16);
3894 opt->flags = 0xffff & rr->ttl;
3895 opt->maxudp = 0xffff & rr->class;
3897 while (src.p < src.pe) {
3900 if (-1 == (code = dns_b_get16(&src, -1)))
3902 if (-1 == (len = dns_b_get16(&src, -1)))
3907 dns_b_put16(&dst, code);
3908 dns_b_put16(&dst, len);
3909 if ((error = dns_b_move(&dst, &src, len)))
3916 } /* dns_opt_parse() */
3919 int dns_opt_push(struct dns_packet *P, struct dns_opt *opt) {
3920 const struct dns_buf src = DNS_B_FROM(opt->data, opt->len);
3921 struct dns_buf dst = DNS_B_INTO(&P->data[P->end], (P->size - P->end));
3924 /* rdata length (see below) */
3925 if ((error = dns_b_put16(&dst, 0)))
3928 /* ... push known options here */
3930 /* push opaque option data */
3931 if ((error = dns_b_move(&dst, &src, (size_t)(src.pe - src.p))))
3935 if ((error = dns_b_pput16(&dst, dns_b_tell(&dst) - 2, 0)))
3938 #if !DNS_DEBUG_OPT_FORMERR
3939 P->end += dns_b_tell(&dst);
3945 } /* dns_opt_push() */
3948 int dns_opt_cmp(const struct dns_opt *a, const struct dns_opt *b) {
3953 } /* dns_opt_cmp() */
3956 size_t dns_opt_print(void *_dst, size_t lim, struct dns_opt *opt) {
3957 struct dns_buf dst = DNS_B_INTO(_dst, lim);
3960 dns_b_putc(&dst, '"');
3962 for (p = 0; p < opt->len; p++) {
3963 dns_b_putc(&dst, '\\');
3964 dns_b_fmtju(&dst, opt->data[p], 3);
3967 dns_b_putc(&dst, '"');
3969 return dns_b_strllen(&dst);
3970 } /* dns_opt_print() */
3973 int dns_ptr_parse(struct dns_ptr *ptr, struct dns_rr *rr, struct dns_packet *P) {
3974 return dns_ns_parse((struct dns_ns *)ptr, rr, P);
3975 } /* dns_ptr_parse() */
3978 int dns_ptr_push(struct dns_packet *P, struct dns_ptr *ptr) {
3979 return dns_ns_push(P, (struct dns_ns *)ptr);
3980 } /* dns_ptr_push() */
3983 size_t dns_ptr_qname(void *dst, size_t lim, int af, void *addr) {
3986 return dns_aaaa_arpa(dst, lim, addr);
3988 return dns_a_arpa(dst, lim, addr);
3991 a.addr.s_addr = INADDR_NONE;
3992 return dns_a_arpa(dst, lim, &a);
3995 } /* dns_ptr_qname() */
3998 int dns_ptr_cmp(const struct dns_ptr *a, const struct dns_ptr *b) {
3999 return strcasecmp(a->host, b->host);
4000 } /* dns_ptr_cmp() */
4003 size_t dns_ptr_print(void *dst, size_t lim, struct dns_ptr *ptr) {
4004 return dns_ns_print(dst, lim, (struct dns_ns *)ptr);
4005 } /* dns_ptr_print() */
4008 size_t dns_ptr_cname(void *dst, size_t lim, struct dns_ptr *ptr) {
4009 return dns_strlcpy(dst, ptr->host, lim);
4010 } /* dns_ptr_cname() */
4013 int dns_sshfp_parse(struct dns_sshfp *fp, struct dns_rr *rr, struct dns_packet *P) {
4014 unsigned p = rr->rd.p, pe = rr->rd.p + rr->rd.len;
4017 return DNS_EILLEGAL;
4019 fp->algo = P->data[p++];
4020 fp->type = P->data[p++];
4023 case DNS_SSHFP_SHA1:
4024 if (pe - p < sizeof fp->digest.sha1)
4025 return DNS_EILLEGAL;
4027 memcpy(fp->digest.sha1, &P->data[p], sizeof fp->digest.sha1);
4035 } /* dns_sshfp_parse() */
4038 int dns_sshfp_push(struct dns_packet *P, struct dns_sshfp *fp) {
4039 unsigned p = P->end, pe = P->size, n;
4045 P->data[p++] = 0xff & fp->algo;
4046 P->data[p++] = 0xff & fp->type;
4049 case DNS_SSHFP_SHA1:
4050 if (pe - p < sizeof fp->digest.sha1)
4053 memcpy(&P->data[p], fp->digest.sha1, sizeof fp->digest.sha1);
4054 p += sizeof fp->digest.sha1;
4058 return DNS_EILLEGAL;
4062 P->data[P->end++] = 0xff & (n >> 8);
4063 P->data[P->end++] = 0xff & (n >> 0);
4067 } /* dns_sshfp_push() */
4070 int dns_sshfp_cmp(const struct dns_sshfp *a, const struct dns_sshfp *b) {
4073 if ((cmp = a->algo - b->algo) || (cmp = a->type - b->type))
4077 case DNS_SSHFP_SHA1:
4078 return memcmp(a->digest.sha1, b->digest.sha1, sizeof a->digest.sha1);
4084 } /* dns_sshfp_cmp() */
4087 size_t dns_sshfp_print(void *_dst, size_t lim, struct dns_sshfp *fp) {
4088 static const unsigned char hex[16] = "0123456789abcdef";
4089 struct dns_buf dst = DNS_B_INTO(_dst, lim);
4092 dns_b_fmtju(&dst, fp->algo, 0);
4093 dns_b_putc(&dst, ' ');
4094 dns_b_fmtju(&dst, fp->type, 0);
4095 dns_b_putc(&dst, ' ');
4098 case DNS_SSHFP_SHA1:
4099 for (i = 0; i < sizeof fp->digest.sha1; i++) {
4100 dns_b_putc(&dst, hex[0x0f & (fp->digest.sha1[i] >> 4)]);
4101 dns_b_putc(&dst, hex[0x0f & (fp->digest.sha1[i] >> 0)]);
4106 dns_b_putc(&dst, '0');
4111 return dns_b_strllen(&dst);
4112 } /* dns_sshfp_print() */
4115 struct dns_txt *dns_txt_init(struct dns_txt *txt, size_t size) {
4116 assert(size > offsetof(struct dns_txt, data));
4118 txt->size = size - offsetof(struct dns_txt, data);
4122 } /* dns_txt_init() */
4125 static union dns_any *dns_txt_initany(union dns_any *any, size_t size) {
4126 /* NB: union dns_any is already initialized as struct dns_txt */
4129 } /* dns_txt_initany() */
4132 int dns_txt_parse(struct dns_txt *txt, struct dns_rr *rr, struct dns_packet *P) {
4133 struct { unsigned char *b; size_t p, end; } dst, src;
4138 dst.end = txt->size;
4142 src.end = src.p + rr->rd.len;
4144 while (src.p < src.end) {
4145 n = 0xff & P->data[src.p++];
4147 if (src.end - src.p < n || dst.end - dst.p < n)
4148 return DNS_EILLEGAL;
4150 memcpy(&dst.b[dst.p], &src.b[src.p], n);
4159 } /* dns_txt_parse() */
4162 int dns_txt_push(struct dns_packet *P, struct dns_txt *txt) {
4163 struct { unsigned char *b; size_t p, end; } dst, src;
4174 if (dst.end - dst.p < 2)
4177 n = txt->len + ((txt->len + 254) / 255);
4179 dst.b[dst.p++] = 0xff & (n >> 8);
4180 dst.b[dst.p++] = 0xff & (n >> 0);
4182 while (src.p < src.end) {
4183 n = DNS_PP_MIN(255, src.end - src.p);
4185 if (dst.p >= dst.end)
4190 if (dst.end - dst.p < n)
4193 memcpy(&dst.b[dst.p], &src.b[src.p], n);
4202 } /* dns_txt_push() */
4205 int dns_txt_cmp(const struct dns_txt *a, const struct dns_txt *b) {
4210 } /* dns_txt_cmp() */
4213 size_t dns_txt_print(void *_dst, size_t lim, struct dns_txt *txt) {
4214 struct dns_buf src = DNS_B_FROM(txt->data, txt->len);
4215 struct dns_buf dst = DNS_B_INTO(_dst, lim);
4218 if (src.p < src.pe) {
4220 dns_b_putc(&dst, '"');
4222 for (i = 0; i < 256 && src.p < src.pe; i++, src.p++) {
4223 if (*src.p < 32 || *src.p > 126 || *src.p == '"' || *src.p == '\\') {
4224 dns_b_putc(&dst, '\\');
4225 dns_b_fmtju(&dst, *src.p, 3);
4227 dns_b_putc(&dst, *src.p);
4231 dns_b_putc(&dst, '"');
4232 dns_b_putc(&dst, ' ');
4233 } while (src.p < src.pe);
4237 dns_b_putc(&dst, '"');
4238 dns_b_putc(&dst, '"');
4241 return dns_b_strllen(&dst);
4242 } /* dns_txt_print() */
4245 static const struct dns_rrtype {
4248 union dns_any *(*init)(union dns_any *, size_t);
4255 { DNS_T_A, "A", 0, &dns_a_parse, &dns_a_push, &dns_a_cmp, &dns_a_print, 0, },
4256 { DNS_T_AAAA, "AAAA", 0, &dns_aaaa_parse, &dns_aaaa_push, &dns_aaaa_cmp, &dns_aaaa_print, 0, },
4257 { DNS_T_MX, "MX", 0, &dns_mx_parse, &dns_mx_push, &dns_mx_cmp, &dns_mx_print, &dns_mx_cname, },
4258 { DNS_T_NS, "NS", 0, &dns_ns_parse, &dns_ns_push, &dns_ns_cmp, &dns_ns_print, &dns_ns_cname, },
4259 { DNS_T_CNAME, "CNAME", 0, &dns_cname_parse, &dns_cname_push, &dns_cname_cmp, &dns_cname_print, &dns_cname_cname, },
4260 { DNS_T_SOA, "SOA", 0, &dns_soa_parse, &dns_soa_push, &dns_soa_cmp, &dns_soa_print, 0, },
4261 { DNS_T_SRV, "SRV", 0, &dns_srv_parse, &dns_srv_push, &dns_srv_cmp, &dns_srv_print, &dns_srv_cname, },
4262 { DNS_T_OPT, "OPT", &dns_opt_initany, &dns_opt_parse, &dns_opt_push, &dns_opt_cmp, &dns_opt_print, 0, },
4263 { DNS_T_PTR, "PTR", 0, &dns_ptr_parse, &dns_ptr_push, &dns_ptr_cmp, &dns_ptr_print, &dns_ptr_cname, },
4264 { DNS_T_TXT, "TXT", &dns_txt_initany, &dns_txt_parse, &dns_txt_push, &dns_txt_cmp, &dns_txt_print, 0, },
4265 { DNS_T_SPF, "SPF", &dns_txt_initany, &dns_txt_parse, &dns_txt_push, &dns_txt_cmp, &dns_txt_print, 0, },
4266 { DNS_T_SSHFP, "SSHFP", 0, &dns_sshfp_parse, &dns_sshfp_push, &dns_sshfp_cmp, &dns_sshfp_print, 0, },
4267 { DNS_T_AXFR, "AXFR", 0, 0, 0, 0, 0, 0, },
4268 }; /* dns_rrtypes[] */
4270 static const struct dns_rrtype *dns_rrtype(enum dns_type type) {
4271 const struct dns_rrtype *t;
4273 for (t = dns_rrtypes; t < endof(dns_rrtypes); t++) {
4274 if (t->type == type && t->parse) {
4280 } /* dns_rrtype() */
4283 union dns_any *dns_any_init(union dns_any *any, size_t size) {
4284 dns_static_assert(dns_same_type(any->txt, any->rdata, 1), "unexpected rdata type");
4285 return (union dns_any *)dns_txt_init(&any->rdata, size);
4286 } /* dns_any_init() */
4289 static size_t dns_any_sizeof(union dns_any *any) {
4290 dns_static_assert(dns_same_type(any->txt, any->rdata, 1), "unexpected rdata type");
4291 return offsetof(struct dns_txt, data) + any->rdata.size;
4292 } /* dns_any_sizeof() */
4294 static union dns_any *dns_any_reinit(union dns_any *any, const struct dns_rrtype *t) {
4295 return (t->init)? t->init(any, dns_any_sizeof(any)) : any;
4296 } /* dns_any_reinit() */
4298 int dns_any_parse(union dns_any *any, struct dns_rr *rr, struct dns_packet *P) {
4299 const struct dns_rrtype *t;
4301 if ((t = dns_rrtype(rr->type)))
4302 return t->parse(dns_any_reinit(any, t), rr, P);
4304 if (rr->rd.len > any->rdata.size)
4305 return DNS_EILLEGAL;
4307 memcpy(any->rdata.data, &P->data[rr->rd.p], rr->rd.len);
4308 any->rdata.len = rr->rd.len;
4311 } /* dns_any_parse() */
4314 int dns_any_push(struct dns_packet *P, union dns_any *any, enum dns_type type) {
4315 const struct dns_rrtype *t;
4317 if ((t = dns_rrtype(type)))
4318 return t->push(P, any);
4320 if (P->size - P->end < any->rdata.len + 2)
4323 P->data[P->end++] = 0xff & (any->rdata.len >> 8);
4324 P->data[P->end++] = 0xff & (any->rdata.len >> 0);
4326 memcpy(&P->data[P->end], any->rdata.data, any->rdata.len);
4327 P->end += any->rdata.len;
4330 } /* dns_any_push() */
4333 int dns_any_cmp(const union dns_any *a, enum dns_type x, const union dns_any *b, enum dns_type y) {
4334 const struct dns_rrtype *t;
4340 if ((t = dns_rrtype(x)))
4341 return t->cmp(a, b);
4344 } /* dns_any_cmp() */
4347 size_t dns_any_print(void *_dst, size_t lim, union dns_any *any, enum dns_type type) {
4348 const struct dns_rrtype *t;
4349 struct dns_buf src, dst;
4351 if ((t = dns_rrtype(type)))
4352 return t->print(_dst, lim, any);
4354 dns_b_from(&src, any->rdata.data, any->rdata.len);
4355 dns_b_into(&dst, _dst, lim);
4357 dns_b_putc(&dst, '"');
4359 while (src.p < src.pe) {
4360 dns_b_putc(&dst, '\\');
4361 dns_b_fmtju(&dst, *src.p++, 3);
4364 dns_b_putc(&dst, '"');
4366 return dns_b_strllen(&dst);
4367 } /* dns_any_print() */
4370 size_t dns_any_cname(void *dst, size_t lim, union dns_any *any, enum dns_type type) {
4371 const struct dns_rrtype *t;
4373 if ((t = dns_rrtype(type)) && t->cname)
4374 return t->cname(dst, lim, any);
4377 } /* dns_any_cname() */
4381 * E V E N T T R A C I N G R O U T I N E S
4383 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4384 #include <float.h> /* DBL_MANT_DIG */
4385 #include <inttypes.h> /* PRIu64 */
4387 /* for default trace ID generation try to fit in lua_Number, usually double */
4388 #define DNS_TRACE_ID_BITS DNS_PP_MIN(DBL_MANT_DIG, (sizeof (dns_trace_id_t) * CHAR_BIT)) /* assuming FLT_RADIX == 2 */
4389 #define DNS_TRACE_ID_MASK (((DNS_TRACE_ID_C(1) << (DNS_TRACE_ID_BITS - 1)) - 1) | (DNS_TRACE_ID_C(1) << (DNS_TRACE_ID_BITS - 1)))
4390 #define DNS_TRACE_ID_PRI PRIu64
4392 static inline dns_trace_id_t dns_trace_mkid(void) {
4393 dns_trace_id_t id = 0;
4394 unsigned r; /* return type of dns_random() */
4395 const size_t id_bit = sizeof id * CHAR_BIT;
4396 const size_t r_bit = sizeof r * CHAR_BIT;
4398 for (size_t n = 0; n < id_bit; n += r_bit) {
4404 return DNS_TRACE_ID_MASK & id;
4408 dns_atomic_t refcount;
4414 struct dns_trace_cname {
4415 char host[DNS_D_MAXNAME + 1];
4416 struct sockaddr_storage addr;
4422 static void dns_te_initname(struct sockaddr_storage *ss, int fd, int (*f)(int, struct sockaddr *, socklen_t *)) {
4423 socklen_t n = sizeof *ss;
4425 if (0 != f(fd, (struct sockaddr *)ss, &n))
4433 memset(ss, '\0', sizeof *ss);
4434 ss->ss_family = AF_UNSPEC;
4437 static void dns_te_initnames(struct sockaddr_storage *local, struct sockaddr_storage *remote, int fd) {
4438 dns_te_initname(local, fd, &getsockname);
4439 dns_te_initname(remote, fd, &getpeername);
4442 static struct dns_trace_event *dns_te_init(struct dns_trace_event *te, int type) {
4443 /* NB: silence valgrind */
4444 memset(te, '\0', offsetof(struct dns_trace_event, data));
4449 int dns_trace_abi(void) {
4450 return DNS_TRACE_ABI;
4453 struct dns_trace *dns_trace_open(FILE *fp, dns_error_t *error) {
4454 static const struct dns_trace trace_initializer = { .refcount = 1 };
4455 struct dns_trace *trace;
4457 if (!(trace = malloc(sizeof *trace)))
4460 *trace = trace_initializer;
4464 } else if (!(fp = tmpfile())) {
4468 trace->id = dns_trace_mkid();
4472 *error = dns_syerr();
4474 dns_trace_close(trace);
4477 } /* dns_trace_open() */
4479 void dns_trace_close(struct dns_trace *trace) {
4480 if (!trace || 1 != dns_trace_release(trace))
4486 } /* dns_trace_close() */
4488 dns_refcount_t dns_trace_acquire(struct dns_trace *trace) {
4489 return dns_atomic_fetch_add(&trace->refcount);
4490 } /* dns_trace_acquire() */
4492 static struct dns_trace *dns_trace_acquire_p(struct dns_trace *trace) {
4493 return (trace)? dns_trace_acquire(trace), trace : NULL;
4494 } /* dns_trace_acquire_p() */
4496 dns_refcount_t dns_trace_release(struct dns_trace *trace) {
4497 return dns_atomic_fetch_sub(&trace->refcount);
4498 } /* dns_trace_release() */
4500 dns_trace_id_t dns_trace_id(struct dns_trace *trace) {
4502 } /* dns_trace_id() */
4504 dns_trace_id_t dns_trace_setid(struct dns_trace *trace, dns_trace_id_t id) {
4505 trace->id = (id)? id : dns_trace_mkid();
4507 } /* dns_trace_setid() */
4509 struct dns_trace_event *dns_trace_get(struct dns_trace *trace, struct dns_trace_event **tp, dns_error_t *error) {
4510 return dns_trace_fget(tp, trace->fp, error);
4511 } /* dns_trace_get() */
4513 dns_error_t dns_trace_put(struct dns_trace *trace, const struct dns_trace_event *te, const void *data, size_t datasize) {
4514 return dns_trace_fput(te, data, datasize, trace->fp);
4515 } /* dns_trace_put() */
4517 struct dns_trace_event *dns_trace_tag(struct dns_trace *trace, struct dns_trace_event *te) {
4521 gettimeofday(&tv, NULL);
4522 dns_tv2ts(&te->ts, &tv);
4523 te->abi = DNS_TRACE_ABI;
4526 } /* dns_trace_tag() */
4528 static dns_error_t dns_trace_tag_and_put(struct dns_trace *trace, struct dns_trace_event *te, const void *data, size_t datasize) {
4529 return dns_trace_put(trace, dns_trace_tag(trace, te), data, datasize);
4530 } /* dns_trace_tag_and_put() */
4532 struct dns_trace_event *dns_trace_fget(struct dns_trace_event **tp, FILE *fp, dns_error_t *error) {
4533 const size_t headsize = offsetof(struct dns_trace_event, data);
4534 struct dns_trace_event tmp, *te;
4538 if (!(n = fread(&tmp, 1, headsize, fp)))
4540 if (n < offsetof(struct dns_trace_event, data))
4543 if (!(te = realloc(*tp, DNS_PP_MAX(headsize, tmp.size)))) {
4549 memcpy(te, &tmp, offsetof(struct dns_trace_event, data));
4551 if (dns_te_datasize(te)) {
4553 if (!(n = fread(te->data, 1, dns_te_datasize(te), fp)))
4555 if (n < dns_te_datasize(te))
4561 *error = (ferror(fp))? errno : 0;
4568 dns_error_t dns_trace_fput(const struct dns_trace_event *te, const void *data, size_t datasize, FILE *fp) {
4569 size_t headsize = offsetof(struct dns_trace_event, data);
4570 struct dns_trace_event tmp;
4572 memcpy(&tmp, te, headsize);
4573 tmp.size = headsize + datasize;
4575 /* NB: ignore seek error as fp might not point to a regular file */
4576 (void)fseek(fp, 0, SEEK_END);
4578 if (fwrite(&tmp, 1, headsize, fp) < headsize)
4580 if (fwrite(data, 1, datasize, fp) < datasize)
4588 static void dns_trace_setcname(struct dns_trace *trace, const char *host, const struct sockaddr *addr) {
4589 struct dns_trace_cname *cname;
4590 if (!trace || !trace->fp)
4593 cname = &trace->cnames.base[trace->cnames.p];
4594 dns_strlcpy(cname->host, host, sizeof cname->host);
4595 memcpy(&cname->addr, addr, DNS_PP_MIN(dns_sa_len(addr), sizeof cname->addr));
4597 trace->cnames.p = (trace->cnames.p + 1) % lengthof(trace->cnames.base);
4600 static const char *dns_trace_cname(struct dns_trace *trace, const struct sockaddr *addr) {
4601 if (!trace || !trace->fp)
4604 /* NB: start search from the write cursor to */
4605 for (const struct dns_trace_cname *cname = trace->cnames.base; cname < endof(trace->cnames.base); cname++) {
4606 if (0 == dns_sa_cmp((struct sockaddr *)addr, (struct sockaddr *)&cname->addr))
4613 static void dns_trace_res_submit(struct dns_trace *trace, const char *qname, enum dns_type qtype, enum dns_class qclass, int error) {
4614 struct dns_trace_event te;
4615 if (!trace || !trace->fp)
4618 dns_te_init(&te, DNS_TE_RES_SUBMIT);
4619 dns_strlcpy(te.res_submit.qname, qname, sizeof te.res_submit.qname);
4620 te.res_submit.qtype = qtype;
4621 te.res_submit.qclass = qclass;
4622 te.res_submit.error = error;
4623 dns_trace_tag_and_put(trace, &te, NULL, 0);
4626 static void dns_trace_res_fetch(struct dns_trace *trace, const struct dns_packet *packet, int error) {
4627 struct dns_trace_event te;
4630 if (!trace || !trace->fp)
4633 dns_te_init(&te, DNS_TE_RES_FETCH);
4634 data = (packet)? packet->data : NULL;
4635 datasize = (packet)? packet->end : 0;
4636 te.res_fetch.error = error;
4637 dns_trace_tag_and_put(trace, &te, data, datasize);
4640 static void dns_trace_so_submit(struct dns_trace *trace, const struct dns_packet *packet, const struct sockaddr *haddr, int error) {
4641 struct dns_trace_event te;
4643 if (!trace || !trace->fp)
4646 dns_te_init(&te, DNS_TE_SO_SUBMIT);
4647 memcpy(&te.so_submit.haddr, haddr, DNS_PP_MIN(dns_sa_len(haddr), sizeof te.so_submit.haddr));
4648 if ((cname = dns_trace_cname(trace, haddr)))
4649 dns_strlcpy(te.so_submit.hname, cname, sizeof te.so_submit.hname);
4650 te.so_submit.error = error;
4651 dns_trace_tag_and_put(trace, &te, packet->data, packet->end);
4654 static void dns_trace_so_verify(struct dns_trace *trace, const struct dns_packet *packet, int error) {
4655 struct dns_trace_event te;
4656 if (!trace || !trace->fp)
4659 dns_te_init(&te, DNS_TE_SO_VERIFY);
4660 te.so_verify.error = error;
4661 dns_trace_tag_and_put(trace, &te, packet->data, packet->end);
4664 static void dns_trace_so_fetch(struct dns_trace *trace, const struct dns_packet *packet, int error) {
4665 struct dns_trace_event te;
4668 if (!trace || !trace->fp)
4671 dns_te_init(&te, DNS_TE_SO_FETCH);
4672 data = (packet)? packet->data : NULL;
4673 datasize = (packet)? packet->end : 0;
4674 te.so_fetch.error = error;
4675 dns_trace_tag_and_put(trace, &te, data, datasize);
4678 static void dns_trace_sys_connect(struct dns_trace *trace, int fd, int socktype, const struct sockaddr *dst, int error) {
4679 struct dns_trace_event te;
4680 if (!trace || !trace->fp)
4683 dns_te_init(&te, DNS_TE_SYS_CONNECT);
4684 dns_te_initname(&te.sys_connect.src, fd, &getsockname);
4685 memcpy(&te.sys_connect.dst, dst, DNS_PP_MIN(dns_sa_len(dst), sizeof te.sys_connect.dst));
4686 te.sys_connect.socktype = socktype;
4687 te.sys_connect.error = error;
4688 dns_trace_tag_and_put(trace, &te, NULL, 0);
4691 static void dns_trace_sys_send(struct dns_trace *trace, int fd, int socktype, const void *data, size_t datasize, int error) {
4692 struct dns_trace_event te;
4693 if (!trace || !trace->fp)
4696 dns_te_init(&te, DNS_TE_SYS_SEND);
4697 dns_te_initnames(&te.sys_send.src, &te.sys_send.dst, fd);
4698 te.sys_send.socktype = socktype;
4699 te.sys_send.error = error;
4700 dns_trace_tag_and_put(trace, &te, data, datasize);
4703 static void dns_trace_sys_recv(struct dns_trace *trace, int fd, int socktype, const void *data, size_t datasize, int error) {
4704 struct dns_trace_event te;
4705 if (!trace || !trace->fp)
4708 dns_te_init(&te, DNS_TE_SYS_RECV);
4709 dns_te_initnames(&te.sys_recv.dst, &te.sys_recv.src, fd);
4710 te.sys_recv.socktype = socktype;
4711 te.sys_recv.error = error;
4712 dns_trace_tag_and_put(trace, &te, data, datasize);
4715 static dns_error_t dns_trace_dump_packet(struct dns_trace *trace, const char *prefix, const unsigned char *data, size_t datasize, FILE *fp) {
4716 struct dns_packet *packet = NULL;
4717 char *line = NULL, *p;
4718 size_t size = 1, skip = 0;
4719 struct dns_rr_i records;
4720 struct dns_p_lines_i lines;
4724 if (!(packet = dns_p_make(datasize, &error)))
4727 memcpy(packet->data, data, datasize);
4728 packet->end = datasize;
4729 (void)dns_p_study(packet);
4731 if (!(p = dns_reallocarray(line, size, 2, &error)))
4736 memset(&records, 0, sizeof records);
4737 memset(&lines, 0, sizeof lines);
4740 while ((len = dns_p_lines(line, size, &error, packet, &records, &lines))) {
4741 if (!(len < size)) {
4744 } else if (skip <= count) {
4746 fwrite(line, 1, len, fp);
4762 static dns_error_t dns_trace_dump_data(struct dns_trace *trace, const char *prefix, const unsigned char *data, size_t datasize, FILE *fp) {
4763 struct dns_hxd_lines_i lines = { 0 };
4767 while ((len = dns_hxd_lines(line, sizeof line, data, datasize, &lines))) {
4768 if (len >= sizeof line)
4769 return EOVERFLOW; /* shouldn't be possible */
4771 fwrite(line, 1, len, fp);
4777 static dns_error_t dns_trace_dump_addr(struct dns_trace *trace, const char *prefix, const struct sockaddr_storage *ss, FILE *fp) {
4783 if ((addr = dns_sa_addr(ss->ss_family, (struct sockaddr *)ss, NULL))) {
4784 char ip[INET6_ADDRSTRLEN + 1];
4786 if ((error = dns_ntop(ss->ss_family, addr, ip, sizeof ip)))
4788 fprintf(fp, "%s%s\n", prefix, ip);
4789 } else if ((path = dns_sa_path((struct sockaddr *)ss, &len))) {
4790 fprintf(fp, "%sunix:%.*s", prefix, (int)len, path);
4798 static dns_error_t dns_trace_dump_meta(struct dns_trace *trace, const char *prefix, const struct dns_trace_event *te, dns_microseconds_t elapsed, FILE *fp) {
4799 char time_s[48], elapsed_s[48];
4801 dns_utime_print(time_s, sizeof time_s, dns_ts2us(&te->ts, 0));
4802 dns_utime_print(elapsed_s, sizeof elapsed_s, elapsed);
4804 fprintf(fp, "%sid: %"DNS_TRACE_ID_PRI"\n", prefix, te->id);
4805 fprintf(fp, "%sts: %s (%s)\n", prefix, time_s, elapsed_s);
4806 fprintf(fp, "%sabi: 0x%x (0x%x)\n", prefix, te->abi, DNS_TRACE_ABI);
4810 static dns_error_t dns_trace_dump_error(struct dns_trace *trace, const char *prefix, int error, FILE *fp) {
4811 fprintf(fp, "%s%d (%s)\n", prefix, error, (error)? dns_strerror(error) : "none");
4815 dns_error_t dns_trace_dump(struct dns_trace *trace, FILE *fp) {
4816 struct dns_trace_event *te = NULL;
4819 dns_microseconds_t begin, elapsed;
4823 if (!trace || !trace->fp)
4826 if (0 != fseek(trace->fp, 0, SEEK_SET))
4829 while (dns_trace_fget(&te, trace->fp, &error)) {
4830 size_t datasize = dns_te_datasize(te);
4831 const unsigned char *data = (datasize)? te->data : NULL;
4833 if (state.id != te->id) {
4835 state.begin = dns_ts2us(&te->ts, 0);
4837 dns_time_diff(&state.elapsed, dns_ts2us(&te->ts, 0), state.begin);
4840 case DNS_TE_RES_SUBMIT:
4841 fprintf(fp, "dns_res_submit:\n");
4842 dns_trace_dump_meta(trace, " ", te, state.elapsed, fp);
4843 fprintf(fp, " qname: %s\n", te->res_submit.qname);
4844 fprintf(fp, " qtype: %s\n", dns_strtype(te->res_submit.qtype));
4845 fprintf(fp, " qclass: %s\n", dns_strclass(te->res_submit.qclass));
4846 dns_trace_dump_error(trace, " error: ", te->res_submit.error, fp);
4848 case DNS_TE_RES_FETCH:
4849 fprintf(fp, "dns_res_fetch:\n");
4850 dns_trace_dump_meta(trace, " ", te, state.elapsed, fp);
4851 dns_trace_dump_error(trace, " error: ", te->res_fetch.error, fp);
4854 fprintf(fp, " packet: |\n");
4855 if ((error = dns_trace_dump_packet(trace, " ", data, datasize, fp)))
4857 fprintf(fp, " data: |\n");
4858 if ((error = dns_trace_dump_data(trace, " ", data, datasize, fp)))
4863 case DNS_TE_SO_SUBMIT:
4864 fprintf(fp, "dns_so_submit:\n");
4865 dns_trace_dump_meta(trace, " ", te, state.elapsed, fp);
4866 fprintf(fp, " hname: %s\n", te->so_submit.hname);
4867 dns_trace_dump_addr(trace, " haddr: ", &te->so_submit.haddr, fp);
4868 dns_trace_dump_error(trace, " error: ", te->so_submit.error, fp);
4871 fprintf(fp, " packet: |\n");
4872 if ((error = dns_trace_dump_packet(trace, " ", data, datasize, fp)))
4874 fprintf(fp, " data: |\n");
4875 if ((error = dns_trace_dump_data(trace, " ", data, datasize, fp)))
4880 case DNS_TE_SO_VERIFY:
4881 fprintf(fp, "dns_so_verify:\n");
4882 dns_trace_dump_meta(trace, " ", te, state.elapsed, fp);
4883 dns_trace_dump_error(trace, " error: ", te->so_verify.error, fp);
4886 fprintf(fp, " packet: |\n");
4887 if ((error = dns_trace_dump_packet(trace, " ", data, datasize, fp)))
4889 fprintf(fp, " data: |\n");
4890 if ((error = dns_trace_dump_data(trace, " ", data, datasize, fp)))
4895 case DNS_TE_SO_FETCH:
4896 fprintf(fp, "dns_so_fetch:\n");
4897 dns_trace_dump_meta(trace, " ", te, state.elapsed, fp);
4898 dns_trace_dump_error(trace, " error: ", te->so_fetch.error, fp);
4901 fprintf(fp, " packet: |\n");
4902 if ((error = dns_trace_dump_packet(trace, " ", data, datasize, fp)))
4904 fprintf(fp, " data: |\n");
4905 if ((error = dns_trace_dump_data(trace, " ", data, datasize, fp)))
4910 case DNS_TE_SYS_CONNECT: {
4911 int socktype = te->sys_connect.socktype;
4912 fprintf(fp, "dns_sys_connect:\n");
4913 dns_trace_dump_meta(trace, " ", te, state.elapsed, fp);
4914 dns_trace_dump_addr(trace, " src: ", &te->sys_connect.src, fp);
4915 dns_trace_dump_addr(trace, " dst: ", &te->sys_connect.dst, fp);
4916 fprintf(fp, " socktype: %d (%s)\n", socktype, ((socktype == SOCK_STREAM)? "SOCK_STREAM" : (socktype == SOCK_DGRAM)? "SOCK_DGRAM" : "?"));
4917 dns_trace_dump_error(trace, " error: ", te->sys_connect.error, fp);
4921 case DNS_TE_SYS_SEND: {
4922 int socktype = te->sys_send.socktype;
4923 fprintf(fp, "dns_sys_send:\n");
4924 dns_trace_dump_meta(trace, " ", te, state.elapsed, fp);
4925 dns_trace_dump_addr(trace, " src: ", &te->sys_send.src, fp);
4926 dns_trace_dump_addr(trace, " dst: ", &te->sys_send.dst, fp);
4927 fprintf(fp, " socktype: %d (%s)\n", socktype, ((socktype == SOCK_STREAM)? "SOCK_STREAM" : (socktype == SOCK_DGRAM)? "SOCK_DGRAM" : "?"));
4928 dns_trace_dump_error(trace, " error: ", te->sys_send.error, fp);
4931 fprintf(fp, " data: |\n");
4932 if ((error = dns_trace_dump_data(trace, " ", data, datasize, fp)))
4938 case DNS_TE_SYS_RECV: {
4939 int socktype = te->sys_recv.socktype;
4940 fprintf(fp, "dns_sys_recv:\n");
4941 dns_trace_dump_meta(trace, " ", te, state.elapsed, fp);
4942 dns_trace_dump_addr(trace, " src: ", &te->sys_recv.src, fp);
4943 dns_trace_dump_addr(trace, " dst: ", &te->sys_recv.dst, fp);
4944 fprintf(fp, " socktype: %d (%s)\n", socktype, ((socktype == SOCK_STREAM)? "SOCK_STREAM" : (socktype == SOCK_DGRAM)? "SOCK_DGRAM" : "?"));
4945 dns_trace_dump_error(trace, " error: ", te->sys_recv.error, fp);
4948 fprintf(fp, " data: |\n");
4949 if ((error = dns_trace_dump_data(trace, " ", data, datasize, fp)))
4956 fprintf(fp, "unknown(0x%.2x):\n", te->type);
4957 dns_trace_dump_meta(trace, " ", te, state.elapsed, fp);
4960 fprintf(fp, " data: |\n");
4961 if ((error = dns_trace_dump_data(trace, " ", data, datasize, fp)))
4981 * H O S T S R O U T I N E S
4983 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4986 struct dns_hosts_entry {
4987 char host[DNS_D_MAXNAME + 1];
4999 struct dns_hosts_entry *next;
5002 dns_atomic_t refcount;
5003 }; /* struct dns_hosts */
5006 struct dns_hosts *dns_hosts_open(int *error) {
5007 static const struct dns_hosts hosts_initializer = { .refcount = 1 };
5008 struct dns_hosts *hosts;
5010 if (!(hosts = malloc(sizeof *hosts)))
5013 *hosts = hosts_initializer;
5015 hosts->tail = &hosts->head;
5019 *error = dns_syerr();
5024 } /* dns_hosts_open() */
5027 void dns_hosts_close(struct dns_hosts *hosts) {
5028 struct dns_hosts_entry *ent, *xnt;
5030 if (!hosts || 1 != dns_hosts_release(hosts))
5033 for (ent = hosts->head; ent; ent = xnt) {
5042 } /* dns_hosts_close() */
5045 dns_refcount_t dns_hosts_acquire(struct dns_hosts *hosts) {
5046 return dns_atomic_fetch_add(&hosts->refcount);
5047 } /* dns_hosts_acquire() */
5050 dns_refcount_t dns_hosts_release(struct dns_hosts *hosts) {
5051 return dns_atomic_fetch_sub(&hosts->refcount);
5052 } /* dns_hosts_release() */
5055 struct dns_hosts *dns_hosts_mortal(struct dns_hosts *hosts) {
5057 dns_hosts_release(hosts);
5060 } /* dns_hosts_mortal() */
5063 struct dns_hosts *dns_hosts_local(int *error_) {
5064 struct dns_hosts *hosts;
5067 if (!(hosts = dns_hosts_open(&error)))
5070 if ((error = dns_hosts_loadpath(hosts, "/etc/hosts")))
5077 dns_hosts_close(hosts);
5080 } /* dns_hosts_local() */
5083 #define dns_hosts_issep(ch) (dns_isspace(ch))
5084 #define dns_hosts_iscom(ch) ((ch) == '#' || (ch) == ';')
5086 int dns_hosts_loadfile(struct dns_hosts *hosts, FILE *fp) {
5087 struct dns_hosts_entry ent;
5088 char word[DNS_PP_MAX(INET6_ADDRSTRLEN, DNS_D_MAXNAME) + 1];
5089 unsigned wp, wc, skip;
5095 memset(&ent, '\0', sizeof ent);
5100 memset(word, '\0', sizeof word);
5103 while (EOF != (ch = fgetc(fp)) && ch != '\n') {
5104 skip |= !!dns_hosts_iscom(ch);
5109 if (dns_hosts_issep(ch))
5112 if (wp < sizeof word - 1)
5126 ent.af = (strchr(word, ':'))? AF_INET6 : AF_INET;
5127 skip = (1 != dns_inet_pton(ent.af, word, &ent.addr));
5134 dns_d_anchor(ent.host, sizeof ent.host, word, wp);
5136 if ((error = dns_hosts_insert(hosts, ent.af, &ent.addr, ent.host, (wc > 2))))
5141 } while (ch != EOF && ch != '\n');
5142 } while (ch != EOF);
5145 } /* dns_hosts_loadfile() */
5148 int dns_hosts_loadpath(struct dns_hosts *hosts, const char *path) {
5152 if (!(fp = dns_fopen(path, "rt", &error)))
5155 error = dns_hosts_loadfile(hosts, fp);
5160 } /* dns_hosts_loadpath() */
5163 int dns_hosts_dump(struct dns_hosts *hosts, FILE *fp) {
5164 struct dns_hosts_entry *ent, *xnt;
5165 char addr[INET6_ADDRSTRLEN + 1];
5168 for (ent = hosts->head; ent; ent = xnt) {
5171 dns_inet_ntop(ent->af, &ent->addr, addr, sizeof addr);
5175 for (i = strlen(addr); i < INET_ADDRSTRLEN; i++)
5180 fputs(ent->host, fp);
5185 } /* dns_hosts_dump() */
5188 int dns_hosts_insert(struct dns_hosts *hosts, int af, const void *addr, const void *host, _Bool alias) {
5189 struct dns_hosts_entry *ent;
5192 if (!(ent = malloc(sizeof *ent)))
5195 dns_d_anchor(ent->host, sizeof ent->host, host, strlen(host));
5197 switch ((ent->af = af)) {
5199 memcpy(&ent->addr.a6, addr, sizeof ent->addr.a6);
5201 dns_aaaa_arpa(ent->arpa, sizeof ent->arpa, addr);
5205 memcpy(&ent->addr.a4, addr, sizeof ent->addr.a4);
5207 dns_a_arpa(ent->arpa, sizeof ent->arpa, addr);
5220 hosts->tail = &ent->next;
5224 error = dns_syerr();
5229 } /* dns_hosts_insert() */
5232 struct dns_packet *dns_hosts_query(struct dns_hosts *hosts, struct dns_packet *Q, int *error_) {
5233 struct dns_packet *P = dns_p_new(512);
5234 struct dns_packet *A = 0;
5236 struct dns_hosts_entry *ent;
5238 char qname[DNS_D_MAXNAME + 1];
5241 if ((error = dns_rr_parse(&rr, 12, Q)))
5244 if (!(qlen = dns_d_expand(qname, sizeof qname, rr.dn.p, Q, &error)))
5246 else if (qlen >= sizeof qname)
5249 if ((error = dns_p_push(P, DNS_S_QD, qname, qlen, rr.type, rr.class, 0, 0)))
5254 for (ent = hosts->head; ent; ent = ent->next) {
5255 if (ent->alias || 0 != strcasecmp(qname, ent->arpa))
5258 if ((error = dns_p_push(P, DNS_S_AN, qname, qlen, rr.type, rr.class, 0, ent->host)))
5270 loop: for (ent = hosts->head; ent; ent = ent->next) {
5271 if (ent->af != af || 0 != strcasecmp(qname, ent->host))
5274 if ((error = dns_p_push(P, DNS_S_AN, qname, qlen, rr.type, rr.class, 0, &ent->addr)))
5284 if (!(A = dns_p_copy(dns_p_make(P->end, &error), P)))
5289 error = DNS_EILLEGAL;
5296 } /* dns_hosts_query() */
5300 * R E S O L V . C O N F R O U T I N E S
5302 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5304 struct dns_resolv_conf *dns_resconf_open(int *error) {
5305 static const struct dns_resolv_conf resconf_initializer = {
5307 .family = { AF_INET, AF_INET6 },
5308 .options = { .ndots = 1, .timeout = 5, .attempts = 2, .tcp = DNS_RESCONF_TCP_ENABLE, },
5309 .iface = { .ss_family = AF_INET },
5311 struct dns_resolv_conf *resconf;
5312 struct sockaddr_in *sin;
5314 if (!(resconf = malloc(sizeof *resconf)))
5317 *resconf = resconf_initializer;
5319 sin = (struct sockaddr_in *)&resconf->nameserver[0];
5320 sin->sin_family = AF_INET;
5321 sin->sin_addr.s_addr = INADDR_ANY;
5322 sin->sin_port = htons(53);
5324 sin->sin_len = sizeof *sin;
5327 if (0 != gethostname(resconf->search[0], sizeof resconf->search[0]))
5330 dns_d_anchor(resconf->search[0], sizeof resconf->search[0], resconf->search[0], strlen(resconf->search[0]));
5331 dns_d_cleave(resconf->search[0], sizeof resconf->search[0], resconf->search[0], strlen(resconf->search[0]));
5334 * XXX: If gethostname() returned a string without any label
5335 * separator, then search[0][0] should be NUL.
5338 dns_resconf_acquire(resconf);
5342 *error = dns_syerr();
5347 } /* dns_resconf_open() */
5350 void dns_resconf_close(struct dns_resolv_conf *resconf) {
5351 if (!resconf || 1 != dns_resconf_release(resconf))
5355 } /* dns_resconf_close() */
5358 dns_refcount_t dns_resconf_acquire(struct dns_resolv_conf *resconf) {
5359 return dns_atomic_fetch_add(&resconf->_.refcount);
5360 } /* dns_resconf_acquire() */
5363 dns_refcount_t dns_resconf_release(struct dns_resolv_conf *resconf) {
5364 return dns_atomic_fetch_sub(&resconf->_.refcount);
5365 } /* dns_resconf_release() */
5368 struct dns_resolv_conf *dns_resconf_mortal(struct dns_resolv_conf *resconf) {
5370 dns_resconf_release(resconf);
5373 } /* dns_resconf_mortal() */
5376 struct dns_resolv_conf *dns_resconf_local(int *error_) {
5377 struct dns_resolv_conf *resconf;
5380 if (!(resconf = dns_resconf_open(&error)))
5383 if ((error = dns_resconf_loadpath(resconf, "/etc/resolv.conf"))) {
5385 * NOTE: Both the glibc and BIND9 resolvers ignore a missing
5386 * /etc/resolv.conf, defaulting to a nameserver of
5387 * 127.0.0.1. See also dns_hints_insert_resconf, and the
5388 * default initialization of nameserver[0] in
5391 if (error != ENOENT)
5395 if ((error = dns_nssconf_loadpath(resconf, "/etc/nsswitch.conf"))) {
5396 if (error != ENOENT)
5404 dns_resconf_close(resconf);
5407 } /* dns_resconf_local() */
5410 struct dns_resolv_conf *dns_resconf_root(int *error) {
5411 struct dns_resolv_conf *resconf;
5413 if ((resconf = dns_resconf_local(error)))
5414 resconf->options.recurse = 1;
5417 } /* dns_resconf_root() */
5420 static time_t dns_resconf_timeout(const struct dns_resolv_conf *resconf) {
5421 return (time_t)DNS_PP_MIN(INT_MAX, resconf->options.timeout);
5422 } /* dns_resconf_timeout() */
5425 enum dns_resconf_keyword {
5426 DNS_RESCONF_NAMESERVER,
5436 DNS_RESCONF_OPTIONS,
5439 DNS_RESCONF_TIMEOUT,
5440 DNS_RESCONF_ATTEMPTS,
5442 DNS_RESCONF_RECURSE,
5446 DNS_RESCONF_INTERFACE,
5451 DNS_RESCONF_DISABLE,
5452 }; /* enum dns_resconf_keyword */
5454 static enum dns_resconf_keyword dns_resconf_keyword(const char *word) {
5455 static const char *words[] = {
5456 [DNS_RESCONF_NAMESERVER] = "nameserver",
5457 [DNS_RESCONF_DOMAIN] = "domain",
5458 [DNS_RESCONF_SEARCH] = "search",
5459 [DNS_RESCONF_LOOKUP] = "lookup",
5460 [DNS_RESCONF_FILE] = "file",
5461 [DNS_RESCONF_BIND] = "bind",
5462 [DNS_RESCONF_CACHE] = "cache",
5463 [DNS_RESCONF_FAMILY] = "family",
5464 [DNS_RESCONF_INET4] = "inet4",
5465 [DNS_RESCONF_INET6] = "inet6",
5466 [DNS_RESCONF_OPTIONS] = "options",
5467 [DNS_RESCONF_EDNS0] = "edns0",
5468 [DNS_RESCONF_ROTATE] = "rotate",
5469 [DNS_RESCONF_RECURSE] = "recurse",
5470 [DNS_RESCONF_SMART] = "smart",
5471 [DNS_RESCONF_TCP] = "tcp",
5472 [DNS_RESCONF_INTERFACE] = "interface",
5473 [DNS_RESCONF_ZERO] = "0",
5474 [DNS_RESCONF_ONE] = "1",
5475 [DNS_RESCONF_ENABLE] = "enable",
5476 [DNS_RESCONF_ONLY] = "only",
5477 [DNS_RESCONF_DISABLE] = "disable",
5481 for (i = 0; i < lengthof(words); i++) {
5482 if (words[i] && 0 == strcasecmp(words[i], word))
5486 if (0 == strncasecmp(word, "ndots:", sizeof "ndots:" - 1))
5487 return DNS_RESCONF_NDOTS;
5489 if (0 == strncasecmp(word, "timeout:", sizeof "timeout:" - 1))
5490 return DNS_RESCONF_TIMEOUT;
5492 if (0 == strncasecmp(word, "attempts:", sizeof "attempts:" - 1))
5493 return DNS_RESCONF_ATTEMPTS;
5495 if (0 == strncasecmp(word, "tcp:", sizeof "tcp:" - 1))
5496 return DNS_RESCONF_TCPx;
5499 } /* dns_resconf_keyword() */
5502 /** OpenBSD-style "[1.2.3.4]:53" nameserver syntax */
5503 int dns_resconf_pton(struct sockaddr_storage *ss, const char *src) {
5504 struct { char buf[128], *p; } addr = { "", addr.buf };
5505 unsigned short port = 0;
5506 int ch, af = AF_INET, error;
5508 while ((ch = *src++)) {
5517 while ((ch = *src++)) {
5518 if (dns_isdigit(ch)) {
5530 if (addr.p < endof(addr.buf) - 1)
5538 if ((error = dns_pton(af, addr.buf, dns_sa_addr(af, ss, NULL))))
5541 port = (!port)? 53 : port;
5542 *dns_sa_port(af, ss) = htons(port);
5543 dns_sa_family(ss) = af;
5546 } /* dns_resconf_pton() */
5548 #define dns_resconf_issep(ch) (dns_isspace(ch) || (ch) == ',')
5549 #define dns_resconf_iscom(ch) ((ch) == '#' || (ch) == ';')
5551 int dns_resconf_loadfile(struct dns_resolv_conf *resconf, FILE *fp) {
5552 unsigned sa_count = 0;
5553 char words[6][DNS_D_MAXNAME + 1];
5554 unsigned wp, wc, i, j, n;
5560 memset(words, '\0', sizeof words);
5564 while (EOF != (ch = getc(fp)) && ch != '\n') {
5565 if (dns_resconf_issep(ch)) {
5569 if (++wc >= lengthof(words))
5572 } else if (dns_resconf_iscom(ch)) {
5576 } while (ch != EOF && ch != '\n');
5579 } else if (wp < sizeof words[wc] - 1) {
5580 words[wc][wp++] = ch;
5582 wp = 0; /* drop word */
5593 switch (dns_resconf_keyword(words[0])) {
5594 case DNS_RESCONF_NAMESERVER:
5595 if (sa_count >= lengthof(resconf->nameserver))
5598 if ((error = dns_resconf_pton(&resconf->nameserver[sa_count], words[1])))
5604 case DNS_RESCONF_DOMAIN:
5605 case DNS_RESCONF_SEARCH:
5606 memset(resconf->search, '\0', sizeof resconf->search);
5608 for (i = 1, j = 0; i < wc && j < lengthof(resconf->search); i++, j++)
5609 dns_d_anchor(resconf->search[j], sizeof resconf->search[j], words[i], strlen(words[i]));
5612 case DNS_RESCONF_LOOKUP:
5613 for (i = 1, j = 0; i < wc && j < lengthof(resconf->lookup); i++) {
5614 switch (dns_resconf_keyword(words[i])) {
5615 case DNS_RESCONF_FILE:
5616 resconf->lookup[j++] = 'f';
5619 case DNS_RESCONF_BIND:
5620 resconf->lookup[j++] = 'b';
5623 case DNS_RESCONF_CACHE:
5624 resconf->lookup[j++] = 'c';
5633 case DNS_RESCONF_FAMILY:
5634 for (i = 1, j = 0; i < wc && j < lengthof(resconf->family); i++) {
5635 switch (dns_resconf_keyword(words[i])) {
5636 case DNS_RESCONF_INET4:
5637 resconf->family[j++] = AF_INET;
5640 case DNS_RESCONF_INET6:
5641 resconf->family[j++] = AF_INET6;
5650 case DNS_RESCONF_OPTIONS:
5651 for (i = 1; i < wc; i++) {
5652 switch (dns_resconf_keyword(words[i])) {
5653 case DNS_RESCONF_EDNS0:
5654 resconf->options.edns0 = 1;
5657 case DNS_RESCONF_NDOTS:
5658 for (j = sizeof "ndots:" - 1, n = 0; dns_isdigit(words[i][j]); j++) {
5660 n += words[i][j] - '0';
5663 resconf->options.ndots = n;
5666 case DNS_RESCONF_TIMEOUT:
5667 for (j = sizeof "timeout:" - 1, n = 0; dns_isdigit(words[i][j]); j++) {
5669 n += words[i][j] - '0';
5672 resconf->options.timeout = n;
5675 case DNS_RESCONF_ATTEMPTS:
5676 for (j = sizeof "attempts:" - 1, n = 0; dns_isdigit(words[i][j]); j++) {
5678 n += words[i][j] - '0';
5681 resconf->options.attempts = n;
5684 case DNS_RESCONF_ROTATE:
5685 resconf->options.rotate = 1;
5688 case DNS_RESCONF_RECURSE:
5689 resconf->options.recurse = 1;
5692 case DNS_RESCONF_SMART:
5693 resconf->options.smart = 1;
5696 case DNS_RESCONF_TCP:
5697 resconf->options.tcp = DNS_RESCONF_TCP_ONLY;
5700 case DNS_RESCONF_TCPx:
5701 switch (dns_resconf_keyword(&words[i][sizeof "tcp:" - 1])) {
5702 case DNS_RESCONF_ENABLE:
5703 resconf->options.tcp = DNS_RESCONF_TCP_ENABLE;
5706 case DNS_RESCONF_ONE:
5707 case DNS_RESCONF_ONLY:
5708 resconf->options.tcp = DNS_RESCONF_TCP_ONLY;
5711 case DNS_RESCONF_ZERO:
5712 case DNS_RESCONF_DISABLE:
5713 resconf->options.tcp = DNS_RESCONF_TCP_DISABLE;
5727 case DNS_RESCONF_INTERFACE:
5728 for (i = 0, n = 0; dns_isdigit(words[2][i]); i++) {
5730 n += words[2][i] - '0';
5733 dns_resconf_setiface(resconf, words[1], n);
5739 } while (ch != EOF);
5742 } /* dns_resconf_loadfile() */
5745 int dns_resconf_loadpath(struct dns_resolv_conf *resconf, const char *path) {
5749 if (!(fp = dns_fopen(path, "rt", &error)))
5752 error = dns_resconf_loadfile(resconf, fp);
5757 } /* dns_resconf_loadpath() */
5760 struct dns_anyconf {
5763 char buffer[1024], *tp, *cp;
5764 }; /* struct dns_anyconf */
5767 static void dns_anyconf_reset(struct dns_anyconf *cf) {
5769 cf->tp = cf->cp = cf->buffer;
5770 } /* dns_anyconf_reset() */
5773 static int dns_anyconf_push(struct dns_anyconf *cf) {
5774 if (!(cf->cp < endof(cf->buffer) && cf->count < lengthof(cf->token)))
5778 cf->token[cf->count++] = cf->tp;
5782 } /* dns_anyconf_push() */
5785 static void dns_anyconf_pop(struct dns_anyconf *cf) {
5786 if (cf->count > 0) {
5788 cf->tp = cf->cp = cf->token[cf->count];
5789 cf->token[cf->count] = 0;
5791 } /* dns_anyconf_pop() */
5794 static int dns_anyconf_addc(struct dns_anyconf *cf, int ch) {
5795 if (!(cf->cp < endof(cf->buffer)))
5801 } /* dns_anyconf_addc() */
5804 static _Bool dns_anyconf_match(const char *pat, int mc) {
5815 while ((pc = *(const unsigned char *)pat++)) {
5818 if (!(pc = *(const unsigned char *)pat++))
5823 if (dns_isalpha(mc))
5827 if (dns_isdigit(mc))
5831 if (dns_isalnum(mc))
5835 if (dns_isspace(mc))
5853 } /* dns_anyconf_match() */
5856 static int dns_anyconf_peek(FILE *fp) {
5861 } /* dns_anyconf_peek() */
5864 static size_t dns_anyconf_skip(const char *pat, FILE *fp) {
5868 while (EOF != (ch = getc(fp))) {
5869 if (dns_anyconf_match(pat, ch)) {
5880 } /* dns_anyconf_skip() */
5883 static size_t dns_anyconf_scan(struct dns_anyconf *cf, const char *pat, FILE *fp, int *error) {
5887 while (EOF != (ch = getc(fp))) {
5888 if (dns_anyconf_match(pat, ch)) {
5889 if ((*error = dns_anyconf_addc(cf, ch)))
5900 if ((len = cf->cp - cf->tp)) {
5901 if ((*error = dns_anyconf_push(cf)))
5910 } /* dns_anyconf_scan() */
5913 DNS_NOTUSED static void dns_anyconf_dump(struct dns_anyconf *cf, FILE *fp) {
5916 fprintf(fp, "tokens:");
5918 for (i = 0; i < cf->count; i++) {
5919 fprintf(fp, " %s", cf->token[i]);
5923 } /* dns_anyconf_dump() */
5926 enum dns_nssconf_keyword {
5927 DNS_NSSCONF_INVALID = 0,
5928 DNS_NSSCONF_HOSTS = 1,
5929 DNS_NSSCONF_SUCCESS,
5930 DNS_NSSCONF_NOTFOUND,
5931 DNS_NSSCONF_UNAVAIL,
5932 DNS_NSSCONF_TRYAGAIN,
5933 DNS_NSSCONF_CONTINUE,
5940 }; /* enum dns_nssconf_keyword */
5942 static enum dns_nssconf_keyword dns_nssconf_keyword(const char *word) {
5943 static const char *list[] = {
5944 [DNS_NSSCONF_HOSTS] = "hosts",
5945 [DNS_NSSCONF_SUCCESS] = "success",
5946 [DNS_NSSCONF_NOTFOUND] = "notfound",
5947 [DNS_NSSCONF_UNAVAIL] = "unavail",
5948 [DNS_NSSCONF_TRYAGAIN] = "tryagain",
5949 [DNS_NSSCONF_CONTINUE] = "continue",
5950 [DNS_NSSCONF_RETURN] = "return",
5951 [DNS_NSSCONF_FILES] = "files",
5952 [DNS_NSSCONF_DNS] = "dns",
5953 [DNS_NSSCONF_MDNS] = "mdns",
5957 for (i = 1; i < lengthof(list); i++) {
5958 if (list[i] && 0 == strcasecmp(list[i], word))
5962 return DNS_NSSCONF_INVALID;
5963 } /* dns_nssconf_keyword() */
5966 static enum dns_nssconf_keyword dns_nssconf_c2k(int ch) {
5967 static const char map[] = {
5968 ['S'] = DNS_NSSCONF_SUCCESS,
5969 ['N'] = DNS_NSSCONF_NOTFOUND,
5970 ['U'] = DNS_NSSCONF_UNAVAIL,
5971 ['T'] = DNS_NSSCONF_TRYAGAIN,
5972 ['C'] = DNS_NSSCONF_CONTINUE,
5973 ['R'] = DNS_NSSCONF_RETURN,
5974 ['f'] = DNS_NSSCONF_FILES,
5975 ['F'] = DNS_NSSCONF_FILES,
5976 ['d'] = DNS_NSSCONF_DNS,
5977 ['D'] = DNS_NSSCONF_DNS,
5978 ['b'] = DNS_NSSCONF_DNS,
5979 ['B'] = DNS_NSSCONF_DNS,
5980 ['m'] = DNS_NSSCONF_MDNS,
5981 ['M'] = DNS_NSSCONF_MDNS,
5984 return (ch >= 0 && ch < (int)lengthof(map))? map[ch] : DNS_NSSCONF_INVALID;
5985 } /* dns_nssconf_c2k() */
5991 static int dns_nssconf_k2c(int k) {
5992 static const char map[DNS_NSSCONF_LAST] = {
5993 [DNS_NSSCONF_SUCCESS] = 'S',
5994 [DNS_NSSCONF_NOTFOUND] = 'N',
5995 [DNS_NSSCONF_UNAVAIL] = 'U',
5996 [DNS_NSSCONF_TRYAGAIN] = 'T',
5997 [DNS_NSSCONF_CONTINUE] = 'C',
5998 [DNS_NSSCONF_RETURN] = 'R',
5999 [DNS_NSSCONF_FILES] = 'f',
6000 [DNS_NSSCONF_DNS] = 'b',
6001 [DNS_NSSCONF_MDNS] = 'm',
6004 return (k >= 0 && k < (int)lengthof(map))? (map[k]? map[k] : '?') : '?';
6005 } /* dns_nssconf_k2c() */
6007 static const char *dns_nssconf_k2s(int k) {
6008 static const char *const map[DNS_NSSCONF_LAST] = {
6009 [DNS_NSSCONF_SUCCESS] = "SUCCESS",
6010 [DNS_NSSCONF_NOTFOUND] = "NOTFOUND",
6011 [DNS_NSSCONF_UNAVAIL] = "UNAVAIL",
6012 [DNS_NSSCONF_TRYAGAIN] = "TRYAGAIN",
6013 [DNS_NSSCONF_CONTINUE] = "continue",
6014 [DNS_NSSCONF_RETURN] = "return",
6015 [DNS_NSSCONF_FILES] = "files",
6016 [DNS_NSSCONF_DNS] = "dns",
6017 [DNS_NSSCONF_MDNS] = "mdns",
6020 return (k >= 0 && k < (int)lengthof(map))? (map[k]? map[k] : "") : "";
6021 } /* dns_nssconf_k2s() */
6026 int dns_nssconf_loadfile(struct dns_resolv_conf *resconf, FILE *fp) {
6027 enum dns_nssconf_keyword source, status, action;
6028 char lookup[sizeof resconf->lookup] = "", *lp;
6029 struct dns_anyconf cf;
6033 while (!feof(fp) && !ferror(fp)) {
6034 dns_anyconf_reset(&cf);
6036 dns_anyconf_skip("%s", fp);
6038 if (!dns_anyconf_scan(&cf, "%w_", fp, &error))
6041 if (DNS_NSSCONF_HOSTS != dns_nssconf_keyword(cf.token[0]))
6044 dns_anyconf_pop(&cf);
6046 if (!dns_anyconf_skip(": \t", fp))
6049 *(lp = lookup) = '\0';
6051 while (dns_anyconf_scan(&cf, "%w_", fp, &error)) {
6052 dns_anyconf_skip(" \t", fp);
6054 if ('[' == dns_anyconf_peek(fp)) {
6055 dns_anyconf_skip("[ \t", fp);
6057 while (dns_anyconf_scan(&cf, "%w_", fp, &error)) {
6058 dns_anyconf_skip("= \t", fp);
6059 if (!dns_anyconf_scan(&cf, "%w_", fp, &error)) {
6060 dns_anyconf_pop(&cf); /* discard status */
6061 dns_anyconf_skip("^#;]\n", fp); /* skip to end of criteria */
6064 dns_anyconf_skip(" \t", fp);
6067 dns_anyconf_skip("] \t", fp);
6070 if ((size_t)(endof(lookup) - lp) < cf.count + 1) /* +1 for '\0' */
6073 source = dns_nssconf_keyword(cf.token[0]);
6076 case DNS_NSSCONF_DNS:
6077 case DNS_NSSCONF_MDNS:
6078 case DNS_NSSCONF_FILES:
6079 *lp++ = dns_nssconf_k2c(source);
6085 for (i = 1; i + 1 < cf.count; i += 2) {
6086 status = dns_nssconf_keyword(cf.token[i]);
6087 action = dns_nssconf_keyword(cf.token[i + 1]);
6090 case DNS_NSSCONF_SUCCESS:
6091 case DNS_NSSCONF_NOTFOUND:
6092 case DNS_NSSCONF_UNAVAIL:
6093 case DNS_NSSCONF_TRYAGAIN:
6094 *lp++ = dns_nssconf_k2c(status);
6101 case DNS_NSSCONF_CONTINUE:
6102 case DNS_NSSCONF_RETURN:
6105 action = (status == DNS_NSSCONF_SUCCESS)
6106 ? DNS_NSSCONF_RETURN
6107 : DNS_NSSCONF_CONTINUE;
6111 *lp++ = dns_nssconf_k2c(action);
6115 dns_anyconf_reset(&cf);
6118 dns_anyconf_skip("^\n", fp);
6122 strncpy(resconf->lookup, lookup, sizeof resconf->lookup);
6125 } /* dns_nssconf_loadfile() */
6128 int dns_nssconf_loadpath(struct dns_resolv_conf *resconf, const char *path) {
6132 if (!(fp = dns_fopen(path, "rt", &error)))
6135 error = dns_nssconf_loadfile(resconf, fp);
6140 } /* dns_nssconf_loadpath() */
6143 struct dns_nssconf_source {
6144 enum dns_nssconf_keyword source, success, notfound, unavail, tryagain;
6145 }; /* struct dns_nssconf_source */
6147 typedef unsigned dns_nssconf_i;
6149 static inline int dns_nssconf_peek(const struct dns_resolv_conf *resconf, dns_nssconf_i state) {
6150 return (state < lengthof(resconf->lookup) && resconf->lookup[state])? resconf->lookup[state] : 0;
6151 } /* dns_nssconf_peek() */
6153 static _Bool dns_nssconf_next(struct dns_nssconf_source *src, const struct dns_resolv_conf *resconf, dns_nssconf_i *state) {
6154 int source, status, action;
6156 src->source = DNS_NSSCONF_INVALID;
6157 src->success = DNS_NSSCONF_RETURN;
6158 src->notfound = DNS_NSSCONF_CONTINUE;
6159 src->unavail = DNS_NSSCONF_CONTINUE;
6160 src->tryagain = DNS_NSSCONF_CONTINUE;
6162 while ((source = dns_nssconf_peek(resconf, *state))) {
6163 source = dns_nssconf_c2k(source);
6167 case DNS_NSSCONF_FILES:
6168 case DNS_NSSCONF_DNS:
6169 case DNS_NSSCONF_MDNS:
6170 src->source = source;
6176 while ((status = dns_nssconf_peek(resconf, *state)) && (action = dns_nssconf_peek(resconf, *state + 1))) {
6177 status = dns_nssconf_c2k(status);
6178 action = dns_nssconf_c2k(action);
6181 case DNS_NSSCONF_RETURN:
6182 case DNS_NSSCONF_CONTINUE:
6189 case DNS_NSSCONF_SUCCESS:
6190 src->success = action;
6192 case DNS_NSSCONF_NOTFOUND:
6193 src->notfound = action;
6195 case DNS_NSSCONF_UNAVAIL:
6196 src->unavail = action;
6198 case DNS_NSSCONF_TRYAGAIN:
6199 src->tryagain = action;
6211 return src->source != DNS_NSSCONF_INVALID;
6212 } /* dns_nssconf_next() */
6215 static int dns_nssconf_dump_status(int status, int action, unsigned *count, FILE *fp) {
6217 case DNS_NSSCONF_SUCCESS:
6218 if (action == DNS_NSSCONF_RETURN)
6222 if (action == DNS_NSSCONF_CONTINUE)
6232 fprintf(fp, "%s=%s", dns_nssconf_k2s(status), dns_nssconf_k2s(action));
6237 } /* dns_nssconf_dump_status() */
6240 int dns_nssconf_dump(struct dns_resolv_conf *resconf, FILE *fp) {
6241 struct dns_nssconf_source src;
6242 dns_nssconf_i i = 0;
6244 fputs("hosts:", fp);
6246 while (dns_nssconf_next(&src, resconf, &i)) {
6249 fprintf(fp, " %s", dns_nssconf_k2s(src.source));
6251 dns_nssconf_dump_status(DNS_NSSCONF_SUCCESS, src.success, &n, fp);
6252 dns_nssconf_dump_status(DNS_NSSCONF_NOTFOUND, src.notfound, &n, fp);
6253 dns_nssconf_dump_status(DNS_NSSCONF_UNAVAIL, src.unavail, &n, fp);
6254 dns_nssconf_dump_status(DNS_NSSCONF_TRYAGAIN, src.tryagain, &n, fp);
6263 } /* dns_nssconf_dump() */
6266 int dns_resconf_setiface(struct dns_resolv_conf *resconf, const char *addr, unsigned short port) {
6267 int af = (strchr(addr, ':'))? AF_INET6 : AF_INET;
6270 if ((error = dns_pton(af, addr, dns_sa_addr(af, &resconf->iface, NULL))))
6273 *dns_sa_port(af, &resconf->iface) = htons(port);
6274 resconf->iface.ss_family = af;
6277 } /* dns_resconf_setiface() */
6280 #define DNS_SM_RESTORE \
6282 pc = 0xff & (*state >> 0); \
6283 srchi = 0xff & (*state >> 8); \
6284 ndots = 0xff & (*state >> 16); \
6287 #define DNS_SM_SAVE \
6289 *state = ((0xff & pc) << 0) \
6290 | ((0xff & srchi) << 8) \
6291 | ((0xff & ndots) << 16); \
6294 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) {
6295 unsigned pc, srchi, ndots, len;
6299 /* if FQDN then return as-is and finish */
6300 if (dns_d_isanchored(qname, qlen)) {
6301 len = dns_d_anchor(dst, lim, qname, qlen);
6306 ndots = dns_d_ndots(qname, qlen);
6308 if (ndots >= resconf->options.ndots) {
6309 len = dns_d_anchor(dst, lim, qname, qlen);
6313 while (srchi < lengthof(resconf->search) && resconf->search[srchi][0]) {
6314 struct dns_buf buf = DNS_B_INTO(dst, lim);
6315 const char *dn = resconf->search[srchi++];
6317 dns_b_put(&buf, qname, qlen);
6318 dns_b_putc(&buf, '.');
6319 dns_b_puts(&buf, dn);
6320 if (!dns_d_isanchored(dn, strlen(dn)))
6321 dns_b_putc(&buf, '.');
6322 len = dns_b_strllen(&buf);
6326 if (ndots < resconf->options.ndots) {
6327 len = dns_d_anchor(dst, lim, qname, qlen);
6333 return dns_strlcpy(dst, "", lim);
6334 } /* dns_resconf_search() */
6337 #undef DNS_SM_RESTORE
6340 int dns_resconf_dump(struct dns_resolv_conf *resconf, FILE *fp) {
6344 for (i = 0; i < lengthof(resconf->nameserver) && (af = resconf->nameserver[i].ss_family) != AF_UNSPEC; i++) {
6345 char addr[INET6_ADDRSTRLEN + 1] = "[INVALID]";
6346 unsigned short port;
6348 dns_inet_ntop(af, dns_sa_addr(af, &resconf->nameserver[i], NULL), addr, sizeof addr);
6349 port = ntohs(*dns_sa_port(af, &resconf->nameserver[i]));
6352 fprintf(fp, "nameserver %s\n", addr);
6354 fprintf(fp, "nameserver [%s]:%hu\n", addr, port);
6358 fprintf(fp, "search");
6360 for (i = 0; i < lengthof(resconf->search) && resconf->search[i][0]; i++)
6361 fprintf(fp, " %s", resconf->search[i]);
6367 dns_nssconf_dump(resconf, fp);
6369 fprintf(fp, "lookup");
6371 for (i = 0; i < lengthof(resconf->lookup) && resconf->lookup[i]; i++) {
6372 switch (resconf->lookup[i]) {
6374 fprintf(fp, " bind"); break;
6376 fprintf(fp, " file"); break;
6378 fprintf(fp, " cache"); break;
6385 fprintf(fp, "options ndots:%u timeout:%u attempts:%u", resconf->options.ndots, resconf->options.timeout, resconf->options.attempts);
6387 if (resconf->options.edns0)
6388 fprintf(fp, " edns0");
6389 if (resconf->options.rotate)
6390 fprintf(fp, " rotate");
6391 if (resconf->options.recurse)
6392 fprintf(fp, " recurse");
6393 if (resconf->options.smart)
6394 fprintf(fp, " smart");
6396 switch (resconf->options.tcp) {
6397 case DNS_RESCONF_TCP_ENABLE:
6399 case DNS_RESCONF_TCP_ONLY:
6400 fprintf(fp, " tcp");
6402 case DNS_RESCONF_TCP_SOCKS:
6403 fprintf(fp, " tcp:socks");
6405 case DNS_RESCONF_TCP_DISABLE:
6406 fprintf(fp, " tcp:disable");
6413 if ((af = resconf->iface.ss_family) != AF_UNSPEC) {
6414 char addr[INET6_ADDRSTRLEN + 1] = "[INVALID]";
6416 dns_inet_ntop(af, dns_sa_addr(af, &resconf->iface, NULL), addr, sizeof addr);
6418 fprintf(fp, "interface %s %hu\n", addr, ntohs(*dns_sa_port(af, &resconf->iface)));
6422 } /* dns_resconf_dump() */
6426 * H I N T S E R V E R R O U T I N E S
6428 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6430 struct dns_hints_soa {
6431 unsigned char zone[DNS_D_MAXNAME + 1];
6434 struct sockaddr_storage ss;
6440 struct dns_hints_soa *next;
6441 }; /* struct dns_hints_soa */
6445 dns_atomic_t refcount;
6447 struct dns_hints_soa *head;
6448 }; /* struct dns_hints */
6451 struct dns_hints *dns_hints_open(struct dns_resolv_conf *resconf, int *error) {
6452 static const struct dns_hints H_initializer;
6453 struct dns_hints *H;
6457 if (!(H = malloc(sizeof *H)))
6462 dns_hints_acquire(H);
6466 *error = dns_syerr();
6471 } /* dns_hints_open() */
6474 void dns_hints_close(struct dns_hints *H) {
6475 struct dns_hints_soa *soa, *nxt;
6477 if (!H || 1 != dns_hints_release(H))
6480 for (soa = H->head; soa; soa = nxt) {
6489 } /* dns_hints_close() */
6492 dns_refcount_t dns_hints_acquire(struct dns_hints *H) {
6493 return dns_atomic_fetch_add(&H->refcount);
6494 } /* dns_hints_acquire() */
6497 dns_refcount_t dns_hints_release(struct dns_hints *H) {
6498 return dns_atomic_fetch_sub(&H->refcount);
6499 } /* dns_hints_release() */
6502 struct dns_hints *dns_hints_mortal(struct dns_hints *hints) {
6504 dns_hints_release(hints);
6507 } /* dns_hints_mortal() */
6510 struct dns_hints *dns_hints_local(struct dns_resolv_conf *resconf, int *error_) {
6511 struct dns_hints *hints = 0;
6515 dns_resconf_acquire(resconf);
6516 else if (!(resconf = dns_resconf_local(&error)))
6519 if (!(hints = dns_hints_open(resconf, &error)))
6524 if (0 == dns_hints_insert_resconf(hints, ".", resconf, &error) && error)
6527 dns_resconf_close(resconf);
6533 dns_resconf_close(resconf);
6534 dns_hints_close(hints);
6537 } /* dns_hints_local() */
6540 struct dns_hints *dns_hints_root(struct dns_resolv_conf *resconf, int *error_) {
6541 static const struct {
6543 char addr[INET6_ADDRSTRLEN];
6545 { AF_INET, "198.41.0.4" }, /* A.ROOT-SERVERS.NET. */
6546 { AF_INET6, "2001:503:ba3e::2:30" }, /* A.ROOT-SERVERS.NET. */
6547 { AF_INET, "192.228.79.201" }, /* B.ROOT-SERVERS.NET. */
6548 { AF_INET6, "2001:500:84::b" }, /* B.ROOT-SERVERS.NET. */
6549 { AF_INET, "192.33.4.12" }, /* C.ROOT-SERVERS.NET. */
6550 { AF_INET6, "2001:500:2::c" }, /* C.ROOT-SERVERS.NET. */
6551 { AF_INET, "199.7.91.13" }, /* D.ROOT-SERVERS.NET. */
6552 { AF_INET6, "2001:500:2d::d" }, /* D.ROOT-SERVERS.NET. */
6553 { AF_INET, "192.203.230.10" }, /* E.ROOT-SERVERS.NET. */
6554 { AF_INET, "192.5.5.241" }, /* F.ROOT-SERVERS.NET. */
6555 { AF_INET6, "2001:500:2f::f" }, /* F.ROOT-SERVERS.NET. */
6556 { AF_INET, "192.112.36.4" }, /* G.ROOT-SERVERS.NET. */
6557 { AF_INET, "128.63.2.53" }, /* H.ROOT-SERVERS.NET. */
6558 { AF_INET6, "2001:500:1::803f:235" }, /* H.ROOT-SERVERS.NET. */
6559 { AF_INET, "192.36.148.17" }, /* I.ROOT-SERVERS.NET. */
6560 { AF_INET6, "2001:7FE::53" }, /* I.ROOT-SERVERS.NET. */
6561 { AF_INET, "192.58.128.30" }, /* J.ROOT-SERVERS.NET. */
6562 { AF_INET6, "2001:503:c27::2:30" }, /* J.ROOT-SERVERS.NET. */
6563 { AF_INET, "193.0.14.129" }, /* K.ROOT-SERVERS.NET. */
6564 { AF_INET6, "2001:7FD::1" }, /* K.ROOT-SERVERS.NET. */
6565 { AF_INET, "199.7.83.42" }, /* L.ROOT-SERVERS.NET. */
6566 { AF_INET6, "2001:500:3::42" }, /* L.ROOT-SERVERS.NET. */
6567 { AF_INET, "202.12.27.33" }, /* M.ROOT-SERVERS.NET. */
6568 { AF_INET6, "2001:DC3::35" }, /* M.ROOT-SERVERS.NET. */
6570 struct dns_hints *hints = 0;
6571 struct sockaddr_storage ss;
6575 if (!(hints = dns_hints_open(resconf, &error)))
6578 for (i = 0; i < lengthof(root_hints); i++) {
6579 af = root_hints[i].af;
6581 if ((error = dns_pton(af, root_hints[i].addr, dns_sa_addr(af, &ss, NULL))))
6584 *dns_sa_port(af, &ss) = htons(53);
6587 if ((error = dns_hints_insert(hints, ".", (struct sockaddr *)&ss, 1)))
6595 dns_hints_close(hints);
6598 } /* dns_hints_root() */
6601 static struct dns_hints_soa *dns_hints_fetch(struct dns_hints *H, const char *zone) {
6602 struct dns_hints_soa *soa;
6604 for (soa = H->head; soa; soa = soa->next) {
6605 if (0 == strcasecmp(zone, (char *)soa->zone))
6610 } /* dns_hints_fetch() */
6613 int dns_hints_insert(struct dns_hints *H, const char *zone, const struct sockaddr *sa, unsigned priority) {
6614 static const struct dns_hints_soa soa_initializer;
6615 struct dns_hints_soa *soa;
6618 if (!(soa = dns_hints_fetch(H, zone))) {
6619 if (!(soa = malloc(sizeof *soa)))
6621 *soa = soa_initializer;
6622 dns_strlcpy((char *)soa->zone, zone, sizeof soa->zone);
6624 soa->next = H->head;
6628 i = soa->count % lengthof(soa->addrs);
6630 memcpy(&soa->addrs[i].ss, sa, dns_sa_len(sa));
6632 soa->addrs[i].priority = DNS_PP_MAX(1, priority);
6634 if (soa->count < lengthof(soa->addrs))
6638 } /* dns_hints_insert() */
6641 static _Bool dns_hints_isinaddr_any(const void *sa) {
6642 struct in_addr *addr;
6644 if (dns_sa_family(sa) != AF_INET)
6647 addr = dns_sa_addr(AF_INET, sa, NULL);
6648 return addr->s_addr == htonl(INADDR_ANY);
6651 unsigned dns_hints_insert_resconf(struct dns_hints *H, const char *zone, const struct dns_resolv_conf *resconf, int *error_) {
6655 for (i = 0, n = 0, p = 1; i < lengthof(resconf->nameserver) && resconf->nameserver[i].ss_family != AF_UNSPEC; i++, n++) {
6656 union { struct sockaddr_in sin; } tmp;
6657 struct sockaddr *ns;
6660 * dns_resconf_open initializes nameserver[0] to INADDR_ANY.
6662 * Traditionally the semantics of 0.0.0.0 meant the default
6663 * interface, which evolved to mean the loopback interface.
6664 * See comment block preceding resolv/res_init.c:res_init in
6665 * glibc 2.23. As of 2.23, glibc no longer translates
6666 * 0.0.0.0 despite the code comment, but it does default to
6667 * 127.0.0.1 when no nameservers are present.
6669 * BIND9 as of 9.10.3 still translates 0.0.0.0 to 127.0.0.1.
6670 * See lib/lwres/lwconfig.c:lwres_create_addr and the
6671 * convert_zero flag. 127.0.0.1 is also the default when no
6672 * nameservers are present.
6674 if (dns_hints_isinaddr_any(&resconf->nameserver[i])) {
6675 memcpy(&tmp.sin, &resconf->nameserver[i], sizeof tmp.sin);
6676 tmp.sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
6677 ns = (struct sockaddr *)&tmp.sin;
6679 ns = (struct sockaddr *)&resconf->nameserver[i];
6682 if ((error = dns_hints_insert(H, zone, ns, p)))
6685 p += !resconf->options.rotate;
6693 } /* dns_hints_insert_resconf() */
6696 static int dns_hints_i_cmp(unsigned a, unsigned b, struct dns_hints_i *i, struct dns_hints_soa *soa) {
6699 if ((cmp = soa->addrs[a].priority - soa->addrs[b].priority))
6702 return dns_k_shuffle16(a, i->state.seed) - dns_k_shuffle16(b, i->state.seed);
6703 } /* dns_hints_i_cmp() */
6706 static unsigned dns_hints_i_start(struct dns_hints_i *i, struct dns_hints_soa *soa) {
6711 for (p = 1; p < soa->count; p++) {
6712 if (dns_hints_i_cmp(p, p0, i, soa) < 0)
6717 } /* dns_hints_i_start() */
6720 static unsigned dns_hints_i_skip(unsigned p0, struct dns_hints_i *i, struct dns_hints_soa *soa) {
6723 for (pZ = 0; pZ < soa->count; pZ++) {
6724 if (dns_hints_i_cmp(pZ, p0, i, soa) > 0)
6730 for (p = pZ + 1; p < soa->count; p++) {
6731 if (dns_hints_i_cmp(p, p0, i, soa) <= 0)
6734 if (dns_hints_i_cmp(p, pZ, i, soa) >= 0)
6742 } /* dns_hints_i_skip() */
6745 static struct dns_hints_i *dns_hints_i_init(struct dns_hints_i *i, struct dns_hints *hints) {
6746 static const struct dns_hints_i i_initializer;
6747 struct dns_hints_soa *soa;
6749 i->state = i_initializer.state;
6752 i->state.seed = dns_random();
6753 } while (0 == i->state.seed);
6755 if ((soa = dns_hints_fetch(hints, i->zone))) {
6756 i->state.next = dns_hints_i_start(i, soa);
6760 } /* dns_hints_i_init() */
6763 unsigned dns_hints_grep(struct sockaddr **sa, socklen_t *sa_len, unsigned lim, struct dns_hints_i *i, struct dns_hints *H) {
6764 struct dns_hints_soa *soa;
6767 if (!(soa = dns_hints_fetch(H, i->zone)))
6772 while (i->state.next < soa->count && n < lim) {
6773 *sa = (struct sockaddr *)&soa->addrs[i->state.next].ss;
6774 *sa_len = dns_sa_len(*sa);
6780 i->state.next = dns_hints_i_skip(i->state.next, i, soa);
6784 } /* dns_hints_grep() */
6787 struct dns_packet *dns_hints_query(struct dns_hints *hints, struct dns_packet *Q, int *error_) {
6788 struct dns_packet *A, *P;
6790 char zone[DNS_D_MAXNAME + 1];
6792 struct dns_hints_i i;
6793 struct sockaddr *sa;
6797 if (!dns_rr_grep(&rr, 1, dns_rr_i_new(Q, .section = DNS_S_QUESTION), Q, &error))
6800 if (!(zlen = dns_d_expand(zone, sizeof zone, rr.dn.p, Q, &error)))
6802 else if (zlen >= sizeof zone)
6806 dns_header(P)->qr = 1;
6808 if ((error = dns_rr_copy(P, &rr, Q)))
6811 if ((error = dns_p_push(P, DNS_S_AUTHORITY, ".", strlen("."), DNS_T_NS, DNS_C_IN, 0, "hints.local.")))
6817 dns_hints_i_init(&i, hints);
6819 while (dns_hints_grep(&sa, &slen, 1, &i, hints)) {
6820 int af = sa->sa_family;
6821 int rtype = (af == AF_INET6)? DNS_T_AAAA : DNS_T_A;
6823 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))))
6826 } while ((zlen = dns_d_cleave(zone, sizeof zone, zone, zlen)));
6828 if (!(A = dns_p_copy(dns_p_make(P->end, &error), P)))
6833 error = DNS_EILLEGAL;
6838 } /* dns_hints_query() */
6841 /** ugly hack to support specifying ports other than 53 in resolv.conf. */
6842 static unsigned short dns_hints_port(struct dns_hints *hints, int af, void *addr) {
6843 struct dns_hints_soa *soa;
6846 unsigned short port;
6849 for (soa = hints->head; soa; soa = soa->next) {
6850 for (i = 0; i < soa->count; i++) {
6851 if (af != soa->addrs[i].ss.ss_family)
6854 if (!(addrsoa = dns_sa_addr(af, &soa->addrs[i].ss, &addrlen)))
6857 if (memcmp(addr, addrsoa, addrlen))
6860 port = *dns_sa_port(af, &soa->addrs[i].ss);
6862 return (port)? port : htons(53);
6867 } /* dns_hints_port() */
6870 int dns_hints_dump(struct dns_hints *hints, FILE *fp) {
6871 struct dns_hints_soa *soa;
6872 char addr[INET6_ADDRSTRLEN];
6876 for (soa = hints->head; soa; soa = soa->next) {
6877 fprintf(fp, "ZONE \"%s\"\n", soa->zone);
6879 for (i = 0; i < soa->count; i++) {
6880 af = soa->addrs[i].ss.ss_family;
6882 if ((error = dns_ntop(af, dns_sa_addr(af, &soa->addrs[i].ss, NULL), addr, sizeof addr)))
6885 fprintf(fp, "\t(%d) [%s]:%hu\n", (int)soa->addrs[i].priority, addr, ntohs(*dns_sa_port(af, &soa->addrs[i].ss)));
6890 } /* dns_hints_dump() */
6894 * C A C H E R O U T I N E S
6896 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6898 static dns_refcount_t dns_cache_acquire(struct dns_cache *cache) {
6899 return dns_atomic_fetch_add(&cache->_.refcount);
6900 } /* dns_cache_acquire() */
6903 static dns_refcount_t dns_cache_release(struct dns_cache *cache) {
6904 return dns_atomic_fetch_sub(&cache->_.refcount);
6905 } /* dns_cache_release() */
6908 static struct dns_packet *dns_cache_query(struct dns_packet *query, struct dns_cache *cache, int *error) {
6914 } /* dns_cache_query() */
6917 static int dns_cache_submit(struct dns_packet *query, struct dns_cache *cache) {
6922 } /* dns_cache_submit() */
6925 static int dns_cache_check(struct dns_cache *cache) {
6929 } /* dns_cache_check() */
6932 static struct dns_packet *dns_cache_fetch(struct dns_cache *cache, int *error) {
6937 } /* dns_cache_fetch() */
6940 static int dns_cache_pollfd(struct dns_cache *cache) {
6944 } /* dns_cache_pollfd() */
6947 static short dns_cache_events(struct dns_cache *cache) {
6951 } /* dns_cache_events() */
6954 static void dns_cache_clear(struct dns_cache *cache) {
6958 } /* dns_cache_clear() */
6961 struct dns_cache *dns_cache_init(struct dns_cache *cache) {
6962 static const struct dns_cache c_init = {
6963 .acquire = &dns_cache_acquire,
6964 .release = &dns_cache_release,
6965 .query = &dns_cache_query,
6966 .submit = &dns_cache_submit,
6967 .check = &dns_cache_check,
6968 .fetch = &dns_cache_fetch,
6969 .pollfd = &dns_cache_pollfd,
6970 .events = &dns_cache_events,
6971 .clear = &dns_cache_clear,
6972 ._ = { .refcount = 1, },
6978 } /* dns_cache_init() */
6981 void dns_cache_close(struct dns_cache *cache) {
6983 cache->release(cache);
6984 } /* dns_cache_close() */
6988 * S O C K E T R O U T I N E S
6990 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6992 static void dns_socketclose(int *fd, const struct dns_options *opts) {
6993 if (opts && opts->closefd.cb)
6994 opts->closefd.cb(fd, opts->closefd.arg);
7004 } /* dns_socketclose() */
7007 #ifndef HAVE_IOCTLSOCKET
7008 #define HAVE_IOCTLSOCKET (_WIN32 || _WIN64)
7011 #ifndef HAVE_SOCK_CLOEXEC
7012 #define HAVE_SOCK_CLOEXEC (defined SOCK_CLOEXEC)
7015 #ifndef HAVE_SOCK_NONBLOCK
7016 #define HAVE_SOCK_NONBLOCK (defined SOCK_NONBLOCK)
7019 #define DNS_SO_MAXTRY 7
7021 static int dns_socket(struct sockaddr *local, int type, int *error_) {
7022 int fd = -1, flags, error;
7028 #if HAVE_SOCK_CLOEXEC
7029 flags |= SOCK_CLOEXEC;
7031 #if HAVE_SOCK_NONBLOCK
7032 flags |= SOCK_NONBLOCK;
7034 if (-1 == (fd = socket(local->sa_family, type|flags, 0)))
7037 #if defined F_SETFD && !HAVE_SOCK_CLOEXEC
7038 if (-1 == fcntl(fd, F_SETFD, 1))
7042 #if defined O_NONBLOCK && !HAVE_SOCK_NONBLOCK
7043 if (-1 == (flags = fcntl(fd, F_GETFL)))
7045 if (-1 == fcntl(fd, F_SETFL, flags | O_NONBLOCK))
7047 #elif defined FIONBIO && HAVE_IOCTLSOCKET
7049 if (0 != ioctlsocket(fd, FIONBIO, &opt))
7053 #if defined SO_NOSIGPIPE
7054 if (type != SOCK_DGRAM) {
7055 if (0 != setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &(int){ 1 }, sizeof (int)))
7060 if (local->sa_family != AF_INET && local->sa_family != AF_INET6)
7063 if (type != SOCK_DGRAM)
7067 * FreeBSD, Linux, OpenBSD, OS X, and Solaris use random ports by
7068 * default. Though the ephemeral range is quite small on OS X
7069 * (49152-65535 on 10.10) and Linux (32768-60999 on 4.4.0, Ubuntu
7070 * Xenial). See also RFC 6056.
7072 * TODO: Optionally rely on the kernel to select a random port.
7074 if (*dns_sa_port(local->sa_family, local) == 0) {
7075 struct sockaddr_storage tmp;
7078 memcpy(&tmp, local, dns_sa_len(local));
7080 for (i = 0; i < DNS_SO_MAXTRY; i++) {
7081 port = 1025 + (dns_random() % 64510);
7083 *dns_sa_port(tmp.ss_family, &tmp) = htons(port);
7085 if (0 == bind(fd, (struct sockaddr *)&tmp, dns_sa_len(&tmp)))
7089 /* NB: continue to next bind statement */
7092 if (0 == bind(fd, local, dns_sa_len(local)))
7097 error = dns_soerr();
7100 #if (defined F_SETFD && !HAVE_SOCK_CLOEXEC) || (defined O_NONBLOCK && !HAVE_SOCK_NONBLOCK)
7102 error = dns_syerr();
7109 dns_socketclose(&fd, NULL);
7112 } /* dns_socket() */
7116 DNS_SO_UDP_INIT = 1,
7130 DNS_SO_SOCKS_HELLO_SEND,
7131 DNS_SO_SOCKS_HELLO_RECV,
7132 DNS_SO_SOCKS_AUTH_SEND,
7133 DNS_SO_SOCKS_AUTH_RECV,
7134 DNS_SO_SOCKS_REQUEST_PREPARE,
7135 DNS_SO_SOCKS_REQUEST_SEND,
7136 DNS_SO_SOCKS_REQUEST_RECV,
7137 DNS_SO_SOCKS_REQUEST_RECV_V6,
7138 DNS_SO_SOCKS_HANDSHAKE_DONE,
7142 struct dns_options opts;
7148 unsigned onum, olim;
7152 struct sockaddr_storage local, remote;
7154 struct dns_k_permutor qids;
7156 struct dns_stat stat;
7158 struct dns_trace *trace;
7161 * NOTE: dns_so_reset() zeroes everything from here down.
7166 char qname[DNS_D_MAXNAME + 1];
7168 enum dns_type qtype;
7169 enum dns_class qclass;
7171 struct dns_packet *query;
7174 /* During a SOCKS handshake the query is temporarily stored
7176 struct dns_packet *query_backup;
7178 struct dns_clock elapsed;
7180 struct dns_packet *answer;
7182 }; /* struct dns_socket */
7186 * NOTE: Actual closure delayed so that kqueue(2) and epoll(2) callers have
7187 * a chance to recognize a state change after installing a persistent event
7188 * and where sequential descriptors with the same integer value returned
7189 * from _pollfd() would be ambiguous. See dns_so_closefds().
7191 static int dns_so_closefd(struct dns_socket *so, int *fd) {
7197 if (so->opts.closefd.cb) {
7198 if ((error = so->opts.closefd.cb(fd, so->opts.closefd.arg))) {
7200 } else if (*fd == -1)
7204 if (!(so->onum < so->olim)) {
7205 unsigned olim = DNS_PP_MAX(4, so->olim * 2);
7208 if (!(old = realloc(so->old, sizeof so->old[0] * olim)))
7215 so->old[so->onum++] = *fd;
7219 } /* dns_so_closefd() */
7222 #define DNS_SO_CLOSE_UDP 0x01
7223 #define DNS_SO_CLOSE_TCP 0x02
7224 #define DNS_SO_CLOSE_OLD 0x04
7225 #define DNS_SO_CLOSE_ALL (DNS_SO_CLOSE_UDP|DNS_SO_CLOSE_TCP|DNS_SO_CLOSE_OLD)
7227 static void dns_so_closefds(struct dns_socket *so, int which) {
7228 if (DNS_SO_CLOSE_UDP & which)
7229 dns_socketclose(&so->udp, &so->opts);
7230 if (DNS_SO_CLOSE_TCP & which)
7231 dns_socketclose(&so->tcp, &so->opts);
7232 if (DNS_SO_CLOSE_OLD & which) {
7234 for (i = 0; i < so->onum; i++)
7235 dns_socketclose(&so->old[i], &so->opts);
7241 } /* dns_so_closefds() */
7244 static void dns_so_destroy(struct dns_socket *);
7246 static struct dns_socket *dns_so_init(struct dns_socket *so, const struct sockaddr *local, int type, const struct dns_options *opts, int *error) {
7247 static const struct dns_socket so_initializer = { .opts = DNS_OPTS_INITIALIZER, .udp = -1, .tcp = -1, };
7249 *so = so_initializer;
7256 memcpy(&so->local, local, dns_sa_len(local));
7258 if (-1 == (so->udp = dns_socket((struct sockaddr *)&so->local, SOCK_DGRAM, error)))
7261 dns_k_permutor_init(&so->qids, 1, 65535);
7268 } /* dns_so_init() */
7271 struct dns_socket *dns_so_open(const struct sockaddr *local, int type, const struct dns_options *opts, int *error) {
7272 struct dns_socket *so;
7274 if (!(so = malloc(sizeof *so)))
7277 if (!dns_so_init(so, local, type, opts, error))
7282 *error = dns_syerr();
7287 } /* dns_so_open() */
7290 static void dns_so_destroy(struct dns_socket *so) {
7292 dns_so_closefds(so, DNS_SO_CLOSE_ALL);
7293 dns_trace_close(so->trace);
7294 } /* dns_so_destroy() */
7297 void dns_so_close(struct dns_socket *so) {
7304 } /* dns_so_close() */
7307 void dns_so_reset(struct dns_socket *so) {
7308 dns_p_setptr(&so->answer, NULL);
7310 memset(&so->state, '\0', sizeof *so - offsetof(struct dns_socket, state));
7311 } /* dns_so_reset() */
7314 unsigned short dns_so_mkqid(struct dns_socket *so) {
7315 return dns_k_permutor_step(&so->qids);
7316 } /* dns_so_mkqid() */
7319 #define DNS_SO_MINBUF 768
7321 static int dns_so_newanswer(struct dns_socket *so, size_t len) {
7322 size_t size = offsetof(struct dns_packet, data) + DNS_PP_MAX(len, DNS_SO_MINBUF);
7325 if (!(p = realloc(so->answer, size)))
7328 so->answer = dns_p_init(p, size);
7331 } /* dns_so_newanswer() */
7334 int dns_so_submit(struct dns_socket *so, struct dns_packet *Q, struct sockaddr *host) {
7336 int error = DNS_EUNKNOWN;
7340 if ((error = dns_rr_parse(&rr, 12, Q)))
7343 if (!(so->qlen = dns_d_expand(so->qname, sizeof so->qname, rr.dn.p, Q, &error)))
7346 * NOTE: Don't bail if expansion is too long; caller may be
7347 * intentionally sending long names. However, we won't be able to
7348 * verify it on return.
7351 so->qtype = rr.type;
7352 so->qclass = rr.class;
7354 if ((error = dns_so_newanswer(so, (Q->memo.opt.maxudp)? Q->memo.opt.maxudp : DNS_SO_MINBUF)))
7357 memcpy(&so->remote, host, dns_sa_len(host));
7362 dns_begin(&so->elapsed);
7364 if (dns_header(so->query)->qid == 0)
7365 dns_header(so->query)->qid = dns_so_mkqid(so);
7367 so->qid = dns_header(so->query)->qid;
7368 so->state = (so->opts.socks_host && so->opts.socks_host->ss_family) ? DNS_SO_SOCKS_INIT :
7369 (so->type == SOCK_STREAM)? DNS_SO_TCP_INIT : DNS_SO_UDP_INIT;
7372 dns_trace_so_submit(so->trace, Q, host, 0);
7376 error = dns_syerr();
7379 dns_trace_so_submit(so->trace, Q, host, error);
7381 } /* dns_so_submit() */
7384 static int dns_so_verify(struct dns_socket *so, struct dns_packet *P) {
7385 char qname[DNS_D_MAXNAME + 1];
7393 if (so->qid != dns_header(P)->qid)
7396 if (!dns_p_count(P, DNS_S_QD))
7399 if (0 != dns_rr_parse(&rr, 12, P))
7402 if (rr.type != so->qtype || rr.class != so->qclass)
7405 if (!(qlen = dns_d_expand(qname, sizeof qname, rr.dn.p, P, &error)))
7407 else if (qlen >= sizeof qname || qlen != so->qlen)
7410 if (0 != strcasecmp(so->qname, qname))
7413 dns_trace_so_verify(so->trace, P, 0);
7417 error = DNS_EVERIFY;
7419 DNS_SHOW(P, "rejecting packet (%s)", dns_strerror(error));
7420 dns_trace_so_verify(so->trace, P, error);
7423 } /* dns_so_verify() */
7426 static _Bool dns_so_tcp_keep(struct dns_socket *so) {
7427 struct sockaddr_storage remote;
7432 if (0 != getpeername(so->tcp, (struct sockaddr *)&remote, &(socklen_t){ sizeof remote }))
7435 return 0 == dns_sa_cmp(&remote, &so->remote);
7436 } /* dns_so_tcp_keep() */
7439 /* Convenience functions for sending non-DNS data. */
7441 /* Set up everything for sending LENGTH octets. Returns the buffer
7443 static unsigned char *dns_so_tcp_send_buffer(struct dns_socket *so, size_t length) {
7444 /* Skip the length octets, we are not doing DNS. */
7446 so->query->end = length;
7447 return so->query->data;
7450 /* Set up everything for receiving LENGTH octets. */
7451 static void dns_so_tcp_recv_expect(struct dns_socket *so, size_t length) {
7452 /* Skip the length octets, we are not doing DNS. */
7457 /* Returns the buffer containing the received data. */
7458 static unsigned char *dns_so_tcp_recv_buffer(struct dns_socket *so) {
7459 return so->answer->data;
7463 #if defined __clang__
7464 #pragma clang diagnostic push
7465 #pragma clang diagnostic ignored "-Warray-bounds"
7468 static int dns_so_tcp_send(struct dns_socket *so) {
7469 unsigned char *qsrc;
7474 so->query->data[-2] = 0xff & (so->query->end >> 8);
7475 so->query->data[-1] = 0xff & (so->query->end >> 0);
7477 qend = so->query->end + 2;
7479 while (so->qout < qend) {
7480 qsrc = &so->query->data[-2] + so->qout;
7481 n = dns_send_nopipe(so->tcp, (void *)qsrc, qend - so->qout, 0, &error);
7482 dns_trace_sys_send(so->trace, so->tcp, SOCK_STREAM, qsrc, n, error);
7486 so->stat.tcp.sent.bytes += n;
7489 so->stat.tcp.sent.count++;
7492 } /* dns_so_tcp_send() */
7495 static int dns_so_tcp_recv(struct dns_socket *so) {
7496 unsigned char *asrc;
7497 size_t aend, alen, n;
7500 aend = so->alen + 2;
7502 while (so->apos < aend) {
7503 asrc = &so->answer->data[-2];
7505 n = dns_recv(so->tcp, (void *)&asrc[so->apos], aend - so->apos, 0, &error);
7506 dns_trace_sys_recv(so->trace, so->tcp, SOCK_STREAM, &asrc[so->apos], n, error);
7511 so->stat.tcp.rcvd.bytes += n;
7513 if (so->alen == 0 && so->apos >= 2) {
7514 alen = ((0xff & so->answer->data[-2]) << 8)
7515 | ((0xff & so->answer->data[-1]) << 0);
7517 if ((error = dns_so_newanswer(so, alen)))
7525 so->answer->end = so->alen;
7526 so->stat.tcp.rcvd.count++;
7529 } /* dns_so_tcp_recv() */
7532 #pragma clang diagnostic pop
7536 int dns_so_check(struct dns_socket *so) {
7539 unsigned char *buffer;
7542 switch (so->state) {
7543 case DNS_SO_UDP_INIT:
7545 case DNS_SO_UDP_CONN:
7546 error = dns_connect(so->udp, (struct sockaddr *)&so->remote, dns_sa_len(&so->remote));
7547 dns_trace_sys_connect(so->trace, so->udp, SOCK_DGRAM, (struct sockaddr *)&so->remote, error);
7552 case DNS_SO_UDP_SEND:
7553 n = dns_send(so->udp, (void *)so->query->data, so->query->end, 0, &error);
7554 dns_trace_sys_send(so->trace, so->udp, SOCK_DGRAM, so->query->data, n, error);
7558 so->stat.udp.sent.bytes += n;
7559 so->stat.udp.sent.count++;
7562 case DNS_SO_UDP_RECV:
7563 n = dns_recv(so->udp, (void *)so->answer->data, so->answer->size, 0, &error);
7564 dns_trace_sys_recv(so->trace, so->udp, SOCK_DGRAM, so->answer->data, n, error);
7568 so->answer->end = n;
7569 so->stat.udp.rcvd.bytes += n;
7570 so->stat.udp.rcvd.count++;
7572 if ((error = dns_so_verify(so, so->answer)))
7576 case DNS_SO_UDP_DONE:
7577 if (!dns_header(so->answer)->tc || so->type == SOCK_DGRAM)
7581 case DNS_SO_TCP_INIT:
7582 if (dns_so_tcp_keep(so)) {
7583 so->state = DNS_SO_TCP_SEND;
7588 if ((error = dns_so_closefd(so, &so->tcp)))
7591 if (-1 == (so->tcp = dns_socket((struct sockaddr *)&so->local, SOCK_STREAM, &error)))
7595 case DNS_SO_TCP_CONN:
7596 error = dns_connect(so->tcp, (struct sockaddr *)&so->remote, dns_sa_len(&so->remote));
7597 dns_trace_sys_connect(so->trace, so->tcp, SOCK_STREAM, (struct sockaddr *)&so->remote, error);
7598 if (error && error != DNS_EISCONN)
7602 case DNS_SO_TCP_SEND:
7603 if ((error = dns_so_tcp_send(so)))
7607 case DNS_SO_TCP_RECV:
7608 if ((error = dns_so_tcp_recv(so)))
7612 case DNS_SO_TCP_DONE:
7613 /* close unless DNS_RESCONF_TCP_ONLY (see dns_res_tcp2type) */
7614 if (so->type != SOCK_STREAM) {
7615 if ((error = dns_so_closefd(so, &so->tcp)))
7619 if ((error = dns_so_verify(so, so->answer)))
7623 case DNS_SO_SOCKS_INIT:
7624 if ((error = dns_so_closefd(so, &so->tcp)))
7627 if (-1 == (so->tcp = dns_socket((struct sockaddr *)&so->local, SOCK_STREAM, &error)))
7631 case DNS_SO_SOCKS_CONN: {
7632 unsigned char method;
7634 error = dns_connect(so->tcp, (struct sockaddr *)so->opts.socks_host, dns_sa_len(so->opts.socks_host));
7635 dns_trace_sys_connect(so->trace, so->tcp, SOCK_STREAM, (struct sockaddr *)so->opts.socks_host, error);
7636 if (error && error != DNS_EISCONN)
7639 /* We need to do a handshake with the SOCKS server,
7640 * but the query is already in the buffer. Move it
7641 * out of the way. */
7642 dns_p_movptr(&so->query_backup, &so->query);
7644 /* Create a new buffer for the handshake. */
7645 dns_p_grow(&so->query);
7647 /* Negotiate method. */
7648 buffer = dns_so_tcp_send_buffer(so, 3);
7649 buffer[0] = 5; /* RFC-1928 VER field. */
7650 buffer[1] = 1; /* NMETHODS */
7651 if (so->opts.socks_user)
7652 method = 2; /* Method: username/password authentication. */
7654 method = 0; /* Method: No authentication required. */
7659 case DNS_SO_SOCKS_HELLO_SEND:
7660 if ((error = dns_so_tcp_send(so)))
7663 dns_so_tcp_recv_expect(so, 2);
7665 case DNS_SO_SOCKS_HELLO_RECV: {
7666 unsigned char method;
7668 if ((error = dns_so_tcp_recv(so)))
7671 buffer = dns_so_tcp_recv_buffer(so);
7672 method = so->opts.socks_user ? 2 : 0;
7673 if (buffer[0] != 5 || buffer[1] != method) {
7674 /* Socks server returned wrong version or does
7675 not support our requested method. */
7676 error = ENOTSUP; /* Fixme: Is there a better errno? */
7681 /* No authentication, go ahead and send the
7683 so->state = DNS_SO_SOCKS_REQUEST_PREPARE;
7687 /* Prepare username/password sub-negotiation. */
7688 if (! so->opts.socks_password) {
7689 error = EINVAL; /* No password given. */
7692 size_t buflen, ulen, plen;
7694 ulen = strlen(so->opts.socks_user);
7695 plen = strlen(so->opts.socks_password);
7696 if (!ulen || ulen > 255 || !plen || plen > 255) {
7697 error = EINVAL; /* Credentials too long or too short. */
7701 buffer = dns_so_tcp_send_buffer(so, 3 + ulen + plen);
7702 buffer[0] = 1; /* VER of the sub-negotiation. */
7703 buffer[1] = (unsigned char) ulen;
7705 memcpy (buffer+buflen, so->opts.socks_user, ulen);
7707 buffer[buflen++] = (unsigned char) plen;
7708 memcpy (buffer+buflen, so->opts.socks_password, plen);
7713 case DNS_SO_SOCKS_AUTH_SEND:
7714 if ((error = dns_so_tcp_send(so)))
7717 /* Skip the two length octets, and receive two octets. */
7718 dns_so_tcp_recv_expect(so, 2);
7721 case DNS_SO_SOCKS_AUTH_RECV:
7722 if ((error = dns_so_tcp_recv(so)))
7725 buffer = dns_so_tcp_recv_buffer(so);
7726 if (buffer[0] != 1) {
7727 /* SOCKS server returned wrong version. */
7732 /* SOCKS server denied access. */
7738 case DNS_SO_SOCKS_REQUEST_PREPARE:
7739 /* Send request details (rfc-1928, 4). */
7740 buffer = dns_so_tcp_send_buffer(so, so->remote.ss_family == AF_INET6 ? 22 : 10);
7741 buffer[0] = 5; /* VER */
7742 buffer[1] = 1; /* CMD = CONNECT */
7743 buffer[2] = 0; /* RSV */
7744 if (so->remote.ss_family == AF_INET6) {
7745 struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)&so->remote;
7747 buffer[3] = 4; /* ATYP = IPv6 */
7748 memcpy (buffer+ 4, &addr_in6->sin6_addr.s6_addr, 16); /* DST.ADDR */
7749 memcpy (buffer+20, &addr_in6->sin6_port, 2); /* DST.PORT */
7751 struct sockaddr_in *addr_in = (struct sockaddr_in *)&so->remote;
7753 buffer[3] = 1; /* ATYP = IPv4 */
7754 memcpy (buffer+4, &addr_in->sin_addr.s_addr, 4); /* DST.ADDR */
7755 memcpy (buffer+8, &addr_in->sin_port, 2); /* DST.PORT */
7759 case DNS_SO_SOCKS_REQUEST_SEND:
7760 if ((error = dns_so_tcp_send(so)))
7763 /* Expect ten octets. This is the length of the
7764 * response assuming a IPv4 address is used. */
7765 dns_so_tcp_recv_expect(so, 10);
7767 case DNS_SO_SOCKS_REQUEST_RECV:
7768 if ((error = dns_so_tcp_recv(so)))
7771 buffer = dns_so_tcp_recv_buffer(so);
7772 if (buffer[0] != 5 || buffer[2] != 0) {
7773 /* Socks server returned wrong version or the
7774 reserved field is not zero. */
7779 switch (buffer[1]) {
7780 case 0x01: /* general SOCKS server failure. */
7783 case 0x02: /* connection not allowed by ruleset. */
7786 case 0x03: /* Network unreachable */
7787 error = ENETUNREACH;
7789 case 0x04: /* Host unreachable */
7790 error = EHOSTUNREACH;
7792 case 0x05: /* Connection refused */
7793 error = ECONNREFUSED;
7795 case 0x06: /* TTL expired */
7798 case 0x08: /* Address type not supported */
7799 error = EPROTONOSUPPORT;
7801 case 0x07: /* Command not supported */
7803 error = ENOTSUP; /* Fixme: Is there a better error? */
7809 if (buffer[3] == 1) {
7810 /* This was indeed an IPv4 address. */
7811 so->state = DNS_SO_SOCKS_HANDSHAKE_DONE;
7815 if (buffer[3] != 4) {
7820 /* Expect receive twelve octets. This accounts for
7821 * the remaining bytes assuming an IPv6 address is
7823 dns_so_tcp_recv_expect(so, 12);
7825 case DNS_SO_SOCKS_REQUEST_RECV_V6:
7826 if ((error = dns_so_tcp_recv(so)))
7830 case DNS_SO_SOCKS_HANDSHAKE_DONE:
7831 /* We have not way to store the actual address used by
7832 * the server. Then again, we don't really care. */
7834 /* Restore the query. */
7835 dns_p_movptr(&so->query, &so->query_backup);
7837 /* Reset cursors. */
7842 /* SOCKS handshake is done. Proceed with the
7844 so->state = DNS_SO_TCP_SEND;
7847 error = DNS_EUNKNOWN;
7853 DNS_CARP("discarding packet");
7859 case DNS_EINPROGRESS:
7863 #if DNS_EWOULDBLOCK != DNS_EAGAIN
7864 case DNS_EWOULDBLOCK:
7873 } /* dns_so_check() */
7876 struct dns_packet *dns_so_fetch(struct dns_socket *so, int *error) {
7877 struct dns_packet *answer;
7879 switch (so->state) {
7880 case DNS_SO_UDP_DONE:
7881 case DNS_SO_TCP_DONE:
7882 answer = so->answer;
7884 dns_trace_so_fetch(so->trace, answer, 0);
7888 *error = DNS_EUNKNOWN;
7889 dns_trace_so_fetch(so->trace, NULL, *error);
7893 } /* dns_so_fetch() */
7896 struct dns_packet *dns_so_query(struct dns_socket *so, struct dns_packet *Q, struct sockaddr *host, int *error_) {
7897 struct dns_packet *A;
7901 if ((error = dns_so_submit(so, Q, host)))
7905 if ((error = dns_so_check(so)))
7908 if (!(A = dns_so_fetch(so, &error)))
7918 } /* dns_so_query() */
7921 time_t dns_so_elapsed(struct dns_socket *so) {
7922 return dns_elapsed(&so->elapsed);
7923 } /* dns_so_elapsed() */
7926 void dns_so_clear(struct dns_socket *so) {
7927 dns_so_closefds(so, DNS_SO_CLOSE_OLD);
7928 } /* dns_so_clear() */
7931 static int dns_so_events2(struct dns_socket *so, enum dns_events type) {
7934 switch (so->state) {
7935 case DNS_SO_UDP_CONN:
7936 case DNS_SO_UDP_SEND:
7937 events |= DNS_POLLOUT;
7940 case DNS_SO_UDP_RECV:
7941 events |= DNS_POLLIN;
7944 case DNS_SO_TCP_CONN:
7945 case DNS_SO_TCP_SEND:
7946 events |= DNS_POLLOUT;
7949 case DNS_SO_TCP_RECV:
7950 events |= DNS_POLLIN;
7957 return DNS_POLL2EV(events);
7961 } /* dns_so_events2() */
7964 int dns_so_events(struct dns_socket *so) {
7965 return dns_so_events2(so, so->opts.events);
7966 } /* dns_so_events() */
7969 int dns_so_pollfd(struct dns_socket *so) {
7970 switch (so->state) {
7971 case DNS_SO_UDP_CONN:
7972 case DNS_SO_UDP_SEND:
7973 case DNS_SO_UDP_RECV:
7975 case DNS_SO_TCP_CONN:
7976 case DNS_SO_TCP_SEND:
7977 case DNS_SO_TCP_RECV:
7982 } /* dns_so_pollfd() */
7985 int dns_so_poll(struct dns_socket *so, int timeout) {
7986 return dns_poll(dns_so_pollfd(so), dns_so_events2(so, DNS_SYSPOLL), timeout);
7987 } /* dns_so_poll() */
7990 const struct dns_stat *dns_so_stat(struct dns_socket *so) {
7992 } /* dns_so_stat() */
7995 struct dns_trace *dns_so_trace(struct dns_socket *so) {
7997 } /* dns_so_trace() */
8000 void dns_so_settrace(struct dns_socket *so, struct dns_trace *trace) {
8001 struct dns_trace *otrace = so->trace;
8002 so->trace = dns_trace_acquire_p(trace);
8003 dns_trace_close(otrace);
8004 } /* dns_so_settrace() */
8008 * R E S O L V E R R O U T I N E S
8010 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8012 enum dns_res_state {
8015 DNS_R_SWITCH, /* (B)IND, (F)ILE, (C)ACHE */
8017 DNS_R_FILE, /* Lookup in local hosts database */
8019 DNS_R_CACHE, /* Lookup in application cache */
8024 DNS_R_BIND, /* Lookup in the network */
8029 DNS_R_RESOLV0_NS, /* Prologue: Setup next frame and recurse */
8030 DNS_R_RESOLV1_NS, /* Epilog: Inspect answer */
8041 }; /* enum dns_res_state */
8044 #define DNS_R_MAXDEPTH 8
8045 #define DNS_R_ENDFRAME (DNS_R_MAXDEPTH - 1)
8047 struct dns_resolver {
8048 struct dns_socket so;
8050 struct dns_resolv_conf *resconf;
8051 struct dns_hosts *hosts;
8052 struct dns_hints *hints;
8053 struct dns_cache *cache;
8054 struct dns_trace *trace;
8056 dns_atomic_t refcount;
8058 /* Reset zeroes everything below here. */
8060 char qname[DNS_D_MAXNAME + 1];
8063 enum dns_type qtype;
8064 enum dns_class qclass;
8066 struct dns_clock elapsed;
8068 dns_resconf_i_t search;
8070 struct dns_rr_i smart;
8072 struct dns_packet *nodata; /* answer if nothing better */
8076 struct dns_res_frame {
8077 enum dns_res_state state;
8080 int which; /* (B)IND, (F)ILE; index into resconf->lookup */
8085 struct dns_packet *query, *answer, *hints;
8087 struct dns_rr_i hints_i, hints_j;
8088 struct dns_rr hints_ns, ans_cname;
8089 } stack[DNS_R_MAXDEPTH];
8090 }; /* struct dns_resolver */
8093 static int dns_res_tcp2type(int tcp) {
8095 case DNS_RESCONF_TCP_ONLY:
8096 case DNS_RESCONF_TCP_SOCKS:
8098 case DNS_RESCONF_TCP_DISABLE:
8103 } /* dns_res_tcp2type() */
8105 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) {
8106 static const struct dns_resolver R_initializer
8107 = { .refcount = 1, };
8108 struct dns_resolver *R = 0;
8112 * Grab ref count early because the caller may have passed us a mortal
8113 * reference, and we want to do the right thing if we return early
8117 dns_resconf_acquire(resconf);
8119 dns_hosts_acquire(hosts);
8121 dns_hints_acquire(hints);
8123 dns_cache_acquire(cache);
8126 * Don't try to load it ourselves because a NULL object might be an
8127 * error from, say, dns_resconf_root(), and loading
8128 * dns_resconf_local() by default would create undesirable surpises.
8130 if (!resconf || !hosts || !hints) {
8136 if (!(R = malloc(sizeof *R)))
8140 type = dns_res_tcp2type(resconf->options.tcp);
8142 if (!dns_so_init(&R->so, (struct sockaddr *)&resconf->iface, type, opts, &error))
8145 R->resconf = resconf;
8152 error = dns_syerr();
8158 dns_resconf_close(resconf);
8159 dns_hosts_close(hosts);
8160 dns_hints_close(hints);
8161 dns_cache_close(cache);
8164 } /* dns_res_open() */
8167 struct dns_resolver *dns_res_stub(const struct dns_options *opts, int *error) {
8168 struct dns_resolv_conf *resconf = 0;
8169 struct dns_hosts *hosts = 0;
8170 struct dns_hints *hints = 0;
8171 struct dns_resolver *res = 0;
8173 if (!(resconf = dns_resconf_local(error)))
8176 if (!(hosts = dns_hosts_local(error)))
8179 if (!(hints = dns_hints_local(resconf, error)))
8182 if (!(res = dns_res_open(resconf, hosts, hints, NULL, opts, error)))
8186 dns_resconf_close(resconf);
8187 dns_hosts_close(hosts);
8188 dns_hints_close(hints);
8191 } /* dns_res_stub() */
8194 static void dns_res_frame_destroy(struct dns_resolver *R, struct dns_res_frame *frame) {
8197 dns_p_setptr(&frame->query, NULL);
8198 dns_p_setptr(&frame->answer, NULL);
8199 dns_p_setptr(&frame->hints, NULL);
8200 } /* dns_res_frame_destroy() */
8203 static void dns_res_frame_init(struct dns_resolver *R, struct dns_res_frame *frame) {
8204 memset(frame, '\0', sizeof *frame);
8207 * NB: Can be invoked from dns_res_open, before R->resconf has been
8211 if (!R->resconf->options.recurse)
8212 frame->qflags |= DNS_Q_RD;
8213 if (R->resconf->options.edns0)
8214 frame->qflags |= DNS_Q_EDNS0;
8216 } /* dns_res_frame_init() */
8219 static void dns_res_frame_reset(struct dns_resolver *R, struct dns_res_frame *frame) {
8220 dns_res_frame_destroy(R, frame);
8221 dns_res_frame_init(R, frame);
8222 } /* dns_res_frame_reset() */
8225 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) {
8226 struct dns_packet *P = NULL;
8228 if (!(F < endof(R->stack)))
8229 return DNS_EUNKNOWN;
8231 dns_p_movptr(&P, &F->query);
8232 dns_res_frame_reset(R, F);
8233 dns_p_movptr(&F->query, &P);
8235 return dns_q_make(&F->query, qname, qtype, qclass, F->qflags);
8236 } /* dns_res_frame_prepare() */
8239 void dns_res_reset(struct dns_resolver *R) {
8242 dns_so_reset(&R->so);
8243 dns_p_setptr(&R->nodata, NULL);
8245 for (i = 0; i < lengthof(R->stack); i++)
8246 dns_res_frame_destroy(R, &R->stack[i]);
8248 memset(&R->qname, '\0', sizeof *R - offsetof(struct dns_resolver, qname));
8250 for (i = 0; i < lengthof(R->stack); i++)
8251 dns_res_frame_init(R, &R->stack[i]);
8252 } /* dns_res_reset() */
8255 void dns_res_close(struct dns_resolver *R) {
8256 if (!R || 1 < dns_res_release(R))
8261 dns_so_destroy(&R->so);
8263 dns_hints_close(R->hints);
8264 dns_hosts_close(R->hosts);
8265 dns_resconf_close(R->resconf);
8266 dns_cache_close(R->cache);
8267 dns_trace_close(R->trace);
8270 } /* dns_res_close() */
8273 dns_refcount_t dns_res_acquire(struct dns_resolver *R) {
8274 return dns_atomic_fetch_add(&R->refcount);
8275 } /* dns_res_acquire() */
8278 dns_refcount_t dns_res_release(struct dns_resolver *R) {
8279 return dns_atomic_fetch_sub(&R->refcount);
8280 } /* dns_res_release() */
8283 struct dns_resolver *dns_res_mortal(struct dns_resolver *res) {
8285 dns_res_release(res);
8287 } /* dns_res_mortal() */
8290 static struct dns_packet *dns_res_merge(struct dns_packet *P0, struct dns_packet *P1, int *error_) {
8291 size_t bufsiz = P0->end + P1->end;
8292 struct dns_packet *P[3] = { P0, P1, 0 };
8293 struct dns_rr rr[3];
8295 enum dns_section section;
8298 if (!(P[2] = dns_p_make(bufsiz, &error)))
8301 dns_rr_foreach(&rr[0], P[0], .section = DNS_S_QD) {
8302 if ((error = dns_rr_copy(P[2], &rr[0], P[0])))
8306 for (section = DNS_S_AN; (DNS_S_ALL & section); section <<= 1) {
8307 for (i = 0; i < 2; i++) {
8308 dns_rr_foreach(&rr[i], P[i], .section = section) {
8311 dns_rr_foreach(&rr[2], P[2], .type = rr[i].type, .section = (DNS_S_ALL & ~DNS_S_QD)) {
8312 if (0 == dns_rr_cmp(&rr[i], P[i], &rr[2], P[2])) {
8319 if (copy && (error = dns_rr_copy(P[2], &rr[i], P[i]))) {
8320 if (error == DNS_ENOBUFS && bufsiz < 65535) {
8321 dns_p_setptr(&P[2], NULL);
8323 bufsiz = DNS_PP_MAX(65535, bufsiz * 2);
8331 } /* foreach(packet) */
8332 } /* foreach(section) */
8341 } /* dns_res_merge() */
8344 static struct dns_packet *dns_res_glue(struct dns_resolver *R, struct dns_packet *Q) {
8345 struct dns_packet *P = dns_p_new(512);
8346 char qname[DNS_D_MAXNAME + 1];
8348 enum dns_type qtype;
8353 if (!(qlen = dns_d_expand(qname, sizeof qname, 12, Q, &error))
8354 || qlen >= sizeof qname)
8357 if (!(qtype = dns_rr_type(12, Q)))
8360 if ((error = dns_p_push(P, DNS_S_QD, qname, strlen(qname), qtype, DNS_C_IN, 0, 0)))
8363 for (sp = 0; sp <= R->sp; sp++) {
8364 if (!R->stack[sp].answer)
8367 dns_rr_foreach(&rr, R->stack[sp].answer, .name = qname, .type = qtype, .section = (DNS_S_ALL & ~DNS_S_QD)) {
8368 rr.section = DNS_S_AN;
8370 if ((error = dns_rr_copy(P, &rr, R->stack[sp].answer)))
8375 if (dns_p_count(P, DNS_S_AN) > 0)
8378 /* Otherwise, look for a CNAME */
8379 for (sp = 0; sp <= R->sp; sp++) {
8380 if (!R->stack[sp].answer)
8383 dns_rr_foreach(&rr, R->stack[sp].answer, .name = qname, .type = DNS_T_CNAME, .section = (DNS_S_ALL & ~DNS_S_QD)) {
8384 rr.section = DNS_S_AN;
8386 if ((error = dns_rr_copy(P, &rr, R->stack[sp].answer)))
8391 if (!dns_p_count(P, DNS_S_AN))
8395 return dns_p_copy(dns_p_make(P->end, &error), P);
8396 } /* dns_res_glue() */
8400 * Sort NS records by three criteria:
8402 * 1) Whether glue is present.
8403 * 2) Whether glue record is original or of recursive lookup.
8404 * 3) Randomly shuffle records which share the above criteria.
8406 * NOTE: Assumes only NS records passed, AND ASSUMES no new NS records will
8407 * be added during an iteration.
8409 * FIXME: Only groks A glue, not AAAA glue.
8411 static int dns_res_nameserv_cmp(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) {
8412 _Bool glued[2] = { 0 };
8413 struct dns_rr x = { 0 }, y = { 0 };
8417 if (!(error = dns_ns_parse(&ns, a, P)))
8418 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);
8420 if (!(error = dns_ns_parse(&ns, b, P)))
8421 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);
8423 if ((cmp = glued[1] - glued[0])) {
8425 } else if ((cmp = (dns_rr_offset(&y) < i->args[0]) - (dns_rr_offset(&x) < i->args[0]))) {
8428 return dns_rr_i_shuffle(a, b, i, P);
8430 } /* dns_res_nameserv_cmp() */
8433 #define dgoto(sp, i) \
8434 do { R->stack[(sp)].state = (i); goto exec; } while (0)
8436 static int dns_res_exec(struct dns_resolver *R) {
8437 struct dns_res_frame *F;
8438 struct dns_packet *P;
8440 char host[DNS_D_MAXNAME + 1];
8441 char name[DNS_D_MAXNAME + 1];
8443 struct dns_cname cname;
8451 F = &R->stack[R->sp];
8458 dgoto(R->sp, DNS_R_SWITCH);
8463 if (!(F->answer = dns_res_glue(R, F->query)))
8464 dgoto(R->sp, DNS_R_SWITCH);
8466 if (!(len = dns_d_expand(u.name, sizeof u.name, 12, F->query, &error)))
8468 else if (len >= sizeof u.name)
8471 dns_rr_foreach(&rr, F->answer, .name = u.name, .type = dns_rr_type(12, F->query), .section = DNS_S_AN) {
8472 dgoto(R->sp, DNS_R_FINISH);
8475 dns_rr_foreach(&rr, F->answer, .name = u.name, .type = DNS_T_CNAME, .section = DNS_S_AN) {
8478 dgoto(R->sp, DNS_R_CNAME0_A);
8483 while (F->which < (int)sizeof R->resconf->lookup && R->resconf->lookup[F->which]) {
8484 switch (R->resconf->lookup[F->which++]) {
8486 dgoto(R->sp, DNS_R_BIND);
8488 dgoto(R->sp, DNS_R_FILE);
8491 dgoto(R->sp, DNS_R_CACHE);
8500 * FIXME: Examine more closely whether our logic is correct
8501 * and DNS_R_SERVFAIL is the correct default response.
8503 * Case 1: We got here because we never got an answer on the
8504 * wire. All queries timed-out and we reached maximum
8505 * attempts count. See DNS_R_FOREACH_NS. In that case
8506 * DNS_R_SERVFAIL is the correct state, unless we want to
8507 * return DNS_ETIMEDOUT.
8509 * Case 2: We were a stub resolver and got an unsatisfactory
8510 * answer (empty ANSWER section) which caused us to jump
8511 * back to DNS_R_SEARCH and ultimately to DNS_R_SWITCH. We
8512 * return the answer returned from the wire, which we
8513 * stashed in R->nodata.
8515 * Case 3: We reached maximum attempts count as in case #1,
8516 * but never got an authoritative response which caused us
8517 * to short-circuit. See end of DNS_R_QUERY_A case. We
8518 * should probably prepare R->nodata as in case #2.
8520 if (R->sp == 0 && R->nodata) { /* XXX: can we just return nodata regardless? */
8521 dns_p_movptr(&F->answer, &R->nodata);
8522 dgoto(R->sp, DNS_R_FINISH);
8525 dgoto(R->sp, DNS_R_SERVFAIL);
8528 if (!dns_p_setptr(&F->answer, dns_hosts_query(R->hosts, F->query, &error)))
8531 if (dns_p_count(F->answer, DNS_S_AN) > 0)
8532 dgoto(R->sp, DNS_R_FINISH);
8534 dns_p_setptr(&F->answer, NULL);
8538 while ((len = dns_resconf_search(u.name, sizeof u.name, R->qname, R->qlen, R->resconf, &R->search))) {
8539 if ((error = dns_q_make2(&F->query, u.name, len, R->qtype, R->qclass, F->qflags)))
8542 if (!dns_p_setptr(&F->answer, dns_hosts_query(R->hosts, F->query, &error)))
8545 if (dns_p_count(F->answer, DNS_S_AN) > 0)
8546 dgoto(R->sp, DNS_R_FINISH);
8548 dns_p_setptr(&F->answer, NULL);
8552 dgoto(R->sp, DNS_R_SWITCH);
8556 if (!F->query && (error = dns_q_make(&F->query, R->qname, R->qtype, R->qclass, F->qflags)))
8559 if (dns_p_setptr(&F->answer, R->cache->query(F->query, R->cache, &error))) {
8560 if (dns_p_count(F->answer, DNS_S_AN) > 0)
8561 dgoto(R->sp, DNS_R_FINISH);
8563 dns_p_setptr(&F->answer, NULL);
8565 dgoto(R->sp, DNS_R_SWITCH);
8571 if ((error = R->cache->submit(F->query, R->cache)))
8576 if ((error = R->cache->check(R->cache)))
8583 if (dns_p_setptr(&F->answer, R->cache->fetch(R->cache, &error))) {
8584 if (dns_p_count(F->answer, DNS_S_AN) > 0)
8585 dgoto(R->sp, DNS_R_FINISH);
8587 dns_p_setptr(&F->answer, NULL);
8589 dgoto(R->sp, DNS_R_SWITCH);
8593 dgoto(R->sp, DNS_R_SWITCH);
8599 dgoto(R->sp, DNS_R_HINTS);
8607 * XXX: We probably should only apply the domain search
8608 * algorithm if R->sp == 0.
8610 if (!(len = dns_resconf_search(u.name, sizeof u.name, R->qname, R->qlen, R->resconf, &R->search)))
8611 dgoto(R->sp, DNS_R_SWITCH);
8613 if ((error = dns_q_make2(&F->query, u.name, len, R->qtype, R->qclass, F->qflags)))
8618 if (!dns_p_setptr(&F->hints, dns_hints_query(R->hints, F->query, &error)))
8623 dns_rr_i_init(&F->hints_i, F->hints);
8625 F->hints_i.section = DNS_S_AUTHORITY;
8626 F->hints_i.type = DNS_T_NS;
8627 F->hints_i.sort = &dns_res_nameserv_cmp;
8628 F->hints_i.args[0] = F->hints->end;
8631 case DNS_R_FOREACH_NS:
8632 dns_rr_i_save(&F->hints_i);
8634 /* Load our next nameserver host. */
8635 if (!dns_rr_grep(&F->hints_ns, 1, &F->hints_i, F->hints, &error)) {
8636 if (++F->attempts < R->resconf->options.attempts)
8637 dgoto(R->sp, DNS_R_ITERATE);
8639 dgoto(R->sp, DNS_R_SWITCH);
8642 dns_rr_i_init(&F->hints_j, F->hints);
8644 /* Assume there are glue records */
8645 dgoto(R->sp, DNS_R_FOREACH_A);
8646 case DNS_R_RESOLV0_NS:
8647 /* Have we reached our max depth? */
8648 if (&F[1] >= endof(R->stack))
8649 dgoto(R->sp, DNS_R_FOREACH_NS);
8651 if ((error = dns_ns_parse(&u.ns, &F->hints_ns, F->hints)))
8653 if ((error = dns_res_frame_prepare(R, &F[1], u.ns.host, DNS_T_A, DNS_C_IN)))
8658 dgoto(++R->sp, DNS_R_INIT);
8659 case DNS_R_RESOLV1_NS:
8660 if (!(len = dns_d_expand(u.host, sizeof u.host, 12, F[1].query, &error)))
8662 else if (len >= sizeof u.host)
8665 dns_rr_foreach(&rr, F[1].answer, .name = u.host, .type = DNS_T_A, .section = (DNS_S_ALL & ~DNS_S_QD)) {
8666 rr.section = DNS_S_AR;
8668 if ((error = dns_rr_copy(F->hints, &rr, F[1].answer)))
8671 dns_rr_i_rewind(&F->hints_i); /* Now there's glue. */
8674 dgoto(R->sp, DNS_R_FOREACH_NS);
8675 case DNS_R_FOREACH_A: {
8677 struct sockaddr_in sin;
8680 * NOTE: Iterator initialized in DNS_R_FOREACH_NS because
8681 * this state is re-entrant, but we need to reset
8682 * .name to a valid pointer each time.
8684 if ((error = dns_ns_parse(&u.ns, &F->hints_ns, F->hints)))
8687 F->hints_j.name = u.ns.host;
8688 F->hints_j.type = DNS_T_A;
8689 F->hints_j.section = DNS_S_ALL & ~DNS_S_QD;
8691 if (!dns_rr_grep(&rr, 1, &F->hints_j, F->hints, &error)) {
8692 if (!dns_rr_i_count(&F->hints_j))
8693 dgoto(R->sp, DNS_R_RESOLV0_NS);
8695 dgoto(R->sp, DNS_R_FOREACH_NS);
8698 if ((error = dns_a_parse(&a, &rr, F->hints)))
8701 memset(&sin, '\0', sizeof sin); /* NB: silence valgrind */
8702 sin.sin_family = AF_INET;
8703 sin.sin_addr = a.addr;
8705 sin.sin_port = dns_hints_port(R->hints, AF_INET, &sin.sin_addr);
8707 sin.sin_port = htons(53);
8710 char addr[INET_ADDRSTRLEN + 1];
8711 dns_a_print(addr, sizeof addr, &a);
8712 dns_header(F->query)->qid = dns_so_mkqid(&R->so);
8713 DNS_SHOW(F->query, "ASKING: %s/%s @ DEPTH: %u)", u.ns.host, addr, R->sp);
8716 dns_trace_setcname(R->trace, u.ns.host, (struct sockaddr *)&sin);
8718 if ((error = dns_so_submit(&R->so, F->query, (struct sockaddr *)&sin)))
8724 if (dns_so_elapsed(&R->so) >= dns_resconf_timeout(R->resconf))
8725 dgoto(R->sp, DNS_R_FOREACH_A);
8727 if ((error = dns_so_check(&R->so)))
8730 if (!dns_p_setptr(&F->answer, dns_so_fetch(&R->so, &error)))
8734 DNS_SHOW(F->answer, "ANSWER @ DEPTH: %u)", R->sp);
8737 if (dns_p_rcode(F->answer) == DNS_RC_FORMERR ||
8738 dns_p_rcode(F->answer) == DNS_RC_NOTIMP ||
8739 dns_p_rcode(F->answer) == DNS_RC_BADVERS) {
8740 /* Temporarily disable EDNS0 and try again. */
8741 if (F->qflags & DNS_Q_EDNS0) {
8742 F->qflags &= ~DNS_Q_EDNS0;
8743 if ((error = dns_q_remake(&F->query, F->qflags)))
8746 dgoto(R->sp, DNS_R_FOREACH_A);
8750 if ((error = dns_rr_parse(&rr, 12, F->query)))
8753 if (!(len = dns_d_expand(u.name, sizeof u.name, rr.dn.p, F->query, &error)))
8755 else if (len >= sizeof u.name)
8758 dns_rr_foreach(&rr, F->answer, .section = DNS_S_AN, .name = u.name, .type = rr.type) {
8759 dgoto(R->sp, DNS_R_FINISH); /* Found */
8762 dns_rr_foreach(&rr, F->answer, .section = DNS_S_AN, .name = u.name, .type = DNS_T_CNAME) {
8765 dgoto(R->sp, DNS_R_CNAME0_A);
8769 * XXX: The condition here should probably check whether
8770 * R->sp == 0, because DNS_R_SEARCH runs regardless of
8771 * options.recurse. See DNS_R_BIND.
8773 if (!R->resconf->options.recurse) {
8774 /* Make first answer our tentative answer */
8776 dns_p_movptr(&R->nodata, &F->answer);
8778 dgoto(R->sp, DNS_R_SEARCH);
8781 dns_rr_foreach(&rr, F->answer, .section = DNS_S_NS, .type = DNS_T_NS) {
8782 dns_p_movptr(&F->hints, &F->answer);
8784 dgoto(R->sp, DNS_R_ITERATE);
8787 /* XXX: Should this go further up? */
8788 if (dns_header(F->answer)->aa)
8789 dgoto(R->sp, DNS_R_FINISH);
8791 /* XXX: Should we copy F->answer to R->nodata? */
8793 dgoto(R->sp, DNS_R_FOREACH_A);
8794 case DNS_R_CNAME0_A:
8795 if (&F[1] >= endof(R->stack))
8796 dgoto(R->sp, DNS_R_FINISH);
8798 if ((error = dns_cname_parse(&u.cname, &F->ans_cname, F->answer)))
8800 if ((error = dns_res_frame_prepare(R, &F[1], u.cname.host, dns_rr_type(12, F->query), DNS_C_IN)))
8805 dgoto(++R->sp, DNS_R_INIT);
8806 case DNS_R_CNAME1_A:
8807 if (!(P = dns_res_merge(F->answer, F[1].answer, &error)))
8810 dns_p_setptr(&F->answer, P);
8812 dgoto(R->sp, DNS_R_FINISH);
8817 if (!R->resconf->options.smart || R->sp > 0)
8818 dgoto(R->sp, DNS_R_DONE);
8820 R->smart.section = DNS_S_AN;
8821 R->smart.type = R->qtype;
8823 dns_rr_i_init(&R->smart, F->answer);
8826 case DNS_R_SMART0_A:
8827 if (&F[1] >= endof(R->stack))
8828 dgoto(R->sp, DNS_R_DONE);
8830 while (dns_rr_grep(&rr, 1, &R->smart, F->answer, &error)) {
8837 enum dns_type qtype;
8838 enum dns_class qclass;
8842 if ((error = dns_ns_parse(&rd.ns, &rr, F->answer)))
8851 if ((error = dns_mx_parse(&rd.mx, &rr, F->answer)))
8860 if ((error = dns_srv_parse(&rd.srv, &rr, F->answer)))
8863 qname = rd.srv.target;
8872 if ((error = dns_res_frame_prepare(R, &F[1], qname, qtype, qclass)))
8877 dgoto(++R->sp, DNS_R_INIT);
8881 * NOTE: SMTP specification says to fallback to A record.
8883 * XXX: Should we add a mock MX answer?
8885 if (R->qtype == DNS_T_MX && R->smart.state.count == 0) {
8886 if ((error = dns_res_frame_prepare(R, &F[1], R->qname, DNS_T_A, DNS_C_IN)))
8889 R->smart.state.count++;
8892 dgoto(++R->sp, DNS_R_INIT);
8895 dgoto(R->sp, DNS_R_DONE);
8896 case DNS_R_SMART1_A:
8901 * FIXME: For CNAME chains (which are typically illegal in
8902 * this context), we should rewrite the record host name
8903 * to the original smart qname. All the user cares about
8904 * is locating that A/AAAA record.
8906 dns_rr_foreach(&rr, F[1].answer, .section = DNS_S_AN, .type = DNS_T_A) {
8907 rr.section = DNS_S_AR;
8909 if (dns_rr_exists(&rr, F[1].answer, F->answer))
8912 while ((error = dns_rr_copy(F->answer, &rr, F[1].answer))) {
8913 if (error != DNS_ENOBUFS)
8915 if ((error = dns_p_grow(&F->answer)))
8920 dgoto(R->sp, DNS_R_SMART0_A);
8926 dgoto(--R->sp, F[-1].state);
8929 case DNS_R_SERVFAIL:
8930 if (!dns_p_setptr(&F->answer, dns_p_make(DNS_P_QBUFSIZ, &error)))
8933 dns_header(F->answer)->qr = 1;
8934 dns_header(F->answer)->rcode = DNS_RC_SERVFAIL;
8936 if ((error = dns_p_push(F->answer, DNS_S_QD, R->qname, strlen(R->qname), R->qtype, R->qclass, 0, 0)))
8939 dgoto(R->sp, DNS_R_DONE);
8948 error = DNS_ENOQUERY;
8952 error = DNS_ENOANSWER;
8956 error = DNS_EILLEGAL;
8961 } /* dns_res_exec() */
8966 void dns_res_clear(struct dns_resolver *R) {
8967 switch (R->stack[R->sp].state) {
8969 R->cache->clear(R->cache);
8972 dns_so_clear(&R->so);
8975 } /* dns_res_clear() */
8978 static int dns_res_events2(struct dns_resolver *R, enum dns_events type) {
8981 switch (R->stack[R->sp].state) {
8983 events = R->cache->events(R->cache);
8985 return (type == DNS_LIBEVENT)? DNS_POLL2EV(events) : events;
8987 return dns_so_events2(&R->so, type);
8989 } /* dns_res_events2() */
8992 int dns_res_events(struct dns_resolver *R) {
8993 return dns_res_events2(R, R->so.opts.events);
8994 } /* dns_res_events() */
8997 int dns_res_pollfd(struct dns_resolver *R) {
8998 switch (R->stack[R->sp].state) {
9000 return R->cache->pollfd(R->cache);
9002 return dns_so_pollfd(&R->so);
9004 } /* dns_res_pollfd() */
9007 time_t dns_res_timeout(struct dns_resolver *R) {
9010 switch (R->stack[R->sp].state) {
9012 case DNS_R_QUERY_AAAA:
9015 elapsed = dns_so_elapsed(&R->so);
9017 if (elapsed <= dns_resconf_timeout(R->resconf))
9018 return R->resconf->options.timeout - elapsed;
9026 * NOTE: We're not in a pollable state, or the user code hasn't
9027 * called dns_res_check properly. The calling code is probably
9028 * broken. Put them into a slow-burn pattern.
9031 } /* dns_res_timeout() */
9034 time_t dns_res_elapsed(struct dns_resolver *R) {
9035 return dns_elapsed(&R->elapsed);
9036 } /* dns_res_elapsed() */
9039 int dns_res_poll(struct dns_resolver *R, int timeout) {
9040 return dns_poll(dns_res_pollfd(R), dns_res_events2(R, DNS_SYSPOLL), timeout);
9041 } /* dns_res_poll() */
9044 int dns_res_submit2(struct dns_resolver *R, const char *qname, size_t qlen, enum dns_type qtype, enum dns_class qclass) {
9047 /* Don't anchor; that can conflict with searchlist generation. */
9048 dns_d_init(R->qname, sizeof R->qname, qname, (R->qlen = qlen), 0);
9053 dns_begin(&R->elapsed);
9055 dns_trace_res_submit(R->trace, R->qname, R->qtype, R->qclass, 0);
9058 } /* dns_res_submit2() */
9061 int dns_res_submit(struct dns_resolver *R, const char *qname, enum dns_type qtype, enum dns_class qclass) {
9062 return dns_res_submit2(R, qname, strlen(qname), qtype, qclass);
9063 } /* dns_res_submit() */
9066 int dns_res_check(struct dns_resolver *R) {
9069 if (R->stack[0].state != DNS_R_DONE) {
9070 if ((error = dns_res_exec(R)))
9075 } /* dns_res_check() */
9078 struct dns_packet *dns_res_fetch(struct dns_resolver *R, int *_error) {
9079 struct dns_packet *P = NULL;
9082 if (R->stack[0].state != DNS_R_DONE) {
9083 error = DNS_EUNKNOWN;
9087 if (!dns_p_movptr(&P, &R->stack[0].answer)) {
9088 error = DNS_EFETCHED;
9092 dns_trace_res_fetch(R->trace, P, 0);
9097 dns_trace_res_fetch(R->trace, NULL, error);
9099 } /* dns_res_fetch() */
9102 static struct dns_packet *dns_res_fetch_and_study(struct dns_resolver *R, int *_error) {
9103 struct dns_packet *P = NULL;
9106 if (!(P = dns_res_fetch(R, &error)))
9108 if ((error = dns_p_study(P)))
9118 } /* dns_res_fetch_and_study() */
9121 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_) {
9124 if ((error = dns_res_submit(res, qname, qtype, qclass)))
9127 while ((error = dns_res_check(res))) {
9128 if (dns_res_elapsed(res) > timeout)
9129 error = DNS_ETIMEDOUT;
9131 if (error != DNS_EAGAIN)
9134 if ((error = dns_res_poll(res, 1)))
9138 return dns_res_fetch(res, error_);
9143 } /* dns_res_query() */
9146 const struct dns_stat *dns_res_stat(struct dns_resolver *res) {
9147 return dns_so_stat(&res->so);
9148 } /* dns_res_stat() */
9151 void dns_res_sethints(struct dns_resolver *res, struct dns_hints *hints) {
9152 dns_hints_acquire(hints); /* acquire first in case same hints object */
9153 dns_hints_close(res->hints);
9155 } /* dns_res_sethints() */
9158 struct dns_trace *dns_res_trace(struct dns_resolver *res) {
9160 } /* dns_res_trace() */
9163 void dns_res_settrace(struct dns_resolver *res, struct dns_trace *trace) {
9164 struct dns_trace *otrace = res->trace;
9165 res->trace = dns_trace_acquire_p(trace);
9166 dns_trace_close(otrace);
9167 dns_so_settrace(&res->so, trace);
9168 } /* dns_res_settrace() */
9172 * A D D R I N F O R O U T I N E S
9174 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9176 struct dns_addrinfo {
9177 struct addrinfo hints;
9178 struct dns_resolver *res;
9179 struct dns_trace *trace;
9181 char qname[DNS_D_MAXNAME + 1];
9182 enum dns_type qtype;
9183 unsigned short qport, port;
9189 enum dns_type qtype;
9192 struct dns_packet *answer;
9193 struct dns_packet *glue;
9195 struct dns_rr_i i, g;
9198 char cname[DNS_D_MAXNAME + 1];
9199 char i_cname[DNS_D_MAXNAME + 1], g_cname[DNS_D_MAXNAME + 1];
9207 }; /* struct dns_addrinfo */
9210 #define DNS_AI_AFMAX 32
9211 #define DNS_AI_AF2INDEX(af) (1UL << ((af) - 1))
9213 static inline unsigned long dns_ai_af2index(int af) {
9214 dns_static_assert(dns_same_type(unsigned long, DNS_AI_AF2INDEX(1), 1), "internal type mismatch");
9215 dns_static_assert(dns_same_type(unsigned long, ((struct dns_addrinfo *)0)->af.todo, 1), "internal type mismatch");
9217 return (af > 0 && af <= DNS_AI_AFMAX)? DNS_AI_AF2INDEX(af) : 0;
9220 static int dns_ai_setaf(struct dns_addrinfo *ai, int af, int qtype) {
9222 ai->af.qtype = qtype;
9224 ai->af.todo &= ~dns_ai_af2index(af);
9227 } /* dns_ai_setaf() */
9229 #define DNS_SM_RESTORE \
9230 do { pc = 0xff & (ai->af.state >> 0); i = 0xff & (ai->af.state >> 8); } while (0)
9231 #define DNS_SM_SAVE \
9232 do { ai->af.state = ((0xff & pc) << 0) | ((0xff & i) << 8); } while (0)
9234 static int dns_ai_nextaf(struct dns_addrinfo *ai) {
9237 dns_static_assert(AF_UNSPEC == 0, "AF_UNSPEC constant not 0");
9238 dns_static_assert(AF_INET <= DNS_AI_AFMAX, "AF_INET constant too large");
9239 dns_static_assert(AF_INET6 <= DNS_AI_AFMAX, "AF_INET6 constant too large");
9245 * NB: On OpenBSD, at least, the types of entries resolved
9246 * is the intersection of the /etc/resolv.conf families and
9247 * the families permitted by the .ai_type hint. So if
9248 * /etc/resolv.conf has "family inet4" and .ai_type
9249 * is AF_INET6, then the address ::1 will return 0 entries
9250 * even if AI_NUMERICHOST is specified in .ai_flags.
9252 while (i < (int)lengthof(ai->res->resconf->family)) {
9253 int af = ai->res->resconf->family[i++];
9255 if (af == AF_UNSPEC) {
9257 } else if (af < 0 || af > DNS_AI_AFMAX) {
9259 } else if (!(DNS_AI_AF2INDEX(af) & ai->af.todo)) {
9261 } else if (af == AF_INET) {
9262 DNS_SM_YIELD(dns_ai_setaf(ai, AF_INET, DNS_T_A));
9263 } else if (af == AF_INET6) {
9264 DNS_SM_YIELD(dns_ai_setaf(ai, AF_INET6, DNS_T_AAAA));
9269 * NB: If we get here than AI_NUMERICFLAGS should be set and
9270 * order shouldn't matter.
9272 if (DNS_AI_AF2INDEX(AF_INET) & ai->af.todo)
9273 DNS_SM_YIELD(dns_ai_setaf(ai, AF_INET, DNS_T_A));
9274 if (DNS_AI_AF2INDEX(AF_INET6) & ai->af.todo)
9275 DNS_SM_YIELD(dns_ai_setaf(ai, AF_INET6, DNS_T_AAAA));
9280 return dns_ai_setaf(ai, AF_UNSPEC, 0);
9281 } /* dns_ai_nextaf() */
9283 #undef DNS_SM_RESTORE
9286 static enum dns_type dns_ai_qtype(struct dns_addrinfo *ai) {
9287 return (ai->qtype)? ai->qtype : ai->af.qtype;
9288 } /* dns_ai_qtype() */
9290 /* JW: This is not defined on mingw. */
9291 #ifndef AI_NUMERICSERV
9292 #define AI_NUMERICSERV 0
9295 static dns_error_t dns_ai_parseport(unsigned short *port, const char *serv, const struct addrinfo *hints) {
9296 const char *cp = serv;
9297 unsigned long n = 0;
9299 while (*cp >= '0' && *cp <= '9' && n < 65536) {
9305 if (cp == serv || n >= 65536)
9306 return DNS_ESERVICE;
9313 if (hints->ai_flags & AI_NUMERICSERV)
9314 return DNS_ESERVICE;
9316 /* TODO: try getaddrinfo(NULL, serv, { .ai_flags = AI_NUMERICSERV }) */
9318 return DNS_ESERVICE;
9319 } /* dns_ai_parseport() */
9322 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) {
9323 static const struct dns_addrinfo ai_initializer;
9324 struct dns_addrinfo *ai;
9328 dns_res_acquire(res);
9329 } else if (!(hints->ai_flags & AI_NUMERICHOST)) {
9331 * NOTE: it's assumed that *_error is set from a previous
9332 * API function call, such as dns_res_stub(). Should change
9333 * this semantic, but it's applied elsewhere, too.
9340 if (!(ai = malloc(sizeof *ai)))
9343 *ai = ai_initializer;
9349 if (sizeof ai->qname <= dns_strlcpy(ai->qname, host, sizeof ai->qname))
9350 { error = ENAMETOOLONG; goto error; }
9355 if (serv && (error = dns_ai_parseport(&ai->qport, serv, hints)))
9357 ai->port = ai->qport;
9360 * FIXME: If an explicit A or AAAA record type conflicts with
9361 * .ai_family or with resconf.family (i.e. AAAA specified but
9362 * AF_INET6 not in interection of .ai_family and resconf.family),
9365 switch (ai->qtype) {
9367 ai->af.todo = DNS_AI_AF2INDEX(AF_INET);
9370 ai->af.todo = DNS_AI_AF2INDEX(AF_INET6);
9372 default: /* 0, MX, SRV, etc */
9373 switch (ai->hints.ai_family) {
9375 ai->af.todo = DNS_AI_AF2INDEX(AF_INET) | DNS_AI_AF2INDEX(AF_INET6);
9378 ai->af.todo = DNS_AI_AF2INDEX(AF_INET);
9381 ai->af.todo = DNS_AI_AF2INDEX(AF_INET6);
9390 error = dns_syerr();
9398 } /* dns_ai_open() */
9401 void dns_ai_close(struct dns_addrinfo *ai) {
9405 dns_res_close(ai->res);
9406 dns_trace_close(ai->trace);
9408 if (ai->answer != ai->glue)
9409 dns_p_free(ai->glue);
9411 dns_p_free(ai->answer);
9413 } /* dns_ai_close() */
9416 static int dns_ai_setent(struct addrinfo **ent, union dns_any *any, enum dns_type type, struct dns_addrinfo *ai) {
9417 struct sockaddr *saddr;
9418 struct sockaddr_in sin;
9419 struct sockaddr_in6 sin6;
9425 saddr = memset(&sin, '\0', sizeof sin);
9427 sin.sin_family = AF_INET;
9428 sin.sin_port = htons(ai->port);
9430 memcpy(&sin.sin_addr, any, sizeof sin.sin_addr);
9434 saddr = memset(&sin6, '\0', sizeof sin6);
9436 sin6.sin6_family = AF_INET6;
9437 sin6.sin6_port = htons(ai->port);
9439 memcpy(&sin6.sin6_addr, any, sizeof sin6.sin6_addr);
9446 if (ai->hints.ai_flags & AI_CANONNAME) {
9447 cname = (*ai->cname)? ai->cname : ai->qname;
9448 clen = strlen(cname);
9454 if (!(*ent = malloc(sizeof **ent + dns_sa_len(saddr) + ((ai->hints.ai_flags & AI_CANONNAME)? clen + 1 : 0))))
9457 memset(*ent, '\0', sizeof **ent);
9459 (*ent)->ai_family = saddr->sa_family;
9460 (*ent)->ai_socktype = ai->hints.ai_socktype;
9461 (*ent)->ai_protocol = ai->hints.ai_protocol;
9463 (*ent)->ai_addr = memcpy((unsigned char *)*ent + sizeof **ent, saddr, dns_sa_len(saddr));
9464 (*ent)->ai_addrlen = dns_sa_len(saddr);
9466 if (ai->hints.ai_flags & AI_CANONNAME)
9467 (*ent)->ai_canonname = memcpy((unsigned char *)*ent + sizeof **ent + dns_sa_len(saddr), cname, clen + 1);
9472 } /* dns_ai_setent() */
9490 }; /* enum dns_ai_state */
9492 #define dns_ai_goto(which) do { ai->state = (which); goto exec; } while (0)
9494 int dns_ai_nextent(struct addrinfo **ent, struct dns_addrinfo *ai) {
9495 struct dns_packet *ans, *glue;
9497 char qname[DNS_D_MAXNAME + 1];
9506 switch (ai->state) {
9509 case DNS_AI_S_NEXTAF:
9510 if (!dns_ai_nextaf(ai))
9511 dns_ai_goto(DNS_AI_S_DONE);
9514 case DNS_AI_S_NUMERIC:
9515 if (1 == dns_inet_pton(AF_INET, ai->qname, &any.a)) {
9516 if (ai->af.atype == AF_INET) {
9517 ai->state = DNS_AI_S_NEXTAF;
9518 return dns_ai_setent(ent, &any, DNS_T_A, ai);
9520 dns_ai_goto(DNS_AI_S_NEXTAF);
9524 if (1 == dns_inet_pton(AF_INET6, ai->qname, &any.aaaa)) {
9525 if (ai->af.atype == AF_INET6) {
9526 ai->state = DNS_AI_S_NEXTAF;
9527 return dns_ai_setent(ent, &any, DNS_T_AAAA, ai);
9529 dns_ai_goto(DNS_AI_S_NEXTAF);
9533 if (ai->hints.ai_flags & AI_NUMERICHOST)
9534 dns_ai_goto(DNS_AI_S_NEXTAF);
9537 case DNS_AI_S_SUBMIT:
9540 if ((error = dns_res_submit(ai->res, ai->qname, dns_ai_qtype(ai), DNS_C_IN)))
9544 case DNS_AI_S_CHECK:
9545 if ((error = dns_res_check(ai->res)))
9549 case DNS_AI_S_FETCH:
9550 if (!(ans = dns_res_fetch_and_study(ai->res, &error)))
9552 if (ai->glue != ai->answer)
9553 dns_p_free(ai->glue);
9554 ai->glue = dns_p_movptr(&ai->answer, &ans);
9556 /* Search generator may have changed the qname. */
9557 if (!(qlen = dns_d_expand(qname, sizeof qname, 12, ai->answer, &error)))
9559 else if (qlen >= sizeof qname)
9560 return DNS_EILLEGAL;
9561 if (!dns_d_cname(ai->cname, sizeof ai->cname, qname, qlen, ai->answer, &error))
9564 dns_strlcpy(ai->i_cname, ai->cname, sizeof ai->i_cname);
9565 dns_rr_i_init(&ai->i, ai->answer);
9566 ai->i.section = DNS_S_AN;
9567 ai->i.name = ai->i_cname;
9568 ai->i.type = dns_ai_qtype(ai);
9569 ai->i.sort = &dns_rr_i_order;
9572 case DNS_AI_S_FOREACH_I:
9573 if (!dns_rr_grep(&rr, 1, &ai->i, ai->answer, &error))
9574 dns_ai_goto(DNS_AI_S_NEXTAF);
9576 if ((error = dns_any_parse(&any, &rr, ai->answer)))
9579 ai->port = ai->qport;
9584 return dns_ai_setent(ent, &any, rr.type, ai);
9586 if (!(clen = dns_any_cname(ai->cname, sizeof ai->cname, &any, rr.type)))
9587 dns_ai_goto(DNS_AI_S_FOREACH_I);
9590 * Find the "real" canonical name. Some authorities
9591 * publish aliases where an RFC defines a canonical
9592 * name. We trust that the resolver followed any
9593 * CNAME chains on it's own, regardless of whether
9594 * the "smart" option is enabled.
9596 if (!dns_d_cname(ai->cname, sizeof ai->cname, ai->cname, clen, ai->answer, &error))
9599 if (rr.type == DNS_T_SRV)
9600 ai->port = any.srv.port;
9606 case DNS_AI_S_INIT_G:
9610 case DNS_AI_S_ITERATE_G:
9611 dns_strlcpy(ai->g_cname, ai->cname, sizeof ai->g_cname);
9612 dns_rr_i_init(&ai->g, ai->glue);
9613 ai->g.section = DNS_S_ALL & ~DNS_S_QD;
9614 ai->g.name = ai->g_cname;
9615 ai->g.type = ai->af.qtype;
9618 case DNS_AI_S_FOREACH_G:
9619 if (!dns_rr_grep(&rr, 1, &ai->g, ai->glue, &error)) {
9620 if (dns_rr_i_count(&ai->g) > 0)
9621 dns_ai_goto(DNS_AI_S_FOREACH_I);
9623 dns_ai_goto(DNS_AI_S_SUBMIT_G);
9626 if ((error = dns_any_parse(&any, &rr, ai->glue)))
9629 return dns_ai_setent(ent, &any, rr.type, ai);
9630 case DNS_AI_S_SUBMIT_G:
9631 /* skip if already queried */
9632 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))
9633 dns_ai_goto(DNS_AI_S_FOREACH_I);
9634 /* skip if we recursed (CNAME chains should have been handled in the resolver) */
9635 if (++ai->g_depth > 1)
9636 dns_ai_goto(DNS_AI_S_FOREACH_I);
9638 if ((error = dns_res_submit(ai->res, ai->g.name, ai->g.type, DNS_C_IN)))
9642 case DNS_AI_S_CHECK_G:
9643 if ((error = dns_res_check(ai->res)))
9647 case DNS_AI_S_FETCH_G:
9648 if (!(ans = dns_res_fetch_and_study(ai->res, &error)))
9651 glue = dns_p_merge(ai->glue, DNS_S_ALL, ans, DNS_S_ALL, &error);
9652 dns_p_setptr(&ans, NULL);
9656 if (ai->glue != ai->answer)
9657 dns_p_free(ai->glue);
9660 if (!dns_d_cname(ai->cname, sizeof ai->cname, ai->g.name, strlen(ai->g.name), ai->glue, &error))
9661 dns_ai_goto(DNS_AI_S_FOREACH_I);
9663 dns_ai_goto(DNS_AI_S_ITERATE_G);
9666 return ENOENT; /* TODO: Just return 0 */
9667 } else if (ai->answer) {
9668 switch (dns_p_rcode(ai->answer)) {
9669 case DNS_RC_NOERROR:
9671 case DNS_RC_NXDOMAIN:
9682 } /* dns_ai_nextent() */
9685 time_t dns_ai_elapsed(struct dns_addrinfo *ai) {
9686 return (ai->res)? dns_res_elapsed(ai->res) : 0;
9687 } /* dns_ai_elapsed() */
9690 void dns_ai_clear(struct dns_addrinfo *ai) {
9692 dns_res_clear(ai->res);
9693 } /* dns_ai_clear() */
9696 int dns_ai_events(struct dns_addrinfo *ai) {
9697 return (ai->res)? dns_res_events(ai->res) : 0;
9698 } /* dns_ai_events() */
9701 int dns_ai_pollfd(struct dns_addrinfo *ai) {
9702 return (ai->res)? dns_res_pollfd(ai->res) : -1;
9703 } /* dns_ai_pollfd() */
9706 time_t dns_ai_timeout(struct dns_addrinfo *ai) {
9707 return (ai->res)? dns_res_timeout(ai->res) : 0;
9708 } /* dns_ai_timeout() */
9711 int dns_ai_poll(struct dns_addrinfo *ai, int timeout) {
9712 return (ai->res)? dns_res_poll(ai->res, timeout) : 0;
9713 } /* dns_ai_poll() */
9716 size_t dns_ai_print(void *_dst, size_t lim, struct addrinfo *ent, struct dns_addrinfo *ai) {
9717 struct dns_buf dst = DNS_B_INTO(_dst, lim);
9718 char addr[DNS_PP_MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) + 1];
9720 dns_b_puts(&dst, "[ ");
9721 dns_b_puts(&dst, ai->qname);
9722 dns_b_puts(&dst, " IN ");
9724 dns_b_puts(&dst, dns_strtype(ai->qtype));
9725 } else if (ent->ai_family == AF_INET) {
9726 dns_b_puts(&dst, dns_strtype(DNS_T_A));
9727 } else if (ent->ai_family == AF_INET6) {
9728 dns_b_puts(&dst, dns_strtype(DNS_T_AAAA));
9730 dns_b_puts(&dst, "0");
9732 dns_b_puts(&dst, " ]\n");
9734 dns_b_puts(&dst, ".ai_family = ");
9735 switch (ent->ai_family) {
9737 dns_b_puts(&dst, "AF_INET");
9740 dns_b_puts(&dst, "AF_INET6");
9743 dns_b_fmtju(&dst, ent->ai_family, 0);
9746 dns_b_putc(&dst, '\n');
9748 dns_b_puts(&dst, ".ai_socktype = ");
9749 switch (ent->ai_socktype) {
9751 dns_b_puts(&dst, "SOCK_STREAM");
9754 dns_b_puts(&dst, "SOCK_DGRAM");
9757 dns_b_fmtju(&dst, ent->ai_socktype, 0);
9760 dns_b_putc(&dst, '\n');
9762 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);
9763 dns_b_puts(&dst, ".ai_addr = [");
9764 dns_b_puts(&dst, addr);
9765 dns_b_puts(&dst, "]:");
9766 dns_b_fmtju(&dst, ntohs(*dns_sa_port(dns_sa_family(ent->ai_addr), ent->ai_addr)), 0);
9767 dns_b_putc(&dst, '\n');
9769 dns_b_puts(&dst, ".ai_canonname = ");
9770 dns_b_puts(&dst, (ent->ai_canonname)? ent->ai_canonname : "[NULL]");
9771 dns_b_putc(&dst, '\n');
9773 return dns_b_strllen(&dst);
9774 } /* dns_ai_print() */
9777 const struct dns_stat *dns_ai_stat(struct dns_addrinfo *ai) {
9778 return (ai->res)? dns_res_stat(ai->res) : &ai->st;
9779 } /* dns_ai_stat() */
9782 struct dns_trace *dns_ai_trace(struct dns_addrinfo *ai) {
9784 } /* dns_ai_trace() */
9787 void dns_ai_settrace(struct dns_addrinfo *ai, struct dns_trace *trace) {
9788 struct dns_trace *otrace = ai->trace;
9789 ai->trace = dns_trace_acquire_p(trace);
9790 dns_trace_close(otrace);
9792 dns_res_settrace(ai->res, trace);
9793 } /* dns_ai_settrace() */
9797 * M I S C E L L A N E O U S R O U T I N E S
9799 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9801 static const struct {
9803 enum dns_section type;
9804 } dns_sections[] = {
9805 { "QUESTION", DNS_S_QUESTION },
9806 { "QD", DNS_S_QUESTION },
9807 { "ANSWER", DNS_S_ANSWER },
9808 { "AN", DNS_S_ANSWER },
9809 { "AUTHORITY", DNS_S_AUTHORITY },
9810 { "NS", DNS_S_AUTHORITY },
9811 { "ADDITIONAL", DNS_S_ADDITIONAL },
9812 { "AR", DNS_S_ADDITIONAL },
9815 const char *(dns_strsection)(enum dns_section section, void *_dst, size_t lim) {
9816 struct dns_buf dst = DNS_B_INTO(_dst, lim);
9819 for (i = 0; i < lengthof(dns_sections); i++) {
9820 if (dns_sections[i].type & section) {
9821 dns_b_puts(&dst, dns_sections[i].name);
9822 section &= ~dns_sections[i].type;
9824 dns_b_putc(&dst, '|');
9828 if (section || dst.p == dst.base)
9829 dns_b_fmtju(&dst, (0xffff & section), 0);
9831 return dns_b_tostring(&dst);
9832 } /* dns_strsection() */
9835 enum dns_section dns_isection(const char *src) {
9836 enum dns_section section = 0;
9841 dns_strlcpy(sbuf, src, sizeof sbuf);
9844 while ((name = dns_strsep(&next, "|+, \t"))) {
9845 for (i = 0; i < lengthof(dns_sections); i++) {
9846 if (!strcasecmp(dns_sections[i].name, name)) {
9847 section |= dns_sections[i].type;
9854 } /* dns_isection() */
9857 static const struct {
9859 enum dns_class type;
9864 const char *(dns_strclass)(enum dns_class type, void *_dst, size_t lim) {
9865 struct dns_buf dst = DNS_B_INTO(_dst, lim);
9868 for (i = 0; i < lengthof(dns_classes); i++) {
9869 if (dns_classes[i].type == type) {
9870 dns_b_puts(&dst, dns_classes[i].name);
9875 if (dst.p == dst.base)
9876 dns_b_fmtju(&dst, (0xffff & type), 0);
9878 return dns_b_tostring(&dst);
9879 } /* dns_strclass() */
9882 enum dns_class dns_iclass(const char *name) {
9885 for (i = 0; i < lengthof(dns_classes); i++) {
9886 if (!strcasecmp(dns_classes[i].name, name))
9887 return dns_classes[i].type;
9891 while (dns_isdigit(*name)) {
9893 class += *name++ - '0';
9896 return DNS_PP_MIN(class, 0xffff);
9897 } /* dns_iclass() */
9900 const char *(dns_strtype)(enum dns_type type, void *_dst, size_t lim) {
9901 struct dns_buf dst = DNS_B_INTO(_dst, lim);
9904 for (i = 0; i < lengthof(dns_rrtypes); i++) {
9905 if (dns_rrtypes[i].type == type) {
9906 dns_b_puts(&dst, dns_rrtypes[i].name);
9911 if (dst.p == dst.base)
9912 dns_b_fmtju(&dst, (0xffff & type), 0);
9914 return dns_b_tostring(&dst);
9915 } /* dns_strtype() */
9918 enum dns_type dns_itype(const char *name) {
9921 for (i = 0; i < lengthof(dns_rrtypes); i++) {
9922 if (!strcasecmp(dns_rrtypes[i].name, name))
9923 return dns_rrtypes[i].type;
9927 while (dns_isdigit(*name)) {
9929 type += *name++ - '0';
9932 return DNS_PP_MIN(type, 0xffff);
9936 static char dns_opcodes[16][16] = {
9937 [DNS_OP_QUERY] = "QUERY",
9938 [DNS_OP_IQUERY] = "IQUERY",
9939 [DNS_OP_STATUS] = "STATUS",
9940 [DNS_OP_NOTIFY] = "NOTIFY",
9941 [DNS_OP_UPDATE] = "UPDATE",
9944 static const char *dns__strcode(int code, volatile char *dst, size_t lim) {
9950 dns_b_fmtju(dns_b_into(&tmp, _tmp, DNS_PP_MIN(sizeof _tmp, lim - 1)), code, 0);
9952 /* copy downwards so first byte is copied last (see below) */
9953 p = (size_t)(tmp.p - tmp.base);
9958 return (const char *)dst;
9961 const char *dns_stropcode(enum dns_opcode opcode) {
9962 opcode = (unsigned)opcode % lengthof(dns_opcodes);
9964 if ('\0' == dns_opcodes[opcode][0])
9965 return dns__strcode(opcode, dns_opcodes[opcode], sizeof dns_opcodes[opcode]);
9967 return dns_opcodes[opcode];
9968 } /* dns_stropcode() */
9971 enum dns_opcode dns_iopcode(const char *name) {
9974 for (opcode = 0; opcode < lengthof(dns_opcodes); opcode++) {
9975 if (!strcasecmp(name, dns_opcodes[opcode]))
9980 while (dns_isdigit(*name)) {
9982 opcode += *name++ - '0';
9985 return DNS_PP_MIN(opcode, 0x0f);
9986 } /* dns_iopcode() */
9989 static char dns_rcodes[32][16] = {
9990 [DNS_RC_NOERROR] = "NOERROR",
9991 [DNS_RC_FORMERR] = "FORMERR",
9992 [DNS_RC_SERVFAIL] = "SERVFAIL",
9993 [DNS_RC_NXDOMAIN] = "NXDOMAIN",
9994 [DNS_RC_NOTIMP] = "NOTIMP",
9995 [DNS_RC_REFUSED] = "REFUSED",
9996 [DNS_RC_YXDOMAIN] = "YXDOMAIN",
9997 [DNS_RC_YXRRSET] = "YXRRSET",
9998 [DNS_RC_NXRRSET] = "NXRRSET",
9999 [DNS_RC_NOTAUTH] = "NOTAUTH",
10000 [DNS_RC_NOTZONE] = "NOTZONE",
10001 /* EDNS(0) extended RCODEs ... */
10002 [DNS_RC_BADVERS] = "BADVERS",
10005 const char *dns_strrcode(enum dns_rcode rcode) {
10006 rcode = (unsigned)rcode % lengthof(dns_rcodes);
10008 if ('\0' == dns_rcodes[rcode][0])
10009 return dns__strcode(rcode, dns_rcodes[rcode], sizeof dns_rcodes[rcode]);
10011 return dns_rcodes[rcode];
10012 } /* dns_strrcode() */
10015 enum dns_rcode dns_ircode(const char *name) {
10018 for (rcode = 0; rcode < lengthof(dns_rcodes); rcode++) {
10019 if (!strcasecmp(name, dns_rcodes[rcode]))
10024 while (dns_isdigit(*name)) {
10026 rcode += *name++ - '0';
10029 return DNS_PP_MIN(rcode, 0xfff);
10030 } /* dns_ircode() */
10035 * 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
10037 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
10040 #include <stdarg.h>
10041 #include <stdlib.h>
10047 #include <getopt.h>
10057 const char *path[8];
10059 } resconf, nssconf, hosts, cache;
10062 enum dns_type qtype;
10071 struct dns_resolv_conf *resconf;
10072 struct dns_hosts *hosts;
10073 struct dns_trace *trace;
10076 struct sockaddr_storage socks_host;
10077 const char *socks_user;
10078 const char *socks_password;
10080 .sort = &dns_rr_i_packet,
10084 static void hexdump(const unsigned char *src, size_t len, FILE *fp) {
10085 struct dns_hxd_lines_i lines = { 0 };
10088 while (dns_hxd_lines(line, sizeof line, src, len, &lines)) {
10094 DNS_NORETURN static void panic(const char *fmt, ...) {
10100 vfprintf(stderr, fmt, ap);
10102 exit(EXIT_FAILURE);
10104 verrx(EXIT_FAILURE, fmt, ap);
10108 #define panic_(fn, ln, fmt, ...) \
10109 panic(fmt "%0s", (fn), (ln), __VA_ARGS__)
10110 #define panic(...) \
10111 panic_(__func__, __LINE__, "(%s:%d) " __VA_ARGS__, "")
10114 static void *grow(unsigned char *p, size_t size) {
10117 if (!(tmp = realloc(p, size)))
10118 panic("realloc(%"PRIuZ"): %s", size, dns_strerror(errno));
10124 static size_t add(size_t a, size_t b) {
10126 panic("%"PRIuZ" + %"PRIuZ": integer overflow", a, b);
10132 static size_t append(unsigned char **dst, size_t osize, const void *src, size_t len) {
10133 size_t size = add(osize, len);
10135 *dst = grow(*dst, size);
10136 memcpy(*dst + osize, src, len);
10142 static size_t slurp(unsigned char **dst, size_t osize, FILE *fp, const char *path) {
10143 size_t size = osize;
10144 unsigned char buf[1024];
10147 while ((count = fread(buf, 1, sizeof buf, fp)))
10148 size = append(dst, size, buf, count);
10151 panic("%s: %s", path, dns_strerror(errno));
10157 static struct dns_resolv_conf *resconf(void) {
10158 struct dns_resolv_conf **resconf = &MAIN.memo.resconf;
10166 if (!(*resconf = dns_resconf_open(&error)))
10167 panic("dns_resconf_open: %s", dns_strerror(error));
10169 if (!MAIN.resconf.count)
10170 MAIN.resconf.path[MAIN.resconf.count++] = "/etc/resolv.conf";
10172 for (i = 0; i < MAIN.resconf.count; i++) {
10173 path = MAIN.resconf.path[i];
10175 if (0 == strcmp(path, "-"))
10176 error = dns_resconf_loadfile(*resconf, stdin);
10178 error = dns_resconf_loadpath(*resconf, path);
10181 panic("%s: %s", path, dns_strerror(error));
10184 for (i = 0; i < MAIN.nssconf.count; i++) {
10185 path = MAIN.nssconf.path[i];
10187 if (0 == strcmp(path, "-"))
10188 error = dns_nssconf_loadfile(*resconf, stdin);
10190 error = dns_nssconf_loadpath(*resconf, path);
10193 panic("%s: %s", path, dns_strerror(error));
10196 if (!MAIN.nssconf.count) {
10197 path = "/etc/nsswitch.conf";
10199 if (!(error = dns_nssconf_loadpath(*resconf, path)))
10200 MAIN.nssconf.path[MAIN.nssconf.count++] = path;
10201 else if (error != ENOENT)
10202 panic("%s: %s", path, dns_strerror(error));
10209 static struct dns_hosts *hosts(void) {
10210 struct dns_hosts **hosts = &MAIN.memo.hosts;
10218 if (!MAIN.hosts.count) {
10219 MAIN.hosts.path[MAIN.hosts.count++] = "/etc/hosts";
10221 /* Explicitly test dns_hosts_local() */
10222 if (!(*hosts = dns_hosts_local(&error)))
10223 panic("%s: %s", "/etc/hosts", dns_strerror(error));
10228 if (!(*hosts = dns_hosts_open(&error)))
10229 panic("dns_hosts_open: %s", dns_strerror(error));
10231 for (i = 0; i < MAIN.hosts.count; i++) {
10232 path = MAIN.hosts.path[i];
10234 if (0 == strcmp(path, "-"))
10235 error = dns_hosts_loadfile(*hosts, stdin);
10237 error = dns_hosts_loadpath(*hosts, path);
10240 panic("%s: %s", path, dns_strerror(error));
10250 static struct dns_cache *cache(void) {
10251 static struct cache *cache;
10257 return cache_resi(cache);
10258 if (!MAIN.cache.count)
10261 if (!(cache = cache_open(&error)))
10262 panic("%s: %s", MAIN.cache.path[0], dns_strerror(error));
10264 for (i = 0; i < MAIN.cache.count; i++) {
10265 path = MAIN.cache.path[i];
10267 if (!strcmp(path, "-")) {
10268 if ((error = cache_loadfile(cache, stdin, NULL, 0)))
10269 panic("%s: %s", path, dns_strerror(error));
10270 } else if ((error = cache_loadpath(cache, path, NULL, 0)))
10271 panic("%s: %s", path, dns_strerror(error));
10274 return cache_resi(cache);
10277 static struct dns_cache *cache(void) { return NULL; }
10281 static struct dns_trace *trace(const char *mode) {
10282 static char omode[64] = "";
10283 struct dns_trace **trace = &MAIN.memo.trace;
10287 if (*trace && 0 == strcmp(omode, mode))
10292 if (!(fp = fopen(MAIN.trace, mode)))
10293 panic("%s: %s", MAIN.trace, strerror(errno));
10294 dns_trace_close(*trace);
10295 if (!(*trace = dns_trace_open(fp, &error)))
10296 panic("%s: %s", MAIN.trace, dns_strerror(error));
10297 dns_strlcpy(omode, mode, sizeof omode);
10303 static void print_packet(struct dns_packet *P, FILE *fp) {
10304 dns_p_dump3(P, dns_rr_i_new(P, .sort = MAIN.sort), fp);
10306 if (MAIN.verbose > 2)
10307 hexdump(P->data, P->end, fp);
10308 } /* print_packet() */
10311 static int parse_packet(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
10312 struct dns_packet *P = dns_p_new(512);
10313 struct dns_packet *Q = dns_p_new(512);
10314 enum dns_section section;
10318 char pretty[sizeof any * 2];
10321 P->end = fread(P->data, 1, P->size, stdin);
10323 fputs(";; [HEADER]\n", stdout);
10324 fprintf(stdout, ";; qr : %s(%d)\n", (dns_header(P)->qr)? "RESPONSE" : "QUERY", dns_header(P)->qr);
10325 fprintf(stdout, ";; opcode : %s(%d)\n", dns_stropcode(dns_header(P)->opcode), dns_header(P)->opcode);
10326 fprintf(stdout, ";; aa : %s(%d)\n", (dns_header(P)->aa)? "AUTHORITATIVE" : "NON-AUTHORITATIVE", dns_header(P)->aa);
10327 fprintf(stdout, ";; tc : %s(%d)\n", (dns_header(P)->tc)? "TRUNCATED" : "NOT-TRUNCATED", dns_header(P)->tc);
10328 fprintf(stdout, ";; rd : %s(%d)\n", (dns_header(P)->rd)? "RECURSION-DESIRED" : "RECURSION-NOT-DESIRED", dns_header(P)->rd);
10329 fprintf(stdout, ";; ra : %s(%d)\n", (dns_header(P)->ra)? "RECURSION-ALLOWED" : "RECURSION-NOT-ALLOWED", dns_header(P)->ra);
10330 fprintf(stdout, ";; rcode : %s(%d)\n", dns_strrcode(dns_p_rcode(P)), dns_p_rcode(P));
10334 dns_rr_foreach(&rr, P, .sort = MAIN.sort) {
10335 if (section != rr.section)
10336 fprintf(stdout, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(P, rr.section));
10338 if ((len = dns_rr_print(pretty, sizeof pretty, &rr, P, &error)))
10339 fprintf(stdout, "%s\n", pretty);
10341 dns_rr_copy(Q, &rr, P);
10343 section = rr.section;
10346 fputs("; ; ; ; ; ; ; ;\n\n", stdout);
10351 dns_rr_foreach(&rr, Q, .name = "ns8.yahoo.com.") {
10353 struct dns_rr rrset[32];
10354 struct dns_rr_i *rri = dns_rr_i_new(Q, .name = dns_d_new("ns8.yahoo.com", DNS_D_ANCHOR), .sort = MAIN.sort);
10355 unsigned rrcount = dns_rr_grep(rrset, lengthof(rrset), rri, Q, &error);
10357 for (unsigned i = 0; i < rrcount; i++) {
10360 if (section != rr.section)
10361 fprintf(stdout, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(Q, rr.section));
10363 if ((len = dns_rr_print(pretty, sizeof pretty, &rr, Q, &error)))
10364 fprintf(stdout, "%s\n", pretty);
10366 section = rr.section;
10369 if (MAIN.verbose > 1) {
10370 fprintf(stderr, "orig:%"PRIuZ"\n", P->end);
10371 hexdump(P->data, P->end, stdout);
10373 fprintf(stderr, "copy:%"PRIuZ"\n", Q->end);
10374 hexdump(Q->data, Q->end, stdout);
10378 } /* parse_packet() */
10381 static int parse_domain(int argc, char *argv[]) {
10384 dn = (argc > 1)? argv[1] : "f.l.google.com";
10386 printf("[%s]\n", dn);
10388 dn = dns_d_new(dn);
10392 } while (dns_d_cleave(dn, strlen(dn) + 1, dn, strlen(dn)));
10395 } /* parse_domain() */
10398 static int trim_domain(int argc, char **argv) {
10399 for (argc--, argv++; argc > 0; argc--, argv++) {
10400 char name[DNS_D_MAXNAME + 1];
10402 dns_d_trim(name, sizeof name, *argv, strlen(*argv), DNS_D_ANCHOR);
10408 } /* trim_domain() */
10411 static int expand_domain(int argc, char *argv[]) {
10412 unsigned short rp = 0;
10413 unsigned char *src = NULL;
10414 unsigned char *dst;
10415 struct dns_packet *pkt;
10416 size_t lim = 0, len;
10420 rp = atoi(argv[1]);
10422 len = slurp(&src, 0, stdin, "-");
10424 if (!(pkt = dns_p_make(len, &error)))
10425 panic("malloc(%"PRIuZ"): %s", len, dns_strerror(error));
10427 memcpy(pkt->data, src, len);
10431 dst = grow(NULL, lim);
10433 while (lim <= (len = dns_d_expand(dst, lim, rp, pkt, &error))) {
10435 dst = grow(dst, lim);
10439 panic("expand: %s", dns_strerror(error));
10441 fwrite(dst, 1, len, stdout);
10449 } /* expand_domain() */
10452 static int show_resconf(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
10455 resconf(); /* load it */
10457 fputs("; SOURCES\n", stdout);
10459 for (i = 0; i < MAIN.resconf.count; i++)
10460 fprintf(stdout, "; %s\n", MAIN.resconf.path[i]);
10462 for (i = 0; i < MAIN.nssconf.count; i++)
10463 fprintf(stdout, "; %s\n", MAIN.nssconf.path[i]);
10465 fputs(";\n", stdout);
10467 dns_resconf_dump(resconf(), stdout);
10470 } /* show_resconf() */
10473 static int show_nssconf(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
10478 fputs("# SOURCES\n", stdout);
10480 for (i = 0; i < MAIN.resconf.count; i++)
10481 fprintf(stdout, "# %s\n", MAIN.resconf.path[i]);
10483 for (i = 0; i < MAIN.nssconf.count; i++)
10484 fprintf(stdout, "# %s\n", MAIN.nssconf.path[i]);
10486 fputs("#\n", stdout);
10488 dns_nssconf_dump(resconf(), stdout);
10491 } /* show_nssconf() */
10494 static int show_hosts(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
10499 fputs("# SOURCES\n", stdout);
10501 for (i = 0; i < MAIN.hosts.count; i++)
10502 fprintf(stdout, "# %s\n", MAIN.hosts.path[i]);
10504 fputs("#\n", stdout);
10506 dns_hosts_dump(hosts(), stdout);
10509 } /* show_hosts() */
10512 static int query_hosts(int argc, char *argv[]) {
10513 struct dns_packet *Q = dns_p_new(512);
10514 struct dns_packet *A;
10515 char qname[DNS_D_MAXNAME + 1];
10520 MAIN.qname = (argc > 1)? argv[1] : "localhost";
10522 MAIN.qtype = DNS_T_A;
10526 if (MAIN.qtype == DNS_T_PTR && !strstr(MAIN.qname, "arpa")) {
10527 union { struct in_addr a; struct in6_addr a6; } addr;
10528 int af = (strchr(MAIN.qname, ':'))? AF_INET6 : AF_INET;
10530 if ((error = dns_pton(af, MAIN.qname, &addr)))
10531 panic("%s: %s", MAIN.qname, dns_strerror(error));
10533 qlen = dns_ptr_qname(qname, sizeof qname, af, &addr);
10535 qlen = dns_strlcpy(qname, MAIN.qname, sizeof qname);
10537 if ((error = dns_p_push(Q, DNS_S_QD, qname, qlen, MAIN.qtype, DNS_C_IN, 0, 0)))
10538 panic("%s: %s", qname, dns_strerror(error));
10540 if (!(A = dns_hosts_query(hosts(), Q, &error)))
10541 panic("%s: %s", qname, dns_strerror(error));
10543 print_packet(A, stdout);
10548 } /* query_hosts() */
10551 static int search_list(int argc, char *argv[]) {
10552 const char *qname = (argc > 1)? argv[1] : "f.l.google.com";
10553 unsigned long i = 0;
10554 char name[DNS_D_MAXNAME + 1];
10556 printf("[%s]\n", qname);
10558 while (dns_resconf_search(name, sizeof name, qname, strlen(qname), resconf(), &i))
10562 } /* search_list() */
10565 static int permute_set(int argc, char *argv[]) {
10566 unsigned lo, hi, i;
10567 struct dns_k_permutor p;
10569 hi = (--argc > 0)? atoi(argv[argc]) : 8;
10570 lo = (--argc > 0)? atoi(argv[argc]) : 0;
10572 fprintf(stderr, "[%u .. %u]\n", lo, hi);
10574 dns_k_permutor_init(&p, lo, hi);
10576 for (i = lo; i <= hi; i++)
10577 fprintf(stdout, "%u\n", dns_k_permutor_step(&p));
10578 // printf("%u -> %u -> %u\n", i, dns_k_permutor_E(&p, i), dns_k_permutor_D(&p, dns_k_permutor_E(&p, i)));
10581 } /* permute_set() */
10584 static int shuffle_16(int argc, char *argv[]) {
10588 n = 0xffff & atoi(argv[argc]);
10589 r = (--argc > 0)? (unsigned)atoi(argv[argc]) : dns_random();
10591 fprintf(stdout, "%hu\n", dns_k_shuffle16(n, r));
10595 for (n = 0; n < 65536; n++)
10596 fprintf(stdout, "%hu\n", dns_k_shuffle16(n, r));
10600 } /* shuffle_16() */
10603 static int dump_random(int argc, char *argv[]) {
10604 unsigned char b[32];
10605 unsigned i, j, n, r;
10607 n = (argc > 1)? atoi(argv[1]) : 32;
10615 for (j = 0; j < sizeof r && i < n && i < sizeof b; i++, j++) {
10619 } while (i < n && i < sizeof b);
10621 hexdump(b, i, stdout);
10627 } /* dump_random() */
10630 static int send_query(int argc, char *argv[]) {
10631 struct dns_packet *A, *Q = dns_p_new(512);
10632 char host[INET6_ADDRSTRLEN + 1];
10633 struct sockaddr_storage ss;
10634 struct dns_socket *so;
10638 ss.ss_family = (strchr(argv[1], ':'))? AF_INET6 : AF_INET;
10640 if ((error = dns_pton(ss.ss_family, argv[1], dns_sa_addr(ss.ss_family, &ss, NULL))))
10641 panic("%s: %s", argv[1], dns_strerror(error));
10643 *dns_sa_port(ss.ss_family, &ss) = htons(53);
10645 memcpy(&ss, &resconf()->nameserver[0], dns_sa_len(&resconf()->nameserver[0]));
10647 if (!dns_inet_ntop(ss.ss_family, dns_sa_addr(ss.ss_family, &ss, NULL), host, sizeof host))
10648 panic("bad host address, or none provided");
10651 MAIN.qname = "ipv6.google.com";
10653 MAIN.qtype = DNS_T_AAAA;
10655 if ((error = dns_p_push(Q, DNS_S_QD, MAIN.qname, strlen(MAIN.qname), MAIN.qtype, DNS_C_IN, 0, 0)))
10656 panic("dns_p_push: %s", dns_strerror(error));
10658 dns_header(Q)->rd = 1;
10660 if (strstr(argv[0], "udp"))
10662 else if (strstr(argv[0], "tcp"))
10663 type = SOCK_STREAM;
10665 type = dns_res_tcp2type(resconf()->options.tcp);
10667 fprintf(stderr, "querying %s for %s IN %s\n", host, MAIN.qname, dns_strtype(MAIN.qtype));
10669 if (!(so = dns_so_open((struct sockaddr *)&resconf()->iface, type, dns_opts(), &error)))
10670 panic("dns_so_open: %s", dns_strerror(error));
10672 while (!(A = dns_so_query(so, Q, (struct sockaddr *)&ss, &error))) {
10673 if (error != DNS_EAGAIN)
10674 panic("dns_so_query: %s (%d)", dns_strerror(error), error);
10675 if (dns_so_elapsed(so) > 10)
10676 panic("query timed-out");
10678 dns_so_poll(so, 1);
10681 print_packet(A, stdout);
10686 } /* send_query() */
10689 static int print_arpa(int argc, char *argv[]) {
10690 const char *ip = (argc > 1)? argv[1] : "::1";
10691 int af = (strchr(ip, ':'))? AF_INET6 : AF_INET;
10692 union { struct in_addr a4; struct in6_addr a6; } addr;
10693 char host[DNS_D_MAXNAME + 1];
10695 if (1 != dns_inet_pton(af, ip, &addr) || 0 == dns_ptr_qname(host, sizeof host, af, &addr))
10696 panic("%s: invalid address", ip);
10698 fprintf(stdout, "%s\n", host);
10701 } /* print_arpa() */
10704 static int show_hints(int argc, char *argv[]) {
10705 struct dns_hints *(*load)(struct dns_resolv_conf *, int *);
10706 const char *which, *how, *who;
10707 struct dns_hints *hints;
10710 which = (argc > 1)? argv[1] : "local";
10711 how = (argc > 2)? argv[2] : "plain";
10712 who = (argc > 3)? argv[3] : "google.com";
10714 load = (0 == strcmp(which, "local"))
10718 if (!(hints = load(resconf(), &error)))
10719 panic("%s: %s", argv[0], dns_strerror(error));
10721 if (0 == strcmp(how, "plain")) {
10722 dns_hints_dump(hints, stdout);
10724 struct dns_packet *query, *answer;
10726 query = dns_p_new(512);
10728 if ((error = dns_p_push(query, DNS_S_QUESTION, who, strlen(who), DNS_T_A, DNS_C_IN, 0, 0)))
10729 panic("%s: %s", who, dns_strerror(error));
10731 if (!(answer = dns_hints_query(hints, query, &error)))
10732 panic("%s: %s", who, dns_strerror(error));
10734 print_packet(answer, stdout);
10739 dns_hints_close(hints);
10742 } /* show_hints() */
10745 static int resolve_query(int argc DNS_NOTUSED, char *argv[]) {
10746 _Bool recurse = !!strstr(argv[0], "recurse");
10747 struct dns_hints *(*hints)() = (recurse)? &dns_hints_root : &dns_hints_local;
10748 struct dns_resolver *R;
10749 struct dns_packet *ans;
10750 const struct dns_stat *st;
10754 MAIN.qname = "www.google.com";
10756 MAIN.qtype = DNS_T_A;
10758 resconf()->options.recurse = recurse;
10760 if (!(R = dns_res_open(resconf(), hosts(), dns_hints_mortal(hints(resconf(), &error)), cache(),
10761 dns_opts(.socks_host=&MAIN.socks_host,
10762 .socks_user=MAIN.socks_user,
10763 .socks_password=MAIN.socks_password), &error)))
10764 panic("%s: %s", MAIN.qname, dns_strerror(error));
10766 dns_res_settrace(R, trace("w+b"));
10768 if ((error = dns_res_submit(R, MAIN.qname, MAIN.qtype, DNS_C_IN)))
10769 panic("%s: %s", MAIN.qname, dns_strerror(error));
10771 while ((error = dns_res_check(R))) {
10772 if (error != DNS_EAGAIN)
10773 panic("dns_res_check: %s (%d)", dns_strerror(error), error);
10774 if (dns_res_elapsed(R) > 30)
10775 panic("query timed-out");
10777 dns_res_poll(R, 1);
10780 ans = dns_res_fetch(R, &error);
10781 print_packet(ans, stdout);
10784 st = dns_res_stat(R);
10786 printf(";; queries: %"PRIuZ"\n", st->queries);
10787 printf(";; udp sent: %"PRIuZ" in %"PRIuZ" bytes\n", st->udp.sent.count, st->udp.sent.bytes);
10788 printf(";; udp rcvd: %"PRIuZ" in %"PRIuZ" bytes\n", st->udp.rcvd.count, st->udp.rcvd.bytes);
10789 printf(";; tcp sent: %"PRIuZ" in %"PRIuZ" bytes\n", st->tcp.sent.count, st->tcp.sent.bytes);
10790 printf(";; tcp rcvd: %"PRIuZ" in %"PRIuZ" bytes\n", st->tcp.rcvd.count, st->tcp.rcvd.bytes);
10795 } /* resolve_query() */
10798 static int resolve_addrinfo(int argc DNS_NOTUSED, char *argv[]) {
10799 _Bool recurse = !!strstr(argv[0], "recurse");
10800 struct dns_hints *(*hints)() = (recurse)? &dns_hints_root : &dns_hints_local;
10801 struct dns_resolver *res = NULL;
10802 struct dns_addrinfo *ai = NULL;
10803 struct addrinfo ai_hints = { .ai_family = PF_UNSPEC, .ai_socktype = SOCK_STREAM, .ai_flags = AI_CANONNAME };
10804 struct addrinfo *ent;
10809 MAIN.qname = "www.google.com";
10810 /* NB: MAIN.qtype of 0 means obey hints.ai_family */
10812 resconf()->options.recurse = recurse;
10814 if (!(res = dns_res_open(resconf(), hosts(), dns_hints_mortal(hints(resconf(), &error)), cache(), dns_opts(), &error)))
10815 panic("%s: %s", MAIN.qname, dns_strerror(error));
10817 if (!(ai = dns_ai_open(MAIN.qname, "80", MAIN.qtype, &ai_hints, res, &error)))
10818 panic("%s: %s", MAIN.qname, dns_strerror(error));
10820 dns_ai_settrace(ai, trace("w+b"));
10823 switch (error = dns_ai_nextent(&ent, ai)) {
10825 dns_ai_print(pretty, sizeof pretty, ent, ai);
10827 fputs(pretty, stdout);
10835 if (dns_ai_elapsed(ai) > 30)
10836 panic("query timed-out");
10838 dns_ai_poll(ai, 1);
10842 panic("dns_ai_nextent: %s (%d)", dns_strerror(error), error);
10844 } while (error != ENOENT);
10846 dns_res_close(res);
10850 } /* resolve_addrinfo() */
10853 static int dump_trace(int argc DNS_NOTUSED, char *argv[]) {
10857 panic("no trace file specified");
10859 if ((error = dns_trace_dump(trace("r"), stdout)))
10860 panic("dump_trace: %s", dns_strerror(error));
10863 } /* dump_trace() */
10866 static int echo_port(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
10868 struct sockaddr sa;
10869 struct sockaddr_in sin;
10873 memset(&port, 0, sizeof port);
10874 port.sin.sin_family = AF_INET;
10875 port.sin.sin_port = htons(5354);
10876 port.sin.sin_addr.s_addr = inet_addr("127.0.0.1");
10878 if (-1 == (fd = socket(PF_INET, SOCK_DGRAM, 0)))
10879 panic("socket: %s", strerror(errno));
10881 if (0 != bind(fd, &port.sa, sizeof port.sa))
10882 panic("127.0.0.1:5353: %s", dns_strerror(errno));
10885 struct dns_packet *pkt = dns_p_new(512);
10886 struct sockaddr_storage ss;
10887 socklen_t slen = sizeof ss;
10889 #if defined(MSG_WAITALL) /* MinGW issue */
10890 int rflags = MSG_WAITALL;
10895 count = recvfrom(fd, (char *)pkt->data, pkt->size, rflags, (struct sockaddr *)&ss, &slen);
10897 if (!count || count < 0)
10898 panic("recvfrom: %s", strerror(errno));
10902 dns_p_dump(pkt, stdout);
10904 (void)sendto(fd, (char *)pkt->data, pkt->end, 0, (struct sockaddr *)&ss, slen);
10908 } /* echo_port() */
10911 static int isection(int argc, char *argv[]) {
10912 const char *name = (argc > 1)? argv[1] : "";
10915 type = dns_isection(name);
10916 name = dns_strsection(type);
10918 printf("%s (%d)\n", name, type);
10924 static int iclass(int argc, char *argv[]) {
10925 const char *name = (argc > 1)? argv[1] : "";
10928 type = dns_iclass(name);
10929 name = dns_strclass(type);
10931 printf("%s (%d)\n", name, type);
10937 static int itype(int argc, char *argv[]) {
10938 const char *name = (argc > 1)? argv[1] : "";
10941 type = dns_itype(name);
10942 name = dns_strtype(type);
10944 printf("%s (%d)\n", name, type);
10950 static int iopcode(int argc, char *argv[]) {
10951 const char *name = (argc > 1)? argv[1] : "";
10954 type = dns_iopcode(name);
10955 name = dns_stropcode(type);
10957 printf("%s (%d)\n", name, type);
10963 static int ircode(int argc, char *argv[]) {
10964 const char *name = (argc > 1)? argv[1] : "";
10967 type = dns_ircode(name);
10968 name = dns_strrcode(type);
10970 printf("%s (%d)\n", name, type);
10976 #define SIZE1(x) { DNS_PP_STRINGIFY(x), sizeof (x) }
10977 #define SIZE2(x, ...) SIZE1(x), SIZE1(__VA_ARGS__)
10978 #define SIZE3(x, ...) SIZE1(x), SIZE2(__VA_ARGS__)
10979 #define SIZE4(x, ...) SIZE1(x), SIZE3(__VA_ARGS__)
10980 #define SIZE(...) DNS_PP_CALL(DNS_PP_XPASTE(SIZE, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__)
10982 static int sizes(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
10983 static const struct { const char *name; size_t size; } type[] = {
10984 SIZE(struct dns_header, struct dns_packet, struct dns_rr, struct dns_rr_i),
10985 SIZE(struct dns_a, struct dns_aaaa, struct dns_mx, struct dns_ns),
10986 SIZE(struct dns_cname, struct dns_soa, struct dns_ptr, struct dns_srv),
10987 SIZE(struct dns_sshfp, struct dns_txt, union dns_any),
10988 SIZE(struct dns_resolv_conf, struct dns_hosts, struct dns_hints, struct dns_hints_i),
10989 SIZE(struct dns_options, struct dns_socket, struct dns_resolver, struct dns_addrinfo),
10990 SIZE(struct dns_cache), SIZE(size_t), SIZE(void *), SIZE(long)
10994 for (i = 0, max = 0; i < lengthof(type); i++)
10995 max = DNS_PP_MAX(max, strlen(type[i].name));
10997 for (i = 0; i < lengthof(type); i++)
10998 printf("%*s : %"PRIuZ"\n", max, type[i].name, type[i].size);
11004 static const struct { const char *cmd; int (*run)(); const char *help; } cmds[] = {
11005 { "parse-packet", &parse_packet, "parse binary packet from stdin" },
11006 { "parse-domain", &parse_domain, "anchor and iteratively cleave domain" },
11007 { "trim-domain", &trim_domain, "trim and anchor domain name" },
11008 { "expand-domain", &expand_domain, "expand domain at offset NN in packet from stdin" },
11009 { "show-resconf", &show_resconf, "show resolv.conf data" },
11010 { "show-hosts", &show_hosts, "show hosts data" },
11011 { "show-nssconf", &show_nssconf, "show nsswitch.conf data" },
11012 { "query-hosts", &query_hosts, "query A, AAAA or PTR in hosts data" },
11013 { "search-list", &search_list, "generate query search list from domain" },
11014 { "permute-set", &permute_set, "generate random permutation -> (0 .. N or N .. M)" },
11015 { "shuffle-16", &shuffle_16, "simple 16-bit permutation" },
11016 { "dump-random", &dump_random, "generate random bytes" },
11017 { "send-query", &send_query, "send query to host" },
11018 { "send-query-udp", &send_query, "send udp query to host" },
11019 { "send-query-tcp", &send_query, "send tcp query to host" },
11020 { "print-arpa", &print_arpa, "print arpa. zone name of address" },
11021 { "show-hints", &show_hints, "print hints: show-hints [local|root] [plain|packet]" },
11022 { "resolve-stub", &resolve_query, "resolve as stub resolver" },
11023 { "resolve-recurse", &resolve_query, "resolve as recursive resolver" },
11024 { "addrinfo-stub", &resolve_addrinfo, "resolve through getaddrinfo clone" },
11025 { "addrinfo-recurse", &resolve_addrinfo, "resolve through getaddrinfo clone" },
11026 /* { "resolve-nameinfo", &resolve_query, "resolve as recursive resolver" }, */
11027 { "dump-trace", &dump_trace, "dump the contents of a trace file" },
11028 { "echo", &echo_port, "server echo mode, for nmap fuzzing" },
11029 { "isection", &isection, "parse section string" },
11030 { "iclass", &iclass, "parse class string" },
11031 { "itype", &itype, "parse type string" },
11032 { "iopcode", &iopcode, "parse opcode string" },
11033 { "ircode", &ircode, "parse rcode string" },
11034 { "sizes", &sizes, "print data structure sizes" },
11038 static void print_usage(const char *progname, FILE *fp) {
11039 static const char *usage =
11040 " [OPTIONS] COMMAND [ARGS]\n"
11041 " -c PATH Path to resolv.conf\n"
11042 " -n PATH Path to nsswitch.conf\n"
11043 " -l PATH Path to local hosts\n"
11044 " -z PATH Path to zone cache\n"
11045 " -q QNAME Query name\n"
11046 " -t QTYPE Query type\n"
11047 " -s HOW Sort records\n"
11048 " -S ADDR Address of SOCKS server to use\n"
11049 " -P PORT Port of SOCKS server to use\n"
11050 " -A USER:PASSWORD Credentials for the SOCKS server\n"
11051 " -f PATH Path to trace file\n"
11052 " -v Be more verbose (-vv show packets; -vvv hexdump packets)\n"
11053 " -V Print version info\n"
11054 " -h Print this usage message\n"
11058 fputs(progname, fp);
11061 for (i = 0, m = 0; i < lengthof(cmds); i++) {
11062 if (strlen(cmds[i].cmd) > m)
11063 m = strlen(cmds[i].cmd);
11066 for (i = 0; i < lengthof(cmds); i++) {
11067 fprintf(fp, " %s ", cmds[i].cmd);
11069 for (n = strlen(cmds[i].cmd); n < m; n++)
11072 fputs(cmds[i].help, fp);
11076 fputs("\nReport bugs to William Ahern <william@25thandClement.com>\n", fp);
11077 } /* print_usage() */
11080 static void print_version(const char *progname, FILE *fp) {
11081 fprintf(fp, "%s (dns.c) %.8X\n", progname, dns_v_rel());
11082 fprintf(fp, "vendor %s\n", dns_vendor());
11083 fprintf(fp, "release %.8X\n", dns_v_rel());
11084 fprintf(fp, "abi %.8X\n", dns_v_abi());
11085 fprintf(fp, "api %.8X\n", dns_v_api());
11086 } /* print_version() */
11089 static void main_exit(void) {
11090 dns_trace_close(MAIN.memo.trace);
11091 MAIN.memo.trace = NULL;
11092 dns_hosts_close(MAIN.memo.hosts);
11093 MAIN.memo.hosts = NULL;
11094 dns_resconf_close(MAIN.memo.resconf);
11095 MAIN.memo.resconf = NULL;
11096 } /* main_exit() */
11098 int main(int argc, char **argv) {
11100 extern char *optarg;
11101 const char *progname = argv[0];
11105 atexit(&main_exit);
11107 while (-1 != (ch = getopt(argc, argv, "q:t:c:n:l:z:s:S:P:A:f:vVh"))) {
11110 assert(MAIN.resconf.count < lengthof(MAIN.resconf.path));
11112 MAIN.resconf.path[MAIN.resconf.count++] = optarg;
11116 assert(MAIN.nssconf.count < lengthof(MAIN.nssconf.path));
11118 MAIN.nssconf.path[MAIN.nssconf.count++] = optarg;
11122 assert(MAIN.hosts.count < lengthof(MAIN.hosts.path));
11124 MAIN.hosts.path[MAIN.hosts.count++] = optarg;
11128 assert(MAIN.cache.count < lengthof(MAIN.cache.path));
11130 MAIN.cache.path[MAIN.cache.count++] = optarg;
11134 MAIN.qname = optarg;
11138 for (i = 0; i < lengthof(dns_rrtypes); i++) {
11139 if (0 == strcasecmp(dns_rrtypes[i].name, optarg))
11140 { MAIN.qtype = dns_rrtypes[i].type; break; }
11146 for (i = 0; dns_isdigit(optarg[i]); i++) {
11148 MAIN.qtype += optarg[i] - '0';
11152 panic("%s: invalid query type", optarg);
11156 if (0 == strcasecmp(optarg, "packet"))
11157 MAIN.sort = &dns_rr_i_packet;
11158 else if (0 == strcasecmp(optarg, "shuffle"))
11159 MAIN.sort = &dns_rr_i_shuffle;
11160 else if (0 == strcasecmp(optarg, "order"))
11161 MAIN.sort = &dns_rr_i_order;
11163 panic("%s: invalid sort method", optarg);
11168 struct dns_resolv_conf *conf = resconf();
11169 conf->options.tcp = DNS_RESCONF_TCP_SOCKS;
11171 MAIN.socks_host.ss_family = (strchr(optarg, ':')) ? AF_INET6 : AF_INET;
11172 if ((error = dns_pton(MAIN.socks_host.ss_family, optarg,
11173 dns_sa_addr(MAIN.socks_host.ss_family,
11174 &MAIN.socks_host, NULL))))
11175 panic("%s: %s", optarg, dns_strerror(error));
11177 *dns_sa_port(MAIN.socks_host.ss_family, &MAIN.socks_host) = htons(1080);
11182 if (! MAIN.socks_host.ss_family)
11183 panic("-P without prior -S");
11184 *dns_sa_port(MAIN.socks_host.ss_family, &MAIN.socks_host) = htons(atoi(optarg));
11189 if (! MAIN.socks_host.ss_family)
11190 panic("-A without prior -S");
11191 if (! (password = strchr(optarg, ':')))
11192 panic("Usage: -A USER:PASSWORD");
11195 MAIN.socks_user = optarg;
11196 MAIN.socks_password = password;
11200 MAIN.trace = optarg;
11204 dns_debug = ++MAIN.verbose;
11208 print_version(progname, stdout);
11212 print_usage(progname, stdout);
11216 print_usage(progname, stderr);
11218 return EXIT_FAILURE;
11225 for (i = 0; i < lengthof(cmds) && argv[0]; i++) {
11226 if (0 == strcmp(cmds[i].cmd, argv[0]))
11227 return cmds[i].run(argc, argv);
11230 print_usage(progname, stderr);
11232 return EXIT_FAILURE;
11236 #endif /* DNS_MAIN */
11240 * pop file-scoped compiler annotations
11243 #pragma clang diagnostic pop
11244 #elif DNS_GNUC_PREREQ(4,6,0)
11245 #pragma GCC diagnostic pop