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