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 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
292 # define EPROTO EPROTONOSUPPORT
297 #define DNS_EINTR WSAEINTR
298 #define DNS_EINPROGRESS WSAEINPROGRESS
299 #define DNS_EISCONN WSAEISCONN
300 #define DNS_EWOULDBLOCK WSAEWOULDBLOCK
301 #define DNS_EALREADY WSAEALREADY
302 #define DNS_EAGAIN EAGAIN
303 #define DNS_ETIMEDOUT WSAETIMEDOUT
305 #define dns_syerr() ((int)GetLastError())
306 #define dns_soerr() ((int)WSAGetLastError())
310 #define DNS_EINTR EINTR
311 #define DNS_EINPROGRESS EINPROGRESS
312 #define DNS_EISCONN EISCONN
313 #define DNS_EWOULDBLOCK EWOULDBLOCK
314 #define DNS_EALREADY EALREADY
315 #define DNS_EAGAIN EAGAIN
316 #define DNS_ETIMEDOUT ETIMEDOUT
318 #define dns_syerr() errno
319 #define dns_soerr() errno
324 const char *dns_strerror(int error) {
327 return "DNS packet buffer too small";
329 return "Illegal DNS RR name or data";
331 return "Attempt to push RR out of section order";
333 return "Invalid section specified";
335 return "Unknown DNS error";
337 return "Invalid textual address form";
339 return "Bad execution state (missing query packet)";
341 return "Bad execution state (missing answer packet)";
343 return "Answer already fetched";
345 return "The service passed was not recognized for the specified socket type";
347 return "The name does not resolve for the supplied parameters";
349 return "A non-recoverable error occurred when attempting to resolve the name";
351 return "Connection closed";
353 return "Reply failed verification";
355 return strerror(error);
357 } /* dns_strerror() */
361 * A T O M I C R O U T I N E S
363 * Use GCC's __atomic built-ins if possible. Unlike the __sync built-ins, we
364 * can use the preprocessor to detect API and, more importantly, ISA
365 * support. We want to avoid linking headaches where the API depends on an
366 * external library if the ISA (e.g. i386) doesn't support lockless
369 * TODO: Support C11's atomic API. Although that may require some finesse
370 * with how we define some public types, such as dns_atomic_t and struct
373 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
375 #ifndef HAVE___ATOMIC_FETCH_ADD
376 #define HAVE___ATOMIC_FETCH_ADD (defined __ATOMIC_RELAXED)
379 #ifndef HAVE___ATOMIC_FETCH_SUB
380 #define HAVE___ATOMIC_FETCH_SUB HAVE___ATOMIC_FETCH_ADD
383 #ifndef DNS_ATOMIC_FETCH_ADD
384 #if HAVE___ATOMIC_FETCH_ADD && __GCC_ATOMIC_LONG_LOCK_FREE == 2
385 #define DNS_ATOMIC_FETCH_ADD(i) __atomic_fetch_add((i), 1, __ATOMIC_RELAXED)
387 #pragma message("no atomic_fetch_add available")
388 #define DNS_ATOMIC_FETCH_ADD(i) ((*(i))++)
392 #ifndef DNS_ATOMIC_FETCH_SUB
393 #if HAVE___ATOMIC_FETCH_SUB && __GCC_ATOMIC_LONG_LOCK_FREE == 2
394 #define DNS_ATOMIC_FETCH_SUB(i) __atomic_fetch_sub((i), 1, __ATOMIC_RELAXED)
396 #pragma message("no atomic_fetch_sub available")
397 #define DNS_ATOMIC_FETCH_SUB(i) ((*(i))--)
401 static inline unsigned dns_atomic_fetch_add(dns_atomic_t *i) {
402 return DNS_ATOMIC_FETCH_ADD(i);
403 } /* dns_atomic_fetch_add() */
406 static inline unsigned dns_atomic_fetch_sub(dns_atomic_t *i) {
407 return DNS_ATOMIC_FETCH_SUB(i);
408 } /* dns_atomic_fetch_sub() */
412 * C R Y P T O R O U T I N E S
414 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
421 #if defined(HAVE_ARC4RANDOM) \
422 || defined(__OpenBSD__) \
423 || defined(__FreeBSD__) \
424 || defined(__NetBSD__) \
425 || defined(__APPLE__)
426 #define DNS_RANDOM arc4random
428 #define DNS_RANDOM random
430 #define DNS_RANDOM rand
434 #define DNS_RANDOM_arc4random 1
435 #define DNS_RANDOM_random 2
436 #define DNS_RANDOM_rand 3
437 #define DNS_RANDOM_RAND_bytes 4
439 #define DNS_RANDOM_OPENSSL (DNS_RANDOM_RAND_bytes == DNS_PP_XPASTE(DNS_RANDOM_, DNS_RANDOM))
441 #if DNS_RANDOM_OPENSSL
442 #include <openssl/rand.h>
445 static unsigned dns_random_(void) {
446 #if DNS_RANDOM_OPENSSL
450 ok = (1 == RAND_bytes((unsigned char *)&r, sizeof r));
451 assert(ok && "1 == RAND_bytes()");
457 } /* dns_random_() */
459 dns_random_f **dns_random_p(void) {
460 static dns_random_f *random_f = &dns_random_;
463 } /* dns_random_p() */
467 * P E R M U T A T I O N G E N E R A T O R
470 #define DNS_K_TEA_KEY_SIZE 16
471 #define DNS_K_TEA_BLOCK_SIZE 8
472 #define DNS_K_TEA_CYCLES 32
473 #define DNS_K_TEA_MAGIC 0x9E3779B9U
476 uint32_t key[DNS_K_TEA_KEY_SIZE / sizeof (uint32_t)];
478 }; /* struct dns_k_tea */
481 static void dns_k_tea_init(struct dns_k_tea *tea, uint32_t key[], unsigned cycles) {
482 memcpy(tea->key, key, sizeof tea->key);
484 tea->cycles = (cycles)? cycles : DNS_K_TEA_CYCLES;
485 } /* dns_k_tea_init() */
488 static void dns_k_tea_encrypt(struct dns_k_tea *tea, uint32_t v[], uint32_t *w) {
489 uint32_t y, z, sum, n;
495 for (n = 0; n < tea->cycles; n++) {
496 sum += DNS_K_TEA_MAGIC;
497 y += ((z << 4) + tea->key[0]) ^ (z + sum) ^ ((z >> 5) + tea->key[1]);
498 z += ((y << 4) + tea->key[2]) ^ (y + sum) ^ ((y >> 5) + tea->key[3]);
505 } /* dns_k_tea_encrypt() */
509 * Permutation generator, based on a Luby-Rackoff Feistel construction.
511 * Specifically, this is a generic balanced Feistel block cipher using TEA
512 * (another block cipher) as the pseudo-random function, F. At best it's as
513 * strong as F (TEA), notwithstanding the seeding. F could be AES, SHA-1, or
514 * perhaps Bernstein's Salsa20 core; I am naively trying to keep things
517 * The generator can create a permutation of any set of numbers, as long as
518 * the size of the set is an even power of 2. This limitation arises either
519 * out of an inherent property of balanced Feistel constructions, or by my
520 * own ignorance. I'll tackle an unbalanced construction after I wrap my
521 * head around Schneier and Kelsey's paper.
523 * CAVEAT EMPTOR. IANAC.
525 #define DNS_K_PERMUTOR_ROUNDS 8
527 struct dns_k_permutor {
528 unsigned stepi, length, limit;
529 unsigned shift, mask, rounds;
531 struct dns_k_tea tea;
532 }; /* struct dns_k_permutor */
535 static inline unsigned dns_k_permutor_powof(unsigned n) {
538 for (m = 1; m < n; m <<= 1, i++)
542 } /* dns_k_permutor_powof() */
544 static void dns_k_permutor_init(struct dns_k_permutor *p, unsigned low, unsigned high) {
545 uint32_t key[DNS_K_TEA_KEY_SIZE / sizeof (uint32_t)];
550 p->length = (high - low) + 1;
553 width = dns_k_permutor_powof(p->length);
556 p->shift = width / 2;
557 p->mask = (1U << p->shift) - 1;
558 p->rounds = DNS_K_PERMUTOR_ROUNDS;
560 for (i = 0; i < lengthof(key); i++)
561 key[i] = dns_random();
563 dns_k_tea_init(&p->tea, key, 0);
566 } /* dns_k_permutor_init() */
569 static unsigned dns_k_permutor_F(struct dns_k_permutor *p, unsigned k, unsigned x) {
570 uint32_t in[DNS_K_TEA_BLOCK_SIZE / sizeof (uint32_t)], out[DNS_K_TEA_BLOCK_SIZE / sizeof (uint32_t)];
572 memset(in, '\0', sizeof in);
577 dns_k_tea_encrypt(&p->tea, in, out);
579 return p->mask & out[0];
580 } /* dns_k_permutor_F() */
583 static unsigned dns_k_permutor_E(struct dns_k_permutor *p, unsigned n) {
588 l[i] = p->mask & (n >> p->shift);
589 r[i] = p->mask & (n >> 0);
592 l[(i + 1) % 2] = r[i % 2];
593 r[(i + 1) % 2] = l[i % 2] ^ dns_k_permutor_F(p, i, r[i % 2]);
596 } while (i < p->rounds - 1);
598 return ((l[i % 2] & p->mask) << p->shift) | ((r[i % 2] & p->mask) << 0);
599 } /* dns_k_permutor_E() */
602 DNS_NOTUSED static unsigned dns_k_permutor_D(struct dns_k_permutor *p, unsigned n) {
607 l[i % 2] = p->mask & (n >> p->shift);
608 r[i % 2] = p->mask & (n >> 0);
613 r[i % 2] = l[(i + 1) % 2];
614 l[i % 2] = r[(i + 1) % 2] ^ dns_k_permutor_F(p, i, l[(i + 1) % 2]);
617 return ((l[i % 2] & p->mask) << p->shift) | ((r[i % 2] & p->mask) << 0);
618 } /* dns_k_permutor_D() */
621 static unsigned dns_k_permutor_step(struct dns_k_permutor *p) {
625 n = dns_k_permutor_E(p, p->stepi++);
626 } while (n >= p->length);
628 return n + (p->limit + 1 - p->length);
629 } /* dns_k_permutor_step() */
633 * Simple permutation box. Useful for shuffling rrsets from an iterator.
634 * Uses AES s-box to provide good diffusion.
636 * Seems to pass muster under runs test.
638 * $ for i in 0 1 2 3 4 5 6 7 8 9; do ./dns shuffle-16 > /tmp/out; done
639 * $ R -q -f /dev/stdin 2>/dev/null <<-EOF | awk '/p-value/{ print $8 }'
641 * runs.test(scan(file="/tmp/out"))
644 static unsigned short dns_k_shuffle16(unsigned short n, unsigned s) {
645 static const unsigned char sbox[256] =
646 { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
647 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
648 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
649 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
650 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
651 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
652 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
653 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
654 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
655 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
656 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
657 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
658 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
659 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
660 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
661 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
662 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
663 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
664 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
665 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
666 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
667 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
668 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
669 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
670 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
671 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
672 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
673 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
674 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
675 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
676 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
677 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };
684 for (i = 0; i < 4; i++) {
691 return ((0xff00 & (a << 8)) | (0x00ff & (b << 0)));
692 } /* dns_k_shuffle16() */
695 * S T A T E M A C H I N E R O U T I N E S
697 * Application code should define DNS_SM_RESTORE and DNS_SM_SAVE, and the
700 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
702 #define DNS_SM_ENTER \
704 static const int pc0 = __LINE__; \
706 switch (pc0 + pc) { \
707 case __LINE__: (void)0
709 #define DNS_SM_SAVE_AND_DO(do_statement) \
711 pc = __LINE__ - pc0; \
714 case __LINE__: (void)0; \
717 #define DNS_SM_YIELD(rv) \
718 DNS_SM_SAVE_AND_DO(return (rv))
720 #define DNS_SM_EXIT \
721 do { goto leave; } while (0)
723 #define DNS_SM_LEAVE \
725 DNS_SM_SAVE_AND_DO(break); \
730 * U T I L I T Y R O U T I N E S
732 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
734 #define DNS_MAXINTERVAL 300
737 time_t sample, elapsed;
738 }; /* struct dns_clock */
740 static void dns_begin(struct dns_clock *clk) {
741 clk->sample = time(0);
745 static time_t dns_elapsed(struct dns_clock *clk) {
748 if ((time_t)-1 == time(&curtime))
751 if (curtime > clk->sample)
752 clk->elapsed += (time_t)DNS_PP_MIN(difftime(curtime, clk->sample), DNS_MAXINTERVAL);
754 clk->sample = curtime;
757 } /* dns_elapsed() */
760 DNS_NOTUSED static size_t dns_strnlen(const char *src, size_t m) {
763 while (*src++ && n < m)
767 } /* dns_strnlen() */
770 DNS_NOTUSED static size_t dns_strnlcpy(char *dst, size_t lim, const char *src, size_t max) {
771 size_t len = dns_strnlen(src, max), n;
774 n = DNS_PP_MIN(lim - 1, len);
780 } /* dns_strnlcpy() */
783 #define DNS_HAVE_SOCKADDR_UN (defined AF_UNIX && !defined _WIN32)
785 static size_t dns_af_len(int af) {
786 static const size_t table[AF_MAX] = {
787 [AF_INET6] = sizeof (struct sockaddr_in6),
788 [AF_INET] = sizeof (struct sockaddr_in),
789 #if DNS_HAVE_SOCKADDR_UN
790 [AF_UNIX] = sizeof (struct sockaddr_un),
797 #define dns_sa_family(sa) (((struct sockaddr *)(sa))->sa_family)
799 #define dns_sa_len(sa) dns_af_len(dns_sa_family(sa))
802 #define DNS_SA_NOPORT &dns_sa_noport
803 static unsigned short dns_sa_noport;
805 static unsigned short *dns_sa_port(int af, void *sa) {
808 return &((struct sockaddr_in6 *)sa)->sin6_port;
810 return &((struct sockaddr_in *)sa)->sin_port;
812 return DNS_SA_NOPORT;
814 } /* dns_sa_port() */
817 static void *dns_sa_addr(int af, const void *sa, socklen_t *size) {
820 struct in6_addr *in6 = &((struct sockaddr_in6 *)sa)->sin6_addr;
828 struct in_addr *in = &((struct sockaddr_in *)sa)->sin_addr;
841 } /* dns_sa_addr() */
844 #if DNS_HAVE_SOCKADDR_UN
845 #define DNS_SUNPATHMAX (sizeof ((struct sockaddr_un *)0)->sun_path)
848 DNS_NOTUSED static void *dns_sa_path(void *sa, socklen_t *size) {
849 switch (dns_sa_family(sa)) {
850 #if DNS_HAVE_SOCKADDR_UN
852 char *path = ((struct sockaddr_un *)sa)->sun_path;
855 *size = dns_strnlen(path, DNS_SUNPATHMAX);
866 } /* dns_sa_path() */
869 static int dns_sa_cmp(void *a, void *b) {
872 if ((cmp = dns_sa_family(a) - dns_sa_family(b)))
875 switch ((af = dns_sa_family(a))) {
877 struct in_addr *a4, *b4;
879 if ((cmp = htons(*dns_sa_port(af, a)) - htons(*dns_sa_port(af, b))))
882 a4 = dns_sa_addr(af, a, NULL);
883 b4 = dns_sa_addr(af, b, NULL);
885 if (ntohl(a4->s_addr) < ntohl(b4->s_addr))
887 if (ntohl(a4->s_addr) > ntohl(b4->s_addr))
893 struct in6_addr *a6, *b6;
896 if ((cmp = htons(*dns_sa_port(af, a)) - htons(*dns_sa_port(af, b))))
899 a6 = dns_sa_addr(af, a, NULL);
900 b6 = dns_sa_addr(af, b, NULL);
902 /* XXX: do we need to use in6_clearscope()? */
903 for (i = 0; i < sizeof a6->s6_addr; i++) {
904 if ((cmp = a6->s6_addr[i] - b6->s6_addr[i]))
910 #if DNS_HAVE_SOCKADDR_UN
912 char a_path[DNS_SUNPATHMAX + 1], b_path[sizeof a_path];
914 dns_strnlcpy(a_path, sizeof a_path, dns_sa_path(a, NULL), DNS_SUNPATHMAX);
915 dns_strnlcpy(b_path, sizeof b_path, dns_sa_path(b, NULL), DNS_SUNPATHMAX);
917 return strcmp(a_path, b_path);
927 static int dns_inet_pton(int af, const void *src, void *dst) {
928 union { struct sockaddr_in sin; struct sockaddr_in6 sin6; } u;
930 u.sin.sin_family = af;
932 if (0 != WSAStringToAddressA((void *)src, af, (void *)0, (struct sockaddr *)&u, &(int){ sizeof u }))
937 *(struct in6_addr *)dst = u.sin6.sin6_addr;
941 *(struct in_addr *)dst = u.sin.sin_addr;
947 } /* dns_inet_pton() */
949 static const char *dns_inet_ntop(int af, const void *src, void *dst, unsigned long lim) {
950 union { struct sockaddr_in sin; struct sockaddr_in6 sin6; } u;
952 /* NOTE: WSAAddressToString will print .sin_port unless zeroed. */
953 memset(&u, 0, sizeof u);
955 u.sin.sin_family = af;
959 u.sin6.sin6_addr = *(struct in6_addr *)src;
962 u.sin.sin_addr = *(struct in_addr *)src;
969 if (0 != WSAAddressToStringA((struct sockaddr *)&u, dns_sa_len(&u), (void *)0, dst, &lim))
973 } /* dns_inet_ntop() */
975 #define dns_inet_pton(...) inet_pton(__VA_ARGS__)
976 #define dns_inet_ntop(...) inet_ntop(__VA_ARGS__)
980 static dns_error_t dns_pton(int af, const void *src, void *dst) {
981 switch (dns_inet_pton(af, src, dst)) {
992 static dns_error_t dns_ntop(int af, const void *src, void *dst, unsigned long lim) {
993 return (dns_inet_ntop(af, src, dst, lim))? 0 : dns_soerr();
997 size_t dns_strlcpy(char *dst, const char *src, size_t lim) {
1000 const char *s = src;
1004 if ('\0' == (*d++ = *s++))
1011 while (*s++ != '\0')
1015 } /* dns_strlcpy() */
1018 size_t dns_strlcat(char *dst, const char *src, size_t lim) {
1019 char *d = memchr(dst, '\0', lim);
1020 char *e = &dst[lim];
1021 const char *s = src;
1026 if ('\0' == (*d++ = *s++))
1035 while (*s++ != '\0')
1038 return lim + (s - p - 1);
1039 } /* dns_strlcat() */
1042 static void *dns_reallocarray(void *p, size_t nmemb, size_t size, dns_error_t *error) {
1045 if (nmemb > 0 && SIZE_MAX / nmemb < size) {
1050 if (!(rp = realloc(p, nmemb * size)))
1051 *error = (errno)? errno : EINVAL;
1054 } /* dns_reallocarray() */
1059 static char *dns_strsep(char **sp, const char *delim) {
1065 *sp += strcspn(p, delim);
1074 } /* dns_strsep() */
1077 #define dns_strsep(...) strsep(__VA_ARGS__)
1082 #define strcasecmp(...) _stricmp(__VA_ARGS__)
1083 #define strncasecmp(...) _strnicmp(__VA_ARGS__)
1087 static inline _Bool dns_isalpha(unsigned char c) {
1089 } /* dns_isalpha() */
1091 static inline _Bool dns_isdigit(unsigned char c) {
1093 } /* dns_isdigit() */
1095 static inline _Bool dns_isalnum(unsigned char c) {
1097 } /* dns_isalnum() */
1099 static inline _Bool dns_isspace(unsigned char c) {
1101 } /* dns_isspace() */
1103 static inline _Bool dns_isgraph(unsigned char c) {
1105 } /* dns_isgraph() */
1108 static int dns_poll(int fd, short events, int timeout) {
1114 if (fd < 0 || (unsigned)fd >= FD_SETSIZE)
1120 if (events & DNS_POLLIN)
1123 if (events & DNS_POLLOUT)
1126 select(fd + 1, &rset, &wset, 0, (timeout >= 0)? &(struct timeval){ timeout, 0 } : NULL);
1133 DNS_NOTUSED static int dns_sigmask(int how, const sigset_t *set, sigset_t *oset) {
1135 return pthread_sigmask(how, set, oset);
1137 return (0 == sigprocmask(how, set, oset))? 0 : errno;
1139 } /* dns_sigmask() */
1143 static size_t dns_send(int fd, const void *src, size_t len, int flags, dns_error_t *error) {
1144 long n = send(fd, src, len, flags);
1147 *error = dns_soerr();
1155 static size_t dns_recv(int fd, void *dst, size_t lim, int flags, dns_error_t *error) {
1156 long n = recv(fd, dst, lim, flags);
1159 *error = dns_soerr();
1161 } else if (n == 0) {
1162 *error = (lim > 0)? DNS_ECONNFIN : EINVAL;
1170 static size_t dns_send_nopipe(int fd, const void *src, size_t len, int flags, dns_error_t *_error) {
1171 #if _WIN32 || !defined SIGPIPE || defined SO_NOSIGPIPE
1172 return dns_send(fd, src, len, flags, _error);
1173 #elif defined MSG_NOSIGNAL
1174 return dns_send(fd, src, len, (flags|MSG_NOSIGNAL), _error);
1175 #elif _POSIX_REALTIME_SIGNALS > 0 /* require sigtimedwait */
1177 * SIGPIPE handling similar to the approach described in
1178 * http://krokisplace.blogspot.com/2010/02/suppressing-sigpipe-in-library.html
1180 sigset_t pending, blocked, piped;
1184 sigemptyset(&pending);
1185 sigpending(&pending);
1187 if (!sigismember(&pending, SIGPIPE)) {
1188 sigemptyset(&piped);
1189 sigaddset(&piped, SIGPIPE);
1190 sigemptyset(&blocked);
1192 if ((error = dns_sigmask(SIG_BLOCK, &piped, &blocked)))
1196 count = dns_send(fd, src, len, flags, &error);
1198 if (!sigismember(&pending, SIGPIPE)) {
1201 if (!count && error == EPIPE) {
1202 while (-1 == sigtimedwait(&piped, NULL, &(struct timespec){ 0, 0 }) && errno == EINTR)
1206 if ((error = dns_sigmask(SIG_SETMASK, &blocked, NULL)))
1218 #error "unable to suppress SIGPIPE"
1219 return dns_send(fd, src, len, flags, _error);
1221 } /* dns_send_nopipe() */
1224 static dns_error_t dns_connect(int fd, const struct sockaddr *addr, socklen_t addrlen) {
1225 if (0 != connect(fd, addr, addrlen))
1228 } /* dns_connect() */
1231 #define DNS_FOPEN_STDFLAGS "rwabt+"
1233 static dns_error_t dns_fopen_addflag(char *dst, const char *src, size_t lim, int fc) {
1234 char *p = dst, *pe = dst + lim;
1236 /* copy standard flags */
1237 while (*src && strchr(DNS_FOPEN_STDFLAGS, *src)) {
1243 /* append flag to standard flags */
1248 /* copy remaining mode string, including '\0' */
1252 } while ((*p++ = *src++));
1255 } /* dns_fopen_addflag() */
1257 static FILE *dns_fopen(const char *path, const char *mode, dns_error_t *_error) {
1259 char mode_cloexec[32];
1262 assert(path && mode && *mode);
1268 #if _WIN32 || _WIN64
1269 if ((error = dns_fopen_addflag(mode_cloexec, mode, sizeof mode_cloexec, 'N')))
1271 if (!(fp = fopen(path, mode_cloexec)))
1274 if ((error = dns_fopen_addflag(mode_cloexec, mode, sizeof mode_cloexec, 'e')))
1276 if (!(fp = fopen(path, mode_cloexec))) {
1277 if (errno != EINVAL)
1279 if (!(fp = fopen(path, mode)))
1286 error = dns_syerr();
1294 struct dns_hxd_lines_i {
1299 #define DNS_SM_RESTORE \
1302 sp = src + state->p; \
1305 #define DNS_SM_SAVE \
1307 state->p = sp - src; \
1311 static size_t dns_hxd_lines(void *dst, size_t lim, const unsigned char *src, size_t len, struct dns_hxd_lines_i *state) {
1312 static const unsigned char hex[] = "0123456789abcdef";
1313 static const unsigned char tmpl[] = " | |\n";
1314 unsigned char ln[sizeof tmpl];
1315 const unsigned char *sp, *se;
1316 unsigned char *h, *g;
1323 memcpy(ln, tmpl, sizeof ln);
1328 for (n = 0; n < 2; n++) {
1329 for (i = 0; i < 8 && se - sp > 0; i++, sp++) {
1330 h[0] = hex[0x0f & (*sp >> 4)];
1331 h[1] = hex[0x0f & (*sp >> 0)];
1334 *g++ = (dns_isgraph(*sp))? *sp : '.';
1340 n = dns_strlcpy(dst, (char *)ln, lim);
1351 #undef DNS_SM_RESTORE
1354 * A R I T H M E T I C R O U T I N E S
1356 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1358 #define DNS_CHECK_OVERFLOW(error, r, f, ...) \
1361 *(error) = f(&_r, __VA_ARGS__); \
1365 static dns_error_t dns_clamp_overflow(uintmax_t *r, uintmax_t n, uintmax_t clamp) {
1373 } /* dns_clamp_overflow() */
1375 static dns_error_t dns_add_overflow(uintmax_t *r, uintmax_t a, uintmax_t b, uintmax_t clamp) {
1377 *r = DNS_PP_MIN(clamp, ~UINTMAX_C(0));
1380 return dns_clamp_overflow(r, a + b, clamp);
1382 } /* dns_add_overflow() */
1384 static dns_error_t dns_mul_overflow(uintmax_t *r, uintmax_t a, uintmax_t b, uintmax_t clamp) {
1385 if (a > 0 && UINTMAX_MAX / a < b) {
1386 *r = DNS_PP_MIN(clamp, ~UINTMAX_C(0));
1389 return dns_clamp_overflow(r, a * b, clamp);
1391 } /* dns_mul_overflow() */
1394 * F I X E D - S I Z E D B U F F E R R O U T I N E S
1396 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1398 #define DNS_B_INIT(src, n) { \
1399 (unsigned char *)(src), \
1400 (unsigned char *)(src), \
1401 (unsigned char *)(src) + (n), \
1404 #define DNS_B_FROM(src, n) DNS_B_INIT((src), (n))
1405 #define DNS_B_INTO(src, n) DNS_B_INIT((src), (n))
1408 const unsigned char *base;
1410 const unsigned char *pe;
1413 }; /* struct dns_buf */
1415 static inline size_t
1416 dns_b_tell(struct dns_buf *b)
1418 return b->p - b->base;
1421 static inline dns_error_t
1422 dns_b_setoverflow(struct dns_buf *b, size_t n, dns_error_t error)
1425 return b->error = error;
1428 DNS_NOTUSED static struct dns_buf *
1429 dns_b_into(struct dns_buf *b, void *src, size_t n)
1431 *b = (struct dns_buf)DNS_B_INTO(src, n);
1437 dns_b_putc(struct dns_buf *b, unsigned char uc)
1439 if (!(b->p < b->pe))
1440 return dns_b_setoverflow(b, 1, DNS_ENOBUFS);
1448 dns_b_pputc(struct dns_buf *b, unsigned char uc, size_t p)
1450 size_t pe = b->pe - b->base;
1452 return dns_b_setoverflow(b, p - pe + 1, DNS_ENOBUFS);
1454 *((unsigned char *)b->base + p) = uc;
1459 static inline dns_error_t
1460 dns_b_put16(struct dns_buf *b, uint16_t u)
1462 return dns_b_putc(b, u >> 8), dns_b_putc(b, u >> 0);
1465 static inline dns_error_t
1466 dns_b_pput16(struct dns_buf *b, uint16_t u, size_t p)
1468 if (dns_b_pputc(b, u >> 8, p) || dns_b_pputc(b, u >> 0, p + 1))
1474 DNS_NOTUSED static inline dns_error_t
1475 dns_b_put32(struct dns_buf *b, uint32_t u)
1477 return dns_b_putc(b, u >> 24), dns_b_putc(b, u >> 16),
1478 dns_b_putc(b, u >> 8), dns_b_putc(b, u >> 0);
1482 dns_b_put(struct dns_buf *b, const void *src, size_t len)
1484 size_t n = DNS_PP_MIN((size_t)(b->pe - b->p), len);
1486 memcpy(b->p, src, n);
1490 return dns_b_setoverflow(b, len - n, DNS_ENOBUFS);
1496 dns_b_puts(struct dns_buf *b, const void *src)
1498 return dns_b_put(b, src, strlen(src));
1501 DNS_NOTUSED static inline dns_error_t
1502 dns_b_fmtju(struct dns_buf *b, const uintmax_t u, const unsigned width)
1504 size_t digits, padding, overflow;
1506 unsigned char *tp, *te, tc;
1515 padding = width - DNS_PP_MIN(digits, width);
1516 overflow = (digits + padding) - DNS_PP_MIN((size_t)(b->pe - b->p), (digits + padding));
1526 if (overflow < ++digits)
1527 dns_b_putc(b, '0' + (r % 10));
1542 dns_b_popc(struct dns_buf *b)
1544 if (b->overflow && !--b->overflow)
1550 static inline const char *
1551 dns_b_tolstring(struct dns_buf *b, size_t *n)
1555 *n = b->p - b->base;
1557 return (const char *)b->base;
1558 } else if (b->p > b->base) {
1559 if (b->p[-1] != '\0') {
1560 dns_b_setoverflow(b, 1, DNS_ENOBUFS);
1563 *n = &b->p[-1] - b->base;
1565 return (const char *)b->base;
1573 static inline const char *
1574 dns_b_tostring(struct dns_buf *b)
1577 return dns_b_tolstring(b, &n);
1580 static inline size_t
1581 dns_b_strlen(struct dns_buf *b)
1584 dns_b_tolstring(b, &n);
1588 static inline size_t
1589 dns_b_strllen(struct dns_buf *b)
1591 size_t n = dns_b_strlen(b);
1592 return n + b->overflow;
1595 DNS_NOTUSED static const struct dns_buf *
1596 dns_b_from(const struct dns_buf *b, const void *src, size_t n)
1598 *(struct dns_buf *)b = (struct dns_buf)DNS_B_FROM(src, n);
1604 dns_b_getc(const struct dns_buf *_b, const int eof)
1606 struct dns_buf *b = (struct dns_buf *)_b;
1608 if (!(b->p < b->pe))
1609 return dns_b_setoverflow(b, 1, DNS_EILLEGAL), eof;
1614 static inline intmax_t
1615 dns_b_get16(const struct dns_buf *b, const intmax_t eof)
1619 n = (dns_b_getc(b, 0) << 8);
1620 n |= (dns_b_getc(b, 0) << 0);
1622 return (!b->overflow)? n : eof;
1625 DNS_NOTUSED static inline intmax_t
1626 dns_b_get32(const struct dns_buf *b, const intmax_t eof)
1630 n = (dns_b_get16(b, 0) << 16);
1631 n |= (dns_b_get16(b, 0) << 0);
1633 return (!b->overflow)? n : eof;
1636 static inline dns_error_t
1637 dns_b_move(struct dns_buf *dst, const struct dns_buf *_src, size_t n)
1639 struct dns_buf *src = (struct dns_buf *)_src;
1640 size_t src_n = DNS_PP_MIN((size_t)(src->pe - src->p), n);
1641 size_t src_r = n - src_n;
1643 dns_b_put(dst, src->p, src_n);
1647 return dns_b_setoverflow(src, src_r, DNS_EILLEGAL);
1653 * T I M E R O U T I N E S
1655 * Most functions still rely on the older time routines defined in the
1656 * utility routines section, above.
1658 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1660 #define DNS_TIME_C(n) UINT64_C(n)
1661 #define DNS_TIME_INF (~DNS_TIME_C(0))
1663 typedef uint64_t dns_time_t;
1664 typedef dns_time_t dns_microseconds_t;
1666 static dns_error_t dns_time_add(dns_time_t *r, dns_time_t a, dns_time_t b) {
1668 DNS_CHECK_OVERFLOW(&error, r, dns_add_overflow, a, b, DNS_TIME_INF);
1672 static dns_error_t dns_time_mul(dns_time_t *r, dns_time_t a, dns_time_t b) {
1674 DNS_CHECK_OVERFLOW(&error, r, dns_mul_overflow, a, b, DNS_TIME_INF);
1678 static dns_error_t dns_time_diff(dns_time_t *r, dns_time_t a, dns_time_t b) {
1688 static dns_microseconds_t dns_ts2us(const struct timespec *ts, _Bool rup) {
1690 dns_time_t sec = DNS_PP_MAX(0, ts->tv_sec);
1691 dns_time_t nsec = DNS_PP_MAX(0, ts->tv_nsec);
1692 dns_time_t usec = nsec / 1000;
1693 dns_microseconds_t r;
1695 if (rup && nsec % 1000 > 0)
1697 dns_time_mul(&r, sec, DNS_TIME_C(1000000));
1698 dns_time_add(&r, r, usec);
1702 return DNS_TIME_INF;
1706 static struct timespec *dns_tv2ts(struct timespec *ts, const struct timeval *tv) {
1708 ts->tv_sec = tv->tv_sec;
1709 ts->tv_nsec = tv->tv_usec * 1000;
1717 static size_t dns_utime_print(void *_dst, size_t lim, dns_microseconds_t us) {
1718 struct dns_buf dst = DNS_B_INTO(_dst, lim);
1720 dns_b_fmtju(&dst, us / 1000000, 1);
1721 dns_b_putc(&dst, '.');
1722 dns_b_fmtju(&dst, us % 1000000, 6);
1724 return dns_b_strllen(&dst);
1725 } /* dns_utime_print() */
1728 * P A C K E T R O U T I N E S
1730 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1732 unsigned dns_p_count(struct dns_packet *P, enum dns_section section) {
1737 return ntohs(dns_header(P)->qdcount);
1739 return ntohs(dns_header(P)->ancount);
1741 return ntohs(dns_header(P)->nscount);
1743 return ntohs(dns_header(P)->arcount);
1747 if (section & DNS_S_QD)
1748 count += ntohs(dns_header(P)->qdcount);
1749 if (section & DNS_S_AN)
1750 count += ntohs(dns_header(P)->ancount);
1751 if (section & DNS_S_NS)
1752 count += ntohs(dns_header(P)->nscount);
1753 if (section & DNS_S_AR)
1754 count += ntohs(dns_header(P)->arcount);
1758 } /* dns_p_count() */
1761 struct dns_packet *dns_p_init(struct dns_packet *P, size_t size) {
1765 assert(size >= offsetof(struct dns_packet, data) + 12);
1767 memset(P, 0, sizeof *P);
1768 P->size = size - offsetof(struct dns_packet, data);
1771 memset(P->data, '\0', 12);
1774 } /* dns_p_init() */
1777 static struct dns_packet *dns_p_reset(struct dns_packet *P) {
1778 return dns_p_init(P, offsetof(struct dns_packet, data) + P->size);
1779 } /* dns_p_reset() */
1782 static unsigned short dns_p_qend(struct dns_packet *P) {
1783 unsigned short qend = 12;
1784 unsigned i, count = dns_p_count(P, DNS_S_QD);
1786 for (i = 0; i < count && qend < P->end; i++) {
1787 if (P->end == (qend = dns_d_skip(qend, P)))
1790 if (P->end - qend < 4)
1796 return DNS_PP_MIN(qend, P->end);
1799 } /* dns_p_qend() */
1802 struct dns_packet *dns_p_make(size_t len, int *error) {
1803 struct dns_packet *P;
1804 size_t size = dns_p_calcsize(len);
1806 if (!(P = dns_p_init(malloc(size), size)))
1807 *error = dns_syerr();
1810 } /* dns_p_make() */
1813 static void dns_p_free(struct dns_packet *P) {
1815 } /* dns_p_free() */
1818 /* convience routine to free any existing packet before storing new packet */
1819 static struct dns_packet *dns_p_setptr(struct dns_packet **dst, struct dns_packet *src) {
1825 } /* dns_p_setptr() */
1828 static struct dns_packet *dns_p_movptr(struct dns_packet **dst, struct dns_packet **src) {
1829 dns_p_setptr(dst, *src);
1834 } /* dns_p_movptr() */
1837 int dns_p_grow(struct dns_packet **P) {
1838 struct dns_packet *tmp;
1843 if (!(*P = dns_p_make(DNS_P_QBUFSIZ, &error)))
1849 size = dns_p_sizeof(*P);
1859 if (!(tmp = realloc(*P, dns_p_calcsize(size))))
1866 } /* dns_p_grow() */
1869 struct dns_packet *dns_p_copy(struct dns_packet *P, const struct dns_packet *P0) {
1873 P->end = DNS_PP_MIN(P->size, P0->end);
1875 memcpy(P->data, P0->data, P->end);
1878 } /* dns_p_copy() */
1881 struct dns_packet *dns_p_merge(struct dns_packet *A, enum dns_section Amask, struct dns_packet *B, enum dns_section Bmask, int *error_) {
1882 size_t bufsiz = DNS_PP_MIN(65535, ((A)? A->end : 0) + ((B)? B->end : 0));
1883 struct dns_packet *M;
1884 enum dns_section section;
1885 struct dns_rr rr, mr;
1895 if (!(M = dns_p_make(bufsiz, &error)))
1898 for (section = DNS_S_QD; (DNS_S_ALL & section); section <<= 1) {
1899 if (A && (section & Amask)) {
1900 dns_rr_foreach(&rr, A, .section = section) {
1901 if ((error = dns_rr_copy(M, &rr, A)))
1906 if (B && (section & Bmask)) {
1907 dns_rr_foreach(&rr, B, .section = section) {
1910 dns_rr_foreach(&mr, M, .type = rr.type, .section = DNS_S_ALL) {
1911 if (!(copy = dns_rr_cmp(&rr, B, &mr, M)))
1915 if (copy && (error = dns_rr_copy(M, &rr, B)))
1923 dns_p_setptr(&M, NULL);
1925 if (error == DNS_ENOBUFS && bufsiz < 65535) {
1926 bufsiz = DNS_PP_MIN(65535, bufsiz * 2);
1934 } /* dns_p_merge() */
1937 static unsigned short dns_l_skip(unsigned short, const unsigned char *, size_t);
1939 void dns_p_dictadd(struct dns_packet *P, unsigned short dn) {
1940 unsigned short lp, lptr, i;
1944 while (lp < P->end) {
1945 if (0xc0 == (0xc0 & P->data[lp]) && P->end - lp >= 2 && lp != dn) {
1946 lptr = ((0x3f & P->data[lp + 0]) << 8)
1947 | ((0xff & P->data[lp + 1]) << 0);
1949 for (i = 0; i < lengthof(P->dict) && P->dict[i]; i++) {
1950 if (P->dict[i] == lptr) {
1958 lp = dns_l_skip(lp, P->data, P->end);
1961 for (i = 0; i < lengthof(P->dict); i++) {
1968 } /* dns_p_dictadd() */
1971 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) {
1972 size_t end = P->end;
1975 if ((error = dns_d_push(P, dn, dnlen)))
1978 if (P->size - P->end < 4)
1981 P->data[P->end++] = 0xff & (type >> 8);
1982 P->data[P->end++] = 0xff & (type >> 0);
1984 P->data[P->end++] = 0xff & (class >> 8);
1985 P->data[P->end++] = 0xff & (class >> 0);
1987 if (section == DNS_S_QD)
1990 if (P->size - P->end < 6)
1993 if (type != DNS_T_OPT)
1994 ttl = DNS_PP_MIN(ttl, 0x7fffffffU);
1995 P->data[P->end++] = ttl >> 24;
1996 P->data[P->end++] = ttl >> 16;
1997 P->data[P->end++] = ttl >> 8;
1998 P->data[P->end++] = ttl >> 0;
2000 if ((error = dns_any_push(P, (union dns_any *)any, type)))
2006 if (dns_p_count(P, DNS_S_AN|DNS_S_NS|DNS_S_AR))
2009 if (!P->memo.qd.base && (error = dns_p_study(P)))
2012 dns_header(P)->qdcount = htons(ntohs(dns_header(P)->qdcount) + 1);
2014 P->memo.qd.end = P->end;
2015 P->memo.an.base = P->end;
2016 P->memo.an.end = P->end;
2017 P->memo.ns.base = P->end;
2018 P->memo.ns.end = P->end;
2019 P->memo.ar.base = P->end;
2020 P->memo.ar.end = P->end;
2024 if (dns_p_count(P, DNS_S_NS|DNS_S_AR))
2027 if (!P->memo.an.base && (error = dns_p_study(P)))
2030 dns_header(P)->ancount = htons(ntohs(dns_header(P)->ancount) + 1);
2032 P->memo.an.end = P->end;
2033 P->memo.ns.base = P->end;
2034 P->memo.ns.end = P->end;
2035 P->memo.ar.base = P->end;
2036 P->memo.ar.end = P->end;
2040 if (dns_p_count(P, DNS_S_AR))
2043 if (!P->memo.ns.base && (error = dns_p_study(P)))
2046 dns_header(P)->nscount = htons(ntohs(dns_header(P)->nscount) + 1);
2048 P->memo.ns.end = P->end;
2049 P->memo.ar.base = P->end;
2050 P->memo.ar.end = P->end;
2054 if (!P->memo.ar.base && (error = dns_p_study(P)))
2057 dns_header(P)->arcount = htons(ntohs(dns_header(P)->arcount) + 1);
2059 P->memo.ar.end = P->end;
2061 if (type == DNS_T_OPT && !P->memo.opt.p) {
2062 P->memo.opt.p = end;
2063 P->memo.opt.maxudp = class;
2064 P->memo.opt.ttl = ttl;
2069 error = DNS_ESECTION;
2076 error = DNS_ENOBUFS;
2087 } /* dns_p_push() */
2089 #define DNS_SM_RESTORE do { pc = state->pc; error = state->error; } while (0)
2090 #define DNS_SM_SAVE do { state->error = error; state->pc = pc; } while (0)
2092 struct dns_p_lines_i {
2094 enum dns_section section;
2099 static size_t dns_p_lines_fmt(void *dst, size_t lim, dns_error_t *_error, const char *fmt, ...) {
2104 if ((n = vsnprintf(dst, lim, fmt, ap)) < 0)
2109 return DNS_PP_MAX(n, 0);
2110 } /* dns_p_lines_fmt() */
2112 #define DNS_P_LINE(...) \
2114 len = dns_p_lines_fmt(dst, lim, &error, __VA_ARGS__); \
2115 if (len == 0 && error) \
2117 DNS_SM_YIELD(len); \
2120 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) {
2128 DNS_P_LINE(";; [HEADER]\n");
2129 DNS_P_LINE(";; qid : %d\n", ntohs(dns_header(P)->qid));
2130 DNS_P_LINE(";; qr : %s(%d)\n", (dns_header(P)->qr)? "RESPONSE" : "QUERY", dns_header(P)->qr);
2131 DNS_P_LINE(";; opcode : %s(%d)\n", dns_stropcode(dns_header(P)->opcode), dns_header(P)->opcode);
2132 DNS_P_LINE(";; aa : %s(%d)\n", (dns_header(P)->aa)? "AUTHORITATIVE" : "NON-AUTHORITATIVE", dns_header(P)->aa);
2133 DNS_P_LINE(";; tc : %s(%d)\n", (dns_header(P)->tc)? "TRUNCATED" : "NOT-TRUNCATED", dns_header(P)->tc);
2134 DNS_P_LINE(";; rd : %s(%d)\n", (dns_header(P)->rd)? "RECURSION-DESIRED" : "RECURSION-NOT-DESIRED", dns_header(P)->rd);
2135 DNS_P_LINE(";; ra : %s(%d)\n", (dns_header(P)->ra)? "RECURSION-ALLOWED" : "RECURSION-NOT-ALLOWED", dns_header(P)->ra);
2136 DNS_P_LINE(";; rcode : %s(%d)\n", dns_strrcode(dns_p_rcode(P)), dns_p_rcode(P));
2138 while (dns_rr_grep(&state->rr, 1, I, P, &error)) {
2139 if (state->section != state->rr.section) {
2141 DNS_P_LINE(";; [%s:%d]\n", dns_strsection(state->rr.section), dns_p_count(P, state->rr.section));
2144 if (!(len = dns_rr_print(dst, lim, &state->rr, P, &error)))
2146 dns_strlcat(dst, "\n", lim);
2147 DNS_SM_YIELD(len + 1);
2149 state->section = state->rr.section;
2166 } /* dns_p_lines() */
2170 #undef DNS_SM_RESTORE
2172 static void dns_p_dump3(struct dns_packet *P, struct dns_rr_i *I, FILE *fp) {
2173 struct dns_p_lines_i lines = { 0 };
2174 char line[sizeof (union dns_any) * 2];
2178 while ((len = dns_p_lines(line, sizeof line, &error, P, I, &lines))) {
2179 if (len < sizeof line) {
2180 fwrite(line, 1, len, fp);
2182 fwrite(line, 1, sizeof line - 1, fp);
2186 } /* dns_p_dump3() */
2189 void dns_p_dump(struct dns_packet *P, FILE *fp) {
2190 dns_p_dump3(P, dns_rr_i_new(P, .section = 0), fp);
2191 } /* dns_p_dump() */
2194 static void dns_s_unstudy(struct dns_s_memo *m)
2195 { m->base = 0; m->end = 0; }
2197 static void dns_m_unstudy(struct dns_p_memo *m) {
2198 dns_s_unstudy(&m->qd);
2199 dns_s_unstudy(&m->an);
2200 dns_s_unstudy(&m->ns);
2201 dns_s_unstudy(&m->ar);
2205 } /* dns_m_unstudy() */
2207 static int dns_s_study(struct dns_s_memo *m, enum dns_section section, unsigned short base, struct dns_packet *P) {
2208 unsigned short count, rp;
2210 count = dns_p_count(P, section);
2212 for (rp = base; count && rp < P->end; count--)
2213 rp = dns_rr_skip(rp, P);
2219 } /* dns_s_study() */
2221 static int dns_m_study(struct dns_p_memo *m, struct dns_packet *P) {
2225 if ((error = dns_s_study(&m->qd, DNS_S_QD, 12, P)))
2227 if ((error = dns_s_study(&m->an, DNS_S_AN, m->qd.end, P)))
2229 if ((error = dns_s_study(&m->ns, DNS_S_NS, m->an.end, P)))
2231 if ((error = dns_s_study(&m->ar, DNS_S_AR, m->ns.end, P)))
2237 dns_rr_foreach(&rr, P, .type = DNS_T_OPT, .section = DNS_S_AR) {
2239 m->opt.maxudp = rr.class;
2240 m->opt.ttl = rr.ttl;
2249 } /* dns_m_study() */
2251 int dns_p_study(struct dns_packet *P) {
2252 return dns_m_study(&P->memo, P);
2253 } /* dns_p_study() */
2256 enum dns_rcode dns_p_rcode(struct dns_packet *P) {
2257 return 0xfff & ((P->memo.opt.ttl >> 20) | dns_header(P)->rcode);
2258 } /* dns_p_rcode() */
2262 * Q U E R Y P A C K E T R O U T I N E S
2264 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2266 #define DNS_Q_RD 0x1 /* recursion desired */
2267 #define DNS_Q_EDNS0 0x2 /* include OPT RR */
2270 dns_q_make2(struct dns_packet **_Q, const char *qname, size_t qlen, enum dns_type qtype, enum dns_class qclass, int qflags)
2272 struct dns_packet *Q = NULL;
2275 if (dns_p_movptr(&Q, _Q)) {
2277 } else if (!(Q = dns_p_make(DNS_P_QBUFSIZ, &error))) {
2281 if ((error = dns_p_push(Q, DNS_S_QD, qname, qlen, qtype, qclass, 0, 0)))
2284 dns_header(Q)->rd = !!(qflags & DNS_Q_RD);
2286 if (qflags & DNS_Q_EDNS0) {
2287 struct dns_opt opt = DNS_OPT_INIT(&opt);
2289 opt.version = 0; /* RFC 6891 version */
2292 if ((error = dns_p_push(Q, DNS_S_AR, ".", 1, DNS_T_OPT, dns_opt_class(&opt), dns_opt_ttl(&opt), &opt)))
2306 dns_q_make(struct dns_packet **Q, const char *qname, enum dns_type qtype, enum dns_class qclass, int qflags)
2308 return dns_q_make2(Q, qname, strlen(qname), qtype, qclass, qflags);
2312 dns_q_remake(struct dns_packet **Q, int qflags)
2314 char qname[DNS_D_MAXNAME + 1];
2320 if ((error = dns_rr_parse(&rr, 12, *Q)))
2322 if (!(qlen = dns_d_expand(qname, sizeof qname, rr.dn.p, *Q, &error)))
2324 if (qlen >= sizeof qname)
2325 return DNS_EILLEGAL;
2326 return dns_q_make2(Q, qname, qlen, rr.type, rr.class, qflags);
2330 * D O M A I N N A M E R O U T I N E S
2332 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2334 #ifndef DNS_D_MAXPTRS
2335 #define DNS_D_MAXPTRS 127 /* Arbitrary; possible, valid depth is something like packet size / 2 + fudge. */
2338 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) {
2346 switch (0x03 & (data[src] >> 6)) {
2348 len = (0x3f & (data[src++]));
2350 if (end - src < len)
2354 memcpy(dst, &data[src], DNS_PP_MIN(lim, len));
2356 dst[DNS_PP_MIN(lim - 1, len)] = '\0';
2367 if (++nptrs > DNS_D_MAXPTRS)
2373 src = ((0x3f & data[src + 0]) << 8)
2374 | ((0xff & data[src + 1]) << 0);
2384 } /* dns_l_expand() */
2387 static unsigned short dns_l_skip(unsigned short src, const unsigned char *data, size_t end) {
2393 switch (0x03 & (data[src] >> 6)) {
2395 len = (0x3f & (data[src++]));
2397 if (end - src < len)
2400 return (len)? src + len : end;
2412 } /* dns_l_skip() */
2415 static _Bool dns_d_isanchored(const void *_src, size_t len) {
2416 const unsigned char *src = _src;
2417 return len > 0 && src[len - 1] == '.';
2418 } /* dns_d_isanchored() */
2421 static size_t dns_d_ndots(const void *_src, size_t len) {
2422 const unsigned char *p = _src, *pe = p + len;
2425 while ((p = memchr(p, '.', pe - p))) {
2431 } /* dns_d_ndots() */
2434 static size_t dns_d_trim(void *dst_, size_t lim, const void *src_, size_t len, int flags) {
2435 unsigned char *dst = dst_;
2436 const unsigned char *src = src_;
2437 size_t dp = 0, sp = 0;
2440 /* trim any leading dot(s) */
2441 while (sp < len && src[sp] == '.')
2444 for (lc = 0; sp < len; lc = src[sp++]) {
2445 /* trim extra dot(s) */
2446 if (src[sp] == '.' && lc == '.')
2455 if ((flags & DNS_D_ANCHOR) && lc != '.') {
2463 dst[DNS_PP_MIN(dp, lim - 1)] = '\0';
2466 } /* dns_d_trim() */
2469 char *dns_d_init(void *dst, size_t lim, const void *src, size_t len, int flags) {
2470 if (flags & DNS_D_TRIM) {
2471 dns_d_trim(dst, lim, src, len, flags);
2472 } if (flags & DNS_D_ANCHOR) {
2473 dns_d_anchor(dst, lim, src, len);
2475 memmove(dst, src, DNS_PP_MIN(lim, len));
2478 ((char *)dst)[DNS_PP_MIN(len, lim - 1)] = '\0';
2482 } /* dns_d_init() */
2485 size_t dns_d_anchor(void *dst, size_t lim, const void *src, size_t len) {
2489 memmove(dst, src, DNS_PP_MIN(lim, len));
2491 if (((const char *)src)[len - 1] != '.') {
2493 ((char *)dst)[len] = '.';
2498 ((char *)dst)[DNS_PP_MIN(lim - 1, len)] = '\0';
2501 } /* dns_d_anchor() */
2504 size_t dns_d_cleave(void *dst, size_t lim, const void *src, size_t len) {
2507 /* XXX: Skip any leading dot. Handles cleaving root ".". */
2508 if (len == 0 || !(dot = memchr((const char *)src + 1, '.', len - 1)))
2511 len -= dot - (const char *)src;
2513 /* XXX: Unless root, skip the label's trailing dot. */
2520 memmove(dst, src, DNS_PP_MIN(lim, len));
2523 ((char *)dst)[DNS_PP_MIN(lim - 1, len)] = '\0';
2526 } /* dns_d_cleave() */
2529 size_t dns_d_comp(void *dst_, size_t lim, const void *src_, size_t len, struct dns_packet *P, int *error) {
2530 struct { unsigned char *b; size_t p, x; } dst, src;
2531 unsigned char ch = '.';
2537 src.b = (unsigned char *)src_;
2541 while (src.x < len) {
2546 dst.b[dst.p] = (0x3f & (src.x - src.p));
2559 if (src.x > src.p) {
2561 dst.b[dst.p] = (0x3f & (src.x - src.p));
2568 dst.b[dst.p] = 0x00;
2575 struct { unsigned char label[DNS_D_MAXLABEL + 1]; size_t len; unsigned short p, x, y; } a, b;
2580 while ((a.len = dns_l_expand(a.label, sizeof a.label, a.p, &a.x, dst.b, lim))) {
2581 for (i = 0; i < lengthof(P->dict) && P->dict[i]; i++) {
2584 while ((b.len = dns_l_expand(b.label, sizeof b.label, b.p, &b.x, P->data, P->end))) {
2588 while (a.len && b.len && 0 == strcasecmp((char *)a.label, (char *)b.label)) {
2589 a.len = dns_l_expand(a.label, sizeof a.label, a.y, &a.y, dst.b, lim);
2590 b.len = dns_l_expand(b.label, sizeof b.label, b.y, &b.y, P->data, P->end);
2593 if (a.len == 0 && b.len == 0 && b.p <= 0x3fff) {
2595 | (0x3f & (b.p >> 8));
2596 dst.b[a.p++] = (0xff & (b.p >> 0));
2598 /* silence static analyzers */
2599 dns_assume(a.p > 0);
2614 *error = DNS_EILLEGAL;
2617 } /* dns_d_comp() */
2620 unsigned short dns_d_skip(unsigned short src, struct dns_packet *P) {
2623 while (src < P->end) {
2624 switch (0x03 & (P->data[src] >> 6)) {
2625 case 0x00: /* FOLLOWS */
2626 len = (0x3f & P->data[src++]);
2629 /* success ==> */ return src;
2630 } else if (P->end - src > len) {
2638 case 0x01: /* RESERVED */
2640 case 0x02: /* RESERVED */
2642 case 0x03: /* POINTER */
2643 if (P->end - src < 2)
2648 /* success ==> */ return src;
2654 } /* dns_d_skip() */
2659 size_t dns_d_expand(void *dst, size_t lim, unsigned short src, struct dns_packet *P, int *error) {
2664 while (src < P->end) {
2665 switch ((0x03 & (P->data[src] >> 6))) {
2666 case 0x00: /* FOLLOWS */
2667 len = (0x3f & P->data[src]);
2672 ((unsigned char *)dst)[dstp] = '.';
2679 ((unsigned char *)dst)[DNS_PP_MIN(dstp, lim - 1)] = '\0';
2681 /* success ==> */ return dstp;
2686 if (P->end - src < len)
2690 memcpy(&((unsigned char *)dst)[dstp], &P->data[src], DNS_PP_MIN(len, lim - dstp));
2696 ((unsigned char *)dst)[dstp] = '.';
2703 case 0x01: /* RESERVED */
2705 case 0x02: /* RESERVED */
2707 case 0x03: /* POINTER */
2708 if (++nptrs > DNS_D_MAXPTRS)
2711 if (P->end - src < 2)
2714 src = ((0x3f & P->data[src + 0]) << 8)
2715 | ((0xff & P->data[src + 1]) << 0);
2722 *error = DNS_EILLEGAL;
2725 ((unsigned char *)dst)[DNS_PP_MIN(dstp, lim - 1)] = '\0';
2729 *error = DNS_EILLEGAL;
2732 ((unsigned char *)dst)[DNS_PP_MIN(dstp, lim - 1)] = '\0';
2735 } /* dns_d_expand() */
2738 int dns_d_push(struct dns_packet *P, const void *dn, size_t len) {
2739 size_t lim = P->size - P->end;
2740 unsigned dp = P->end;
2741 int error = DNS_EILLEGAL; /* silence compiler */
2743 len = dns_d_comp(&P->data[dp], lim, dn, len, P, &error);
2752 dns_p_dictadd(P, dp);
2755 } /* dns_d_push() */
2758 size_t dns_d_cname(void *dst, size_t lim, const void *dn, size_t len, struct dns_packet *P, int *error_) {
2759 char host[DNS_D_MAXNAME + 1];
2765 if (sizeof host <= dns_d_anchor(host, sizeof host, dn, len))
2766 { error = ENAMETOOLONG; goto error; }
2768 for (depth = 0; depth < 7; depth++) {
2769 dns_rr_i_init(memset(&i, 0, sizeof i), P);
2771 i.section = DNS_S_ALL & ~DNS_S_QD;
2773 i.type = DNS_T_CNAME;
2775 if (!dns_rr_grep(&rr, 1, &i, P, &error))
2778 if ((error = dns_cname_parse((struct dns_cname *)host, &rr, P)))
2782 return dns_strlcpy(dst, host, lim);
2787 } /* dns_d_cname() */
2791 * R E S O U R C E R E C O R D R O U T I N E S
2793 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2795 int dns_rr_copy(struct dns_packet *P, struct dns_rr *rr, struct dns_packet *Q) {
2796 unsigned char dn[DNS_D_MAXNAME + 1];
2801 if (!(len = dns_d_expand(dn, sizeof dn, rr->dn.p, Q, &error)))
2803 else if (len >= sizeof dn)
2804 return DNS_EILLEGAL;
2806 if (rr->section != DNS_S_QD && (error = dns_any_parse(dns_any_init(&any, sizeof any), rr, Q)))
2809 return dns_p_push(P, rr->section, dn, len, rr->type, rr->class, rr->ttl, &any);
2810 } /* dns_rr_copy() */
2813 int dns_rr_parse(struct dns_rr *rr, unsigned short src, struct dns_packet *P) {
2814 unsigned short p = src;
2820 rr->dn.len = (p = dns_d_skip(p, P)) - rr->dn.p;
2825 rr->type = ((0xff & P->data[p + 0]) << 8)
2826 | ((0xff & P->data[p + 1]) << 0);
2828 rr->class = ((0xff & P->data[p + 2]) << 8)
2829 | ((0xff & P->data[p + 3]) << 0);
2833 if (src < dns_p_qend(P)) {
2834 rr->section = DNS_S_QUESTION;
2846 rr->ttl = ((0xff & P->data[p + 0]) << 24)
2847 | ((0xff & P->data[p + 1]) << 16)
2848 | ((0xff & P->data[p + 2]) << 8)
2849 | ((0xff & P->data[p + 3]) << 0);
2850 if (rr->type != DNS_T_OPT)
2851 rr->ttl = DNS_PP_MIN(rr->ttl, 0x7fffffffU);
2858 rr->rd.len = ((0xff & P->data[p + 0]) << 8)
2859 | ((0xff & P->data[p + 1]) << 0);
2864 if (P->end - p < rr->rd.len)
2869 return DNS_EILLEGAL;
2870 } /* dns_rr_parse() */
2873 static unsigned short dns_rr_len(const unsigned short src, struct dns_packet *P) {
2874 unsigned short rp, rdlen;
2876 rp = dns_d_skip(src, P);
2878 if (P->end - rp < 4)
2879 return P->end - src;
2881 rp += 4; /* TYPE, CLASS */
2883 if (rp <= dns_p_qend(P))
2886 if (P->end - rp < 6)
2887 return P->end - src;
2889 rp += 6; /* TTL, RDLEN */
2891 rdlen = ((0xff & P->data[rp - 2]) << 8)
2892 | ((0xff & P->data[rp - 1]) << 0);
2894 if (P->end - rp < rdlen)
2895 return P->end - src;
2900 } /* dns_rr_len() */
2903 unsigned short dns_rr_skip(unsigned short src, struct dns_packet *P) {
2904 return src + dns_rr_len(src, P);
2905 } /* dns_rr_skip() */
2908 static enum dns_section dns_rr_section(unsigned short src, struct dns_packet *P) {
2909 enum dns_section section;
2910 unsigned count, index;
2913 if (src >= P->memo.qd.base && src < P->memo.qd.end)
2915 if (src >= P->memo.an.base && src < P->memo.an.end)
2917 if (src >= P->memo.ns.base && src < P->memo.ns.end)
2919 if (src >= P->memo.ar.base && src < P->memo.ar.end)
2922 /* NOTE: Possibly bad memoization. Try it the hard-way. */
2924 for (rp = 12, index = 0; rp < src && rp < P->end; index++)
2925 rp = dns_rr_skip(rp, P);
2928 count = dns_p_count(P, section);
2930 while (index >= count && section <= DNS_S_AR) {
2932 count += dns_p_count(P, section);
2935 return DNS_S_ALL & section;
2936 } /* dns_rr_section() */
2939 static enum dns_type dns_rr_type(unsigned short src, struct dns_packet *P) {
2943 if ((error = dns_rr_parse(&rr, src, P)))
2947 } /* dns_rr_type() */
2950 int dns_rr_cmp(struct dns_rr *r0, struct dns_packet *P0, struct dns_rr *r1, struct dns_packet *P1) {
2951 char host0[DNS_D_MAXNAME + 1], host1[DNS_D_MAXNAME + 1];
2952 union dns_any any0, any1;
2956 if ((cmp = r0->type - r1->type))
2959 if ((cmp = r0->class - r1->class))
2963 * FIXME: Do label-by-label comparison to handle illegally long names?
2966 if (!(len = dns_d_expand(host0, sizeof host0, r0->dn.p, P0, &error))
2967 || len >= sizeof host0)
2970 if (!(len = dns_d_expand(host1, sizeof host1, r1->dn.p, P1, &error))
2971 || len >= sizeof host1)
2974 if ((cmp = strcasecmp(host0, host1)))
2977 if (DNS_S_QD & (r0->section | r1->section)) {
2978 if (r0->section == r1->section)
2981 return (r0->section == DNS_S_QD)? -1 : 1;
2984 if ((error = dns_any_parse(&any0, r0, P0)))
2987 if ((error = dns_any_parse(&any1, r1, P1)))
2990 return dns_any_cmp(&any0, r0->type, &any1, r1->type);
2991 } /* dns_rr_cmp() */
2994 static _Bool dns_rr_exists(struct dns_rr *rr0, struct dns_packet *P0, struct dns_packet *P1) {
2997 dns_rr_foreach(&rr1, P1, .section = rr0->section, .type = rr0->type) {
2998 if (0 == dns_rr_cmp(rr0, P0, &rr1, P1))
3003 } /* dns_rr_exists() */
3006 static unsigned short dns_rr_offset(struct dns_rr *rr) {
3008 } /* dns_rr_offset() */
3011 static _Bool dns_rr_i_match(struct dns_rr *rr, struct dns_rr_i *i, struct dns_packet *P) {
3012 if (i->section && !(rr->section & i->section))
3015 if (i->type && rr->type != i->type && i->type != DNS_T_ALL)
3018 if (i->class && rr->class != i->class && i->class != DNS_C_ANY)
3022 char dn[DNS_D_MAXNAME + 1];
3026 if (!(len = dns_d_expand(dn, sizeof dn, rr->dn.p, P, &error))
3027 || len >= sizeof dn)
3030 if (0 != strcasecmp(dn, i->name))
3034 if (i->data && i->type && rr->section > DNS_S_QD) {
3038 if ((error = dns_any_parse(&rd, rr, P)))
3041 if (0 != dns_any_cmp(&rd, rr->type, i->data, i->type))
3046 } /* dns_rr_i_match() */
3049 static unsigned short dns_rr_i_start(struct dns_rr_i *i, struct dns_packet *P) {
3051 struct dns_rr r0, rr;
3054 if ((i->section & DNS_S_QD) && P->memo.qd.base)
3055 rp = P->memo.qd.base;
3056 else if ((i->section & DNS_S_AN) && P->memo.an.base)
3057 rp = P->memo.an.base;
3058 else if ((i->section & DNS_S_NS) && P->memo.ns.base)
3059 rp = P->memo.ns.base;
3060 else if ((i->section & DNS_S_AR) && P->memo.ar.base)
3061 rp = P->memo.ar.base;
3065 for (; rp < P->end; rp = dns_rr_skip(rp, P)) {
3066 if ((error = dns_rr_parse(&rr, rp, P)))
3069 rr.section = dns_rr_section(rp, P);
3071 if (!dns_rr_i_match(&rr, i, P))
3081 if (i->sort == &dns_rr_i_packet)
3082 return dns_rr_offset(&r0);
3084 while ((rp = dns_rr_skip(rp, P)) < P->end) {
3085 if ((error = dns_rr_parse(&rr, rp, P)))
3088 rr.section = dns_rr_section(rp, P);
3090 if (!dns_rr_i_match(&rr, i, P))
3093 if (i->sort(&rr, &r0, i, P) < 0)
3097 return dns_rr_offset(&r0);
3098 } /* dns_rr_i_start() */
3101 static unsigned short dns_rr_i_skip(unsigned short rp, struct dns_rr_i *i, struct dns_packet *P) {
3102 struct dns_rr r0, r1, rr;
3105 if ((error = dns_rr_parse(&r0, rp, P)))
3108 r0.section = dns_rr_section(rp, P);
3110 rp = (i->sort == &dns_rr_i_packet)? dns_rr_skip(rp, P) : 12;
3112 for (; rp < P->end; rp = dns_rr_skip(rp, P)) {
3113 if ((error = dns_rr_parse(&rr, rp, P)))
3116 rr.section = dns_rr_section(rp, P);
3118 if (!dns_rr_i_match(&rr, i, P))
3121 if (i->sort(&rr, &r0, i, P) <= 0)
3131 if (i->sort == &dns_rr_i_packet)
3132 return dns_rr_offset(&r1);
3134 while ((rp = dns_rr_skip(rp, P)) < P->end) {
3135 if ((error = dns_rr_parse(&rr, rp, P)))
3138 rr.section = dns_rr_section(rp, P);
3140 if (!dns_rr_i_match(&rr, i, P))
3143 if (i->sort(&rr, &r0, i, P) <= 0)
3146 if (i->sort(&rr, &r1, i, P) >= 0)
3152 return dns_rr_offset(&r1);
3153 } /* dns_rr_i_skip() */
3156 int dns_rr_i_packet(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) {
3160 return (int)a->dn.p - (int)b->dn.p;
3161 } /* dns_rr_i_packet() */
3164 int dns_rr_i_order(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) {
3169 if ((cmp = a->section - b->section))
3172 if (a->type != b->type)
3173 return (int)a->dn.p - (int)b->dn.p;
3175 return dns_rr_cmp(a, P, b, P);
3176 } /* dns_rr_i_order() */
3179 int dns_rr_i_shuffle(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) {
3185 while (!i->state.regs[0])
3186 i->state.regs[0] = dns_random();
3188 if ((cmp = a->section - b->section))
3191 return dns_k_shuffle16(a->dn.p, i->state.regs[0]) - dns_k_shuffle16(b->dn.p, i->state.regs[0]);
3192 } /* dns_rr_i_shuffle() */
3195 struct dns_rr_i *dns_rr_i_init(struct dns_rr_i *i, struct dns_packet *P) {
3196 static const struct dns_rr_i i_initializer;
3200 i->state = i_initializer.state;
3201 i->saved = i->state;
3204 } /* dns_rr_i_init() */
3207 unsigned dns_rr_grep(struct dns_rr *rr, unsigned lim, struct dns_rr_i *i, struct dns_packet *P, int *error_) {
3211 switch (i->state.exec) {
3214 i->sort = &dns_rr_i_packet;
3216 i->state.next = dns_rr_i_start(i, P);
3221 while (count < lim && i->state.next < P->end) {
3222 if ((error = dns_rr_parse(rr, i->state.next, P)))
3225 rr->section = dns_rr_section(i->state.next, P);
3231 i->state.next = dns_rr_i_skip(i->state.next, i, P);
3242 } /* dns_rr_grep() */
3245 size_t dns_rr_print(void *_dst, size_t lim, struct dns_rr *rr, struct dns_packet *P, int *_error) {
3246 struct dns_buf dst = DNS_B_INTO(_dst, lim);
3251 if (rr->section == DNS_S_QD)
3252 dns_b_putc(&dst, ';');
3254 if (!(n = dns_d_expand(any.ns.host, sizeof any.ns.host, rr->dn.p, P, &error)))
3256 dns_b_put(&dst, any.ns.host, DNS_PP_MIN(n, sizeof any.ns.host - 1));
3258 if (rr->section != DNS_S_QD) {
3259 dns_b_putc(&dst, ' ');
3260 dns_b_fmtju(&dst, rr->ttl, 0);
3263 dns_b_putc(&dst, ' ');
3264 dns_b_puts(&dst, dns_strclass(rr->class));
3265 dns_b_putc(&dst, ' ');
3266 dns_b_puts(&dst, dns_strtype(rr->type));
3268 if (rr->section == DNS_S_QD)
3271 dns_b_putc(&dst, ' ');
3273 if ((error = dns_any_parse(dns_any_init(&any, sizeof any), rr, P)))
3276 n = dns_any_print(dst.p, dst.pe - dst.p, &any, rr->type);
3277 dst.p += DNS_PP_MIN(n, (size_t)(dst.pe - dst.p));
3279 return dns_b_strllen(&dst);
3284 } /* dns_rr_print() */
3287 int dns_a_parse(struct dns_a *a, struct dns_rr *rr, struct dns_packet *P) {
3290 if (rr->rd.len != 4)
3291 return DNS_EILLEGAL;
3293 addr = ((0xffU & P->data[rr->rd.p + 0]) << 24)
3294 | ((0xffU & P->data[rr->rd.p + 1]) << 16)
3295 | ((0xffU & P->data[rr->rd.p + 2]) << 8)
3296 | ((0xffU & P->data[rr->rd.p + 3]) << 0);
3298 a->addr.s_addr = htonl(addr);
3301 } /* dns_a_parse() */
3304 int dns_a_push(struct dns_packet *P, struct dns_a *a) {
3307 if (P->size - P->end < 6)
3310 P->data[P->end++] = 0x00;
3311 P->data[P->end++] = 0x04;
3313 addr = ntohl(a->addr.s_addr);
3315 P->data[P->end++] = 0xffU & (addr >> 24);
3316 P->data[P->end++] = 0xffU & (addr >> 16);
3317 P->data[P->end++] = 0xffU & (addr >> 8);
3318 P->data[P->end++] = 0xffU & (addr >> 0);
3321 } /* dns_a_push() */
3324 size_t dns_a_arpa(void *_dst, size_t lim, const struct dns_a *a) {
3325 struct dns_buf dst = DNS_B_INTO(_dst, lim);
3326 unsigned long octets = ntohl(a->addr.s_addr);
3329 for (i = 0; i < 4; i++) {
3330 dns_b_fmtju(&dst, 0xff & octets, 0);
3331 dns_b_putc(&dst, '.');
3335 dns_b_puts(&dst, "in-addr.arpa.");
3337 return dns_b_strllen(&dst);
3338 } /* dns_a_arpa() */
3341 int dns_a_cmp(const struct dns_a *a, const struct dns_a *b) {
3342 if (ntohl(a->addr.s_addr) < ntohl(b->addr.s_addr))
3344 if (ntohl(a->addr.s_addr) > ntohl(b->addr.s_addr))
3351 size_t dns_a_print(void *dst, size_t lim, struct dns_a *a) {
3352 char addr[INET_ADDRSTRLEN + 1] = "0.0.0.0";
3354 dns_inet_ntop(AF_INET, &a->addr, addr, sizeof addr);
3356 return dns_strlcpy(dst, addr, lim);
3357 } /* dns_a_print() */
3360 int dns_aaaa_parse(struct dns_aaaa *aaaa, struct dns_rr *rr, struct dns_packet *P) {
3361 if (rr->rd.len != sizeof aaaa->addr.s6_addr)
3362 return DNS_EILLEGAL;
3364 memcpy(aaaa->addr.s6_addr, &P->data[rr->rd.p], sizeof aaaa->addr.s6_addr);
3367 } /* dns_aaaa_parse() */
3370 int dns_aaaa_push(struct dns_packet *P, struct dns_aaaa *aaaa) {
3371 if (P->size - P->end < 2 + sizeof aaaa->addr.s6_addr)
3374 P->data[P->end++] = 0x00;
3375 P->data[P->end++] = 0x10;
3377 memcpy(&P->data[P->end], aaaa->addr.s6_addr, sizeof aaaa->addr.s6_addr);
3379 P->end += sizeof aaaa->addr.s6_addr;
3382 } /* dns_aaaa_push() */
3385 int dns_aaaa_cmp(const struct dns_aaaa *a, const struct dns_aaaa *b) {
3389 for (i = 0; i < lengthof(a->addr.s6_addr); i++) {
3390 if ((cmp = (a->addr.s6_addr[i] - b->addr.s6_addr[i])))
3395 } /* dns_aaaa_cmp() */
3398 size_t dns_aaaa_arpa(void *_dst, size_t lim, const struct dns_aaaa *aaaa) {
3399 static const unsigned char hex[16] = "0123456789abcdef";
3400 struct dns_buf dst = DNS_B_INTO(_dst, lim);
3404 for (i = sizeof aaaa->addr.s6_addr - 1; i >= 0; i--) {
3405 nyble = aaaa->addr.s6_addr[i];
3407 for (j = 0; j < 2; j++) {
3408 dns_b_putc(&dst, hex[0x0f & nyble]);
3409 dns_b_putc(&dst, '.');
3414 dns_b_puts(&dst, "ip6.arpa.");
3416 return dns_b_strllen(&dst);
3417 } /* dns_aaaa_arpa() */
3420 size_t dns_aaaa_print(void *dst, size_t lim, struct dns_aaaa *aaaa) {
3421 char addr[INET6_ADDRSTRLEN + 1] = "::";
3423 dns_inet_ntop(AF_INET6, &aaaa->addr, addr, sizeof addr);
3425 return dns_strlcpy(dst, addr, lim);
3426 } /* dns_aaaa_print() */
3429 int dns_mx_parse(struct dns_mx *mx, struct dns_rr *rr, struct dns_packet *P) {
3434 return DNS_EILLEGAL;
3436 mx->preference = (0xff00 & (P->data[rr->rd.p + 0] << 8))
3437 | (0x00ff & (P->data[rr->rd.p + 1] << 0));
3439 if (!(len = dns_d_expand(mx->host, sizeof mx->host, rr->rd.p + 2, P, &error)))
3441 else if (len >= sizeof mx->host)
3442 return DNS_EILLEGAL;
3445 } /* dns_mx_parse() */
3448 int dns_mx_push(struct dns_packet *P, struct dns_mx *mx) {
3452 if (P->size - P->end < 5)
3458 P->data[P->end++] = 0xff & (mx->preference >> 8);
3459 P->data[P->end++] = 0xff & (mx->preference >> 0);
3461 if ((error = dns_d_push(P, mx->host, strlen(mx->host))))
3464 len = P->end - end - 2;
3466 P->data[end + 0] = 0xff & (len >> 8);
3467 P->data[end + 1] = 0xff & (len >> 0);
3474 } /* dns_mx_push() */
3477 int dns_mx_cmp(const struct dns_mx *a, const struct dns_mx *b) {
3480 if ((cmp = a->preference - b->preference))
3483 return strcasecmp(a->host, b->host);
3484 } /* dns_mx_cmp() */
3487 size_t dns_mx_print(void *_dst, size_t lim, struct dns_mx *mx) {
3488 struct dns_buf dst = DNS_B_INTO(_dst, lim);
3490 dns_b_fmtju(&dst, mx->preference, 0);
3491 dns_b_putc(&dst, ' ');
3492 dns_b_puts(&dst, mx->host);
3494 return dns_b_strllen(&dst);
3495 } /* dns_mx_print() */
3498 size_t dns_mx_cname(void *dst, size_t lim, struct dns_mx *mx) {
3499 return dns_strlcpy(dst, mx->host, lim);
3500 } /* dns_mx_cname() */
3503 int dns_ns_parse(struct dns_ns *ns, struct dns_rr *rr, struct dns_packet *P) {
3507 if (!(len = dns_d_expand(ns->host, sizeof ns->host, rr->rd.p, P, &error)))
3509 else if (len >= sizeof ns->host)
3510 return DNS_EILLEGAL;
3513 } /* dns_ns_parse() */
3516 int dns_ns_push(struct dns_packet *P, struct dns_ns *ns) {
3520 if (P->size - P->end < 3)
3526 if ((error = dns_d_push(P, ns->host, strlen(ns->host))))
3529 len = P->end - end - 2;
3531 P->data[end + 0] = 0xff & (len >> 8);
3532 P->data[end + 1] = 0xff & (len >> 0);
3539 } /* dns_ns_push() */
3542 int dns_ns_cmp(const struct dns_ns *a, const struct dns_ns *b) {
3543 return strcasecmp(a->host, b->host);
3544 } /* dns_ns_cmp() */
3547 size_t dns_ns_print(void *dst, size_t lim, struct dns_ns *ns) {
3548 return dns_strlcpy(dst, ns->host, lim);
3549 } /* dns_ns_print() */
3552 size_t dns_ns_cname(void *dst, size_t lim, struct dns_ns *ns) {
3553 return dns_strlcpy(dst, ns->host, lim);
3554 } /* dns_ns_cname() */
3557 int dns_cname_parse(struct dns_cname *cname, struct dns_rr *rr, struct dns_packet *P) {
3558 return dns_ns_parse((struct dns_ns *)cname, rr, P);
3559 } /* dns_cname_parse() */
3562 int dns_cname_push(struct dns_packet *P, struct dns_cname *cname) {
3563 return dns_ns_push(P, (struct dns_ns *)cname);
3564 } /* dns_cname_push() */
3567 int dns_cname_cmp(const struct dns_cname *a, const struct dns_cname *b) {
3568 return strcasecmp(a->host, b->host);
3569 } /* dns_cname_cmp() */
3572 size_t dns_cname_print(void *dst, size_t lim, struct dns_cname *cname) {
3573 return dns_ns_print(dst, lim, (struct dns_ns *)cname);
3574 } /* dns_cname_print() */
3577 size_t dns_cname_cname(void *dst, size_t lim, struct dns_cname *cname) {
3578 return dns_strlcpy(dst, cname->host, lim);
3579 } /* dns_cname_cname() */
3582 int dns_soa_parse(struct dns_soa *soa, struct dns_rr *rr, struct dns_packet *P) {
3583 struct { void *dst; size_t lim; } dn[] =
3584 { { soa->mname, sizeof soa->mname },
3585 { soa->rname, sizeof soa->rname } };
3587 { &soa->serial, &soa->refresh, &soa->retry, &soa->expire, &soa->minimum };
3593 if ((rp = rr->rd.p) >= P->end)
3594 return DNS_EILLEGAL;
3596 for (i = 0; i < lengthof(dn); i++) {
3597 if (!(n = dns_d_expand(dn[i].dst, dn[i].lim, rp, P, &error)))
3599 else if (n >= dn[i].lim)
3600 return DNS_EILLEGAL;
3602 if ((rp = dns_d_skip(rp, P)) >= P->end)
3603 return DNS_EILLEGAL;
3606 /* SERIAL / REFRESH / RETRY / EXPIRE / MINIMUM */
3607 for (i = 0; i < lengthof(ts); i++) {
3608 for (j = 0; j < 4; j++, rp++) {
3610 return DNS_EILLEGAL;
3613 *ts[i] |= (0xff & P->data[rp]);
3618 } /* dns_soa_parse() */
3621 int dns_soa_push(struct dns_packet *P, struct dns_soa *soa) {
3622 void *dn[] = { soa->mname, soa->rname };
3623 unsigned ts[] = { (0xffffffff & soa->serial),
3624 (0x7fffffff & soa->refresh),
3625 (0x7fffffff & soa->retry),
3626 (0x7fffffff & soa->expire),
3627 (0xffffffff & soa->minimum) };
3634 if ((P->end += 2) >= P->size)
3638 for (i = 0; i < lengthof(dn); i++) {
3639 if ((error = dns_d_push(P, dn[i], strlen(dn[i]))))
3643 /* SERIAL / REFRESH / RETRY / EXPIRE / MINIMUM */
3644 for (i = 0; i < lengthof(ts); i++) {
3645 if ((P->end += 4) >= P->size)
3648 for (j = 1; j <= 4; j++) {
3649 P->data[P->end - j] = (0xff & ts[i]);
3654 len = P->end - end - 2;
3655 P->data[end + 0] = (0xff & (len >> 8));
3656 P->data[end + 1] = (0xff & (len >> 0));
3660 error = DNS_ENOBUFS;
3667 } /* dns_soa_push() */
3670 int dns_soa_cmp(const struct dns_soa *a, const struct dns_soa *b) {
3673 if ((cmp = strcasecmp(a->mname, b->mname)))
3676 if ((cmp = strcasecmp(a->rname, b->rname)))
3679 if (a->serial > b->serial)
3681 else if (a->serial < b->serial)
3684 if (a->refresh > b->refresh)
3686 else if (a->refresh < b->refresh)
3689 if (a->retry > b->retry)
3691 else if (a->retry < b->retry)
3694 if (a->expire > b->expire)
3696 else if (a->expire < b->expire)
3699 if (a->minimum > b->minimum)
3701 else if (a->minimum < b->minimum)
3705 } /* dns_soa_cmp() */
3708 size_t dns_soa_print(void *_dst, size_t lim, struct dns_soa *soa) {
3709 struct dns_buf dst = DNS_B_INTO(_dst, lim);
3711 dns_b_puts(&dst, soa->mname);
3712 dns_b_putc(&dst, ' ');
3713 dns_b_puts(&dst, soa->rname);
3714 dns_b_putc(&dst, ' ');
3715 dns_b_fmtju(&dst, soa->serial, 0);
3716 dns_b_putc(&dst, ' ');
3717 dns_b_fmtju(&dst, soa->refresh, 0);
3718 dns_b_putc(&dst, ' ');
3719 dns_b_fmtju(&dst, soa->retry, 0);
3720 dns_b_putc(&dst, ' ');
3721 dns_b_fmtju(&dst, soa->expire, 0);
3722 dns_b_putc(&dst, ' ');
3723 dns_b_fmtju(&dst, soa->minimum, 0);
3725 return dns_b_strllen(&dst);
3726 } /* dns_soa_print() */
3729 int dns_srv_parse(struct dns_srv *srv, struct dns_rr *rr, struct dns_packet *P) {
3735 memset(srv, '\0', sizeof *srv);
3740 return DNS_EILLEGAL;
3742 for (i = 0; i < 2; i++, rp++) {
3743 srv->priority <<= 8;
3744 srv->priority |= (0xff & P->data[rp]);
3747 for (i = 0; i < 2; i++, rp++) {
3749 srv->weight |= (0xff & P->data[rp]);
3752 for (i = 0; i < 2; i++, rp++) {
3754 srv->port |= (0xff & P->data[rp]);
3757 if (!(n = dns_d_expand(srv->target, sizeof srv->target, rp, P, &error)))
3759 else if (n >= sizeof srv->target)
3760 return DNS_EILLEGAL;
3763 } /* dns_srv_parse() */
3766 int dns_srv_push(struct dns_packet *P, struct dns_srv *srv) {
3772 if (P->size - P->end < 2)
3777 if (P->size - P->end < 6)
3780 P->data[P->end++] = 0xff & (srv->priority >> 8);
3781 P->data[P->end++] = 0xff & (srv->priority >> 0);
3783 P->data[P->end++] = 0xff & (srv->weight >> 8);
3784 P->data[P->end++] = 0xff & (srv->weight >> 0);
3786 P->data[P->end++] = 0xff & (srv->port >> 8);
3787 P->data[P->end++] = 0xff & (srv->port >> 0);
3789 if (0 == (len = dns_d_comp(&P->data[P->end], P->size - P->end, srv->target, strlen(srv->target), P, &error)))
3791 else if (P->size - P->end < len)
3799 len = P->end - end - 2;
3801 P->data[end + 0] = 0xff & (len >> 8);
3802 P->data[end + 1] = 0xff & (len >> 0);
3806 error = DNS_ENOBUFS;
3813 } /* dns_srv_push() */
3816 int dns_srv_cmp(const struct dns_srv *a, const struct dns_srv *b) {
3819 if ((cmp = a->priority - b->priority))
3823 * FIXME: We need some sort of random seed to implement the dynamic
3824 * weighting required by RFC 2782.
3826 if ((cmp = a->weight - b->weight))
3829 if ((cmp = a->port - b->port))
3832 return strcasecmp(a->target, b->target);
3833 } /* dns_srv_cmp() */
3836 size_t dns_srv_print(void *_dst, size_t lim, struct dns_srv *srv) {
3837 struct dns_buf dst = DNS_B_INTO(_dst, lim);
3839 dns_b_fmtju(&dst, srv->priority, 0);
3840 dns_b_putc(&dst, ' ');
3841 dns_b_fmtju(&dst, srv->weight, 0);
3842 dns_b_putc(&dst, ' ');
3843 dns_b_fmtju(&dst, srv->port, 0);
3844 dns_b_putc(&dst, ' ');
3845 dns_b_puts(&dst, srv->target);
3847 return dns_b_strllen(&dst);
3848 } /* dns_srv_print() */
3851 size_t dns_srv_cname(void *dst, size_t lim, struct dns_srv *srv) {
3852 return dns_strlcpy(dst, srv->target, lim);
3853 } /* dns_srv_cname() */
3856 unsigned int dns_opt_ttl(const struct dns_opt *opt) {
3857 unsigned int ttl = 0;
3859 ttl |= (0xffU & opt->rcode) << 24;
3860 ttl |= (0xffU & opt->version) << 16;
3861 ttl |= (0xffffU & opt->flags) << 0;
3864 } /* dns_opt_ttl() */
3867 unsigned short dns_opt_class(const struct dns_opt *opt) {
3869 } /* dns_opt_class() */
3872 struct dns_opt *dns_opt_init(struct dns_opt *opt, size_t size) {
3873 assert(size >= offsetof(struct dns_opt, data));
3875 opt->size = size - offsetof(struct dns_opt, data);
3883 } /* dns_opt_init() */
3886 static union dns_any *dns_opt_initany(union dns_any *any, size_t size) {
3887 return dns_opt_init(&any->opt, size), any;
3888 } /* dns_opt_initany() */
3891 int dns_opt_parse(struct dns_opt *opt, struct dns_rr *rr, struct dns_packet *P) {
3892 const struct dns_buf src = DNS_B_FROM(&P->data[rr->rd.p], rr->rd.len);
3893 struct dns_buf dst = DNS_B_INTO(opt->data, opt->size);
3896 opt->rcode = 0xfff & ((rr->ttl >> 20) | dns_header(P)->rcode);
3897 opt->version = 0xff & (rr->ttl >> 16);
3898 opt->flags = 0xffff & rr->ttl;
3899 opt->maxudp = 0xffff & rr->class;
3901 while (src.p < src.pe) {
3904 if (-1 == (code = dns_b_get16(&src, -1)))
3906 if (-1 == (len = dns_b_get16(&src, -1)))
3911 dns_b_put16(&dst, code);
3912 dns_b_put16(&dst, len);
3913 if ((error = dns_b_move(&dst, &src, len)))
3920 } /* dns_opt_parse() */
3923 int dns_opt_push(struct dns_packet *P, struct dns_opt *opt) {
3924 const struct dns_buf src = DNS_B_FROM(opt->data, opt->len);
3925 struct dns_buf dst = DNS_B_INTO(&P->data[P->end], (P->size - P->end));
3928 /* rdata length (see below) */
3929 if ((error = dns_b_put16(&dst, 0)))
3932 /* ... push known options here */
3934 /* push opaque option data */
3935 if ((error = dns_b_move(&dst, &src, (size_t)(src.pe - src.p))))
3939 if ((error = dns_b_pput16(&dst, dns_b_tell(&dst) - 2, 0)))
3942 #if !DNS_DEBUG_OPT_FORMERR
3943 P->end += dns_b_tell(&dst);
3949 } /* dns_opt_push() */
3952 int dns_opt_cmp(const struct dns_opt *a, const struct dns_opt *b) {
3957 } /* dns_opt_cmp() */
3960 size_t dns_opt_print(void *_dst, size_t lim, struct dns_opt *opt) {
3961 struct dns_buf dst = DNS_B_INTO(_dst, lim);
3964 dns_b_putc(&dst, '"');
3966 for (p = 0; p < opt->len; p++) {
3967 dns_b_putc(&dst, '\\');
3968 dns_b_fmtju(&dst, opt->data[p], 3);
3971 dns_b_putc(&dst, '"');
3973 return dns_b_strllen(&dst);
3974 } /* dns_opt_print() */
3977 int dns_ptr_parse(struct dns_ptr *ptr, struct dns_rr *rr, struct dns_packet *P) {
3978 return dns_ns_parse((struct dns_ns *)ptr, rr, P);
3979 } /* dns_ptr_parse() */
3982 int dns_ptr_push(struct dns_packet *P, struct dns_ptr *ptr) {
3983 return dns_ns_push(P, (struct dns_ns *)ptr);
3984 } /* dns_ptr_push() */
3987 size_t dns_ptr_qname(void *dst, size_t lim, int af, void *addr) {
3990 return dns_aaaa_arpa(dst, lim, addr);
3992 return dns_a_arpa(dst, lim, addr);
3995 a.addr.s_addr = INADDR_NONE;
3996 return dns_a_arpa(dst, lim, &a);
3999 } /* dns_ptr_qname() */
4002 int dns_ptr_cmp(const struct dns_ptr *a, const struct dns_ptr *b) {
4003 return strcasecmp(a->host, b->host);
4004 } /* dns_ptr_cmp() */
4007 size_t dns_ptr_print(void *dst, size_t lim, struct dns_ptr *ptr) {
4008 return dns_ns_print(dst, lim, (struct dns_ns *)ptr);
4009 } /* dns_ptr_print() */
4012 size_t dns_ptr_cname(void *dst, size_t lim, struct dns_ptr *ptr) {
4013 return dns_strlcpy(dst, ptr->host, lim);
4014 } /* dns_ptr_cname() */
4017 int dns_sshfp_parse(struct dns_sshfp *fp, struct dns_rr *rr, struct dns_packet *P) {
4018 unsigned p = rr->rd.p, pe = rr->rd.p + rr->rd.len;
4021 return DNS_EILLEGAL;
4023 fp->algo = P->data[p++];
4024 fp->type = P->data[p++];
4027 case DNS_SSHFP_SHA1:
4028 if (pe - p < sizeof fp->digest.sha1)
4029 return DNS_EILLEGAL;
4031 memcpy(fp->digest.sha1, &P->data[p], sizeof fp->digest.sha1);
4039 } /* dns_sshfp_parse() */
4042 int dns_sshfp_push(struct dns_packet *P, struct dns_sshfp *fp) {
4043 unsigned p = P->end, pe = P->size, n;
4049 P->data[p++] = 0xff & fp->algo;
4050 P->data[p++] = 0xff & fp->type;
4053 case DNS_SSHFP_SHA1:
4054 if (pe - p < sizeof fp->digest.sha1)
4057 memcpy(&P->data[p], fp->digest.sha1, sizeof fp->digest.sha1);
4058 p += sizeof fp->digest.sha1;
4062 return DNS_EILLEGAL;
4066 P->data[P->end++] = 0xff & (n >> 8);
4067 P->data[P->end++] = 0xff & (n >> 0);
4071 } /* dns_sshfp_push() */
4074 int dns_sshfp_cmp(const struct dns_sshfp *a, const struct dns_sshfp *b) {
4077 if ((cmp = a->algo - b->algo) || (cmp = a->type - b->type))
4081 case DNS_SSHFP_SHA1:
4082 return memcmp(a->digest.sha1, b->digest.sha1, sizeof a->digest.sha1);
4088 } /* dns_sshfp_cmp() */
4091 size_t dns_sshfp_print(void *_dst, size_t lim, struct dns_sshfp *fp) {
4092 static const unsigned char hex[16] = "0123456789abcdef";
4093 struct dns_buf dst = DNS_B_INTO(_dst, lim);
4096 dns_b_fmtju(&dst, fp->algo, 0);
4097 dns_b_putc(&dst, ' ');
4098 dns_b_fmtju(&dst, fp->type, 0);
4099 dns_b_putc(&dst, ' ');
4102 case DNS_SSHFP_SHA1:
4103 for (i = 0; i < sizeof fp->digest.sha1; i++) {
4104 dns_b_putc(&dst, hex[0x0f & (fp->digest.sha1[i] >> 4)]);
4105 dns_b_putc(&dst, hex[0x0f & (fp->digest.sha1[i] >> 0)]);
4110 dns_b_putc(&dst, '0');
4115 return dns_b_strllen(&dst);
4116 } /* dns_sshfp_print() */
4119 struct dns_txt *dns_txt_init(struct dns_txt *txt, size_t size) {
4120 assert(size > offsetof(struct dns_txt, data));
4122 txt->size = size - offsetof(struct dns_txt, data);
4126 } /* dns_txt_init() */
4129 static union dns_any *dns_txt_initany(union dns_any *any, size_t size) {
4130 /* NB: union dns_any is already initialized as struct dns_txt */
4133 } /* dns_txt_initany() */
4136 int dns_txt_parse(struct dns_txt *txt, struct dns_rr *rr, struct dns_packet *P) {
4137 struct { unsigned char *b; size_t p, end; } dst, src;
4142 dst.end = txt->size;
4146 src.end = src.p + rr->rd.len;
4148 while (src.p < src.end) {
4149 n = 0xff & P->data[src.p++];
4151 if (src.end - src.p < n || dst.end - dst.p < n)
4152 return DNS_EILLEGAL;
4154 memcpy(&dst.b[dst.p], &src.b[src.p], n);
4163 } /* dns_txt_parse() */
4166 int dns_txt_push(struct dns_packet *P, struct dns_txt *txt) {
4167 struct { unsigned char *b; size_t p, end; } dst, src;
4178 if (dst.end - dst.p < 2)
4181 n = txt->len + ((txt->len + 254) / 255);
4183 dst.b[dst.p++] = 0xff & (n >> 8);
4184 dst.b[dst.p++] = 0xff & (n >> 0);
4186 while (src.p < src.end) {
4187 n = DNS_PP_MIN(255, src.end - src.p);
4189 if (dst.p >= dst.end)
4194 if (dst.end - dst.p < n)
4197 memcpy(&dst.b[dst.p], &src.b[src.p], n);
4206 } /* dns_txt_push() */
4209 int dns_txt_cmp(const struct dns_txt *a, const struct dns_txt *b) {
4214 } /* dns_txt_cmp() */
4217 size_t dns_txt_print(void *_dst, size_t lim, struct dns_txt *txt) {
4218 struct dns_buf src = DNS_B_FROM(txt->data, txt->len);
4219 struct dns_buf dst = DNS_B_INTO(_dst, lim);
4222 if (src.p < src.pe) {
4224 dns_b_putc(&dst, '"');
4226 for (i = 0; i < 256 && src.p < src.pe; i++, src.p++) {
4227 if (*src.p < 32 || *src.p > 126 || *src.p == '"' || *src.p == '\\') {
4228 dns_b_putc(&dst, '\\');
4229 dns_b_fmtju(&dst, *src.p, 3);
4231 dns_b_putc(&dst, *src.p);
4235 dns_b_putc(&dst, '"');
4236 dns_b_putc(&dst, ' ');
4237 } while (src.p < src.pe);
4241 dns_b_putc(&dst, '"');
4242 dns_b_putc(&dst, '"');
4245 return dns_b_strllen(&dst);
4246 } /* dns_txt_print() */
4249 /* Some of the function pointers of DNS_RRTYPES are initialized with
4250 * slighlly different fucntions, thus we can't use prototypes. */
4253 #pragma clang diagnostic ignored "-Wstrict-prototypes"
4254 #elif DNS_GNUC_PREREQ(4,6,0)
4255 #pragma GCC diagnostic ignored "-Wstrict-prototypes"
4258 static const struct dns_rrtype {
4261 union dns_any *(*init)(union dns_any *, size_t);
4268 { DNS_T_A, "A", 0, &dns_a_parse, &dns_a_push, &dns_a_cmp, &dns_a_print, 0, },
4269 { DNS_T_AAAA, "AAAA", 0, &dns_aaaa_parse, &dns_aaaa_push, &dns_aaaa_cmp, &dns_aaaa_print, 0, },
4270 { DNS_T_MX, "MX", 0, &dns_mx_parse, &dns_mx_push, &dns_mx_cmp, &dns_mx_print, &dns_mx_cname, },
4271 { DNS_T_NS, "NS", 0, &dns_ns_parse, &dns_ns_push, &dns_ns_cmp, &dns_ns_print, &dns_ns_cname, },
4272 { DNS_T_CNAME, "CNAME", 0, &dns_cname_parse, &dns_cname_push, &dns_cname_cmp, &dns_cname_print, &dns_cname_cname, },
4273 { DNS_T_SOA, "SOA", 0, &dns_soa_parse, &dns_soa_push, &dns_soa_cmp, &dns_soa_print, 0, },
4274 { DNS_T_SRV, "SRV", 0, &dns_srv_parse, &dns_srv_push, &dns_srv_cmp, &dns_srv_print, &dns_srv_cname, },
4275 { DNS_T_OPT, "OPT", &dns_opt_initany, &dns_opt_parse, &dns_opt_push, &dns_opt_cmp, &dns_opt_print, 0, },
4276 { DNS_T_PTR, "PTR", 0, &dns_ptr_parse, &dns_ptr_push, &dns_ptr_cmp, &dns_ptr_print, &dns_ptr_cname, },
4277 { DNS_T_TXT, "TXT", &dns_txt_initany, &dns_txt_parse, &dns_txt_push, &dns_txt_cmp, &dns_txt_print, 0, },
4278 { DNS_T_SPF, "SPF", &dns_txt_initany, &dns_txt_parse, &dns_txt_push, &dns_txt_cmp, &dns_txt_print, 0, },
4279 { DNS_T_SSHFP, "SSHFP", 0, &dns_sshfp_parse, &dns_sshfp_push, &dns_sshfp_cmp, &dns_sshfp_print, 0, },
4280 { DNS_T_AXFR, "AXFR", 0, 0, 0, 0, 0, 0, },
4281 }; /* dns_rrtypes[] */
4283 DNS_PRAGMA_POP /*(-Wstrict-prototypes)*/
4287 static const struct dns_rrtype *dns_rrtype(enum dns_type type) {
4288 const struct dns_rrtype *t;
4290 for (t = dns_rrtypes; t < endof(dns_rrtypes); t++) {
4291 if (t->type == type && t->parse) {
4297 } /* dns_rrtype() */
4300 union dns_any *dns_any_init(union dns_any *any, size_t size) {
4301 dns_static_assert(dns_same_type(any->txt, any->rdata, 1), "unexpected rdata type");
4302 return (union dns_any *)dns_txt_init(&any->rdata, size);
4303 } /* dns_any_init() */
4306 static size_t dns_any_sizeof(union dns_any *any) {
4307 dns_static_assert(dns_same_type(any->txt, any->rdata, 1), "unexpected rdata type");
4308 return offsetof(struct dns_txt, data) + any->rdata.size;
4309 } /* dns_any_sizeof() */
4311 static union dns_any *dns_any_reinit(union dns_any *any, const struct dns_rrtype *t) {
4312 return (t->init)? t->init(any, dns_any_sizeof(any)) : any;
4313 } /* dns_any_reinit() */
4315 int dns_any_parse(union dns_any *any, struct dns_rr *rr, struct dns_packet *P) {
4316 const struct dns_rrtype *t;
4318 if ((t = dns_rrtype(rr->type)))
4319 return t->parse(dns_any_reinit(any, t), rr, P);
4321 if (rr->rd.len > any->rdata.size)
4322 return DNS_EILLEGAL;
4324 memcpy(any->rdata.data, &P->data[rr->rd.p], rr->rd.len);
4325 any->rdata.len = rr->rd.len;
4328 } /* dns_any_parse() */
4331 int dns_any_push(struct dns_packet *P, union dns_any *any, enum dns_type type) {
4332 const struct dns_rrtype *t;
4334 if ((t = dns_rrtype(type)))
4335 return t->push(P, any);
4337 if (P->size - P->end < any->rdata.len + 2)
4340 P->data[P->end++] = 0xff & (any->rdata.len >> 8);
4341 P->data[P->end++] = 0xff & (any->rdata.len >> 0);
4343 memcpy(&P->data[P->end], any->rdata.data, any->rdata.len);
4344 P->end += any->rdata.len;
4347 } /* dns_any_push() */
4350 int dns_any_cmp(const union dns_any *a, enum dns_type x, const union dns_any *b, enum dns_type y) {
4351 const struct dns_rrtype *t;
4357 if ((t = dns_rrtype(x)))
4358 return t->cmp(a, b);
4361 } /* dns_any_cmp() */
4364 size_t dns_any_print(void *_dst, size_t lim, union dns_any *any, enum dns_type type) {
4365 const struct dns_rrtype *t;
4366 struct dns_buf src, dst;
4368 if ((t = dns_rrtype(type)))
4369 return t->print(_dst, lim, any);
4371 dns_b_from(&src, any->rdata.data, any->rdata.len);
4372 dns_b_into(&dst, _dst, lim);
4374 dns_b_putc(&dst, '"');
4376 while (src.p < src.pe) {
4377 dns_b_putc(&dst, '\\');
4378 dns_b_fmtju(&dst, *src.p++, 3);
4381 dns_b_putc(&dst, '"');
4383 return dns_b_strllen(&dst);
4384 } /* dns_any_print() */
4387 size_t dns_any_cname(void *dst, size_t lim, union dns_any *any, enum dns_type type) {
4388 const struct dns_rrtype *t;
4390 if ((t = dns_rrtype(type)) && t->cname)
4391 return t->cname(dst, lim, any);
4394 } /* dns_any_cname() */
4398 * E V E N T T R A C I N G R O U T I N E S
4400 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4401 #include <float.h> /* DBL_MANT_DIG */
4402 #include <inttypes.h> /* PRIu64 */
4404 /* for default trace ID generation try to fit in lua_Number, usually double */
4405 #define DNS_TRACE_ID_BITS DNS_PP_MIN(DBL_MANT_DIG, (sizeof (dns_trace_id_t) * CHAR_BIT)) /* assuming FLT_RADIX == 2 */
4406 #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)))
4407 #define DNS_TRACE_ID_PRI PRIu64
4409 static inline dns_trace_id_t dns_trace_mkid(void) {
4410 dns_trace_id_t id = 0;
4411 unsigned r; /* return type of dns_random() */
4412 const size_t id_bit = sizeof id * CHAR_BIT;
4413 const size_t r_bit = sizeof r * CHAR_BIT;
4415 for (size_t n = 0; n < id_bit; n += r_bit) {
4421 return DNS_TRACE_ID_MASK & id;
4425 dns_atomic_t refcount;
4431 struct dns_trace_cname {
4432 char host[DNS_D_MAXNAME + 1];
4433 struct sockaddr_storage addr;
4439 static void dns_te_initname(struct sockaddr_storage *ss, int fd, int (*f)(int, struct sockaddr *, socklen_t *)) {
4440 socklen_t n = sizeof *ss;
4442 if (0 != f(fd, (struct sockaddr *)ss, &n))
4450 memset(ss, '\0', sizeof *ss);
4451 ss->ss_family = AF_UNSPEC;
4454 static void dns_te_initnames(struct sockaddr_storage *local, struct sockaddr_storage *remote, int fd) {
4455 dns_te_initname(local, fd, &getsockname);
4456 dns_te_initname(remote, fd, &getpeername);
4459 static struct dns_trace_event *dns_te_init(struct dns_trace_event *te, int type) {
4460 /* NB: silence valgrind */
4461 memset(te, '\0', offsetof(struct dns_trace_event, data));
4466 int dns_trace_abi(void) {
4467 return DNS_TRACE_ABI;
4470 struct dns_trace *dns_trace_open(FILE *fp, dns_error_t *error) {
4471 static const struct dns_trace trace_initializer = { .refcount = 1 };
4472 struct dns_trace *trace;
4474 if (!(trace = malloc(sizeof *trace)))
4477 *trace = trace_initializer;
4481 } else if (!(fp = tmpfile())) {
4485 trace->id = dns_trace_mkid();
4489 *error = dns_syerr();
4491 dns_trace_close(trace);
4494 } /* dns_trace_open() */
4496 void dns_trace_close(struct dns_trace *trace) {
4497 if (!trace || 1 != dns_trace_release(trace))
4503 } /* dns_trace_close() */
4505 dns_refcount_t dns_trace_acquire(struct dns_trace *trace) {
4506 return dns_atomic_fetch_add(&trace->refcount);
4507 } /* dns_trace_acquire() */
4509 static struct dns_trace *dns_trace_acquire_p(struct dns_trace *trace) {
4510 return (trace)? dns_trace_acquire(trace), trace : NULL;
4511 } /* dns_trace_acquire_p() */
4513 dns_refcount_t dns_trace_release(struct dns_trace *trace) {
4514 return dns_atomic_fetch_sub(&trace->refcount);
4515 } /* dns_trace_release() */
4517 dns_trace_id_t dns_trace_id(struct dns_trace *trace) {
4519 } /* dns_trace_id() */
4521 dns_trace_id_t dns_trace_setid(struct dns_trace *trace, dns_trace_id_t id) {
4522 trace->id = (id)? id : dns_trace_mkid();
4524 } /* dns_trace_setid() */
4526 struct dns_trace_event *dns_trace_get(struct dns_trace *trace, struct dns_trace_event **tp, dns_error_t *error) {
4527 return dns_trace_fget(tp, trace->fp, error);
4528 } /* dns_trace_get() */
4530 dns_error_t dns_trace_put(struct dns_trace *trace, const struct dns_trace_event *te, const void *data, size_t datasize) {
4531 return dns_trace_fput(te, data, datasize, trace->fp);
4532 } /* dns_trace_put() */
4534 struct dns_trace_event *dns_trace_tag(struct dns_trace *trace, struct dns_trace_event *te) {
4538 gettimeofday(&tv, NULL);
4539 dns_tv2ts(&te->ts, &tv);
4540 te->abi = DNS_TRACE_ABI;
4543 } /* dns_trace_tag() */
4545 static dns_error_t dns_trace_tag_and_put(struct dns_trace *trace, struct dns_trace_event *te, const void *data, size_t datasize) {
4546 return dns_trace_put(trace, dns_trace_tag(trace, te), data, datasize);
4547 } /* dns_trace_tag_and_put() */
4549 struct dns_trace_event *dns_trace_fget(struct dns_trace_event **tp, FILE *fp, dns_error_t *error) {
4550 const size_t headsize = offsetof(struct dns_trace_event, data);
4551 struct dns_trace_event tmp, *te;
4555 if (!(n = fread(&tmp, 1, headsize, fp)))
4557 if (n < offsetof(struct dns_trace_event, data))
4560 if (!(te = realloc(*tp, DNS_PP_MAX(headsize, tmp.size)))) {
4566 memcpy(te, &tmp, offsetof(struct dns_trace_event, data));
4568 if (dns_te_datasize(te)) {
4570 if (!(n = fread(te->data, 1, dns_te_datasize(te), fp)))
4572 if (n < dns_te_datasize(te))
4578 *error = (ferror(fp))? errno : 0;
4585 dns_error_t dns_trace_fput(const struct dns_trace_event *te, const void *data, size_t datasize, FILE *fp) {
4586 size_t headsize = offsetof(struct dns_trace_event, data);
4587 struct dns_trace_event tmp;
4589 memcpy(&tmp, te, headsize);
4590 tmp.size = headsize + datasize;
4592 /* NB: ignore seek error as fp might not point to a regular file */
4593 (void)fseek(fp, 0, SEEK_END);
4595 if (fwrite(&tmp, 1, headsize, fp) < headsize)
4597 if (fwrite(data, 1, datasize, fp) < datasize)
4605 static void dns_trace_setcname(struct dns_trace *trace, const char *host, const struct sockaddr *addr) {
4606 struct dns_trace_cname *cname;
4607 if (!trace || !trace->fp)
4610 cname = &trace->cnames.base[trace->cnames.p];
4611 dns_strlcpy(cname->host, host, sizeof cname->host);
4612 memcpy(&cname->addr, addr, DNS_PP_MIN(dns_sa_len(addr), sizeof cname->addr));
4614 trace->cnames.p = (trace->cnames.p + 1) % lengthof(trace->cnames.base);
4617 static const char *dns_trace_cname(struct dns_trace *trace, const struct sockaddr *addr) {
4618 if (!trace || !trace->fp)
4621 /* NB: start search from the write cursor to */
4622 for (const struct dns_trace_cname *cname = trace->cnames.base; cname < endof(trace->cnames.base); cname++) {
4623 if (0 == dns_sa_cmp((struct sockaddr *)addr, (struct sockaddr *)&cname->addr))
4630 static void dns_trace_res_submit(struct dns_trace *trace, const char *qname, enum dns_type qtype, enum dns_class qclass, int error) {
4631 struct dns_trace_event te;
4632 if (!trace || !trace->fp)
4635 dns_te_init(&te, DNS_TE_RES_SUBMIT);
4636 dns_strlcpy(te.res_submit.qname, qname, sizeof te.res_submit.qname);
4637 te.res_submit.qtype = qtype;
4638 te.res_submit.qclass = qclass;
4639 te.res_submit.error = error;
4640 dns_trace_tag_and_put(trace, &te, NULL, 0);
4643 static void dns_trace_res_fetch(struct dns_trace *trace, const struct dns_packet *packet, int error) {
4644 struct dns_trace_event te;
4647 if (!trace || !trace->fp)
4650 dns_te_init(&te, DNS_TE_RES_FETCH);
4651 data = (packet)? packet->data : NULL;
4652 datasize = (packet)? packet->end : 0;
4653 te.res_fetch.error = error;
4654 dns_trace_tag_and_put(trace, &te, data, datasize);
4657 static void dns_trace_so_submit(struct dns_trace *trace, const struct dns_packet *packet, const struct sockaddr *haddr, int error) {
4658 struct dns_trace_event te;
4660 if (!trace || !trace->fp)
4663 dns_te_init(&te, DNS_TE_SO_SUBMIT);
4664 memcpy(&te.so_submit.haddr, haddr, DNS_PP_MIN(dns_sa_len(haddr), sizeof te.so_submit.haddr));
4665 if ((cname = dns_trace_cname(trace, haddr)))
4666 dns_strlcpy(te.so_submit.hname, cname, sizeof te.so_submit.hname);
4667 te.so_submit.error = error;
4668 dns_trace_tag_and_put(trace, &te, packet->data, packet->end);
4671 static void dns_trace_so_verify(struct dns_trace *trace, const struct dns_packet *packet, int error) {
4672 struct dns_trace_event te;
4673 if (!trace || !trace->fp)
4676 dns_te_init(&te, DNS_TE_SO_VERIFY);
4677 te.so_verify.error = error;
4678 dns_trace_tag_and_put(trace, &te, packet->data, packet->end);
4681 static void dns_trace_so_fetch(struct dns_trace *trace, const struct dns_packet *packet, int error) {
4682 struct dns_trace_event te;
4685 if (!trace || !trace->fp)
4688 dns_te_init(&te, DNS_TE_SO_FETCH);
4689 data = (packet)? packet->data : NULL;
4690 datasize = (packet)? packet->end : 0;
4691 te.so_fetch.error = error;
4692 dns_trace_tag_and_put(trace, &te, data, datasize);
4695 static void dns_trace_sys_connect(struct dns_trace *trace, int fd, int socktype, const struct sockaddr *dst, int error) {
4696 struct dns_trace_event te;
4697 if (!trace || !trace->fp)
4700 dns_te_init(&te, DNS_TE_SYS_CONNECT);
4701 dns_te_initname(&te.sys_connect.src, fd, &getsockname);
4702 memcpy(&te.sys_connect.dst, dst, DNS_PP_MIN(dns_sa_len(dst), sizeof te.sys_connect.dst));
4703 te.sys_connect.socktype = socktype;
4704 te.sys_connect.error = error;
4705 dns_trace_tag_and_put(trace, &te, NULL, 0);
4708 static void dns_trace_sys_send(struct dns_trace *trace, int fd, int socktype, const void *data, size_t datasize, int error) {
4709 struct dns_trace_event te;
4710 if (!trace || !trace->fp)
4713 dns_te_init(&te, DNS_TE_SYS_SEND);
4714 dns_te_initnames(&te.sys_send.src, &te.sys_send.dst, fd);
4715 te.sys_send.socktype = socktype;
4716 te.sys_send.error = error;
4717 dns_trace_tag_and_put(trace, &te, data, datasize);
4720 static void dns_trace_sys_recv(struct dns_trace *trace, int fd, int socktype, const void *data, size_t datasize, int error) {
4721 struct dns_trace_event te;
4722 if (!trace || !trace->fp)
4725 dns_te_init(&te, DNS_TE_SYS_RECV);
4726 dns_te_initnames(&te.sys_recv.dst, &te.sys_recv.src, fd);
4727 te.sys_recv.socktype = socktype;
4728 te.sys_recv.error = error;
4729 dns_trace_tag_and_put(trace, &te, data, datasize);
4732 static dns_error_t dns_trace_dump_packet(struct dns_trace *trace, const char *prefix, const unsigned char *data, size_t datasize, FILE *fp) {
4733 struct dns_packet *packet = NULL;
4734 char *line = NULL, *p;
4735 size_t size = 1, skip = 0;
4736 struct dns_rr_i records;
4737 struct dns_p_lines_i lines;
4741 if (!(packet = dns_p_make(datasize, &error)))
4744 memcpy(packet->data, data, datasize);
4745 packet->end = datasize;
4746 (void)dns_p_study(packet);
4748 if (!(p = dns_reallocarray(line, size, 2, &error)))
4753 memset(&records, 0, sizeof records);
4754 memset(&lines, 0, sizeof lines);
4757 while ((len = dns_p_lines(line, size, &error, packet, &records, &lines))) {
4758 if (!(len < size)) {
4761 } else if (skip <= count) {
4763 fwrite(line, 1, len, fp);
4779 static dns_error_t dns_trace_dump_data(struct dns_trace *trace, const char *prefix, const unsigned char *data, size_t datasize, FILE *fp) {
4780 struct dns_hxd_lines_i lines = { 0 };
4784 while ((len = dns_hxd_lines(line, sizeof line, data, datasize, &lines))) {
4785 if (len >= sizeof line)
4786 return EOVERFLOW; /* shouldn't be possible */
4788 fwrite(line, 1, len, fp);
4794 static dns_error_t dns_trace_dump_addr(struct dns_trace *trace, const char *prefix, const struct sockaddr_storage *ss, FILE *fp) {
4800 if ((addr = dns_sa_addr(ss->ss_family, (struct sockaddr *)ss, NULL))) {
4801 char ip[INET6_ADDRSTRLEN + 1];
4803 if ((error = dns_ntop(ss->ss_family, addr, ip, sizeof ip)))
4805 fprintf(fp, "%s%s\n", prefix, ip);
4806 } else if ((path = dns_sa_path((struct sockaddr *)ss, &len))) {
4807 fprintf(fp, "%sunix:%.*s", prefix, (int)len, path);
4815 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) {
4816 char time_s[48], elapsed_s[48];
4818 dns_utime_print(time_s, sizeof time_s, dns_ts2us(&te->ts, 0));
4819 dns_utime_print(elapsed_s, sizeof elapsed_s, elapsed);
4821 fprintf(fp, "%sid: %"DNS_TRACE_ID_PRI"\n", prefix, te->id);
4822 fprintf(fp, "%sts: %s (%s)\n", prefix, time_s, elapsed_s);
4823 fprintf(fp, "%sabi: 0x%x (0x%x)\n", prefix, te->abi, DNS_TRACE_ABI);
4827 static dns_error_t dns_trace_dump_error(struct dns_trace *trace, const char *prefix, int error, FILE *fp) {
4828 fprintf(fp, "%s%d (%s)\n", prefix, error, (error)? dns_strerror(error) : "none");
4832 dns_error_t dns_trace_dump(struct dns_trace *trace, FILE *fp) {
4833 struct dns_trace_event *te = NULL;
4836 dns_microseconds_t begin, elapsed;
4840 if (!trace || !trace->fp)
4843 if (0 != fseek(trace->fp, 0, SEEK_SET))
4846 while (dns_trace_fget(&te, trace->fp, &error)) {
4847 size_t datasize = dns_te_datasize(te);
4848 const unsigned char *data = (datasize)? te->data : NULL;
4850 if (state.id != te->id) {
4852 state.begin = dns_ts2us(&te->ts, 0);
4854 dns_time_diff(&state.elapsed, dns_ts2us(&te->ts, 0), state.begin);
4857 case DNS_TE_RES_SUBMIT:
4858 fprintf(fp, "dns_res_submit:\n");
4859 dns_trace_dump_meta(trace, " ", te, state.elapsed, fp);
4860 fprintf(fp, " qname: %s\n", te->res_submit.qname);
4861 fprintf(fp, " qtype: %s\n", dns_strtype(te->res_submit.qtype));
4862 fprintf(fp, " qclass: %s\n", dns_strclass(te->res_submit.qclass));
4863 dns_trace_dump_error(trace, " error: ", te->res_submit.error, fp);
4865 case DNS_TE_RES_FETCH:
4866 fprintf(fp, "dns_res_fetch:\n");
4867 dns_trace_dump_meta(trace, " ", te, state.elapsed, fp);
4868 dns_trace_dump_error(trace, " error: ", te->res_fetch.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_SUBMIT:
4881 fprintf(fp, "dns_so_submit:\n");
4882 dns_trace_dump_meta(trace, " ", te, state.elapsed, fp);
4883 fprintf(fp, " hname: %s\n", te->so_submit.hname);
4884 dns_trace_dump_addr(trace, " haddr: ", &te->so_submit.haddr, fp);
4885 dns_trace_dump_error(trace, " error: ", te->so_submit.error, fp);
4888 fprintf(fp, " packet: |\n");
4889 if ((error = dns_trace_dump_packet(trace, " ", data, datasize, fp)))
4891 fprintf(fp, " data: |\n");
4892 if ((error = dns_trace_dump_data(trace, " ", data, datasize, fp)))
4897 case DNS_TE_SO_VERIFY:
4898 fprintf(fp, "dns_so_verify:\n");
4899 dns_trace_dump_meta(trace, " ", te, state.elapsed, fp);
4900 dns_trace_dump_error(trace, " error: ", te->so_verify.error, fp);
4903 fprintf(fp, " packet: |\n");
4904 if ((error = dns_trace_dump_packet(trace, " ", data, datasize, fp)))
4906 fprintf(fp, " data: |\n");
4907 if ((error = dns_trace_dump_data(trace, " ", data, datasize, fp)))
4912 case DNS_TE_SO_FETCH:
4913 fprintf(fp, "dns_so_fetch:\n");
4914 dns_trace_dump_meta(trace, " ", te, state.elapsed, fp);
4915 dns_trace_dump_error(trace, " error: ", te->so_fetch.error, fp);
4918 fprintf(fp, " packet: |\n");
4919 if ((error = dns_trace_dump_packet(trace, " ", data, datasize, fp)))
4921 fprintf(fp, " data: |\n");
4922 if ((error = dns_trace_dump_data(trace, " ", data, datasize, fp)))
4927 case DNS_TE_SYS_CONNECT: {
4928 int socktype = te->sys_connect.socktype;
4929 fprintf(fp, "dns_sys_connect:\n");
4930 dns_trace_dump_meta(trace, " ", te, state.elapsed, fp);
4931 dns_trace_dump_addr(trace, " src: ", &te->sys_connect.src, fp);
4932 dns_trace_dump_addr(trace, " dst: ", &te->sys_connect.dst, fp);
4933 fprintf(fp, " socktype: %d (%s)\n", socktype, ((socktype == SOCK_STREAM)? "SOCK_STREAM" : (socktype == SOCK_DGRAM)? "SOCK_DGRAM" : "?"));
4934 dns_trace_dump_error(trace, " error: ", te->sys_connect.error, fp);
4938 case DNS_TE_SYS_SEND: {
4939 int socktype = te->sys_send.socktype;
4940 fprintf(fp, "dns_sys_send:\n");
4941 dns_trace_dump_meta(trace, " ", te, state.elapsed, fp);
4942 dns_trace_dump_addr(trace, " src: ", &te->sys_send.src, fp);
4943 dns_trace_dump_addr(trace, " dst: ", &te->sys_send.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_send.error, fp);
4948 fprintf(fp, " data: |\n");
4949 if ((error = dns_trace_dump_data(trace, " ", data, datasize, fp)))
4955 case DNS_TE_SYS_RECV: {
4956 int socktype = te->sys_recv.socktype;
4957 fprintf(fp, "dns_sys_recv:\n");
4958 dns_trace_dump_meta(trace, " ", te, state.elapsed, fp);
4959 dns_trace_dump_addr(trace, " src: ", &te->sys_recv.src, fp);
4960 dns_trace_dump_addr(trace, " dst: ", &te->sys_recv.dst, fp);
4961 fprintf(fp, " socktype: %d (%s)\n", socktype, ((socktype == SOCK_STREAM)? "SOCK_STREAM" : (socktype == SOCK_DGRAM)? "SOCK_DGRAM" : "?"));
4962 dns_trace_dump_error(trace, " error: ", te->sys_recv.error, fp);
4965 fprintf(fp, " data: |\n");
4966 if ((error = dns_trace_dump_data(trace, " ", data, datasize, fp)))
4973 fprintf(fp, "unknown(0x%.2x):\n", te->type);
4974 dns_trace_dump_meta(trace, " ", te, state.elapsed, fp);
4977 fprintf(fp, " data: |\n");
4978 if ((error = dns_trace_dump_data(trace, " ", data, datasize, fp)))
4998 * H O S T S R O U T I N E S
5000 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5003 struct dns_hosts_entry {
5004 char host[DNS_D_MAXNAME + 1];
5016 struct dns_hosts_entry *next;
5019 dns_atomic_t refcount;
5020 }; /* struct dns_hosts */
5023 struct dns_hosts *dns_hosts_open(int *error) {
5024 static const struct dns_hosts hosts_initializer = { .refcount = 1 };
5025 struct dns_hosts *hosts;
5027 if (!(hosts = malloc(sizeof *hosts)))
5030 *hosts = hosts_initializer;
5032 hosts->tail = &hosts->head;
5036 *error = dns_syerr();
5041 } /* dns_hosts_open() */
5044 void dns_hosts_close(struct dns_hosts *hosts) {
5045 struct dns_hosts_entry *ent, *xnt;
5047 if (!hosts || 1 != dns_hosts_release(hosts))
5050 for (ent = hosts->head; ent; ent = xnt) {
5059 } /* dns_hosts_close() */
5062 dns_refcount_t dns_hosts_acquire(struct dns_hosts *hosts) {
5063 return dns_atomic_fetch_add(&hosts->refcount);
5064 } /* dns_hosts_acquire() */
5067 dns_refcount_t dns_hosts_release(struct dns_hosts *hosts) {
5068 return dns_atomic_fetch_sub(&hosts->refcount);
5069 } /* dns_hosts_release() */
5072 struct dns_hosts *dns_hosts_mortal(struct dns_hosts *hosts) {
5074 dns_hosts_release(hosts);
5077 } /* dns_hosts_mortal() */
5080 struct dns_hosts *dns_hosts_local(int *error_) {
5081 struct dns_hosts *hosts;
5084 if (!(hosts = dns_hosts_open(&error)))
5087 if ((error = dns_hosts_loadpath(hosts, "/etc/hosts")))
5094 dns_hosts_close(hosts);
5097 } /* dns_hosts_local() */
5100 #define dns_hosts_issep(ch) (dns_isspace(ch))
5101 #define dns_hosts_iscom(ch) ((ch) == '#' || (ch) == ';')
5103 int dns_hosts_loadfile(struct dns_hosts *hosts, FILE *fp) {
5104 struct dns_hosts_entry ent;
5105 char word[DNS_PP_MAX(INET6_ADDRSTRLEN, DNS_D_MAXNAME) + 1];
5106 unsigned wp, wc, skip;
5112 memset(&ent, '\0', sizeof ent);
5117 memset(word, '\0', sizeof word);
5120 while (EOF != (ch = fgetc(fp)) && ch != '\n') {
5121 skip |= !!dns_hosts_iscom(ch);
5126 if (dns_hosts_issep(ch))
5129 if (wp < sizeof word - 1)
5143 ent.af = (strchr(word, ':'))? AF_INET6 : AF_INET;
5144 skip = (1 != dns_inet_pton(ent.af, word, &ent.addr));
5151 dns_d_anchor(ent.host, sizeof ent.host, word, wp);
5153 if ((error = dns_hosts_insert(hosts, ent.af, &ent.addr, ent.host, (wc > 2))))
5158 } while (ch != EOF && ch != '\n');
5159 } while (ch != EOF);
5162 } /* dns_hosts_loadfile() */
5165 int dns_hosts_loadpath(struct dns_hosts *hosts, const char *path) {
5169 if (!(fp = dns_fopen(path, "rt", &error)))
5172 error = dns_hosts_loadfile(hosts, fp);
5177 } /* dns_hosts_loadpath() */
5180 int dns_hosts_dump(struct dns_hosts *hosts, FILE *fp) {
5181 struct dns_hosts_entry *ent, *xnt;
5182 char addr[INET6_ADDRSTRLEN + 1];
5185 for (ent = hosts->head; ent; ent = xnt) {
5188 dns_inet_ntop(ent->af, &ent->addr, addr, sizeof addr);
5192 for (i = strlen(addr); i < INET_ADDRSTRLEN; i++)
5197 fputs(ent->host, fp);
5202 } /* dns_hosts_dump() */
5205 int dns_hosts_insert(struct dns_hosts *hosts, int af, const void *addr, const void *host, _Bool alias) {
5206 struct dns_hosts_entry *ent;
5209 if (!(ent = malloc(sizeof *ent)))
5212 dns_d_anchor(ent->host, sizeof ent->host, host, strlen(host));
5214 switch ((ent->af = af)) {
5216 memcpy(&ent->addr.a6, addr, sizeof ent->addr.a6);
5218 dns_aaaa_arpa(ent->arpa, sizeof ent->arpa, addr);
5222 memcpy(&ent->addr.a4, addr, sizeof ent->addr.a4);
5224 dns_a_arpa(ent->arpa, sizeof ent->arpa, addr);
5237 hosts->tail = &ent->next;
5241 error = dns_syerr();
5246 } /* dns_hosts_insert() */
5249 struct dns_packet *dns_hosts_query(struct dns_hosts *hosts, struct dns_packet *Q, int *error_) {
5250 struct dns_packet *P = dns_p_new(512);
5251 struct dns_packet *A = 0;
5253 struct dns_hosts_entry *ent;
5255 char qname[DNS_D_MAXNAME + 1];
5258 if ((error = dns_rr_parse(&rr, 12, Q)))
5261 if (!(qlen = dns_d_expand(qname, sizeof qname, rr.dn.p, Q, &error)))
5263 else if (qlen >= sizeof qname)
5266 if ((error = dns_p_push(P, DNS_S_QD, qname, qlen, rr.type, rr.class, 0, 0)))
5271 for (ent = hosts->head; ent; ent = ent->next) {
5272 if (ent->alias || 0 != strcasecmp(qname, ent->arpa))
5275 if ((error = dns_p_push(P, DNS_S_AN, qname, qlen, rr.type, rr.class, 0, ent->host)))
5287 loop: for (ent = hosts->head; ent; ent = ent->next) {
5288 if (ent->af != af || 0 != strcasecmp(qname, ent->host))
5291 if ((error = dns_p_push(P, DNS_S_AN, qname, qlen, rr.type, rr.class, 0, &ent->addr)))
5301 if (!(A = dns_p_copy(dns_p_make(P->end, &error), P)))
5306 error = DNS_EILLEGAL;
5313 } /* dns_hosts_query() */
5317 * R E S O L V . C O N F R O U T I N E S
5319 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5321 struct dns_resolv_conf *dns_resconf_open(int *error) {
5322 static const struct dns_resolv_conf resconf_initializer = {
5324 .family = { AF_INET, AF_INET6 },
5325 .options = { .ndots = 1, .timeout = 5, .attempts = 2, .tcp = DNS_RESCONF_TCP_ENABLE, },
5326 .iface = { .ss_family = AF_INET },
5328 struct dns_resolv_conf *resconf;
5329 struct sockaddr_in *sin;
5331 if (!(resconf = malloc(sizeof *resconf)))
5334 *resconf = resconf_initializer;
5336 sin = (struct sockaddr_in *)&resconf->nameserver[0];
5337 sin->sin_family = AF_INET;
5338 sin->sin_addr.s_addr = INADDR_ANY;
5339 sin->sin_port = htons(53);
5341 sin->sin_len = sizeof *sin;
5344 if (0 != gethostname(resconf->search[0], sizeof resconf->search[0]))
5347 dns_d_anchor(resconf->search[0], sizeof resconf->search[0], resconf->search[0], strlen(resconf->search[0]));
5348 dns_d_cleave(resconf->search[0], sizeof resconf->search[0], resconf->search[0], strlen(resconf->search[0]));
5351 * XXX: If gethostname() returned a string without any label
5352 * separator, then search[0][0] should be NUL.
5355 dns_resconf_acquire(resconf);
5359 *error = dns_syerr();
5364 } /* dns_resconf_open() */
5367 void dns_resconf_close(struct dns_resolv_conf *resconf) {
5368 if (!resconf || 1 != dns_resconf_release(resconf))
5372 } /* dns_resconf_close() */
5375 dns_refcount_t dns_resconf_acquire(struct dns_resolv_conf *resconf) {
5376 return dns_atomic_fetch_add(&resconf->_.refcount);
5377 } /* dns_resconf_acquire() */
5380 dns_refcount_t dns_resconf_release(struct dns_resolv_conf *resconf) {
5381 return dns_atomic_fetch_sub(&resconf->_.refcount);
5382 } /* dns_resconf_release() */
5385 struct dns_resolv_conf *dns_resconf_mortal(struct dns_resolv_conf *resconf) {
5387 dns_resconf_release(resconf);
5390 } /* dns_resconf_mortal() */
5393 struct dns_resolv_conf *dns_resconf_local(int *error_) {
5394 struct dns_resolv_conf *resconf;
5397 if (!(resconf = dns_resconf_open(&error)))
5400 if ((error = dns_resconf_loadpath(resconf, "/etc/resolv.conf"))) {
5402 * NOTE: Both the glibc and BIND9 resolvers ignore a missing
5403 * /etc/resolv.conf, defaulting to a nameserver of
5404 * 127.0.0.1. See also dns_hints_insert_resconf, and the
5405 * default initialization of nameserver[0] in
5408 if (error != ENOENT)
5412 if ((error = dns_nssconf_loadpath(resconf, "/etc/nsswitch.conf"))) {
5413 if (error != ENOENT)
5421 dns_resconf_close(resconf);
5424 } /* dns_resconf_local() */
5427 struct dns_resolv_conf *dns_resconf_root(int *error) {
5428 struct dns_resolv_conf *resconf;
5430 if ((resconf = dns_resconf_local(error)))
5431 resconf->options.recurse = 1;
5434 } /* dns_resconf_root() */
5437 static time_t dns_resconf_timeout(const struct dns_resolv_conf *resconf) {
5438 return (time_t)DNS_PP_MIN(INT_MAX, resconf->options.timeout);
5439 } /* dns_resconf_timeout() */
5442 enum dns_resconf_keyword {
5443 DNS_RESCONF_NAMESERVER,
5453 DNS_RESCONF_OPTIONS,
5456 DNS_RESCONF_TIMEOUT,
5457 DNS_RESCONF_ATTEMPTS,
5459 DNS_RESCONF_RECURSE,
5463 DNS_RESCONF_INTERFACE,
5468 DNS_RESCONF_DISABLE,
5469 }; /* enum dns_resconf_keyword */
5471 static enum dns_resconf_keyword dns_resconf_keyword(const char *word) {
5472 static const char *words[] = {
5473 [DNS_RESCONF_NAMESERVER] = "nameserver",
5474 [DNS_RESCONF_DOMAIN] = "domain",
5475 [DNS_RESCONF_SEARCH] = "search",
5476 [DNS_RESCONF_LOOKUP] = "lookup",
5477 [DNS_RESCONF_FILE] = "file",
5478 [DNS_RESCONF_BIND] = "bind",
5479 [DNS_RESCONF_CACHE] = "cache",
5480 [DNS_RESCONF_FAMILY] = "family",
5481 [DNS_RESCONF_INET4] = "inet4",
5482 [DNS_RESCONF_INET6] = "inet6",
5483 [DNS_RESCONF_OPTIONS] = "options",
5484 [DNS_RESCONF_EDNS0] = "edns0",
5485 [DNS_RESCONF_ROTATE] = "rotate",
5486 [DNS_RESCONF_RECURSE] = "recurse",
5487 [DNS_RESCONF_SMART] = "smart",
5488 [DNS_RESCONF_TCP] = "tcp",
5489 [DNS_RESCONF_INTERFACE] = "interface",
5490 [DNS_RESCONF_ZERO] = "0",
5491 [DNS_RESCONF_ONE] = "1",
5492 [DNS_RESCONF_ENABLE] = "enable",
5493 [DNS_RESCONF_ONLY] = "only",
5494 [DNS_RESCONF_DISABLE] = "disable",
5498 for (i = 0; i < lengthof(words); i++) {
5499 if (words[i] && 0 == strcasecmp(words[i], word))
5503 if (0 == strncasecmp(word, "ndots:", sizeof "ndots:" - 1))
5504 return DNS_RESCONF_NDOTS;
5506 if (0 == strncasecmp(word, "timeout:", sizeof "timeout:" - 1))
5507 return DNS_RESCONF_TIMEOUT;
5509 if (0 == strncasecmp(word, "attempts:", sizeof "attempts:" - 1))
5510 return DNS_RESCONF_ATTEMPTS;
5512 if (0 == strncasecmp(word, "tcp:", sizeof "tcp:" - 1))
5513 return DNS_RESCONF_TCPx;
5516 } /* dns_resconf_keyword() */
5519 /** OpenBSD-style "[1.2.3.4]:53" nameserver syntax */
5520 int dns_resconf_pton(struct sockaddr_storage *ss, const char *src) {
5521 struct { char buf[128], *p; } addr = { "", addr.buf };
5522 unsigned short port = 0;
5523 int ch, af = AF_INET, error;
5525 while ((ch = *src++)) {
5534 while ((ch = *src++)) {
5535 if (dns_isdigit(ch)) {
5547 if (addr.p < endof(addr.buf) - 1)
5555 if ((error = dns_pton(af, addr.buf, dns_sa_addr(af, ss, NULL))))
5558 port = (!port)? 53 : port;
5559 *dns_sa_port(af, ss) = htons(port);
5560 dns_sa_family(ss) = af;
5563 } /* dns_resconf_pton() */
5565 #define dns_resconf_issep(ch) (dns_isspace(ch) || (ch) == ',')
5566 #define dns_resconf_iscom(ch) ((ch) == '#' || (ch) == ';')
5568 int dns_resconf_loadfile(struct dns_resolv_conf *resconf, FILE *fp) {
5569 unsigned sa_count = 0;
5570 char words[6][DNS_D_MAXNAME + 1];
5571 unsigned wp, wc, i, j, n;
5577 memset(words, '\0', sizeof words);
5581 while (EOF != (ch = getc(fp)) && ch != '\n') {
5582 if (dns_resconf_issep(ch)) {
5586 if (++wc >= lengthof(words))
5589 } else if (dns_resconf_iscom(ch)) {
5593 } while (ch != EOF && ch != '\n');
5596 } else if (wp < sizeof words[wc] - 1) {
5597 words[wc][wp++] = ch;
5599 wp = 0; /* drop word */
5610 switch (dns_resconf_keyword(words[0])) {
5611 case DNS_RESCONF_NAMESERVER:
5612 if (sa_count >= lengthof(resconf->nameserver))
5615 if ((error = dns_resconf_pton(&resconf->nameserver[sa_count], words[1])))
5621 case DNS_RESCONF_DOMAIN:
5622 case DNS_RESCONF_SEARCH:
5623 memset(resconf->search, '\0', sizeof resconf->search);
5625 for (i = 1, j = 0; i < wc && j < lengthof(resconf->search); i++, j++)
5626 dns_d_anchor(resconf->search[j], sizeof resconf->search[j], words[i], strlen(words[i]));
5629 case DNS_RESCONF_LOOKUP:
5630 for (i = 1, j = 0; i < wc && j < lengthof(resconf->lookup); i++) {
5631 switch (dns_resconf_keyword(words[i])) {
5632 case DNS_RESCONF_FILE:
5633 resconf->lookup[j++] = 'f';
5636 case DNS_RESCONF_BIND:
5637 resconf->lookup[j++] = 'b';
5640 case DNS_RESCONF_CACHE:
5641 resconf->lookup[j++] = 'c';
5650 case DNS_RESCONF_FAMILY:
5651 for (i = 1, j = 0; i < wc && j < lengthof(resconf->family); i++) {
5652 switch (dns_resconf_keyword(words[i])) {
5653 case DNS_RESCONF_INET4:
5654 resconf->family[j++] = AF_INET;
5657 case DNS_RESCONF_INET6:
5658 resconf->family[j++] = AF_INET6;
5667 case DNS_RESCONF_OPTIONS:
5668 for (i = 1; i < wc; i++) {
5669 switch (dns_resconf_keyword(words[i])) {
5670 case DNS_RESCONF_EDNS0:
5671 resconf->options.edns0 = 1;
5674 case DNS_RESCONF_NDOTS:
5675 for (j = sizeof "ndots:" - 1, n = 0; dns_isdigit(words[i][j]); j++) {
5677 n += words[i][j] - '0';
5680 resconf->options.ndots = n;
5683 case DNS_RESCONF_TIMEOUT:
5684 for (j = sizeof "timeout:" - 1, n = 0; dns_isdigit(words[i][j]); j++) {
5686 n += words[i][j] - '0';
5689 resconf->options.timeout = n;
5692 case DNS_RESCONF_ATTEMPTS:
5693 for (j = sizeof "attempts:" - 1, n = 0; dns_isdigit(words[i][j]); j++) {
5695 n += words[i][j] - '0';
5698 resconf->options.attempts = n;
5701 case DNS_RESCONF_ROTATE:
5702 resconf->options.rotate = 1;
5705 case DNS_RESCONF_RECURSE:
5706 resconf->options.recurse = 1;
5709 case DNS_RESCONF_SMART:
5710 resconf->options.smart = 1;
5713 case DNS_RESCONF_TCP:
5714 resconf->options.tcp = DNS_RESCONF_TCP_ONLY;
5717 case DNS_RESCONF_TCPx:
5718 switch (dns_resconf_keyword(&words[i][sizeof "tcp:" - 1])) {
5719 case DNS_RESCONF_ENABLE:
5720 resconf->options.tcp = DNS_RESCONF_TCP_ENABLE;
5723 case DNS_RESCONF_ONE:
5724 case DNS_RESCONF_ONLY:
5725 resconf->options.tcp = DNS_RESCONF_TCP_ONLY;
5728 case DNS_RESCONF_ZERO:
5729 case DNS_RESCONF_DISABLE:
5730 resconf->options.tcp = DNS_RESCONF_TCP_DISABLE;
5744 case DNS_RESCONF_INTERFACE:
5745 for (i = 0, n = 0; dns_isdigit(words[2][i]); i++) {
5747 n += words[2][i] - '0';
5750 dns_resconf_setiface(resconf, words[1], n);
5756 } while (ch != EOF);
5759 } /* dns_resconf_loadfile() */
5762 int dns_resconf_loadpath(struct dns_resolv_conf *resconf, const char *path) {
5766 if (!(fp = dns_fopen(path, "rt", &error)))
5769 error = dns_resconf_loadfile(resconf, fp);
5774 } /* dns_resconf_loadpath() */
5777 struct dns_anyconf {
5780 char buffer[1024], *tp, *cp;
5781 }; /* struct dns_anyconf */
5784 static void dns_anyconf_reset(struct dns_anyconf *cf) {
5786 cf->tp = cf->cp = cf->buffer;
5787 } /* dns_anyconf_reset() */
5790 static int dns_anyconf_push(struct dns_anyconf *cf) {
5791 if (!(cf->cp < endof(cf->buffer) && cf->count < lengthof(cf->token)))
5795 cf->token[cf->count++] = cf->tp;
5799 } /* dns_anyconf_push() */
5802 static void dns_anyconf_pop(struct dns_anyconf *cf) {
5803 if (cf->count > 0) {
5805 cf->tp = cf->cp = cf->token[cf->count];
5806 cf->token[cf->count] = 0;
5808 } /* dns_anyconf_pop() */
5811 static int dns_anyconf_addc(struct dns_anyconf *cf, int ch) {
5812 if (!(cf->cp < endof(cf->buffer)))
5818 } /* dns_anyconf_addc() */
5821 static _Bool dns_anyconf_match(const char *pat, int mc) {
5832 while ((pc = *(const unsigned char *)pat++)) {
5835 if (!(pc = *(const unsigned char *)pat++))
5840 if (dns_isalpha(mc))
5844 if (dns_isdigit(mc))
5848 if (dns_isalnum(mc))
5852 if (dns_isspace(mc))
5870 } /* dns_anyconf_match() */
5873 static int dns_anyconf_peek(FILE *fp) {
5878 } /* dns_anyconf_peek() */
5881 static size_t dns_anyconf_skip(const char *pat, FILE *fp) {
5885 while (EOF != (ch = getc(fp))) {
5886 if (dns_anyconf_match(pat, ch)) {
5897 } /* dns_anyconf_skip() */
5900 static size_t dns_anyconf_scan(struct dns_anyconf *cf, const char *pat, FILE *fp, int *error) {
5904 while (EOF != (ch = getc(fp))) {
5905 if (dns_anyconf_match(pat, ch)) {
5906 if ((*error = dns_anyconf_addc(cf, ch)))
5917 if ((len = cf->cp - cf->tp)) {
5918 if ((*error = dns_anyconf_push(cf)))
5927 } /* dns_anyconf_scan() */
5930 DNS_NOTUSED static void dns_anyconf_dump(struct dns_anyconf *cf, FILE *fp) {
5933 fprintf(fp, "tokens:");
5935 for (i = 0; i < cf->count; i++) {
5936 fprintf(fp, " %s", cf->token[i]);
5940 } /* dns_anyconf_dump() */
5943 enum dns_nssconf_keyword {
5944 DNS_NSSCONF_INVALID = 0,
5945 DNS_NSSCONF_HOSTS = 1,
5946 DNS_NSSCONF_SUCCESS,
5947 DNS_NSSCONF_NOTFOUND,
5948 DNS_NSSCONF_UNAVAIL,
5949 DNS_NSSCONF_TRYAGAIN,
5950 DNS_NSSCONF_CONTINUE,
5957 }; /* enum dns_nssconf_keyword */
5959 static enum dns_nssconf_keyword dns_nssconf_keyword(const char *word) {
5960 static const char *list[] = {
5961 [DNS_NSSCONF_HOSTS] = "hosts",
5962 [DNS_NSSCONF_SUCCESS] = "success",
5963 [DNS_NSSCONF_NOTFOUND] = "notfound",
5964 [DNS_NSSCONF_UNAVAIL] = "unavail",
5965 [DNS_NSSCONF_TRYAGAIN] = "tryagain",
5966 [DNS_NSSCONF_CONTINUE] = "continue",
5967 [DNS_NSSCONF_RETURN] = "return",
5968 [DNS_NSSCONF_FILES] = "files",
5969 [DNS_NSSCONF_DNS] = "dns",
5970 [DNS_NSSCONF_MDNS] = "mdns",
5974 for (i = 1; i < lengthof(list); i++) {
5975 if (list[i] && 0 == strcasecmp(list[i], word))
5979 return DNS_NSSCONF_INVALID;
5980 } /* dns_nssconf_keyword() */
5983 static enum dns_nssconf_keyword dns_nssconf_c2k(int ch) {
5984 static const char map[] = {
5985 ['S'] = DNS_NSSCONF_SUCCESS,
5986 ['N'] = DNS_NSSCONF_NOTFOUND,
5987 ['U'] = DNS_NSSCONF_UNAVAIL,
5988 ['T'] = DNS_NSSCONF_TRYAGAIN,
5989 ['C'] = DNS_NSSCONF_CONTINUE,
5990 ['R'] = DNS_NSSCONF_RETURN,
5991 ['f'] = DNS_NSSCONF_FILES,
5992 ['F'] = DNS_NSSCONF_FILES,
5993 ['d'] = DNS_NSSCONF_DNS,
5994 ['D'] = DNS_NSSCONF_DNS,
5995 ['b'] = DNS_NSSCONF_DNS,
5996 ['B'] = DNS_NSSCONF_DNS,
5997 ['m'] = DNS_NSSCONF_MDNS,
5998 ['M'] = DNS_NSSCONF_MDNS,
6001 return (ch >= 0 && ch < (int)lengthof(map))? map[ch] : DNS_NSSCONF_INVALID;
6002 } /* dns_nssconf_c2k() */
6008 static int dns_nssconf_k2c(int k) {
6009 static const char map[DNS_NSSCONF_LAST] = {
6010 [DNS_NSSCONF_SUCCESS] = 'S',
6011 [DNS_NSSCONF_NOTFOUND] = 'N',
6012 [DNS_NSSCONF_UNAVAIL] = 'U',
6013 [DNS_NSSCONF_TRYAGAIN] = 'T',
6014 [DNS_NSSCONF_CONTINUE] = 'C',
6015 [DNS_NSSCONF_RETURN] = 'R',
6016 [DNS_NSSCONF_FILES] = 'f',
6017 [DNS_NSSCONF_DNS] = 'b',
6018 [DNS_NSSCONF_MDNS] = 'm',
6021 return (k >= 0 && k < (int)lengthof(map))? (map[k]? map[k] : '?') : '?';
6022 } /* dns_nssconf_k2c() */
6024 static const char *dns_nssconf_k2s(int k) {
6025 static const char *const map[DNS_NSSCONF_LAST] = {
6026 [DNS_NSSCONF_SUCCESS] = "SUCCESS",
6027 [DNS_NSSCONF_NOTFOUND] = "NOTFOUND",
6028 [DNS_NSSCONF_UNAVAIL] = "UNAVAIL",
6029 [DNS_NSSCONF_TRYAGAIN] = "TRYAGAIN",
6030 [DNS_NSSCONF_CONTINUE] = "continue",
6031 [DNS_NSSCONF_RETURN] = "return",
6032 [DNS_NSSCONF_FILES] = "files",
6033 [DNS_NSSCONF_DNS] = "dns",
6034 [DNS_NSSCONF_MDNS] = "mdns",
6037 return (k >= 0 && k < (int)lengthof(map))? (map[k]? map[k] : "") : "";
6038 } /* dns_nssconf_k2s() */
6043 int dns_nssconf_loadfile(struct dns_resolv_conf *resconf, FILE *fp) {
6044 enum dns_nssconf_keyword source, status, action;
6045 char lookup[sizeof resconf->lookup] = "", *lp;
6046 struct dns_anyconf cf;
6050 while (!feof(fp) && !ferror(fp)) {
6051 dns_anyconf_reset(&cf);
6053 dns_anyconf_skip("%s", fp);
6055 if (!dns_anyconf_scan(&cf, "%w_", fp, &error))
6058 if (DNS_NSSCONF_HOSTS != dns_nssconf_keyword(cf.token[0]))
6061 dns_anyconf_pop(&cf);
6063 if (!dns_anyconf_skip(": \t", fp))
6066 *(lp = lookup) = '\0';
6068 while (dns_anyconf_scan(&cf, "%w_", fp, &error)) {
6069 dns_anyconf_skip(" \t", fp);
6071 if ('[' == dns_anyconf_peek(fp)) {
6072 dns_anyconf_skip("[ \t", fp);
6075 if ('!' == dns_anyconf_peek(fp)) {
6076 dns_anyconf_skip("! \t", fp);
6077 /* FIXME: negating statuses; currently not implemented */
6078 dns_anyconf_skip("^#;]\n", fp); /* skip to end of criteria */
6082 if (!dns_anyconf_scan(&cf, "%w_", fp, &error)) break;
6083 dns_anyconf_skip("= \t", fp);
6084 if (!dns_anyconf_scan(&cf, "%w_", fp, &error)) {
6085 dns_anyconf_pop(&cf); /* discard status */
6086 dns_anyconf_skip("^#;]\n", fp); /* skip to end of criteria */
6089 dns_anyconf_skip(" \t", fp);
6092 dns_anyconf_skip("] \t", fp);
6095 if ((size_t)(endof(lookup) - lp) < cf.count + 1) /* +1 for '\0' */
6098 source = dns_nssconf_keyword(cf.token[0]);
6101 case DNS_NSSCONF_DNS:
6102 case DNS_NSSCONF_MDNS:
6103 case DNS_NSSCONF_FILES:
6104 *lp++ = dns_nssconf_k2c(source);
6110 for (i = 1; i + 1 < cf.count; i += 2) {
6111 status = dns_nssconf_keyword(cf.token[i]);
6112 action = dns_nssconf_keyword(cf.token[i + 1]);
6115 case DNS_NSSCONF_SUCCESS:
6116 case DNS_NSSCONF_NOTFOUND:
6117 case DNS_NSSCONF_UNAVAIL:
6118 case DNS_NSSCONF_TRYAGAIN:
6119 *lp++ = dns_nssconf_k2c(status);
6126 case DNS_NSSCONF_CONTINUE:
6127 case DNS_NSSCONF_RETURN:
6130 action = (status == DNS_NSSCONF_SUCCESS)
6131 ? DNS_NSSCONF_RETURN
6132 : DNS_NSSCONF_CONTINUE;
6136 *lp++ = dns_nssconf_k2c(action);
6140 dns_anyconf_reset(&cf);
6143 dns_anyconf_skip("^\n", fp);
6147 strncpy(resconf->lookup, lookup, sizeof resconf->lookup);
6150 } /* dns_nssconf_loadfile() */
6153 int dns_nssconf_loadpath(struct dns_resolv_conf *resconf, const char *path) {
6157 if (!(fp = dns_fopen(path, "rt", &error)))
6160 error = dns_nssconf_loadfile(resconf, fp);
6165 } /* dns_nssconf_loadpath() */
6168 struct dns_nssconf_source {
6169 enum dns_nssconf_keyword source, success, notfound, unavail, tryagain;
6170 }; /* struct dns_nssconf_source */
6172 typedef unsigned dns_nssconf_i;
6174 static inline int dns_nssconf_peek(const struct dns_resolv_conf *resconf, dns_nssconf_i state) {
6175 return (state < lengthof(resconf->lookup) && resconf->lookup[state])? resconf->lookup[state] : 0;
6176 } /* dns_nssconf_peek() */
6178 static _Bool dns_nssconf_next(struct dns_nssconf_source *src, const struct dns_resolv_conf *resconf, dns_nssconf_i *state) {
6179 int source, status, action;
6181 src->source = DNS_NSSCONF_INVALID;
6182 src->success = DNS_NSSCONF_RETURN;
6183 src->notfound = DNS_NSSCONF_CONTINUE;
6184 src->unavail = DNS_NSSCONF_CONTINUE;
6185 src->tryagain = DNS_NSSCONF_CONTINUE;
6187 while ((source = dns_nssconf_peek(resconf, *state))) {
6188 source = dns_nssconf_c2k(source);
6192 case DNS_NSSCONF_FILES:
6193 case DNS_NSSCONF_DNS:
6194 case DNS_NSSCONF_MDNS:
6195 src->source = source;
6201 while ((status = dns_nssconf_peek(resconf, *state)) && (action = dns_nssconf_peek(resconf, *state + 1))) {
6202 status = dns_nssconf_c2k(status);
6203 action = dns_nssconf_c2k(action);
6206 case DNS_NSSCONF_RETURN:
6207 case DNS_NSSCONF_CONTINUE:
6214 case DNS_NSSCONF_SUCCESS:
6215 src->success = action;
6217 case DNS_NSSCONF_NOTFOUND:
6218 src->notfound = action;
6220 case DNS_NSSCONF_UNAVAIL:
6221 src->unavail = action;
6223 case DNS_NSSCONF_TRYAGAIN:
6224 src->tryagain = action;
6236 return src->source != DNS_NSSCONF_INVALID;
6237 } /* dns_nssconf_next() */
6240 static int dns_nssconf_dump_status(int status, int action, unsigned *count, FILE *fp) {
6242 case DNS_NSSCONF_SUCCESS:
6243 if (action == DNS_NSSCONF_RETURN)
6247 if (action == DNS_NSSCONF_CONTINUE)
6257 fprintf(fp, "%s=%s", dns_nssconf_k2s(status), dns_nssconf_k2s(action));
6262 } /* dns_nssconf_dump_status() */
6265 int dns_nssconf_dump(struct dns_resolv_conf *resconf, FILE *fp) {
6266 struct dns_nssconf_source src;
6267 dns_nssconf_i i = 0;
6269 fputs("hosts:", fp);
6271 while (dns_nssconf_next(&src, resconf, &i)) {
6274 fprintf(fp, " %s", dns_nssconf_k2s(src.source));
6276 dns_nssconf_dump_status(DNS_NSSCONF_SUCCESS, src.success, &n, fp);
6277 dns_nssconf_dump_status(DNS_NSSCONF_NOTFOUND, src.notfound, &n, fp);
6278 dns_nssconf_dump_status(DNS_NSSCONF_UNAVAIL, src.unavail, &n, fp);
6279 dns_nssconf_dump_status(DNS_NSSCONF_TRYAGAIN, src.tryagain, &n, fp);
6288 } /* dns_nssconf_dump() */
6291 int dns_resconf_setiface(struct dns_resolv_conf *resconf, const char *addr, unsigned short port) {
6292 int af = (strchr(addr, ':'))? AF_INET6 : AF_INET;
6295 if ((error = dns_pton(af, addr, dns_sa_addr(af, &resconf->iface, NULL))))
6298 *dns_sa_port(af, &resconf->iface) = htons(port);
6299 resconf->iface.ss_family = af;
6302 } /* dns_resconf_setiface() */
6305 #define DNS_SM_RESTORE \
6307 pc = 0xff & (*state >> 0); \
6308 srchi = 0xff & (*state >> 8); \
6309 ndots = 0xff & (*state >> 16); \
6312 #define DNS_SM_SAVE \
6314 *state = ((0xff & pc) << 0) \
6315 | ((0xff & srchi) << 8) \
6316 | ((0xff & ndots) << 16); \
6319 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) {
6320 unsigned pc, srchi, ndots, len;
6324 /* if FQDN then return as-is and finish */
6325 if (dns_d_isanchored(qname, qlen)) {
6326 len = dns_d_anchor(dst, lim, qname, qlen);
6331 ndots = dns_d_ndots(qname, qlen);
6333 if (ndots >= resconf->options.ndots) {
6334 len = dns_d_anchor(dst, lim, qname, qlen);
6338 while (srchi < lengthof(resconf->search) && resconf->search[srchi][0]) {
6339 struct dns_buf buf = DNS_B_INTO(dst, lim);
6340 const char *dn = resconf->search[srchi++];
6342 dns_b_put(&buf, qname, qlen);
6343 dns_b_putc(&buf, '.');
6344 dns_b_puts(&buf, dn);
6345 if (!dns_d_isanchored(dn, strlen(dn)))
6346 dns_b_putc(&buf, '.');
6347 len = dns_b_strllen(&buf);
6351 if (ndots < resconf->options.ndots) {
6352 len = dns_d_anchor(dst, lim, qname, qlen);
6358 return dns_strlcpy(dst, "", lim);
6359 } /* dns_resconf_search() */
6362 #undef DNS_SM_RESTORE
6365 int dns_resconf_dump(struct dns_resolv_conf *resconf, FILE *fp) {
6369 for (i = 0; i < lengthof(resconf->nameserver) && (af = resconf->nameserver[i].ss_family) != AF_UNSPEC; i++) {
6370 char addr[INET6_ADDRSTRLEN + 1] = "[INVALID]";
6371 unsigned short port;
6373 dns_inet_ntop(af, dns_sa_addr(af, &resconf->nameserver[i], NULL), addr, sizeof addr);
6374 port = ntohs(*dns_sa_port(af, &resconf->nameserver[i]));
6377 fprintf(fp, "nameserver %s\n", addr);
6379 fprintf(fp, "nameserver [%s]:%hu\n", addr, port);
6383 fprintf(fp, "search");
6385 for (i = 0; i < lengthof(resconf->search) && resconf->search[i][0]; i++)
6386 fprintf(fp, " %s", resconf->search[i]);
6392 dns_nssconf_dump(resconf, fp);
6394 fprintf(fp, "lookup");
6396 for (i = 0; i < lengthof(resconf->lookup) && resconf->lookup[i]; i++) {
6397 switch (resconf->lookup[i]) {
6399 fprintf(fp, " bind"); break;
6401 fprintf(fp, " file"); break;
6403 fprintf(fp, " cache"); break;
6410 fprintf(fp, "options ndots:%u timeout:%u attempts:%u", resconf->options.ndots, resconf->options.timeout, resconf->options.attempts);
6412 if (resconf->options.edns0)
6413 fprintf(fp, " edns0");
6414 if (resconf->options.rotate)
6415 fprintf(fp, " rotate");
6416 if (resconf->options.recurse)
6417 fprintf(fp, " recurse");
6418 if (resconf->options.smart)
6419 fprintf(fp, " smart");
6421 switch (resconf->options.tcp) {
6422 case DNS_RESCONF_TCP_ENABLE:
6424 case DNS_RESCONF_TCP_ONLY:
6425 fprintf(fp, " tcp");
6427 case DNS_RESCONF_TCP_SOCKS:
6428 fprintf(fp, " tcp:socks");
6430 case DNS_RESCONF_TCP_DISABLE:
6431 fprintf(fp, " tcp:disable");
6438 if ((af = resconf->iface.ss_family) != AF_UNSPEC) {
6439 char addr[INET6_ADDRSTRLEN + 1] = "[INVALID]";
6441 dns_inet_ntop(af, dns_sa_addr(af, &resconf->iface, NULL), addr, sizeof addr);
6443 fprintf(fp, "interface %s %hu\n", addr, ntohs(*dns_sa_port(af, &resconf->iface)));
6447 } /* dns_resconf_dump() */
6451 * H I N T S E R V E R R O U T I N E S
6453 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6455 struct dns_hints_soa {
6456 unsigned char zone[DNS_D_MAXNAME + 1];
6459 struct sockaddr_storage ss;
6465 struct dns_hints_soa *next;
6466 }; /* struct dns_hints_soa */
6470 dns_atomic_t refcount;
6472 struct dns_hints_soa *head;
6473 }; /* struct dns_hints */
6476 struct dns_hints *dns_hints_open(struct dns_resolv_conf *resconf, int *error) {
6477 static const struct dns_hints H_initializer;
6478 struct dns_hints *H;
6482 if (!(H = malloc(sizeof *H)))
6487 dns_hints_acquire(H);
6491 *error = dns_syerr();
6496 } /* dns_hints_open() */
6499 void dns_hints_close(struct dns_hints *H) {
6500 struct dns_hints_soa *soa, *nxt;
6502 if (!H || 1 != dns_hints_release(H))
6505 for (soa = H->head; soa; soa = nxt) {
6514 } /* dns_hints_close() */
6517 dns_refcount_t dns_hints_acquire(struct dns_hints *H) {
6518 return dns_atomic_fetch_add(&H->refcount);
6519 } /* dns_hints_acquire() */
6522 dns_refcount_t dns_hints_release(struct dns_hints *H) {
6523 return dns_atomic_fetch_sub(&H->refcount);
6524 } /* dns_hints_release() */
6527 struct dns_hints *dns_hints_mortal(struct dns_hints *hints) {
6529 dns_hints_release(hints);
6532 } /* dns_hints_mortal() */
6535 struct dns_hints *dns_hints_local(struct dns_resolv_conf *resconf, int *error_) {
6536 struct dns_hints *hints = 0;
6540 dns_resconf_acquire(resconf);
6541 else if (!(resconf = dns_resconf_local(&error)))
6544 if (!(hints = dns_hints_open(resconf, &error)))
6549 if (0 == dns_hints_insert_resconf(hints, ".", resconf, &error) && error)
6552 dns_resconf_close(resconf);
6558 dns_resconf_close(resconf);
6559 dns_hints_close(hints);
6562 } /* dns_hints_local() */
6565 struct dns_hints *dns_hints_root(struct dns_resolv_conf *resconf, int *error_) {
6566 static const struct {
6568 char addr[INET6_ADDRSTRLEN];
6570 { AF_INET, "198.41.0.4" }, /* A.ROOT-SERVERS.NET. */
6571 { AF_INET6, "2001:503:ba3e::2:30" }, /* A.ROOT-SERVERS.NET. */
6572 { AF_INET, "192.228.79.201" }, /* B.ROOT-SERVERS.NET. */
6573 { AF_INET6, "2001:500:84::b" }, /* B.ROOT-SERVERS.NET. */
6574 { AF_INET, "192.33.4.12" }, /* C.ROOT-SERVERS.NET. */
6575 { AF_INET6, "2001:500:2::c" }, /* C.ROOT-SERVERS.NET. */
6576 { AF_INET, "199.7.91.13" }, /* D.ROOT-SERVERS.NET. */
6577 { AF_INET6, "2001:500:2d::d" }, /* D.ROOT-SERVERS.NET. */
6578 { AF_INET, "192.203.230.10" }, /* E.ROOT-SERVERS.NET. */
6579 { AF_INET, "192.5.5.241" }, /* F.ROOT-SERVERS.NET. */
6580 { AF_INET6, "2001:500:2f::f" }, /* F.ROOT-SERVERS.NET. */
6581 { AF_INET, "192.112.36.4" }, /* G.ROOT-SERVERS.NET. */
6582 { AF_INET, "128.63.2.53" }, /* H.ROOT-SERVERS.NET. */
6583 { AF_INET6, "2001:500:1::803f:235" }, /* H.ROOT-SERVERS.NET. */
6584 { AF_INET, "192.36.148.17" }, /* I.ROOT-SERVERS.NET. */
6585 { AF_INET6, "2001:7FE::53" }, /* I.ROOT-SERVERS.NET. */
6586 { AF_INET, "192.58.128.30" }, /* J.ROOT-SERVERS.NET. */
6587 { AF_INET6, "2001:503:c27::2:30" }, /* J.ROOT-SERVERS.NET. */
6588 { AF_INET, "193.0.14.129" }, /* K.ROOT-SERVERS.NET. */
6589 { AF_INET6, "2001:7FD::1" }, /* K.ROOT-SERVERS.NET. */
6590 { AF_INET, "199.7.83.42" }, /* L.ROOT-SERVERS.NET. */
6591 { AF_INET6, "2001:500:3::42" }, /* L.ROOT-SERVERS.NET. */
6592 { AF_INET, "202.12.27.33" }, /* M.ROOT-SERVERS.NET. */
6593 { AF_INET6, "2001:DC3::35" }, /* M.ROOT-SERVERS.NET. */
6595 struct dns_hints *hints = 0;
6596 struct sockaddr_storage ss;
6600 if (!(hints = dns_hints_open(resconf, &error)))
6603 for (i = 0; i < lengthof(root_hints); i++) {
6604 af = root_hints[i].af;
6606 if ((error = dns_pton(af, root_hints[i].addr, dns_sa_addr(af, &ss, NULL))))
6609 *dns_sa_port(af, &ss) = htons(53);
6612 if ((error = dns_hints_insert(hints, ".", (struct sockaddr *)&ss, 1)))
6620 dns_hints_close(hints);
6623 } /* dns_hints_root() */
6626 static struct dns_hints_soa *dns_hints_fetch(struct dns_hints *H, const char *zone) {
6627 struct dns_hints_soa *soa;
6629 for (soa = H->head; soa; soa = soa->next) {
6630 if (0 == strcasecmp(zone, (char *)soa->zone))
6635 } /* dns_hints_fetch() */
6638 int dns_hints_insert(struct dns_hints *H, const char *zone, const struct sockaddr *sa, unsigned priority) {
6639 static const struct dns_hints_soa soa_initializer;
6640 struct dns_hints_soa *soa;
6643 if (!(soa = dns_hints_fetch(H, zone))) {
6644 if (!(soa = malloc(sizeof *soa)))
6646 *soa = soa_initializer;
6647 dns_strlcpy((char *)soa->zone, zone, sizeof soa->zone);
6649 soa->next = H->head;
6653 i = soa->count % lengthof(soa->addrs);
6655 memcpy(&soa->addrs[i].ss, sa, dns_sa_len(sa));
6657 soa->addrs[i].priority = DNS_PP_MAX(1, priority);
6659 if (soa->count < lengthof(soa->addrs))
6663 } /* dns_hints_insert() */
6666 static _Bool dns_hints_isinaddr_any(const void *sa) {
6667 struct in_addr *addr;
6669 if (dns_sa_family(sa) != AF_INET)
6672 addr = dns_sa_addr(AF_INET, sa, NULL);
6673 return addr->s_addr == htonl(INADDR_ANY);
6676 unsigned dns_hints_insert_resconf(struct dns_hints *H, const char *zone, const struct dns_resolv_conf *resconf, int *error_) {
6680 for (i = 0, n = 0, p = 1; i < lengthof(resconf->nameserver) && resconf->nameserver[i].ss_family != AF_UNSPEC; i++, n++) {
6681 union { struct sockaddr_in sin; } tmp;
6682 struct sockaddr *ns;
6685 * dns_resconf_open initializes nameserver[0] to INADDR_ANY.
6687 * Traditionally the semantics of 0.0.0.0 meant the default
6688 * interface, which evolved to mean the loopback interface.
6689 * See comment block preceding resolv/res_init.c:res_init in
6690 * glibc 2.23. As of 2.23, glibc no longer translates
6691 * 0.0.0.0 despite the code comment, but it does default to
6692 * 127.0.0.1 when no nameservers are present.
6694 * BIND9 as of 9.10.3 still translates 0.0.0.0 to 127.0.0.1.
6695 * See lib/lwres/lwconfig.c:lwres_create_addr and the
6696 * convert_zero flag. 127.0.0.1 is also the default when no
6697 * nameservers are present.
6699 if (dns_hints_isinaddr_any(&resconf->nameserver[i])) {
6700 memcpy(&tmp.sin, &resconf->nameserver[i], sizeof tmp.sin);
6701 tmp.sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
6702 ns = (struct sockaddr *)&tmp.sin;
6704 ns = (struct sockaddr *)&resconf->nameserver[i];
6707 if ((error = dns_hints_insert(H, zone, ns, p)))
6710 p += !resconf->options.rotate;
6718 } /* dns_hints_insert_resconf() */
6721 static int dns_hints_i_cmp(unsigned a, unsigned b, struct dns_hints_i *i, struct dns_hints_soa *soa) {
6724 if ((cmp = soa->addrs[a].priority - soa->addrs[b].priority))
6727 return dns_k_shuffle16(a, i->state.seed) - dns_k_shuffle16(b, i->state.seed);
6728 } /* dns_hints_i_cmp() */
6731 static unsigned dns_hints_i_start(struct dns_hints_i *i, struct dns_hints_soa *soa) {
6736 for (p = 1; p < soa->count; p++) {
6737 if (dns_hints_i_cmp(p, p0, i, soa) < 0)
6742 } /* dns_hints_i_start() */
6745 static unsigned dns_hints_i_skip(unsigned p0, struct dns_hints_i *i, struct dns_hints_soa *soa) {
6748 for (pZ = 0; pZ < soa->count; pZ++) {
6749 if (dns_hints_i_cmp(pZ, p0, i, soa) > 0)
6755 for (p = pZ + 1; p < soa->count; p++) {
6756 if (dns_hints_i_cmp(p, p0, i, soa) <= 0)
6759 if (dns_hints_i_cmp(p, pZ, i, soa) >= 0)
6767 } /* dns_hints_i_skip() */
6770 static struct dns_hints_i *dns_hints_i_init(struct dns_hints_i *i, struct dns_hints *hints) {
6771 static const struct dns_hints_i i_initializer;
6772 struct dns_hints_soa *soa;
6774 i->state = i_initializer.state;
6777 i->state.seed = dns_random();
6778 } while (0 == i->state.seed);
6780 if ((soa = dns_hints_fetch(hints, i->zone))) {
6781 i->state.next = dns_hints_i_start(i, soa);
6785 } /* dns_hints_i_init() */
6788 unsigned dns_hints_grep(struct sockaddr **sa, socklen_t *sa_len, unsigned lim, struct dns_hints_i *i, struct dns_hints *H) {
6789 struct dns_hints_soa *soa;
6792 if (!(soa = dns_hints_fetch(H, i->zone)))
6797 while (i->state.next < soa->count && n < lim) {
6798 *sa = (struct sockaddr *)&soa->addrs[i->state.next].ss;
6799 *sa_len = dns_sa_len(*sa);
6805 i->state.next = dns_hints_i_skip(i->state.next, i, soa);
6809 } /* dns_hints_grep() */
6812 struct dns_packet *dns_hints_query(struct dns_hints *hints, struct dns_packet *Q, int *error_) {
6813 struct dns_packet *A, *P;
6815 char zone[DNS_D_MAXNAME + 1];
6817 struct dns_hints_i i;
6818 struct sockaddr *sa;
6822 if (!dns_rr_grep(&rr, 1, dns_rr_i_new(Q, .section = DNS_S_QUESTION), Q, &error))
6825 if (!(zlen = dns_d_expand(zone, sizeof zone, rr.dn.p, Q, &error)))
6827 else if (zlen >= sizeof zone)
6831 dns_header(P)->qr = 1;
6833 if ((error = dns_rr_copy(P, &rr, Q)))
6836 if ((error = dns_p_push(P, DNS_S_AUTHORITY, ".", strlen("."), DNS_T_NS, DNS_C_IN, 0, "hints.local.")))
6842 dns_hints_i_init(&i, hints);
6844 while (dns_hints_grep(&sa, &slen, 1, &i, hints)) {
6845 int af = sa->sa_family;
6846 int rtype = (af == AF_INET6)? DNS_T_AAAA : DNS_T_A;
6848 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))))
6851 } while ((zlen = dns_d_cleave(zone, sizeof zone, zone, zlen)));
6853 if (!(A = dns_p_copy(dns_p_make(P->end, &error), P)))
6858 error = DNS_EILLEGAL;
6863 } /* dns_hints_query() */
6866 /** ugly hack to support specifying ports other than 53 in resolv.conf. */
6867 static unsigned short dns_hints_port(struct dns_hints *hints, int af, void *addr) {
6868 struct dns_hints_soa *soa;
6871 unsigned short port;
6874 for (soa = hints->head; soa; soa = soa->next) {
6875 for (i = 0; i < soa->count; i++) {
6876 if (af != soa->addrs[i].ss.ss_family)
6879 if (!(addrsoa = dns_sa_addr(af, &soa->addrs[i].ss, &addrlen)))
6882 if (memcmp(addr, addrsoa, addrlen))
6885 port = *dns_sa_port(af, &soa->addrs[i].ss);
6887 return (port)? port : htons(53);
6892 } /* dns_hints_port() */
6895 int dns_hints_dump(struct dns_hints *hints, FILE *fp) {
6896 struct dns_hints_soa *soa;
6897 char addr[INET6_ADDRSTRLEN];
6901 for (soa = hints->head; soa; soa = soa->next) {
6902 fprintf(fp, "ZONE \"%s\"\n", soa->zone);
6904 for (i = 0; i < soa->count; i++) {
6905 af = soa->addrs[i].ss.ss_family;
6907 if ((error = dns_ntop(af, dns_sa_addr(af, &soa->addrs[i].ss, NULL), addr, sizeof addr)))
6910 fprintf(fp, "\t(%d) [%s]:%hu\n", (int)soa->addrs[i].priority, addr, ntohs(*dns_sa_port(af, &soa->addrs[i].ss)));
6915 } /* dns_hints_dump() */
6919 * C A C H E R O U T I N E S
6921 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6923 static dns_refcount_t dns_cache_acquire(struct dns_cache *cache) {
6924 return dns_atomic_fetch_add(&cache->_.refcount);
6925 } /* dns_cache_acquire() */
6928 static dns_refcount_t dns_cache_release(struct dns_cache *cache) {
6929 return dns_atomic_fetch_sub(&cache->_.refcount);
6930 } /* dns_cache_release() */
6933 static struct dns_packet *dns_cache_query(struct dns_packet *query, struct dns_cache *cache, int *error) {
6939 } /* dns_cache_query() */
6942 static int dns_cache_submit(struct dns_packet *query, struct dns_cache *cache) {
6947 } /* dns_cache_submit() */
6950 static int dns_cache_check(struct dns_cache *cache) {
6954 } /* dns_cache_check() */
6957 static struct dns_packet *dns_cache_fetch(struct dns_cache *cache, int *error) {
6962 } /* dns_cache_fetch() */
6965 static int dns_cache_pollfd(struct dns_cache *cache) {
6969 } /* dns_cache_pollfd() */
6972 static short dns_cache_events(struct dns_cache *cache) {
6976 } /* dns_cache_events() */
6979 static void dns_cache_clear(struct dns_cache *cache) {
6983 } /* dns_cache_clear() */
6986 struct dns_cache *dns_cache_init(struct dns_cache *cache) {
6987 static const struct dns_cache c_init = {
6988 .acquire = &dns_cache_acquire,
6989 .release = &dns_cache_release,
6990 .query = &dns_cache_query,
6991 .submit = &dns_cache_submit,
6992 .check = &dns_cache_check,
6993 .fetch = &dns_cache_fetch,
6994 .pollfd = &dns_cache_pollfd,
6995 .events = &dns_cache_events,
6996 .clear = &dns_cache_clear,
6997 ._ = { .refcount = 1, },
7003 } /* dns_cache_init() */
7006 void dns_cache_close(struct dns_cache *cache) {
7008 cache->release(cache);
7009 } /* dns_cache_close() */
7013 * S O C K E T R O U T I N E S
7015 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7017 static void dns_socketclose(int *fd, const struct dns_options *opts) {
7018 if (opts && opts->closefd.cb)
7019 opts->closefd.cb(fd, opts->closefd.arg);
7029 } /* dns_socketclose() */
7032 #ifndef HAVE_IOCTLSOCKET
7033 #define HAVE_IOCTLSOCKET (_WIN32 || _WIN64)
7036 #ifndef HAVE_SOCK_CLOEXEC
7037 #define HAVE_SOCK_CLOEXEC (defined SOCK_CLOEXEC)
7040 #ifndef HAVE_SOCK_NONBLOCK
7041 #define HAVE_SOCK_NONBLOCK (defined SOCK_NONBLOCK)
7044 #define DNS_SO_MAXTRY 7
7046 static int dns_socket(struct sockaddr *local, int type, int *error_) {
7047 int fd = -1, flags, error;
7053 #if HAVE_SOCK_CLOEXEC
7054 flags |= SOCK_CLOEXEC;
7056 #if HAVE_SOCK_NONBLOCK
7057 flags |= SOCK_NONBLOCK;
7059 if (-1 == (fd = socket(local->sa_family, type|flags, 0)))
7062 #if defined F_SETFD && !HAVE_SOCK_CLOEXEC
7063 if (-1 == fcntl(fd, F_SETFD, 1))
7067 #if defined O_NONBLOCK && !HAVE_SOCK_NONBLOCK
7068 if (-1 == (flags = fcntl(fd, F_GETFL)))
7070 if (-1 == fcntl(fd, F_SETFL, flags | O_NONBLOCK))
7072 #elif defined FIONBIO && HAVE_IOCTLSOCKET
7074 if (0 != ioctlsocket(fd, FIONBIO, &opt))
7078 #if defined SO_NOSIGPIPE
7079 if (type != SOCK_DGRAM) {
7080 if (0 != setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &(int){ 1 }, sizeof (int)))
7085 if (local->sa_family != AF_INET && local->sa_family != AF_INET6)
7088 if (type != SOCK_DGRAM)
7092 * FreeBSD, Linux, OpenBSD, OS X, and Solaris use random ports by
7093 * default. Though the ephemeral range is quite small on OS X
7094 * (49152-65535 on 10.10) and Linux (32768-60999 on 4.4.0, Ubuntu
7095 * Xenial). See also RFC 6056.
7097 * TODO: Optionally rely on the kernel to select a random port.
7099 if (*dns_sa_port(local->sa_family, local) == 0) {
7100 struct sockaddr_storage tmp;
7103 memcpy(&tmp, local, dns_sa_len(local));
7105 for (i = 0; i < DNS_SO_MAXTRY; i++) {
7106 port = 1025 + (dns_random() % 64510);
7108 *dns_sa_port(tmp.ss_family, &tmp) = htons(port);
7110 if (0 == bind(fd, (struct sockaddr *)&tmp, dns_sa_len(&tmp)))
7114 /* NB: continue to next bind statement */
7117 if (0 == bind(fd, local, dns_sa_len(local)))
7122 error = dns_soerr();
7125 #if (defined F_SETFD && !HAVE_SOCK_CLOEXEC) || (defined O_NONBLOCK && !HAVE_SOCK_NONBLOCK)
7127 error = dns_syerr();
7134 dns_socketclose(&fd, NULL);
7137 } /* dns_socket() */
7141 DNS_SO_UDP_INIT = 1,
7155 DNS_SO_SOCKS_HELLO_SEND,
7156 DNS_SO_SOCKS_HELLO_RECV,
7157 DNS_SO_SOCKS_AUTH_SEND,
7158 DNS_SO_SOCKS_AUTH_RECV,
7159 DNS_SO_SOCKS_REQUEST_PREPARE,
7160 DNS_SO_SOCKS_REQUEST_SEND,
7161 DNS_SO_SOCKS_REQUEST_RECV,
7162 DNS_SO_SOCKS_REQUEST_RECV_V6,
7163 DNS_SO_SOCKS_HANDSHAKE_DONE,
7167 struct dns_options opts;
7173 unsigned onum, olim;
7177 struct sockaddr_storage local, remote;
7179 struct dns_k_permutor qids;
7181 struct dns_stat stat;
7183 struct dns_trace *trace;
7186 * NOTE: dns_so_reset() zeroes everything from here down.
7191 char qname[DNS_D_MAXNAME + 1];
7193 enum dns_type qtype;
7194 enum dns_class qclass;
7196 struct dns_packet *query;
7199 /* During a SOCKS handshake the query is temporarily stored
7201 struct dns_packet *query_backup;
7203 struct dns_clock elapsed;
7205 struct dns_packet *answer;
7207 }; /* struct dns_socket */
7211 * NOTE: Actual closure delayed so that kqueue(2) and epoll(2) callers have
7212 * a chance to recognize a state change after installing a persistent event
7213 * and where sequential descriptors with the same integer value returned
7214 * from _pollfd() would be ambiguous. See dns_so_closefds().
7216 static int dns_so_closefd(struct dns_socket *so, int *fd) {
7222 if (so->opts.closefd.cb) {
7223 if ((error = so->opts.closefd.cb(fd, so->opts.closefd.arg))) {
7225 } else if (*fd == -1)
7229 if (!(so->onum < so->olim)) {
7230 unsigned olim = DNS_PP_MAX(4, so->olim * 2);
7233 if (!(old = realloc(so->old, sizeof so->old[0] * olim)))
7240 so->old[so->onum++] = *fd;
7244 } /* dns_so_closefd() */
7247 #define DNS_SO_CLOSE_UDP 0x01
7248 #define DNS_SO_CLOSE_TCP 0x02
7249 #define DNS_SO_CLOSE_OLD 0x04
7250 #define DNS_SO_CLOSE_ALL (DNS_SO_CLOSE_UDP|DNS_SO_CLOSE_TCP|DNS_SO_CLOSE_OLD)
7252 static void dns_so_closefds(struct dns_socket *so, int which) {
7253 if (DNS_SO_CLOSE_UDP & which)
7254 dns_socketclose(&so->udp, &so->opts);
7255 if (DNS_SO_CLOSE_TCP & which)
7256 dns_socketclose(&so->tcp, &so->opts);
7257 if (DNS_SO_CLOSE_OLD & which) {
7259 for (i = 0; i < so->onum; i++)
7260 dns_socketclose(&so->old[i], &so->opts);
7266 } /* dns_so_closefds() */
7269 static void dns_so_destroy(struct dns_socket *);
7271 static struct dns_socket *dns_so_init(struct dns_socket *so, const struct sockaddr *local, int type, const struct dns_options *opts, int *error) {
7272 static const struct dns_socket so_initializer = { .opts = DNS_OPTS_INITIALIZER, .udp = -1, .tcp = -1, };
7274 *so = so_initializer;
7281 memcpy(&so->local, local, dns_sa_len(local));
7283 if (-1 == (so->udp = dns_socket((struct sockaddr *)&so->local, SOCK_DGRAM, error)))
7286 dns_k_permutor_init(&so->qids, 1, 65535);
7293 } /* dns_so_init() */
7296 struct dns_socket *dns_so_open(const struct sockaddr *local, int type, const struct dns_options *opts, int *error) {
7297 struct dns_socket *so;
7299 if (!(so = malloc(sizeof *so)))
7302 if (!dns_so_init(so, local, type, opts, error))
7307 *error = dns_syerr();
7312 } /* dns_so_open() */
7315 static void dns_so_destroy(struct dns_socket *so) {
7317 dns_so_closefds(so, DNS_SO_CLOSE_ALL);
7318 dns_trace_close(so->trace);
7319 } /* dns_so_destroy() */
7322 void dns_so_close(struct dns_socket *so) {
7329 } /* dns_so_close() */
7332 void dns_so_reset(struct dns_socket *so) {
7333 dns_p_setptr(&so->answer, NULL);
7335 memset(&so->state, '\0', sizeof *so - offsetof(struct dns_socket, state));
7336 } /* dns_so_reset() */
7339 unsigned short dns_so_mkqid(struct dns_socket *so) {
7340 return dns_k_permutor_step(&so->qids);
7341 } /* dns_so_mkqid() */
7344 #define DNS_SO_MINBUF 768
7346 static int dns_so_newanswer(struct dns_socket *so, size_t len) {
7347 size_t size = offsetof(struct dns_packet, data) + DNS_PP_MAX(len, DNS_SO_MINBUF);
7350 if (!(p = realloc(so->answer, size)))
7353 so->answer = dns_p_init(p, size);
7356 } /* dns_so_newanswer() */
7359 int dns_so_submit(struct dns_socket *so, struct dns_packet *Q, struct sockaddr *host) {
7361 int error = DNS_EUNKNOWN;
7365 if ((error = dns_rr_parse(&rr, 12, Q)))
7368 if (!(so->qlen = dns_d_expand(so->qname, sizeof so->qname, rr.dn.p, Q, &error)))
7371 * NOTE: Don't bail if expansion is too long; caller may be
7372 * intentionally sending long names. However, we won't be able to
7373 * verify it on return.
7376 so->qtype = rr.type;
7377 so->qclass = rr.class;
7379 if ((error = dns_so_newanswer(so, (Q->memo.opt.maxudp)? Q->memo.opt.maxudp : DNS_SO_MINBUF)))
7382 memcpy(&so->remote, host, dns_sa_len(host));
7387 dns_begin(&so->elapsed);
7389 if (dns_header(so->query)->qid == 0)
7390 dns_header(so->query)->qid = dns_so_mkqid(so);
7392 so->qid = dns_header(so->query)->qid;
7393 so->state = (so->opts.socks_host && so->opts.socks_host->ss_family) ? DNS_SO_SOCKS_INIT :
7394 (so->type == SOCK_STREAM)? DNS_SO_TCP_INIT : DNS_SO_UDP_INIT;
7397 dns_trace_so_submit(so->trace, Q, host, 0);
7401 error = dns_syerr();
7404 dns_trace_so_submit(so->trace, Q, host, error);
7406 } /* dns_so_submit() */
7409 static int dns_so_verify(struct dns_socket *so, struct dns_packet *P) {
7410 char qname[DNS_D_MAXNAME + 1];
7418 if (so->qid != dns_header(P)->qid)
7421 if (!dns_p_count(P, DNS_S_QD))
7424 if (0 != dns_rr_parse(&rr, 12, P))
7427 if (rr.type != so->qtype || rr.class != so->qclass)
7430 if (!(qlen = dns_d_expand(qname, sizeof qname, rr.dn.p, P, &error)))
7432 else if (qlen >= sizeof qname || qlen != so->qlen)
7435 if (0 != strcasecmp(so->qname, qname))
7438 dns_trace_so_verify(so->trace, P, 0);
7442 error = DNS_EVERIFY;
7444 DNS_SHOW(P, "rejecting packet (%s)", dns_strerror(error));
7445 dns_trace_so_verify(so->trace, P, error);
7448 } /* dns_so_verify() */
7451 static _Bool dns_so_tcp_keep(struct dns_socket *so) {
7452 struct sockaddr_storage remote;
7457 if (0 != getpeername(so->tcp, (struct sockaddr *)&remote, &(socklen_t){ sizeof remote }))
7460 return 0 == dns_sa_cmp(&remote, &so->remote);
7461 } /* dns_so_tcp_keep() */
7464 /* Convenience functions for sending non-DNS data. */
7466 /* Set up everything for sending LENGTH octets. Returns the buffer
7468 static unsigned char *dns_so_tcp_send_buffer(struct dns_socket *so, size_t length) {
7469 /* Skip the length octets, we are not doing DNS. */
7471 so->query->end = length;
7472 return so->query->data;
7475 /* Set up everything for receiving LENGTH octets. */
7476 static void dns_so_tcp_recv_expect(struct dns_socket *so, size_t length) {
7477 /* Skip the length octets, we are not doing DNS. */
7482 /* Returns the buffer containing the received data. */
7483 static unsigned char *dns_so_tcp_recv_buffer(struct dns_socket *so) {
7484 return so->answer->data;
7488 #if defined __clang__
7489 #pragma clang diagnostic push
7490 #pragma clang diagnostic ignored "-Warray-bounds"
7493 static int dns_so_tcp_send(struct dns_socket *so) {
7494 unsigned char *qsrc;
7499 so->query->data[-2] = 0xff & (so->query->end >> 8);
7500 so->query->data[-1] = 0xff & (so->query->end >> 0);
7502 qend = so->query->end + 2;
7504 while (so->qout < qend) {
7505 qsrc = &so->query->data[-2] + so->qout;
7506 n = dns_send_nopipe(so->tcp, (void *)qsrc, qend - so->qout, 0, &error);
7507 dns_trace_sys_send(so->trace, so->tcp, SOCK_STREAM, qsrc, n, error);
7511 so->stat.tcp.sent.bytes += n;
7514 so->stat.tcp.sent.count++;
7517 } /* dns_so_tcp_send() */
7520 static int dns_so_tcp_recv(struct dns_socket *so) {
7521 unsigned char *asrc;
7522 size_t aend, alen, n;
7525 aend = so->alen + 2;
7527 while (so->apos < aend) {
7528 asrc = &so->answer->data[-2];
7530 n = dns_recv(so->tcp, (void *)&asrc[so->apos], aend - so->apos, 0, &error);
7531 dns_trace_sys_recv(so->trace, so->tcp, SOCK_STREAM, &asrc[so->apos], n, error);
7536 so->stat.tcp.rcvd.bytes += n;
7538 if (so->alen == 0 && so->apos >= 2) {
7539 alen = ((0xff & so->answer->data[-2]) << 8)
7540 | ((0xff & so->answer->data[-1]) << 0);
7542 if ((error = dns_so_newanswer(so, alen)))
7550 so->answer->end = so->alen;
7551 so->stat.tcp.rcvd.count++;
7554 } /* dns_so_tcp_recv() */
7557 #pragma clang diagnostic pop
7561 int dns_so_check(struct dns_socket *so) {
7564 unsigned char *buffer;
7567 switch (so->state) {
7568 case DNS_SO_UDP_INIT:
7570 case DNS_SO_UDP_CONN:
7571 error = dns_connect(so->udp, (struct sockaddr *)&so->remote, dns_sa_len(&so->remote));
7572 dns_trace_sys_connect(so->trace, so->udp, SOCK_DGRAM, (struct sockaddr *)&so->remote, error);
7577 case DNS_SO_UDP_SEND:
7578 n = dns_send(so->udp, (void *)so->query->data, so->query->end, 0, &error);
7579 dns_trace_sys_send(so->trace, so->udp, SOCK_DGRAM, so->query->data, n, error);
7583 so->stat.udp.sent.bytes += n;
7584 so->stat.udp.sent.count++;
7587 case DNS_SO_UDP_RECV:
7588 n = dns_recv(so->udp, (void *)so->answer->data, so->answer->size, 0, &error);
7589 dns_trace_sys_recv(so->trace, so->udp, SOCK_DGRAM, so->answer->data, n, error);
7593 so->answer->end = n;
7594 so->stat.udp.rcvd.bytes += n;
7595 so->stat.udp.rcvd.count++;
7597 if ((error = dns_so_verify(so, so->answer)))
7601 case DNS_SO_UDP_DONE:
7602 if (!dns_header(so->answer)->tc || so->type == SOCK_DGRAM)
7606 case DNS_SO_TCP_INIT:
7607 if (dns_so_tcp_keep(so)) {
7608 so->state = DNS_SO_TCP_SEND;
7613 if ((error = dns_so_closefd(so, &so->tcp)))
7616 if (-1 == (so->tcp = dns_socket((struct sockaddr *)&so->local, SOCK_STREAM, &error)))
7620 case DNS_SO_TCP_CONN:
7621 error = dns_connect(so->tcp, (struct sockaddr *)&so->remote, dns_sa_len(&so->remote));
7622 dns_trace_sys_connect(so->trace, so->tcp, SOCK_STREAM, (struct sockaddr *)&so->remote, error);
7623 if (error && error != DNS_EISCONN)
7627 case DNS_SO_TCP_SEND:
7628 if ((error = dns_so_tcp_send(so)))
7632 case DNS_SO_TCP_RECV:
7633 if ((error = dns_so_tcp_recv(so)))
7637 case DNS_SO_TCP_DONE:
7638 /* close unless DNS_RESCONF_TCP_ONLY (see dns_res_tcp2type) */
7639 if (so->type != SOCK_STREAM) {
7640 if ((error = dns_so_closefd(so, &so->tcp)))
7644 if ((error = dns_so_verify(so, so->answer)))
7648 case DNS_SO_SOCKS_INIT:
7649 if ((error = dns_so_closefd(so, &so->tcp)))
7652 if (-1 == (so->tcp = dns_socket((struct sockaddr *)&so->local, SOCK_STREAM, &error)))
7656 case DNS_SO_SOCKS_CONN: {
7657 unsigned char method;
7659 error = dns_connect(so->tcp, (struct sockaddr *)so->opts.socks_host, dns_sa_len(so->opts.socks_host));
7660 dns_trace_sys_connect(so->trace, so->tcp, SOCK_STREAM, (struct sockaddr *)so->opts.socks_host, error);
7661 if (error && error != DNS_EISCONN)
7664 /* We need to do a handshake with the SOCKS server,
7665 * but the query is already in the buffer. Move it
7666 * out of the way. */
7667 dns_p_movptr(&so->query_backup, &so->query);
7669 /* Create a new buffer for the handshake. */
7670 dns_p_grow(&so->query);
7672 /* Negotiate method. */
7673 buffer = dns_so_tcp_send_buffer(so, 3);
7674 buffer[0] = 5; /* RFC-1928 VER field. */
7675 buffer[1] = 1; /* NMETHODS */
7676 if (so->opts.socks_user)
7677 method = 2; /* Method: username/password authentication. */
7679 method = 0; /* Method: No authentication required. */
7684 case DNS_SO_SOCKS_HELLO_SEND:
7685 if ((error = dns_so_tcp_send(so)))
7688 dns_so_tcp_recv_expect(so, 2);
7690 case DNS_SO_SOCKS_HELLO_RECV: {
7691 unsigned char method;
7693 if ((error = dns_so_tcp_recv(so)))
7696 buffer = dns_so_tcp_recv_buffer(so);
7697 method = so->opts.socks_user ? 2 : 0;
7698 if (buffer[0] != 5 || buffer[1] != method) {
7699 /* Socks server returned wrong version or does
7700 not support our requested method. */
7701 error = ENOTSUP; /* Fixme: Is there a better errno? */
7706 /* No authentication, go ahead and send the
7708 so->state = DNS_SO_SOCKS_REQUEST_PREPARE;
7712 /* Prepare username/password sub-negotiation. */
7713 if (! so->opts.socks_password) {
7714 error = EINVAL; /* No password given. */
7717 size_t buflen, ulen, plen;
7719 ulen = strlen(so->opts.socks_user);
7720 plen = strlen(so->opts.socks_password);
7721 if (!ulen || ulen > 255 || !plen || plen > 255) {
7722 error = EINVAL; /* Credentials too long or too short. */
7726 buffer = dns_so_tcp_send_buffer(so, 3 + ulen + plen);
7727 buffer[0] = 1; /* VER of the sub-negotiation. */
7728 buffer[1] = (unsigned char) ulen;
7730 memcpy (buffer+buflen, so->opts.socks_user, ulen);
7732 buffer[buflen++] = (unsigned char) plen;
7733 memcpy (buffer+buflen, so->opts.socks_password, plen);
7738 case DNS_SO_SOCKS_AUTH_SEND:
7739 if ((error = dns_so_tcp_send(so)))
7742 /* Skip the two length octets, and receive two octets. */
7743 dns_so_tcp_recv_expect(so, 2);
7746 case DNS_SO_SOCKS_AUTH_RECV:
7747 if ((error = dns_so_tcp_recv(so)))
7750 buffer = dns_so_tcp_recv_buffer(so);
7751 if (buffer[0] != 1) {
7752 /* SOCKS server returned wrong version. */
7757 /* SOCKS server denied access. */
7763 case DNS_SO_SOCKS_REQUEST_PREPARE:
7764 /* Send request details (rfc-1928, 4). */
7765 buffer = dns_so_tcp_send_buffer(so, so->remote.ss_family == AF_INET6 ? 22 : 10);
7766 buffer[0] = 5; /* VER */
7767 buffer[1] = 1; /* CMD = CONNECT */
7768 buffer[2] = 0; /* RSV */
7769 if (so->remote.ss_family == AF_INET6) {
7770 struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)&so->remote;
7772 buffer[3] = 4; /* ATYP = IPv6 */
7773 memcpy (buffer+ 4, &addr_in6->sin6_addr.s6_addr, 16); /* DST.ADDR */
7774 memcpy (buffer+20, &addr_in6->sin6_port, 2); /* DST.PORT */
7776 struct sockaddr_in *addr_in = (struct sockaddr_in *)&so->remote;
7778 buffer[3] = 1; /* ATYP = IPv4 */
7779 memcpy (buffer+4, &addr_in->sin_addr.s_addr, 4); /* DST.ADDR */
7780 memcpy (buffer+8, &addr_in->sin_port, 2); /* DST.PORT */
7784 case DNS_SO_SOCKS_REQUEST_SEND:
7785 if ((error = dns_so_tcp_send(so)))
7788 /* Expect ten octets. This is the length of the
7789 * response assuming a IPv4 address is used. */
7790 dns_so_tcp_recv_expect(so, 10);
7792 case DNS_SO_SOCKS_REQUEST_RECV:
7793 if ((error = dns_so_tcp_recv(so)))
7796 buffer = dns_so_tcp_recv_buffer(so);
7797 if (buffer[0] != 5 || buffer[2] != 0) {
7798 /* Socks server returned wrong version or the
7799 reserved field is not zero. */
7804 switch (buffer[1]) {
7805 case 0x01: /* general SOCKS server failure. */
7808 case 0x02: /* connection not allowed by ruleset. */
7811 case 0x03: /* Network unreachable */
7812 error = ENETUNREACH;
7814 case 0x04: /* Host unreachable */
7815 error = EHOSTUNREACH;
7817 case 0x05: /* Connection refused */
7818 error = ECONNREFUSED;
7820 case 0x06: /* TTL expired */
7823 case 0x08: /* Address type not supported */
7824 error = EPROTONOSUPPORT;
7826 case 0x07: /* Command not supported */
7828 error = ENOTSUP; /* Fixme: Is there a better error? */
7834 if (buffer[3] == 1) {
7835 /* This was indeed an IPv4 address. */
7836 so->state = DNS_SO_SOCKS_HANDSHAKE_DONE;
7840 if (buffer[3] != 4) {
7845 /* Expect receive twelve octets. This accounts for
7846 * the remaining bytes assuming an IPv6 address is
7848 dns_so_tcp_recv_expect(so, 12);
7850 case DNS_SO_SOCKS_REQUEST_RECV_V6:
7851 if ((error = dns_so_tcp_recv(so)))
7855 case DNS_SO_SOCKS_HANDSHAKE_DONE:
7856 /* We have not way to store the actual address used by
7857 * the server. Then again, we don't really care. */
7859 /* Restore the query. */
7860 dns_p_movptr(&so->query, &so->query_backup);
7862 /* Reset cursors. */
7867 /* SOCKS handshake is done. Proceed with the
7869 so->state = DNS_SO_TCP_SEND;
7872 error = DNS_EUNKNOWN;
7878 DNS_CARP("discarding packet");
7884 case DNS_EINPROGRESS:
7888 #if DNS_EWOULDBLOCK != DNS_EAGAIN
7889 case DNS_EWOULDBLOCK:
7898 } /* dns_so_check() */
7901 struct dns_packet *dns_so_fetch(struct dns_socket *so, int *error) {
7902 struct dns_packet *answer;
7904 switch (so->state) {
7905 case DNS_SO_UDP_DONE:
7906 case DNS_SO_TCP_DONE:
7907 answer = so->answer;
7909 dns_trace_so_fetch(so->trace, answer, 0);
7913 *error = DNS_EUNKNOWN;
7914 dns_trace_so_fetch(so->trace, NULL, *error);
7918 } /* dns_so_fetch() */
7921 struct dns_packet *dns_so_query(struct dns_socket *so, struct dns_packet *Q, struct sockaddr *host, int *error_) {
7922 struct dns_packet *A;
7926 if ((error = dns_so_submit(so, Q, host)))
7930 if ((error = dns_so_check(so)))
7933 if (!(A = dns_so_fetch(so, &error)))
7943 } /* dns_so_query() */
7946 time_t dns_so_elapsed(struct dns_socket *so) {
7947 return dns_elapsed(&so->elapsed);
7948 } /* dns_so_elapsed() */
7951 void dns_so_clear(struct dns_socket *so) {
7952 dns_so_closefds(so, DNS_SO_CLOSE_OLD);
7953 } /* dns_so_clear() */
7956 static int dns_so_events2(struct dns_socket *so, enum dns_events type) {
7959 switch (so->state) {
7960 case DNS_SO_UDP_CONN:
7961 case DNS_SO_UDP_SEND:
7962 events |= DNS_POLLOUT;
7965 case DNS_SO_UDP_RECV:
7966 events |= DNS_POLLIN;
7969 case DNS_SO_TCP_CONN:
7970 case DNS_SO_TCP_SEND:
7971 events |= DNS_POLLOUT;
7974 case DNS_SO_TCP_RECV:
7975 events |= DNS_POLLIN;
7982 return DNS_POLL2EV(events);
7986 } /* dns_so_events2() */
7989 int dns_so_events(struct dns_socket *so) {
7990 return dns_so_events2(so, so->opts.events);
7991 } /* dns_so_events() */
7994 int dns_so_pollfd(struct dns_socket *so) {
7995 switch (so->state) {
7996 case DNS_SO_UDP_CONN:
7997 case DNS_SO_UDP_SEND:
7998 case DNS_SO_UDP_RECV:
8000 case DNS_SO_TCP_CONN:
8001 case DNS_SO_TCP_SEND:
8002 case DNS_SO_TCP_RECV:
8007 } /* dns_so_pollfd() */
8010 int dns_so_poll(struct dns_socket *so, int timeout) {
8011 return dns_poll(dns_so_pollfd(so), dns_so_events2(so, DNS_SYSPOLL), timeout);
8012 } /* dns_so_poll() */
8015 const struct dns_stat *dns_so_stat(struct dns_socket *so) {
8017 } /* dns_so_stat() */
8020 struct dns_trace *dns_so_trace(struct dns_socket *so) {
8022 } /* dns_so_trace() */
8025 void dns_so_settrace(struct dns_socket *so, struct dns_trace *trace) {
8026 struct dns_trace *otrace = so->trace;
8027 so->trace = dns_trace_acquire_p(trace);
8028 dns_trace_close(otrace);
8029 } /* dns_so_settrace() */
8033 * R E S O L V E R R O U T I N E S
8035 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8037 enum dns_res_state {
8040 DNS_R_SWITCH, /* (B)IND, (F)ILE, (C)ACHE */
8042 DNS_R_FILE, /* Lookup in local hosts database */
8044 DNS_R_CACHE, /* Lookup in application cache */
8049 DNS_R_BIND, /* Lookup in the network */
8054 DNS_R_RESOLV0_NS, /* Prologue: Setup next frame and recurse */
8055 DNS_R_RESOLV1_NS, /* Epilog: Inspect answer */
8066 }; /* enum dns_res_state */
8069 #define DNS_R_MAXDEPTH 8
8070 #define DNS_R_ENDFRAME (DNS_R_MAXDEPTH - 1)
8072 struct dns_resolver {
8073 struct dns_socket so;
8075 struct dns_resolv_conf *resconf;
8076 struct dns_hosts *hosts;
8077 struct dns_hints *hints;
8078 struct dns_cache *cache;
8079 struct dns_trace *trace;
8081 dns_atomic_t refcount;
8083 /* Reset zeroes everything below here. */
8085 char qname[DNS_D_MAXNAME + 1];
8088 enum dns_type qtype;
8089 enum dns_class qclass;
8091 struct dns_clock elapsed;
8093 dns_resconf_i_t search;
8095 struct dns_rr_i smart;
8097 struct dns_packet *nodata; /* answer if nothing better */
8101 struct dns_res_frame {
8102 enum dns_res_state state;
8105 int which; /* (B)IND, (F)ILE; index into resconf->lookup */
8110 struct dns_packet *query, *answer, *hints;
8112 struct dns_rr_i hints_i, hints_j;
8113 struct dns_rr hints_ns, ans_cname;
8114 } stack[DNS_R_MAXDEPTH];
8115 }; /* struct dns_resolver */
8118 static int dns_res_tcp2type(int tcp) {
8120 case DNS_RESCONF_TCP_ONLY:
8121 case DNS_RESCONF_TCP_SOCKS:
8123 case DNS_RESCONF_TCP_DISABLE:
8128 } /* dns_res_tcp2type() */
8130 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) {
8131 static const struct dns_resolver R_initializer
8132 = { .refcount = 1, };
8133 struct dns_resolver *R = 0;
8137 * Grab ref count early because the caller may have passed us a mortal
8138 * reference, and we want to do the right thing if we return early
8142 dns_resconf_acquire(resconf);
8144 dns_hosts_acquire(hosts);
8146 dns_hints_acquire(hints);
8148 dns_cache_acquire(cache);
8151 * Don't try to load it ourselves because a NULL object might be an
8152 * error from, say, dns_resconf_root(), and loading
8153 * dns_resconf_local() by default would create undesirable surpises.
8155 if (!resconf || !hosts || !hints) {
8161 if (!(R = malloc(sizeof *R)))
8165 type = dns_res_tcp2type(resconf->options.tcp);
8167 if (!dns_so_init(&R->so, (struct sockaddr *)&resconf->iface, type, opts, &error))
8170 R->resconf = resconf;
8177 error = dns_syerr();
8183 dns_resconf_close(resconf);
8184 dns_hosts_close(hosts);
8185 dns_hints_close(hints);
8186 dns_cache_close(cache);
8189 } /* dns_res_open() */
8192 struct dns_resolver *dns_res_stub(const struct dns_options *opts, int *error) {
8193 struct dns_resolv_conf *resconf = 0;
8194 struct dns_hosts *hosts = 0;
8195 struct dns_hints *hints = 0;
8196 struct dns_resolver *res = 0;
8198 if (!(resconf = dns_resconf_local(error)))
8201 if (!(hosts = dns_hosts_local(error)))
8204 if (!(hints = dns_hints_local(resconf, error)))
8207 if (!(res = dns_res_open(resconf, hosts, hints, NULL, opts, error)))
8211 dns_resconf_close(resconf);
8212 dns_hosts_close(hosts);
8213 dns_hints_close(hints);
8216 } /* dns_res_stub() */
8219 static void dns_res_frame_destroy(struct dns_resolver *R, struct dns_res_frame *frame) {
8222 dns_p_setptr(&frame->query, NULL);
8223 dns_p_setptr(&frame->answer, NULL);
8224 dns_p_setptr(&frame->hints, NULL);
8225 } /* dns_res_frame_destroy() */
8228 static void dns_res_frame_init(struct dns_resolver *R, struct dns_res_frame *frame) {
8229 memset(frame, '\0', sizeof *frame);
8232 * NB: Can be invoked from dns_res_open, before R->resconf has been
8236 if (!R->resconf->options.recurse)
8237 frame->qflags |= DNS_Q_RD;
8238 if (R->resconf->options.edns0)
8239 frame->qflags |= DNS_Q_EDNS0;
8241 } /* dns_res_frame_init() */
8244 static void dns_res_frame_reset(struct dns_resolver *R, struct dns_res_frame *frame) {
8245 dns_res_frame_destroy(R, frame);
8246 dns_res_frame_init(R, frame);
8247 } /* dns_res_frame_reset() */
8250 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) {
8251 struct dns_packet *P = NULL;
8253 if (!(F < endof(R->stack)))
8254 return DNS_EUNKNOWN;
8256 dns_p_movptr(&P, &F->query);
8257 dns_res_frame_reset(R, F);
8258 dns_p_movptr(&F->query, &P);
8260 return dns_q_make(&F->query, qname, qtype, qclass, F->qflags);
8261 } /* dns_res_frame_prepare() */
8264 void dns_res_reset(struct dns_resolver *R) {
8267 dns_so_reset(&R->so);
8268 dns_p_setptr(&R->nodata, NULL);
8270 for (i = 0; i < lengthof(R->stack); i++)
8271 dns_res_frame_destroy(R, &R->stack[i]);
8273 memset(&R->qname, '\0', sizeof *R - offsetof(struct dns_resolver, qname));
8275 for (i = 0; i < lengthof(R->stack); i++)
8276 dns_res_frame_init(R, &R->stack[i]);
8277 } /* dns_res_reset() */
8280 void dns_res_close(struct dns_resolver *R) {
8281 if (!R || 1 < dns_res_release(R))
8286 dns_so_destroy(&R->so);
8288 dns_hints_close(R->hints);
8289 dns_hosts_close(R->hosts);
8290 dns_resconf_close(R->resconf);
8291 dns_cache_close(R->cache);
8292 dns_trace_close(R->trace);
8295 } /* dns_res_close() */
8298 dns_refcount_t dns_res_acquire(struct dns_resolver *R) {
8299 return dns_atomic_fetch_add(&R->refcount);
8300 } /* dns_res_acquire() */
8303 dns_refcount_t dns_res_release(struct dns_resolver *R) {
8304 return dns_atomic_fetch_sub(&R->refcount);
8305 } /* dns_res_release() */
8308 struct dns_resolver *dns_res_mortal(struct dns_resolver *res) {
8310 dns_res_release(res);
8312 } /* dns_res_mortal() */
8315 static struct dns_packet *dns_res_merge(struct dns_packet *P0, struct dns_packet *P1, int *error_) {
8316 size_t bufsiz = P0->end + P1->end;
8317 struct dns_packet *P[3] = { P0, P1, 0 };
8318 struct dns_rr rr[3];
8320 enum dns_section section;
8323 if (!(P[2] = dns_p_make(bufsiz, &error)))
8326 dns_rr_foreach(&rr[0], P[0], .section = DNS_S_QD) {
8327 if ((error = dns_rr_copy(P[2], &rr[0], P[0])))
8331 for (section = DNS_S_AN; (DNS_S_ALL & section); section <<= 1) {
8332 for (i = 0; i < 2; i++) {
8333 dns_rr_foreach(&rr[i], P[i], .section = section) {
8336 dns_rr_foreach(&rr[2], P[2], .type = rr[i].type, .section = (DNS_S_ALL & ~DNS_S_QD)) {
8337 if (0 == dns_rr_cmp(&rr[i], P[i], &rr[2], P[2])) {
8344 if (copy && (error = dns_rr_copy(P[2], &rr[i], P[i]))) {
8345 if (error == DNS_ENOBUFS && bufsiz < 65535) {
8346 dns_p_setptr(&P[2], NULL);
8348 bufsiz = DNS_PP_MAX(65535, bufsiz * 2);
8356 } /* foreach(packet) */
8357 } /* foreach(section) */
8366 } /* dns_res_merge() */
8369 static struct dns_packet *dns_res_glue(struct dns_resolver *R, struct dns_packet *Q) {
8370 struct dns_packet *P = dns_p_new(512);
8371 char qname[DNS_D_MAXNAME + 1];
8373 enum dns_type qtype;
8378 if (!(qlen = dns_d_expand(qname, sizeof qname, 12, Q, &error))
8379 || qlen >= sizeof qname)
8382 if (!(qtype = dns_rr_type(12, Q)))
8385 if ((error = dns_p_push(P, DNS_S_QD, qname, strlen(qname), qtype, DNS_C_IN, 0, 0)))
8388 for (sp = 0; sp <= R->sp; sp++) {
8389 if (!R->stack[sp].answer)
8392 dns_rr_foreach(&rr, R->stack[sp].answer, .name = qname, .type = qtype, .section = (DNS_S_ALL & ~DNS_S_QD)) {
8393 rr.section = DNS_S_AN;
8395 if ((error = dns_rr_copy(P, &rr, R->stack[sp].answer)))
8400 if (dns_p_count(P, DNS_S_AN) > 0)
8403 /* Otherwise, look for a CNAME */
8404 for (sp = 0; sp <= R->sp; sp++) {
8405 if (!R->stack[sp].answer)
8408 dns_rr_foreach(&rr, R->stack[sp].answer, .name = qname, .type = DNS_T_CNAME, .section = (DNS_S_ALL & ~DNS_S_QD)) {
8409 rr.section = DNS_S_AN;
8411 if ((error = dns_rr_copy(P, &rr, R->stack[sp].answer)))
8416 if (!dns_p_count(P, DNS_S_AN))
8420 return dns_p_copy(dns_p_make(P->end, &error), P);
8421 } /* dns_res_glue() */
8425 * Sort NS records by three criteria:
8427 * 1) Whether glue is present.
8428 * 2) Whether glue record is original or of recursive lookup.
8429 * 3) Randomly shuffle records which share the above criteria.
8431 * NOTE: Assumes only NS records passed, AND ASSUMES no new NS records will
8432 * be added during an iteration.
8434 * FIXME: Only groks A glue, not AAAA glue.
8436 static int dns_res_nameserv_cmp(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) {
8437 _Bool glued[2] = { 0 };
8438 struct dns_rr x = { 0 }, y = { 0 };
8442 if (!(error = dns_ns_parse(&ns, a, P)))
8443 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);
8445 if (!(error = dns_ns_parse(&ns, b, P)))
8446 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);
8448 if ((cmp = glued[1] - glued[0])) {
8450 } else if ((cmp = (dns_rr_offset(&y) < i->args[0]) - (dns_rr_offset(&x) < i->args[0]))) {
8453 return dns_rr_i_shuffle(a, b, i, P);
8455 } /* dns_res_nameserv_cmp() */
8458 #define dgoto(sp, i) \
8459 do { R->stack[(sp)].state = (i); goto exec; } while (0)
8461 static int dns_res_exec(struct dns_resolver *R) {
8462 struct dns_res_frame *F;
8463 struct dns_packet *P;
8465 char host[DNS_D_MAXNAME + 1];
8466 char name[DNS_D_MAXNAME + 1];
8468 struct dns_cname cname;
8476 F = &R->stack[R->sp];
8483 dgoto(R->sp, DNS_R_SWITCH);
8488 if (!(F->answer = dns_res_glue(R, F->query)))
8489 dgoto(R->sp, DNS_R_SWITCH);
8491 if (!(len = dns_d_expand(u.name, sizeof u.name, 12, F->query, &error)))
8493 else if (len >= sizeof u.name)
8496 dns_rr_foreach(&rr, F->answer, .name = u.name, .type = dns_rr_type(12, F->query), .section = DNS_S_AN) {
8497 dgoto(R->sp, DNS_R_FINISH);
8500 dns_rr_foreach(&rr, F->answer, .name = u.name, .type = DNS_T_CNAME, .section = DNS_S_AN) {
8503 dgoto(R->sp, DNS_R_CNAME0_A);
8508 while (F->which < (int)sizeof R->resconf->lookup && R->resconf->lookup[F->which]) {
8509 switch (R->resconf->lookup[F->which++]) {
8511 dgoto(R->sp, DNS_R_BIND);
8513 dgoto(R->sp, DNS_R_FILE);
8516 dgoto(R->sp, DNS_R_CACHE);
8525 * FIXME: Examine more closely whether our logic is correct
8526 * and DNS_R_SERVFAIL is the correct default response.
8528 * Case 1: We got here because we never got an answer on the
8529 * wire. All queries timed-out and we reached maximum
8530 * attempts count. See DNS_R_FOREACH_NS. In that case
8531 * DNS_R_SERVFAIL is the correct state, unless we want to
8532 * return DNS_ETIMEDOUT.
8534 * Case 2: We were a stub resolver and got an unsatisfactory
8535 * answer (empty ANSWER section) which caused us to jump
8536 * back to DNS_R_SEARCH and ultimately to DNS_R_SWITCH. We
8537 * return the answer returned from the wire, which we
8538 * stashed in R->nodata.
8540 * Case 3: We reached maximum attempts count as in case #1,
8541 * but never got an authoritative response which caused us
8542 * to short-circuit. See end of DNS_R_QUERY_A case. We
8543 * should probably prepare R->nodata as in case #2.
8545 if (R->sp == 0 && R->nodata) { /* XXX: can we just return nodata regardless? */
8546 dns_p_movptr(&F->answer, &R->nodata);
8547 dgoto(R->sp, DNS_R_FINISH);
8550 dgoto(R->sp, DNS_R_SERVFAIL);
8553 if (!dns_p_setptr(&F->answer, dns_hosts_query(R->hosts, F->query, &error)))
8556 if (dns_p_count(F->answer, DNS_S_AN) > 0)
8557 dgoto(R->sp, DNS_R_FINISH);
8559 dns_p_setptr(&F->answer, NULL);
8563 while ((len = dns_resconf_search(u.name, sizeof u.name, R->qname, R->qlen, R->resconf, &R->search))) {
8564 if ((error = dns_q_make2(&F->query, u.name, len, R->qtype, R->qclass, F->qflags)))
8567 if (!dns_p_setptr(&F->answer, dns_hosts_query(R->hosts, F->query, &error)))
8570 if (dns_p_count(F->answer, DNS_S_AN) > 0)
8571 dgoto(R->sp, DNS_R_FINISH);
8573 dns_p_setptr(&F->answer, NULL);
8577 dgoto(R->sp, DNS_R_SWITCH);
8581 if (!F->query && (error = dns_q_make(&F->query, R->qname, R->qtype, R->qclass, F->qflags)))
8584 if (dns_p_setptr(&F->answer, R->cache->query(F->query, R->cache, &error))) {
8585 if (dns_p_count(F->answer, DNS_S_AN) > 0)
8586 dgoto(R->sp, DNS_R_FINISH);
8588 dns_p_setptr(&F->answer, NULL);
8590 dgoto(R->sp, DNS_R_SWITCH);
8596 if ((error = R->cache->submit(F->query, R->cache)))
8601 if ((error = R->cache->check(R->cache)))
8608 if (dns_p_setptr(&F->answer, R->cache->fetch(R->cache, &error))) {
8609 if (dns_p_count(F->answer, DNS_S_AN) > 0)
8610 dgoto(R->sp, DNS_R_FINISH);
8612 dns_p_setptr(&F->answer, NULL);
8614 dgoto(R->sp, DNS_R_SWITCH);
8618 dgoto(R->sp, DNS_R_SWITCH);
8624 dgoto(R->sp, DNS_R_HINTS);
8632 * XXX: We probably should only apply the domain search
8633 * algorithm if R->sp == 0.
8635 if (!(len = dns_resconf_search(u.name, sizeof u.name, R->qname, R->qlen, R->resconf, &R->search)))
8636 dgoto(R->sp, DNS_R_SWITCH);
8638 if ((error = dns_q_make2(&F->query, u.name, len, R->qtype, R->qclass, F->qflags)))
8643 if (!dns_p_setptr(&F->hints, dns_hints_query(R->hints, F->query, &error)))
8648 dns_rr_i_init(&F->hints_i, F->hints);
8650 F->hints_i.section = DNS_S_AUTHORITY;
8651 F->hints_i.type = DNS_T_NS;
8652 F->hints_i.sort = &dns_res_nameserv_cmp;
8653 F->hints_i.args[0] = F->hints->end;
8656 case DNS_R_FOREACH_NS:
8657 dns_rr_i_save(&F->hints_i);
8659 /* Load our next nameserver host. */
8660 if (!dns_rr_grep(&F->hints_ns, 1, &F->hints_i, F->hints, &error)) {
8661 if (++F->attempts < R->resconf->options.attempts)
8662 dgoto(R->sp, DNS_R_ITERATE);
8664 dgoto(R->sp, DNS_R_SWITCH);
8667 dns_rr_i_init(&F->hints_j, F->hints);
8669 /* Assume there are glue records */
8670 dgoto(R->sp, DNS_R_FOREACH_A);
8671 case DNS_R_RESOLV0_NS:
8672 /* Have we reached our max depth? */
8673 if (&F[1] >= endof(R->stack))
8674 dgoto(R->sp, DNS_R_FOREACH_NS);
8676 if ((error = dns_ns_parse(&u.ns, &F->hints_ns, F->hints)))
8678 if ((error = dns_res_frame_prepare(R, &F[1], u.ns.host, DNS_T_A, DNS_C_IN)))
8683 dgoto(++R->sp, DNS_R_INIT);
8684 case DNS_R_RESOLV1_NS:
8685 if (!(len = dns_d_expand(u.host, sizeof u.host, 12, F[1].query, &error)))
8687 else if (len >= sizeof u.host)
8690 dns_rr_foreach(&rr, F[1].answer, .name = u.host, .type = DNS_T_A, .section = (DNS_S_ALL & ~DNS_S_QD)) {
8691 rr.section = DNS_S_AR;
8693 if ((error = dns_rr_copy(F->hints, &rr, F[1].answer)))
8696 dns_rr_i_rewind(&F->hints_i); /* Now there's glue. */
8699 dgoto(R->sp, DNS_R_FOREACH_NS);
8700 case DNS_R_FOREACH_A: {
8702 struct sockaddr_in sin;
8705 * NOTE: Iterator initialized in DNS_R_FOREACH_NS because
8706 * this state is re-entrant, but we need to reset
8707 * .name to a valid pointer each time.
8709 if ((error = dns_ns_parse(&u.ns, &F->hints_ns, F->hints)))
8712 F->hints_j.name = u.ns.host;
8713 F->hints_j.type = DNS_T_A;
8714 F->hints_j.section = DNS_S_ALL & ~DNS_S_QD;
8716 if (!dns_rr_grep(&rr, 1, &F->hints_j, F->hints, &error)) {
8717 if (!dns_rr_i_count(&F->hints_j))
8718 dgoto(R->sp, DNS_R_RESOLV0_NS);
8720 dgoto(R->sp, DNS_R_FOREACH_NS);
8723 if ((error = dns_a_parse(&a, &rr, F->hints)))
8726 memset(&sin, '\0', sizeof sin); /* NB: silence valgrind */
8727 sin.sin_family = AF_INET;
8728 sin.sin_addr = a.addr;
8730 sin.sin_port = dns_hints_port(R->hints, AF_INET, &sin.sin_addr);
8732 sin.sin_port = htons(53);
8735 char addr[INET_ADDRSTRLEN + 1];
8736 dns_a_print(addr, sizeof addr, &a);
8737 dns_header(F->query)->qid = dns_so_mkqid(&R->so);
8738 DNS_SHOW(F->query, "ASKING: %s/%s @ DEPTH: %u)", u.ns.host, addr, R->sp);
8741 dns_trace_setcname(R->trace, u.ns.host, (struct sockaddr *)&sin);
8743 if ((error = dns_so_submit(&R->so, F->query, (struct sockaddr *)&sin)))
8749 if (dns_so_elapsed(&R->so) >= dns_resconf_timeout(R->resconf))
8750 dgoto(R->sp, DNS_R_FOREACH_A);
8752 if ((error = dns_so_check(&R->so)))
8755 if (!dns_p_setptr(&F->answer, dns_so_fetch(&R->so, &error)))
8759 DNS_SHOW(F->answer, "ANSWER @ DEPTH: %u)", R->sp);
8762 if (dns_p_rcode(F->answer) == DNS_RC_FORMERR ||
8763 dns_p_rcode(F->answer) == DNS_RC_NOTIMP ||
8764 dns_p_rcode(F->answer) == DNS_RC_BADVERS) {
8765 /* Temporarily disable EDNS0 and try again. */
8766 if (F->qflags & DNS_Q_EDNS0) {
8767 F->qflags &= ~DNS_Q_EDNS0;
8768 if ((error = dns_q_remake(&F->query, F->qflags)))
8771 dgoto(R->sp, DNS_R_FOREACH_A);
8775 if ((error = dns_rr_parse(&rr, 12, F->query)))
8778 if (!(len = dns_d_expand(u.name, sizeof u.name, rr.dn.p, F->query, &error)))
8780 else if (len >= sizeof u.name)
8783 dns_rr_foreach(&rr, F->answer, .section = DNS_S_AN, .name = u.name, .type = rr.type) {
8784 dgoto(R->sp, DNS_R_FINISH); /* Found */
8787 dns_rr_foreach(&rr, F->answer, .section = DNS_S_AN, .name = u.name, .type = DNS_T_CNAME) {
8790 dgoto(R->sp, DNS_R_CNAME0_A);
8794 * XXX: The condition here should probably check whether
8795 * R->sp == 0, because DNS_R_SEARCH runs regardless of
8796 * options.recurse. See DNS_R_BIND.
8798 if (!R->resconf->options.recurse) {
8799 /* Make first answer our tentative answer */
8801 dns_p_movptr(&R->nodata, &F->answer);
8803 dgoto(R->sp, DNS_R_SEARCH);
8806 dns_rr_foreach(&rr, F->answer, .section = DNS_S_NS, .type = DNS_T_NS) {
8807 dns_p_movptr(&F->hints, &F->answer);
8809 dgoto(R->sp, DNS_R_ITERATE);
8812 /* XXX: Should this go further up? */
8813 if (dns_header(F->answer)->aa)
8814 dgoto(R->sp, DNS_R_FINISH);
8816 /* XXX: Should we copy F->answer to R->nodata? */
8818 dgoto(R->sp, DNS_R_FOREACH_A);
8819 case DNS_R_CNAME0_A:
8820 if (&F[1] >= endof(R->stack))
8821 dgoto(R->sp, DNS_R_FINISH);
8823 if ((error = dns_cname_parse(&u.cname, &F->ans_cname, F->answer)))
8825 if ((error = dns_res_frame_prepare(R, &F[1], u.cname.host, dns_rr_type(12, F->query), DNS_C_IN)))
8830 dgoto(++R->sp, DNS_R_INIT);
8831 case DNS_R_CNAME1_A:
8832 if (!(P = dns_res_merge(F->answer, F[1].answer, &error)))
8835 dns_p_setptr(&F->answer, P);
8837 dgoto(R->sp, DNS_R_FINISH);
8842 if (!R->resconf->options.smart || R->sp > 0)
8843 dgoto(R->sp, DNS_R_DONE);
8845 R->smart.section = DNS_S_AN;
8846 R->smart.type = R->qtype;
8848 dns_rr_i_init(&R->smart, F->answer);
8851 case DNS_R_SMART0_A:
8852 if (&F[1] >= endof(R->stack))
8853 dgoto(R->sp, DNS_R_DONE);
8855 while (dns_rr_grep(&rr, 1, &R->smart, F->answer, &error)) {
8862 enum dns_type qtype;
8863 enum dns_class qclass;
8867 if ((error = dns_ns_parse(&rd.ns, &rr, F->answer)))
8876 if ((error = dns_mx_parse(&rd.mx, &rr, F->answer)))
8885 if ((error = dns_srv_parse(&rd.srv, &rr, F->answer)))
8888 qname = rd.srv.target;
8897 if ((error = dns_res_frame_prepare(R, &F[1], qname, qtype, qclass)))
8902 dgoto(++R->sp, DNS_R_INIT);
8906 * NOTE: SMTP specification says to fallback to A record.
8908 * XXX: Should we add a mock MX answer?
8910 if (R->qtype == DNS_T_MX && R->smart.state.count == 0) {
8911 if ((error = dns_res_frame_prepare(R, &F[1], R->qname, DNS_T_A, DNS_C_IN)))
8914 R->smart.state.count++;
8917 dgoto(++R->sp, DNS_R_INIT);
8920 dgoto(R->sp, DNS_R_DONE);
8921 case DNS_R_SMART1_A:
8926 * FIXME: For CNAME chains (which are typically illegal in
8927 * this context), we should rewrite the record host name
8928 * to the original smart qname. All the user cares about
8929 * is locating that A/AAAA record.
8931 dns_rr_foreach(&rr, F[1].answer, .section = DNS_S_AN, .type = DNS_T_A) {
8932 rr.section = DNS_S_AR;
8934 if (dns_rr_exists(&rr, F[1].answer, F->answer))
8937 while ((error = dns_rr_copy(F->answer, &rr, F[1].answer))) {
8938 if (error != DNS_ENOBUFS)
8940 if ((error = dns_p_grow(&F->answer)))
8945 dgoto(R->sp, DNS_R_SMART0_A);
8951 dgoto(--R->sp, F[-1].state);
8954 case DNS_R_SERVFAIL:
8955 if (!dns_p_setptr(&F->answer, dns_p_make(DNS_P_QBUFSIZ, &error)))
8958 dns_header(F->answer)->qr = 1;
8959 dns_header(F->answer)->rcode = DNS_RC_SERVFAIL;
8961 if ((error = dns_p_push(F->answer, DNS_S_QD, R->qname, strlen(R->qname), R->qtype, R->qclass, 0, 0)))
8964 dgoto(R->sp, DNS_R_DONE);
8973 error = DNS_ENOQUERY;
8977 error = DNS_ENOANSWER;
8981 error = DNS_EILLEGAL;
8986 } /* dns_res_exec() */
8991 void dns_res_clear(struct dns_resolver *R) {
8992 switch (R->stack[R->sp].state) {
8994 R->cache->clear(R->cache);
8997 dns_so_clear(&R->so);
9000 } /* dns_res_clear() */
9003 static int dns_res_events2(struct dns_resolver *R, enum dns_events type) {
9006 switch (R->stack[R->sp].state) {
9008 events = R->cache->events(R->cache);
9010 return (type == DNS_LIBEVENT)? DNS_POLL2EV(events) : events;
9012 return dns_so_events2(&R->so, type);
9014 } /* dns_res_events2() */
9017 int dns_res_events(struct dns_resolver *R) {
9018 return dns_res_events2(R, R->so.opts.events);
9019 } /* dns_res_events() */
9022 int dns_res_pollfd(struct dns_resolver *R) {
9023 switch (R->stack[R->sp].state) {
9025 return R->cache->pollfd(R->cache);
9027 return dns_so_pollfd(&R->so);
9029 } /* dns_res_pollfd() */
9032 time_t dns_res_timeout(struct dns_resolver *R) {
9035 switch (R->stack[R->sp].state) {
9037 case DNS_R_QUERY_AAAA:
9040 elapsed = dns_so_elapsed(&R->so);
9042 if (elapsed <= dns_resconf_timeout(R->resconf))
9043 return R->resconf->options.timeout - elapsed;
9051 * NOTE: We're not in a pollable state, or the user code hasn't
9052 * called dns_res_check properly. The calling code is probably
9053 * broken. Put them into a slow-burn pattern.
9056 } /* dns_res_timeout() */
9059 time_t dns_res_elapsed(struct dns_resolver *R) {
9060 return dns_elapsed(&R->elapsed);
9061 } /* dns_res_elapsed() */
9064 int dns_res_poll(struct dns_resolver *R, int timeout) {
9065 return dns_poll(dns_res_pollfd(R), dns_res_events2(R, DNS_SYSPOLL), timeout);
9066 } /* dns_res_poll() */
9069 int dns_res_submit2(struct dns_resolver *R, const char *qname, size_t qlen, enum dns_type qtype, enum dns_class qclass) {
9072 /* Don't anchor; that can conflict with searchlist generation. */
9073 dns_d_init(R->qname, sizeof R->qname, qname, (R->qlen = qlen), 0);
9078 dns_begin(&R->elapsed);
9080 dns_trace_res_submit(R->trace, R->qname, R->qtype, R->qclass, 0);
9083 } /* dns_res_submit2() */
9086 int dns_res_submit(struct dns_resolver *R, const char *qname, enum dns_type qtype, enum dns_class qclass) {
9087 return dns_res_submit2(R, qname, strlen(qname), qtype, qclass);
9088 } /* dns_res_submit() */
9091 int dns_res_check(struct dns_resolver *R) {
9094 if (R->stack[0].state != DNS_R_DONE) {
9095 if ((error = dns_res_exec(R)))
9100 } /* dns_res_check() */
9103 struct dns_packet *dns_res_fetch(struct dns_resolver *R, int *_error) {
9104 struct dns_packet *P = NULL;
9107 if (R->stack[0].state != DNS_R_DONE) {
9108 error = DNS_EUNKNOWN;
9112 if (!dns_p_movptr(&P, &R->stack[0].answer)) {
9113 error = DNS_EFETCHED;
9117 dns_trace_res_fetch(R->trace, P, 0);
9122 dns_trace_res_fetch(R->trace, NULL, error);
9124 } /* dns_res_fetch() */
9127 static struct dns_packet *dns_res_fetch_and_study(struct dns_resolver *R, int *_error) {
9128 struct dns_packet *P = NULL;
9131 if (!(P = dns_res_fetch(R, &error)))
9133 if ((error = dns_p_study(P)))
9143 } /* dns_res_fetch_and_study() */
9146 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_) {
9149 if ((error = dns_res_submit(res, qname, qtype, qclass)))
9152 while ((error = dns_res_check(res))) {
9153 if (dns_res_elapsed(res) > timeout)
9154 error = DNS_ETIMEDOUT;
9156 if (error != DNS_EAGAIN)
9159 if ((error = dns_res_poll(res, 1)))
9163 return dns_res_fetch(res, error_);
9168 } /* dns_res_query() */
9171 const struct dns_stat *dns_res_stat(struct dns_resolver *res) {
9172 return dns_so_stat(&res->so);
9173 } /* dns_res_stat() */
9176 void dns_res_sethints(struct dns_resolver *res, struct dns_hints *hints) {
9177 dns_hints_acquire(hints); /* acquire first in case same hints object */
9178 dns_hints_close(res->hints);
9180 } /* dns_res_sethints() */
9183 struct dns_trace *dns_res_trace(struct dns_resolver *res) {
9185 } /* dns_res_trace() */
9188 void dns_res_settrace(struct dns_resolver *res, struct dns_trace *trace) {
9189 struct dns_trace *otrace = res->trace;
9190 res->trace = dns_trace_acquire_p(trace);
9191 dns_trace_close(otrace);
9192 dns_so_settrace(&res->so, trace);
9193 } /* dns_res_settrace() */
9197 * A D D R I N F O R O U T I N E S
9199 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9201 struct dns_addrinfo {
9202 struct addrinfo hints;
9203 struct dns_resolver *res;
9204 struct dns_trace *trace;
9206 char qname[DNS_D_MAXNAME + 1];
9207 enum dns_type qtype;
9208 unsigned short qport, port;
9214 enum dns_type qtype;
9217 struct dns_packet *answer;
9218 struct dns_packet *glue;
9220 struct dns_rr_i i, g;
9223 char cname[DNS_D_MAXNAME + 1];
9224 char i_cname[DNS_D_MAXNAME + 1], g_cname[DNS_D_MAXNAME + 1];
9232 }; /* struct dns_addrinfo */
9235 #define DNS_AI_AFMAX 32
9236 #define DNS_AI_AF2INDEX(af) (1UL << ((af) - 1))
9238 static inline unsigned long dns_ai_af2index(int af) {
9239 dns_static_assert(dns_same_type(unsigned long, DNS_AI_AF2INDEX(1), 1), "internal type mismatch");
9240 dns_static_assert(dns_same_type(unsigned long, ((struct dns_addrinfo *)0)->af.todo, 1), "internal type mismatch");
9242 return (af > 0 && af <= DNS_AI_AFMAX)? DNS_AI_AF2INDEX(af) : 0;
9245 static int dns_ai_setaf(struct dns_addrinfo *ai, int af, int qtype) {
9247 ai->af.qtype = qtype;
9249 ai->af.todo &= ~dns_ai_af2index(af);
9252 } /* dns_ai_setaf() */
9254 #define DNS_SM_RESTORE \
9255 do { pc = 0xff & (ai->af.state >> 0); i = 0xff & (ai->af.state >> 8); } while (0)
9256 #define DNS_SM_SAVE \
9257 do { ai->af.state = ((0xff & pc) << 0) | ((0xff & i) << 8); } while (0)
9259 static int dns_ai_nextaf(struct dns_addrinfo *ai) {
9262 dns_static_assert(AF_UNSPEC == 0, "AF_UNSPEC constant not 0");
9263 dns_static_assert(AF_INET <= DNS_AI_AFMAX, "AF_INET constant too large");
9264 dns_static_assert(AF_INET6 <= DNS_AI_AFMAX, "AF_INET6 constant too large");
9270 * NB: On OpenBSD, at least, the types of entries resolved
9271 * is the intersection of the /etc/resolv.conf families and
9272 * the families permitted by the .ai_type hint. So if
9273 * /etc/resolv.conf has "family inet4" and .ai_type
9274 * is AF_INET6, then the address ::1 will return 0 entries
9275 * even if AI_NUMERICHOST is specified in .ai_flags.
9277 while (i < (int)lengthof(ai->res->resconf->family)) {
9278 int af = ai->res->resconf->family[i++];
9280 if (af == AF_UNSPEC) {
9282 } else if (af < 0 || af > DNS_AI_AFMAX) {
9284 } else if (!(DNS_AI_AF2INDEX(af) & ai->af.todo)) {
9286 } else if (af == AF_INET) {
9287 DNS_SM_YIELD(dns_ai_setaf(ai, AF_INET, DNS_T_A));
9288 } else if (af == AF_INET6) {
9289 DNS_SM_YIELD(dns_ai_setaf(ai, AF_INET6, DNS_T_AAAA));
9294 * NB: If we get here than AI_NUMERICFLAGS should be set and
9295 * order shouldn't matter.
9297 if (DNS_AI_AF2INDEX(AF_INET) & ai->af.todo)
9298 DNS_SM_YIELD(dns_ai_setaf(ai, AF_INET, DNS_T_A));
9299 if (DNS_AI_AF2INDEX(AF_INET6) & ai->af.todo)
9300 DNS_SM_YIELD(dns_ai_setaf(ai, AF_INET6, DNS_T_AAAA));
9305 return dns_ai_setaf(ai, AF_UNSPEC, 0);
9306 } /* dns_ai_nextaf() */
9308 #undef DNS_SM_RESTORE
9311 static enum dns_type dns_ai_qtype(struct dns_addrinfo *ai) {
9312 return (ai->qtype)? ai->qtype : ai->af.qtype;
9313 } /* dns_ai_qtype() */
9315 /* JW: This is not defined on mingw. */
9316 #ifndef AI_NUMERICSERV
9317 #define AI_NUMERICSERV 0
9320 static dns_error_t dns_ai_parseport(unsigned short *port, const char *serv, const struct addrinfo *hints) {
9321 const char *cp = serv;
9322 unsigned long n = 0;
9324 while (*cp >= '0' && *cp <= '9' && n < 65536) {
9330 if (cp == serv || n >= 65536)
9331 return DNS_ESERVICE;
9338 if (hints->ai_flags & AI_NUMERICSERV)
9339 return DNS_ESERVICE;
9341 /* TODO: try getaddrinfo(NULL, serv, { .ai_flags = AI_NUMERICSERV }) */
9343 return DNS_ESERVICE;
9344 } /* dns_ai_parseport() */
9347 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) {
9348 static const struct dns_addrinfo ai_initializer;
9349 struct dns_addrinfo *ai;
9353 dns_res_acquire(res);
9354 } else if (!(hints->ai_flags & AI_NUMERICHOST)) {
9356 * NOTE: it's assumed that *_error is set from a previous
9357 * API function call, such as dns_res_stub(). Should change
9358 * this semantic, but it's applied elsewhere, too.
9365 if (!(ai = malloc(sizeof *ai)))
9368 *ai = ai_initializer;
9374 if (sizeof ai->qname <= dns_strlcpy(ai->qname, host, sizeof ai->qname))
9375 { error = ENAMETOOLONG; goto error; }
9380 if (serv && (error = dns_ai_parseport(&ai->qport, serv, hints)))
9382 ai->port = ai->qport;
9385 * FIXME: If an explicit A or AAAA record type conflicts with
9386 * .ai_family or with resconf.family (i.e. AAAA specified but
9387 * AF_INET6 not in interection of .ai_family and resconf.family),
9390 switch (ai->qtype) {
9392 ai->af.todo = DNS_AI_AF2INDEX(AF_INET);
9395 ai->af.todo = DNS_AI_AF2INDEX(AF_INET6);
9397 default: /* 0, MX, SRV, etc */
9398 switch (ai->hints.ai_family) {
9400 ai->af.todo = DNS_AI_AF2INDEX(AF_INET) | DNS_AI_AF2INDEX(AF_INET6);
9403 ai->af.todo = DNS_AI_AF2INDEX(AF_INET);
9406 ai->af.todo = DNS_AI_AF2INDEX(AF_INET6);
9415 error = dns_syerr();
9423 } /* dns_ai_open() */
9426 void dns_ai_close(struct dns_addrinfo *ai) {
9430 dns_res_close(ai->res);
9431 dns_trace_close(ai->trace);
9433 if (ai->answer != ai->glue)
9434 dns_p_free(ai->glue);
9436 dns_p_free(ai->answer);
9438 } /* dns_ai_close() */
9441 static int dns_ai_setent(struct addrinfo **ent, union dns_any *any, enum dns_type type, struct dns_addrinfo *ai) {
9442 struct sockaddr *saddr;
9443 struct sockaddr_in sin;
9444 struct sockaddr_in6 sin6;
9450 saddr = memset(&sin, '\0', sizeof sin);
9452 sin.sin_family = AF_INET;
9453 sin.sin_port = htons(ai->port);
9455 memcpy(&sin.sin_addr, any, sizeof sin.sin_addr);
9459 saddr = memset(&sin6, '\0', sizeof sin6);
9461 sin6.sin6_family = AF_INET6;
9462 sin6.sin6_port = htons(ai->port);
9464 memcpy(&sin6.sin6_addr, any, sizeof sin6.sin6_addr);
9471 if (ai->hints.ai_flags & AI_CANONNAME) {
9472 cname = (*ai->cname)? ai->cname : ai->qname;
9473 clen = strlen(cname);
9479 if (!(*ent = malloc(sizeof **ent + dns_sa_len(saddr) + ((ai->hints.ai_flags & AI_CANONNAME)? clen + 1 : 0))))
9482 memset(*ent, '\0', sizeof **ent);
9484 (*ent)->ai_family = saddr->sa_family;
9485 (*ent)->ai_socktype = ai->hints.ai_socktype;
9486 (*ent)->ai_protocol = ai->hints.ai_protocol;
9488 (*ent)->ai_addr = memcpy((unsigned char *)*ent + sizeof **ent, saddr, dns_sa_len(saddr));
9489 (*ent)->ai_addrlen = dns_sa_len(saddr);
9491 if (ai->hints.ai_flags & AI_CANONNAME)
9492 (*ent)->ai_canonname = memcpy((unsigned char *)*ent + sizeof **ent + dns_sa_len(saddr), cname, clen + 1);
9497 } /* dns_ai_setent() */
9515 }; /* enum dns_ai_state */
9517 #define dns_ai_goto(which) do { ai->state = (which); goto exec; } while (0)
9519 int dns_ai_nextent(struct addrinfo **ent, struct dns_addrinfo *ai) {
9520 struct dns_packet *ans, *glue;
9522 char qname[DNS_D_MAXNAME + 1];
9531 switch (ai->state) {
9534 case DNS_AI_S_NEXTAF:
9535 if (!dns_ai_nextaf(ai))
9536 dns_ai_goto(DNS_AI_S_DONE);
9539 case DNS_AI_S_NUMERIC:
9540 if (1 == dns_inet_pton(AF_INET, ai->qname, &any.a)) {
9541 if (ai->af.atype == AF_INET) {
9542 ai->state = DNS_AI_S_NEXTAF;
9543 return dns_ai_setent(ent, &any, DNS_T_A, ai);
9545 dns_ai_goto(DNS_AI_S_NEXTAF);
9549 if (1 == dns_inet_pton(AF_INET6, ai->qname, &any.aaaa)) {
9550 if (ai->af.atype == AF_INET6) {
9551 ai->state = DNS_AI_S_NEXTAF;
9552 return dns_ai_setent(ent, &any, DNS_T_AAAA, ai);
9554 dns_ai_goto(DNS_AI_S_NEXTAF);
9558 if (ai->hints.ai_flags & AI_NUMERICHOST)
9559 dns_ai_goto(DNS_AI_S_NEXTAF);
9562 case DNS_AI_S_SUBMIT:
9565 if ((error = dns_res_submit(ai->res, ai->qname, dns_ai_qtype(ai), DNS_C_IN)))
9569 case DNS_AI_S_CHECK:
9570 if ((error = dns_res_check(ai->res)))
9574 case DNS_AI_S_FETCH:
9575 if (!(ans = dns_res_fetch_and_study(ai->res, &error)))
9577 if (ai->glue != ai->answer)
9578 dns_p_free(ai->glue);
9579 ai->glue = dns_p_movptr(&ai->answer, &ans);
9581 /* Search generator may have changed the qname. */
9582 if (!(qlen = dns_d_expand(qname, sizeof qname, 12, ai->answer, &error)))
9584 else if (qlen >= sizeof qname)
9585 return DNS_EILLEGAL;
9586 if (!dns_d_cname(ai->cname, sizeof ai->cname, qname, qlen, ai->answer, &error))
9589 dns_strlcpy(ai->i_cname, ai->cname, sizeof ai->i_cname);
9590 dns_rr_i_init(&ai->i, ai->answer);
9591 ai->i.section = DNS_S_AN;
9592 ai->i.name = ai->i_cname;
9593 ai->i.type = dns_ai_qtype(ai);
9594 ai->i.sort = &dns_rr_i_order;
9597 case DNS_AI_S_FOREACH_I:
9598 if (!dns_rr_grep(&rr, 1, &ai->i, ai->answer, &error))
9599 dns_ai_goto(DNS_AI_S_NEXTAF);
9601 if ((error = dns_any_parse(&any, &rr, ai->answer)))
9604 ai->port = ai->qport;
9609 return dns_ai_setent(ent, &any, rr.type, ai);
9611 if (!(clen = dns_any_cname(ai->cname, sizeof ai->cname, &any, rr.type)))
9612 dns_ai_goto(DNS_AI_S_FOREACH_I);
9615 * Find the "real" canonical name. Some authorities
9616 * publish aliases where an RFC defines a canonical
9617 * name. We trust that the resolver followed any
9618 * CNAME chains on it's own, regardless of whether
9619 * the "smart" option is enabled.
9621 if (!dns_d_cname(ai->cname, sizeof ai->cname, ai->cname, clen, ai->answer, &error))
9624 if (rr.type == DNS_T_SRV)
9625 ai->port = any.srv.port;
9631 case DNS_AI_S_INIT_G:
9635 case DNS_AI_S_ITERATE_G:
9636 dns_strlcpy(ai->g_cname, ai->cname, sizeof ai->g_cname);
9637 dns_rr_i_init(&ai->g, ai->glue);
9638 ai->g.section = DNS_S_ALL & ~DNS_S_QD;
9639 ai->g.name = ai->g_cname;
9640 ai->g.type = ai->af.qtype;
9643 case DNS_AI_S_FOREACH_G:
9644 if (!dns_rr_grep(&rr, 1, &ai->g, ai->glue, &error)) {
9645 if (dns_rr_i_count(&ai->g) > 0)
9646 dns_ai_goto(DNS_AI_S_FOREACH_I);
9648 dns_ai_goto(DNS_AI_S_SUBMIT_G);
9651 if ((error = dns_any_parse(&any, &rr, ai->glue)))
9654 return dns_ai_setent(ent, &any, rr.type, ai);
9655 case DNS_AI_S_SUBMIT_G:
9656 /* skip if already queried */
9657 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))
9658 dns_ai_goto(DNS_AI_S_FOREACH_I);
9659 /* skip if we recursed (CNAME chains should have been handled in the resolver) */
9660 if (++ai->g_depth > 1)
9661 dns_ai_goto(DNS_AI_S_FOREACH_I);
9663 if ((error = dns_res_submit(ai->res, ai->g.name, ai->g.type, DNS_C_IN)))
9667 case DNS_AI_S_CHECK_G:
9668 if ((error = dns_res_check(ai->res)))
9672 case DNS_AI_S_FETCH_G:
9673 if (!(ans = dns_res_fetch_and_study(ai->res, &error)))
9676 glue = dns_p_merge(ai->glue, DNS_S_ALL, ans, DNS_S_ALL, &error);
9677 dns_p_setptr(&ans, NULL);
9681 if (ai->glue != ai->answer)
9682 dns_p_free(ai->glue);
9685 if (!dns_d_cname(ai->cname, sizeof ai->cname, ai->g.name, strlen(ai->g.name), ai->glue, &error))
9686 dns_ai_goto(DNS_AI_S_FOREACH_I);
9688 dns_ai_goto(DNS_AI_S_ITERATE_G);
9691 return ENOENT; /* TODO: Just return 0 */
9692 } else if (ai->answer) {
9693 switch (dns_p_rcode(ai->answer)) {
9694 case DNS_RC_NOERROR:
9696 case DNS_RC_NXDOMAIN:
9707 } /* dns_ai_nextent() */
9710 time_t dns_ai_elapsed(struct dns_addrinfo *ai) {
9711 return (ai->res)? dns_res_elapsed(ai->res) : 0;
9712 } /* dns_ai_elapsed() */
9715 void dns_ai_clear(struct dns_addrinfo *ai) {
9717 dns_res_clear(ai->res);
9718 } /* dns_ai_clear() */
9721 int dns_ai_events(struct dns_addrinfo *ai) {
9722 return (ai->res)? dns_res_events(ai->res) : 0;
9723 } /* dns_ai_events() */
9726 int dns_ai_pollfd(struct dns_addrinfo *ai) {
9727 return (ai->res)? dns_res_pollfd(ai->res) : -1;
9728 } /* dns_ai_pollfd() */
9731 time_t dns_ai_timeout(struct dns_addrinfo *ai) {
9732 return (ai->res)? dns_res_timeout(ai->res) : 0;
9733 } /* dns_ai_timeout() */
9736 int dns_ai_poll(struct dns_addrinfo *ai, int timeout) {
9737 return (ai->res)? dns_res_poll(ai->res, timeout) : 0;
9738 } /* dns_ai_poll() */
9741 size_t dns_ai_print(void *_dst, size_t lim, struct addrinfo *ent, struct dns_addrinfo *ai) {
9742 struct dns_buf dst = DNS_B_INTO(_dst, lim);
9743 char addr[DNS_PP_MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) + 1];
9745 dns_b_puts(&dst, "[ ");
9746 dns_b_puts(&dst, ai->qname);
9747 dns_b_puts(&dst, " IN ");
9749 dns_b_puts(&dst, dns_strtype(ai->qtype));
9750 } else if (ent->ai_family == AF_INET) {
9751 dns_b_puts(&dst, dns_strtype(DNS_T_A));
9752 } else if (ent->ai_family == AF_INET6) {
9753 dns_b_puts(&dst, dns_strtype(DNS_T_AAAA));
9755 dns_b_puts(&dst, "0");
9757 dns_b_puts(&dst, " ]\n");
9759 dns_b_puts(&dst, ".ai_family = ");
9760 switch (ent->ai_family) {
9762 dns_b_puts(&dst, "AF_INET");
9765 dns_b_puts(&dst, "AF_INET6");
9768 dns_b_fmtju(&dst, ent->ai_family, 0);
9771 dns_b_putc(&dst, '\n');
9773 dns_b_puts(&dst, ".ai_socktype = ");
9774 switch (ent->ai_socktype) {
9776 dns_b_puts(&dst, "SOCK_STREAM");
9779 dns_b_puts(&dst, "SOCK_DGRAM");
9782 dns_b_fmtju(&dst, ent->ai_socktype, 0);
9785 dns_b_putc(&dst, '\n');
9787 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);
9788 dns_b_puts(&dst, ".ai_addr = [");
9789 dns_b_puts(&dst, addr);
9790 dns_b_puts(&dst, "]:");
9791 dns_b_fmtju(&dst, ntohs(*dns_sa_port(dns_sa_family(ent->ai_addr), ent->ai_addr)), 0);
9792 dns_b_putc(&dst, '\n');
9794 dns_b_puts(&dst, ".ai_canonname = ");
9795 dns_b_puts(&dst, (ent->ai_canonname)? ent->ai_canonname : "[NULL]");
9796 dns_b_putc(&dst, '\n');
9798 return dns_b_strllen(&dst);
9799 } /* dns_ai_print() */
9802 const struct dns_stat *dns_ai_stat(struct dns_addrinfo *ai) {
9803 return (ai->res)? dns_res_stat(ai->res) : &ai->st;
9804 } /* dns_ai_stat() */
9807 struct dns_trace *dns_ai_trace(struct dns_addrinfo *ai) {
9809 } /* dns_ai_trace() */
9812 void dns_ai_settrace(struct dns_addrinfo *ai, struct dns_trace *trace) {
9813 struct dns_trace *otrace = ai->trace;
9814 ai->trace = dns_trace_acquire_p(trace);
9815 dns_trace_close(otrace);
9817 dns_res_settrace(ai->res, trace);
9818 } /* dns_ai_settrace() */
9822 * M I S C E L L A N E O U S R O U T I N E S
9824 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9826 static const struct {
9828 enum dns_section type;
9829 } dns_sections[] = {
9830 { "QUESTION", DNS_S_QUESTION },
9831 { "QD", DNS_S_QUESTION },
9832 { "ANSWER", DNS_S_ANSWER },
9833 { "AN", DNS_S_ANSWER },
9834 { "AUTHORITY", DNS_S_AUTHORITY },
9835 { "NS", DNS_S_AUTHORITY },
9836 { "ADDITIONAL", DNS_S_ADDITIONAL },
9837 { "AR", DNS_S_ADDITIONAL },
9840 const char *(dns_strsection)(enum dns_section section, void *_dst, size_t lim) {
9841 struct dns_buf dst = DNS_B_INTO(_dst, lim);
9844 for (i = 0; i < lengthof(dns_sections); i++) {
9845 if (dns_sections[i].type & section) {
9846 dns_b_puts(&dst, dns_sections[i].name);
9847 section &= ~dns_sections[i].type;
9849 dns_b_putc(&dst, '|');
9853 if (section || dst.p == dst.base)
9854 dns_b_fmtju(&dst, (0xffff & section), 0);
9856 return dns_b_tostring(&dst);
9857 } /* dns_strsection() */
9860 enum dns_section dns_isection(const char *src) {
9861 enum dns_section section = 0;
9866 dns_strlcpy(sbuf, src, sizeof sbuf);
9869 while ((name = dns_strsep(&next, "|+, \t"))) {
9870 for (i = 0; i < lengthof(dns_sections); i++) {
9871 if (!strcasecmp(dns_sections[i].name, name)) {
9872 section |= dns_sections[i].type;
9879 } /* dns_isection() */
9882 static const struct {
9884 enum dns_class type;
9889 const char *(dns_strclass)(enum dns_class type, void *_dst, size_t lim) {
9890 struct dns_buf dst = DNS_B_INTO(_dst, lim);
9893 for (i = 0; i < lengthof(dns_classes); i++) {
9894 if (dns_classes[i].type == type) {
9895 dns_b_puts(&dst, dns_classes[i].name);
9900 if (dst.p == dst.base)
9901 dns_b_fmtju(&dst, (0xffff & type), 0);
9903 return dns_b_tostring(&dst);
9904 } /* dns_strclass() */
9907 enum dns_class dns_iclass(const char *name) {
9910 for (i = 0; i < lengthof(dns_classes); i++) {
9911 if (!strcasecmp(dns_classes[i].name, name))
9912 return dns_classes[i].type;
9916 while (dns_isdigit(*name)) {
9918 class += *name++ - '0';
9921 return DNS_PP_MIN(class, 0xffff);
9922 } /* dns_iclass() */
9925 const char *(dns_strtype)(enum dns_type type, void *_dst, size_t lim) {
9926 struct dns_buf dst = DNS_B_INTO(_dst, lim);
9929 for (i = 0; i < lengthof(dns_rrtypes); i++) {
9930 if (dns_rrtypes[i].type == type) {
9931 dns_b_puts(&dst, dns_rrtypes[i].name);
9936 if (dst.p == dst.base)
9937 dns_b_fmtju(&dst, (0xffff & type), 0);
9939 return dns_b_tostring(&dst);
9940 } /* dns_strtype() */
9943 enum dns_type dns_itype(const char *name) {
9946 for (i = 0; i < lengthof(dns_rrtypes); i++) {
9947 if (!strcasecmp(dns_rrtypes[i].name, name))
9948 return dns_rrtypes[i].type;
9952 while (dns_isdigit(*name)) {
9954 type += *name++ - '0';
9957 return DNS_PP_MIN(type, 0xffff);
9961 static char dns_opcodes[16][16] = {
9962 [DNS_OP_QUERY] = "QUERY",
9963 [DNS_OP_IQUERY] = "IQUERY",
9964 [DNS_OP_STATUS] = "STATUS",
9965 [DNS_OP_NOTIFY] = "NOTIFY",
9966 [DNS_OP_UPDATE] = "UPDATE",
9969 static const char *dns__strcode(int code, volatile char *dst, size_t lim) {
9975 dns_b_fmtju(dns_b_into(&tmp, _tmp, DNS_PP_MIN(sizeof _tmp, lim - 1)), code, 0);
9977 /* copy downwards so first byte is copied last (see below) */
9978 p = (size_t)(tmp.p - tmp.base);
9983 return (const char *)dst;
9986 const char *dns_stropcode(enum dns_opcode opcode) {
9987 opcode = (unsigned)opcode % lengthof(dns_opcodes);
9989 if ('\0' == dns_opcodes[opcode][0])
9990 return dns__strcode(opcode, dns_opcodes[opcode], sizeof dns_opcodes[opcode]);
9992 return dns_opcodes[opcode];
9993 } /* dns_stropcode() */
9996 enum dns_opcode dns_iopcode(const char *name) {
9999 for (opcode = 0; opcode < lengthof(dns_opcodes); opcode++) {
10000 if (!strcasecmp(name, dns_opcodes[opcode]))
10005 while (dns_isdigit(*name)) {
10007 opcode += *name++ - '0';
10010 return DNS_PP_MIN(opcode, 0x0f);
10011 } /* dns_iopcode() */
10014 static char dns_rcodes[32][16] = {
10015 [DNS_RC_NOERROR] = "NOERROR",
10016 [DNS_RC_FORMERR] = "FORMERR",
10017 [DNS_RC_SERVFAIL] = "SERVFAIL",
10018 [DNS_RC_NXDOMAIN] = "NXDOMAIN",
10019 [DNS_RC_NOTIMP] = "NOTIMP",
10020 [DNS_RC_REFUSED] = "REFUSED",
10021 [DNS_RC_YXDOMAIN] = "YXDOMAIN",
10022 [DNS_RC_YXRRSET] = "YXRRSET",
10023 [DNS_RC_NXRRSET] = "NXRRSET",
10024 [DNS_RC_NOTAUTH] = "NOTAUTH",
10025 [DNS_RC_NOTZONE] = "NOTZONE",
10026 /* EDNS(0) extended RCODEs ... */
10027 [DNS_RC_BADVERS] = "BADVERS",
10030 const char *dns_strrcode(enum dns_rcode rcode) {
10031 rcode = (unsigned)rcode % lengthof(dns_rcodes);
10033 if ('\0' == dns_rcodes[rcode][0])
10034 return dns__strcode(rcode, dns_rcodes[rcode], sizeof dns_rcodes[rcode]);
10036 return dns_rcodes[rcode];
10037 } /* dns_strrcode() */
10040 enum dns_rcode dns_ircode(const char *name) {
10043 for (rcode = 0; rcode < lengthof(dns_rcodes); rcode++) {
10044 if (!strcasecmp(name, dns_rcodes[rcode]))
10049 while (dns_isdigit(*name)) {
10051 rcode += *name++ - '0';
10054 return DNS_PP_MIN(rcode, 0xfff);
10055 } /* dns_ircode() */
10060 * 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
10062 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
10065 #include <stdarg.h>
10066 #include <stdlib.h>
10072 #include <getopt.h>
10082 const char *path[8];
10084 } resconf, nssconf, hosts, cache;
10087 enum dns_type qtype;
10096 struct dns_resolv_conf *resconf;
10097 struct dns_hosts *hosts;
10098 struct dns_trace *trace;
10101 struct sockaddr_storage socks_host;
10102 const char *socks_user;
10103 const char *socks_password;
10105 .sort = &dns_rr_i_packet,
10109 static void hexdump(const unsigned char *src, size_t len, FILE *fp) {
10110 struct dns_hxd_lines_i lines = { 0 };
10113 while (dns_hxd_lines(line, sizeof line, src, len, &lines)) {
10119 DNS_NORETURN static void panic(const char *fmt, ...) {
10125 vfprintf(stderr, fmt, ap);
10127 exit(EXIT_FAILURE);
10129 verrx(EXIT_FAILURE, fmt, ap);
10133 #define panic_(fn, ln, fmt, ...) \
10134 panic(fmt "%0s", (fn), (ln), __VA_ARGS__)
10135 #define panic(...) \
10136 panic_(__func__, __LINE__, "(%s:%d) " __VA_ARGS__, "")
10139 static void *grow(unsigned char *p, size_t size) {
10142 if (!(tmp = realloc(p, size)))
10143 panic("realloc(%"PRIuZ"): %s", size, dns_strerror(errno));
10149 static size_t add(size_t a, size_t b) {
10151 panic("%"PRIuZ" + %"PRIuZ": integer overflow", a, b);
10157 static size_t append(unsigned char **dst, size_t osize, const void *src, size_t len) {
10158 size_t size = add(osize, len);
10160 *dst = grow(*dst, size);
10161 memcpy(*dst + osize, src, len);
10167 static size_t slurp(unsigned char **dst, size_t osize, FILE *fp, const char *path) {
10168 size_t size = osize;
10169 unsigned char buf[1024];
10172 while ((count = fread(buf, 1, sizeof buf, fp)))
10173 size = append(dst, size, buf, count);
10176 panic("%s: %s", path, dns_strerror(errno));
10182 static struct dns_resolv_conf *resconf(void) {
10183 struct dns_resolv_conf **resconf = &MAIN.memo.resconf;
10191 if (!(*resconf = dns_resconf_open(&error)))
10192 panic("dns_resconf_open: %s", dns_strerror(error));
10194 if (!MAIN.resconf.count)
10195 MAIN.resconf.path[MAIN.resconf.count++] = "/etc/resolv.conf";
10197 for (i = 0; i < MAIN.resconf.count; i++) {
10198 path = MAIN.resconf.path[i];
10200 if (0 == strcmp(path, "-"))
10201 error = dns_resconf_loadfile(*resconf, stdin);
10203 error = dns_resconf_loadpath(*resconf, path);
10206 panic("%s: %s", path, dns_strerror(error));
10209 for (i = 0; i < MAIN.nssconf.count; i++) {
10210 path = MAIN.nssconf.path[i];
10212 if (0 == strcmp(path, "-"))
10213 error = dns_nssconf_loadfile(*resconf, stdin);
10215 error = dns_nssconf_loadpath(*resconf, path);
10218 panic("%s: %s", path, dns_strerror(error));
10221 if (!MAIN.nssconf.count) {
10222 path = "/etc/nsswitch.conf";
10224 if (!(error = dns_nssconf_loadpath(*resconf, path)))
10225 MAIN.nssconf.path[MAIN.nssconf.count++] = path;
10226 else if (error != ENOENT)
10227 panic("%s: %s", path, dns_strerror(error));
10234 static struct dns_hosts *hosts(void) {
10235 struct dns_hosts **hosts = &MAIN.memo.hosts;
10243 if (!MAIN.hosts.count) {
10244 MAIN.hosts.path[MAIN.hosts.count++] = "/etc/hosts";
10246 /* Explicitly test dns_hosts_local() */
10247 if (!(*hosts = dns_hosts_local(&error)))
10248 panic("%s: %s", "/etc/hosts", dns_strerror(error));
10253 if (!(*hosts = dns_hosts_open(&error)))
10254 panic("dns_hosts_open: %s", dns_strerror(error));
10256 for (i = 0; i < MAIN.hosts.count; i++) {
10257 path = MAIN.hosts.path[i];
10259 if (0 == strcmp(path, "-"))
10260 error = dns_hosts_loadfile(*hosts, stdin);
10262 error = dns_hosts_loadpath(*hosts, path);
10265 panic("%s: %s", path, dns_strerror(error));
10275 static struct dns_cache *cache(void) {
10276 static struct cache *cache;
10282 return cache_resi(cache);
10283 if (!MAIN.cache.count)
10286 if (!(cache = cache_open(&error)))
10287 panic("%s: %s", MAIN.cache.path[0], dns_strerror(error));
10289 for (i = 0; i < MAIN.cache.count; i++) {
10290 path = MAIN.cache.path[i];
10292 if (!strcmp(path, "-")) {
10293 if ((error = cache_loadfile(cache, stdin, NULL, 0)))
10294 panic("%s: %s", path, dns_strerror(error));
10295 } else if ((error = cache_loadpath(cache, path, NULL, 0)))
10296 panic("%s: %s", path, dns_strerror(error));
10299 return cache_resi(cache);
10302 static struct dns_cache *cache(void) { return NULL; }
10306 static struct dns_trace *trace(const char *mode) {
10307 static char omode[64] = "";
10308 struct dns_trace **trace = &MAIN.memo.trace;
10312 if (*trace && 0 == strcmp(omode, mode))
10317 if (!(fp = fopen(MAIN.trace, mode)))
10318 panic("%s: %s", MAIN.trace, strerror(errno));
10319 dns_trace_close(*trace);
10320 if (!(*trace = dns_trace_open(fp, &error)))
10321 panic("%s: %s", MAIN.trace, dns_strerror(error));
10322 dns_strlcpy(omode, mode, sizeof omode);
10328 static void print_packet(struct dns_packet *P, FILE *fp) {
10329 dns_p_dump3(P, dns_rr_i_new(P, .sort = MAIN.sort), fp);
10331 if (MAIN.verbose > 2)
10332 hexdump(P->data, P->end, fp);
10333 } /* print_packet() */
10336 static int parse_packet(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
10337 struct dns_packet *P = dns_p_new(512);
10338 struct dns_packet *Q = dns_p_new(512);
10339 enum dns_section section;
10343 char pretty[sizeof any * 2];
10346 P->end = fread(P->data, 1, P->size, stdin);
10348 fputs(";; [HEADER]\n", stdout);
10349 fprintf(stdout, ";; qr : %s(%d)\n", (dns_header(P)->qr)? "RESPONSE" : "QUERY", dns_header(P)->qr);
10350 fprintf(stdout, ";; opcode : %s(%d)\n", dns_stropcode(dns_header(P)->opcode), dns_header(P)->opcode);
10351 fprintf(stdout, ";; aa : %s(%d)\n", (dns_header(P)->aa)? "AUTHORITATIVE" : "NON-AUTHORITATIVE", dns_header(P)->aa);
10352 fprintf(stdout, ";; tc : %s(%d)\n", (dns_header(P)->tc)? "TRUNCATED" : "NOT-TRUNCATED", dns_header(P)->tc);
10353 fprintf(stdout, ";; rd : %s(%d)\n", (dns_header(P)->rd)? "RECURSION-DESIRED" : "RECURSION-NOT-DESIRED", dns_header(P)->rd);
10354 fprintf(stdout, ";; ra : %s(%d)\n", (dns_header(P)->ra)? "RECURSION-ALLOWED" : "RECURSION-NOT-ALLOWED", dns_header(P)->ra);
10355 fprintf(stdout, ";; rcode : %s(%d)\n", dns_strrcode(dns_p_rcode(P)), dns_p_rcode(P));
10359 dns_rr_foreach(&rr, P, .sort = MAIN.sort) {
10360 if (section != rr.section)
10361 fprintf(stdout, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(P, rr.section));
10363 if ((len = dns_rr_print(pretty, sizeof pretty, &rr, P, &error)))
10364 fprintf(stdout, "%s\n", pretty);
10366 dns_rr_copy(Q, &rr, P);
10368 section = rr.section;
10371 fputs("; ; ; ; ; ; ; ;\n\n", stdout);
10376 dns_rr_foreach(&rr, Q, .name = "ns8.yahoo.com.") {
10378 struct dns_rr rrset[32];
10379 struct dns_rr_i *rri = dns_rr_i_new(Q, .name = dns_d_new("ns8.yahoo.com", DNS_D_ANCHOR), .sort = MAIN.sort);
10380 unsigned rrcount = dns_rr_grep(rrset, lengthof(rrset), rri, Q, &error);
10382 for (unsigned i = 0; i < rrcount; i++) {
10385 if (section != rr.section)
10386 fprintf(stdout, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(Q, rr.section));
10388 if ((len = dns_rr_print(pretty, sizeof pretty, &rr, Q, &error)))
10389 fprintf(stdout, "%s\n", pretty);
10391 section = rr.section;
10394 if (MAIN.verbose > 1) {
10395 fprintf(stderr, "orig:%"PRIuZ"\n", P->end);
10396 hexdump(P->data, P->end, stdout);
10398 fprintf(stderr, "copy:%"PRIuZ"\n", Q->end);
10399 hexdump(Q->data, Q->end, stdout);
10403 } /* parse_packet() */
10406 static int parse_domain(int argc, char *argv[]) {
10409 dn = (argc > 1)? argv[1] : "f.l.google.com";
10411 printf("[%s]\n", dn);
10413 dn = dns_d_new(dn);
10417 } while (dns_d_cleave(dn, strlen(dn) + 1, dn, strlen(dn)));
10420 } /* parse_domain() */
10423 static int trim_domain(int argc, char **argv) {
10424 for (argc--, argv++; argc > 0; argc--, argv++) {
10425 char name[DNS_D_MAXNAME + 1];
10427 dns_d_trim(name, sizeof name, *argv, strlen(*argv), DNS_D_ANCHOR);
10433 } /* trim_domain() */
10436 static int expand_domain(int argc, char *argv[]) {
10437 unsigned short rp = 0;
10438 unsigned char *src = NULL;
10439 unsigned char *dst;
10440 struct dns_packet *pkt;
10441 size_t lim = 0, len;
10445 rp = atoi(argv[1]);
10447 len = slurp(&src, 0, stdin, "-");
10449 if (!(pkt = dns_p_make(len, &error)))
10450 panic("malloc(%"PRIuZ"): %s", len, dns_strerror(error));
10452 memcpy(pkt->data, src, len);
10456 dst = grow(NULL, lim);
10458 while (lim <= (len = dns_d_expand(dst, lim, rp, pkt, &error))) {
10460 dst = grow(dst, lim);
10464 panic("expand: %s", dns_strerror(error));
10466 fwrite(dst, 1, len, stdout);
10474 } /* expand_domain() */
10477 static int show_resconf(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
10480 resconf(); /* load it */
10482 fputs("; SOURCES\n", stdout);
10484 for (i = 0; i < MAIN.resconf.count; i++)
10485 fprintf(stdout, "; %s\n", MAIN.resconf.path[i]);
10487 for (i = 0; i < MAIN.nssconf.count; i++)
10488 fprintf(stdout, "; %s\n", MAIN.nssconf.path[i]);
10490 fputs(";\n", stdout);
10492 dns_resconf_dump(resconf(), stdout);
10495 } /* show_resconf() */
10498 static int show_nssconf(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
10503 fputs("# SOURCES\n", stdout);
10505 for (i = 0; i < MAIN.resconf.count; i++)
10506 fprintf(stdout, "# %s\n", MAIN.resconf.path[i]);
10508 for (i = 0; i < MAIN.nssconf.count; i++)
10509 fprintf(stdout, "# %s\n", MAIN.nssconf.path[i]);
10511 fputs("#\n", stdout);
10513 dns_nssconf_dump(resconf(), stdout);
10516 } /* show_nssconf() */
10519 static int show_hosts(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
10524 fputs("# SOURCES\n", stdout);
10526 for (i = 0; i < MAIN.hosts.count; i++)
10527 fprintf(stdout, "# %s\n", MAIN.hosts.path[i]);
10529 fputs("#\n", stdout);
10531 dns_hosts_dump(hosts(), stdout);
10534 } /* show_hosts() */
10537 static int query_hosts(int argc, char *argv[]) {
10538 struct dns_packet *Q = dns_p_new(512);
10539 struct dns_packet *A;
10540 char qname[DNS_D_MAXNAME + 1];
10545 MAIN.qname = (argc > 1)? argv[1] : "localhost";
10547 MAIN.qtype = DNS_T_A;
10551 if (MAIN.qtype == DNS_T_PTR && !strstr(MAIN.qname, "arpa")) {
10552 union { struct in_addr a; struct in6_addr a6; } addr;
10553 int af = (strchr(MAIN.qname, ':'))? AF_INET6 : AF_INET;
10555 if ((error = dns_pton(af, MAIN.qname, &addr)))
10556 panic("%s: %s", MAIN.qname, dns_strerror(error));
10558 qlen = dns_ptr_qname(qname, sizeof qname, af, &addr);
10560 qlen = dns_strlcpy(qname, MAIN.qname, sizeof qname);
10562 if ((error = dns_p_push(Q, DNS_S_QD, qname, qlen, MAIN.qtype, DNS_C_IN, 0, 0)))
10563 panic("%s: %s", qname, dns_strerror(error));
10565 if (!(A = dns_hosts_query(hosts(), Q, &error)))
10566 panic("%s: %s", qname, dns_strerror(error));
10568 print_packet(A, stdout);
10573 } /* query_hosts() */
10576 static int search_list(int argc, char *argv[]) {
10577 const char *qname = (argc > 1)? argv[1] : "f.l.google.com";
10578 unsigned long i = 0;
10579 char name[DNS_D_MAXNAME + 1];
10581 printf("[%s]\n", qname);
10583 while (dns_resconf_search(name, sizeof name, qname, strlen(qname), resconf(), &i))
10587 } /* search_list() */
10590 static int permute_set(int argc, char *argv[]) {
10591 unsigned lo, hi, i;
10592 struct dns_k_permutor p;
10594 hi = (--argc > 0)? atoi(argv[argc]) : 8;
10595 lo = (--argc > 0)? atoi(argv[argc]) : 0;
10597 fprintf(stderr, "[%u .. %u]\n", lo, hi);
10599 dns_k_permutor_init(&p, lo, hi);
10601 for (i = lo; i <= hi; i++)
10602 fprintf(stdout, "%u\n", dns_k_permutor_step(&p));
10603 // printf("%u -> %u -> %u\n", i, dns_k_permutor_E(&p, i), dns_k_permutor_D(&p, dns_k_permutor_E(&p, i)));
10606 } /* permute_set() */
10609 static int shuffle_16(int argc, char *argv[]) {
10613 n = 0xffff & atoi(argv[argc]);
10614 r = (--argc > 0)? (unsigned)atoi(argv[argc]) : dns_random();
10616 fprintf(stdout, "%hu\n", dns_k_shuffle16(n, r));
10620 for (n = 0; n < 65536; n++)
10621 fprintf(stdout, "%hu\n", dns_k_shuffle16(n, r));
10625 } /* shuffle_16() */
10628 static int dump_random(int argc, char *argv[]) {
10629 unsigned char b[32];
10630 unsigned i, j, n, r;
10632 n = (argc > 1)? atoi(argv[1]) : 32;
10640 for (j = 0; j < sizeof r && i < n && i < sizeof b; i++, j++) {
10644 } while (i < n && i < sizeof b);
10646 hexdump(b, i, stdout);
10652 } /* dump_random() */
10655 static int send_query(int argc, char *argv[]) {
10656 struct dns_packet *A, *Q = dns_p_new(512);
10657 char host[INET6_ADDRSTRLEN + 1];
10658 struct sockaddr_storage ss;
10659 struct dns_socket *so;
10663 ss.ss_family = (strchr(argv[1], ':'))? AF_INET6 : AF_INET;
10665 if ((error = dns_pton(ss.ss_family, argv[1], dns_sa_addr(ss.ss_family, &ss, NULL))))
10666 panic("%s: %s", argv[1], dns_strerror(error));
10668 *dns_sa_port(ss.ss_family, &ss) = htons(53);
10670 memcpy(&ss, &resconf()->nameserver[0], dns_sa_len(&resconf()->nameserver[0]));
10672 if (!dns_inet_ntop(ss.ss_family, dns_sa_addr(ss.ss_family, &ss, NULL), host, sizeof host))
10673 panic("bad host address, or none provided");
10676 MAIN.qname = "ipv6.google.com";
10678 MAIN.qtype = DNS_T_AAAA;
10680 if ((error = dns_p_push(Q, DNS_S_QD, MAIN.qname, strlen(MAIN.qname), MAIN.qtype, DNS_C_IN, 0, 0)))
10681 panic("dns_p_push: %s", dns_strerror(error));
10683 dns_header(Q)->rd = 1;
10685 if (strstr(argv[0], "udp"))
10687 else if (strstr(argv[0], "tcp"))
10688 type = SOCK_STREAM;
10690 type = dns_res_tcp2type(resconf()->options.tcp);
10692 fprintf(stderr, "querying %s for %s IN %s\n", host, MAIN.qname, dns_strtype(MAIN.qtype));
10694 if (!(so = dns_so_open((struct sockaddr *)&resconf()->iface, type, dns_opts(), &error)))
10695 panic("dns_so_open: %s", dns_strerror(error));
10697 while (!(A = dns_so_query(so, Q, (struct sockaddr *)&ss, &error))) {
10698 if (error != DNS_EAGAIN)
10699 panic("dns_so_query: %s (%d)", dns_strerror(error), error);
10700 if (dns_so_elapsed(so) > 10)
10701 panic("query timed-out");
10703 dns_so_poll(so, 1);
10706 print_packet(A, stdout);
10711 } /* send_query() */
10714 static int print_arpa(int argc, char *argv[]) {
10715 const char *ip = (argc > 1)? argv[1] : "::1";
10716 int af = (strchr(ip, ':'))? AF_INET6 : AF_INET;
10717 union { struct in_addr a4; struct in6_addr a6; } addr;
10718 char host[DNS_D_MAXNAME + 1];
10720 if (1 != dns_inet_pton(af, ip, &addr) || 0 == dns_ptr_qname(host, sizeof host, af, &addr))
10721 panic("%s: invalid address", ip);
10723 fprintf(stdout, "%s\n", host);
10726 } /* print_arpa() */
10729 static int show_hints(int argc, char *argv[]) {
10730 struct dns_hints *(*load)(struct dns_resolv_conf *, int *);
10731 const char *which, *how, *who;
10732 struct dns_hints *hints;
10735 which = (argc > 1)? argv[1] : "local";
10736 how = (argc > 2)? argv[2] : "plain";
10737 who = (argc > 3)? argv[3] : "google.com";
10739 load = (0 == strcmp(which, "local"))
10743 if (!(hints = load(resconf(), &error)))
10744 panic("%s: %s", argv[0], dns_strerror(error));
10746 if (0 == strcmp(how, "plain")) {
10747 dns_hints_dump(hints, stdout);
10749 struct dns_packet *query, *answer;
10751 query = dns_p_new(512);
10753 if ((error = dns_p_push(query, DNS_S_QUESTION, who, strlen(who), DNS_T_A, DNS_C_IN, 0, 0)))
10754 panic("%s: %s", who, dns_strerror(error));
10756 if (!(answer = dns_hints_query(hints, query, &error)))
10757 panic("%s: %s", who, dns_strerror(error));
10759 print_packet(answer, stdout);
10764 dns_hints_close(hints);
10767 } /* show_hints() */
10770 static int resolve_query(int argc DNS_NOTUSED, char *argv[]) {
10771 _Bool recurse = !!strstr(argv[0], "recurse");
10772 struct dns_hints *(*hints)() = (recurse)? &dns_hints_root : &dns_hints_local;
10773 struct dns_resolver *R;
10774 struct dns_packet *ans;
10775 const struct dns_stat *st;
10779 MAIN.qname = "www.google.com";
10781 MAIN.qtype = DNS_T_A;
10783 resconf()->options.recurse = recurse;
10785 if (!(R = dns_res_open(resconf(), hosts(), dns_hints_mortal(hints(resconf(), &error)), cache(),
10786 dns_opts(.socks_host=&MAIN.socks_host,
10787 .socks_user=MAIN.socks_user,
10788 .socks_password=MAIN.socks_password), &error)))
10789 panic("%s: %s", MAIN.qname, dns_strerror(error));
10791 dns_res_settrace(R, trace("w+b"));
10793 if ((error = dns_res_submit(R, MAIN.qname, MAIN.qtype, DNS_C_IN)))
10794 panic("%s: %s", MAIN.qname, dns_strerror(error));
10796 while ((error = dns_res_check(R))) {
10797 if (error != DNS_EAGAIN)
10798 panic("dns_res_check: %s (%d)", dns_strerror(error), error);
10799 if (dns_res_elapsed(R) > 30)
10800 panic("query timed-out");
10802 dns_res_poll(R, 1);
10805 ans = dns_res_fetch(R, &error);
10806 print_packet(ans, stdout);
10809 st = dns_res_stat(R);
10811 printf(";; queries: %"PRIuZ"\n", st->queries);
10812 printf(";; udp sent: %"PRIuZ" in %"PRIuZ" bytes\n", st->udp.sent.count, st->udp.sent.bytes);
10813 printf(";; udp rcvd: %"PRIuZ" in %"PRIuZ" bytes\n", st->udp.rcvd.count, st->udp.rcvd.bytes);
10814 printf(";; tcp sent: %"PRIuZ" in %"PRIuZ" bytes\n", st->tcp.sent.count, st->tcp.sent.bytes);
10815 printf(";; tcp rcvd: %"PRIuZ" in %"PRIuZ" bytes\n", st->tcp.rcvd.count, st->tcp.rcvd.bytes);
10820 } /* resolve_query() */
10823 static int resolve_addrinfo(int argc DNS_NOTUSED, char *argv[]) {
10824 _Bool recurse = !!strstr(argv[0], "recurse");
10825 struct dns_hints *(*hints)() = (recurse)? &dns_hints_root : &dns_hints_local;
10826 struct dns_resolver *res = NULL;
10827 struct dns_addrinfo *ai = NULL;
10828 struct addrinfo ai_hints = { .ai_family = PF_UNSPEC, .ai_socktype = SOCK_STREAM, .ai_flags = AI_CANONNAME };
10829 struct addrinfo *ent;
10834 MAIN.qname = "www.google.com";
10835 /* NB: MAIN.qtype of 0 means obey hints.ai_family */
10837 resconf()->options.recurse = recurse;
10839 if (!(res = dns_res_open(resconf(), hosts(), dns_hints_mortal(hints(resconf(), &error)), cache(), dns_opts(), &error)))
10840 panic("%s: %s", MAIN.qname, dns_strerror(error));
10842 if (!(ai = dns_ai_open(MAIN.qname, "80", MAIN.qtype, &ai_hints, res, &error)))
10843 panic("%s: %s", MAIN.qname, dns_strerror(error));
10845 dns_ai_settrace(ai, trace("w+b"));
10848 switch (error = dns_ai_nextent(&ent, ai)) {
10850 dns_ai_print(pretty, sizeof pretty, ent, ai);
10852 fputs(pretty, stdout);
10860 if (dns_ai_elapsed(ai) > 30)
10861 panic("query timed-out");
10863 dns_ai_poll(ai, 1);
10867 panic("dns_ai_nextent: %s (%d)", dns_strerror(error), error);
10869 } while (error != ENOENT);
10871 dns_res_close(res);
10875 } /* resolve_addrinfo() */
10878 static int dump_trace(int argc DNS_NOTUSED, char *argv[]) {
10882 panic("no trace file specified");
10884 if ((error = dns_trace_dump(trace("r"), stdout)))
10885 panic("dump_trace: %s", dns_strerror(error));
10888 } /* dump_trace() */
10891 static int echo_port(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
10893 struct sockaddr sa;
10894 struct sockaddr_in sin;
10898 memset(&port, 0, sizeof port);
10899 port.sin.sin_family = AF_INET;
10900 port.sin.sin_port = htons(5354);
10901 port.sin.sin_addr.s_addr = inet_addr("127.0.0.1");
10903 if (-1 == (fd = socket(PF_INET, SOCK_DGRAM, 0)))
10904 panic("socket: %s", strerror(errno));
10906 if (0 != bind(fd, &port.sa, sizeof port.sa))
10907 panic("127.0.0.1:5353: %s", dns_strerror(errno));
10910 struct dns_packet *pkt = dns_p_new(512);
10911 struct sockaddr_storage ss;
10912 socklen_t slen = sizeof ss;
10914 #if defined(MSG_WAITALL) /* MinGW issue */
10915 int rflags = MSG_WAITALL;
10920 count = recvfrom(fd, (char *)pkt->data, pkt->size, rflags, (struct sockaddr *)&ss, &slen);
10922 if (!count || count < 0)
10923 panic("recvfrom: %s", strerror(errno));
10927 dns_p_dump(pkt, stdout);
10929 (void)sendto(fd, (char *)pkt->data, pkt->end, 0, (struct sockaddr *)&ss, slen);
10933 } /* echo_port() */
10936 static int isection(int argc, char *argv[]) {
10937 const char *name = (argc > 1)? argv[1] : "";
10940 type = dns_isection(name);
10941 name = dns_strsection(type);
10943 printf("%s (%d)\n", name, type);
10949 static int iclass(int argc, char *argv[]) {
10950 const char *name = (argc > 1)? argv[1] : "";
10953 type = dns_iclass(name);
10954 name = dns_strclass(type);
10956 printf("%s (%d)\n", name, type);
10962 static int itype(int argc, char *argv[]) {
10963 const char *name = (argc > 1)? argv[1] : "";
10966 type = dns_itype(name);
10967 name = dns_strtype(type);
10969 printf("%s (%d)\n", name, type);
10975 static int iopcode(int argc, char *argv[]) {
10976 const char *name = (argc > 1)? argv[1] : "";
10979 type = dns_iopcode(name);
10980 name = dns_stropcode(type);
10982 printf("%s (%d)\n", name, type);
10988 static int ircode(int argc, char *argv[]) {
10989 const char *name = (argc > 1)? argv[1] : "";
10992 type = dns_ircode(name);
10993 name = dns_strrcode(type);
10995 printf("%s (%d)\n", name, type);
11001 #define SIZE1(x) { DNS_PP_STRINGIFY(x), sizeof (x) }
11002 #define SIZE2(x, ...) SIZE1(x), SIZE1(__VA_ARGS__)
11003 #define SIZE3(x, ...) SIZE1(x), SIZE2(__VA_ARGS__)
11004 #define SIZE4(x, ...) SIZE1(x), SIZE3(__VA_ARGS__)
11005 #define SIZE(...) DNS_PP_CALL(DNS_PP_XPASTE(SIZE, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__)
11007 static int sizes(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
11008 static const struct { const char *name; size_t size; } type[] = {
11009 SIZE(struct dns_header, struct dns_packet, struct dns_rr, struct dns_rr_i),
11010 SIZE(struct dns_a, struct dns_aaaa, struct dns_mx, struct dns_ns),
11011 SIZE(struct dns_cname, struct dns_soa, struct dns_ptr, struct dns_srv),
11012 SIZE(struct dns_sshfp, struct dns_txt, union dns_any),
11013 SIZE(struct dns_resolv_conf, struct dns_hosts, struct dns_hints, struct dns_hints_i),
11014 SIZE(struct dns_options, struct dns_socket, struct dns_resolver, struct dns_addrinfo),
11015 SIZE(struct dns_cache), SIZE(size_t), SIZE(void *), SIZE(long)
11019 for (i = 0, max = 0; i < lengthof(type); i++)
11020 max = DNS_PP_MAX(max, strlen(type[i].name));
11022 for (i = 0; i < lengthof(type); i++)
11023 printf("%*s : %"PRIuZ"\n", max, type[i].name, type[i].size);
11029 static const struct { const char *cmd; int (*run)(); const char *help; } cmds[] = {
11030 { "parse-packet", &parse_packet, "parse binary packet from stdin" },
11031 { "parse-domain", &parse_domain, "anchor and iteratively cleave domain" },
11032 { "trim-domain", &trim_domain, "trim and anchor domain name" },
11033 { "expand-domain", &expand_domain, "expand domain at offset NN in packet from stdin" },
11034 { "show-resconf", &show_resconf, "show resolv.conf data" },
11035 { "show-hosts", &show_hosts, "show hosts data" },
11036 { "show-nssconf", &show_nssconf, "show nsswitch.conf data" },
11037 { "query-hosts", &query_hosts, "query A, AAAA or PTR in hosts data" },
11038 { "search-list", &search_list, "generate query search list from domain" },
11039 { "permute-set", &permute_set, "generate random permutation -> (0 .. N or N .. M)" },
11040 { "shuffle-16", &shuffle_16, "simple 16-bit permutation" },
11041 { "dump-random", &dump_random, "generate random bytes" },
11042 { "send-query", &send_query, "send query to host" },
11043 { "send-query-udp", &send_query, "send udp query to host" },
11044 { "send-query-tcp", &send_query, "send tcp query to host" },
11045 { "print-arpa", &print_arpa, "print arpa. zone name of address" },
11046 { "show-hints", &show_hints, "print hints: show-hints [local|root] [plain|packet]" },
11047 { "resolve-stub", &resolve_query, "resolve as stub resolver" },
11048 { "resolve-recurse", &resolve_query, "resolve as recursive resolver" },
11049 { "addrinfo-stub", &resolve_addrinfo, "resolve through getaddrinfo clone" },
11050 { "addrinfo-recurse", &resolve_addrinfo, "resolve through getaddrinfo clone" },
11051 /* { "resolve-nameinfo", &resolve_query, "resolve as recursive resolver" }, */
11052 { "dump-trace", &dump_trace, "dump the contents of a trace file" },
11053 { "echo", &echo_port, "server echo mode, for nmap fuzzing" },
11054 { "isection", &isection, "parse section string" },
11055 { "iclass", &iclass, "parse class string" },
11056 { "itype", &itype, "parse type string" },
11057 { "iopcode", &iopcode, "parse opcode string" },
11058 { "ircode", &ircode, "parse rcode string" },
11059 { "sizes", &sizes, "print data structure sizes" },
11063 static void print_usage(const char *progname, FILE *fp) {
11064 static const char *usage =
11065 " [OPTIONS] COMMAND [ARGS]\n"
11066 " -c PATH Path to resolv.conf\n"
11067 " -n PATH Path to nsswitch.conf\n"
11068 " -l PATH Path to local hosts\n"
11069 " -z PATH Path to zone cache\n"
11070 " -q QNAME Query name\n"
11071 " -t QTYPE Query type\n"
11072 " -s HOW Sort records\n"
11073 " -S ADDR Address of SOCKS server to use\n"
11074 " -P PORT Port of SOCKS server to use\n"
11075 " -A USER:PASSWORD Credentials for the SOCKS server\n"
11076 " -f PATH Path to trace file\n"
11077 " -v Be more verbose (-vv show packets; -vvv hexdump packets)\n"
11078 " -V Print version info\n"
11079 " -h Print this usage message\n"
11083 fputs(progname, fp);
11086 for (i = 0, m = 0; i < lengthof(cmds); i++) {
11087 if (strlen(cmds[i].cmd) > m)
11088 m = strlen(cmds[i].cmd);
11091 for (i = 0; i < lengthof(cmds); i++) {
11092 fprintf(fp, " %s ", cmds[i].cmd);
11094 for (n = strlen(cmds[i].cmd); n < m; n++)
11097 fputs(cmds[i].help, fp);
11101 fputs("\nReport bugs to William Ahern <william@25thandClement.com>\n", fp);
11102 } /* print_usage() */
11105 static void print_version(const char *progname, FILE *fp) {
11106 fprintf(fp, "%s (dns.c) %.8X\n", progname, dns_v_rel());
11107 fprintf(fp, "vendor %s\n", dns_vendor());
11108 fprintf(fp, "release %.8X\n", dns_v_rel());
11109 fprintf(fp, "abi %.8X\n", dns_v_abi());
11110 fprintf(fp, "api %.8X\n", dns_v_api());
11111 } /* print_version() */
11114 static void main_exit(void) {
11115 dns_trace_close(MAIN.memo.trace);
11116 MAIN.memo.trace = NULL;
11117 dns_hosts_close(MAIN.memo.hosts);
11118 MAIN.memo.hosts = NULL;
11119 dns_resconf_close(MAIN.memo.resconf);
11120 MAIN.memo.resconf = NULL;
11121 } /* main_exit() */
11123 int main(int argc, char **argv) {
11125 extern char *optarg;
11126 const char *progname = argv[0];
11130 atexit(&main_exit);
11132 while (-1 != (ch = getopt(argc, argv, "q:t:c:n:l:z:s:S:P:A:f:vVh"))) {
11135 assert(MAIN.resconf.count < lengthof(MAIN.resconf.path));
11137 MAIN.resconf.path[MAIN.resconf.count++] = optarg;
11141 assert(MAIN.nssconf.count < lengthof(MAIN.nssconf.path));
11143 MAIN.nssconf.path[MAIN.nssconf.count++] = optarg;
11147 assert(MAIN.hosts.count < lengthof(MAIN.hosts.path));
11149 MAIN.hosts.path[MAIN.hosts.count++] = optarg;
11153 assert(MAIN.cache.count < lengthof(MAIN.cache.path));
11155 MAIN.cache.path[MAIN.cache.count++] = optarg;
11159 MAIN.qname = optarg;
11163 for (i = 0; i < lengthof(dns_rrtypes); i++) {
11164 if (0 == strcasecmp(dns_rrtypes[i].name, optarg))
11165 { MAIN.qtype = dns_rrtypes[i].type; break; }
11171 for (i = 0; dns_isdigit(optarg[i]); i++) {
11173 MAIN.qtype += optarg[i] - '0';
11177 panic("%s: invalid query type", optarg);
11181 if (0 == strcasecmp(optarg, "packet"))
11182 MAIN.sort = &dns_rr_i_packet;
11183 else if (0 == strcasecmp(optarg, "shuffle"))
11184 MAIN.sort = &dns_rr_i_shuffle;
11185 else if (0 == strcasecmp(optarg, "order"))
11186 MAIN.sort = &dns_rr_i_order;
11188 panic("%s: invalid sort method", optarg);
11193 struct dns_resolv_conf *conf = resconf();
11194 conf->options.tcp = DNS_RESCONF_TCP_SOCKS;
11196 MAIN.socks_host.ss_family = (strchr(optarg, ':')) ? AF_INET6 : AF_INET;
11197 if ((error = dns_pton(MAIN.socks_host.ss_family, optarg,
11198 dns_sa_addr(MAIN.socks_host.ss_family,
11199 &MAIN.socks_host, NULL))))
11200 panic("%s: %s", optarg, dns_strerror(error));
11202 *dns_sa_port(MAIN.socks_host.ss_family, &MAIN.socks_host) = htons(1080);
11207 if (! MAIN.socks_host.ss_family)
11208 panic("-P without prior -S");
11209 *dns_sa_port(MAIN.socks_host.ss_family, &MAIN.socks_host) = htons(atoi(optarg));
11214 if (! MAIN.socks_host.ss_family)
11215 panic("-A without prior -S");
11216 if (! (password = strchr(optarg, ':')))
11217 panic("Usage: -A USER:PASSWORD");
11220 MAIN.socks_user = optarg;
11221 MAIN.socks_password = password;
11225 MAIN.trace = optarg;
11229 dns_debug = ++MAIN.verbose;
11233 print_version(progname, stdout);
11237 print_usage(progname, stdout);
11241 print_usage(progname, stderr);
11243 return EXIT_FAILURE;
11250 for (i = 0; i < lengthof(cmds) && argv[0]; i++) {
11251 if (0 == strcmp(cmds[i].cmd, argv[0]))
11252 return cmds[i].run(argc, argv);
11255 print_usage(progname, stderr);
11257 return EXIT_FAILURE;
11261 #endif /* DNS_MAIN */
11265 * pop file-scoped compiler annotations
11268 #pragma clang diagnostic pop
11269 #elif DNS_GNUC_PREREQ(4,6,0)
11270 #pragma GCC diagnostic pop