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