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)
4598 if (fwrite(data, 1, datasize, fp) < datasize)
4606 static void dns_trace_setcname(struct dns_trace *trace, const char *host, const struct sockaddr *addr) {
4607 struct dns_trace_cname *cname;
4608 if (!trace || !trace->fp)
4611 cname = &trace->cnames.base[trace->cnames.p];
4612 dns_strlcpy(cname->host, host, sizeof cname->host);
4613 memcpy(&cname->addr, addr, DNS_PP_MIN(dns_sa_len(addr), sizeof cname->addr));
4615 trace->cnames.p = (trace->cnames.p + 1) % lengthof(trace->cnames.base);
4618 static const char *dns_trace_cname(struct dns_trace *trace, const struct sockaddr *addr) {
4619 if (!trace || !trace->fp)
4622 /* NB: start search from the write cursor to */
4623 for (const struct dns_trace_cname *cname = trace->cnames.base; cname < endof(trace->cnames.base); cname++) {
4624 if (0 == dns_sa_cmp((struct sockaddr *)addr, (struct sockaddr *)&cname->addr))
4631 static void dns_trace_res_submit(struct dns_trace *trace, const char *qname, enum dns_type qtype, enum dns_class qclass, int error) {
4632 struct dns_trace_event te;
4633 if (!trace || !trace->fp)
4636 dns_te_init(&te, DNS_TE_RES_SUBMIT);
4637 dns_strlcpy(te.res_submit.qname, qname, sizeof te.res_submit.qname);
4638 te.res_submit.qtype = qtype;
4639 te.res_submit.qclass = qclass;
4640 te.res_submit.error = error;
4641 dns_trace_tag_and_put(trace, &te, NULL, 0);
4644 static void dns_trace_res_fetch(struct dns_trace *trace, const struct dns_packet *packet, int error) {
4645 struct dns_trace_event te;
4648 if (!trace || !trace->fp)
4651 dns_te_init(&te, DNS_TE_RES_FETCH);
4652 data = (packet)? packet->data : NULL;
4653 datasize = (packet)? packet->end : 0;
4654 te.res_fetch.error = error;
4655 dns_trace_tag_and_put(trace, &te, data, datasize);
4658 static void dns_trace_so_submit(struct dns_trace *trace, const struct dns_packet *packet, const struct sockaddr *haddr, int error) {
4659 struct dns_trace_event te;
4661 if (!trace || !trace->fp)
4664 dns_te_init(&te, DNS_TE_SO_SUBMIT);
4665 memcpy(&te.so_submit.haddr, haddr, DNS_PP_MIN(dns_sa_len(haddr), sizeof te.so_submit.haddr));
4666 if ((cname = dns_trace_cname(trace, haddr)))
4667 dns_strlcpy(te.so_submit.hname, cname, sizeof te.so_submit.hname);
4668 te.so_submit.error = error;
4669 dns_trace_tag_and_put(trace, &te, packet->data, packet->end);
4672 static void dns_trace_so_verify(struct dns_trace *trace, const struct dns_packet *packet, int error) {
4673 struct dns_trace_event te;
4674 if (!trace || !trace->fp)
4677 dns_te_init(&te, DNS_TE_SO_VERIFY);
4678 te.so_verify.error = error;
4679 dns_trace_tag_and_put(trace, &te, packet->data, packet->end);
4682 static void dns_trace_so_fetch(struct dns_trace *trace, const struct dns_packet *packet, int error) {
4683 struct dns_trace_event te;
4686 if (!trace || !trace->fp)
4689 dns_te_init(&te, DNS_TE_SO_FETCH);
4690 data = (packet)? packet->data : NULL;
4691 datasize = (packet)? packet->end : 0;
4692 te.so_fetch.error = error;
4693 dns_trace_tag_and_put(trace, &te, data, datasize);
4696 static void dns_trace_sys_connect(struct dns_trace *trace, int fd, int socktype, const struct sockaddr *dst, int error) {
4697 struct dns_trace_event te;
4698 if (!trace || !trace->fp)
4701 dns_te_init(&te, DNS_TE_SYS_CONNECT);
4702 dns_te_initname(&te.sys_connect.src, fd, &getsockname);
4703 memcpy(&te.sys_connect.dst, dst, DNS_PP_MIN(dns_sa_len(dst), sizeof te.sys_connect.dst));
4704 te.sys_connect.socktype = socktype;
4705 te.sys_connect.error = error;
4706 dns_trace_tag_and_put(trace, &te, NULL, 0);
4709 static void dns_trace_sys_send(struct dns_trace *trace, int fd, int socktype, const void *data, size_t datasize, int error) {
4710 struct dns_trace_event te;
4711 if (!trace || !trace->fp)
4714 dns_te_init(&te, DNS_TE_SYS_SEND);
4715 dns_te_initnames(&te.sys_send.src, &te.sys_send.dst, fd);
4716 te.sys_send.socktype = socktype;
4717 te.sys_send.error = error;
4718 dns_trace_tag_and_put(trace, &te, data, datasize);
4721 static void dns_trace_sys_recv(struct dns_trace *trace, int fd, int socktype, const void *data, size_t datasize, int error) {
4722 struct dns_trace_event te;
4723 if (!trace || !trace->fp)
4726 dns_te_init(&te, DNS_TE_SYS_RECV);
4727 dns_te_initnames(&te.sys_recv.dst, &te.sys_recv.src, fd);
4728 te.sys_recv.socktype = socktype;
4729 te.sys_recv.error = error;
4730 dns_trace_tag_and_put(trace, &te, data, datasize);
4733 static dns_error_t dns_trace_dump_packet(struct dns_trace *trace, const char *prefix, const unsigned char *data, size_t datasize, FILE *fp) {
4734 struct dns_packet *packet = NULL;
4735 char *line = NULL, *p;
4736 size_t size = 1, skip = 0;
4737 struct dns_rr_i records;
4738 struct dns_p_lines_i lines;
4742 if (!(packet = dns_p_make(datasize, &error)))
4745 memcpy(packet->data, data, datasize);
4746 packet->end = datasize;
4747 (void)dns_p_study(packet);
4749 if (!(p = dns_reallocarray(line, size, 2, &error)))
4754 memset(&records, 0, sizeof records);
4755 memset(&lines, 0, sizeof lines);
4758 while ((len = dns_p_lines(line, size, &error, packet, &records, &lines))) {
4759 if (!(len < size)) {
4762 } else if (skip <= count) {
4764 fwrite(line, 1, len, fp);
4780 static dns_error_t dns_trace_dump_data(struct dns_trace *trace, const char *prefix, const unsigned char *data, size_t datasize, FILE *fp) {
4781 struct dns_hxd_lines_i lines = { 0 };
4785 while ((len = dns_hxd_lines(line, sizeof line, data, datasize, &lines))) {
4786 if (len >= sizeof line)
4787 return EOVERFLOW; /* shouldn't be possible */
4789 fwrite(line, 1, len, fp);
4795 static dns_error_t dns_trace_dump_addr(struct dns_trace *trace, const char *prefix, const struct sockaddr_storage *ss, FILE *fp) {
4801 if ((addr = dns_sa_addr(ss->ss_family, (struct sockaddr *)ss, NULL))) {
4802 char ip[INET6_ADDRSTRLEN + 1];
4804 if ((error = dns_ntop(ss->ss_family, addr, ip, sizeof ip)))
4806 fprintf(fp, "%s%s\n", prefix, ip);
4807 } else if ((path = dns_sa_path((struct sockaddr *)ss, &len))) {
4808 fprintf(fp, "%sunix:%.*s", prefix, (int)len, path);
4816 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) {
4817 char time_s[48], elapsed_s[48];
4819 dns_utime_print(time_s, sizeof time_s, dns_ts2us(&te->ts, 0));
4820 dns_utime_print(elapsed_s, sizeof elapsed_s, elapsed);
4822 fprintf(fp, "%sid: %"DNS_TRACE_ID_PRI"\n", prefix, te->id);
4823 fprintf(fp, "%sts: %s (%s)\n", prefix, time_s, elapsed_s);
4824 fprintf(fp, "%sabi: 0x%x (0x%x)\n", prefix, te->abi, DNS_TRACE_ABI);
4828 static dns_error_t dns_trace_dump_error(struct dns_trace *trace, const char *prefix, int error, FILE *fp) {
4829 fprintf(fp, "%s%d (%s)\n", prefix, error, (error)? dns_strerror(error) : "none");
4833 dns_error_t dns_trace_dump(struct dns_trace *trace, FILE *fp) {
4834 struct dns_trace_event *te = NULL;
4837 dns_microseconds_t begin, elapsed;
4841 if (!trace || !trace->fp)
4844 if (0 != fseek(trace->fp, 0, SEEK_SET))
4847 while (dns_trace_fget(&te, trace->fp, &error)) {
4848 size_t datasize = dns_te_datasize(te);
4849 const unsigned char *data = (datasize)? te->data : NULL;
4851 if (state.id != te->id) {
4853 state.begin = dns_ts2us(&te->ts, 0);
4855 dns_time_diff(&state.elapsed, dns_ts2us(&te->ts, 0), state.begin);
4858 case DNS_TE_RES_SUBMIT:
4859 fprintf(fp, "dns_res_submit:\n");
4860 dns_trace_dump_meta(trace, " ", te, state.elapsed, fp);
4861 fprintf(fp, " qname: %s\n", te->res_submit.qname);
4862 fprintf(fp, " qtype: %s\n", dns_strtype(te->res_submit.qtype));
4863 fprintf(fp, " qclass: %s\n", dns_strclass(te->res_submit.qclass));
4864 dns_trace_dump_error(trace, " error: ", te->res_submit.error, fp);
4866 case DNS_TE_RES_FETCH:
4867 fprintf(fp, "dns_res_fetch:\n");
4868 dns_trace_dump_meta(trace, " ", te, state.elapsed, fp);
4869 dns_trace_dump_error(trace, " error: ", te->res_fetch.error, fp);
4872 fprintf(fp, " packet: |\n");
4873 if ((error = dns_trace_dump_packet(trace, " ", data, datasize, fp)))
4875 fprintf(fp, " data: |\n");
4876 if ((error = dns_trace_dump_data(trace, " ", data, datasize, fp)))
4881 case DNS_TE_SO_SUBMIT:
4882 fprintf(fp, "dns_so_submit:\n");
4883 dns_trace_dump_meta(trace, " ", te, state.elapsed, fp);
4884 fprintf(fp, " hname: %s\n", te->so_submit.hname);
4885 dns_trace_dump_addr(trace, " haddr: ", &te->so_submit.haddr, fp);
4886 dns_trace_dump_error(trace, " error: ", te->so_submit.error, fp);
4889 fprintf(fp, " packet: |\n");
4890 if ((error = dns_trace_dump_packet(trace, " ", data, datasize, fp)))
4892 fprintf(fp, " data: |\n");
4893 if ((error = dns_trace_dump_data(trace, " ", data, datasize, fp)))
4898 case DNS_TE_SO_VERIFY:
4899 fprintf(fp, "dns_so_verify:\n");
4900 dns_trace_dump_meta(trace, " ", te, state.elapsed, fp);
4901 dns_trace_dump_error(trace, " error: ", te->so_verify.error, fp);
4904 fprintf(fp, " packet: |\n");
4905 if ((error = dns_trace_dump_packet(trace, " ", data, datasize, fp)))
4907 fprintf(fp, " data: |\n");
4908 if ((error = dns_trace_dump_data(trace, " ", data, datasize, fp)))
4913 case DNS_TE_SO_FETCH:
4914 fprintf(fp, "dns_so_fetch:\n");
4915 dns_trace_dump_meta(trace, " ", te, state.elapsed, fp);
4916 dns_trace_dump_error(trace, " error: ", te->so_fetch.error, fp);
4919 fprintf(fp, " packet: |\n");
4920 if ((error = dns_trace_dump_packet(trace, " ", data, datasize, fp)))
4922 fprintf(fp, " data: |\n");
4923 if ((error = dns_trace_dump_data(trace, " ", data, datasize, fp)))
4928 case DNS_TE_SYS_CONNECT: {
4929 int socktype = te->sys_connect.socktype;
4930 fprintf(fp, "dns_sys_connect:\n");
4931 dns_trace_dump_meta(trace, " ", te, state.elapsed, fp);
4932 dns_trace_dump_addr(trace, " src: ", &te->sys_connect.src, fp);
4933 dns_trace_dump_addr(trace, " dst: ", &te->sys_connect.dst, fp);
4934 fprintf(fp, " socktype: %d (%s)\n", socktype, ((socktype == SOCK_STREAM)? "SOCK_STREAM" : (socktype == SOCK_DGRAM)? "SOCK_DGRAM" : "?"));
4935 dns_trace_dump_error(trace, " error: ", te->sys_connect.error, fp);
4939 case DNS_TE_SYS_SEND: {
4940 int socktype = te->sys_send.socktype;
4941 fprintf(fp, "dns_sys_send:\n");
4942 dns_trace_dump_meta(trace, " ", te, state.elapsed, fp);
4943 dns_trace_dump_addr(trace, " src: ", &te->sys_send.src, fp);
4944 dns_trace_dump_addr(trace, " dst: ", &te->sys_send.dst, fp);
4945 fprintf(fp, " socktype: %d (%s)\n", socktype, ((socktype == SOCK_STREAM)? "SOCK_STREAM" : (socktype == SOCK_DGRAM)? "SOCK_DGRAM" : "?"));
4946 dns_trace_dump_error(trace, " error: ", te->sys_send.error, fp);
4949 fprintf(fp, " data: |\n");
4950 if ((error = dns_trace_dump_data(trace, " ", data, datasize, fp)))
4956 case DNS_TE_SYS_RECV: {
4957 int socktype = te->sys_recv.socktype;
4958 fprintf(fp, "dns_sys_recv:\n");
4959 dns_trace_dump_meta(trace, " ", te, state.elapsed, fp);
4960 dns_trace_dump_addr(trace, " src: ", &te->sys_recv.src, fp);
4961 dns_trace_dump_addr(trace, " dst: ", &te->sys_recv.dst, fp);
4962 fprintf(fp, " socktype: %d (%s)\n", socktype, ((socktype == SOCK_STREAM)? "SOCK_STREAM" : (socktype == SOCK_DGRAM)? "SOCK_DGRAM" : "?"));
4963 dns_trace_dump_error(trace, " error: ", te->sys_recv.error, fp);
4966 fprintf(fp, " data: |\n");
4967 if ((error = dns_trace_dump_data(trace, " ", data, datasize, fp)))
4974 fprintf(fp, "unknown(0x%.2x):\n", te->type);
4975 dns_trace_dump_meta(trace, " ", te, state.elapsed, fp);
4978 fprintf(fp, " data: |\n");
4979 if ((error = dns_trace_dump_data(trace, " ", data, datasize, fp)))
4999 * H O S T S R O U T I N E S
5001 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5004 struct dns_hosts_entry {
5005 char host[DNS_D_MAXNAME + 1];
5017 struct dns_hosts_entry *next;
5020 dns_atomic_t refcount;
5021 }; /* struct dns_hosts */
5024 struct dns_hosts *dns_hosts_open(int *error) {
5025 static const struct dns_hosts hosts_initializer = { .refcount = 1 };
5026 struct dns_hosts *hosts;
5028 if (!(hosts = malloc(sizeof *hosts)))
5031 *hosts = hosts_initializer;
5033 hosts->tail = &hosts->head;
5037 *error = dns_syerr();
5042 } /* dns_hosts_open() */
5045 void dns_hosts_close(struct dns_hosts *hosts) {
5046 struct dns_hosts_entry *ent, *xnt;
5048 if (!hosts || 1 != dns_hosts_release(hosts))
5051 for (ent = hosts->head; ent; ent = xnt) {
5060 } /* dns_hosts_close() */
5063 dns_refcount_t dns_hosts_acquire(struct dns_hosts *hosts) {
5064 return dns_atomic_fetch_add(&hosts->refcount);
5065 } /* dns_hosts_acquire() */
5068 dns_refcount_t dns_hosts_release(struct dns_hosts *hosts) {
5069 return dns_atomic_fetch_sub(&hosts->refcount);
5070 } /* dns_hosts_release() */
5073 struct dns_hosts *dns_hosts_mortal(struct dns_hosts *hosts) {
5075 dns_hosts_release(hosts);
5078 } /* dns_hosts_mortal() */
5081 struct dns_hosts *dns_hosts_local(int *error_) {
5082 struct dns_hosts *hosts;
5085 if (!(hosts = dns_hosts_open(&error)))
5088 if ((error = dns_hosts_loadpath(hosts, "/etc/hosts")))
5095 dns_hosts_close(hosts);
5098 } /* dns_hosts_local() */
5101 #define dns_hosts_issep(ch) (dns_isspace(ch))
5102 #define dns_hosts_iscom(ch) ((ch) == '#' || (ch) == ';')
5104 int dns_hosts_loadfile(struct dns_hosts *hosts, FILE *fp) {
5105 struct dns_hosts_entry ent;
5106 char word[DNS_PP_MAX(INET6_ADDRSTRLEN, DNS_D_MAXNAME) + 1];
5107 unsigned wp, wc, skip;
5113 memset(&ent, '\0', sizeof ent);
5118 memset(word, '\0', sizeof word);
5121 while (EOF != (ch = fgetc(fp)) && ch != '\n') {
5122 skip |= !!dns_hosts_iscom(ch);
5127 if (dns_hosts_issep(ch))
5130 if (wp < sizeof word - 1)
5144 ent.af = (strchr(word, ':'))? AF_INET6 : AF_INET;
5145 skip = (1 != dns_inet_pton(ent.af, word, &ent.addr));
5152 dns_d_anchor(ent.host, sizeof ent.host, word, wp);
5154 if ((error = dns_hosts_insert(hosts, ent.af, &ent.addr, ent.host, (wc > 2))))
5159 } while (ch != EOF && ch != '\n');
5160 } while (ch != EOF);
5163 } /* dns_hosts_loadfile() */
5166 int dns_hosts_loadpath(struct dns_hosts *hosts, const char *path) {
5170 if (!(fp = dns_fopen(path, "rt", &error)))
5173 error = dns_hosts_loadfile(hosts, fp);
5178 } /* dns_hosts_loadpath() */
5181 int dns_hosts_dump(struct dns_hosts *hosts, FILE *fp) {
5182 struct dns_hosts_entry *ent, *xnt;
5183 char addr[INET6_ADDRSTRLEN + 1];
5186 for (ent = hosts->head; ent; ent = xnt) {
5189 dns_inet_ntop(ent->af, &ent->addr, addr, sizeof addr);
5193 for (i = strlen(addr); i < INET_ADDRSTRLEN; i++)
5198 fputs(ent->host, fp);
5203 } /* dns_hosts_dump() */
5206 int dns_hosts_insert(struct dns_hosts *hosts, int af, const void *addr, const void *host, _Bool alias) {
5207 struct dns_hosts_entry *ent;
5210 if (!(ent = malloc(sizeof *ent)))
5213 dns_d_anchor(ent->host, sizeof ent->host, host, strlen(host));
5215 switch ((ent->af = af)) {
5217 memcpy(&ent->addr.a6, addr, sizeof ent->addr.a6);
5219 dns_aaaa_arpa(ent->arpa, sizeof ent->arpa, addr);
5223 memcpy(&ent->addr.a4, addr, sizeof ent->addr.a4);
5225 dns_a_arpa(ent->arpa, sizeof ent->arpa, addr);
5238 hosts->tail = &ent->next;
5242 error = dns_syerr();
5247 } /* dns_hosts_insert() */
5250 struct dns_packet *dns_hosts_query(struct dns_hosts *hosts, struct dns_packet *Q, int *error_) {
5251 struct dns_packet *P = dns_p_new(512);
5252 struct dns_packet *A = 0;
5254 struct dns_hosts_entry *ent;
5256 char qname[DNS_D_MAXNAME + 1];
5259 if ((error = dns_rr_parse(&rr, 12, Q)))
5262 if (!(qlen = dns_d_expand(qname, sizeof qname, rr.dn.p, Q, &error)))
5264 else if (qlen >= sizeof qname)
5267 if ((error = dns_p_push(P, DNS_S_QD, qname, qlen, rr.type, rr.class, 0, 0)))
5272 for (ent = hosts->head; ent; ent = ent->next) {
5273 if (ent->alias || 0 != strcasecmp(qname, ent->arpa))
5276 if ((error = dns_p_push(P, DNS_S_AN, qname, qlen, rr.type, rr.class, 0, ent->host)))
5288 loop: for (ent = hosts->head; ent; ent = ent->next) {
5289 if (ent->af != af || 0 != strcasecmp(qname, ent->host))
5292 if ((error = dns_p_push(P, DNS_S_AN, qname, qlen, rr.type, rr.class, 0, &ent->addr)))
5302 if (!(A = dns_p_copy(dns_p_make(P->end, &error), P)))
5307 error = DNS_EILLEGAL;
5314 } /* dns_hosts_query() */
5318 * R E S O L V . C O N F R O U T I N E S
5320 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5322 struct dns_resolv_conf *dns_resconf_open(int *error) {
5323 static const struct dns_resolv_conf resconf_initializer = {
5325 .family = { AF_INET, AF_INET6 },
5326 .options = { .ndots = 1, .timeout = 5, .attempts = 2, .tcp = DNS_RESCONF_TCP_ENABLE, },
5327 .iface = { .ss_family = AF_INET },
5329 struct dns_resolv_conf *resconf;
5330 struct sockaddr_in *sin;
5332 if (!(resconf = malloc(sizeof *resconf)))
5335 *resconf = resconf_initializer;
5337 sin = (struct sockaddr_in *)&resconf->nameserver[0];
5338 sin->sin_family = AF_INET;
5339 sin->sin_addr.s_addr = INADDR_ANY;
5340 sin->sin_port = htons(53);
5342 sin->sin_len = sizeof *sin;
5345 if (0 != gethostname(resconf->search[0], sizeof resconf->search[0]))
5348 dns_d_anchor(resconf->search[0], sizeof resconf->search[0], resconf->search[0], strlen(resconf->search[0]));
5349 dns_d_cleave(resconf->search[0], sizeof resconf->search[0], resconf->search[0], strlen(resconf->search[0]));
5352 * XXX: If gethostname() returned a string without any label
5353 * separator, then search[0][0] should be NUL.
5356 dns_resconf_acquire(resconf);
5360 *error = dns_syerr();
5365 } /* dns_resconf_open() */
5368 void dns_resconf_close(struct dns_resolv_conf *resconf) {
5369 if (!resconf || 1 != dns_resconf_release(resconf))
5373 } /* dns_resconf_close() */
5376 dns_refcount_t dns_resconf_acquire(struct dns_resolv_conf *resconf) {
5377 return dns_atomic_fetch_add(&resconf->_.refcount);
5378 } /* dns_resconf_acquire() */
5381 dns_refcount_t dns_resconf_release(struct dns_resolv_conf *resconf) {
5382 return dns_atomic_fetch_sub(&resconf->_.refcount);
5383 } /* dns_resconf_release() */
5386 struct dns_resolv_conf *dns_resconf_mortal(struct dns_resolv_conf *resconf) {
5388 dns_resconf_release(resconf);
5391 } /* dns_resconf_mortal() */
5394 struct dns_resolv_conf *dns_resconf_local(int *error_) {
5395 struct dns_resolv_conf *resconf;
5398 if (!(resconf = dns_resconf_open(&error)))
5401 if ((error = dns_resconf_loadpath(resconf, "/etc/resolv.conf"))) {
5403 * NOTE: Both the glibc and BIND9 resolvers ignore a missing
5404 * /etc/resolv.conf, defaulting to a nameserver of
5405 * 127.0.0.1. See also dns_hints_insert_resconf, and the
5406 * default initialization of nameserver[0] in
5409 if (error != ENOENT)
5413 if ((error = dns_nssconf_loadpath(resconf, "/etc/nsswitch.conf"))) {
5414 if (error != ENOENT)
5422 dns_resconf_close(resconf);
5425 } /* dns_resconf_local() */
5428 struct dns_resolv_conf *dns_resconf_root(int *error) {
5429 struct dns_resolv_conf *resconf;
5431 if ((resconf = dns_resconf_local(error)))
5432 resconf->options.recurse = 1;
5435 } /* dns_resconf_root() */
5438 static time_t dns_resconf_timeout(const struct dns_resolv_conf *resconf) {
5439 return (time_t)DNS_PP_MIN(INT_MAX, resconf->options.timeout);
5440 } /* dns_resconf_timeout() */
5443 enum dns_resconf_keyword {
5444 DNS_RESCONF_NAMESERVER,
5454 DNS_RESCONF_OPTIONS,
5457 DNS_RESCONF_TIMEOUT,
5458 DNS_RESCONF_ATTEMPTS,
5460 DNS_RESCONF_RECURSE,
5464 DNS_RESCONF_INTERFACE,
5469 DNS_RESCONF_DISABLE,
5470 }; /* enum dns_resconf_keyword */
5472 static enum dns_resconf_keyword dns_resconf_keyword(const char *word) {
5473 static const char *words[] = {
5474 [DNS_RESCONF_NAMESERVER] = "nameserver",
5475 [DNS_RESCONF_DOMAIN] = "domain",
5476 [DNS_RESCONF_SEARCH] = "search",
5477 [DNS_RESCONF_LOOKUP] = "lookup",
5478 [DNS_RESCONF_FILE] = "file",
5479 [DNS_RESCONF_BIND] = "bind",
5480 [DNS_RESCONF_CACHE] = "cache",
5481 [DNS_RESCONF_FAMILY] = "family",
5482 [DNS_RESCONF_INET4] = "inet4",
5483 [DNS_RESCONF_INET6] = "inet6",
5484 [DNS_RESCONF_OPTIONS] = "options",
5485 [DNS_RESCONF_EDNS0] = "edns0",
5486 [DNS_RESCONF_ROTATE] = "rotate",
5487 [DNS_RESCONF_RECURSE] = "recurse",
5488 [DNS_RESCONF_SMART] = "smart",
5489 [DNS_RESCONF_TCP] = "tcp",
5490 [DNS_RESCONF_INTERFACE] = "interface",
5491 [DNS_RESCONF_ZERO] = "0",
5492 [DNS_RESCONF_ONE] = "1",
5493 [DNS_RESCONF_ENABLE] = "enable",
5494 [DNS_RESCONF_ONLY] = "only",
5495 [DNS_RESCONF_DISABLE] = "disable",
5499 for (i = 0; i < lengthof(words); i++) {
5500 if (words[i] && 0 == strcasecmp(words[i], word))
5504 if (0 == strncasecmp(word, "ndots:", sizeof "ndots:" - 1))
5505 return DNS_RESCONF_NDOTS;
5507 if (0 == strncasecmp(word, "timeout:", sizeof "timeout:" - 1))
5508 return DNS_RESCONF_TIMEOUT;
5510 if (0 == strncasecmp(word, "attempts:", sizeof "attempts:" - 1))
5511 return DNS_RESCONF_ATTEMPTS;
5513 if (0 == strncasecmp(word, "tcp:", sizeof "tcp:" - 1))
5514 return DNS_RESCONF_TCPx;
5517 } /* dns_resconf_keyword() */
5520 /** OpenBSD-style "[1.2.3.4]:53" nameserver syntax */
5521 int dns_resconf_pton(struct sockaddr_storage *ss, const char *src) {
5522 struct { char buf[128], *p; } addr = { "", addr.buf };
5523 unsigned short port = 0;
5524 int ch, af = AF_INET, error;
5526 while ((ch = *src++)) {
5535 while ((ch = *src++)) {
5536 if (dns_isdigit(ch)) {
5548 if (addr.p < endof(addr.buf) - 1)
5556 if ((error = dns_pton(af, addr.buf, dns_sa_addr(af, ss, NULL))))
5559 port = (!port)? 53 : port;
5560 *dns_sa_port(af, ss) = htons(port);
5561 dns_sa_family(ss) = af;
5564 } /* dns_resconf_pton() */
5566 #define dns_resconf_issep(ch) (dns_isspace(ch) || (ch) == ',')
5567 #define dns_resconf_iscom(ch) ((ch) == '#' || (ch) == ';')
5569 int dns_resconf_loadfile(struct dns_resolv_conf *resconf, FILE *fp) {
5570 unsigned sa_count = 0;
5571 char words[6][DNS_D_MAXNAME + 1];
5572 unsigned wp, wc, i, j, n;
5578 memset(words, '\0', sizeof words);
5582 while (EOF != (ch = getc(fp)) && ch != '\n') {
5583 if (dns_resconf_issep(ch)) {
5587 if (++wc >= lengthof(words))
5590 } else if (dns_resconf_iscom(ch)) {
5594 } while (ch != EOF && ch != '\n');
5597 } else if (wp < sizeof words[wc] - 1) {
5598 words[wc][wp++] = ch;
5600 wp = 0; /* drop word */
5611 switch (dns_resconf_keyword(words[0])) {
5612 case DNS_RESCONF_NAMESERVER:
5613 if (sa_count >= lengthof(resconf->nameserver))
5616 if ((error = dns_resconf_pton(&resconf->nameserver[sa_count], words[1])))
5622 case DNS_RESCONF_DOMAIN:
5623 case DNS_RESCONF_SEARCH:
5624 memset(resconf->search, '\0', sizeof resconf->search);
5626 for (i = 1, j = 0; i < wc && j < lengthof(resconf->search); i++, j++)
5627 dns_d_anchor(resconf->search[j], sizeof resconf->search[j], words[i], strlen(words[i]));
5630 case DNS_RESCONF_LOOKUP:
5631 for (i = 1, j = 0; i < wc && j < lengthof(resconf->lookup); i++) {
5632 switch (dns_resconf_keyword(words[i])) {
5633 case DNS_RESCONF_FILE:
5634 resconf->lookup[j++] = 'f';
5637 case DNS_RESCONF_BIND:
5638 resconf->lookup[j++] = 'b';
5641 case DNS_RESCONF_CACHE:
5642 resconf->lookup[j++] = 'c';
5651 case DNS_RESCONF_FAMILY:
5652 for (i = 1, j = 0; i < wc && j < lengthof(resconf->family); i++) {
5653 switch (dns_resconf_keyword(words[i])) {
5654 case DNS_RESCONF_INET4:
5655 resconf->family[j++] = AF_INET;
5658 case DNS_RESCONF_INET6:
5659 resconf->family[j++] = AF_INET6;
5668 case DNS_RESCONF_OPTIONS:
5669 for (i = 1; i < wc; i++) {
5670 switch (dns_resconf_keyword(words[i])) {
5671 case DNS_RESCONF_EDNS0:
5672 resconf->options.edns0 = 1;
5675 case DNS_RESCONF_NDOTS:
5676 for (j = sizeof "ndots:" - 1, n = 0; dns_isdigit(words[i][j]); j++) {
5678 n += words[i][j] - '0';
5681 resconf->options.ndots = n;
5684 case DNS_RESCONF_TIMEOUT:
5685 for (j = sizeof "timeout:" - 1, n = 0; dns_isdigit(words[i][j]); j++) {
5687 n += words[i][j] - '0';
5690 resconf->options.timeout = n;
5693 case DNS_RESCONF_ATTEMPTS:
5694 for (j = sizeof "attempts:" - 1, n = 0; dns_isdigit(words[i][j]); j++) {
5696 n += words[i][j] - '0';
5699 resconf->options.attempts = n;
5702 case DNS_RESCONF_ROTATE:
5703 resconf->options.rotate = 1;
5706 case DNS_RESCONF_RECURSE:
5707 resconf->options.recurse = 1;
5710 case DNS_RESCONF_SMART:
5711 resconf->options.smart = 1;
5714 case DNS_RESCONF_TCP:
5715 resconf->options.tcp = DNS_RESCONF_TCP_ONLY;
5718 case DNS_RESCONF_TCPx:
5719 switch (dns_resconf_keyword(&words[i][sizeof "tcp:" - 1])) {
5720 case DNS_RESCONF_ENABLE:
5721 resconf->options.tcp = DNS_RESCONF_TCP_ENABLE;
5724 case DNS_RESCONF_ONE:
5725 case DNS_RESCONF_ONLY:
5726 resconf->options.tcp = DNS_RESCONF_TCP_ONLY;
5729 case DNS_RESCONF_ZERO:
5730 case DNS_RESCONF_DISABLE:
5731 resconf->options.tcp = DNS_RESCONF_TCP_DISABLE;
5745 case DNS_RESCONF_INTERFACE:
5746 for (i = 0, n = 0; dns_isdigit(words[2][i]); i++) {
5748 n += words[2][i] - '0';
5751 dns_resconf_setiface(resconf, words[1], n);
5757 } while (ch != EOF);
5760 } /* dns_resconf_loadfile() */
5763 int dns_resconf_loadpath(struct dns_resolv_conf *resconf, const char *path) {
5767 if (!(fp = dns_fopen(path, "rt", &error)))
5770 error = dns_resconf_loadfile(resconf, fp);
5775 } /* dns_resconf_loadpath() */
5778 struct dns_anyconf {
5781 char buffer[1024], *tp, *cp;
5782 }; /* struct dns_anyconf */
5785 static void dns_anyconf_reset(struct dns_anyconf *cf) {
5787 cf->tp = cf->cp = cf->buffer;
5788 } /* dns_anyconf_reset() */
5791 static int dns_anyconf_push(struct dns_anyconf *cf) {
5792 if (!(cf->cp < endof(cf->buffer) && cf->count < lengthof(cf->token)))
5796 cf->token[cf->count++] = cf->tp;
5800 } /* dns_anyconf_push() */
5803 static void dns_anyconf_pop(struct dns_anyconf *cf) {
5804 if (cf->count > 0) {
5806 cf->tp = cf->cp = cf->token[cf->count];
5807 cf->token[cf->count] = 0;
5809 } /* dns_anyconf_pop() */
5812 static int dns_anyconf_addc(struct dns_anyconf *cf, int ch) {
5813 if (!(cf->cp < endof(cf->buffer)))
5819 } /* dns_anyconf_addc() */
5822 static _Bool dns_anyconf_match(const char *pat, int mc) {
5833 while ((pc = *(const unsigned char *)pat++)) {
5836 if (!(pc = *(const unsigned char *)pat++))
5841 if (dns_isalpha(mc))
5845 if (dns_isdigit(mc))
5849 if (dns_isalnum(mc))
5853 if (dns_isspace(mc))
5871 } /* dns_anyconf_match() */
5874 static int dns_anyconf_peek(FILE *fp) {
5879 } /* dns_anyconf_peek() */
5882 static size_t dns_anyconf_skip(const char *pat, FILE *fp) {
5886 while (EOF != (ch = getc(fp))) {
5887 if (dns_anyconf_match(pat, ch)) {
5898 } /* dns_anyconf_skip() */
5901 static size_t dns_anyconf_scan(struct dns_anyconf *cf, const char *pat, FILE *fp, int *error) {
5905 while (EOF != (ch = getc(fp))) {
5906 if (dns_anyconf_match(pat, ch)) {
5907 if ((*error = dns_anyconf_addc(cf, ch)))
5918 if ((len = cf->cp - cf->tp)) {
5919 if ((*error = dns_anyconf_push(cf)))
5928 } /* dns_anyconf_scan() */
5931 DNS_NOTUSED static void dns_anyconf_dump(struct dns_anyconf *cf, FILE *fp) {
5934 fprintf(fp, "tokens:");
5936 for (i = 0; i < cf->count; i++) {
5937 fprintf(fp, " %s", cf->token[i]);
5941 } /* dns_anyconf_dump() */
5944 enum dns_nssconf_keyword {
5945 DNS_NSSCONF_INVALID = 0,
5946 DNS_NSSCONF_HOSTS = 1,
5947 DNS_NSSCONF_SUCCESS,
5948 DNS_NSSCONF_NOTFOUND,
5949 DNS_NSSCONF_UNAVAIL,
5950 DNS_NSSCONF_TRYAGAIN,
5951 DNS_NSSCONF_CONTINUE,
5958 }; /* enum dns_nssconf_keyword */
5960 static enum dns_nssconf_keyword dns_nssconf_keyword(const char *word) {
5961 static const char *list[] = {
5962 [DNS_NSSCONF_HOSTS] = "hosts",
5963 [DNS_NSSCONF_SUCCESS] = "success",
5964 [DNS_NSSCONF_NOTFOUND] = "notfound",
5965 [DNS_NSSCONF_UNAVAIL] = "unavail",
5966 [DNS_NSSCONF_TRYAGAIN] = "tryagain",
5967 [DNS_NSSCONF_CONTINUE] = "continue",
5968 [DNS_NSSCONF_RETURN] = "return",
5969 [DNS_NSSCONF_FILES] = "files",
5970 [DNS_NSSCONF_DNS] = "dns",
5971 [DNS_NSSCONF_MDNS] = "mdns",
5975 for (i = 1; i < lengthof(list); i++) {
5976 if (list[i] && 0 == strcasecmp(list[i], word))
5980 return DNS_NSSCONF_INVALID;
5981 } /* dns_nssconf_keyword() */
5984 static enum dns_nssconf_keyword dns_nssconf_c2k(int ch) {
5985 static const char map[] = {
5986 ['S'] = DNS_NSSCONF_SUCCESS,
5987 ['N'] = DNS_NSSCONF_NOTFOUND,
5988 ['U'] = DNS_NSSCONF_UNAVAIL,
5989 ['T'] = DNS_NSSCONF_TRYAGAIN,
5990 ['C'] = DNS_NSSCONF_CONTINUE,
5991 ['R'] = DNS_NSSCONF_RETURN,
5992 ['f'] = DNS_NSSCONF_FILES,
5993 ['F'] = DNS_NSSCONF_FILES,
5994 ['d'] = DNS_NSSCONF_DNS,
5995 ['D'] = DNS_NSSCONF_DNS,
5996 ['b'] = DNS_NSSCONF_DNS,
5997 ['B'] = DNS_NSSCONF_DNS,
5998 ['m'] = DNS_NSSCONF_MDNS,
5999 ['M'] = DNS_NSSCONF_MDNS,
6002 return (ch >= 0 && ch < (int)lengthof(map))? map[ch] : DNS_NSSCONF_INVALID;
6003 } /* dns_nssconf_c2k() */
6009 static int dns_nssconf_k2c(int k) {
6010 static const char map[DNS_NSSCONF_LAST] = {
6011 [DNS_NSSCONF_SUCCESS] = 'S',
6012 [DNS_NSSCONF_NOTFOUND] = 'N',
6013 [DNS_NSSCONF_UNAVAIL] = 'U',
6014 [DNS_NSSCONF_TRYAGAIN] = 'T',
6015 [DNS_NSSCONF_CONTINUE] = 'C',
6016 [DNS_NSSCONF_RETURN] = 'R',
6017 [DNS_NSSCONF_FILES] = 'f',
6018 [DNS_NSSCONF_DNS] = 'b',
6019 [DNS_NSSCONF_MDNS] = 'm',
6022 return (k >= 0 && k < (int)lengthof(map))? (map[k]? map[k] : '?') : '?';
6023 } /* dns_nssconf_k2c() */
6025 static const char *dns_nssconf_k2s(int k) {
6026 static const char *const map[DNS_NSSCONF_LAST] = {
6027 [DNS_NSSCONF_SUCCESS] = "SUCCESS",
6028 [DNS_NSSCONF_NOTFOUND] = "NOTFOUND",
6029 [DNS_NSSCONF_UNAVAIL] = "UNAVAIL",
6030 [DNS_NSSCONF_TRYAGAIN] = "TRYAGAIN",
6031 [DNS_NSSCONF_CONTINUE] = "continue",
6032 [DNS_NSSCONF_RETURN] = "return",
6033 [DNS_NSSCONF_FILES] = "files",
6034 [DNS_NSSCONF_DNS] = "dns",
6035 [DNS_NSSCONF_MDNS] = "mdns",
6038 return (k >= 0 && k < (int)lengthof(map))? (map[k]? map[k] : "") : "";
6039 } /* dns_nssconf_k2s() */
6044 int dns_nssconf_loadfile(struct dns_resolv_conf *resconf, FILE *fp) {
6045 enum dns_nssconf_keyword source, status, action;
6046 char lookup[sizeof resconf->lookup] = "", *lp;
6047 struct dns_anyconf cf;
6051 while (!feof(fp) && !ferror(fp)) {
6052 dns_anyconf_reset(&cf);
6054 dns_anyconf_skip("%s", fp);
6056 if (!dns_anyconf_scan(&cf, "%w_", fp, &error))
6059 if (DNS_NSSCONF_HOSTS != dns_nssconf_keyword(cf.token[0]))
6062 dns_anyconf_pop(&cf);
6064 if (!dns_anyconf_skip(": \t", fp))
6067 *(lp = lookup) = '\0';
6069 while (dns_anyconf_scan(&cf, "%w_", fp, &error)) {
6070 dns_anyconf_skip(" \t", fp);
6072 if ('[' == dns_anyconf_peek(fp)) {
6073 dns_anyconf_skip("[ \t", fp);
6076 if ('!' == dns_anyconf_peek(fp)) {
6077 dns_anyconf_skip("! \t", fp);
6078 /* FIXME: negating statuses; currently not implemented */
6079 dns_anyconf_skip("^#;]\n", fp); /* skip to end of criteria */
6083 if (!dns_anyconf_scan(&cf, "%w_", fp, &error)) break;
6084 dns_anyconf_skip("= \t", fp);
6085 if (!dns_anyconf_scan(&cf, "%w_", fp, &error)) {
6086 dns_anyconf_pop(&cf); /* discard status */
6087 dns_anyconf_skip("^#;]\n", fp); /* skip to end of criteria */
6090 dns_anyconf_skip(" \t", fp);
6093 dns_anyconf_skip("] \t", fp);
6096 if ((size_t)(endof(lookup) - lp) < cf.count + 1) /* +1 for '\0' */
6099 source = dns_nssconf_keyword(cf.token[0]);
6102 case DNS_NSSCONF_DNS:
6103 case DNS_NSSCONF_MDNS:
6104 case DNS_NSSCONF_FILES:
6105 *lp++ = dns_nssconf_k2c(source);
6111 for (i = 1; i + 1 < cf.count; i += 2) {
6112 status = dns_nssconf_keyword(cf.token[i]);
6113 action = dns_nssconf_keyword(cf.token[i + 1]);
6116 case DNS_NSSCONF_SUCCESS:
6117 case DNS_NSSCONF_NOTFOUND:
6118 case DNS_NSSCONF_UNAVAIL:
6119 case DNS_NSSCONF_TRYAGAIN:
6120 *lp++ = dns_nssconf_k2c(status);
6127 case DNS_NSSCONF_CONTINUE:
6128 case DNS_NSSCONF_RETURN:
6131 action = (status == DNS_NSSCONF_SUCCESS)
6132 ? DNS_NSSCONF_RETURN
6133 : DNS_NSSCONF_CONTINUE;
6137 *lp++ = dns_nssconf_k2c(action);
6141 dns_anyconf_reset(&cf);
6144 dns_anyconf_skip("^\n", fp);
6148 strncpy(resconf->lookup, lookup, sizeof resconf->lookup);
6151 } /* dns_nssconf_loadfile() */
6154 int dns_nssconf_loadpath(struct dns_resolv_conf *resconf, const char *path) {
6158 if (!(fp = dns_fopen(path, "rt", &error)))
6161 error = dns_nssconf_loadfile(resconf, fp);
6166 } /* dns_nssconf_loadpath() */
6169 struct dns_nssconf_source {
6170 enum dns_nssconf_keyword source, success, notfound, unavail, tryagain;
6171 }; /* struct dns_nssconf_source */
6173 typedef unsigned dns_nssconf_i;
6175 static inline int dns_nssconf_peek(const struct dns_resolv_conf *resconf, dns_nssconf_i state) {
6176 return (state < lengthof(resconf->lookup) && resconf->lookup[state])? resconf->lookup[state] : 0;
6177 } /* dns_nssconf_peek() */
6179 static _Bool dns_nssconf_next(struct dns_nssconf_source *src, const struct dns_resolv_conf *resconf, dns_nssconf_i *state) {
6180 int source, status, action;
6182 src->source = DNS_NSSCONF_INVALID;
6183 src->success = DNS_NSSCONF_RETURN;
6184 src->notfound = DNS_NSSCONF_CONTINUE;
6185 src->unavail = DNS_NSSCONF_CONTINUE;
6186 src->tryagain = DNS_NSSCONF_CONTINUE;
6188 while ((source = dns_nssconf_peek(resconf, *state))) {
6189 source = dns_nssconf_c2k(source);
6193 case DNS_NSSCONF_FILES:
6194 case DNS_NSSCONF_DNS:
6195 case DNS_NSSCONF_MDNS:
6196 src->source = source;
6202 while ((status = dns_nssconf_peek(resconf, *state)) && (action = dns_nssconf_peek(resconf, *state + 1))) {
6203 status = dns_nssconf_c2k(status);
6204 action = dns_nssconf_c2k(action);
6207 case DNS_NSSCONF_RETURN:
6208 case DNS_NSSCONF_CONTINUE:
6215 case DNS_NSSCONF_SUCCESS:
6216 src->success = action;
6218 case DNS_NSSCONF_NOTFOUND:
6219 src->notfound = action;
6221 case DNS_NSSCONF_UNAVAIL:
6222 src->unavail = action;
6224 case DNS_NSSCONF_TRYAGAIN:
6225 src->tryagain = action;
6237 return src->source != DNS_NSSCONF_INVALID;
6238 } /* dns_nssconf_next() */
6241 static int dns_nssconf_dump_status(int status, int action, unsigned *count, FILE *fp) {
6243 case DNS_NSSCONF_SUCCESS:
6244 if (action == DNS_NSSCONF_RETURN)
6248 if (action == DNS_NSSCONF_CONTINUE)
6258 fprintf(fp, "%s=%s", dns_nssconf_k2s(status), dns_nssconf_k2s(action));
6263 } /* dns_nssconf_dump_status() */
6266 int dns_nssconf_dump(struct dns_resolv_conf *resconf, FILE *fp) {
6267 struct dns_nssconf_source src;
6268 dns_nssconf_i i = 0;
6270 fputs("hosts:", fp);
6272 while (dns_nssconf_next(&src, resconf, &i)) {
6275 fprintf(fp, " %s", dns_nssconf_k2s(src.source));
6277 dns_nssconf_dump_status(DNS_NSSCONF_SUCCESS, src.success, &n, fp);
6278 dns_nssconf_dump_status(DNS_NSSCONF_NOTFOUND, src.notfound, &n, fp);
6279 dns_nssconf_dump_status(DNS_NSSCONF_UNAVAIL, src.unavail, &n, fp);
6280 dns_nssconf_dump_status(DNS_NSSCONF_TRYAGAIN, src.tryagain, &n, fp);
6289 } /* dns_nssconf_dump() */
6292 int dns_resconf_setiface(struct dns_resolv_conf *resconf, const char *addr, unsigned short port) {
6293 int af = (strchr(addr, ':'))? AF_INET6 : AF_INET;
6296 if ((error = dns_pton(af, addr, dns_sa_addr(af, &resconf->iface, NULL))))
6299 *dns_sa_port(af, &resconf->iface) = htons(port);
6300 resconf->iface.ss_family = af;
6303 } /* dns_resconf_setiface() */
6306 #define DNS_SM_RESTORE \
6308 pc = 0xff & (*state >> 0); \
6309 srchi = 0xff & (*state >> 8); \
6310 ndots = 0xff & (*state >> 16); \
6313 #define DNS_SM_SAVE \
6315 *state = ((0xff & pc) << 0) \
6316 | ((0xff & srchi) << 8) \
6317 | ((0xff & ndots) << 16); \
6320 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) {
6321 unsigned pc, srchi, ndots, len;
6325 /* if FQDN then return as-is and finish */
6326 if (dns_d_isanchored(qname, qlen)) {
6327 len = dns_d_anchor(dst, lim, qname, qlen);
6332 ndots = dns_d_ndots(qname, qlen);
6334 if (ndots >= resconf->options.ndots) {
6335 len = dns_d_anchor(dst, lim, qname, qlen);
6339 while (srchi < lengthof(resconf->search) && resconf->search[srchi][0]) {
6340 struct dns_buf buf = DNS_B_INTO(dst, lim);
6341 const char *dn = resconf->search[srchi++];
6343 dns_b_put(&buf, qname, qlen);
6344 dns_b_putc(&buf, '.');
6345 dns_b_puts(&buf, dn);
6346 if (!dns_d_isanchored(dn, strlen(dn)))
6347 dns_b_putc(&buf, '.');
6348 len = dns_b_strllen(&buf);
6352 if (ndots < resconf->options.ndots) {
6353 len = dns_d_anchor(dst, lim, qname, qlen);
6359 return dns_strlcpy(dst, "", lim);
6360 } /* dns_resconf_search() */
6363 #undef DNS_SM_RESTORE
6366 int dns_resconf_dump(struct dns_resolv_conf *resconf, FILE *fp) {
6370 for (i = 0; i < lengthof(resconf->nameserver) && (af = resconf->nameserver[i].ss_family) != AF_UNSPEC; i++) {
6371 char addr[INET6_ADDRSTRLEN + 1] = "[INVALID]";
6372 unsigned short port;
6374 dns_inet_ntop(af, dns_sa_addr(af, &resconf->nameserver[i], NULL), addr, sizeof addr);
6375 port = ntohs(*dns_sa_port(af, &resconf->nameserver[i]));
6378 fprintf(fp, "nameserver %s\n", addr);
6380 fprintf(fp, "nameserver [%s]:%hu\n", addr, port);
6384 fprintf(fp, "search");
6386 for (i = 0; i < lengthof(resconf->search) && resconf->search[i][0]; i++)
6387 fprintf(fp, " %s", resconf->search[i]);
6393 dns_nssconf_dump(resconf, fp);
6395 fprintf(fp, "lookup");
6397 for (i = 0; i < lengthof(resconf->lookup) && resconf->lookup[i]; i++) {
6398 switch (resconf->lookup[i]) {
6400 fprintf(fp, " bind"); break;
6402 fprintf(fp, " file"); break;
6404 fprintf(fp, " cache"); break;
6411 fprintf(fp, "options ndots:%u timeout:%u attempts:%u", resconf->options.ndots, resconf->options.timeout, resconf->options.attempts);
6413 if (resconf->options.edns0)
6414 fprintf(fp, " edns0");
6415 if (resconf->options.rotate)
6416 fprintf(fp, " rotate");
6417 if (resconf->options.recurse)
6418 fprintf(fp, " recurse");
6419 if (resconf->options.smart)
6420 fprintf(fp, " smart");
6422 switch (resconf->options.tcp) {
6423 case DNS_RESCONF_TCP_ENABLE:
6425 case DNS_RESCONF_TCP_ONLY:
6426 fprintf(fp, " tcp");
6428 case DNS_RESCONF_TCP_SOCKS:
6429 fprintf(fp, " tcp:socks");
6431 case DNS_RESCONF_TCP_DISABLE:
6432 fprintf(fp, " tcp:disable");
6439 if ((af = resconf->iface.ss_family) != AF_UNSPEC) {
6440 char addr[INET6_ADDRSTRLEN + 1] = "[INVALID]";
6442 dns_inet_ntop(af, dns_sa_addr(af, &resconf->iface, NULL), addr, sizeof addr);
6444 fprintf(fp, "interface %s %hu\n", addr, ntohs(*dns_sa_port(af, &resconf->iface)));
6448 } /* dns_resconf_dump() */
6452 * H I N T S E R V E R R O U T I N E S
6454 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6456 struct dns_hints_soa {
6457 unsigned char zone[DNS_D_MAXNAME + 1];
6460 struct sockaddr_storage ss;
6466 struct dns_hints_soa *next;
6467 }; /* struct dns_hints_soa */
6471 dns_atomic_t refcount;
6473 struct dns_hints_soa *head;
6474 }; /* struct dns_hints */
6477 struct dns_hints *dns_hints_open(struct dns_resolv_conf *resconf, int *error) {
6478 static const struct dns_hints H_initializer;
6479 struct dns_hints *H;
6483 if (!(H = malloc(sizeof *H)))
6488 dns_hints_acquire(H);
6492 *error = dns_syerr();
6497 } /* dns_hints_open() */
6500 void dns_hints_close(struct dns_hints *H) {
6501 struct dns_hints_soa *soa, *nxt;
6503 if (!H || 1 != dns_hints_release(H))
6506 for (soa = H->head; soa; soa = nxt) {
6515 } /* dns_hints_close() */
6518 dns_refcount_t dns_hints_acquire(struct dns_hints *H) {
6519 return dns_atomic_fetch_add(&H->refcount);
6520 } /* dns_hints_acquire() */
6523 dns_refcount_t dns_hints_release(struct dns_hints *H) {
6524 return dns_atomic_fetch_sub(&H->refcount);
6525 } /* dns_hints_release() */
6528 struct dns_hints *dns_hints_mortal(struct dns_hints *hints) {
6530 dns_hints_release(hints);
6533 } /* dns_hints_mortal() */
6536 struct dns_hints *dns_hints_local(struct dns_resolv_conf *resconf, int *error_) {
6537 struct dns_hints *hints = 0;
6541 dns_resconf_acquire(resconf);
6542 else if (!(resconf = dns_resconf_local(&error)))
6545 if (!(hints = dns_hints_open(resconf, &error)))
6550 if (0 == dns_hints_insert_resconf(hints, ".", resconf, &error) && error)
6553 dns_resconf_close(resconf);
6559 dns_resconf_close(resconf);
6560 dns_hints_close(hints);
6563 } /* dns_hints_local() */
6566 struct dns_hints *dns_hints_root(struct dns_resolv_conf *resconf, int *error_) {
6567 static const struct {
6569 char addr[INET6_ADDRSTRLEN];
6571 { AF_INET, "198.41.0.4" }, /* A.ROOT-SERVERS.NET. */
6572 { AF_INET6, "2001:503:ba3e::2:30" }, /* A.ROOT-SERVERS.NET. */
6573 { AF_INET, "192.228.79.201" }, /* B.ROOT-SERVERS.NET. */
6574 { AF_INET6, "2001:500:84::b" }, /* B.ROOT-SERVERS.NET. */
6575 { AF_INET, "192.33.4.12" }, /* C.ROOT-SERVERS.NET. */
6576 { AF_INET6, "2001:500:2::c" }, /* C.ROOT-SERVERS.NET. */
6577 { AF_INET, "199.7.91.13" }, /* D.ROOT-SERVERS.NET. */
6578 { AF_INET6, "2001:500:2d::d" }, /* D.ROOT-SERVERS.NET. */
6579 { AF_INET, "192.203.230.10" }, /* E.ROOT-SERVERS.NET. */
6580 { AF_INET, "192.5.5.241" }, /* F.ROOT-SERVERS.NET. */
6581 { AF_INET6, "2001:500:2f::f" }, /* F.ROOT-SERVERS.NET. */
6582 { AF_INET, "192.112.36.4" }, /* G.ROOT-SERVERS.NET. */
6583 { AF_INET, "128.63.2.53" }, /* H.ROOT-SERVERS.NET. */
6584 { AF_INET6, "2001:500:1::803f:235" }, /* H.ROOT-SERVERS.NET. */
6585 { AF_INET, "192.36.148.17" }, /* I.ROOT-SERVERS.NET. */
6586 { AF_INET6, "2001:7FE::53" }, /* I.ROOT-SERVERS.NET. */
6587 { AF_INET, "192.58.128.30" }, /* J.ROOT-SERVERS.NET. */
6588 { AF_INET6, "2001:503:c27::2:30" }, /* J.ROOT-SERVERS.NET. */
6589 { AF_INET, "193.0.14.129" }, /* K.ROOT-SERVERS.NET. */
6590 { AF_INET6, "2001:7FD::1" }, /* K.ROOT-SERVERS.NET. */
6591 { AF_INET, "199.7.83.42" }, /* L.ROOT-SERVERS.NET. */
6592 { AF_INET6, "2001:500:3::42" }, /* L.ROOT-SERVERS.NET. */
6593 { AF_INET, "202.12.27.33" }, /* M.ROOT-SERVERS.NET. */
6594 { AF_INET6, "2001:DC3::35" }, /* M.ROOT-SERVERS.NET. */
6596 struct dns_hints *hints = 0;
6597 struct sockaddr_storage ss;
6601 if (!(hints = dns_hints_open(resconf, &error)))
6604 for (i = 0; i < lengthof(root_hints); i++) {
6605 af = root_hints[i].af;
6607 if ((error = dns_pton(af, root_hints[i].addr, dns_sa_addr(af, &ss, NULL))))
6610 *dns_sa_port(af, &ss) = htons(53);
6613 if ((error = dns_hints_insert(hints, ".", (struct sockaddr *)&ss, 1)))
6621 dns_hints_close(hints);
6624 } /* dns_hints_root() */
6627 static struct dns_hints_soa *dns_hints_fetch(struct dns_hints *H, const char *zone) {
6628 struct dns_hints_soa *soa;
6630 for (soa = H->head; soa; soa = soa->next) {
6631 if (0 == strcasecmp(zone, (char *)soa->zone))
6636 } /* dns_hints_fetch() */
6639 int dns_hints_insert(struct dns_hints *H, const char *zone, const struct sockaddr *sa, unsigned priority) {
6640 static const struct dns_hints_soa soa_initializer;
6641 struct dns_hints_soa *soa;
6644 if (!(soa = dns_hints_fetch(H, zone))) {
6645 if (!(soa = malloc(sizeof *soa)))
6647 *soa = soa_initializer;
6648 dns_strlcpy((char *)soa->zone, zone, sizeof soa->zone);
6650 soa->next = H->head;
6654 i = soa->count % lengthof(soa->addrs);
6656 memcpy(&soa->addrs[i].ss, sa, dns_sa_len(sa));
6658 soa->addrs[i].priority = DNS_PP_MAX(1, priority);
6660 if (soa->count < lengthof(soa->addrs))
6664 } /* dns_hints_insert() */
6667 static _Bool dns_hints_isinaddr_any(const void *sa) {
6668 struct in_addr *addr;
6670 if (dns_sa_family(sa) != AF_INET)
6673 addr = dns_sa_addr(AF_INET, sa, NULL);
6674 return addr->s_addr == htonl(INADDR_ANY);
6677 unsigned dns_hints_insert_resconf(struct dns_hints *H, const char *zone, const struct dns_resolv_conf *resconf, int *error_) {
6681 for (i = 0, n = 0, p = 1; i < lengthof(resconf->nameserver) && resconf->nameserver[i].ss_family != AF_UNSPEC; i++, n++) {
6682 union { struct sockaddr_in sin; } tmp;
6683 struct sockaddr *ns;
6686 * dns_resconf_open initializes nameserver[0] to INADDR_ANY.
6688 * Traditionally the semantics of 0.0.0.0 meant the default
6689 * interface, which evolved to mean the loopback interface.
6690 * See comment block preceding resolv/res_init.c:res_init in
6691 * glibc 2.23. As of 2.23, glibc no longer translates
6692 * 0.0.0.0 despite the code comment, but it does default to
6693 * 127.0.0.1 when no nameservers are present.
6695 * BIND9 as of 9.10.3 still translates 0.0.0.0 to 127.0.0.1.
6696 * See lib/lwres/lwconfig.c:lwres_create_addr and the
6697 * convert_zero flag. 127.0.0.1 is also the default when no
6698 * nameservers are present.
6700 if (dns_hints_isinaddr_any(&resconf->nameserver[i])) {
6701 memcpy(&tmp.sin, &resconf->nameserver[i], sizeof tmp.sin);
6702 tmp.sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
6703 ns = (struct sockaddr *)&tmp.sin;
6705 ns = (struct sockaddr *)&resconf->nameserver[i];
6708 if ((error = dns_hints_insert(H, zone, ns, p)))
6711 p += !resconf->options.rotate;
6719 } /* dns_hints_insert_resconf() */
6722 static int dns_hints_i_cmp(unsigned a, unsigned b, struct dns_hints_i *i, struct dns_hints_soa *soa) {
6725 if ((cmp = soa->addrs[a].priority - soa->addrs[b].priority))
6728 return dns_k_shuffle16(a, i->state.seed) - dns_k_shuffle16(b, i->state.seed);
6729 } /* dns_hints_i_cmp() */
6732 static unsigned dns_hints_i_start(struct dns_hints_i *i, struct dns_hints_soa *soa) {
6737 for (p = 1; p < soa->count; p++) {
6738 if (dns_hints_i_cmp(p, p0, i, soa) < 0)
6743 } /* dns_hints_i_start() */
6746 static unsigned dns_hints_i_skip(unsigned p0, struct dns_hints_i *i, struct dns_hints_soa *soa) {
6749 for (pZ = 0; pZ < soa->count; pZ++) {
6750 if (dns_hints_i_cmp(pZ, p0, i, soa) > 0)
6756 for (p = pZ + 1; p < soa->count; p++) {
6757 if (dns_hints_i_cmp(p, p0, i, soa) <= 0)
6760 if (dns_hints_i_cmp(p, pZ, i, soa) >= 0)
6768 } /* dns_hints_i_skip() */
6771 static struct dns_hints_i *dns_hints_i_init(struct dns_hints_i *i, struct dns_hints *hints) {
6772 static const struct dns_hints_i i_initializer;
6773 struct dns_hints_soa *soa;
6775 i->state = i_initializer.state;
6778 i->state.seed = dns_random();
6779 } while (0 == i->state.seed);
6781 if ((soa = dns_hints_fetch(hints, i->zone))) {
6782 i->state.next = dns_hints_i_start(i, soa);
6786 } /* dns_hints_i_init() */
6789 unsigned dns_hints_grep(struct sockaddr **sa, socklen_t *sa_len, unsigned lim, struct dns_hints_i *i, struct dns_hints *H) {
6790 struct dns_hints_soa *soa;
6793 if (!(soa = dns_hints_fetch(H, i->zone)))
6798 while (i->state.next < soa->count && n < lim) {
6799 *sa = (struct sockaddr *)&soa->addrs[i->state.next].ss;
6800 *sa_len = dns_sa_len(*sa);
6806 i->state.next = dns_hints_i_skip(i->state.next, i, soa);
6810 } /* dns_hints_grep() */
6813 struct dns_packet *dns_hints_query(struct dns_hints *hints, struct dns_packet *Q, int *error_) {
6814 struct dns_packet *A, *P;
6816 char zone[DNS_D_MAXNAME + 1];
6818 struct dns_hints_i i;
6819 struct sockaddr *sa;
6823 if (!dns_rr_grep(&rr, 1, dns_rr_i_new(Q, .section = DNS_S_QUESTION), Q, &error))
6826 if (!(zlen = dns_d_expand(zone, sizeof zone, rr.dn.p, Q, &error)))
6828 else if (zlen >= sizeof zone)
6832 dns_header(P)->qr = 1;
6834 if ((error = dns_rr_copy(P, &rr, Q)))
6837 if ((error = dns_p_push(P, DNS_S_AUTHORITY, ".", strlen("."), DNS_T_NS, DNS_C_IN, 0, "hints.local.")))
6843 dns_hints_i_init(&i, hints);
6845 while (dns_hints_grep(&sa, &slen, 1, &i, hints)) {
6846 int af = sa->sa_family;
6847 int rtype = (af == AF_INET6)? DNS_T_AAAA : DNS_T_A;
6849 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))))
6852 } while ((zlen = dns_d_cleave(zone, sizeof zone, zone, zlen)));
6854 if (!(A = dns_p_copy(dns_p_make(P->end, &error), P)))
6859 error = DNS_EILLEGAL;
6864 } /* dns_hints_query() */
6867 /** ugly hack to support specifying ports other than 53 in resolv.conf. */
6868 static unsigned short dns_hints_port(struct dns_hints *hints, int af, void *addr) {
6869 struct dns_hints_soa *soa;
6872 unsigned short port;
6875 for (soa = hints->head; soa; soa = soa->next) {
6876 for (i = 0; i < soa->count; i++) {
6877 if (af != soa->addrs[i].ss.ss_family)
6880 if (!(addrsoa = dns_sa_addr(af, &soa->addrs[i].ss, &addrlen)))
6883 if (memcmp(addr, addrsoa, addrlen))
6886 port = *dns_sa_port(af, &soa->addrs[i].ss);
6888 return (port)? port : htons(53);
6893 } /* dns_hints_port() */
6896 int dns_hints_dump(struct dns_hints *hints, FILE *fp) {
6897 struct dns_hints_soa *soa;
6898 char addr[INET6_ADDRSTRLEN];
6902 for (soa = hints->head; soa; soa = soa->next) {
6903 fprintf(fp, "ZONE \"%s\"\n", soa->zone);
6905 for (i = 0; i < soa->count; i++) {
6906 af = soa->addrs[i].ss.ss_family;
6908 if ((error = dns_ntop(af, dns_sa_addr(af, &soa->addrs[i].ss, NULL), addr, sizeof addr)))
6911 fprintf(fp, "\t(%d) [%s]:%hu\n", (int)soa->addrs[i].priority, addr, ntohs(*dns_sa_port(af, &soa->addrs[i].ss)));
6916 } /* dns_hints_dump() */
6920 * C A C H E R O U T I N E S
6922 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6924 static dns_refcount_t dns_cache_acquire(struct dns_cache *cache) {
6925 return dns_atomic_fetch_add(&cache->_.refcount);
6926 } /* dns_cache_acquire() */
6929 static dns_refcount_t dns_cache_release(struct dns_cache *cache) {
6930 return dns_atomic_fetch_sub(&cache->_.refcount);
6931 } /* dns_cache_release() */
6934 static struct dns_packet *dns_cache_query(struct dns_packet *query, struct dns_cache *cache, int *error) {
6940 } /* dns_cache_query() */
6943 static int dns_cache_submit(struct dns_packet *query, struct dns_cache *cache) {
6948 } /* dns_cache_submit() */
6951 static int dns_cache_check(struct dns_cache *cache) {
6955 } /* dns_cache_check() */
6958 static struct dns_packet *dns_cache_fetch(struct dns_cache *cache, int *error) {
6963 } /* dns_cache_fetch() */
6966 static int dns_cache_pollfd(struct dns_cache *cache) {
6970 } /* dns_cache_pollfd() */
6973 static short dns_cache_events(struct dns_cache *cache) {
6977 } /* dns_cache_events() */
6980 static void dns_cache_clear(struct dns_cache *cache) {
6984 } /* dns_cache_clear() */
6987 struct dns_cache *dns_cache_init(struct dns_cache *cache) {
6988 static const struct dns_cache c_init = {
6989 .acquire = &dns_cache_acquire,
6990 .release = &dns_cache_release,
6991 .query = &dns_cache_query,
6992 .submit = &dns_cache_submit,
6993 .check = &dns_cache_check,
6994 .fetch = &dns_cache_fetch,
6995 .pollfd = &dns_cache_pollfd,
6996 .events = &dns_cache_events,
6997 .clear = &dns_cache_clear,
6998 ._ = { .refcount = 1, },
7004 } /* dns_cache_init() */
7007 void dns_cache_close(struct dns_cache *cache) {
7009 cache->release(cache);
7010 } /* dns_cache_close() */
7014 * S O C K E T R O U T I N E S
7016 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7018 static void dns_socketclose(int *fd, const struct dns_options *opts) {
7019 if (opts && opts->closefd.cb)
7020 opts->closefd.cb(fd, opts->closefd.arg);
7030 } /* dns_socketclose() */
7033 #ifndef HAVE_IOCTLSOCKET
7034 #define HAVE_IOCTLSOCKET (_WIN32 || _WIN64)
7037 #ifndef HAVE_SOCK_CLOEXEC
7038 #define HAVE_SOCK_CLOEXEC (defined SOCK_CLOEXEC)
7041 #ifndef HAVE_SOCK_NONBLOCK
7042 #define HAVE_SOCK_NONBLOCK (defined SOCK_NONBLOCK)
7045 #define DNS_SO_MAXTRY 7
7047 static int dns_socket(struct sockaddr *local, int type, int *error_) {
7048 int fd = -1, flags, error;
7054 #if HAVE_SOCK_CLOEXEC
7055 flags |= SOCK_CLOEXEC;
7057 #if HAVE_SOCK_NONBLOCK
7058 flags |= SOCK_NONBLOCK;
7060 if (-1 == (fd = socket(local->sa_family, type|flags, 0)))
7063 #if defined F_SETFD && !HAVE_SOCK_CLOEXEC
7064 if (-1 == fcntl(fd, F_SETFD, 1))
7068 #if defined O_NONBLOCK && !HAVE_SOCK_NONBLOCK
7069 if (-1 == (flags = fcntl(fd, F_GETFL)))
7071 if (-1 == fcntl(fd, F_SETFL, flags | O_NONBLOCK))
7073 #elif defined FIONBIO && HAVE_IOCTLSOCKET
7075 if (0 != ioctlsocket(fd, FIONBIO, &opt))
7079 #if defined SO_NOSIGPIPE
7080 if (type != SOCK_DGRAM) {
7081 if (0 != setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &(int){ 1 }, sizeof (int)))
7086 if (local->sa_family != AF_INET && local->sa_family != AF_INET6)
7089 if (type != SOCK_DGRAM)
7093 * FreeBSD, Linux, OpenBSD, OS X, and Solaris use random ports by
7094 * default. Though the ephemeral range is quite small on OS X
7095 * (49152-65535 on 10.10) and Linux (32768-60999 on 4.4.0, Ubuntu
7096 * Xenial). See also RFC 6056.
7098 * TODO: Optionally rely on the kernel to select a random port.
7100 if (*dns_sa_port(local->sa_family, local) == 0) {
7101 struct sockaddr_storage tmp;
7104 memcpy(&tmp, local, dns_sa_len(local));
7106 for (i = 0; i < DNS_SO_MAXTRY; i++) {
7107 port = 1025 + (dns_random() % 64510);
7109 *dns_sa_port(tmp.ss_family, &tmp) = htons(port);
7111 if (0 == bind(fd, (struct sockaddr *)&tmp, dns_sa_len(&tmp)))
7115 /* NB: continue to next bind statement */
7118 if (0 == bind(fd, local, dns_sa_len(local)))
7123 error = dns_soerr();
7126 #if (defined F_SETFD && !HAVE_SOCK_CLOEXEC) || (defined O_NONBLOCK && !HAVE_SOCK_NONBLOCK)
7128 error = dns_syerr();
7135 dns_socketclose(&fd, NULL);
7138 } /* dns_socket() */
7142 DNS_SO_UDP_INIT = 1,
7156 DNS_SO_SOCKS_HELLO_SEND,
7157 DNS_SO_SOCKS_HELLO_RECV,
7158 DNS_SO_SOCKS_AUTH_SEND,
7159 DNS_SO_SOCKS_AUTH_RECV,
7160 DNS_SO_SOCKS_REQUEST_PREPARE,
7161 DNS_SO_SOCKS_REQUEST_SEND,
7162 DNS_SO_SOCKS_REQUEST_RECV,
7163 DNS_SO_SOCKS_REQUEST_RECV_V6,
7164 DNS_SO_SOCKS_HANDSHAKE_DONE,
7168 struct dns_options opts;
7174 unsigned onum, olim;
7178 struct sockaddr_storage local, remote;
7180 struct dns_k_permutor qids;
7182 struct dns_stat stat;
7184 struct dns_trace *trace;
7187 * NOTE: dns_so_reset() zeroes everything from here down.
7192 char qname[DNS_D_MAXNAME + 1];
7194 enum dns_type qtype;
7195 enum dns_class qclass;
7197 struct dns_packet *query;
7200 /* During a SOCKS handshake the query is temporarily stored
7202 struct dns_packet *query_backup;
7204 struct dns_clock elapsed;
7206 struct dns_packet *answer;
7208 }; /* struct dns_socket */
7212 * NOTE: Actual closure delayed so that kqueue(2) and epoll(2) callers have
7213 * a chance to recognize a state change after installing a persistent event
7214 * and where sequential descriptors with the same integer value returned
7215 * from _pollfd() would be ambiguous. See dns_so_closefds().
7217 static int dns_so_closefd(struct dns_socket *so, int *fd) {
7223 if (so->opts.closefd.cb) {
7224 if ((error = so->opts.closefd.cb(fd, so->opts.closefd.arg))) {
7226 } else if (*fd == -1)
7230 if (!(so->onum < so->olim)) {
7231 unsigned olim = DNS_PP_MAX(4, so->olim * 2);
7234 if (!(old = realloc(so->old, sizeof so->old[0] * olim)))
7241 so->old[so->onum++] = *fd;
7245 } /* dns_so_closefd() */
7248 #define DNS_SO_CLOSE_UDP 0x01
7249 #define DNS_SO_CLOSE_TCP 0x02
7250 #define DNS_SO_CLOSE_OLD 0x04
7251 #define DNS_SO_CLOSE_ALL (DNS_SO_CLOSE_UDP|DNS_SO_CLOSE_TCP|DNS_SO_CLOSE_OLD)
7253 static void dns_so_closefds(struct dns_socket *so, int which) {
7254 if (DNS_SO_CLOSE_UDP & which)
7255 dns_socketclose(&so->udp, &so->opts);
7256 if (DNS_SO_CLOSE_TCP & which)
7257 dns_socketclose(&so->tcp, &so->opts);
7258 if (DNS_SO_CLOSE_OLD & which) {
7260 for (i = 0; i < so->onum; i++)
7261 dns_socketclose(&so->old[i], &so->opts);
7267 } /* dns_so_closefds() */
7270 static void dns_so_destroy(struct dns_socket *);
7272 static struct dns_socket *dns_so_init(struct dns_socket *so, const struct sockaddr *local, int type, const struct dns_options *opts, int *error) {
7273 static const struct dns_socket so_initializer = { .opts = DNS_OPTS_INITIALIZER, .udp = -1, .tcp = -1, };
7275 *so = so_initializer;
7282 memcpy(&so->local, local, dns_sa_len(local));
7284 if (-1 == (so->udp = dns_socket((struct sockaddr *)&so->local, SOCK_DGRAM, error)))
7287 dns_k_permutor_init(&so->qids, 1, 65535);
7294 } /* dns_so_init() */
7297 struct dns_socket *dns_so_open(const struct sockaddr *local, int type, const struct dns_options *opts, int *error) {
7298 struct dns_socket *so;
7300 if (!(so = malloc(sizeof *so)))
7303 if (!dns_so_init(so, local, type, opts, error))
7308 *error = dns_syerr();
7313 } /* dns_so_open() */
7316 static void dns_so_destroy(struct dns_socket *so) {
7318 dns_so_closefds(so, DNS_SO_CLOSE_ALL);
7319 dns_trace_close(so->trace);
7320 } /* dns_so_destroy() */
7323 void dns_so_close(struct dns_socket *so) {
7330 } /* dns_so_close() */
7333 void dns_so_reset(struct dns_socket *so) {
7334 dns_p_setptr(&so->answer, NULL);
7336 memset(&so->state, '\0', sizeof *so - offsetof(struct dns_socket, state));
7337 } /* dns_so_reset() */
7340 unsigned short dns_so_mkqid(struct dns_socket *so) {
7341 return dns_k_permutor_step(&so->qids);
7342 } /* dns_so_mkqid() */
7345 #define DNS_SO_MINBUF 768
7347 static int dns_so_newanswer(struct dns_socket *so, size_t len) {
7348 size_t size = offsetof(struct dns_packet, data) + DNS_PP_MAX(len, DNS_SO_MINBUF);
7351 if (!(p = realloc(so->answer, size)))
7354 so->answer = dns_p_init(p, size);
7357 } /* dns_so_newanswer() */
7360 int dns_so_submit(struct dns_socket *so, struct dns_packet *Q, struct sockaddr *host) {
7362 int error = DNS_EUNKNOWN;
7366 if ((error = dns_rr_parse(&rr, 12, Q)))
7369 if (!(so->qlen = dns_d_expand(so->qname, sizeof so->qname, rr.dn.p, Q, &error)))
7372 * NOTE: Don't bail if expansion is too long; caller may be
7373 * intentionally sending long names. However, we won't be able to
7374 * verify it on return.
7377 so->qtype = rr.type;
7378 so->qclass = rr.class;
7380 if ((error = dns_so_newanswer(so, (Q->memo.opt.maxudp)? Q->memo.opt.maxudp : DNS_SO_MINBUF)))
7383 memcpy(&so->remote, host, dns_sa_len(host));
7388 dns_begin(&so->elapsed);
7390 if (dns_header(so->query)->qid == 0)
7391 dns_header(so->query)->qid = dns_so_mkqid(so);
7393 so->qid = dns_header(so->query)->qid;
7394 so->state = (so->opts.socks_host && so->opts.socks_host->ss_family) ? DNS_SO_SOCKS_INIT :
7395 (so->type == SOCK_STREAM)? DNS_SO_TCP_INIT : DNS_SO_UDP_INIT;
7398 dns_trace_so_submit(so->trace, Q, host, 0);
7402 error = dns_syerr();
7405 dns_trace_so_submit(so->trace, Q, host, error);
7407 } /* dns_so_submit() */
7410 static int dns_so_verify(struct dns_socket *so, struct dns_packet *P) {
7411 char qname[DNS_D_MAXNAME + 1];
7419 if (so->qid != dns_header(P)->qid)
7422 if (!dns_p_count(P, DNS_S_QD))
7425 if (0 != dns_rr_parse(&rr, 12, P))
7428 if (rr.type != so->qtype || rr.class != so->qclass)
7431 if (!(qlen = dns_d_expand(qname, sizeof qname, rr.dn.p, P, &error)))
7433 else if (qlen >= sizeof qname || qlen != so->qlen)
7436 if (0 != strcasecmp(so->qname, qname))
7439 dns_trace_so_verify(so->trace, P, 0);
7443 error = DNS_EVERIFY;
7445 DNS_SHOW(P, "rejecting packet (%s)", dns_strerror(error));
7446 dns_trace_so_verify(so->trace, P, error);
7449 } /* dns_so_verify() */
7452 static _Bool dns_so_tcp_keep(struct dns_socket *so) {
7453 struct sockaddr_storage remote;
7458 if (0 != getpeername(so->tcp, (struct sockaddr *)&remote, &(socklen_t){ sizeof remote }))
7461 return 0 == dns_sa_cmp(&remote, &so->remote);
7462 } /* dns_so_tcp_keep() */
7465 /* Convenience functions for sending non-DNS data. */
7467 /* Set up everything for sending LENGTH octets. Returns the buffer
7469 static unsigned char *dns_so_tcp_send_buffer(struct dns_socket *so, size_t length) {
7470 /* Skip the length octets, we are not doing DNS. */
7472 so->query->end = length;
7473 return so->query->data;
7476 /* Set up everything for receiving LENGTH octets. */
7477 static void dns_so_tcp_recv_expect(struct dns_socket *so, size_t length) {
7478 /* Skip the length octets, we are not doing DNS. */
7483 /* Returns the buffer containing the received data. */
7484 static unsigned char *dns_so_tcp_recv_buffer(struct dns_socket *so) {
7485 return so->answer->data;
7489 #if defined __clang__
7490 #pragma clang diagnostic push
7491 #pragma clang diagnostic ignored "-Warray-bounds"
7494 static int dns_so_tcp_send(struct dns_socket *so) {
7495 unsigned char *qsrc;
7500 so->query->data[-2] = 0xff & (so->query->end >> 8);
7501 so->query->data[-1] = 0xff & (so->query->end >> 0);
7503 qend = so->query->end + 2;
7505 while (so->qout < qend) {
7506 qsrc = &so->query->data[-2] + so->qout;
7507 n = dns_send_nopipe(so->tcp, (void *)qsrc, qend - so->qout, 0, &error);
7508 dns_trace_sys_send(so->trace, so->tcp, SOCK_STREAM, qsrc, n, error);
7512 so->stat.tcp.sent.bytes += n;
7515 so->stat.tcp.sent.count++;
7518 } /* dns_so_tcp_send() */
7521 static int dns_so_tcp_recv(struct dns_socket *so) {
7522 unsigned char *asrc;
7523 size_t aend, alen, n;
7526 aend = so->alen + 2;
7528 while (so->apos < aend) {
7529 asrc = &so->answer->data[-2];
7531 n = dns_recv(so->tcp, (void *)&asrc[so->apos], aend - so->apos, 0, &error);
7532 dns_trace_sys_recv(so->trace, so->tcp, SOCK_STREAM, &asrc[so->apos], n, error);
7537 so->stat.tcp.rcvd.bytes += n;
7539 if (so->alen == 0 && so->apos >= 2) {
7540 alen = ((0xff & so->answer->data[-2]) << 8)
7541 | ((0xff & so->answer->data[-1]) << 0);
7543 if ((error = dns_so_newanswer(so, alen)))
7551 so->answer->end = so->alen;
7552 so->stat.tcp.rcvd.count++;
7555 } /* dns_so_tcp_recv() */
7558 #pragma clang diagnostic pop
7562 int dns_so_check(struct dns_socket *so) {
7565 unsigned char *buffer;
7568 switch (so->state) {
7569 case DNS_SO_UDP_INIT:
7571 case DNS_SO_UDP_CONN:
7572 error = dns_connect(so->udp, (struct sockaddr *)&so->remote, dns_sa_len(&so->remote));
7573 dns_trace_sys_connect(so->trace, so->udp, SOCK_DGRAM, (struct sockaddr *)&so->remote, error);
7578 case DNS_SO_UDP_SEND:
7579 n = dns_send(so->udp, (void *)so->query->data, so->query->end, 0, &error);
7580 dns_trace_sys_send(so->trace, so->udp, SOCK_DGRAM, so->query->data, n, error);
7584 so->stat.udp.sent.bytes += n;
7585 so->stat.udp.sent.count++;
7588 case DNS_SO_UDP_RECV:
7589 n = dns_recv(so->udp, (void *)so->answer->data, so->answer->size, 0, &error);
7590 dns_trace_sys_recv(so->trace, so->udp, SOCK_DGRAM, so->answer->data, n, error);
7594 so->answer->end = n;
7595 so->stat.udp.rcvd.bytes += n;
7596 so->stat.udp.rcvd.count++;
7598 if ((error = dns_so_verify(so, so->answer)))
7602 case DNS_SO_UDP_DONE:
7603 if (!dns_header(so->answer)->tc || so->type == SOCK_DGRAM)
7607 case DNS_SO_TCP_INIT:
7608 if (dns_so_tcp_keep(so)) {
7609 so->state = DNS_SO_TCP_SEND;
7614 if ((error = dns_so_closefd(so, &so->tcp)))
7617 if (-1 == (so->tcp = dns_socket((struct sockaddr *)&so->local, SOCK_STREAM, &error)))
7621 case DNS_SO_TCP_CONN:
7622 error = dns_connect(so->tcp, (struct sockaddr *)&so->remote, dns_sa_len(&so->remote));
7623 dns_trace_sys_connect(so->trace, so->tcp, SOCK_STREAM, (struct sockaddr *)&so->remote, error);
7624 if (error && error != DNS_EISCONN)
7628 case DNS_SO_TCP_SEND:
7629 if ((error = dns_so_tcp_send(so)))
7633 case DNS_SO_TCP_RECV:
7634 if ((error = dns_so_tcp_recv(so)))
7638 case DNS_SO_TCP_DONE:
7639 /* close unless DNS_RESCONF_TCP_ONLY (see dns_res_tcp2type) */
7640 if (so->type != SOCK_STREAM) {
7641 if ((error = dns_so_closefd(so, &so->tcp)))
7645 if ((error = dns_so_verify(so, so->answer)))
7649 case DNS_SO_SOCKS_INIT:
7650 if ((error = dns_so_closefd(so, &so->tcp)))
7653 if (-1 == (so->tcp = dns_socket((struct sockaddr *)&so->local, SOCK_STREAM, &error)))
7657 case DNS_SO_SOCKS_CONN: {
7658 unsigned char method;
7660 error = dns_connect(so->tcp, (struct sockaddr *)so->opts.socks_host, dns_sa_len(so->opts.socks_host));
7661 dns_trace_sys_connect(so->trace, so->tcp, SOCK_STREAM, (struct sockaddr *)so->opts.socks_host, error);
7662 if (error && error != DNS_EISCONN)
7665 /* We need to do a handshake with the SOCKS server,
7666 * but the query is already in the buffer. Move it
7667 * out of the way. */
7668 dns_p_movptr(&so->query_backup, &so->query);
7670 /* Create a new buffer for the handshake. */
7671 dns_p_grow(&so->query);
7673 /* Negotiate method. */
7674 buffer = dns_so_tcp_send_buffer(so, 3);
7675 buffer[0] = 5; /* RFC-1928 VER field. */
7676 buffer[1] = 1; /* NMETHODS */
7677 if (so->opts.socks_user)
7678 method = 2; /* Method: username/password authentication. */
7680 method = 0; /* Method: No authentication required. */
7685 case DNS_SO_SOCKS_HELLO_SEND:
7686 if ((error = dns_so_tcp_send(so)))
7689 dns_so_tcp_recv_expect(so, 2);
7691 case DNS_SO_SOCKS_HELLO_RECV: {
7692 unsigned char method;
7694 if ((error = dns_so_tcp_recv(so)))
7697 buffer = dns_so_tcp_recv_buffer(so);
7698 method = so->opts.socks_user ? 2 : 0;
7699 if (buffer[0] != 5 || buffer[1] != method) {
7700 /* Socks server returned wrong version or does
7701 not support our requested method. */
7702 error = ENOTSUP; /* Fixme: Is there a better errno? */
7707 /* No authentication, go ahead and send the
7709 so->state = DNS_SO_SOCKS_REQUEST_PREPARE;
7713 /* Prepare username/password sub-negotiation. */
7714 if (! so->opts.socks_password) {
7715 error = EINVAL; /* No password given. */
7718 size_t buflen, ulen, plen;
7720 ulen = strlen(so->opts.socks_user);
7721 plen = strlen(so->opts.socks_password);
7722 if (!ulen || ulen > 255 || !plen || plen > 255) {
7723 error = EINVAL; /* Credentials too long or too short. */
7727 buffer = dns_so_tcp_send_buffer(so, 3 + ulen + plen);
7728 buffer[0] = 1; /* VER of the sub-negotiation. */
7729 buffer[1] = (unsigned char) ulen;
7731 memcpy (buffer+buflen, so->opts.socks_user, ulen);
7733 buffer[buflen++] = (unsigned char) plen;
7734 memcpy (buffer+buflen, so->opts.socks_password, plen);
7739 case DNS_SO_SOCKS_AUTH_SEND:
7740 if ((error = dns_so_tcp_send(so)))
7743 /* Skip the two length octets, and receive two octets. */
7744 dns_so_tcp_recv_expect(so, 2);
7747 case DNS_SO_SOCKS_AUTH_RECV:
7748 if ((error = dns_so_tcp_recv(so)))
7751 buffer = dns_so_tcp_recv_buffer(so);
7752 if (buffer[0] != 1) {
7753 /* SOCKS server returned wrong version. */
7758 /* SOCKS server denied access. */
7764 case DNS_SO_SOCKS_REQUEST_PREPARE:
7765 /* Send request details (rfc-1928, 4). */
7766 buffer = dns_so_tcp_send_buffer(so, so->remote.ss_family == AF_INET6 ? 22 : 10);
7767 buffer[0] = 5; /* VER */
7768 buffer[1] = 1; /* CMD = CONNECT */
7769 buffer[2] = 0; /* RSV */
7770 if (so->remote.ss_family == AF_INET6) {
7771 struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)&so->remote;
7773 buffer[3] = 4; /* ATYP = IPv6 */
7774 memcpy (buffer+ 4, &addr_in6->sin6_addr.s6_addr, 16); /* DST.ADDR */
7775 memcpy (buffer+20, &addr_in6->sin6_port, 2); /* DST.PORT */
7777 struct sockaddr_in *addr_in = (struct sockaddr_in *)&so->remote;
7779 buffer[3] = 1; /* ATYP = IPv4 */
7780 memcpy (buffer+4, &addr_in->sin_addr.s_addr, 4); /* DST.ADDR */
7781 memcpy (buffer+8, &addr_in->sin_port, 2); /* DST.PORT */
7785 case DNS_SO_SOCKS_REQUEST_SEND:
7786 if ((error = dns_so_tcp_send(so)))
7789 /* Expect ten octets. This is the length of the
7790 * response assuming a IPv4 address is used. */
7791 dns_so_tcp_recv_expect(so, 10);
7793 case DNS_SO_SOCKS_REQUEST_RECV:
7794 if ((error = dns_so_tcp_recv(so)))
7797 buffer = dns_so_tcp_recv_buffer(so);
7798 if (buffer[0] != 5 || buffer[2] != 0) {
7799 /* Socks server returned wrong version or the
7800 reserved field is not zero. */
7805 switch (buffer[1]) {
7806 case 0x01: /* general SOCKS server failure. */
7809 case 0x02: /* connection not allowed by ruleset. */
7812 case 0x03: /* Network unreachable */
7813 error = ENETUNREACH;
7815 case 0x04: /* Host unreachable */
7816 error = EHOSTUNREACH;
7818 case 0x05: /* Connection refused */
7819 error = ECONNREFUSED;
7821 case 0x06: /* TTL expired */
7824 case 0x08: /* Address type not supported */
7825 error = EPROTONOSUPPORT;
7827 case 0x07: /* Command not supported */
7829 error = ENOTSUP; /* Fixme: Is there a better error? */
7835 if (buffer[3] == 1) {
7836 /* This was indeed an IPv4 address. */
7837 so->state = DNS_SO_SOCKS_HANDSHAKE_DONE;
7841 if (buffer[3] != 4) {
7846 /* Expect receive twelve octets. This accounts for
7847 * the remaining bytes assuming an IPv6 address is
7849 dns_so_tcp_recv_expect(so, 12);
7851 case DNS_SO_SOCKS_REQUEST_RECV_V6:
7852 if ((error = dns_so_tcp_recv(so)))
7856 case DNS_SO_SOCKS_HANDSHAKE_DONE:
7857 /* We have not way to store the actual address used by
7858 * the server. Then again, we don't really care. */
7860 /* Restore the query. */
7861 dns_p_movptr(&so->query, &so->query_backup);
7863 /* Reset cursors. */
7868 /* SOCKS handshake is done. Proceed with the
7870 so->state = DNS_SO_TCP_SEND;
7873 error = DNS_EUNKNOWN;
7879 DNS_CARP("discarding packet");
7885 case DNS_EINPROGRESS:
7889 #if DNS_EWOULDBLOCK != DNS_EAGAIN
7890 case DNS_EWOULDBLOCK:
7899 } /* dns_so_check() */
7902 struct dns_packet *dns_so_fetch(struct dns_socket *so, int *error) {
7903 struct dns_packet *answer;
7905 switch (so->state) {
7906 case DNS_SO_UDP_DONE:
7907 case DNS_SO_TCP_DONE:
7908 answer = so->answer;
7910 dns_trace_so_fetch(so->trace, answer, 0);
7914 *error = DNS_EUNKNOWN;
7915 dns_trace_so_fetch(so->trace, NULL, *error);
7919 } /* dns_so_fetch() */
7922 struct dns_packet *dns_so_query(struct dns_socket *so, struct dns_packet *Q, struct sockaddr *host, int *error_) {
7923 struct dns_packet *A;
7927 if ((error = dns_so_submit(so, Q, host)))
7931 if ((error = dns_so_check(so)))
7934 if (!(A = dns_so_fetch(so, &error)))
7944 } /* dns_so_query() */
7947 time_t dns_so_elapsed(struct dns_socket *so) {
7948 return dns_elapsed(&so->elapsed);
7949 } /* dns_so_elapsed() */
7952 void dns_so_clear(struct dns_socket *so) {
7953 dns_so_closefds(so, DNS_SO_CLOSE_OLD);
7954 } /* dns_so_clear() */
7957 static int dns_so_events2(struct dns_socket *so, enum dns_events type) {
7960 switch (so->state) {
7961 case DNS_SO_UDP_CONN:
7962 case DNS_SO_UDP_SEND:
7963 events |= DNS_POLLOUT;
7966 case DNS_SO_UDP_RECV:
7967 events |= DNS_POLLIN;
7970 case DNS_SO_TCP_CONN:
7971 case DNS_SO_TCP_SEND:
7972 events |= DNS_POLLOUT;
7975 case DNS_SO_TCP_RECV:
7976 events |= DNS_POLLIN;
7983 return DNS_POLL2EV(events);
7987 } /* dns_so_events2() */
7990 int dns_so_events(struct dns_socket *so) {
7991 return dns_so_events2(so, so->opts.events);
7992 } /* dns_so_events() */
7995 int dns_so_pollfd(struct dns_socket *so) {
7996 switch (so->state) {
7997 case DNS_SO_UDP_CONN:
7998 case DNS_SO_UDP_SEND:
7999 case DNS_SO_UDP_RECV:
8001 case DNS_SO_TCP_CONN:
8002 case DNS_SO_TCP_SEND:
8003 case DNS_SO_TCP_RECV:
8008 } /* dns_so_pollfd() */
8011 int dns_so_poll(struct dns_socket *so, int timeout) {
8012 return dns_poll(dns_so_pollfd(so), dns_so_events2(so, DNS_SYSPOLL), timeout);
8013 } /* dns_so_poll() */
8016 const struct dns_stat *dns_so_stat(struct dns_socket *so) {
8018 } /* dns_so_stat() */
8021 struct dns_trace *dns_so_trace(struct dns_socket *so) {
8023 } /* dns_so_trace() */
8026 void dns_so_settrace(struct dns_socket *so, struct dns_trace *trace) {
8027 struct dns_trace *otrace = so->trace;
8028 so->trace = dns_trace_acquire_p(trace);
8029 dns_trace_close(otrace);
8030 } /* dns_so_settrace() */
8034 * R E S O L V E R R O U T I N E S
8036 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8038 enum dns_res_state {
8041 DNS_R_SWITCH, /* (B)IND, (F)ILE, (C)ACHE */
8043 DNS_R_FILE, /* Lookup in local hosts database */
8045 DNS_R_CACHE, /* Lookup in application cache */
8050 DNS_R_BIND, /* Lookup in the network */
8055 DNS_R_RESOLV0_NS, /* Prologue: Setup next frame and recurse */
8056 DNS_R_RESOLV1_NS, /* Epilog: Inspect answer */
8067 }; /* enum dns_res_state */
8070 #define DNS_R_MAXDEPTH 8
8071 #define DNS_R_ENDFRAME (DNS_R_MAXDEPTH - 1)
8073 struct dns_resolver {
8074 struct dns_socket so;
8076 struct dns_resolv_conf *resconf;
8077 struct dns_hosts *hosts;
8078 struct dns_hints *hints;
8079 struct dns_cache *cache;
8080 struct dns_trace *trace;
8082 dns_atomic_t refcount;
8084 /* Reset zeroes everything below here. */
8086 char qname[DNS_D_MAXNAME + 1];
8089 enum dns_type qtype;
8090 enum dns_class qclass;
8092 struct dns_clock elapsed;
8094 dns_resconf_i_t search;
8096 struct dns_rr_i smart;
8098 struct dns_packet *nodata; /* answer if nothing better */
8102 struct dns_res_frame {
8103 enum dns_res_state state;
8106 int which; /* (B)IND, (F)ILE; index into resconf->lookup */
8111 struct dns_packet *query, *answer, *hints;
8113 struct dns_rr_i hints_i, hints_j;
8114 struct dns_rr hints_ns, ans_cname;
8115 } stack[DNS_R_MAXDEPTH];
8116 }; /* struct dns_resolver */
8119 static int dns_res_tcp2type(int tcp) {
8121 case DNS_RESCONF_TCP_ONLY:
8122 case DNS_RESCONF_TCP_SOCKS:
8124 case DNS_RESCONF_TCP_DISABLE:
8129 } /* dns_res_tcp2type() */
8131 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) {
8132 static const struct dns_resolver R_initializer
8133 = { .refcount = 1, };
8134 struct dns_resolver *R = 0;
8138 * Grab ref count early because the caller may have passed us a mortal
8139 * reference, and we want to do the right thing if we return early
8143 dns_resconf_acquire(resconf);
8145 dns_hosts_acquire(hosts);
8147 dns_hints_acquire(hints);
8149 dns_cache_acquire(cache);
8152 * Don't try to load it ourselves because a NULL object might be an
8153 * error from, say, dns_resconf_root(), and loading
8154 * dns_resconf_local() by default would create undesirable surpises.
8156 if (!resconf || !hosts || !hints) {
8162 if (!(R = malloc(sizeof *R)))
8166 type = dns_res_tcp2type(resconf->options.tcp);
8168 if (!dns_so_init(&R->so, (struct sockaddr *)&resconf->iface, type, opts, &error))
8171 R->resconf = resconf;
8178 error = dns_syerr();
8184 dns_resconf_close(resconf);
8185 dns_hosts_close(hosts);
8186 dns_hints_close(hints);
8187 dns_cache_close(cache);
8190 } /* dns_res_open() */
8193 struct dns_resolver *dns_res_stub(const struct dns_options *opts, int *error) {
8194 struct dns_resolv_conf *resconf = 0;
8195 struct dns_hosts *hosts = 0;
8196 struct dns_hints *hints = 0;
8197 struct dns_resolver *res = 0;
8199 if (!(resconf = dns_resconf_local(error)))
8202 if (!(hosts = dns_hosts_local(error)))
8205 if (!(hints = dns_hints_local(resconf, error)))
8208 if (!(res = dns_res_open(resconf, hosts, hints, NULL, opts, error)))
8212 dns_resconf_close(resconf);
8213 dns_hosts_close(hosts);
8214 dns_hints_close(hints);
8217 } /* dns_res_stub() */
8220 static void dns_res_frame_destroy(struct dns_resolver *R, struct dns_res_frame *frame) {
8223 dns_p_setptr(&frame->query, NULL);
8224 dns_p_setptr(&frame->answer, NULL);
8225 dns_p_setptr(&frame->hints, NULL);
8226 } /* dns_res_frame_destroy() */
8229 static void dns_res_frame_init(struct dns_resolver *R, struct dns_res_frame *frame) {
8230 memset(frame, '\0', sizeof *frame);
8233 * NB: Can be invoked from dns_res_open, before R->resconf has been
8237 if (!R->resconf->options.recurse)
8238 frame->qflags |= DNS_Q_RD;
8239 if (R->resconf->options.edns0)
8240 frame->qflags |= DNS_Q_EDNS0;
8242 } /* dns_res_frame_init() */
8245 static void dns_res_frame_reset(struct dns_resolver *R, struct dns_res_frame *frame) {
8246 dns_res_frame_destroy(R, frame);
8247 dns_res_frame_init(R, frame);
8248 } /* dns_res_frame_reset() */
8251 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) {
8252 struct dns_packet *P = NULL;
8254 if (!(F < endof(R->stack)))
8255 return DNS_EUNKNOWN;
8257 dns_p_movptr(&P, &F->query);
8258 dns_res_frame_reset(R, F);
8259 dns_p_movptr(&F->query, &P);
8261 return dns_q_make(&F->query, qname, qtype, qclass, F->qflags);
8262 } /* dns_res_frame_prepare() */
8265 void dns_res_reset(struct dns_resolver *R) {
8268 dns_so_reset(&R->so);
8269 dns_p_setptr(&R->nodata, NULL);
8271 for (i = 0; i < lengthof(R->stack); i++)
8272 dns_res_frame_destroy(R, &R->stack[i]);
8274 memset(&R->qname, '\0', sizeof *R - offsetof(struct dns_resolver, qname));
8276 for (i = 0; i < lengthof(R->stack); i++)
8277 dns_res_frame_init(R, &R->stack[i]);
8278 } /* dns_res_reset() */
8281 void dns_res_close(struct dns_resolver *R) {
8282 if (!R || 1 < dns_res_release(R))
8287 dns_so_destroy(&R->so);
8289 dns_hints_close(R->hints);
8290 dns_hosts_close(R->hosts);
8291 dns_resconf_close(R->resconf);
8292 dns_cache_close(R->cache);
8293 dns_trace_close(R->trace);
8296 } /* dns_res_close() */
8299 dns_refcount_t dns_res_acquire(struct dns_resolver *R) {
8300 return dns_atomic_fetch_add(&R->refcount);
8301 } /* dns_res_acquire() */
8304 dns_refcount_t dns_res_release(struct dns_resolver *R) {
8305 return dns_atomic_fetch_sub(&R->refcount);
8306 } /* dns_res_release() */
8309 struct dns_resolver *dns_res_mortal(struct dns_resolver *res) {
8311 dns_res_release(res);
8313 } /* dns_res_mortal() */
8316 static struct dns_packet *dns_res_merge(struct dns_packet *P0, struct dns_packet *P1, int *error_) {
8317 size_t bufsiz = P0->end + P1->end;
8318 struct dns_packet *P[3] = { P0, P1, 0 };
8319 struct dns_rr rr[3];
8321 enum dns_section section;
8324 if (!(P[2] = dns_p_make(bufsiz, &error)))
8327 dns_rr_foreach(&rr[0], P[0], .section = DNS_S_QD) {
8328 if ((error = dns_rr_copy(P[2], &rr[0], P[0])))
8332 for (section = DNS_S_AN; (DNS_S_ALL & section); section <<= 1) {
8333 for (i = 0; i < 2; i++) {
8334 dns_rr_foreach(&rr[i], P[i], .section = section) {
8337 dns_rr_foreach(&rr[2], P[2], .type = rr[i].type, .section = (DNS_S_ALL & ~DNS_S_QD)) {
8338 if (0 == dns_rr_cmp(&rr[i], P[i], &rr[2], P[2])) {
8345 if (copy && (error = dns_rr_copy(P[2], &rr[i], P[i]))) {
8346 if (error == DNS_ENOBUFS && bufsiz < 65535) {
8347 dns_p_setptr(&P[2], NULL);
8349 bufsiz = DNS_PP_MAX(65535, bufsiz * 2);
8357 } /* foreach(packet) */
8358 } /* foreach(section) */
8367 } /* dns_res_merge() */
8370 static struct dns_packet *dns_res_glue(struct dns_resolver *R, struct dns_packet *Q) {
8371 struct dns_packet *P = dns_p_new(512);
8372 char qname[DNS_D_MAXNAME + 1];
8374 enum dns_type qtype;
8379 if (!(qlen = dns_d_expand(qname, sizeof qname, 12, Q, &error))
8380 || qlen >= sizeof qname)
8383 if (!(qtype = dns_rr_type(12, Q)))
8386 if ((error = dns_p_push(P, DNS_S_QD, qname, strlen(qname), qtype, DNS_C_IN, 0, 0)))
8389 for (sp = 0; sp <= R->sp; sp++) {
8390 if (!R->stack[sp].answer)
8393 dns_rr_foreach(&rr, R->stack[sp].answer, .name = qname, .type = qtype, .section = (DNS_S_ALL & ~DNS_S_QD)) {
8394 rr.section = DNS_S_AN;
8396 if ((error = dns_rr_copy(P, &rr, R->stack[sp].answer)))
8401 if (dns_p_count(P, DNS_S_AN) > 0)
8404 /* Otherwise, look for a CNAME */
8405 for (sp = 0; sp <= R->sp; sp++) {
8406 if (!R->stack[sp].answer)
8409 dns_rr_foreach(&rr, R->stack[sp].answer, .name = qname, .type = DNS_T_CNAME, .section = (DNS_S_ALL & ~DNS_S_QD)) {
8410 rr.section = DNS_S_AN;
8412 if ((error = dns_rr_copy(P, &rr, R->stack[sp].answer)))
8417 if (!dns_p_count(P, DNS_S_AN))
8421 return dns_p_copy(dns_p_make(P->end, &error), P);
8422 } /* dns_res_glue() */
8426 * Sort NS records by three criteria:
8428 * 1) Whether glue is present.
8429 * 2) Whether glue record is original or of recursive lookup.
8430 * 3) Randomly shuffle records which share the above criteria.
8432 * NOTE: Assumes only NS records passed, AND ASSUMES no new NS records will
8433 * be added during an iteration.
8435 * FIXME: Only groks A glue, not AAAA glue.
8437 static int dns_res_nameserv_cmp(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) {
8438 _Bool glued[2] = { 0 };
8439 struct dns_rr x = { 0 }, y = { 0 };
8443 if (!(error = dns_ns_parse(&ns, a, P)))
8444 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);
8446 if (!(error = dns_ns_parse(&ns, b, P)))
8447 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);
8449 if ((cmp = glued[1] - glued[0])) {
8451 } else if ((cmp = (dns_rr_offset(&y) < i->args[0]) - (dns_rr_offset(&x) < i->args[0]))) {
8454 return dns_rr_i_shuffle(a, b, i, P);
8456 } /* dns_res_nameserv_cmp() */
8459 #define dgoto(sp, i) \
8460 do { R->stack[(sp)].state = (i); goto exec; } while (0)
8462 static int dns_res_exec(struct dns_resolver *R) {
8463 struct dns_res_frame *F;
8464 struct dns_packet *P;
8466 char host[DNS_D_MAXNAME + 1];
8467 char name[DNS_D_MAXNAME + 1];
8469 struct dns_cname cname;
8477 F = &R->stack[R->sp];
8484 dgoto(R->sp, DNS_R_SWITCH);
8489 if (!(F->answer = dns_res_glue(R, F->query)))
8490 dgoto(R->sp, DNS_R_SWITCH);
8492 if (!(len = dns_d_expand(u.name, sizeof u.name, 12, F->query, &error)))
8494 else if (len >= sizeof u.name)
8497 dns_rr_foreach(&rr, F->answer, .name = u.name, .type = dns_rr_type(12, F->query), .section = DNS_S_AN) {
8498 dgoto(R->sp, DNS_R_FINISH);
8501 dns_rr_foreach(&rr, F->answer, .name = u.name, .type = DNS_T_CNAME, .section = DNS_S_AN) {
8504 dgoto(R->sp, DNS_R_CNAME0_A);
8509 while (F->which < (int)sizeof R->resconf->lookup && R->resconf->lookup[F->which]) {
8510 switch (R->resconf->lookup[F->which++]) {
8512 dgoto(R->sp, DNS_R_BIND);
8514 dgoto(R->sp, DNS_R_FILE);
8517 dgoto(R->sp, DNS_R_CACHE);
8526 * FIXME: Examine more closely whether our logic is correct
8527 * and DNS_R_SERVFAIL is the correct default response.
8529 * Case 1: We got here because we never got an answer on the
8530 * wire. All queries timed-out and we reached maximum
8531 * attempts count. See DNS_R_FOREACH_NS. In that case
8532 * DNS_R_SERVFAIL is the correct state, unless we want to
8533 * return DNS_ETIMEDOUT.
8535 * Case 2: We were a stub resolver and got an unsatisfactory
8536 * answer (empty ANSWER section) which caused us to jump
8537 * back to DNS_R_SEARCH and ultimately to DNS_R_SWITCH. We
8538 * return the answer returned from the wire, which we
8539 * stashed in R->nodata.
8541 * Case 3: We reached maximum attempts count as in case #1,
8542 * but never got an authoritative response which caused us
8543 * to short-circuit. See end of DNS_R_QUERY_A case. We
8544 * should probably prepare R->nodata as in case #2.
8546 if (R->sp == 0 && R->nodata) { /* XXX: can we just return nodata regardless? */
8547 dns_p_movptr(&F->answer, &R->nodata);
8548 dgoto(R->sp, DNS_R_FINISH);
8551 dgoto(R->sp, DNS_R_SERVFAIL);
8554 if (!dns_p_setptr(&F->answer, dns_hosts_query(R->hosts, F->query, &error)))
8557 if (dns_p_count(F->answer, DNS_S_AN) > 0)
8558 dgoto(R->sp, DNS_R_FINISH);
8560 dns_p_setptr(&F->answer, NULL);
8564 while ((len = dns_resconf_search(u.name, sizeof u.name, R->qname, R->qlen, R->resconf, &R->search))) {
8565 if ((error = dns_q_make2(&F->query, u.name, len, R->qtype, R->qclass, F->qflags)))
8568 if (!dns_p_setptr(&F->answer, dns_hosts_query(R->hosts, F->query, &error)))
8571 if (dns_p_count(F->answer, DNS_S_AN) > 0)
8572 dgoto(R->sp, DNS_R_FINISH);
8574 dns_p_setptr(&F->answer, NULL);
8578 dgoto(R->sp, DNS_R_SWITCH);
8582 if (!F->query && (error = dns_q_make(&F->query, R->qname, R->qtype, R->qclass, F->qflags)))
8585 if (dns_p_setptr(&F->answer, R->cache->query(F->query, R->cache, &error))) {
8586 if (dns_p_count(F->answer, DNS_S_AN) > 0)
8587 dgoto(R->sp, DNS_R_FINISH);
8589 dns_p_setptr(&F->answer, NULL);
8591 dgoto(R->sp, DNS_R_SWITCH);
8597 if ((error = R->cache->submit(F->query, R->cache)))
8602 if ((error = R->cache->check(R->cache)))
8609 if (dns_p_setptr(&F->answer, R->cache->fetch(R->cache, &error))) {
8610 if (dns_p_count(F->answer, DNS_S_AN) > 0)
8611 dgoto(R->sp, DNS_R_FINISH);
8613 dns_p_setptr(&F->answer, NULL);
8615 dgoto(R->sp, DNS_R_SWITCH);
8619 dgoto(R->sp, DNS_R_SWITCH);
8625 dgoto(R->sp, DNS_R_HINTS);
8633 * XXX: We probably should only apply the domain search
8634 * algorithm if R->sp == 0.
8636 if (!(len = dns_resconf_search(u.name, sizeof u.name, R->qname, R->qlen, R->resconf, &R->search)))
8637 dgoto(R->sp, DNS_R_SWITCH);
8639 if ((error = dns_q_make2(&F->query, u.name, len, R->qtype, R->qclass, F->qflags)))
8644 if (!dns_p_setptr(&F->hints, dns_hints_query(R->hints, F->query, &error)))
8649 dns_rr_i_init(&F->hints_i, F->hints);
8651 F->hints_i.section = DNS_S_AUTHORITY;
8652 F->hints_i.type = DNS_T_NS;
8653 F->hints_i.sort = &dns_res_nameserv_cmp;
8654 F->hints_i.args[0] = F->hints->end;
8657 case DNS_R_FOREACH_NS:
8658 dns_rr_i_save(&F->hints_i);
8660 /* Load our next nameserver host. */
8661 if (!dns_rr_grep(&F->hints_ns, 1, &F->hints_i, F->hints, &error)) {
8662 if (++F->attempts < R->resconf->options.attempts)
8663 dgoto(R->sp, DNS_R_ITERATE);
8665 dgoto(R->sp, DNS_R_SWITCH);
8668 dns_rr_i_init(&F->hints_j, F->hints);
8670 /* Assume there are glue records */
8671 dgoto(R->sp, DNS_R_FOREACH_A);
8672 case DNS_R_RESOLV0_NS:
8673 /* Have we reached our max depth? */
8674 if (&F[1] >= endof(R->stack))
8675 dgoto(R->sp, DNS_R_FOREACH_NS);
8677 if ((error = dns_ns_parse(&u.ns, &F->hints_ns, F->hints)))
8679 if ((error = dns_res_frame_prepare(R, &F[1], u.ns.host, DNS_T_A, DNS_C_IN)))
8684 dgoto(++R->sp, DNS_R_INIT);
8685 case DNS_R_RESOLV1_NS:
8686 if (!(len = dns_d_expand(u.host, sizeof u.host, 12, F[1].query, &error)))
8688 else if (len >= sizeof u.host)
8691 dns_rr_foreach(&rr, F[1].answer, .name = u.host, .type = DNS_T_A, .section = (DNS_S_ALL & ~DNS_S_QD)) {
8692 rr.section = DNS_S_AR;
8694 if ((error = dns_rr_copy(F->hints, &rr, F[1].answer)))
8697 dns_rr_i_rewind(&F->hints_i); /* Now there's glue. */
8700 dgoto(R->sp, DNS_R_FOREACH_NS);
8701 case DNS_R_FOREACH_A: {
8703 struct sockaddr_in sin;
8706 * NOTE: Iterator initialized in DNS_R_FOREACH_NS because
8707 * this state is re-entrant, but we need to reset
8708 * .name to a valid pointer each time.
8710 if ((error = dns_ns_parse(&u.ns, &F->hints_ns, F->hints)))
8713 F->hints_j.name = u.ns.host;
8714 F->hints_j.type = DNS_T_A;
8715 F->hints_j.section = DNS_S_ALL & ~DNS_S_QD;
8717 if (!dns_rr_grep(&rr, 1, &F->hints_j, F->hints, &error)) {
8718 if (!dns_rr_i_count(&F->hints_j))
8719 dgoto(R->sp, DNS_R_RESOLV0_NS);
8721 dgoto(R->sp, DNS_R_FOREACH_NS);
8724 if ((error = dns_a_parse(&a, &rr, F->hints)))
8727 memset(&sin, '\0', sizeof sin); /* NB: silence valgrind */
8728 sin.sin_family = AF_INET;
8729 sin.sin_addr = a.addr;
8731 sin.sin_port = dns_hints_port(R->hints, AF_INET, &sin.sin_addr);
8733 sin.sin_port = htons(53);
8736 char addr[INET_ADDRSTRLEN + 1];
8737 dns_a_print(addr, sizeof addr, &a);
8738 dns_header(F->query)->qid = dns_so_mkqid(&R->so);
8739 DNS_SHOW(F->query, "ASKING: %s/%s @ DEPTH: %u)", u.ns.host, addr, R->sp);
8742 dns_trace_setcname(R->trace, u.ns.host, (struct sockaddr *)&sin);
8744 if ((error = dns_so_submit(&R->so, F->query, (struct sockaddr *)&sin)))
8750 if (dns_so_elapsed(&R->so) >= dns_resconf_timeout(R->resconf))
8751 dgoto(R->sp, DNS_R_FOREACH_A);
8753 if ((error = dns_so_check(&R->so)))
8756 if (!dns_p_setptr(&F->answer, dns_so_fetch(&R->so, &error)))
8760 DNS_SHOW(F->answer, "ANSWER @ DEPTH: %u)", R->sp);
8763 if (dns_p_rcode(F->answer) == DNS_RC_FORMERR ||
8764 dns_p_rcode(F->answer) == DNS_RC_NOTIMP ||
8765 dns_p_rcode(F->answer) == DNS_RC_BADVERS) {
8766 /* Temporarily disable EDNS0 and try again. */
8767 if (F->qflags & DNS_Q_EDNS0) {
8768 F->qflags &= ~DNS_Q_EDNS0;
8769 if ((error = dns_q_remake(&F->query, F->qflags)))
8772 dgoto(R->sp, DNS_R_FOREACH_A);
8776 if ((error = dns_rr_parse(&rr, 12, F->query)))
8779 if (!(len = dns_d_expand(u.name, sizeof u.name, rr.dn.p, F->query, &error)))
8781 else if (len >= sizeof u.name)
8784 dns_rr_foreach(&rr, F->answer, .section = DNS_S_AN, .name = u.name, .type = rr.type) {
8785 dgoto(R->sp, DNS_R_FINISH); /* Found */
8788 dns_rr_foreach(&rr, F->answer, .section = DNS_S_AN, .name = u.name, .type = DNS_T_CNAME) {
8791 dgoto(R->sp, DNS_R_CNAME0_A);
8795 * XXX: The condition here should probably check whether
8796 * R->sp == 0, because DNS_R_SEARCH runs regardless of
8797 * options.recurse. See DNS_R_BIND.
8799 if (!R->resconf->options.recurse) {
8800 /* Make first answer our tentative answer */
8802 dns_p_movptr(&R->nodata, &F->answer);
8804 dgoto(R->sp, DNS_R_SEARCH);
8807 dns_rr_foreach(&rr, F->answer, .section = DNS_S_NS, .type = DNS_T_NS) {
8808 dns_p_movptr(&F->hints, &F->answer);
8810 dgoto(R->sp, DNS_R_ITERATE);
8813 /* XXX: Should this go further up? */
8814 if (dns_header(F->answer)->aa)
8815 dgoto(R->sp, DNS_R_FINISH);
8817 /* XXX: Should we copy F->answer to R->nodata? */
8819 dgoto(R->sp, DNS_R_FOREACH_A);
8820 case DNS_R_CNAME0_A:
8821 if (&F[1] >= endof(R->stack))
8822 dgoto(R->sp, DNS_R_FINISH);
8824 if ((error = dns_cname_parse(&u.cname, &F->ans_cname, F->answer)))
8826 if ((error = dns_res_frame_prepare(R, &F[1], u.cname.host, dns_rr_type(12, F->query), DNS_C_IN)))
8831 dgoto(++R->sp, DNS_R_INIT);
8832 case DNS_R_CNAME1_A:
8833 if (!(P = dns_res_merge(F->answer, F[1].answer, &error)))
8836 dns_p_setptr(&F->answer, P);
8838 dgoto(R->sp, DNS_R_FINISH);
8843 if (!R->resconf->options.smart || R->sp > 0)
8844 dgoto(R->sp, DNS_R_DONE);
8846 R->smart.section = DNS_S_AN;
8847 R->smart.type = R->qtype;
8849 dns_rr_i_init(&R->smart, F->answer);
8852 case DNS_R_SMART0_A:
8853 if (&F[1] >= endof(R->stack))
8854 dgoto(R->sp, DNS_R_DONE);
8856 while (dns_rr_grep(&rr, 1, &R->smart, F->answer, &error)) {
8863 enum dns_type qtype;
8864 enum dns_class qclass;
8868 if ((error = dns_ns_parse(&rd.ns, &rr, F->answer)))
8877 if ((error = dns_mx_parse(&rd.mx, &rr, F->answer)))
8886 if ((error = dns_srv_parse(&rd.srv, &rr, F->answer)))
8889 qname = rd.srv.target;
8898 if ((error = dns_res_frame_prepare(R, &F[1], qname, qtype, qclass)))
8903 dgoto(++R->sp, DNS_R_INIT);
8907 * NOTE: SMTP specification says to fallback to A record.
8909 * XXX: Should we add a mock MX answer?
8911 if (R->qtype == DNS_T_MX && R->smart.state.count == 0) {
8912 if ((error = dns_res_frame_prepare(R, &F[1], R->qname, DNS_T_A, DNS_C_IN)))
8915 R->smart.state.count++;
8918 dgoto(++R->sp, DNS_R_INIT);
8921 dgoto(R->sp, DNS_R_DONE);
8922 case DNS_R_SMART1_A:
8927 * FIXME: For CNAME chains (which are typically illegal in
8928 * this context), we should rewrite the record host name
8929 * to the original smart qname. All the user cares about
8930 * is locating that A/AAAA record.
8932 dns_rr_foreach(&rr, F[1].answer, .section = DNS_S_AN, .type = DNS_T_A) {
8933 rr.section = DNS_S_AR;
8935 if (dns_rr_exists(&rr, F[1].answer, F->answer))
8938 while ((error = dns_rr_copy(F->answer, &rr, F[1].answer))) {
8939 if (error != DNS_ENOBUFS)
8941 if ((error = dns_p_grow(&F->answer)))
8946 dgoto(R->sp, DNS_R_SMART0_A);
8952 dgoto(--R->sp, F[-1].state);
8955 case DNS_R_SERVFAIL:
8956 if (!dns_p_setptr(&F->answer, dns_p_make(DNS_P_QBUFSIZ, &error)))
8959 dns_header(F->answer)->qr = 1;
8960 dns_header(F->answer)->rcode = DNS_RC_SERVFAIL;
8962 if ((error = dns_p_push(F->answer, DNS_S_QD, R->qname, strlen(R->qname), R->qtype, R->qclass, 0, 0)))
8965 dgoto(R->sp, DNS_R_DONE);
8974 error = DNS_ENOQUERY;
8978 error = DNS_ENOANSWER;
8982 error = DNS_EILLEGAL;
8987 } /* dns_res_exec() */
8992 void dns_res_clear(struct dns_resolver *R) {
8993 switch (R->stack[R->sp].state) {
8995 R->cache->clear(R->cache);
8998 dns_so_clear(&R->so);
9001 } /* dns_res_clear() */
9004 static int dns_res_events2(struct dns_resolver *R, enum dns_events type) {
9007 switch (R->stack[R->sp].state) {
9009 events = R->cache->events(R->cache);
9011 return (type == DNS_LIBEVENT)? DNS_POLL2EV(events) : events;
9013 return dns_so_events2(&R->so, type);
9015 } /* dns_res_events2() */
9018 int dns_res_events(struct dns_resolver *R) {
9019 return dns_res_events2(R, R->so.opts.events);
9020 } /* dns_res_events() */
9023 int dns_res_pollfd(struct dns_resolver *R) {
9024 switch (R->stack[R->sp].state) {
9026 return R->cache->pollfd(R->cache);
9028 return dns_so_pollfd(&R->so);
9030 } /* dns_res_pollfd() */
9033 time_t dns_res_timeout(struct dns_resolver *R) {
9036 switch (R->stack[R->sp].state) {
9038 case DNS_R_QUERY_AAAA:
9041 elapsed = dns_so_elapsed(&R->so);
9043 if (elapsed <= dns_resconf_timeout(R->resconf))
9044 return R->resconf->options.timeout - elapsed;
9052 * NOTE: We're not in a pollable state, or the user code hasn't
9053 * called dns_res_check properly. The calling code is probably
9054 * broken. Put them into a slow-burn pattern.
9057 } /* dns_res_timeout() */
9060 time_t dns_res_elapsed(struct dns_resolver *R) {
9061 return dns_elapsed(&R->elapsed);
9062 } /* dns_res_elapsed() */
9065 int dns_res_poll(struct dns_resolver *R, int timeout) {
9066 return dns_poll(dns_res_pollfd(R), dns_res_events2(R, DNS_SYSPOLL), timeout);
9067 } /* dns_res_poll() */
9070 int dns_res_submit2(struct dns_resolver *R, const char *qname, size_t qlen, enum dns_type qtype, enum dns_class qclass) {
9073 /* Don't anchor; that can conflict with searchlist generation. */
9074 dns_d_init(R->qname, sizeof R->qname, qname, (R->qlen = qlen), 0);
9079 dns_begin(&R->elapsed);
9081 dns_trace_res_submit(R->trace, R->qname, R->qtype, R->qclass, 0);
9084 } /* dns_res_submit2() */
9087 int dns_res_submit(struct dns_resolver *R, const char *qname, enum dns_type qtype, enum dns_class qclass) {
9088 return dns_res_submit2(R, qname, strlen(qname), qtype, qclass);
9089 } /* dns_res_submit() */
9092 int dns_res_check(struct dns_resolver *R) {
9095 if (R->stack[0].state != DNS_R_DONE) {
9096 if ((error = dns_res_exec(R)))
9101 } /* dns_res_check() */
9104 struct dns_packet *dns_res_fetch(struct dns_resolver *R, int *_error) {
9105 struct dns_packet *P = NULL;
9108 if (R->stack[0].state != DNS_R_DONE) {
9109 error = DNS_EUNKNOWN;
9113 if (!dns_p_movptr(&P, &R->stack[0].answer)) {
9114 error = DNS_EFETCHED;
9118 dns_trace_res_fetch(R->trace, P, 0);
9123 dns_trace_res_fetch(R->trace, NULL, error);
9125 } /* dns_res_fetch() */
9128 static struct dns_packet *dns_res_fetch_and_study(struct dns_resolver *R, int *_error) {
9129 struct dns_packet *P = NULL;
9132 if (!(P = dns_res_fetch(R, &error)))
9134 if ((error = dns_p_study(P)))
9144 } /* dns_res_fetch_and_study() */
9147 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_) {
9150 if ((error = dns_res_submit(res, qname, qtype, qclass)))
9153 while ((error = dns_res_check(res))) {
9154 if (dns_res_elapsed(res) > timeout)
9155 error = DNS_ETIMEDOUT;
9157 if (error != DNS_EAGAIN)
9160 if ((error = dns_res_poll(res, 1)))
9164 return dns_res_fetch(res, error_);
9169 } /* dns_res_query() */
9172 const struct dns_stat *dns_res_stat(struct dns_resolver *res) {
9173 return dns_so_stat(&res->so);
9174 } /* dns_res_stat() */
9177 void dns_res_sethints(struct dns_resolver *res, struct dns_hints *hints) {
9178 dns_hints_acquire(hints); /* acquire first in case same hints object */
9179 dns_hints_close(res->hints);
9181 } /* dns_res_sethints() */
9184 struct dns_trace *dns_res_trace(struct dns_resolver *res) {
9186 } /* dns_res_trace() */
9189 void dns_res_settrace(struct dns_resolver *res, struct dns_trace *trace) {
9190 struct dns_trace *otrace = res->trace;
9191 res->trace = dns_trace_acquire_p(trace);
9192 dns_trace_close(otrace);
9193 dns_so_settrace(&res->so, trace);
9194 } /* dns_res_settrace() */
9198 * A D D R I N F O R O U T I N E S
9200 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9202 struct dns_addrinfo {
9203 struct addrinfo hints;
9204 struct dns_resolver *res;
9205 struct dns_trace *trace;
9207 char qname[DNS_D_MAXNAME + 1];
9208 enum dns_type qtype;
9209 unsigned short qport, port;
9215 enum dns_type qtype;
9218 struct dns_packet *answer;
9219 struct dns_packet *glue;
9221 struct dns_rr_i i, g;
9224 char cname[DNS_D_MAXNAME + 1];
9225 char i_cname[DNS_D_MAXNAME + 1], g_cname[DNS_D_MAXNAME + 1];
9233 }; /* struct dns_addrinfo */
9236 #define DNS_AI_AFMAX 32
9237 #define DNS_AI_AF2INDEX(af) (1UL << ((af) - 1))
9239 static inline unsigned long dns_ai_af2index(int af) {
9240 dns_static_assert(dns_same_type(unsigned long, DNS_AI_AF2INDEX(1), 1), "internal type mismatch");
9241 dns_static_assert(dns_same_type(unsigned long, ((struct dns_addrinfo *)0)->af.todo, 1), "internal type mismatch");
9243 return (af > 0 && af <= DNS_AI_AFMAX)? DNS_AI_AF2INDEX(af) : 0;
9246 static int dns_ai_setaf(struct dns_addrinfo *ai, int af, int qtype) {
9248 ai->af.qtype = qtype;
9250 ai->af.todo &= ~dns_ai_af2index(af);
9253 } /* dns_ai_setaf() */
9255 #define DNS_SM_RESTORE \
9256 do { pc = 0xff & (ai->af.state >> 0); i = 0xff & (ai->af.state >> 8); } while (0)
9257 #define DNS_SM_SAVE \
9258 do { ai->af.state = ((0xff & pc) << 0) | ((0xff & i) << 8); } while (0)
9260 static int dns_ai_nextaf(struct dns_addrinfo *ai) {
9263 dns_static_assert(AF_UNSPEC == 0, "AF_UNSPEC constant not 0");
9264 dns_static_assert(AF_INET <= DNS_AI_AFMAX, "AF_INET constant too large");
9265 dns_static_assert(AF_INET6 <= DNS_AI_AFMAX, "AF_INET6 constant too large");
9271 * NB: On OpenBSD, at least, the types of entries resolved
9272 * is the intersection of the /etc/resolv.conf families and
9273 * the families permitted by the .ai_type hint. So if
9274 * /etc/resolv.conf has "family inet4" and .ai_type
9275 * is AF_INET6, then the address ::1 will return 0 entries
9276 * even if AI_NUMERICHOST is specified in .ai_flags.
9278 while (i < (int)lengthof(ai->res->resconf->family)) {
9279 int af = ai->res->resconf->family[i++];
9281 if (af == AF_UNSPEC) {
9283 } else if (af < 0 || af > DNS_AI_AFMAX) {
9285 } else if (!(DNS_AI_AF2INDEX(af) & ai->af.todo)) {
9287 } else if (af == AF_INET) {
9288 DNS_SM_YIELD(dns_ai_setaf(ai, AF_INET, DNS_T_A));
9289 } else if (af == AF_INET6) {
9290 DNS_SM_YIELD(dns_ai_setaf(ai, AF_INET6, DNS_T_AAAA));
9295 * NB: If we get here than AI_NUMERICFLAGS should be set and
9296 * order shouldn't matter.
9298 if (DNS_AI_AF2INDEX(AF_INET) & ai->af.todo)
9299 DNS_SM_YIELD(dns_ai_setaf(ai, AF_INET, DNS_T_A));
9300 if (DNS_AI_AF2INDEX(AF_INET6) & ai->af.todo)
9301 DNS_SM_YIELD(dns_ai_setaf(ai, AF_INET6, DNS_T_AAAA));
9306 return dns_ai_setaf(ai, AF_UNSPEC, 0);
9307 } /* dns_ai_nextaf() */
9309 #undef DNS_SM_RESTORE
9312 static enum dns_type dns_ai_qtype(struct dns_addrinfo *ai) {
9313 return (ai->qtype)? ai->qtype : ai->af.qtype;
9314 } /* dns_ai_qtype() */
9316 /* JW: This is not defined on mingw. */
9317 #ifndef AI_NUMERICSERV
9318 #define AI_NUMERICSERV 0
9321 static dns_error_t dns_ai_parseport(unsigned short *port, const char *serv, const struct addrinfo *hints) {
9322 const char *cp = serv;
9323 unsigned long n = 0;
9325 while (*cp >= '0' && *cp <= '9' && n < 65536) {
9331 if (cp == serv || n >= 65536)
9332 return DNS_ESERVICE;
9339 if (hints->ai_flags & AI_NUMERICSERV)
9340 return DNS_ESERVICE;
9342 /* TODO: try getaddrinfo(NULL, serv, { .ai_flags = AI_NUMERICSERV }) */
9344 return DNS_ESERVICE;
9345 } /* dns_ai_parseport() */
9348 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) {
9349 static const struct dns_addrinfo ai_initializer;
9350 struct dns_addrinfo *ai;
9354 dns_res_acquire(res);
9355 } else if (!(hints->ai_flags & AI_NUMERICHOST)) {
9357 * NOTE: it's assumed that *_error is set from a previous
9358 * API function call, such as dns_res_stub(). Should change
9359 * this semantic, but it's applied elsewhere, too.
9366 if (!(ai = malloc(sizeof *ai)))
9369 *ai = ai_initializer;
9375 if (sizeof ai->qname <= dns_strlcpy(ai->qname, host, sizeof ai->qname))
9376 { error = ENAMETOOLONG; goto error; }
9381 if (serv && (error = dns_ai_parseport(&ai->qport, serv, hints)))
9383 ai->port = ai->qport;
9386 * FIXME: If an explicit A or AAAA record type conflicts with
9387 * .ai_family or with resconf.family (i.e. AAAA specified but
9388 * AF_INET6 not in interection of .ai_family and resconf.family),
9391 switch (ai->qtype) {
9393 ai->af.todo = DNS_AI_AF2INDEX(AF_INET);
9396 ai->af.todo = DNS_AI_AF2INDEX(AF_INET6);
9398 default: /* 0, MX, SRV, etc */
9399 switch (ai->hints.ai_family) {
9401 ai->af.todo = DNS_AI_AF2INDEX(AF_INET) | DNS_AI_AF2INDEX(AF_INET6);
9404 ai->af.todo = DNS_AI_AF2INDEX(AF_INET);
9407 ai->af.todo = DNS_AI_AF2INDEX(AF_INET6);
9416 error = dns_syerr();
9424 } /* dns_ai_open() */
9427 void dns_ai_close(struct dns_addrinfo *ai) {
9431 dns_res_close(ai->res);
9432 dns_trace_close(ai->trace);
9434 if (ai->answer != ai->glue)
9435 dns_p_free(ai->glue);
9437 dns_p_free(ai->answer);
9439 } /* dns_ai_close() */
9442 static int dns_ai_setent(struct addrinfo **ent, union dns_any *any, enum dns_type type, struct dns_addrinfo *ai) {
9444 struct sockaddr_in sin;
9445 struct sockaddr_in6 sin6;
9446 struct sockaddr_storage ss;
9453 memset(&addr.sin, '\0', sizeof addr.sin);
9455 addr.sin.sin_family = AF_INET;
9456 addr.sin.sin_port = htons(ai->port);
9458 memcpy(&addr.sin.sin_addr, any, sizeof addr.sin.sin_addr);
9462 memset(&addr.sin6, '\0', sizeof addr.sin6);
9464 addr.sin6.sin6_family = AF_INET6;
9465 addr.sin6.sin6_port = htons(ai->port);
9467 memcpy(&addr.sin6.sin6_addr, any, sizeof addr.sin6.sin6_addr);
9474 if (ai->hints.ai_flags & AI_CANONNAME) {
9475 cname = (*ai->cname)? ai->cname : ai->qname;
9476 clen = strlen(cname);
9482 if (!(*ent = malloc(sizeof **ent + dns_sa_len(&addr) + ((ai->hints.ai_flags & AI_CANONNAME)? clen + 1 : 0))))
9485 memset(*ent, '\0', sizeof **ent);
9487 (*ent)->ai_family = addr.ss.ss_family;
9488 (*ent)->ai_socktype = ai->hints.ai_socktype;
9489 (*ent)->ai_protocol = ai->hints.ai_protocol;
9491 (*ent)->ai_addr = memcpy((unsigned char *)*ent + sizeof **ent, &addr, dns_sa_len(&addr));
9492 (*ent)->ai_addrlen = dns_sa_len(&addr);
9494 if (ai->hints.ai_flags & AI_CANONNAME)
9495 (*ent)->ai_canonname = memcpy((unsigned char *)*ent + sizeof **ent + dns_sa_len(&addr), cname, clen + 1);
9500 } /* dns_ai_setent() */
9518 }; /* enum dns_ai_state */
9520 #define dns_ai_goto(which) do { ai->state = (which); goto exec; } while (0)
9522 int dns_ai_nextent(struct addrinfo **ent, struct dns_addrinfo *ai) {
9523 struct dns_packet *ans, *glue;
9525 char qname[DNS_D_MAXNAME + 1];
9534 switch (ai->state) {
9537 case DNS_AI_S_NEXTAF:
9538 if (!dns_ai_nextaf(ai))
9539 dns_ai_goto(DNS_AI_S_DONE);
9542 case DNS_AI_S_NUMERIC:
9543 if (1 == dns_inet_pton(AF_INET, ai->qname, &any.a)) {
9544 if (ai->af.atype == AF_INET) {
9545 ai->state = DNS_AI_S_NEXTAF;
9546 return dns_ai_setent(ent, &any, DNS_T_A, ai);
9548 dns_ai_goto(DNS_AI_S_NEXTAF);
9552 if (1 == dns_inet_pton(AF_INET6, ai->qname, &any.aaaa)) {
9553 if (ai->af.atype == AF_INET6) {
9554 ai->state = DNS_AI_S_NEXTAF;
9555 return dns_ai_setent(ent, &any, DNS_T_AAAA, ai);
9557 dns_ai_goto(DNS_AI_S_NEXTAF);
9561 if (ai->hints.ai_flags & AI_NUMERICHOST)
9562 dns_ai_goto(DNS_AI_S_NEXTAF);
9565 case DNS_AI_S_SUBMIT:
9568 if ((error = dns_res_submit(ai->res, ai->qname, dns_ai_qtype(ai), DNS_C_IN)))
9572 case DNS_AI_S_CHECK:
9573 if ((error = dns_res_check(ai->res)))
9577 case DNS_AI_S_FETCH:
9578 if (!(ans = dns_res_fetch_and_study(ai->res, &error)))
9580 if (ai->glue != ai->answer)
9581 dns_p_free(ai->glue);
9582 ai->glue = dns_p_movptr(&ai->answer, &ans);
9584 /* Search generator may have changed the qname. */
9585 if (!(qlen = dns_d_expand(qname, sizeof qname, 12, ai->answer, &error)))
9587 else if (qlen >= sizeof qname)
9588 return DNS_EILLEGAL;
9589 if (!dns_d_cname(ai->cname, sizeof ai->cname, qname, qlen, ai->answer, &error))
9592 dns_strlcpy(ai->i_cname, ai->cname, sizeof ai->i_cname);
9593 dns_rr_i_init(&ai->i, ai->answer);
9594 ai->i.section = DNS_S_AN;
9595 ai->i.name = ai->i_cname;
9596 ai->i.type = dns_ai_qtype(ai);
9597 ai->i.sort = &dns_rr_i_order;
9600 case DNS_AI_S_FOREACH_I:
9601 if (!dns_rr_grep(&rr, 1, &ai->i, ai->answer, &error))
9602 dns_ai_goto(DNS_AI_S_NEXTAF);
9604 if ((error = dns_any_parse(&any, &rr, ai->answer)))
9607 ai->port = ai->qport;
9612 return dns_ai_setent(ent, &any, rr.type, ai);
9614 if (!(clen = dns_any_cname(ai->cname, sizeof ai->cname, &any, rr.type)))
9615 dns_ai_goto(DNS_AI_S_FOREACH_I);
9618 * Find the "real" canonical name. Some authorities
9619 * publish aliases where an RFC defines a canonical
9620 * name. We trust that the resolver followed any
9621 * CNAME chains on it's own, regardless of whether
9622 * the "smart" option is enabled.
9624 if (!dns_d_cname(ai->cname, sizeof ai->cname, ai->cname, clen, ai->answer, &error))
9627 if (rr.type == DNS_T_SRV)
9628 ai->port = any.srv.port;
9634 case DNS_AI_S_INIT_G:
9638 case DNS_AI_S_ITERATE_G:
9639 dns_strlcpy(ai->g_cname, ai->cname, sizeof ai->g_cname);
9640 dns_rr_i_init(&ai->g, ai->glue);
9641 ai->g.section = DNS_S_ALL & ~DNS_S_QD;
9642 ai->g.name = ai->g_cname;
9643 ai->g.type = ai->af.qtype;
9646 case DNS_AI_S_FOREACH_G:
9647 if (!dns_rr_grep(&rr, 1, &ai->g, ai->glue, &error)) {
9648 if (dns_rr_i_count(&ai->g) > 0)
9649 dns_ai_goto(DNS_AI_S_FOREACH_I);
9651 dns_ai_goto(DNS_AI_S_SUBMIT_G);
9654 if ((error = dns_any_parse(&any, &rr, ai->glue)))
9657 return dns_ai_setent(ent, &any, rr.type, ai);
9658 case DNS_AI_S_SUBMIT_G:
9659 /* skip if already queried */
9660 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))
9661 dns_ai_goto(DNS_AI_S_FOREACH_I);
9662 /* skip if we recursed (CNAME chains should have been handled in the resolver) */
9663 if (++ai->g_depth > 1)
9664 dns_ai_goto(DNS_AI_S_FOREACH_I);
9666 if ((error = dns_res_submit(ai->res, ai->g.name, ai->g.type, DNS_C_IN)))
9670 case DNS_AI_S_CHECK_G:
9671 if ((error = dns_res_check(ai->res)))
9675 case DNS_AI_S_FETCH_G:
9676 if (!(ans = dns_res_fetch_and_study(ai->res, &error)))
9679 glue = dns_p_merge(ai->glue, DNS_S_ALL, ans, DNS_S_ALL, &error);
9680 dns_p_setptr(&ans, NULL);
9684 if (ai->glue != ai->answer)
9685 dns_p_free(ai->glue);
9688 if (!dns_d_cname(ai->cname, sizeof ai->cname, ai->g.name, strlen(ai->g.name), ai->glue, &error))
9689 dns_ai_goto(DNS_AI_S_FOREACH_I);
9691 dns_ai_goto(DNS_AI_S_ITERATE_G);
9694 return ENOENT; /* TODO: Just return 0 */
9695 } else if (ai->answer) {
9696 switch (dns_p_rcode(ai->answer)) {
9697 case DNS_RC_NOERROR:
9699 case DNS_RC_NXDOMAIN:
9710 } /* dns_ai_nextent() */
9713 time_t dns_ai_elapsed(struct dns_addrinfo *ai) {
9714 return (ai->res)? dns_res_elapsed(ai->res) : 0;
9715 } /* dns_ai_elapsed() */
9718 void dns_ai_clear(struct dns_addrinfo *ai) {
9720 dns_res_clear(ai->res);
9721 } /* dns_ai_clear() */
9724 int dns_ai_events(struct dns_addrinfo *ai) {
9725 return (ai->res)? dns_res_events(ai->res) : 0;
9726 } /* dns_ai_events() */
9729 int dns_ai_pollfd(struct dns_addrinfo *ai) {
9730 return (ai->res)? dns_res_pollfd(ai->res) : -1;
9731 } /* dns_ai_pollfd() */
9734 time_t dns_ai_timeout(struct dns_addrinfo *ai) {
9735 return (ai->res)? dns_res_timeout(ai->res) : 0;
9736 } /* dns_ai_timeout() */
9739 int dns_ai_poll(struct dns_addrinfo *ai, int timeout) {
9740 return (ai->res)? dns_res_poll(ai->res, timeout) : 0;
9741 } /* dns_ai_poll() */
9744 size_t dns_ai_print(void *_dst, size_t lim, struct addrinfo *ent, struct dns_addrinfo *ai) {
9745 struct dns_buf dst = DNS_B_INTO(_dst, lim);
9746 char addr[DNS_PP_MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) + 1];
9748 dns_b_puts(&dst, "[ ");
9749 dns_b_puts(&dst, ai->qname);
9750 dns_b_puts(&dst, " IN ");
9752 dns_b_puts(&dst, dns_strtype(ai->qtype));
9753 } else if (ent->ai_family == AF_INET) {
9754 dns_b_puts(&dst, dns_strtype(DNS_T_A));
9755 } else if (ent->ai_family == AF_INET6) {
9756 dns_b_puts(&dst, dns_strtype(DNS_T_AAAA));
9758 dns_b_puts(&dst, "0");
9760 dns_b_puts(&dst, " ]\n");
9762 dns_b_puts(&dst, ".ai_family = ");
9763 switch (ent->ai_family) {
9765 dns_b_puts(&dst, "AF_INET");
9768 dns_b_puts(&dst, "AF_INET6");
9771 dns_b_fmtju(&dst, ent->ai_family, 0);
9774 dns_b_putc(&dst, '\n');
9776 dns_b_puts(&dst, ".ai_socktype = ");
9777 switch (ent->ai_socktype) {
9779 dns_b_puts(&dst, "SOCK_STREAM");
9782 dns_b_puts(&dst, "SOCK_DGRAM");
9785 dns_b_fmtju(&dst, ent->ai_socktype, 0);
9788 dns_b_putc(&dst, '\n');
9790 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);
9791 dns_b_puts(&dst, ".ai_addr = [");
9792 dns_b_puts(&dst, addr);
9793 dns_b_puts(&dst, "]:");
9794 dns_b_fmtju(&dst, ntohs(*dns_sa_port(dns_sa_family(ent->ai_addr), ent->ai_addr)), 0);
9795 dns_b_putc(&dst, '\n');
9797 dns_b_puts(&dst, ".ai_canonname = ");
9798 dns_b_puts(&dst, (ent->ai_canonname)? ent->ai_canonname : "[NULL]");
9799 dns_b_putc(&dst, '\n');
9801 return dns_b_strllen(&dst);
9802 } /* dns_ai_print() */
9805 const struct dns_stat *dns_ai_stat(struct dns_addrinfo *ai) {
9806 return (ai->res)? dns_res_stat(ai->res) : &ai->st;
9807 } /* dns_ai_stat() */
9810 struct dns_trace *dns_ai_trace(struct dns_addrinfo *ai) {
9812 } /* dns_ai_trace() */
9815 void dns_ai_settrace(struct dns_addrinfo *ai, struct dns_trace *trace) {
9816 struct dns_trace *otrace = ai->trace;
9817 ai->trace = dns_trace_acquire_p(trace);
9818 dns_trace_close(otrace);
9820 dns_res_settrace(ai->res, trace);
9821 } /* dns_ai_settrace() */
9825 * M I S C E L L A N E O U S R O U T I N E S
9827 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9829 static const struct {
9831 enum dns_section type;
9832 } dns_sections[] = {
9833 { "QUESTION", DNS_S_QUESTION },
9834 { "QD", DNS_S_QUESTION },
9835 { "ANSWER", DNS_S_ANSWER },
9836 { "AN", DNS_S_ANSWER },
9837 { "AUTHORITY", DNS_S_AUTHORITY },
9838 { "NS", DNS_S_AUTHORITY },
9839 { "ADDITIONAL", DNS_S_ADDITIONAL },
9840 { "AR", DNS_S_ADDITIONAL },
9843 const char *(dns_strsection)(enum dns_section section, void *_dst, size_t lim) {
9844 struct dns_buf dst = DNS_B_INTO(_dst, lim);
9847 for (i = 0; i < lengthof(dns_sections); i++) {
9848 if (dns_sections[i].type & section) {
9849 dns_b_puts(&dst, dns_sections[i].name);
9850 section &= ~dns_sections[i].type;
9852 dns_b_putc(&dst, '|');
9856 if (section || dst.p == dst.base)
9857 dns_b_fmtju(&dst, (0xffff & section), 0);
9859 return dns_b_tostring(&dst);
9860 } /* dns_strsection() */
9863 enum dns_section dns_isection(const char *src) {
9864 enum dns_section section = 0;
9869 dns_strlcpy(sbuf, src, sizeof sbuf);
9872 while ((name = dns_strsep(&next, "|+, \t"))) {
9873 for (i = 0; i < lengthof(dns_sections); i++) {
9874 if (!strcasecmp(dns_sections[i].name, name)) {
9875 section |= dns_sections[i].type;
9882 } /* dns_isection() */
9885 static const struct {
9887 enum dns_class type;
9892 const char *(dns_strclass)(enum dns_class type, void *_dst, size_t lim) {
9893 struct dns_buf dst = DNS_B_INTO(_dst, lim);
9896 for (i = 0; i < lengthof(dns_classes); i++) {
9897 if (dns_classes[i].type == type) {
9898 dns_b_puts(&dst, dns_classes[i].name);
9903 if (dst.p == dst.base)
9904 dns_b_fmtju(&dst, (0xffff & type), 0);
9906 return dns_b_tostring(&dst);
9907 } /* dns_strclass() */
9910 enum dns_class dns_iclass(const char *name) {
9913 for (i = 0; i < lengthof(dns_classes); i++) {
9914 if (!strcasecmp(dns_classes[i].name, name))
9915 return dns_classes[i].type;
9919 while (dns_isdigit(*name)) {
9921 class += *name++ - '0';
9924 return DNS_PP_MIN(class, 0xffff);
9925 } /* dns_iclass() */
9928 const char *(dns_strtype)(enum dns_type type, void *_dst, size_t lim) {
9929 struct dns_buf dst = DNS_B_INTO(_dst, lim);
9932 for (i = 0; i < lengthof(dns_rrtypes); i++) {
9933 if (dns_rrtypes[i].type == type) {
9934 dns_b_puts(&dst, dns_rrtypes[i].name);
9939 if (dst.p == dst.base)
9940 dns_b_fmtju(&dst, (0xffff & type), 0);
9942 return dns_b_tostring(&dst);
9943 } /* dns_strtype() */
9946 enum dns_type dns_itype(const char *name) {
9949 for (i = 0; i < lengthof(dns_rrtypes); i++) {
9950 if (!strcasecmp(dns_rrtypes[i].name, name))
9951 return dns_rrtypes[i].type;
9955 while (dns_isdigit(*name)) {
9957 type += *name++ - '0';
9960 return DNS_PP_MIN(type, 0xffff);
9964 static char dns_opcodes[16][16] = {
9965 [DNS_OP_QUERY] = "QUERY",
9966 [DNS_OP_IQUERY] = "IQUERY",
9967 [DNS_OP_STATUS] = "STATUS",
9968 [DNS_OP_NOTIFY] = "NOTIFY",
9969 [DNS_OP_UPDATE] = "UPDATE",
9972 static const char *dns__strcode(int code, volatile char *dst, size_t lim) {
9978 dns_b_fmtju(dns_b_into(&tmp, _tmp, DNS_PP_MIN(sizeof _tmp, lim - 1)), code, 0);
9980 /* copy downwards so first byte is copied last (see below) */
9981 p = (size_t)(tmp.p - tmp.base);
9986 return (const char *)dst;
9989 const char *dns_stropcode(enum dns_opcode opcode) {
9990 opcode = (unsigned)opcode % lengthof(dns_opcodes);
9992 if ('\0' == dns_opcodes[opcode][0])
9993 return dns__strcode(opcode, dns_opcodes[opcode], sizeof dns_opcodes[opcode]);
9995 return dns_opcodes[opcode];
9996 } /* dns_stropcode() */
9999 enum dns_opcode dns_iopcode(const char *name) {
10002 for (opcode = 0; opcode < lengthof(dns_opcodes); opcode++) {
10003 if (!strcasecmp(name, dns_opcodes[opcode]))
10008 while (dns_isdigit(*name)) {
10010 opcode += *name++ - '0';
10013 return DNS_PP_MIN(opcode, 0x0f);
10014 } /* dns_iopcode() */
10017 static char dns_rcodes[32][16] = {
10018 [DNS_RC_NOERROR] = "NOERROR",
10019 [DNS_RC_FORMERR] = "FORMERR",
10020 [DNS_RC_SERVFAIL] = "SERVFAIL",
10021 [DNS_RC_NXDOMAIN] = "NXDOMAIN",
10022 [DNS_RC_NOTIMP] = "NOTIMP",
10023 [DNS_RC_REFUSED] = "REFUSED",
10024 [DNS_RC_YXDOMAIN] = "YXDOMAIN",
10025 [DNS_RC_YXRRSET] = "YXRRSET",
10026 [DNS_RC_NXRRSET] = "NXRRSET",
10027 [DNS_RC_NOTAUTH] = "NOTAUTH",
10028 [DNS_RC_NOTZONE] = "NOTZONE",
10029 /* EDNS(0) extended RCODEs ... */
10030 [DNS_RC_BADVERS] = "BADVERS",
10033 const char *dns_strrcode(enum dns_rcode rcode) {
10034 rcode = (unsigned)rcode % lengthof(dns_rcodes);
10036 if ('\0' == dns_rcodes[rcode][0])
10037 return dns__strcode(rcode, dns_rcodes[rcode], sizeof dns_rcodes[rcode]);
10039 return dns_rcodes[rcode];
10040 } /* dns_strrcode() */
10043 enum dns_rcode dns_ircode(const char *name) {
10046 for (rcode = 0; rcode < lengthof(dns_rcodes); rcode++) {
10047 if (!strcasecmp(name, dns_rcodes[rcode]))
10052 while (dns_isdigit(*name)) {
10054 rcode += *name++ - '0';
10057 return DNS_PP_MIN(rcode, 0xfff);
10058 } /* dns_ircode() */
10063 * 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
10065 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
10068 #include <stdarg.h>
10069 #include <stdlib.h>
10075 #include <getopt.h>
10085 const char *path[8];
10087 } resconf, nssconf, hosts, cache;
10090 enum dns_type qtype;
10099 struct dns_resolv_conf *resconf;
10100 struct dns_hosts *hosts;
10101 struct dns_trace *trace;
10104 struct sockaddr_storage socks_host;
10105 const char *socks_user;
10106 const char *socks_password;
10108 .sort = &dns_rr_i_packet,
10112 static void hexdump(const unsigned char *src, size_t len, FILE *fp) {
10113 struct dns_hxd_lines_i lines = { 0 };
10116 while (dns_hxd_lines(line, sizeof line, src, len, &lines)) {
10122 DNS_NORETURN static void panic(const char *fmt, ...) {
10128 vfprintf(stderr, fmt, ap);
10130 exit(EXIT_FAILURE);
10132 verrx(EXIT_FAILURE, fmt, ap);
10136 #define panic_(fn, ln, fmt, ...) \
10137 panic(fmt "%0s", (fn), (ln), __VA_ARGS__)
10138 #define panic(...) \
10139 panic_(__func__, __LINE__, "(%s:%d) " __VA_ARGS__, "")
10142 static void *grow(unsigned char *p, size_t size) {
10145 if (!(tmp = realloc(p, size)))
10146 panic("realloc(%"PRIuZ"): %s", size, dns_strerror(errno));
10152 static size_t add(size_t a, size_t b) {
10154 panic("%"PRIuZ" + %"PRIuZ": integer overflow", a, b);
10160 static size_t append(unsigned char **dst, size_t osize, const void *src, size_t len) {
10161 size_t size = add(osize, len);
10163 *dst = grow(*dst, size);
10164 memcpy(*dst + osize, src, len);
10170 static size_t slurp(unsigned char **dst, size_t osize, FILE *fp, const char *path) {
10171 size_t size = osize;
10172 unsigned char buf[1024];
10175 while ((count = fread(buf, 1, sizeof buf, fp)))
10176 size = append(dst, size, buf, count);
10179 panic("%s: %s", path, dns_strerror(errno));
10185 static struct dns_resolv_conf *resconf(void) {
10186 struct dns_resolv_conf **resconf = &MAIN.memo.resconf;
10194 if (!(*resconf = dns_resconf_open(&error)))
10195 panic("dns_resconf_open: %s", dns_strerror(error));
10197 if (!MAIN.resconf.count)
10198 MAIN.resconf.path[MAIN.resconf.count++] = "/etc/resolv.conf";
10200 for (i = 0; i < MAIN.resconf.count; i++) {
10201 path = MAIN.resconf.path[i];
10203 if (0 == strcmp(path, "-"))
10204 error = dns_resconf_loadfile(*resconf, stdin);
10206 error = dns_resconf_loadpath(*resconf, path);
10209 panic("%s: %s", path, dns_strerror(error));
10212 for (i = 0; i < MAIN.nssconf.count; i++) {
10213 path = MAIN.nssconf.path[i];
10215 if (0 == strcmp(path, "-"))
10216 error = dns_nssconf_loadfile(*resconf, stdin);
10218 error = dns_nssconf_loadpath(*resconf, path);
10221 panic("%s: %s", path, dns_strerror(error));
10224 if (!MAIN.nssconf.count) {
10225 path = "/etc/nsswitch.conf";
10227 if (!(error = dns_nssconf_loadpath(*resconf, path)))
10228 MAIN.nssconf.path[MAIN.nssconf.count++] = path;
10229 else if (error != ENOENT)
10230 panic("%s: %s", path, dns_strerror(error));
10237 static struct dns_hosts *hosts(void) {
10238 struct dns_hosts **hosts = &MAIN.memo.hosts;
10246 if (!MAIN.hosts.count) {
10247 MAIN.hosts.path[MAIN.hosts.count++] = "/etc/hosts";
10249 /* Explicitly test dns_hosts_local() */
10250 if (!(*hosts = dns_hosts_local(&error)))
10251 panic("%s: %s", "/etc/hosts", dns_strerror(error));
10256 if (!(*hosts = dns_hosts_open(&error)))
10257 panic("dns_hosts_open: %s", dns_strerror(error));
10259 for (i = 0; i < MAIN.hosts.count; i++) {
10260 path = MAIN.hosts.path[i];
10262 if (0 == strcmp(path, "-"))
10263 error = dns_hosts_loadfile(*hosts, stdin);
10265 error = dns_hosts_loadpath(*hosts, path);
10268 panic("%s: %s", path, dns_strerror(error));
10278 static struct dns_cache *cache(void) {
10279 static struct cache *cache;
10285 return cache_resi(cache);
10286 if (!MAIN.cache.count)
10289 if (!(cache = cache_open(&error)))
10290 panic("%s: %s", MAIN.cache.path[0], dns_strerror(error));
10292 for (i = 0; i < MAIN.cache.count; i++) {
10293 path = MAIN.cache.path[i];
10295 if (!strcmp(path, "-")) {
10296 if ((error = cache_loadfile(cache, stdin, NULL, 0)))
10297 panic("%s: %s", path, dns_strerror(error));
10298 } else if ((error = cache_loadpath(cache, path, NULL, 0)))
10299 panic("%s: %s", path, dns_strerror(error));
10302 return cache_resi(cache);
10305 static struct dns_cache *cache(void) { return NULL; }
10309 static struct dns_trace *trace(const char *mode) {
10310 static char omode[64] = "";
10311 struct dns_trace **trace = &MAIN.memo.trace;
10315 if (*trace && 0 == strcmp(omode, mode))
10320 if (!(fp = fopen(MAIN.trace, mode)))
10321 panic("%s: %s", MAIN.trace, strerror(errno));
10322 dns_trace_close(*trace);
10323 if (!(*trace = dns_trace_open(fp, &error)))
10324 panic("%s: %s", MAIN.trace, dns_strerror(error));
10325 dns_strlcpy(omode, mode, sizeof omode);
10331 static void print_packet(struct dns_packet *P, FILE *fp) {
10332 dns_p_dump3(P, dns_rr_i_new(P, .sort = MAIN.sort), fp);
10334 if (MAIN.verbose > 2)
10335 hexdump(P->data, P->end, fp);
10336 } /* print_packet() */
10339 static int parse_packet(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
10340 struct dns_packet *P = dns_p_new(512);
10341 struct dns_packet *Q = dns_p_new(512);
10342 enum dns_section section;
10346 char pretty[sizeof any * 2];
10349 P->end = fread(P->data, 1, P->size, stdin);
10351 fputs(";; [HEADER]\n", stdout);
10352 fprintf(stdout, ";; qr : %s(%d)\n", (dns_header(P)->qr)? "RESPONSE" : "QUERY", dns_header(P)->qr);
10353 fprintf(stdout, ";; opcode : %s(%d)\n", dns_stropcode(dns_header(P)->opcode), dns_header(P)->opcode);
10354 fprintf(stdout, ";; aa : %s(%d)\n", (dns_header(P)->aa)? "AUTHORITATIVE" : "NON-AUTHORITATIVE", dns_header(P)->aa);
10355 fprintf(stdout, ";; tc : %s(%d)\n", (dns_header(P)->tc)? "TRUNCATED" : "NOT-TRUNCATED", dns_header(P)->tc);
10356 fprintf(stdout, ";; rd : %s(%d)\n", (dns_header(P)->rd)? "RECURSION-DESIRED" : "RECURSION-NOT-DESIRED", dns_header(P)->rd);
10357 fprintf(stdout, ";; ra : %s(%d)\n", (dns_header(P)->ra)? "RECURSION-ALLOWED" : "RECURSION-NOT-ALLOWED", dns_header(P)->ra);
10358 fprintf(stdout, ";; rcode : %s(%d)\n", dns_strrcode(dns_p_rcode(P)), dns_p_rcode(P));
10362 dns_rr_foreach(&rr, P, .sort = MAIN.sort) {
10363 if (section != rr.section)
10364 fprintf(stdout, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(P, rr.section));
10366 if ((len = dns_rr_print(pretty, sizeof pretty, &rr, P, &error)))
10367 fprintf(stdout, "%s\n", pretty);
10369 dns_rr_copy(Q, &rr, P);
10371 section = rr.section;
10374 fputs("; ; ; ; ; ; ; ;\n\n", stdout);
10379 dns_rr_foreach(&rr, Q, .name = "ns8.yahoo.com.") {
10381 struct dns_rr rrset[32];
10382 struct dns_rr_i *rri = dns_rr_i_new(Q, .name = dns_d_new("ns8.yahoo.com", DNS_D_ANCHOR), .sort = MAIN.sort);
10383 unsigned rrcount = dns_rr_grep(rrset, lengthof(rrset), rri, Q, &error);
10385 for (unsigned i = 0; i < rrcount; i++) {
10388 if (section != rr.section)
10389 fprintf(stdout, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(Q, rr.section));
10391 if ((len = dns_rr_print(pretty, sizeof pretty, &rr, Q, &error)))
10392 fprintf(stdout, "%s\n", pretty);
10394 section = rr.section;
10397 if (MAIN.verbose > 1) {
10398 fprintf(stderr, "orig:%"PRIuZ"\n", P->end);
10399 hexdump(P->data, P->end, stdout);
10401 fprintf(stderr, "copy:%"PRIuZ"\n", Q->end);
10402 hexdump(Q->data, Q->end, stdout);
10406 } /* parse_packet() */
10409 static int parse_domain(int argc, char *argv[]) {
10412 dn = (argc > 1)? argv[1] : "f.l.google.com";
10414 printf("[%s]\n", dn);
10416 dn = dns_d_new(dn);
10420 } while (dns_d_cleave(dn, strlen(dn) + 1, dn, strlen(dn)));
10423 } /* parse_domain() */
10426 static int trim_domain(int argc, char **argv) {
10427 for (argc--, argv++; argc > 0; argc--, argv++) {
10428 char name[DNS_D_MAXNAME + 1];
10430 dns_d_trim(name, sizeof name, *argv, strlen(*argv), DNS_D_ANCHOR);
10436 } /* trim_domain() */
10439 static int expand_domain(int argc, char *argv[]) {
10440 unsigned short rp = 0;
10441 unsigned char *src = NULL;
10442 unsigned char *dst;
10443 struct dns_packet *pkt;
10444 size_t lim = 0, len;
10448 rp = atoi(argv[1]);
10450 len = slurp(&src, 0, stdin, "-");
10452 if (!(pkt = dns_p_make(len, &error)))
10453 panic("malloc(%"PRIuZ"): %s", len, dns_strerror(error));
10455 memcpy(pkt->data, src, len);
10459 dst = grow(NULL, lim);
10461 while (lim <= (len = dns_d_expand(dst, lim, rp, pkt, &error))) {
10463 dst = grow(dst, lim);
10467 panic("expand: %s", dns_strerror(error));
10469 fwrite(dst, 1, len, stdout);
10477 } /* expand_domain() */
10480 static int show_resconf(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
10483 resconf(); /* load it */
10485 fputs("; SOURCES\n", stdout);
10487 for (i = 0; i < MAIN.resconf.count; i++)
10488 fprintf(stdout, "; %s\n", MAIN.resconf.path[i]);
10490 for (i = 0; i < MAIN.nssconf.count; i++)
10491 fprintf(stdout, "; %s\n", MAIN.nssconf.path[i]);
10493 fputs(";\n", stdout);
10495 dns_resconf_dump(resconf(), stdout);
10498 } /* show_resconf() */
10501 static int show_nssconf(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
10506 fputs("# SOURCES\n", stdout);
10508 for (i = 0; i < MAIN.resconf.count; i++)
10509 fprintf(stdout, "# %s\n", MAIN.resconf.path[i]);
10511 for (i = 0; i < MAIN.nssconf.count; i++)
10512 fprintf(stdout, "# %s\n", MAIN.nssconf.path[i]);
10514 fputs("#\n", stdout);
10516 dns_nssconf_dump(resconf(), stdout);
10519 } /* show_nssconf() */
10522 static int show_hosts(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
10527 fputs("# SOURCES\n", stdout);
10529 for (i = 0; i < MAIN.hosts.count; i++)
10530 fprintf(stdout, "# %s\n", MAIN.hosts.path[i]);
10532 fputs("#\n", stdout);
10534 dns_hosts_dump(hosts(), stdout);
10537 } /* show_hosts() */
10540 static int query_hosts(int argc, char *argv[]) {
10541 struct dns_packet *Q = dns_p_new(512);
10542 struct dns_packet *A;
10543 char qname[DNS_D_MAXNAME + 1];
10548 MAIN.qname = (argc > 1)? argv[1] : "localhost";
10550 MAIN.qtype = DNS_T_A;
10554 if (MAIN.qtype == DNS_T_PTR && !strstr(MAIN.qname, "arpa")) {
10555 union { struct in_addr a; struct in6_addr a6; } addr;
10556 int af = (strchr(MAIN.qname, ':'))? AF_INET6 : AF_INET;
10558 if ((error = dns_pton(af, MAIN.qname, &addr)))
10559 panic("%s: %s", MAIN.qname, dns_strerror(error));
10561 qlen = dns_ptr_qname(qname, sizeof qname, af, &addr);
10563 qlen = dns_strlcpy(qname, MAIN.qname, sizeof qname);
10565 if ((error = dns_p_push(Q, DNS_S_QD, qname, qlen, MAIN.qtype, DNS_C_IN, 0, 0)))
10566 panic("%s: %s", qname, dns_strerror(error));
10568 if (!(A = dns_hosts_query(hosts(), Q, &error)))
10569 panic("%s: %s", qname, dns_strerror(error));
10571 print_packet(A, stdout);
10576 } /* query_hosts() */
10579 static int search_list(int argc, char *argv[]) {
10580 const char *qname = (argc > 1)? argv[1] : "f.l.google.com";
10581 unsigned long i = 0;
10582 char name[DNS_D_MAXNAME + 1];
10584 printf("[%s]\n", qname);
10586 while (dns_resconf_search(name, sizeof name, qname, strlen(qname), resconf(), &i))
10590 } /* search_list() */
10593 static int permute_set(int argc, char *argv[]) {
10594 unsigned lo, hi, i;
10595 struct dns_k_permutor p;
10597 hi = (--argc > 0)? atoi(argv[argc]) : 8;
10598 lo = (--argc > 0)? atoi(argv[argc]) : 0;
10600 fprintf(stderr, "[%u .. %u]\n", lo, hi);
10602 dns_k_permutor_init(&p, lo, hi);
10604 for (i = lo; i <= hi; i++)
10605 fprintf(stdout, "%u\n", dns_k_permutor_step(&p));
10606 // printf("%u -> %u -> %u\n", i, dns_k_permutor_E(&p, i), dns_k_permutor_D(&p, dns_k_permutor_E(&p, i)));
10609 } /* permute_set() */
10612 static int shuffle_16(int argc, char *argv[]) {
10616 n = 0xffff & atoi(argv[argc]);
10617 r = (--argc > 0)? (unsigned)atoi(argv[argc]) : dns_random();
10619 fprintf(stdout, "%hu\n", dns_k_shuffle16(n, r));
10623 for (n = 0; n < 65536; n++)
10624 fprintf(stdout, "%hu\n", dns_k_shuffle16(n, r));
10628 } /* shuffle_16() */
10631 static int dump_random(int argc, char *argv[]) {
10632 unsigned char b[32];
10633 unsigned i, j, n, r;
10635 n = (argc > 1)? atoi(argv[1]) : 32;
10643 for (j = 0; j < sizeof r && i < n && i < sizeof b; i++, j++) {
10647 } while (i < n && i < sizeof b);
10649 hexdump(b, i, stdout);
10655 } /* dump_random() */
10658 static int send_query(int argc, char *argv[]) {
10659 struct dns_packet *A, *Q = dns_p_new(512);
10660 char host[INET6_ADDRSTRLEN + 1];
10661 struct sockaddr_storage ss;
10662 struct dns_socket *so;
10666 ss.ss_family = (strchr(argv[1], ':'))? AF_INET6 : AF_INET;
10668 if ((error = dns_pton(ss.ss_family, argv[1], dns_sa_addr(ss.ss_family, &ss, NULL))))
10669 panic("%s: %s", argv[1], dns_strerror(error));
10671 *dns_sa_port(ss.ss_family, &ss) = htons(53);
10673 memcpy(&ss, &resconf()->nameserver[0], dns_sa_len(&resconf()->nameserver[0]));
10675 if (!dns_inet_ntop(ss.ss_family, dns_sa_addr(ss.ss_family, &ss, NULL), host, sizeof host))
10676 panic("bad host address, or none provided");
10679 MAIN.qname = "ipv6.google.com";
10681 MAIN.qtype = DNS_T_AAAA;
10683 if ((error = dns_p_push(Q, DNS_S_QD, MAIN.qname, strlen(MAIN.qname), MAIN.qtype, DNS_C_IN, 0, 0)))
10684 panic("dns_p_push: %s", dns_strerror(error));
10686 dns_header(Q)->rd = 1;
10688 if (strstr(argv[0], "udp"))
10690 else if (strstr(argv[0], "tcp"))
10691 type = SOCK_STREAM;
10693 type = dns_res_tcp2type(resconf()->options.tcp);
10695 fprintf(stderr, "querying %s for %s IN %s\n", host, MAIN.qname, dns_strtype(MAIN.qtype));
10697 if (!(so = dns_so_open((struct sockaddr *)&resconf()->iface, type, dns_opts(), &error)))
10698 panic("dns_so_open: %s", dns_strerror(error));
10700 while (!(A = dns_so_query(so, Q, (struct sockaddr *)&ss, &error))) {
10701 if (error != DNS_EAGAIN)
10702 panic("dns_so_query: %s (%d)", dns_strerror(error), error);
10703 if (dns_so_elapsed(so) > 10)
10704 panic("query timed-out");
10706 dns_so_poll(so, 1);
10709 print_packet(A, stdout);
10714 } /* send_query() */
10717 static int print_arpa(int argc, char *argv[]) {
10718 const char *ip = (argc > 1)? argv[1] : "::1";
10719 int af = (strchr(ip, ':'))? AF_INET6 : AF_INET;
10720 union { struct in_addr a4; struct in6_addr a6; } addr;
10721 char host[DNS_D_MAXNAME + 1];
10723 if (1 != dns_inet_pton(af, ip, &addr) || 0 == dns_ptr_qname(host, sizeof host, af, &addr))
10724 panic("%s: invalid address", ip);
10726 fprintf(stdout, "%s\n", host);
10729 } /* print_arpa() */
10732 static int show_hints(int argc, char *argv[]) {
10733 struct dns_hints *(*load)(struct dns_resolv_conf *, int *);
10734 const char *which, *how, *who;
10735 struct dns_hints *hints;
10738 which = (argc > 1)? argv[1] : "local";
10739 how = (argc > 2)? argv[2] : "plain";
10740 who = (argc > 3)? argv[3] : "google.com";
10742 load = (0 == strcmp(which, "local"))
10746 if (!(hints = load(resconf(), &error)))
10747 panic("%s: %s", argv[0], dns_strerror(error));
10749 if (0 == strcmp(how, "plain")) {
10750 dns_hints_dump(hints, stdout);
10752 struct dns_packet *query, *answer;
10754 query = dns_p_new(512);
10756 if ((error = dns_p_push(query, DNS_S_QUESTION, who, strlen(who), DNS_T_A, DNS_C_IN, 0, 0)))
10757 panic("%s: %s", who, dns_strerror(error));
10759 if (!(answer = dns_hints_query(hints, query, &error)))
10760 panic("%s: %s", who, dns_strerror(error));
10762 print_packet(answer, stdout);
10767 dns_hints_close(hints);
10770 } /* show_hints() */
10773 static int resolve_query(int argc DNS_NOTUSED, char *argv[]) {
10774 _Bool recurse = !!strstr(argv[0], "recurse");
10775 struct dns_hints *(*hints)() = (recurse)? &dns_hints_root : &dns_hints_local;
10776 struct dns_resolver *R;
10777 struct dns_packet *ans;
10778 const struct dns_stat *st;
10782 MAIN.qname = "www.google.com";
10784 MAIN.qtype = DNS_T_A;
10786 resconf()->options.recurse = recurse;
10788 if (!(R = dns_res_open(resconf(), hosts(), dns_hints_mortal(hints(resconf(), &error)), cache(),
10789 dns_opts(.socks_host=&MAIN.socks_host,
10790 .socks_user=MAIN.socks_user,
10791 .socks_password=MAIN.socks_password), &error)))
10792 panic("%s: %s", MAIN.qname, dns_strerror(error));
10794 dns_res_settrace(R, trace("w+b"));
10796 if ((error = dns_res_submit(R, MAIN.qname, MAIN.qtype, DNS_C_IN)))
10797 panic("%s: %s", MAIN.qname, dns_strerror(error));
10799 while ((error = dns_res_check(R))) {
10800 if (error != DNS_EAGAIN)
10801 panic("dns_res_check: %s (%d)", dns_strerror(error), error);
10802 if (dns_res_elapsed(R) > 30)
10803 panic("query timed-out");
10805 dns_res_poll(R, 1);
10808 ans = dns_res_fetch(R, &error);
10809 print_packet(ans, stdout);
10812 st = dns_res_stat(R);
10814 printf(";; queries: %"PRIuZ"\n", st->queries);
10815 printf(";; udp sent: %"PRIuZ" in %"PRIuZ" bytes\n", st->udp.sent.count, st->udp.sent.bytes);
10816 printf(";; udp rcvd: %"PRIuZ" in %"PRIuZ" bytes\n", st->udp.rcvd.count, st->udp.rcvd.bytes);
10817 printf(";; tcp sent: %"PRIuZ" in %"PRIuZ" bytes\n", st->tcp.sent.count, st->tcp.sent.bytes);
10818 printf(";; tcp rcvd: %"PRIuZ" in %"PRIuZ" bytes\n", st->tcp.rcvd.count, st->tcp.rcvd.bytes);
10823 } /* resolve_query() */
10826 static int resolve_addrinfo(int argc DNS_NOTUSED, char *argv[]) {
10827 _Bool recurse = !!strstr(argv[0], "recurse");
10828 struct dns_hints *(*hints)() = (recurse)? &dns_hints_root : &dns_hints_local;
10829 struct dns_resolver *res = NULL;
10830 struct dns_addrinfo *ai = NULL;
10831 struct addrinfo ai_hints = { .ai_family = PF_UNSPEC, .ai_socktype = SOCK_STREAM, .ai_flags = AI_CANONNAME };
10832 struct addrinfo *ent;
10837 MAIN.qname = "www.google.com";
10838 /* NB: MAIN.qtype of 0 means obey hints.ai_family */
10840 resconf()->options.recurse = recurse;
10842 if (!(res = dns_res_open(resconf(), hosts(), dns_hints_mortal(hints(resconf(), &error)), cache(), dns_opts(), &error)))
10843 panic("%s: %s", MAIN.qname, dns_strerror(error));
10845 if (!(ai = dns_ai_open(MAIN.qname, "80", MAIN.qtype, &ai_hints, res, &error)))
10846 panic("%s: %s", MAIN.qname, dns_strerror(error));
10848 dns_ai_settrace(ai, trace("w+b"));
10851 switch (error = dns_ai_nextent(&ent, ai)) {
10853 dns_ai_print(pretty, sizeof pretty, ent, ai);
10855 fputs(pretty, stdout);
10863 if (dns_ai_elapsed(ai) > 30)
10864 panic("query timed-out");
10866 dns_ai_poll(ai, 1);
10870 panic("dns_ai_nextent: %s (%d)", dns_strerror(error), error);
10872 } while (error != ENOENT);
10874 dns_res_close(res);
10878 } /* resolve_addrinfo() */
10881 static int dump_trace(int argc DNS_NOTUSED, char *argv[]) {
10885 panic("no trace file specified");
10887 if ((error = dns_trace_dump(trace("r"), stdout)))
10888 panic("dump_trace: %s", dns_strerror(error));
10891 } /* dump_trace() */
10894 static int echo_port(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
10896 struct sockaddr sa;
10897 struct sockaddr_in sin;
10901 memset(&port, 0, sizeof port);
10902 port.sin.sin_family = AF_INET;
10903 port.sin.sin_port = htons(5354);
10904 port.sin.sin_addr.s_addr = inet_addr("127.0.0.1");
10906 if (-1 == (fd = socket(PF_INET, SOCK_DGRAM, 0)))
10907 panic("socket: %s", strerror(errno));
10909 if (0 != bind(fd, &port.sa, sizeof port.sa))
10910 panic("127.0.0.1:5353: %s", dns_strerror(errno));
10913 struct dns_packet *pkt = dns_p_new(512);
10914 struct sockaddr_storage ss;
10915 socklen_t slen = sizeof ss;
10917 #if defined(MSG_WAITALL) /* MinGW issue */
10918 int rflags = MSG_WAITALL;
10923 count = recvfrom(fd, (char *)pkt->data, pkt->size, rflags, (struct sockaddr *)&ss, &slen);
10925 if (!count || count < 0)
10926 panic("recvfrom: %s", strerror(errno));
10930 dns_p_dump(pkt, stdout);
10932 (void)sendto(fd, (char *)pkt->data, pkt->end, 0, (struct sockaddr *)&ss, slen);
10936 } /* echo_port() */
10939 static int isection(int argc, char *argv[]) {
10940 const char *name = (argc > 1)? argv[1] : "";
10943 type = dns_isection(name);
10944 name = dns_strsection(type);
10946 printf("%s (%d)\n", name, type);
10952 static int iclass(int argc, char *argv[]) {
10953 const char *name = (argc > 1)? argv[1] : "";
10956 type = dns_iclass(name);
10957 name = dns_strclass(type);
10959 printf("%s (%d)\n", name, type);
10965 static int itype(int argc, char *argv[]) {
10966 const char *name = (argc > 1)? argv[1] : "";
10969 type = dns_itype(name);
10970 name = dns_strtype(type);
10972 printf("%s (%d)\n", name, type);
10978 static int iopcode(int argc, char *argv[]) {
10979 const char *name = (argc > 1)? argv[1] : "";
10982 type = dns_iopcode(name);
10983 name = dns_stropcode(type);
10985 printf("%s (%d)\n", name, type);
10991 static int ircode(int argc, char *argv[]) {
10992 const char *name = (argc > 1)? argv[1] : "";
10995 type = dns_ircode(name);
10996 name = dns_strrcode(type);
10998 printf("%s (%d)\n", name, type);
11004 #define SIZE1(x) { DNS_PP_STRINGIFY(x), sizeof (x) }
11005 #define SIZE2(x, ...) SIZE1(x), SIZE1(__VA_ARGS__)
11006 #define SIZE3(x, ...) SIZE1(x), SIZE2(__VA_ARGS__)
11007 #define SIZE4(x, ...) SIZE1(x), SIZE3(__VA_ARGS__)
11008 #define SIZE(...) DNS_PP_CALL(DNS_PP_XPASTE(SIZE, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__)
11010 static int sizes(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
11011 static const struct { const char *name; size_t size; } type[] = {
11012 SIZE(struct dns_header, struct dns_packet, struct dns_rr, struct dns_rr_i),
11013 SIZE(struct dns_a, struct dns_aaaa, struct dns_mx, struct dns_ns),
11014 SIZE(struct dns_cname, struct dns_soa, struct dns_ptr, struct dns_srv),
11015 SIZE(struct dns_sshfp, struct dns_txt, union dns_any),
11016 SIZE(struct dns_resolv_conf, struct dns_hosts, struct dns_hints, struct dns_hints_i),
11017 SIZE(struct dns_options, struct dns_socket, struct dns_resolver, struct dns_addrinfo),
11018 SIZE(struct dns_cache), SIZE(size_t), SIZE(void *), SIZE(long)
11022 for (i = 0, max = 0; i < lengthof(type); i++)
11023 max = DNS_PP_MAX(max, strlen(type[i].name));
11025 for (i = 0; i < lengthof(type); i++)
11026 printf("%*s : %"PRIuZ"\n", max, type[i].name, type[i].size);
11032 static const struct { const char *cmd; int (*run)(); const char *help; } cmds[] = {
11033 { "parse-packet", &parse_packet, "parse binary packet from stdin" },
11034 { "parse-domain", &parse_domain, "anchor and iteratively cleave domain" },
11035 { "trim-domain", &trim_domain, "trim and anchor domain name" },
11036 { "expand-domain", &expand_domain, "expand domain at offset NN in packet from stdin" },
11037 { "show-resconf", &show_resconf, "show resolv.conf data" },
11038 { "show-hosts", &show_hosts, "show hosts data" },
11039 { "show-nssconf", &show_nssconf, "show nsswitch.conf data" },
11040 { "query-hosts", &query_hosts, "query A, AAAA or PTR in hosts data" },
11041 { "search-list", &search_list, "generate query search list from domain" },
11042 { "permute-set", &permute_set, "generate random permutation -> (0 .. N or N .. M)" },
11043 { "shuffle-16", &shuffle_16, "simple 16-bit permutation" },
11044 { "dump-random", &dump_random, "generate random bytes" },
11045 { "send-query", &send_query, "send query to host" },
11046 { "send-query-udp", &send_query, "send udp query to host" },
11047 { "send-query-tcp", &send_query, "send tcp query to host" },
11048 { "print-arpa", &print_arpa, "print arpa. zone name of address" },
11049 { "show-hints", &show_hints, "print hints: show-hints [local|root] [plain|packet]" },
11050 { "resolve-stub", &resolve_query, "resolve as stub resolver" },
11051 { "resolve-recurse", &resolve_query, "resolve as recursive resolver" },
11052 { "addrinfo-stub", &resolve_addrinfo, "resolve through getaddrinfo clone" },
11053 { "addrinfo-recurse", &resolve_addrinfo, "resolve through getaddrinfo clone" },
11054 /* { "resolve-nameinfo", &resolve_query, "resolve as recursive resolver" }, */
11055 { "dump-trace", &dump_trace, "dump the contents of a trace file" },
11056 { "echo", &echo_port, "server echo mode, for nmap fuzzing" },
11057 { "isection", &isection, "parse section string" },
11058 { "iclass", &iclass, "parse class string" },
11059 { "itype", &itype, "parse type string" },
11060 { "iopcode", &iopcode, "parse opcode string" },
11061 { "ircode", &ircode, "parse rcode string" },
11062 { "sizes", &sizes, "print data structure sizes" },
11066 static void print_usage(const char *progname, FILE *fp) {
11067 static const char *usage =
11068 " [OPTIONS] COMMAND [ARGS]\n"
11069 " -c PATH Path to resolv.conf\n"
11070 " -n PATH Path to nsswitch.conf\n"
11071 " -l PATH Path to local hosts\n"
11072 " -z PATH Path to zone cache\n"
11073 " -q QNAME Query name\n"
11074 " -t QTYPE Query type\n"
11075 " -s HOW Sort records\n"
11076 " -S ADDR Address of SOCKS server to use\n"
11077 " -P PORT Port of SOCKS server to use\n"
11078 " -A USER:PASSWORD Credentials for the SOCKS server\n"
11079 " -f PATH Path to trace file\n"
11080 " -v Be more verbose (-vv show packets; -vvv hexdump packets)\n"
11081 " -V Print version info\n"
11082 " -h Print this usage message\n"
11086 fputs(progname, fp);
11089 for (i = 0, m = 0; i < lengthof(cmds); i++) {
11090 if (strlen(cmds[i].cmd) > m)
11091 m = strlen(cmds[i].cmd);
11094 for (i = 0; i < lengthof(cmds); i++) {
11095 fprintf(fp, " %s ", cmds[i].cmd);
11097 for (n = strlen(cmds[i].cmd); n < m; n++)
11100 fputs(cmds[i].help, fp);
11104 fputs("\nReport bugs to William Ahern <william@25thandClement.com>\n", fp);
11105 } /* print_usage() */
11108 static void print_version(const char *progname, FILE *fp) {
11109 fprintf(fp, "%s (dns.c) %.8X\n", progname, dns_v_rel());
11110 fprintf(fp, "vendor %s\n", dns_vendor());
11111 fprintf(fp, "release %.8X\n", dns_v_rel());
11112 fprintf(fp, "abi %.8X\n", dns_v_abi());
11113 fprintf(fp, "api %.8X\n", dns_v_api());
11114 } /* print_version() */
11117 static void main_exit(void) {
11118 dns_trace_close(MAIN.memo.trace);
11119 MAIN.memo.trace = NULL;
11120 dns_hosts_close(MAIN.memo.hosts);
11121 MAIN.memo.hosts = NULL;
11122 dns_resconf_close(MAIN.memo.resconf);
11123 MAIN.memo.resconf = NULL;
11124 } /* main_exit() */
11126 int main(int argc, char **argv) {
11128 extern char *optarg;
11129 const char *progname = argv[0];
11133 atexit(&main_exit);
11135 while (-1 != (ch = getopt(argc, argv, "q:t:c:n:l:z:s:S:P:A:f:vVh"))) {
11138 assert(MAIN.resconf.count < lengthof(MAIN.resconf.path));
11140 MAIN.resconf.path[MAIN.resconf.count++] = optarg;
11144 assert(MAIN.nssconf.count < lengthof(MAIN.nssconf.path));
11146 MAIN.nssconf.path[MAIN.nssconf.count++] = optarg;
11150 assert(MAIN.hosts.count < lengthof(MAIN.hosts.path));
11152 MAIN.hosts.path[MAIN.hosts.count++] = optarg;
11156 assert(MAIN.cache.count < lengthof(MAIN.cache.path));
11158 MAIN.cache.path[MAIN.cache.count++] = optarg;
11162 MAIN.qname = optarg;
11166 for (i = 0; i < lengthof(dns_rrtypes); i++) {
11167 if (0 == strcasecmp(dns_rrtypes[i].name, optarg))
11168 { MAIN.qtype = dns_rrtypes[i].type; break; }
11174 for (i = 0; dns_isdigit(optarg[i]); i++) {
11176 MAIN.qtype += optarg[i] - '0';
11180 panic("%s: invalid query type", optarg);
11184 if (0 == strcasecmp(optarg, "packet"))
11185 MAIN.sort = &dns_rr_i_packet;
11186 else if (0 == strcasecmp(optarg, "shuffle"))
11187 MAIN.sort = &dns_rr_i_shuffle;
11188 else if (0 == strcasecmp(optarg, "order"))
11189 MAIN.sort = &dns_rr_i_order;
11191 panic("%s: invalid sort method", optarg);
11196 struct dns_resolv_conf *conf = resconf();
11197 conf->options.tcp = DNS_RESCONF_TCP_SOCKS;
11199 MAIN.socks_host.ss_family = (strchr(optarg, ':')) ? AF_INET6 : AF_INET;
11200 if ((error = dns_pton(MAIN.socks_host.ss_family, optarg,
11201 dns_sa_addr(MAIN.socks_host.ss_family,
11202 &MAIN.socks_host, NULL))))
11203 panic("%s: %s", optarg, dns_strerror(error));
11205 *dns_sa_port(MAIN.socks_host.ss_family, &MAIN.socks_host) = htons(1080);
11210 if (! MAIN.socks_host.ss_family)
11211 panic("-P without prior -S");
11212 *dns_sa_port(MAIN.socks_host.ss_family, &MAIN.socks_host) = htons(atoi(optarg));
11217 if (! MAIN.socks_host.ss_family)
11218 panic("-A without prior -S");
11219 if (! (password = strchr(optarg, ':')))
11220 panic("Usage: -A USER:PASSWORD");
11223 MAIN.socks_user = optarg;
11224 MAIN.socks_password = password;
11228 MAIN.trace = optarg;
11232 dns_debug = ++MAIN.verbose;
11236 print_version(progname, stdout);
11240 print_usage(progname, stdout);
11244 print_usage(progname, stderr);
11246 return EXIT_FAILURE;
11253 for (i = 0; i < lengthof(cmds) && argv[0]; i++) {
11254 if (0 == strcmp(cmds[i].cmd, argv[0]))
11255 return cmds[i].run(argc, argv);
11258 print_usage(progname, stderr);
11260 return EXIT_FAILURE;
11264 #endif /* DNS_MAIN */
11268 * pop file-scoped compiler annotations
11271 #pragma clang diagnostic pop
11272 #elif DNS_GNUC_PREREQ(4,6,0)
11273 #pragma GCC diagnostic pop