chiark / gitweb /
dirmngr: Fix aliasing problem in dns.c.
[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 (data)
4598                 if (fwrite(data, 1, datasize, fp) < datasize)
4599                         return errno;
4600         if (fflush(fp))
4601                 return errno;
4602
4603         return 0;
4604 }
4605
4606 static void dns_trace_setcname(struct dns_trace *trace, const char *host, const struct sockaddr *addr) {
4607         struct dns_trace_cname *cname;
4608         if (!trace || !trace->fp)
4609                 return;
4610
4611         cname = &trace->cnames.base[trace->cnames.p];
4612         dns_strlcpy(cname->host, host, sizeof cname->host);
4613         memcpy(&cname->addr, addr, DNS_PP_MIN(dns_sa_len(addr), sizeof cname->addr));
4614
4615         trace->cnames.p = (trace->cnames.p + 1) % lengthof(trace->cnames.base);
4616 }
4617
4618 static const char *dns_trace_cname(struct dns_trace *trace, const struct sockaddr *addr) {
4619         if (!trace || !trace->fp)
4620                 return NULL;
4621
4622         /* NB: start search from the write cursor to  */
4623         for (const struct dns_trace_cname *cname = trace->cnames.base; cname < endof(trace->cnames.base); cname++) {
4624                 if (0 == dns_sa_cmp((struct sockaddr *)addr, (struct sockaddr *)&cname->addr))
4625                         return cname->host;
4626         }
4627
4628         return NULL;
4629 }
4630
4631 static void dns_trace_res_submit(struct dns_trace *trace, const char *qname, enum dns_type qtype, enum dns_class qclass, int error) {
4632         struct dns_trace_event te;
4633         if (!trace || !trace->fp)
4634                 return;
4635
4636         dns_te_init(&te, DNS_TE_RES_SUBMIT);
4637         dns_strlcpy(te.res_submit.qname, qname, sizeof te.res_submit.qname);
4638         te.res_submit.qtype = qtype;
4639         te.res_submit.qclass = qclass;
4640         te.res_submit.error = error;
4641         dns_trace_tag_and_put(trace, &te, NULL, 0);
4642 }
4643
4644 static void dns_trace_res_fetch(struct dns_trace *trace, const struct dns_packet *packet, int error) {
4645         struct dns_trace_event te;
4646         const void *data;
4647         size_t datasize;
4648         if (!trace || !trace->fp)
4649                 return;
4650
4651         dns_te_init(&te, DNS_TE_RES_FETCH);
4652         data = (packet)? packet->data : NULL;
4653         datasize = (packet)? packet->end : 0;
4654         te.res_fetch.error = error;
4655         dns_trace_tag_and_put(trace, &te, data, datasize);
4656 }
4657
4658 static void dns_trace_so_submit(struct dns_trace *trace, const struct dns_packet *packet, const struct sockaddr *haddr, int error) {
4659         struct dns_trace_event te;
4660         const char *cname;
4661         if (!trace || !trace->fp)
4662                 return;
4663
4664         dns_te_init(&te, DNS_TE_SO_SUBMIT);
4665         memcpy(&te.so_submit.haddr, haddr, DNS_PP_MIN(dns_sa_len(haddr), sizeof te.so_submit.haddr));
4666         if ((cname = dns_trace_cname(trace, haddr)))
4667                 dns_strlcpy(te.so_submit.hname, cname, sizeof te.so_submit.hname);
4668         te.so_submit.error = error;
4669         dns_trace_tag_and_put(trace, &te, packet->data, packet->end);
4670 }
4671
4672 static void dns_trace_so_verify(struct dns_trace *trace, const struct dns_packet *packet, int error) {
4673         struct dns_trace_event te;
4674         if (!trace || !trace->fp)
4675                 return;
4676
4677         dns_te_init(&te, DNS_TE_SO_VERIFY);
4678         te.so_verify.error = error;
4679         dns_trace_tag_and_put(trace, &te, packet->data, packet->end);
4680 }
4681
4682 static void dns_trace_so_fetch(struct dns_trace *trace, const struct dns_packet *packet, int error) {
4683         struct dns_trace_event te;
4684         const void *data;
4685         size_t datasize;
4686         if (!trace || !trace->fp)
4687                 return;
4688
4689         dns_te_init(&te, DNS_TE_SO_FETCH);
4690         data = (packet)? packet->data : NULL;
4691         datasize = (packet)? packet->end : 0;
4692         te.so_fetch.error = error;
4693         dns_trace_tag_and_put(trace, &te, data, datasize);
4694 }
4695
4696 static void dns_trace_sys_connect(struct dns_trace *trace, int fd, int socktype, const struct sockaddr *dst, int error) {
4697         struct dns_trace_event te;
4698         if (!trace || !trace->fp)
4699                 return;
4700
4701         dns_te_init(&te, DNS_TE_SYS_CONNECT);
4702         dns_te_initname(&te.sys_connect.src, fd, &getsockname);
4703         memcpy(&te.sys_connect.dst, dst, DNS_PP_MIN(dns_sa_len(dst), sizeof te.sys_connect.dst));
4704         te.sys_connect.socktype = socktype;
4705         te.sys_connect.error = error;
4706         dns_trace_tag_and_put(trace, &te, NULL, 0);
4707 }
4708
4709 static void dns_trace_sys_send(struct dns_trace *trace, int fd, int socktype, const void *data, size_t datasize, int error) {
4710         struct dns_trace_event te;
4711         if (!trace || !trace->fp)
4712                 return;
4713
4714         dns_te_init(&te, DNS_TE_SYS_SEND);
4715         dns_te_initnames(&te.sys_send.src, &te.sys_send.dst, fd);
4716         te.sys_send.socktype = socktype;
4717         te.sys_send.error = error;
4718         dns_trace_tag_and_put(trace, &te, data, datasize);
4719 }
4720
4721 static void dns_trace_sys_recv(struct dns_trace *trace, int fd, int socktype, const void *data, size_t datasize, int error) {
4722         struct dns_trace_event te;
4723         if (!trace || !trace->fp)
4724                 return;
4725
4726         dns_te_init(&te, DNS_TE_SYS_RECV);
4727         dns_te_initnames(&te.sys_recv.dst, &te.sys_recv.src, fd);
4728         te.sys_recv.socktype = socktype;
4729         te.sys_recv.error = error;
4730         dns_trace_tag_and_put(trace, &te, data, datasize);
4731 }
4732
4733 static dns_error_t dns_trace_dump_packet(struct dns_trace *trace, const char *prefix, const unsigned char *data, size_t datasize, FILE *fp) {
4734         struct dns_packet *packet = NULL;
4735         char *line = NULL, *p;
4736         size_t size = 1, skip = 0;
4737         struct dns_rr_i records;
4738         struct dns_p_lines_i lines;
4739         size_t len, count;
4740         int error;
4741
4742         if (!(packet = dns_p_make(datasize, &error)))
4743                 goto error;
4744
4745         memcpy(packet->data, data, datasize);
4746         packet->end = datasize;
4747         (void)dns_p_study(packet);
4748 resize:
4749         if (!(p = dns_reallocarray(line, size, 2, &error)))
4750                 goto error;
4751         line = p;
4752         size *= 2;
4753
4754         memset(&records, 0, sizeof records);
4755         memset(&lines, 0, sizeof lines);
4756         count = 0;
4757
4758         while ((len = dns_p_lines(line, size, &error, packet, &records, &lines))) {
4759                 if (!(len < size)) {
4760                         skip = count;
4761                         goto resize;
4762                 } else if (skip <= count) {
4763                         fputs(prefix, fp);
4764                         fwrite(line, 1, len, fp);
4765                 }
4766                 count++;
4767         }
4768
4769         if (error)
4770                 goto error;
4771
4772         error = 0;
4773 error:
4774         free(line);
4775         dns_p_free(packet);
4776
4777         return error;
4778 }
4779
4780 static dns_error_t dns_trace_dump_data(struct dns_trace *trace, const char *prefix, const unsigned char *data, size_t datasize, FILE *fp) {
4781         struct dns_hxd_lines_i lines = { 0 };
4782         char line[128];
4783         size_t len;
4784
4785         while ((len = dns_hxd_lines(line, sizeof line, data, datasize, &lines))) {
4786                 if (len >= sizeof line)
4787                         return EOVERFLOW; /* shouldn't be possible */
4788                 fputs(prefix, fp);
4789                 fwrite(line, 1, len, fp);
4790         }
4791
4792         return 0;
4793 }
4794
4795 static dns_error_t dns_trace_dump_addr(struct dns_trace *trace, const char *prefix, const struct sockaddr_storage *ss, FILE *fp) {
4796         const void *addr;
4797         const char *path;
4798         socklen_t len;
4799         int error;
4800
4801         if ((addr = dns_sa_addr(ss->ss_family, (struct sockaddr *)ss, NULL))) {
4802                 char ip[INET6_ADDRSTRLEN + 1];
4803
4804                 if ((error = dns_ntop(ss->ss_family, addr, ip, sizeof ip)))
4805                         return error;
4806                 fprintf(fp, "%s%s\n", prefix, ip);
4807         } else if ((path = dns_sa_path((struct sockaddr *)ss, &len))) {
4808                 fprintf(fp, "%sunix:%.*s", prefix, (int)len, path);
4809         } else {
4810                 return EINVAL;
4811         }
4812
4813         return 0;
4814 }
4815
4816 static dns_error_t dns_trace_dump_meta(struct dns_trace *trace, const char *prefix, const struct dns_trace_event *te, dns_microseconds_t elapsed, FILE *fp) {
4817         char time_s[48], elapsed_s[48];
4818
4819         dns_utime_print(time_s, sizeof time_s, dns_ts2us(&te->ts, 0));
4820         dns_utime_print(elapsed_s, sizeof elapsed_s, elapsed);
4821
4822         fprintf(fp, "%sid: %"DNS_TRACE_ID_PRI"\n", prefix, te->id);
4823         fprintf(fp, "%sts: %s (%s)\n", prefix, time_s, elapsed_s);
4824         fprintf(fp, "%sabi: 0x%x (0x%x)\n", prefix, te->abi, DNS_TRACE_ABI);
4825         return 0;
4826 }
4827
4828 static dns_error_t dns_trace_dump_error(struct dns_trace *trace, const char *prefix, int error, FILE *fp) {
4829         fprintf(fp, "%s%d (%s)\n", prefix, error, (error)? dns_strerror(error) : "none");
4830         return 0;
4831 }
4832
4833 dns_error_t dns_trace_dump(struct dns_trace *trace, FILE *fp) {
4834         struct dns_trace_event *te = NULL;
4835         struct {
4836                 dns_trace_id_t id;
4837                 dns_microseconds_t begin, elapsed;
4838         } state = { 0 };
4839         int error;
4840
4841         if (!trace || !trace->fp)
4842                 return EINVAL;
4843
4844         if (0 != fseek(trace->fp, 0, SEEK_SET))
4845                 goto syerr;
4846
4847         while (dns_trace_fget(&te, trace->fp, &error)) {
4848                 size_t datasize = dns_te_datasize(te);
4849                 const unsigned char *data = (datasize)? te->data : NULL;
4850
4851                 if (state.id != te->id) {
4852                         state.id = te->id;
4853                         state.begin = dns_ts2us(&te->ts, 0);
4854                 }
4855                 dns_time_diff(&state.elapsed, dns_ts2us(&te->ts, 0), state.begin);
4856
4857                 switch(te->type) {
4858                 case DNS_TE_RES_SUBMIT:
4859                         fprintf(fp, "dns_res_submit:\n");
4860                         dns_trace_dump_meta(trace, "  ", te, state.elapsed, fp);
4861                         fprintf(fp, "  qname: %s\n", te->res_submit.qname);
4862                         fprintf(fp, "  qtype: %s\n", dns_strtype(te->res_submit.qtype));
4863                         fprintf(fp, "  qclass: %s\n", dns_strclass(te->res_submit.qclass));
4864                         dns_trace_dump_error(trace, "  error: ", te->res_submit.error, fp);
4865                         break;
4866                 case DNS_TE_RES_FETCH:
4867                         fprintf(fp, "dns_res_fetch:\n");
4868                         dns_trace_dump_meta(trace, "  ", te, state.elapsed, fp);
4869                         dns_trace_dump_error(trace, "  error: ", te->res_fetch.error, fp);
4870
4871                         if (data) {
4872                                 fprintf(fp, "  packet: |\n");
4873                                 if ((error = dns_trace_dump_packet(trace, "    ", data, datasize, fp)))
4874                                         goto error;
4875                                 fprintf(fp, "  data: |\n");
4876                                 if ((error = dns_trace_dump_data(trace, "    ", data, datasize, fp)))
4877                                         goto error;
4878                         }
4879
4880                         break;
4881                 case DNS_TE_SO_SUBMIT:
4882                         fprintf(fp, "dns_so_submit:\n");
4883                         dns_trace_dump_meta(trace, "  ", te, state.elapsed, fp);
4884                         fprintf(fp, "  hname: %s\n", te->so_submit.hname);
4885                         dns_trace_dump_addr(trace, "  haddr: ", &te->so_submit.haddr, fp);
4886                         dns_trace_dump_error(trace, "  error: ", te->so_submit.error, fp);
4887
4888                         if (data) {
4889                                 fprintf(fp, "  packet: |\n");
4890                                 if ((error = dns_trace_dump_packet(trace, "    ", data, datasize, fp)))
4891                                         goto error;
4892                                 fprintf(fp, "  data: |\n");
4893                                 if ((error = dns_trace_dump_data(trace, "    ", data, datasize, fp)))
4894                                         goto error;
4895                         }
4896
4897                         break;
4898                 case DNS_TE_SO_VERIFY:
4899                         fprintf(fp, "dns_so_verify:\n");
4900                         dns_trace_dump_meta(trace, "  ", te, state.elapsed, fp);
4901                         dns_trace_dump_error(trace, "  error: ", te->so_verify.error, fp);
4902
4903                         if (data) {
4904                                 fprintf(fp, "  packet: |\n");
4905                                 if ((error = dns_trace_dump_packet(trace, "    ", data, datasize, fp)))
4906                                         goto error;
4907                                 fprintf(fp, "  data: |\n");
4908                                 if ((error = dns_trace_dump_data(trace, "    ", data, datasize, fp)))
4909                                         goto error;
4910                         }
4911
4912                         break;
4913                 case DNS_TE_SO_FETCH:
4914                         fprintf(fp, "dns_so_fetch:\n");
4915                         dns_trace_dump_meta(trace, "  ", te, state.elapsed, fp);
4916                         dns_trace_dump_error(trace, "  error: ", te->so_fetch.error, fp);
4917
4918                         if (data) {
4919                                 fprintf(fp, "  packet: |\n");
4920                                 if ((error = dns_trace_dump_packet(trace, "    ", data, datasize, fp)))
4921                                         goto error;
4922                                 fprintf(fp, "  data: |\n");
4923                                 if ((error = dns_trace_dump_data(trace, "    ", data, datasize, fp)))
4924                                         goto error;
4925                         }
4926
4927                         break;
4928                 case DNS_TE_SYS_CONNECT: {
4929                         int socktype = te->sys_connect.socktype;
4930                         fprintf(fp, "dns_sys_connect:\n");
4931                         dns_trace_dump_meta(trace, "  ", te, state.elapsed, fp);
4932                         dns_trace_dump_addr(trace, "  src: ", &te->sys_connect.src, fp);
4933                         dns_trace_dump_addr(trace, "  dst: ", &te->sys_connect.dst, fp);
4934                         fprintf(fp, "  socktype: %d (%s)\n", socktype, ((socktype == SOCK_STREAM)? "SOCK_STREAM" : (socktype == SOCK_DGRAM)? "SOCK_DGRAM" : "?"));
4935                         dns_trace_dump_error(trace, "  error: ", te->sys_connect.error, fp);
4936
4937                         break;
4938                 }
4939                 case DNS_TE_SYS_SEND: {
4940                         int socktype = te->sys_send.socktype;
4941                         fprintf(fp, "dns_sys_send:\n");
4942                         dns_trace_dump_meta(trace, "  ", te, state.elapsed, fp);
4943                         dns_trace_dump_addr(trace, "  src: ", &te->sys_send.src, fp);
4944                         dns_trace_dump_addr(trace, "  dst: ", &te->sys_send.dst, fp);
4945                         fprintf(fp, "  socktype: %d (%s)\n", socktype, ((socktype == SOCK_STREAM)? "SOCK_STREAM" : (socktype == SOCK_DGRAM)? "SOCK_DGRAM" : "?"));
4946                         dns_trace_dump_error(trace, "  error: ", te->sys_send.error, fp);
4947
4948                         if (data) {
4949                                 fprintf(fp, "  data: |\n");
4950                                 if ((error = dns_trace_dump_data(trace, "    ", data, datasize, fp)))
4951                                         goto error;
4952                         }
4953
4954                         break;
4955                 }
4956                 case DNS_TE_SYS_RECV: {
4957                         int socktype = te->sys_recv.socktype;
4958                         fprintf(fp, "dns_sys_recv:\n");
4959                         dns_trace_dump_meta(trace, "  ", te, state.elapsed, fp);
4960                         dns_trace_dump_addr(trace, "  src: ", &te->sys_recv.src, fp);
4961                         dns_trace_dump_addr(trace, "  dst: ", &te->sys_recv.dst, fp);
4962                         fprintf(fp, "  socktype: %d (%s)\n", socktype, ((socktype == SOCK_STREAM)? "SOCK_STREAM" : (socktype == SOCK_DGRAM)? "SOCK_DGRAM" : "?"));
4963                         dns_trace_dump_error(trace, "  error: ", te->sys_recv.error, fp);
4964
4965                         if (data) {
4966                                 fprintf(fp, "  data: |\n");
4967                                 if ((error = dns_trace_dump_data(trace, "    ", data, datasize, fp)))
4968                                         goto error;
4969                         }
4970
4971                         break;
4972                 }
4973                 default:
4974                         fprintf(fp, "unknown(0x%.2x):\n", te->type);
4975                         dns_trace_dump_meta(trace, "  ", te, state.elapsed, fp);
4976
4977                         if (data) {
4978                                 fprintf(fp, "  data: |\n");
4979                                 if ((error = dns_trace_dump_data(trace, "    ", data, datasize, fp)))
4980                                         goto error;
4981                         }
4982
4983                         break;
4984                 }
4985         }
4986
4987         goto epilog;
4988 syerr:
4989         error = errno;
4990 error:
4991         (void)0;
4992 epilog:
4993         free(te);
4994
4995         return error;
4996 }
4997
4998 /*
4999  * H O S T S  R O U T I N E S
5000  *
5001  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5002
5003 struct dns_hosts {
5004         struct dns_hosts_entry {
5005                 char host[DNS_D_MAXNAME + 1];
5006                 char arpa[73 + 1];
5007
5008                 int af;
5009
5010                 union {
5011                         struct in_addr a4;
5012                         struct in6_addr a6;
5013                 } addr;
5014
5015                 _Bool alias;
5016
5017                 struct dns_hosts_entry *next;
5018         } *head, **tail;
5019
5020         dns_atomic_t refcount;
5021 }; /* struct dns_hosts */
5022
5023
5024 struct dns_hosts *dns_hosts_open(int *error) {
5025         static const struct dns_hosts hosts_initializer = { .refcount = 1 };
5026         struct dns_hosts *hosts;
5027
5028         if (!(hosts = malloc(sizeof *hosts)))
5029                 goto syerr;
5030
5031         *hosts  = hosts_initializer;
5032
5033         hosts->tail     = &hosts->head;
5034
5035         return hosts;
5036 syerr:
5037         *error  = dns_syerr();
5038
5039         free(hosts);
5040
5041         return 0;
5042 } /* dns_hosts_open() */
5043
5044
5045 void dns_hosts_close(struct dns_hosts *hosts) {
5046         struct dns_hosts_entry *ent, *xnt;
5047
5048         if (!hosts || 1 != dns_hosts_release(hosts))
5049                 return;
5050
5051         for (ent = hosts->head; ent; ent = xnt) {
5052                 xnt     = ent->next;
5053
5054                 free(ent);
5055         }
5056
5057         free(hosts);
5058
5059         return;
5060 } /* dns_hosts_close() */
5061
5062
5063 dns_refcount_t dns_hosts_acquire(struct dns_hosts *hosts) {
5064         return dns_atomic_fetch_add(&hosts->refcount);
5065 } /* dns_hosts_acquire() */
5066
5067
5068 dns_refcount_t dns_hosts_release(struct dns_hosts *hosts) {
5069         return dns_atomic_fetch_sub(&hosts->refcount);
5070 } /* dns_hosts_release() */
5071
5072
5073 struct dns_hosts *dns_hosts_mortal(struct dns_hosts *hosts) {
5074         if (hosts)
5075                 dns_hosts_release(hosts);
5076
5077         return hosts;
5078 } /* dns_hosts_mortal() */
5079
5080
5081 struct dns_hosts *dns_hosts_local(int *error_) {
5082         struct dns_hosts *hosts;
5083         int error;
5084
5085         if (!(hosts = dns_hosts_open(&error)))
5086                 goto error;
5087
5088         if ((error = dns_hosts_loadpath(hosts, "/etc/hosts")))
5089                 goto error;
5090
5091         return hosts;
5092 error:
5093         *error_ = error;
5094
5095         dns_hosts_close(hosts);
5096
5097         return 0;
5098 } /* dns_hosts_local() */
5099
5100
5101 #define dns_hosts_issep(ch)     (dns_isspace(ch))
5102 #define dns_hosts_iscom(ch)     ((ch) == '#' || (ch) == ';')
5103
5104 int dns_hosts_loadfile(struct dns_hosts *hosts, FILE *fp) {
5105         struct dns_hosts_entry ent;
5106         char word[DNS_PP_MAX(INET6_ADDRSTRLEN, DNS_D_MAXNAME) + 1];
5107         unsigned wp, wc, skip;
5108         int ch, error;
5109
5110         rewind(fp);
5111
5112         do {
5113                 memset(&ent, '\0', sizeof ent);
5114                 wc      = 0;
5115                 skip    = 0;
5116
5117                 do {
5118                         memset(word, '\0', sizeof word);
5119                         wp      = 0;
5120
5121                         while (EOF != (ch = fgetc(fp)) && ch != '\n') {
5122                                 skip    |= !!dns_hosts_iscom(ch);
5123
5124                                 if (skip)
5125                                         continue;
5126
5127                                 if (dns_hosts_issep(ch))
5128                                         break;
5129
5130                                 if (wp < sizeof word - 1)
5131                                         word[wp]        = ch;
5132                                 wp++;
5133                         }
5134
5135                         if (!wp)
5136                                 continue;
5137
5138                         wc++;
5139
5140                         switch (wc) {
5141                         case 0:
5142                                 break;
5143                         case 1:
5144                                 ent.af  = (strchr(word, ':'))? AF_INET6 : AF_INET;
5145                                 skip    = (1 != dns_inet_pton(ent.af, word, &ent.addr));
5146
5147                                 break;
5148                         default:
5149                                 if (!wp)
5150                                         break;
5151
5152                                 dns_d_anchor(ent.host, sizeof ent.host, word, wp);
5153
5154                                 if ((error = dns_hosts_insert(hosts, ent.af, &ent.addr, ent.host, (wc > 2))))
5155                                         return error;
5156
5157                                 break;
5158                         } /* switch() */
5159                 } while (ch != EOF && ch != '\n');
5160         } while (ch != EOF);
5161
5162         return 0;
5163 } /* dns_hosts_loadfile() */
5164
5165
5166 int dns_hosts_loadpath(struct dns_hosts *hosts, const char *path) {
5167         FILE *fp;
5168         int error;
5169
5170         if (!(fp = dns_fopen(path, "rt", &error)))
5171                 return error;
5172
5173         error = dns_hosts_loadfile(hosts, fp);
5174
5175         fclose(fp);
5176
5177         return error;
5178 } /* dns_hosts_loadpath() */
5179
5180
5181 int dns_hosts_dump(struct dns_hosts *hosts, FILE *fp) {
5182         struct dns_hosts_entry *ent, *xnt;
5183         char addr[INET6_ADDRSTRLEN + 1];
5184         unsigned i;
5185
5186         for (ent = hosts->head; ent; ent = xnt) {
5187                 xnt     = ent->next;
5188
5189                 dns_inet_ntop(ent->af, &ent->addr, addr, sizeof addr);
5190
5191                 fputs(addr, fp);
5192
5193                 for (i = strlen(addr); i < INET_ADDRSTRLEN; i++)
5194                         fputc(' ', fp);
5195
5196                 fputc(' ', fp);
5197
5198                 fputs(ent->host, fp);
5199                 fputc('\n', fp);
5200         }
5201
5202         return 0;
5203 } /* dns_hosts_dump() */
5204
5205
5206 int dns_hosts_insert(struct dns_hosts *hosts, int af, const void *addr, const void *host, _Bool alias) {
5207         struct dns_hosts_entry *ent;
5208         int error;
5209
5210         if (!(ent = malloc(sizeof *ent)))
5211                 goto syerr;
5212
5213         dns_d_anchor(ent->host, sizeof ent->host, host, strlen(host));
5214
5215         switch ((ent->af = af)) {
5216         case AF_INET6:
5217                 memcpy(&ent->addr.a6, addr, sizeof ent->addr.a6);
5218
5219                 dns_aaaa_arpa(ent->arpa, sizeof ent->arpa, addr);
5220
5221                 break;
5222         case AF_INET:
5223                 memcpy(&ent->addr.a4, addr, sizeof ent->addr.a4);
5224
5225                 dns_a_arpa(ent->arpa, sizeof ent->arpa, addr);
5226
5227                 break;
5228         default:
5229                 error   = EINVAL;
5230
5231                 goto error;
5232         } /* switch() */
5233
5234         ent->alias      = alias;
5235
5236         ent->next       = 0;
5237         *hosts->tail    = ent;
5238         hosts->tail     = &ent->next;
5239
5240         return 0;
5241 syerr:
5242         error   = dns_syerr();
5243 error:
5244         free(ent);
5245
5246         return error;
5247 } /* dns_hosts_insert() */
5248
5249
5250 struct dns_packet *dns_hosts_query(struct dns_hosts *hosts, struct dns_packet *Q, int *error_) {
5251         struct dns_packet *P    = dns_p_new(512);
5252         struct dns_packet *A    = 0;
5253         struct dns_rr rr;
5254         struct dns_hosts_entry *ent;
5255         int error, af;
5256         char qname[DNS_D_MAXNAME + 1];
5257         size_t qlen;
5258
5259         if ((error = dns_rr_parse(&rr, 12, Q)))
5260                 goto error;
5261
5262         if (!(qlen = dns_d_expand(qname, sizeof qname, rr.dn.p, Q, &error)))
5263                 goto error;
5264         else if (qlen >= sizeof qname)
5265                 goto toolong;
5266
5267         if ((error = dns_p_push(P, DNS_S_QD, qname, qlen, rr.type, rr.class, 0, 0)))
5268                 goto error;
5269
5270         switch (rr.type) {
5271         case DNS_T_PTR:
5272                 for (ent = hosts->head; ent; ent = ent->next) {
5273                         if (ent->alias || 0 != strcasecmp(qname, ent->arpa))
5274                                 continue;
5275
5276                         if ((error = dns_p_push(P, DNS_S_AN, qname, qlen, rr.type, rr.class, 0, ent->host)))
5277                                 goto error;
5278                 }
5279
5280                 break;
5281         case DNS_T_AAAA:
5282                 af      = AF_INET6;
5283
5284                 goto loop;
5285         case DNS_T_A:
5286                 af      = AF_INET;
5287
5288 loop:           for (ent = hosts->head; ent; ent = ent->next) {
5289                         if (ent->af != af || 0 != strcasecmp(qname, ent->host))
5290                                 continue;
5291
5292                         if ((error = dns_p_push(P, DNS_S_AN, qname, qlen, rr.type, rr.class, 0, &ent->addr)))
5293                                 goto error;
5294                 }
5295
5296                 break;
5297         default:
5298                 break;
5299         } /* switch() */
5300
5301
5302         if (!(A = dns_p_copy(dns_p_make(P->end, &error), P)))
5303                 goto error;
5304
5305         return A;
5306 toolong:
5307         error = DNS_EILLEGAL;
5308 error:
5309         *error_ = error;
5310
5311         dns_p_free(A);
5312
5313         return 0;
5314 } /* dns_hosts_query() */
5315
5316
5317 /*
5318  * R E S O L V . C O N F  R O U T I N E S
5319  *
5320  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5321
5322 struct dns_resolv_conf *dns_resconf_open(int *error) {
5323         static const struct dns_resolv_conf resconf_initializer = {
5324                 .lookup = "bf",
5325                 .family = { AF_INET, AF_INET6 },
5326                 .options = { .ndots = 1, .timeout = 5, .attempts = 2, .tcp = DNS_RESCONF_TCP_ENABLE, },
5327                 .iface = { .ss_family = AF_INET },
5328         };
5329         struct dns_resolv_conf *resconf;
5330         struct sockaddr_in *sin;
5331
5332         if (!(resconf = malloc(sizeof *resconf)))
5333                 goto syerr;
5334
5335         *resconf = resconf_initializer;
5336
5337         sin = (struct sockaddr_in *)&resconf->nameserver[0];
5338         sin->sin_family      = AF_INET;
5339         sin->sin_addr.s_addr = INADDR_ANY;
5340         sin->sin_port        = htons(53);
5341 #if defined(SA_LEN)
5342         sin->sin_len         = sizeof *sin;
5343 #endif
5344
5345         if (0 != gethostname(resconf->search[0], sizeof resconf->search[0]))
5346                 goto syerr;
5347
5348         dns_d_anchor(resconf->search[0], sizeof resconf->search[0], resconf->search[0], strlen(resconf->search[0]));
5349         dns_d_cleave(resconf->search[0], sizeof resconf->search[0], resconf->search[0], strlen(resconf->search[0]));
5350
5351         /*
5352          * XXX: If gethostname() returned a string without any label
5353          *      separator, then search[0][0] should be NUL.
5354          */
5355
5356         dns_resconf_acquire(resconf);
5357
5358         return resconf;
5359 syerr:
5360         *error  = dns_syerr();
5361
5362         free(resconf);
5363
5364         return 0;
5365 } /* dns_resconf_open() */
5366
5367
5368 void dns_resconf_close(struct dns_resolv_conf *resconf) {
5369         if (!resconf || 1 != dns_resconf_release(resconf))
5370                 return /* void */;
5371
5372         free(resconf);
5373 } /* dns_resconf_close() */
5374
5375
5376 dns_refcount_t dns_resconf_acquire(struct dns_resolv_conf *resconf) {
5377         return dns_atomic_fetch_add(&resconf->_.refcount);
5378 } /* dns_resconf_acquire() */
5379
5380
5381 dns_refcount_t dns_resconf_release(struct dns_resolv_conf *resconf) {
5382         return dns_atomic_fetch_sub(&resconf->_.refcount);
5383 } /* dns_resconf_release() */
5384
5385
5386 struct dns_resolv_conf *dns_resconf_mortal(struct dns_resolv_conf *resconf) {
5387         if (resconf)
5388                 dns_resconf_release(resconf);
5389
5390         return resconf;
5391 } /* dns_resconf_mortal() */
5392
5393
5394 struct dns_resolv_conf *dns_resconf_local(int *error_) {
5395         struct dns_resolv_conf *resconf;
5396         int error;
5397
5398         if (!(resconf = dns_resconf_open(&error)))
5399                 goto error;
5400
5401         if ((error = dns_resconf_loadpath(resconf, "/etc/resolv.conf"))) {
5402                 /*
5403                  * NOTE: Both the glibc and BIND9 resolvers ignore a missing
5404                  * /etc/resolv.conf, defaulting to a nameserver of
5405                  * 127.0.0.1. See also dns_hints_insert_resconf, and the
5406                  * default initialization of nameserver[0] in
5407                  * dns_resconf_open.
5408                  */
5409                 if (error != ENOENT)
5410                         goto error;
5411         }
5412
5413         if ((error = dns_nssconf_loadpath(resconf, "/etc/nsswitch.conf"))) {
5414                 if (error != ENOENT)
5415                         goto error;
5416         }
5417
5418         return resconf;
5419 error:
5420         *error_ = error;
5421
5422         dns_resconf_close(resconf);
5423
5424         return 0;
5425 } /* dns_resconf_local() */
5426
5427
5428 struct dns_resolv_conf *dns_resconf_root(int *error) {
5429         struct dns_resolv_conf *resconf;
5430
5431         if ((resconf = dns_resconf_local(error)))
5432                 resconf->options.recurse = 1;
5433
5434         return resconf;
5435 } /* dns_resconf_root() */
5436
5437
5438 static time_t dns_resconf_timeout(const struct dns_resolv_conf *resconf) {
5439         return (time_t)DNS_PP_MIN(INT_MAX, resconf->options.timeout);
5440 } /* dns_resconf_timeout() */
5441
5442
5443 enum dns_resconf_keyword {
5444         DNS_RESCONF_NAMESERVER,
5445         DNS_RESCONF_DOMAIN,
5446         DNS_RESCONF_SEARCH,
5447         DNS_RESCONF_LOOKUP,
5448         DNS_RESCONF_FILE,
5449         DNS_RESCONF_BIND,
5450         DNS_RESCONF_CACHE,
5451         DNS_RESCONF_FAMILY,
5452         DNS_RESCONF_INET4,
5453         DNS_RESCONF_INET6,
5454         DNS_RESCONF_OPTIONS,
5455         DNS_RESCONF_EDNS0,
5456         DNS_RESCONF_NDOTS,
5457         DNS_RESCONF_TIMEOUT,
5458         DNS_RESCONF_ATTEMPTS,
5459         DNS_RESCONF_ROTATE,
5460         DNS_RESCONF_RECURSE,
5461         DNS_RESCONF_SMART,
5462         DNS_RESCONF_TCP,
5463         DNS_RESCONF_TCPx,
5464         DNS_RESCONF_INTERFACE,
5465         DNS_RESCONF_ZERO,
5466         DNS_RESCONF_ONE,
5467         DNS_RESCONF_ENABLE,
5468         DNS_RESCONF_ONLY,
5469         DNS_RESCONF_DISABLE,
5470 }; /* enum dns_resconf_keyword */
5471
5472 static enum dns_resconf_keyword dns_resconf_keyword(const char *word) {
5473         static const char *words[]      = {
5474                 [DNS_RESCONF_NAMESERVER]        = "nameserver",
5475                 [DNS_RESCONF_DOMAIN]            = "domain",
5476                 [DNS_RESCONF_SEARCH]            = "search",
5477                 [DNS_RESCONF_LOOKUP]            = "lookup",
5478                 [DNS_RESCONF_FILE]              = "file",
5479                 [DNS_RESCONF_BIND]              = "bind",
5480                 [DNS_RESCONF_CACHE]             = "cache",
5481                 [DNS_RESCONF_FAMILY]            = "family",
5482                 [DNS_RESCONF_INET4]             = "inet4",
5483                 [DNS_RESCONF_INET6]             = "inet6",
5484                 [DNS_RESCONF_OPTIONS]           = "options",
5485                 [DNS_RESCONF_EDNS0]             = "edns0",
5486                 [DNS_RESCONF_ROTATE]            = "rotate",
5487                 [DNS_RESCONF_RECURSE]           = "recurse",
5488                 [DNS_RESCONF_SMART]             = "smart",
5489                 [DNS_RESCONF_TCP]               = "tcp",
5490                 [DNS_RESCONF_INTERFACE]         = "interface",
5491                 [DNS_RESCONF_ZERO]              = "0",
5492                 [DNS_RESCONF_ONE]               = "1",
5493                 [DNS_RESCONF_ENABLE]            = "enable",
5494                 [DNS_RESCONF_ONLY]              = "only",
5495                 [DNS_RESCONF_DISABLE]           = "disable",
5496         };
5497         unsigned i;
5498
5499         for (i = 0; i < lengthof(words); i++) {
5500                 if (words[i] && 0 == strcasecmp(words[i], word))
5501                         return i;
5502         }
5503
5504         if (0 == strncasecmp(word, "ndots:", sizeof "ndots:" - 1))
5505                 return DNS_RESCONF_NDOTS;
5506
5507         if (0 == strncasecmp(word, "timeout:", sizeof "timeout:" - 1))
5508                 return DNS_RESCONF_TIMEOUT;
5509
5510         if (0 == strncasecmp(word, "attempts:", sizeof "attempts:" - 1))
5511                 return DNS_RESCONF_ATTEMPTS;
5512
5513         if (0 == strncasecmp(word, "tcp:", sizeof "tcp:" - 1))
5514                 return DNS_RESCONF_TCPx;
5515
5516         return -1;
5517 } /* dns_resconf_keyword() */
5518
5519
5520 /** OpenBSD-style "[1.2.3.4]:53" nameserver syntax */
5521 int dns_resconf_pton(struct sockaddr_storage *ss, const char *src) {
5522         struct { char buf[128], *p; } addr = { "", addr.buf };
5523         unsigned short port = 0;
5524         int ch, af = AF_INET, error;
5525
5526         while ((ch = *src++)) {
5527                 switch (ch) {
5528                 case ' ':
5529                         /* FALL THROUGH */
5530                 case '\t':
5531                         break;
5532                 case '[':
5533                         break;
5534                 case ']':
5535                         while ((ch = *src++)) {
5536                                 if (dns_isdigit(ch)) {
5537                                         port *= 10;
5538                                         port += ch - '0';
5539                                 }
5540                         }
5541
5542                         goto inet;
5543                 case ':':
5544                         af = AF_INET6;
5545
5546                         /* FALL THROUGH */
5547                 default:
5548                         if (addr.p < endof(addr.buf) - 1)
5549                                 *addr.p++ = ch;
5550
5551                         break;
5552                 } /* switch() */
5553         } /* while() */
5554 inet:
5555
5556         if ((error = dns_pton(af, addr.buf, dns_sa_addr(af, ss, NULL))))
5557                 return error;
5558
5559         port = (!port)? 53 : port;
5560         *dns_sa_port(af, ss) = htons(port);
5561         dns_sa_family(ss) = af;
5562
5563         return 0;
5564 } /* dns_resconf_pton() */
5565
5566 #define dns_resconf_issep(ch)   (dns_isspace(ch) || (ch) == ',')
5567 #define dns_resconf_iscom(ch)   ((ch) == '#' || (ch) == ';')
5568
5569 int dns_resconf_loadfile(struct dns_resolv_conf *resconf, FILE *fp) {
5570         unsigned sa_count       = 0;
5571         char words[6][DNS_D_MAXNAME + 1];
5572         unsigned wp, wc, i, j, n;
5573         int ch, error;
5574
5575         rewind(fp);
5576
5577         do {
5578                 memset(words, '\0', sizeof words);
5579                 wp      = 0;
5580                 wc      = 0;
5581
5582                 while (EOF != (ch = getc(fp)) && ch != '\n') {
5583                         if (dns_resconf_issep(ch)) {
5584                                 if (wp > 0) {
5585                                         wp      = 0;
5586
5587                                         if (++wc >= lengthof(words))
5588                                                 goto skip;
5589                                 }
5590                         } else if (dns_resconf_iscom(ch)) {
5591 skip:
5592                                 do {
5593                                         ch      = getc(fp);
5594                                 } while (ch != EOF && ch != '\n');
5595
5596                                 break;
5597                         } else if (wp < sizeof words[wc] - 1) {
5598                                 words[wc][wp++] = ch;
5599                         } else {
5600                                 wp = 0; /* drop word */
5601                                 goto skip;
5602                         }
5603                 }
5604
5605                 if (wp > 0)
5606                         wc++;
5607
5608                 if (wc < 2)
5609                         continue;
5610
5611                 switch (dns_resconf_keyword(words[0])) {
5612                 case DNS_RESCONF_NAMESERVER:
5613                         if (sa_count >= lengthof(resconf->nameserver))
5614                                 continue;
5615
5616                         if ((error = dns_resconf_pton(&resconf->nameserver[sa_count], words[1])))
5617                                 continue;
5618
5619                         sa_count++;
5620
5621                         break;
5622                 case DNS_RESCONF_DOMAIN:
5623                 case DNS_RESCONF_SEARCH:
5624                         memset(resconf->search, '\0', sizeof resconf->search);
5625
5626                         for (i = 1, j = 0; i < wc && j < lengthof(resconf->search); i++, j++)
5627                                 dns_d_anchor(resconf->search[j], sizeof resconf->search[j], words[i], strlen(words[i]));
5628
5629                         break;
5630                 case DNS_RESCONF_LOOKUP:
5631                         for (i = 1, j = 0; i < wc && j < lengthof(resconf->lookup); i++) {
5632                                 switch (dns_resconf_keyword(words[i])) {
5633                                 case DNS_RESCONF_FILE:
5634                                         resconf->lookup[j++]    = 'f';
5635
5636                                         break;
5637                                 case DNS_RESCONF_BIND:
5638                                         resconf->lookup[j++]    = 'b';
5639
5640                                         break;
5641                                 case DNS_RESCONF_CACHE:
5642                                         resconf->lookup[j++]    = 'c';
5643
5644                                         break;
5645                                 default:
5646                                         break;
5647                                 } /* switch() */
5648                         } /* for() */
5649
5650                         break;
5651                 case DNS_RESCONF_FAMILY:
5652                         for (i = 1, j = 0; i < wc && j < lengthof(resconf->family); i++) {
5653                                 switch (dns_resconf_keyword(words[i])) {
5654                                 case DNS_RESCONF_INET4:
5655                                         resconf->family[j++]    = AF_INET;
5656
5657                                         break;
5658                                 case DNS_RESCONF_INET6:
5659                                         resconf->family[j++]    = AF_INET6;
5660
5661                                         break;
5662                                 default:
5663                                         break;
5664                                 }
5665                         }
5666
5667                         break;
5668                 case DNS_RESCONF_OPTIONS:
5669                         for (i = 1; i < wc; i++) {
5670                                 switch (dns_resconf_keyword(words[i])) {
5671                                 case DNS_RESCONF_EDNS0:
5672                                         resconf->options.edns0  = 1;
5673
5674                                         break;
5675                                 case DNS_RESCONF_NDOTS:
5676                                         for (j = sizeof "ndots:" - 1, n = 0; dns_isdigit(words[i][j]); j++) {
5677                                                 n       *= 10;
5678                                                 n       += words[i][j] - '0';
5679                                         } /* for() */
5680
5681                                         resconf->options.ndots  = n;
5682
5683                                         break;
5684                                 case DNS_RESCONF_TIMEOUT:
5685                                         for (j = sizeof "timeout:" - 1, n = 0; dns_isdigit(words[i][j]); j++) {
5686                                                 n       *= 10;
5687                                                 n       += words[i][j] - '0';
5688                                         } /* for() */
5689
5690                                         resconf->options.timeout        = n;
5691
5692                                         break;
5693                                 case DNS_RESCONF_ATTEMPTS:
5694                                         for (j = sizeof "attempts:" - 1, n = 0; dns_isdigit(words[i][j]); j++) {
5695                                                 n       *= 10;
5696                                                 n       += words[i][j] - '0';
5697                                         } /* for() */
5698
5699                                         resconf->options.attempts       = n;
5700
5701                                         break;
5702                                 case DNS_RESCONF_ROTATE:
5703                                         resconf->options.rotate         = 1;
5704
5705                                         break;
5706                                 case DNS_RESCONF_RECURSE:
5707                                         resconf->options.recurse        = 1;
5708
5709                                         break;
5710                                 case DNS_RESCONF_SMART:
5711                                         resconf->options.smart          = 1;
5712
5713                                         break;
5714                                 case DNS_RESCONF_TCP:
5715                                         resconf->options.tcp            = DNS_RESCONF_TCP_ONLY;
5716
5717                                         break;
5718                                 case DNS_RESCONF_TCPx:
5719                                         switch (dns_resconf_keyword(&words[i][sizeof "tcp:" - 1])) {
5720                                         case DNS_RESCONF_ENABLE:
5721                                                 resconf->options.tcp    = DNS_RESCONF_TCP_ENABLE;
5722
5723                                                 break;
5724                                         case DNS_RESCONF_ONE:
5725                                         case DNS_RESCONF_ONLY:
5726                                                 resconf->options.tcp    = DNS_RESCONF_TCP_ONLY;
5727
5728                                                 break;
5729                                         case DNS_RESCONF_ZERO:
5730                                         case DNS_RESCONF_DISABLE:
5731                                                 resconf->options.tcp    = DNS_RESCONF_TCP_DISABLE;
5732
5733                                                 break;
5734                                         default:
5735                                                 break;
5736                                         } /* switch() */
5737
5738                                         break;
5739                                 default:
5740                                         break;
5741                                 } /* switch() */
5742                         } /* for() */
5743
5744                         break;
5745                 case DNS_RESCONF_INTERFACE:
5746                         for (i = 0, n = 0; dns_isdigit(words[2][i]); i++) {
5747                                 n       *= 10;
5748                                 n       += words[2][i] - '0';
5749                         }
5750
5751                         dns_resconf_setiface(resconf, words[1], n);
5752
5753                         break;
5754                 default:
5755                         break;
5756                 } /* switch() */
5757         } while (ch != EOF);
5758
5759         return 0;
5760 } /* dns_resconf_loadfile() */
5761
5762
5763 int dns_resconf_loadpath(struct dns_resolv_conf *resconf, const char *path) {
5764         FILE *fp;
5765         int error;
5766
5767         if (!(fp = dns_fopen(path, "rt", &error)))
5768                 return error;
5769
5770         error = dns_resconf_loadfile(resconf, fp);
5771
5772         fclose(fp);
5773
5774         return error;
5775 } /* dns_resconf_loadpath() */
5776
5777
5778 struct dns_anyconf {
5779         char *token[16];
5780         unsigned count;
5781         char buffer[1024], *tp, *cp;
5782 }; /* struct dns_anyconf */
5783
5784
5785 static void dns_anyconf_reset(struct dns_anyconf *cf) {
5786         cf->count = 0;
5787         cf->tp = cf->cp = cf->buffer;
5788 } /* dns_anyconf_reset() */
5789
5790
5791 static int dns_anyconf_push(struct dns_anyconf *cf) {
5792         if (!(cf->cp < endof(cf->buffer) && cf->count < lengthof(cf->token)))
5793                 return ENOMEM;
5794
5795         *cf->cp++ = '\0';
5796         cf->token[cf->count++] = cf->tp;
5797         cf->tp = cf->cp;
5798
5799         return 0;
5800 } /* dns_anyconf_push() */
5801
5802
5803 static void dns_anyconf_pop(struct dns_anyconf *cf) {
5804         if (cf->count > 0) {
5805                 --cf->count;
5806                 cf->tp = cf->cp = cf->token[cf->count];
5807                 cf->token[cf->count] = 0;
5808         }
5809 } /* dns_anyconf_pop() */
5810
5811
5812 static int dns_anyconf_addc(struct dns_anyconf *cf, int ch) {
5813         if (!(cf->cp < endof(cf->buffer)))
5814                 return ENOMEM;
5815
5816         *cf->cp++ = ch;
5817
5818         return 0;
5819 } /* dns_anyconf_addc() */
5820
5821
5822 static _Bool dns_anyconf_match(const char *pat, int mc) {
5823         _Bool match;
5824         int pc;
5825
5826         if (*pat == '^') {
5827                 match = 0;
5828                 ++pat;
5829         } else {
5830                 match = 1;
5831         }
5832
5833         while ((pc = *(const unsigned char *)pat++)) {
5834                 switch (pc) {
5835                 case '%':
5836                         if (!(pc = *(const unsigned char *)pat++))
5837                                 return !match;
5838
5839                         switch (pc) {
5840                         case 'a':
5841                                 if (dns_isalpha(mc))
5842                                         return match;
5843                                 break;
5844                         case 'd':
5845                                 if (dns_isdigit(mc))
5846                                         return match;
5847                                 break;
5848                         case 'w':
5849                                 if (dns_isalnum(mc))
5850                                         return match;
5851                                 break;
5852                         case 's':
5853                                 if (dns_isspace(mc))
5854                                         return match;
5855                                 break;
5856                         default:
5857                                 if (mc == pc)
5858                                         return match;
5859                                 break;
5860                         } /* switch() */
5861
5862                         break;
5863                 default:
5864                         if (mc == pc)
5865                                 return match;
5866                         break;
5867                 } /* switch() */
5868         } /* while() */
5869
5870         return !match;
5871 } /* dns_anyconf_match() */
5872
5873
5874 static int dns_anyconf_peek(FILE *fp) {
5875         int ch;
5876         ch = getc(fp);
5877         ungetc(ch, fp);
5878         return ch;
5879 } /* dns_anyconf_peek() */
5880
5881
5882 static size_t dns_anyconf_skip(const char *pat, FILE *fp) {
5883         size_t count = 0;
5884         int ch;
5885
5886         while (EOF != (ch = getc(fp))) {
5887                 if (dns_anyconf_match(pat, ch)) {
5888                         count++;
5889                         continue;
5890                 }
5891
5892                 ungetc(ch, fp);
5893
5894                 break;
5895         }
5896
5897         return count;
5898 } /* dns_anyconf_skip() */
5899
5900
5901 static size_t dns_anyconf_scan(struct dns_anyconf *cf, const char *pat, FILE *fp, int *error) {
5902         size_t len;
5903         int ch;
5904
5905         while (EOF != (ch = getc(fp))) {
5906                 if (dns_anyconf_match(pat, ch)) {
5907                         if ((*error = dns_anyconf_addc(cf, ch)))
5908                                 return 0;
5909
5910                         continue;
5911                 } else {
5912                         ungetc(ch, fp);
5913
5914                         break;
5915                 }
5916         }
5917
5918         if ((len = cf->cp - cf->tp)) {
5919                 if ((*error = dns_anyconf_push(cf)))
5920                         return 0;
5921
5922                 return len;
5923         } else {
5924                 *error = 0;
5925
5926                 return 0;
5927         }
5928 } /* dns_anyconf_scan() */
5929
5930
5931 DNS_NOTUSED static void dns_anyconf_dump(struct dns_anyconf *cf, FILE *fp) {
5932         unsigned i;
5933
5934         fprintf(fp, "tokens:");
5935
5936         for (i = 0; i < cf->count; i++) {
5937                 fprintf(fp, " %s", cf->token[i]);
5938         }
5939
5940         fputc('\n', fp);
5941 } /* dns_anyconf_dump() */
5942
5943
5944 enum dns_nssconf_keyword {
5945         DNS_NSSCONF_INVALID = 0,
5946         DNS_NSSCONF_HOSTS   = 1,
5947         DNS_NSSCONF_SUCCESS,
5948         DNS_NSSCONF_NOTFOUND,
5949         DNS_NSSCONF_UNAVAIL,
5950         DNS_NSSCONF_TRYAGAIN,
5951         DNS_NSSCONF_CONTINUE,
5952         DNS_NSSCONF_RETURN,
5953         DNS_NSSCONF_FILES,
5954         DNS_NSSCONF_DNS,
5955         DNS_NSSCONF_MDNS,
5956
5957         DNS_NSSCONF_LAST,
5958 }; /* enum dns_nssconf_keyword */
5959
5960 static enum dns_nssconf_keyword dns_nssconf_keyword(const char *word) {
5961         static const char *list[] = {
5962                 [DNS_NSSCONF_HOSTS]    = "hosts",
5963                 [DNS_NSSCONF_SUCCESS]  = "success",
5964                 [DNS_NSSCONF_NOTFOUND] = "notfound",
5965                 [DNS_NSSCONF_UNAVAIL]  = "unavail",
5966                 [DNS_NSSCONF_TRYAGAIN] = "tryagain",
5967                 [DNS_NSSCONF_CONTINUE] = "continue",
5968                 [DNS_NSSCONF_RETURN]   = "return",
5969                 [DNS_NSSCONF_FILES]    = "files",
5970                 [DNS_NSSCONF_DNS]      = "dns",
5971                 [DNS_NSSCONF_MDNS]     = "mdns",
5972         };
5973         unsigned i;
5974
5975         for (i = 1; i < lengthof(list); i++) {
5976                 if (list[i] && 0 == strcasecmp(list[i], word))
5977                         return i;
5978         }
5979
5980         return DNS_NSSCONF_INVALID;
5981 } /* dns_nssconf_keyword() */
5982
5983
5984 static enum dns_nssconf_keyword dns_nssconf_c2k(int ch) {
5985         static const char map[] = {
5986                 ['S'] = DNS_NSSCONF_SUCCESS,
5987                 ['N'] = DNS_NSSCONF_NOTFOUND,
5988                 ['U'] = DNS_NSSCONF_UNAVAIL,
5989                 ['T'] = DNS_NSSCONF_TRYAGAIN,
5990                 ['C'] = DNS_NSSCONF_CONTINUE,
5991                 ['R'] = DNS_NSSCONF_RETURN,
5992                 ['f'] = DNS_NSSCONF_FILES,
5993                 ['F'] = DNS_NSSCONF_FILES,
5994                 ['d'] = DNS_NSSCONF_DNS,
5995                 ['D'] = DNS_NSSCONF_DNS,
5996                 ['b'] = DNS_NSSCONF_DNS,
5997                 ['B'] = DNS_NSSCONF_DNS,
5998                 ['m'] = DNS_NSSCONF_MDNS,
5999                 ['M'] = DNS_NSSCONF_MDNS,
6000         };
6001
6002         return (ch >= 0 && ch < (int)lengthof(map))? map[ch] : DNS_NSSCONF_INVALID;
6003 } /* dns_nssconf_c2k() */
6004
6005
6006 DNS_PRAGMA_PUSH
6007 DNS_PRAGMA_QUIET
6008
6009 static int dns_nssconf_k2c(int k) {
6010         static const char map[DNS_NSSCONF_LAST] = {
6011                 [DNS_NSSCONF_SUCCESS]  = 'S',
6012                 [DNS_NSSCONF_NOTFOUND] = 'N',
6013                 [DNS_NSSCONF_UNAVAIL]  = 'U',
6014                 [DNS_NSSCONF_TRYAGAIN] = 'T',
6015                 [DNS_NSSCONF_CONTINUE] = 'C',
6016                 [DNS_NSSCONF_RETURN]   = 'R',
6017                 [DNS_NSSCONF_FILES]    = 'f',
6018                 [DNS_NSSCONF_DNS]      = 'b',
6019                 [DNS_NSSCONF_MDNS]     = 'm',
6020         };
6021
6022         return (k >= 0 && k < (int)lengthof(map))? (map[k]? map[k] : '?') : '?';
6023 } /* dns_nssconf_k2c() */
6024
6025 static const char *dns_nssconf_k2s(int k) {
6026         static const char *const map[DNS_NSSCONF_LAST] = {
6027                 [DNS_NSSCONF_SUCCESS]  = "SUCCESS",
6028                 [DNS_NSSCONF_NOTFOUND] = "NOTFOUND",
6029                 [DNS_NSSCONF_UNAVAIL]  = "UNAVAIL",
6030                 [DNS_NSSCONF_TRYAGAIN] = "TRYAGAIN",
6031                 [DNS_NSSCONF_CONTINUE] = "continue",
6032                 [DNS_NSSCONF_RETURN]   = "return",
6033                 [DNS_NSSCONF_FILES]    = "files",
6034                 [DNS_NSSCONF_DNS]      = "dns",
6035                 [DNS_NSSCONF_MDNS]     = "mdns",
6036         };
6037
6038         return (k >= 0 && k < (int)lengthof(map))? (map[k]? map[k] : "") : "";
6039 } /* dns_nssconf_k2s() */
6040
6041 DNS_PRAGMA_POP
6042
6043
6044 int dns_nssconf_loadfile(struct dns_resolv_conf *resconf, FILE *fp) {
6045         enum dns_nssconf_keyword source, status, action;
6046         char lookup[sizeof resconf->lookup] = "", *lp;
6047         struct dns_anyconf cf;
6048         size_t i;
6049         int error;
6050
6051         while (!feof(fp) && !ferror(fp)) {
6052                 dns_anyconf_reset(&cf);
6053
6054                 dns_anyconf_skip("%s", fp);
6055
6056                 if (!dns_anyconf_scan(&cf, "%w_", fp, &error))
6057                         goto nextent;
6058
6059                 if (DNS_NSSCONF_HOSTS != dns_nssconf_keyword(cf.token[0]))
6060                         goto nextent;
6061
6062                 dns_anyconf_pop(&cf);
6063
6064                 if (!dns_anyconf_skip(": \t", fp))
6065                         goto nextent;
6066
6067                 *(lp = lookup) = '\0';
6068
6069                 while (dns_anyconf_scan(&cf, "%w_", fp, &error)) {
6070                         dns_anyconf_skip(" \t", fp);
6071
6072                         if ('[' == dns_anyconf_peek(fp)) {
6073                                 dns_anyconf_skip("[ \t", fp);
6074
6075                                 for (;;) {
6076                                         if ('!' == dns_anyconf_peek(fp)) {
6077                                                 dns_anyconf_skip("! \t", fp);
6078                                                 /* FIXME: negating statuses; currently not implemented */
6079                                                 dns_anyconf_skip("^#;]\n", fp); /* skip to end of criteria */
6080                                                 break;
6081                                         }
6082
6083                                         if (!dns_anyconf_scan(&cf, "%w_", fp, &error)) break;
6084                                         dns_anyconf_skip("= \t", fp);
6085                                         if (!dns_anyconf_scan(&cf, "%w_", fp, &error)) {
6086                                                 dns_anyconf_pop(&cf); /* discard status */
6087                                                 dns_anyconf_skip("^#;]\n", fp); /* skip to end of criteria */
6088                                                 break;
6089                                         }
6090                                         dns_anyconf_skip(" \t", fp);
6091                                 }
6092
6093                                 dns_anyconf_skip("] \t", fp);
6094                         }
6095
6096                         if ((size_t)(endof(lookup) - lp) < cf.count + 1) /* +1 for '\0' */
6097                                 goto nextsrc;
6098
6099                         source = dns_nssconf_keyword(cf.token[0]);
6100
6101                         switch (source) {
6102                         case DNS_NSSCONF_DNS:
6103                         case DNS_NSSCONF_MDNS:
6104                         case DNS_NSSCONF_FILES:
6105                                 *lp++ = dns_nssconf_k2c(source);
6106                                 break;
6107                         default:
6108                                 goto nextsrc;
6109                         }
6110
6111                         for (i = 1; i + 1 < cf.count; i += 2) {
6112                                 status = dns_nssconf_keyword(cf.token[i]);
6113                                 action = dns_nssconf_keyword(cf.token[i + 1]);
6114
6115                                 switch (status) {
6116                                 case DNS_NSSCONF_SUCCESS:
6117                                 case DNS_NSSCONF_NOTFOUND:
6118                                 case DNS_NSSCONF_UNAVAIL:
6119                                 case DNS_NSSCONF_TRYAGAIN:
6120                                         *lp++ = dns_nssconf_k2c(status);
6121                                         break;
6122                                 default:
6123                                         continue;
6124                                 }
6125
6126                                 switch (action) {
6127                                 case DNS_NSSCONF_CONTINUE:
6128                                 case DNS_NSSCONF_RETURN:
6129                                         break;
6130                                 default:
6131                                         action = (status == DNS_NSSCONF_SUCCESS)
6132                                                ? DNS_NSSCONF_RETURN
6133                                                : DNS_NSSCONF_CONTINUE;
6134                                         break;
6135                                 }
6136
6137                                 *lp++ = dns_nssconf_k2c(action);
6138                         }
6139 nextsrc:
6140                         *lp = '\0';
6141                         dns_anyconf_reset(&cf);
6142                 }
6143 nextent:
6144                 dns_anyconf_skip("^\n", fp);
6145         }
6146
6147         if (*lookup)
6148                 strncpy(resconf->lookup, lookup, sizeof resconf->lookup);
6149
6150         return 0;
6151 } /* dns_nssconf_loadfile() */
6152
6153
6154 int dns_nssconf_loadpath(struct dns_resolv_conf *resconf, const char *path) {
6155         FILE *fp;
6156         int error;
6157
6158         if (!(fp = dns_fopen(path, "rt", &error)))
6159                 return error;
6160
6161         error = dns_nssconf_loadfile(resconf, fp);
6162
6163         fclose(fp);
6164
6165         return error;
6166 } /* dns_nssconf_loadpath() */
6167
6168
6169 struct dns_nssconf_source {
6170         enum dns_nssconf_keyword source, success, notfound, unavail, tryagain;
6171 }; /* struct dns_nssconf_source */
6172
6173 typedef unsigned dns_nssconf_i;
6174
6175 static inline int dns_nssconf_peek(const struct dns_resolv_conf *resconf, dns_nssconf_i state) {
6176         return (state < lengthof(resconf->lookup) && resconf->lookup[state])? resconf->lookup[state] : 0;
6177 } /* dns_nssconf_peek() */
6178
6179 static _Bool dns_nssconf_next(struct dns_nssconf_source *src, const struct dns_resolv_conf *resconf, dns_nssconf_i *state) {
6180         int source, status, action;
6181
6182         src->source = DNS_NSSCONF_INVALID;
6183         src->success = DNS_NSSCONF_RETURN;
6184         src->notfound = DNS_NSSCONF_CONTINUE;
6185         src->unavail = DNS_NSSCONF_CONTINUE;
6186         src->tryagain = DNS_NSSCONF_CONTINUE;
6187
6188         while ((source = dns_nssconf_peek(resconf, *state))) {
6189                 source = dns_nssconf_c2k(source);
6190                 ++*state;
6191
6192                 switch (source) {
6193                 case DNS_NSSCONF_FILES:
6194                 case DNS_NSSCONF_DNS:
6195                 case DNS_NSSCONF_MDNS:
6196                         src->source = source;
6197                         break;
6198                 default:
6199                         continue;
6200                 }
6201
6202                 while ((status = dns_nssconf_peek(resconf, *state)) && (action = dns_nssconf_peek(resconf, *state + 1))) {
6203                         status = dns_nssconf_c2k(status);
6204                         action = dns_nssconf_c2k(action);
6205
6206                         switch (action) {
6207                         case DNS_NSSCONF_RETURN:
6208                         case DNS_NSSCONF_CONTINUE:
6209                                 break;
6210                         default:
6211                                 goto done;
6212                         }
6213
6214                         switch (status) {
6215                         case DNS_NSSCONF_SUCCESS:
6216                                 src->success = action;
6217                                 break;
6218                         case DNS_NSSCONF_NOTFOUND:
6219                                 src->notfound = action;
6220                                 break;
6221                         case DNS_NSSCONF_UNAVAIL:
6222                                 src->unavail = action;
6223                                 break;
6224                         case DNS_NSSCONF_TRYAGAIN:
6225                                 src->tryagain = action;
6226                                 break;
6227                         default:
6228                                 goto done;
6229                         }
6230
6231                         *state += 2;
6232                 }
6233
6234                 break;
6235         }
6236 done:
6237         return src->source != DNS_NSSCONF_INVALID;
6238 } /* dns_nssconf_next() */
6239
6240
6241 static int dns_nssconf_dump_status(int status, int action, unsigned *count, FILE *fp) {
6242         switch (status) {
6243         case DNS_NSSCONF_SUCCESS:
6244                 if (action == DNS_NSSCONF_RETURN)
6245                         return 0;
6246                 break;
6247         default:
6248                 if (action == DNS_NSSCONF_CONTINUE)
6249                         return 0;
6250                 break;
6251         }
6252
6253         fputc(' ', fp);
6254
6255         if (!*count)
6256                 fputc('[', fp);
6257
6258         fprintf(fp, "%s=%s", dns_nssconf_k2s(status), dns_nssconf_k2s(action));
6259
6260         ++*count;
6261
6262         return 0;
6263 } /* dns_nssconf_dump_status() */
6264
6265
6266 int dns_nssconf_dump(struct dns_resolv_conf *resconf, FILE *fp) {
6267         struct dns_nssconf_source src;
6268         dns_nssconf_i i = 0;
6269
6270         fputs("hosts:", fp);
6271
6272         while (dns_nssconf_next(&src, resconf, &i)) {
6273                 unsigned n = 0;
6274
6275                 fprintf(fp, " %s", dns_nssconf_k2s(src.source));
6276
6277                 dns_nssconf_dump_status(DNS_NSSCONF_SUCCESS, src.success, &n, fp);
6278                 dns_nssconf_dump_status(DNS_NSSCONF_NOTFOUND, src.notfound, &n, fp);
6279                 dns_nssconf_dump_status(DNS_NSSCONF_UNAVAIL, src.unavail, &n, fp);
6280                 dns_nssconf_dump_status(DNS_NSSCONF_TRYAGAIN, src.tryagain, &n, fp);
6281
6282                 if (n)
6283                         fputc(']', fp);
6284         }
6285
6286         fputc('\n', fp);
6287
6288         return 0;
6289 } /* dns_nssconf_dump() */
6290
6291
6292 int dns_resconf_setiface(struct dns_resolv_conf *resconf, const char *addr, unsigned short port) {
6293         int af = (strchr(addr, ':'))? AF_INET6 : AF_INET;
6294         int error;
6295
6296         if ((error = dns_pton(af, addr, dns_sa_addr(af, &resconf->iface, NULL))))
6297                 return error;
6298
6299         *dns_sa_port(af, &resconf->iface)       = htons(port);
6300         resconf->iface.ss_family                = af;
6301
6302         return 0;
6303 } /* dns_resconf_setiface() */
6304
6305
6306 #define DNS_SM_RESTORE \
6307         do { \
6308                 pc = 0xff & (*state >> 0); \
6309                 srchi = 0xff & (*state >> 8); \
6310                 ndots = 0xff & (*state >> 16); \
6311         } while (0)
6312
6313 #define DNS_SM_SAVE \
6314         do { \
6315                 *state = ((0xff & pc) << 0) \
6316                        | ((0xff & srchi) << 8) \
6317                        | ((0xff & ndots) << 16); \
6318         } while (0)
6319
6320 size_t dns_resconf_search(void *dst, size_t lim, const void *qname, size_t qlen, struct dns_resolv_conf *resconf, dns_resconf_i_t *state) {
6321         unsigned pc, srchi, ndots, len;
6322
6323         DNS_SM_ENTER;
6324
6325         /* if FQDN then return as-is and finish */
6326         if (dns_d_isanchored(qname, qlen)) {
6327                 len = dns_d_anchor(dst, lim, qname, qlen);
6328                 DNS_SM_YIELD(len);
6329                 DNS_SM_EXIT;
6330         }
6331
6332         ndots = dns_d_ndots(qname, qlen);
6333
6334         if (ndots >= resconf->options.ndots) {
6335                 len = dns_d_anchor(dst, lim, qname, qlen);
6336                 DNS_SM_YIELD(len);
6337         }
6338
6339         while (srchi < lengthof(resconf->search) && resconf->search[srchi][0]) {
6340                 struct dns_buf buf = DNS_B_INTO(dst, lim);
6341                 const char *dn = resconf->search[srchi++];
6342
6343                 dns_b_put(&buf, qname, qlen);
6344                 dns_b_putc(&buf, '.');
6345                 dns_b_puts(&buf, dn);
6346                 if (!dns_d_isanchored(dn, strlen(dn)))
6347                         dns_b_putc(&buf, '.');
6348                 len = dns_b_strllen(&buf);
6349                 DNS_SM_YIELD(len);
6350         }
6351
6352         if (ndots < resconf->options.ndots) {
6353                 len = dns_d_anchor(dst, lim, qname, qlen);
6354                 DNS_SM_YIELD(len);
6355         }
6356
6357         DNS_SM_LEAVE;
6358
6359         return dns_strlcpy(dst, "", lim);
6360 } /* dns_resconf_search() */
6361
6362 #undef DNS_SM_SAVE
6363 #undef DNS_SM_RESTORE
6364
6365
6366 int dns_resconf_dump(struct dns_resolv_conf *resconf, FILE *fp) {
6367         unsigned i;
6368         int af;
6369
6370         for (i = 0; i < lengthof(resconf->nameserver) && (af = resconf->nameserver[i].ss_family) != AF_UNSPEC; i++) {
6371                 char addr[INET6_ADDRSTRLEN + 1] = "[INVALID]";
6372                 unsigned short port;
6373
6374                 dns_inet_ntop(af, dns_sa_addr(af, &resconf->nameserver[i], NULL), addr, sizeof addr);
6375                 port = ntohs(*dns_sa_port(af, &resconf->nameserver[i]));
6376
6377                 if (port == 53)
6378                         fprintf(fp, "nameserver %s\n", addr);
6379                 else
6380                         fprintf(fp, "nameserver [%s]:%hu\n", addr, port);
6381         }
6382
6383
6384         fprintf(fp, "search");
6385
6386         for (i = 0; i < lengthof(resconf->search) && resconf->search[i][0]; i++)
6387                 fprintf(fp, " %s", resconf->search[i]);
6388
6389         fputc('\n', fp);
6390
6391
6392         fputs("; ", fp);
6393         dns_nssconf_dump(resconf, fp);
6394
6395         fprintf(fp, "lookup");
6396
6397         for (i = 0; i < lengthof(resconf->lookup) && resconf->lookup[i]; i++) {
6398                 switch (resconf->lookup[i]) {
6399                 case 'b':
6400                         fprintf(fp, " bind"); break;
6401                 case 'f':
6402                         fprintf(fp, " file"); break;
6403                 case 'c':
6404                         fprintf(fp, " cache"); break;
6405                 }
6406         }
6407
6408         fputc('\n', fp);
6409
6410
6411         fprintf(fp, "options ndots:%u timeout:%u attempts:%u", resconf->options.ndots, resconf->options.timeout, resconf->options.attempts);
6412
6413         if (resconf->options.edns0)
6414                 fprintf(fp, " edns0");
6415         if (resconf->options.rotate)
6416                 fprintf(fp, " rotate");
6417         if (resconf->options.recurse)
6418                 fprintf(fp, " recurse");
6419         if (resconf->options.smart)
6420                 fprintf(fp, " smart");
6421
6422         switch (resconf->options.tcp) {
6423         case DNS_RESCONF_TCP_ENABLE:
6424                 break;
6425         case DNS_RESCONF_TCP_ONLY:
6426                 fprintf(fp, " tcp");
6427                 break;
6428         case DNS_RESCONF_TCP_SOCKS:
6429                 fprintf(fp, " tcp:socks");
6430                 break;
6431         case DNS_RESCONF_TCP_DISABLE:
6432                 fprintf(fp, " tcp:disable");
6433                 break;
6434         }
6435
6436         fputc('\n', fp);
6437
6438
6439         if ((af = resconf->iface.ss_family) != AF_UNSPEC) {
6440                 char addr[INET6_ADDRSTRLEN + 1] = "[INVALID]";
6441
6442                 dns_inet_ntop(af, dns_sa_addr(af, &resconf->iface, NULL), addr, sizeof addr);
6443
6444                 fprintf(fp, "interface %s %hu\n", addr, ntohs(*dns_sa_port(af, &resconf->iface)));
6445         }
6446
6447         return 0;
6448 } /* dns_resconf_dump() */
6449
6450
6451 /*
6452  * H I N T  S E R V E R  R O U T I N E S
6453  *
6454  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6455
6456 struct dns_hints_soa {
6457         unsigned char zone[DNS_D_MAXNAME + 1];
6458
6459         struct {
6460                 struct sockaddr_storage ss;
6461                 unsigned priority;
6462         } addrs[16];
6463
6464         unsigned count;
6465
6466         struct dns_hints_soa *next;
6467 }; /* struct dns_hints_soa */
6468
6469
6470 struct dns_hints {
6471         dns_atomic_t refcount;
6472
6473         struct dns_hints_soa *head;
6474 }; /* struct dns_hints */
6475
6476
6477 struct dns_hints *dns_hints_open(struct dns_resolv_conf *resconf, int *error) {
6478         static const struct dns_hints H_initializer;
6479         struct dns_hints *H;
6480
6481         (void)resconf;
6482
6483         if (!(H = malloc(sizeof *H)))
6484                 goto syerr;
6485
6486         *H      = H_initializer;
6487
6488         dns_hints_acquire(H);
6489
6490         return H;
6491 syerr:
6492         *error  = dns_syerr();
6493
6494         free(H);
6495
6496         return 0;
6497 } /* dns_hints_open() */
6498
6499
6500 void dns_hints_close(struct dns_hints *H) {
6501         struct dns_hints_soa *soa, *nxt;
6502
6503         if (!H || 1 != dns_hints_release(H))
6504                 return /* void */;
6505
6506         for (soa = H->head; soa; soa = nxt) {
6507                 nxt     = soa->next;
6508
6509                 free(soa);
6510         }
6511
6512         free(H);
6513
6514         return /* void */;
6515 } /* dns_hints_close() */
6516
6517
6518 dns_refcount_t dns_hints_acquire(struct dns_hints *H) {
6519         return dns_atomic_fetch_add(&H->refcount);
6520 } /* dns_hints_acquire() */
6521
6522
6523 dns_refcount_t dns_hints_release(struct dns_hints *H) {
6524         return dns_atomic_fetch_sub(&H->refcount);
6525 } /* dns_hints_release() */
6526
6527
6528 struct dns_hints *dns_hints_mortal(struct dns_hints *hints) {
6529         if (hints)
6530                 dns_hints_release(hints);
6531
6532         return hints;
6533 } /* dns_hints_mortal() */
6534
6535
6536 struct dns_hints *dns_hints_local(struct dns_resolv_conf *resconf, int *error_) {
6537         struct dns_hints *hints         = 0;
6538         int error;
6539
6540         if (resconf)
6541                 dns_resconf_acquire(resconf);
6542         else if (!(resconf = dns_resconf_local(&error)))
6543                 goto error;
6544
6545         if (!(hints = dns_hints_open(resconf, &error)))
6546                 goto error;
6547
6548         error   = 0;
6549
6550         if (0 == dns_hints_insert_resconf(hints, ".", resconf, &error) && error)
6551                 goto error;
6552
6553         dns_resconf_close(resconf);
6554
6555         return hints;
6556 error:
6557         *error_ = error;
6558
6559         dns_resconf_close(resconf);
6560         dns_hints_close(hints);
6561
6562         return 0;
6563 } /* dns_hints_local() */
6564
6565
6566 struct dns_hints *dns_hints_root(struct dns_resolv_conf *resconf, int *error_) {
6567         static const struct {
6568                 int af;
6569                 char addr[INET6_ADDRSTRLEN];
6570         } root_hints[] = {
6571                 { AF_INET,      "198.41.0.4"            },      /* A.ROOT-SERVERS.NET. */
6572                 { AF_INET6,     "2001:503:ba3e::2:30"   },      /* A.ROOT-SERVERS.NET. */
6573                 { AF_INET,      "192.228.79.201"        },      /* B.ROOT-SERVERS.NET. */
6574                 { AF_INET6,     "2001:500:84::b"        },      /* B.ROOT-SERVERS.NET. */
6575                 { AF_INET,      "192.33.4.12"           },      /* C.ROOT-SERVERS.NET. */
6576                 { AF_INET6,     "2001:500:2::c"         },      /* C.ROOT-SERVERS.NET. */
6577                 { AF_INET,      "199.7.91.13"           },      /* D.ROOT-SERVERS.NET. */
6578                 { AF_INET6,     "2001:500:2d::d"        },      /* D.ROOT-SERVERS.NET. */
6579                 { AF_INET,      "192.203.230.10"        },      /* E.ROOT-SERVERS.NET. */
6580                 { AF_INET,      "192.5.5.241"           },      /* F.ROOT-SERVERS.NET. */
6581                 { AF_INET6,     "2001:500:2f::f"        },      /* F.ROOT-SERVERS.NET. */
6582                 { AF_INET,      "192.112.36.4"          },      /* G.ROOT-SERVERS.NET. */
6583                 { AF_INET,      "128.63.2.53"           },      /* H.ROOT-SERVERS.NET. */
6584                 { AF_INET6,     "2001:500:1::803f:235"  },      /* H.ROOT-SERVERS.NET. */
6585                 { AF_INET,      "192.36.148.17"         },      /* I.ROOT-SERVERS.NET. */
6586                 { AF_INET6,     "2001:7FE::53"          },      /* I.ROOT-SERVERS.NET. */
6587                 { AF_INET,      "192.58.128.30"         },      /* J.ROOT-SERVERS.NET. */
6588                 { AF_INET6,     "2001:503:c27::2:30"    },      /* J.ROOT-SERVERS.NET. */
6589                 { AF_INET,      "193.0.14.129"          },      /* K.ROOT-SERVERS.NET. */
6590                 { AF_INET6,     "2001:7FD::1"           },      /* K.ROOT-SERVERS.NET. */
6591                 { AF_INET,      "199.7.83.42"           },      /* L.ROOT-SERVERS.NET. */
6592                 { AF_INET6,     "2001:500:3::42"        },      /* L.ROOT-SERVERS.NET. */
6593                 { AF_INET,      "202.12.27.33"          },      /* M.ROOT-SERVERS.NET. */
6594                 { AF_INET6,     "2001:DC3::35"          },      /* M.ROOT-SERVERS.NET. */
6595         };
6596         struct dns_hints *hints         = 0;
6597         struct sockaddr_storage ss;
6598         unsigned i;
6599         int error, af;
6600
6601         if (!(hints = dns_hints_open(resconf, &error)))
6602                 goto error;
6603
6604         for (i = 0; i < lengthof(root_hints); i++) {
6605                 af      = root_hints[i].af;
6606
6607                 if ((error = dns_pton(af, root_hints[i].addr, dns_sa_addr(af, &ss, NULL))))
6608                         goto error;
6609
6610                 *dns_sa_port(af, &ss)   = htons(53);
6611                 ss.ss_family            = af;
6612
6613                 if ((error = dns_hints_insert(hints, ".", (struct sockaddr *)&ss, 1)))
6614                         goto error;
6615         }
6616
6617         return hints;
6618 error:
6619         *error_ = error;
6620
6621         dns_hints_close(hints);
6622
6623         return 0;
6624 } /* dns_hints_root() */
6625
6626
6627 static struct dns_hints_soa *dns_hints_fetch(struct dns_hints *H, const char *zone) {
6628         struct dns_hints_soa *soa;
6629
6630         for (soa = H->head; soa; soa = soa->next) {
6631                 if (0 == strcasecmp(zone, (char *)soa->zone))
6632                         return soa;
6633         }
6634
6635         return 0;
6636 } /* dns_hints_fetch() */
6637
6638
6639 int dns_hints_insert(struct dns_hints *H, const char *zone, const struct sockaddr *sa, unsigned priority) {
6640         static const struct dns_hints_soa soa_initializer;
6641         struct dns_hints_soa *soa;
6642         unsigned i;
6643
6644         if (!(soa = dns_hints_fetch(H, zone))) {
6645                 if (!(soa = malloc(sizeof *soa)))
6646                         return dns_syerr();
6647                 *soa = soa_initializer;
6648                 dns_strlcpy((char *)soa->zone, zone, sizeof soa->zone);
6649
6650                 soa->next = H->head;
6651                 H->head = soa;
6652         }
6653
6654         i = soa->count % lengthof(soa->addrs);
6655
6656         memcpy(&soa->addrs[i].ss, sa, dns_sa_len(sa));
6657
6658         soa->addrs[i].priority = DNS_PP_MAX(1, priority);
6659
6660         if (soa->count < lengthof(soa->addrs))
6661                 soa->count++;
6662
6663         return 0;
6664 } /* dns_hints_insert() */
6665
6666
6667 static _Bool dns_hints_isinaddr_any(const void *sa) {
6668         struct in_addr *addr;
6669
6670         if (dns_sa_family(sa) != AF_INET)
6671                 return 0;
6672
6673         addr = dns_sa_addr(AF_INET, sa, NULL);
6674         return addr->s_addr == htonl(INADDR_ANY);
6675 }
6676
6677 unsigned dns_hints_insert_resconf(struct dns_hints *H, const char *zone, const struct dns_resolv_conf *resconf, int *error_) {
6678         unsigned i, n, p;
6679         int error;
6680
6681         for (i = 0, n = 0, p = 1; i < lengthof(resconf->nameserver) && resconf->nameserver[i].ss_family != AF_UNSPEC; i++, n++) {
6682                 union { struct sockaddr_in sin; } tmp;
6683                 struct sockaddr *ns;
6684
6685                 /*
6686                  * dns_resconf_open initializes nameserver[0] to INADDR_ANY.
6687                  *
6688                  * Traditionally the semantics of 0.0.0.0 meant the default
6689                  * interface, which evolved to mean the loopback interface.
6690                  * See comment block preceding resolv/res_init.c:res_init in
6691                  * glibc 2.23. As of 2.23, glibc no longer translates
6692                  * 0.0.0.0 despite the code comment, but it does default to
6693                  * 127.0.0.1 when no nameservers are present.
6694                  *
6695                  * BIND9 as of 9.10.3 still translates 0.0.0.0 to 127.0.0.1.
6696                  * See lib/lwres/lwconfig.c:lwres_create_addr and the
6697                  * convert_zero flag. 127.0.0.1 is also the default when no
6698                  * nameservers are present.
6699                  */
6700                 if (dns_hints_isinaddr_any(&resconf->nameserver[i])) {
6701                         memcpy(&tmp.sin, &resconf->nameserver[i], sizeof tmp.sin);
6702                         tmp.sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
6703                         ns = (struct sockaddr *)&tmp.sin;
6704                 } else {
6705                         ns = (struct sockaddr *)&resconf->nameserver[i];
6706                 }
6707
6708                 if ((error = dns_hints_insert(H, zone, ns, p)))
6709                         goto error;
6710
6711                 p += !resconf->options.rotate;
6712         }
6713
6714         return n;
6715 error:
6716         *error_ = error;
6717
6718         return n;
6719 } /* dns_hints_insert_resconf() */
6720
6721
6722 static int dns_hints_i_cmp(unsigned a, unsigned b, struct dns_hints_i *i, struct dns_hints_soa *soa) {
6723         int cmp;
6724
6725         if ((cmp = soa->addrs[a].priority - soa->addrs[b].priority))
6726                 return cmp;
6727
6728         return dns_k_shuffle16(a, i->state.seed) - dns_k_shuffle16(b, i->state.seed);
6729 } /* dns_hints_i_cmp() */
6730
6731
6732 static unsigned dns_hints_i_start(struct dns_hints_i *i, struct dns_hints_soa *soa) {
6733         unsigned p0, p;
6734
6735         p0      = 0;
6736
6737         for (p = 1; p < soa->count; p++) {
6738                 if (dns_hints_i_cmp(p, p0, i, soa) < 0)
6739                         p0      = p;
6740         }
6741
6742         return p0;
6743 } /* dns_hints_i_start() */
6744
6745
6746 static unsigned dns_hints_i_skip(unsigned p0, struct dns_hints_i *i, struct dns_hints_soa *soa) {
6747         unsigned pZ, p;
6748
6749         for (pZ = 0; pZ < soa->count; pZ++) {
6750                 if (dns_hints_i_cmp(pZ, p0, i, soa) > 0)
6751                         goto cont;
6752         }
6753
6754         return soa->count;
6755 cont:
6756         for (p = pZ + 1; p < soa->count; p++) {
6757                 if (dns_hints_i_cmp(p, p0, i, soa) <= 0)
6758                         continue;
6759
6760                 if (dns_hints_i_cmp(p, pZ, i, soa) >= 0)
6761                         continue;
6762
6763                 pZ      = p;
6764         }
6765
6766
6767         return pZ;
6768 } /* dns_hints_i_skip() */
6769
6770
6771 static struct dns_hints_i *dns_hints_i_init(struct dns_hints_i *i, struct dns_hints *hints) {
6772         static const struct dns_hints_i i_initializer;
6773         struct dns_hints_soa *soa;
6774
6775         i->state        = i_initializer.state;
6776
6777         do {
6778                 i->state.seed   = dns_random();
6779         } while (0 == i->state.seed);
6780
6781         if ((soa = dns_hints_fetch(hints, i->zone))) {
6782                 i->state.next   = dns_hints_i_start(i, soa);
6783         }
6784
6785         return i;
6786 } /* dns_hints_i_init() */
6787
6788
6789 unsigned dns_hints_grep(struct sockaddr **sa, socklen_t *sa_len, unsigned lim, struct dns_hints_i *i, struct dns_hints *H) {
6790         struct dns_hints_soa *soa;
6791         unsigned n;
6792
6793         if (!(soa = dns_hints_fetch(H, i->zone)))
6794                 return 0;
6795
6796         n       = 0;
6797
6798         while (i->state.next < soa->count && n < lim) {
6799                 *sa     = (struct sockaddr *)&soa->addrs[i->state.next].ss;
6800                 *sa_len = dns_sa_len(*sa);
6801
6802                 sa++;
6803                 sa_len++;
6804                 n++;
6805
6806                 i->state.next   = dns_hints_i_skip(i->state.next, i, soa);
6807         }
6808
6809         return n;
6810 } /* dns_hints_grep() */
6811
6812
6813 struct dns_packet *dns_hints_query(struct dns_hints *hints, struct dns_packet *Q, int *error_) {
6814         struct dns_packet *A, *P;
6815         struct dns_rr rr;
6816         char zone[DNS_D_MAXNAME + 1];
6817         size_t zlen;
6818         struct dns_hints_i i;
6819         struct sockaddr *sa;
6820         socklen_t slen;
6821         int error;
6822
6823         if (!dns_rr_grep(&rr, 1, dns_rr_i_new(Q, .section = DNS_S_QUESTION), Q, &error))
6824                 goto error;
6825
6826         if (!(zlen = dns_d_expand(zone, sizeof zone, rr.dn.p, Q, &error)))
6827                 goto error;
6828         else if (zlen >= sizeof zone)
6829                 goto toolong;
6830
6831         P                       = dns_p_new(512);
6832         dns_header(P)->qr       = 1;
6833
6834         if ((error = dns_rr_copy(P, &rr, Q)))
6835                 goto error;
6836
6837         if ((error = dns_p_push(P, DNS_S_AUTHORITY, ".", strlen("."), DNS_T_NS, DNS_C_IN, 0, "hints.local.")))
6838                 goto error;
6839
6840         do {
6841                 i.zone  = zone;
6842
6843                 dns_hints_i_init(&i, hints);
6844
6845                 while (dns_hints_grep(&sa, &slen, 1, &i, hints)) {
6846                         int af          = sa->sa_family;
6847                         int rtype       = (af == AF_INET6)? DNS_T_AAAA : DNS_T_A;
6848
6849                         if ((error = dns_p_push(P, DNS_S_ADDITIONAL, "hints.local.", strlen("hints.local."), rtype, DNS_C_IN, 0, dns_sa_addr(af, sa, NULL))))
6850                                 goto error;
6851                 }
6852         } while ((zlen = dns_d_cleave(zone, sizeof zone, zone, zlen)));
6853
6854         if (!(A = dns_p_copy(dns_p_make(P->end, &error), P)))
6855                 goto error;
6856
6857         return A;
6858 toolong:
6859         error = DNS_EILLEGAL;
6860 error:
6861         *error_ = error;
6862
6863         return 0;
6864 } /* dns_hints_query() */
6865
6866
6867 /** ugly hack to support specifying ports other than 53 in resolv.conf. */
6868 static unsigned short dns_hints_port(struct dns_hints *hints, int af, void *addr) {
6869         struct dns_hints_soa *soa;
6870         void *addrsoa;
6871         socklen_t addrlen;
6872         unsigned short port;
6873         unsigned i;
6874
6875         for (soa = hints->head; soa; soa = soa->next) {
6876                 for (i = 0; i < soa->count; i++) {
6877                         if (af != soa->addrs[i].ss.ss_family)
6878                                 continue;
6879
6880                         if (!(addrsoa = dns_sa_addr(af, &soa->addrs[i].ss, &addrlen)))
6881                                 continue;
6882
6883                         if (memcmp(addr, addrsoa, addrlen))
6884                                 continue;
6885
6886                         port = *dns_sa_port(af, &soa->addrs[i].ss);
6887
6888                         return (port)? port : htons(53);
6889                 }
6890         }
6891
6892         return htons(53);
6893 } /* dns_hints_port() */
6894
6895
6896 int dns_hints_dump(struct dns_hints *hints, FILE *fp) {
6897         struct dns_hints_soa *soa;
6898         char addr[INET6_ADDRSTRLEN];
6899         unsigned i;
6900         int af, error;
6901
6902         for (soa = hints->head; soa; soa = soa->next) {
6903                 fprintf(fp, "ZONE \"%s\"\n", soa->zone);
6904
6905                 for (i = 0; i < soa->count; i++) {
6906                         af = soa->addrs[i].ss.ss_family;
6907
6908                         if ((error = dns_ntop(af, dns_sa_addr(af, &soa->addrs[i].ss, NULL), addr, sizeof addr)))
6909                                 return error;
6910
6911                         fprintf(fp, "\t(%d) [%s]:%hu\n", (int)soa->addrs[i].priority, addr, ntohs(*dns_sa_port(af, &soa->addrs[i].ss)));
6912                 }
6913         }
6914
6915         return 0;
6916 } /* dns_hints_dump() */
6917
6918
6919 /*
6920  * C A C H E  R O U T I N E S
6921  *
6922  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6923
6924 static dns_refcount_t dns_cache_acquire(struct dns_cache *cache) {
6925         return dns_atomic_fetch_add(&cache->_.refcount);
6926 } /* dns_cache_acquire() */
6927
6928
6929 static dns_refcount_t dns_cache_release(struct dns_cache *cache) {
6930         return dns_atomic_fetch_sub(&cache->_.refcount);
6931 } /* dns_cache_release() */
6932
6933
6934 static struct dns_packet *dns_cache_query(struct dns_packet *query, struct dns_cache *cache, int *error) {
6935         (void)query;
6936         (void)cache;
6937         (void)error;
6938
6939         return NULL;
6940 } /* dns_cache_query() */
6941
6942
6943 static int dns_cache_submit(struct dns_packet *query, struct dns_cache *cache) {
6944         (void)query;
6945         (void)cache;
6946
6947         return 0;
6948 } /* dns_cache_submit() */
6949
6950
6951 static int dns_cache_check(struct dns_cache *cache) {
6952         (void)cache;
6953
6954         return 0;
6955 } /* dns_cache_check() */
6956
6957
6958 static struct dns_packet *dns_cache_fetch(struct dns_cache *cache, int *error) {
6959         (void)cache;
6960         (void)error;
6961
6962         return NULL;
6963 } /* dns_cache_fetch() */
6964
6965
6966 static int dns_cache_pollfd(struct dns_cache *cache) {
6967         (void)cache;
6968
6969         return -1;
6970 } /* dns_cache_pollfd() */
6971
6972
6973 static short dns_cache_events(struct dns_cache *cache) {
6974         (void)cache;
6975
6976         return 0;
6977 } /* dns_cache_events() */
6978
6979
6980 static void dns_cache_clear(struct dns_cache *cache) {
6981         (void)cache;
6982
6983         return;
6984 } /* dns_cache_clear() */
6985
6986
6987 struct dns_cache *dns_cache_init(struct dns_cache *cache) {
6988         static const struct dns_cache c_init = {
6989                 .acquire = &dns_cache_acquire,
6990                 .release = &dns_cache_release,
6991                 .query   = &dns_cache_query,
6992                 .submit  = &dns_cache_submit,
6993                 .check   = &dns_cache_check,
6994                 .fetch   = &dns_cache_fetch,
6995                 .pollfd  = &dns_cache_pollfd,
6996                 .events  = &dns_cache_events,
6997                 .clear   = &dns_cache_clear,
6998                 ._ = { .refcount = 1, },
6999         };
7000
7001         *cache = c_init;
7002
7003         return cache;
7004 } /* dns_cache_init() */
7005
7006
7007 void dns_cache_close(struct dns_cache *cache) {
7008         if (cache)
7009                 cache->release(cache);
7010 } /* dns_cache_close() */
7011
7012
7013 /*
7014  * S O C K E T  R O U T I N E S
7015  *
7016  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7017
7018 static void dns_socketclose(int *fd, const struct dns_options *opts) {
7019         if (opts && opts->closefd.cb)
7020                 opts->closefd.cb(fd, opts->closefd.arg);
7021
7022         if (*fd != -1) {
7023 #if _WIN32
7024                 closesocket(*fd);
7025 #else
7026                 close(*fd);
7027 #endif
7028                 *fd     = -1;
7029         }
7030 } /* dns_socketclose() */
7031
7032
7033 #ifndef HAVE_IOCTLSOCKET
7034 #define HAVE_IOCTLSOCKET (_WIN32 || _WIN64)
7035 #endif
7036
7037 #ifndef HAVE_SOCK_CLOEXEC
7038 #define HAVE_SOCK_CLOEXEC (defined SOCK_CLOEXEC)
7039 #endif
7040
7041 #ifndef HAVE_SOCK_NONBLOCK
7042 #define HAVE_SOCK_NONBLOCK (defined SOCK_NONBLOCK)
7043 #endif
7044
7045 #define DNS_SO_MAXTRY   7
7046
7047 static int dns_socket(struct sockaddr *local, int type, int *error_) {
7048         int fd = -1, flags, error;
7049 #if defined FIONBIO
7050         unsigned long opt;
7051 #endif
7052
7053         flags = 0;
7054 #if HAVE_SOCK_CLOEXEC
7055         flags |= SOCK_CLOEXEC;
7056 #endif
7057 #if HAVE_SOCK_NONBLOCK
7058         flags |= SOCK_NONBLOCK;
7059 #endif
7060         if (-1 == (fd = socket(local->sa_family, type|flags, 0)))
7061                 goto soerr;
7062
7063 #if defined F_SETFD && !HAVE_SOCK_CLOEXEC
7064         if (-1 == fcntl(fd, F_SETFD, 1))
7065                 goto syerr;
7066 #endif
7067
7068 #if defined O_NONBLOCK && !HAVE_SOCK_NONBLOCK
7069         if (-1 == (flags = fcntl(fd, F_GETFL)))
7070                 goto syerr;
7071         if (-1 == fcntl(fd, F_SETFL, flags | O_NONBLOCK))
7072                 goto syerr;
7073 #elif defined FIONBIO && HAVE_IOCTLSOCKET
7074         opt = 1;
7075         if (0 != ioctlsocket(fd, FIONBIO, &opt))
7076                 goto soerr;
7077 #endif
7078
7079 #if defined SO_NOSIGPIPE
7080         if (type != SOCK_DGRAM) {
7081                 if (0 != setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &(int){ 1 }, sizeof (int)))
7082                         goto soerr;
7083         }
7084 #endif
7085
7086         if (local->sa_family != AF_INET && local->sa_family != AF_INET6)
7087                 return fd;
7088
7089         if (type != SOCK_DGRAM)
7090                 return fd;
7091
7092         /*
7093          * FreeBSD, Linux, OpenBSD, OS X, and Solaris use random ports by
7094          * default. Though the ephemeral range is quite small on OS X
7095          * (49152-65535 on 10.10) and Linux (32768-60999 on 4.4.0, Ubuntu
7096          * Xenial). See also RFC 6056.
7097          *
7098          * TODO: Optionally rely on the kernel to select a random port.
7099          */
7100         if (*dns_sa_port(local->sa_family, local) == 0) {
7101                 struct sockaddr_storage tmp;
7102                 unsigned i, port;
7103
7104                 memcpy(&tmp, local, dns_sa_len(local));
7105
7106                 for (i = 0; i < DNS_SO_MAXTRY; i++) {
7107                         port = 1025 + (dns_random() % 64510);
7108
7109                         *dns_sa_port(tmp.ss_family, &tmp) = htons(port);
7110
7111                         if (0 == bind(fd, (struct sockaddr *)&tmp, dns_sa_len(&tmp)))
7112                                 return fd;
7113                 }
7114
7115                 /* NB: continue to next bind statement */
7116         }
7117
7118         if (0 == bind(fd, local, dns_sa_len(local)))
7119                 return fd;
7120
7121         /* FALL THROUGH */
7122 soerr:
7123         error = dns_soerr();
7124
7125         goto error;
7126 #if (defined F_SETFD && !HAVE_SOCK_CLOEXEC) || (defined O_NONBLOCK && !HAVE_SOCK_NONBLOCK)
7127 syerr:
7128         error = dns_syerr();
7129
7130         goto error;
7131 #endif
7132 error:
7133         *error_ = error;
7134
7135         dns_socketclose(&fd, NULL);
7136
7137         return -1;
7138 } /* dns_socket() */
7139
7140
7141 enum {
7142         DNS_SO_UDP_INIT = 1,
7143         DNS_SO_UDP_CONN,
7144         DNS_SO_UDP_SEND,
7145         DNS_SO_UDP_RECV,
7146         DNS_SO_UDP_DONE,
7147
7148         DNS_SO_TCP_INIT,
7149         DNS_SO_TCP_CONN,
7150         DNS_SO_TCP_SEND,
7151         DNS_SO_TCP_RECV,
7152         DNS_SO_TCP_DONE,
7153
7154         DNS_SO_SOCKS_INIT,
7155         DNS_SO_SOCKS_CONN,
7156         DNS_SO_SOCKS_HELLO_SEND,
7157         DNS_SO_SOCKS_HELLO_RECV,
7158         DNS_SO_SOCKS_AUTH_SEND,
7159         DNS_SO_SOCKS_AUTH_RECV,
7160         DNS_SO_SOCKS_REQUEST_PREPARE,
7161         DNS_SO_SOCKS_REQUEST_SEND,
7162         DNS_SO_SOCKS_REQUEST_RECV,
7163         DNS_SO_SOCKS_REQUEST_RECV_V6,
7164         DNS_SO_SOCKS_HANDSHAKE_DONE,
7165 };
7166
7167 struct dns_socket {
7168         struct dns_options opts;
7169
7170         int udp;
7171         int tcp;
7172
7173         int *old;
7174         unsigned onum, olim;
7175
7176         int type;
7177
7178         struct sockaddr_storage local, remote;
7179
7180         struct dns_k_permutor qids;
7181
7182         struct dns_stat stat;
7183
7184         struct dns_trace *trace;
7185
7186         /*
7187          * NOTE: dns_so_reset() zeroes everything from here down.
7188          */
7189         int state;
7190
7191         unsigned short qid;
7192         char qname[DNS_D_MAXNAME + 1];
7193         size_t qlen;
7194         enum dns_type qtype;
7195         enum dns_class qclass;
7196
7197         struct dns_packet *query;
7198         size_t qout;
7199
7200         /* During a SOCKS handshake the query is temporarily stored
7201          * here.  */
7202         struct dns_packet *query_backup;
7203
7204         struct dns_clock elapsed;
7205
7206         struct dns_packet *answer;
7207         size_t alen, apos;
7208 }; /* struct dns_socket */
7209
7210
7211 /*
7212  * NOTE: Actual closure delayed so that kqueue(2) and epoll(2) callers have
7213  * a chance to recognize a state change after installing a persistent event
7214  * and where sequential descriptors with the same integer value returned
7215  * from _pollfd() would be ambiguous. See dns_so_closefds().
7216  */
7217 static int dns_so_closefd(struct dns_socket *so, int *fd) {
7218         int error;
7219
7220         if (*fd == -1)
7221                 return 0;
7222
7223         if (so->opts.closefd.cb) {
7224                 if ((error = so->opts.closefd.cb(fd, so->opts.closefd.arg))) {
7225                         return error;
7226                 } else if (*fd == -1)
7227                         return 0;
7228         }
7229
7230         if (!(so->onum < so->olim)) {
7231                 unsigned olim = DNS_PP_MAX(4, so->olim * 2);
7232                 void *old;
7233
7234                 if (!(old = realloc(so->old, sizeof so->old[0] * olim)))
7235                         return dns_syerr();
7236
7237                 so->old  = old;
7238                 so->olim = olim;
7239         }
7240
7241         so->old[so->onum++] = *fd;
7242         *fd = -1;
7243
7244         return 0;
7245 } /* dns_so_closefd() */
7246
7247
7248 #define DNS_SO_CLOSE_UDP 0x01
7249 #define DNS_SO_CLOSE_TCP 0x02
7250 #define DNS_SO_CLOSE_OLD 0x04
7251 #define DNS_SO_CLOSE_ALL (DNS_SO_CLOSE_UDP|DNS_SO_CLOSE_TCP|DNS_SO_CLOSE_OLD)
7252
7253 static void dns_so_closefds(struct dns_socket *so, int which) {
7254         if (DNS_SO_CLOSE_UDP & which)
7255                 dns_socketclose(&so->udp, &so->opts);
7256         if (DNS_SO_CLOSE_TCP & which)
7257                 dns_socketclose(&so->tcp, &so->opts);
7258         if (DNS_SO_CLOSE_OLD & which) {
7259                 unsigned i;
7260                 for (i = 0; i < so->onum; i++)
7261                         dns_socketclose(&so->old[i], &so->opts);
7262                 so->onum = 0;
7263                 free(so->old);
7264                 so->old  = 0;
7265                 so->olim = 0;
7266         }
7267 } /* dns_so_closefds() */
7268
7269
7270 static void dns_so_destroy(struct dns_socket *);
7271
7272 static struct dns_socket *dns_so_init(struct dns_socket *so, const struct sockaddr *local, int type, const struct dns_options *opts, int *error) {
7273         static const struct dns_socket so_initializer = { .opts = DNS_OPTS_INITIALIZER, .udp = -1, .tcp = -1, };
7274
7275         *so             = so_initializer;
7276         so->type        = type;
7277
7278         if (opts)
7279                 so->opts = *opts;
7280
7281         if (local)
7282                 memcpy(&so->local, local, dns_sa_len(local));
7283
7284         if (-1 == (so->udp = dns_socket((struct sockaddr *)&so->local, SOCK_DGRAM, error)))
7285                 goto error;
7286
7287         dns_k_permutor_init(&so->qids, 1, 65535);
7288
7289         return so;
7290 error:
7291         dns_so_destroy(so);
7292
7293         return 0;
7294 } /* dns_so_init() */
7295
7296
7297 struct dns_socket *dns_so_open(const struct sockaddr *local, int type, const struct dns_options *opts, int *error) {
7298         struct dns_socket *so;
7299
7300         if (!(so = malloc(sizeof *so)))
7301                 goto syerr;
7302
7303         if (!dns_so_init(so, local, type, opts, error))
7304                 goto error;
7305
7306         return so;
7307 syerr:
7308         *error  = dns_syerr();
7309 error:
7310         dns_so_close(so);
7311
7312         return 0;
7313 } /* dns_so_open() */
7314
7315
7316 static void dns_so_destroy(struct dns_socket *so) {
7317         dns_so_reset(so);
7318         dns_so_closefds(so, DNS_SO_CLOSE_ALL);
7319         dns_trace_close(so->trace);
7320 } /* dns_so_destroy() */
7321
7322
7323 void dns_so_close(struct dns_socket *so) {
7324         if (!so)
7325                 return;
7326
7327         dns_so_destroy(so);
7328
7329         free(so);
7330 } /* dns_so_close() */
7331
7332
7333 void dns_so_reset(struct dns_socket *so) {
7334         dns_p_setptr(&so->answer, NULL);
7335
7336         memset(&so->state, '\0', sizeof *so - offsetof(struct dns_socket, state));
7337 } /* dns_so_reset() */
7338
7339
7340 unsigned short dns_so_mkqid(struct dns_socket *so) {
7341         return dns_k_permutor_step(&so->qids);
7342 } /* dns_so_mkqid() */
7343
7344
7345 #define DNS_SO_MINBUF   768
7346
7347 static int dns_so_newanswer(struct dns_socket *so, size_t len) {
7348         size_t size     = offsetof(struct dns_packet, data) + DNS_PP_MAX(len, DNS_SO_MINBUF);
7349         void *p;
7350
7351         if (!(p = realloc(so->answer, size)))
7352                 return dns_syerr();
7353
7354         so->answer      = dns_p_init(p, size);
7355
7356         return 0;
7357 } /* dns_so_newanswer() */
7358
7359
7360 int dns_so_submit(struct dns_socket *so, struct dns_packet *Q, struct sockaddr *host) {
7361         struct dns_rr rr;
7362         int error = DNS_EUNKNOWN;
7363
7364         dns_so_reset(so);
7365
7366         if ((error = dns_rr_parse(&rr, 12, Q)))
7367                 goto error;
7368
7369         if (!(so->qlen = dns_d_expand(so->qname, sizeof so->qname, rr.dn.p, Q, &error)))
7370                 goto error;
7371         /*
7372          * NOTE: Don't bail if expansion is too long; caller may be
7373          * intentionally sending long names. However, we won't be able to
7374          * verify it on return.
7375          */
7376
7377         so->qtype       = rr.type;
7378         so->qclass      = rr.class;
7379
7380         if ((error = dns_so_newanswer(so, (Q->memo.opt.maxudp)? Q->memo.opt.maxudp : DNS_SO_MINBUF)))
7381                 goto syerr;
7382
7383         memcpy(&so->remote, host, dns_sa_len(host));
7384
7385         so->query       = Q;
7386         so->qout        = 0;
7387
7388         dns_begin(&so->elapsed);
7389
7390         if (dns_header(so->query)->qid == 0)
7391                 dns_header(so->query)->qid      = dns_so_mkqid(so);
7392
7393         so->qid         = dns_header(so->query)->qid;
7394         so->state       = (so->opts.socks_host && so->opts.socks_host->ss_family) ? DNS_SO_SOCKS_INIT :
7395                 (so->type == SOCK_STREAM)? DNS_SO_TCP_INIT : DNS_SO_UDP_INIT;
7396
7397         so->stat.queries++;
7398         dns_trace_so_submit(so->trace, Q, host, 0);
7399
7400         return 0;
7401 syerr:
7402         error   = dns_syerr();
7403 error:
7404         dns_so_reset(so);
7405         dns_trace_so_submit(so->trace, Q, host, error);
7406         return error;
7407 } /* dns_so_submit() */
7408
7409
7410 static int dns_so_verify(struct dns_socket *so, struct dns_packet *P) {
7411         char qname[DNS_D_MAXNAME + 1];
7412         size_t qlen;
7413         struct dns_rr rr;
7414         int error = -1;
7415
7416         if (P->end < 12)
7417                 goto reject;
7418
7419         if (so->qid != dns_header(P)->qid)
7420                 goto reject;
7421
7422         if (!dns_p_count(P, DNS_S_QD))
7423                 goto reject;
7424
7425         if (0 != dns_rr_parse(&rr, 12, P))
7426                 goto reject;
7427
7428         if (rr.type != so->qtype || rr.class != so->qclass)
7429                 goto reject;
7430
7431         if (!(qlen = dns_d_expand(qname, sizeof qname, rr.dn.p, P, &error)))
7432                 goto error;
7433         else if (qlen >= sizeof qname || qlen != so->qlen)
7434                 goto reject;
7435
7436         if (0 != strcasecmp(so->qname, qname))
7437                 goto reject;
7438
7439         dns_trace_so_verify(so->trace, P, 0);
7440
7441         return 0;
7442 reject:
7443         error = DNS_EVERIFY;
7444 error:
7445         DNS_SHOW(P, "rejecting packet (%s)", dns_strerror(error));
7446         dns_trace_so_verify(so->trace, P, error);
7447
7448         return error;
7449 } /* dns_so_verify() */
7450
7451
7452 static _Bool dns_so_tcp_keep(struct dns_socket *so) {
7453         struct sockaddr_storage remote;
7454
7455         if (so->tcp == -1)
7456                 return 0;
7457
7458         if (0 != getpeername(so->tcp, (struct sockaddr *)&remote, &(socklen_t){ sizeof remote }))
7459                 return 0;
7460
7461         return 0 == dns_sa_cmp(&remote, &so->remote);
7462 } /* dns_so_tcp_keep() */
7463
7464
7465 /* Convenience functions for sending non-DNS data.  */
7466
7467 /* Set up everything for sending LENGTH octets.  Returns the buffer
7468    for the data.  */
7469 static unsigned char *dns_so_tcp_send_buffer(struct dns_socket *so, size_t length) {
7470         /* Skip the length octets, we are not doing DNS.  */
7471         so->qout = 2;
7472         so->query->end = length;
7473         return so->query->data;
7474 }
7475
7476 /* Set up everything for receiving LENGTH octets.  */
7477 static void dns_so_tcp_recv_expect(struct dns_socket *so, size_t length) {
7478         /* Skip the length octets, we are not doing DNS.  */
7479         so->apos = 2;
7480         so->alen = length;
7481 }
7482
7483 /* Returns the buffer containing the received data.  */
7484 static unsigned char *dns_so_tcp_recv_buffer(struct dns_socket *so) {
7485         return so->answer->data;
7486 }
7487
7488
7489 #if defined __clang__
7490 #pragma clang diagnostic push
7491 #pragma clang diagnostic ignored "-Warray-bounds"
7492 #endif
7493
7494 static int dns_so_tcp_send(struct dns_socket *so) {
7495         unsigned char *qsrc;
7496         size_t qend;
7497         int error;
7498         size_t n;
7499
7500         so->query->data[-2] = 0xff & (so->query->end >> 8);
7501         so->query->data[-1] = 0xff & (so->query->end >> 0);
7502
7503         qend = so->query->end + 2;
7504
7505         while (so->qout < qend) {
7506                 qsrc = &so->query->data[-2] + so->qout;
7507                 n = dns_send_nopipe(so->tcp, (void *)qsrc, qend - so->qout, 0, &error);
7508                 dns_trace_sys_send(so->trace, so->tcp, SOCK_STREAM, qsrc, n, error);
7509                 if (error)
7510                         return error;
7511                 so->qout += n;
7512                 so->stat.tcp.sent.bytes += n;
7513         }
7514
7515         so->stat.tcp.sent.count++;
7516
7517         return 0;
7518 } /* dns_so_tcp_send() */
7519
7520
7521 static int dns_so_tcp_recv(struct dns_socket *so) {
7522         unsigned char *asrc;
7523         size_t aend, alen, n;
7524         int error;
7525
7526         aend = so->alen + 2;
7527
7528         while (so->apos < aend) {
7529                 asrc = &so->answer->data[-2];
7530
7531                 n = dns_recv(so->tcp, (void *)&asrc[so->apos], aend - so->apos, 0, &error);
7532                 dns_trace_sys_recv(so->trace, so->tcp, SOCK_STREAM, &asrc[so->apos], n, error);
7533                 if (error)
7534                         return error;
7535
7536                 so->apos += n;
7537                 so->stat.tcp.rcvd.bytes += n;
7538
7539                 if (so->alen == 0 && so->apos >= 2) {
7540                         alen = ((0xff & so->answer->data[-2]) << 8)
7541                              | ((0xff & so->answer->data[-1]) << 0);
7542
7543                         if ((error = dns_so_newanswer(so, alen)))
7544                                 return error;
7545
7546                         so->alen = alen;
7547                         aend = alen + 2;
7548                 }
7549         }
7550
7551         so->answer->end = so->alen;
7552         so->stat.tcp.rcvd.count++;
7553
7554         return 0;
7555 } /* dns_so_tcp_recv() */
7556
7557 #if __clang__
7558 #pragma clang diagnostic pop
7559 #endif
7560
7561
7562 int dns_so_check(struct dns_socket *so) {
7563         int error;
7564         size_t n;
7565         unsigned char *buffer;
7566
7567 retry:
7568         switch (so->state) {
7569         case DNS_SO_UDP_INIT:
7570                 so->state++;
7571         case DNS_SO_UDP_CONN:
7572                 error = dns_connect(so->udp, (struct sockaddr *)&so->remote, dns_sa_len(&so->remote));
7573                 dns_trace_sys_connect(so->trace, so->udp, SOCK_DGRAM, (struct sockaddr *)&so->remote, error);
7574                 if (error)
7575                         goto error;
7576
7577                 so->state++;
7578         case DNS_SO_UDP_SEND:
7579                 n = dns_send(so->udp, (void *)so->query->data, so->query->end, 0, &error);
7580                 dns_trace_sys_send(so->trace, so->udp, SOCK_DGRAM, so->query->data, n, error);
7581                 if (error)
7582                         goto error;
7583
7584                 so->stat.udp.sent.bytes += n;
7585                 so->stat.udp.sent.count++;
7586
7587                 so->state++;
7588         case DNS_SO_UDP_RECV:
7589                 n = dns_recv(so->udp, (void *)so->answer->data, so->answer->size, 0, &error);
7590                 dns_trace_sys_recv(so->trace, so->udp, SOCK_DGRAM, so->answer->data, n, error);
7591                 if (error)
7592                         goto error;
7593
7594                 so->answer->end = n;
7595                 so->stat.udp.rcvd.bytes += n;
7596                 so->stat.udp.rcvd.count++;
7597
7598                 if ((error = dns_so_verify(so, so->answer)))
7599                         goto trash;
7600
7601                 so->state++;
7602         case DNS_SO_UDP_DONE:
7603                 if (!dns_header(so->answer)->tc || so->type == SOCK_DGRAM)
7604                         return 0;
7605
7606                 so->state++;
7607         case DNS_SO_TCP_INIT:
7608                 if (dns_so_tcp_keep(so)) {
7609                         so->state = DNS_SO_TCP_SEND;
7610
7611                         goto retry;
7612                 }
7613
7614                 if ((error = dns_so_closefd(so, &so->tcp)))
7615                         goto error;
7616
7617                 if (-1 == (so->tcp = dns_socket((struct sockaddr *)&so->local, SOCK_STREAM, &error)))
7618                         goto error;
7619
7620                 so->state++;
7621         case DNS_SO_TCP_CONN:
7622                 error = dns_connect(so->tcp, (struct sockaddr *)&so->remote, dns_sa_len(&so->remote));
7623                 dns_trace_sys_connect(so->trace, so->tcp, SOCK_STREAM, (struct sockaddr *)&so->remote, error);
7624                 if (error && error != DNS_EISCONN)
7625                         goto error;
7626
7627                 so->state++;
7628         case DNS_SO_TCP_SEND:
7629                 if ((error = dns_so_tcp_send(so)))
7630                         goto error;
7631
7632                 so->state++;
7633         case DNS_SO_TCP_RECV:
7634                 if ((error = dns_so_tcp_recv(so)))
7635                         goto error;
7636
7637                 so->state++;
7638         case DNS_SO_TCP_DONE:
7639                 /* close unless DNS_RESCONF_TCP_ONLY (see dns_res_tcp2type) */
7640                 if (so->type != SOCK_STREAM) {
7641                         if ((error = dns_so_closefd(so, &so->tcp)))
7642                                 goto error;
7643                 }
7644
7645                 if ((error = dns_so_verify(so, so->answer)))
7646                         goto error;
7647
7648                 return 0;
7649         case DNS_SO_SOCKS_INIT:
7650                 if ((error = dns_so_closefd(so, &so->tcp)))
7651                         goto error;
7652
7653                 if (-1 == (so->tcp = dns_socket((struct sockaddr *)&so->local, SOCK_STREAM, &error)))
7654                         goto error;
7655
7656                 so->state++;
7657         case DNS_SO_SOCKS_CONN: {
7658                 unsigned char method;
7659
7660                 error = dns_connect(so->tcp, (struct sockaddr *)so->opts.socks_host, dns_sa_len(so->opts.socks_host));
7661                 dns_trace_sys_connect(so->trace, so->tcp, SOCK_STREAM, (struct sockaddr *)so->opts.socks_host, error);
7662                 if (error && error != DNS_EISCONN)
7663                         goto error;
7664
7665                 /* We need to do a handshake with the SOCKS server,
7666                  * but the query is already in the buffer.  Move it
7667                  * out of the way.  */
7668                 dns_p_movptr(&so->query_backup, &so->query);
7669
7670                 /* Create a new buffer for the handshake.  */
7671                 dns_p_grow(&so->query);
7672
7673                 /* Negotiate method.  */
7674                 buffer = dns_so_tcp_send_buffer(so, 3);
7675                 buffer[0] = 5; /* RFC-1928 VER field.  */
7676                 buffer[1] = 1; /* NMETHODS */
7677                 if (so->opts.socks_user)
7678                         method = 2;  /* Method: username/password authentication. */
7679                 else
7680                         method = 0;  /* Method: No authentication required. */
7681                 buffer[2] = method;
7682
7683                 so->state++;
7684         }
7685         case DNS_SO_SOCKS_HELLO_SEND:
7686                 if ((error = dns_so_tcp_send(so)))
7687                         goto error;
7688
7689                 dns_so_tcp_recv_expect(so, 2);
7690                 so->state++;
7691         case DNS_SO_SOCKS_HELLO_RECV: {
7692                 unsigned char method;
7693
7694                 if ((error = dns_so_tcp_recv(so)))
7695                         goto error;
7696
7697                 buffer = dns_so_tcp_recv_buffer(so);
7698                 method = so->opts.socks_user ? 2 : 0;
7699                 if (buffer[0] != 5 || buffer[1] != method) {
7700                         /* Socks server returned wrong version or does
7701                            not support our requested method.  */
7702                         error = ENOTSUP; /* Fixme: Is there a better errno? */
7703                         goto error;
7704                 }
7705
7706                 if (method == 0) {
7707                         /* No authentication, go ahead and send the
7708                            request.  */
7709                         so->state = DNS_SO_SOCKS_REQUEST_PREPARE;
7710                         goto retry;
7711                 }
7712
7713                 /* Prepare username/password sub-negotiation.  */
7714                 if (! so->opts.socks_password) {
7715                         error = EINVAL; /* No password given.  */
7716                         goto error;
7717                 } else {
7718                         size_t buflen, ulen, plen;
7719
7720                         ulen = strlen(so->opts.socks_user);
7721                         plen = strlen(so->opts.socks_password);
7722                         if (!ulen || ulen > 255 || !plen || plen > 255) {
7723                                 error = EINVAL; /* Credentials too long or too short.  */
7724                                 goto error;
7725                         }
7726
7727                         buffer = dns_so_tcp_send_buffer(so, 3 + ulen + plen);
7728                         buffer[0] = 1; /* VER of the sub-negotiation. */
7729                         buffer[1] = (unsigned char) ulen;
7730                         buflen = 2;
7731                         memcpy (buffer+buflen, so->opts.socks_user, ulen);
7732                         buflen += ulen;
7733                         buffer[buflen++] = (unsigned char) plen;
7734                         memcpy (buffer+buflen, so->opts.socks_password, plen);
7735                 }
7736
7737                 so->state++;
7738         }
7739         case DNS_SO_SOCKS_AUTH_SEND:
7740                 if ((error = dns_so_tcp_send(so)))
7741                         goto error;
7742
7743                 /* Skip the two length octets, and receive two octets.  */
7744                 dns_so_tcp_recv_expect(so, 2);
7745
7746                 so->state++;
7747         case DNS_SO_SOCKS_AUTH_RECV:
7748                 if ((error = dns_so_tcp_recv(so)))
7749                         goto error;
7750
7751                 buffer = dns_so_tcp_recv_buffer(so);
7752                 if (buffer[0] != 1) {
7753                         /* SOCKS server returned wrong version.  */
7754                         error = EPROTO;
7755                         goto error;
7756                 }
7757                 if (buffer[1]) {
7758                         /* SOCKS server denied access.  */
7759                         error = EACCES;
7760                         goto error;
7761                 }
7762
7763                 so->state++;
7764         case DNS_SO_SOCKS_REQUEST_PREPARE:
7765                 /* Send request details (rfc-1928, 4).  */
7766                 buffer = dns_so_tcp_send_buffer(so, so->remote.ss_family == AF_INET6 ? 22 : 10);
7767                 buffer[0] = 5; /* VER  */
7768                 buffer[1] = 1; /* CMD = CONNECT  */
7769                 buffer[2] = 0; /* RSV  */
7770                 if (so->remote.ss_family == AF_INET6) {
7771                         struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)&so->remote;
7772
7773                         buffer[3] = 4; /* ATYP = IPv6 */
7774                         memcpy (buffer+ 4, &addr_in6->sin6_addr.s6_addr, 16); /* DST.ADDR */
7775                         memcpy (buffer+20, &addr_in6->sin6_port, 2);          /* DST.PORT */
7776                 } else {
7777                         struct sockaddr_in *addr_in = (struct sockaddr_in *)&so->remote;
7778
7779                         buffer[3] = 1; /* ATYP = IPv4 */
7780                         memcpy (buffer+4, &addr_in->sin_addr.s_addr, 4); /* DST.ADDR */
7781                         memcpy (buffer+8, &addr_in->sin_port, 2);        /* DST.PORT */
7782                 }
7783
7784                 so->state++;
7785         case DNS_SO_SOCKS_REQUEST_SEND:
7786                 if ((error = dns_so_tcp_send(so)))
7787                         goto error;
7788
7789                 /* Expect ten octets.  This is the length of the
7790                  * response assuming a IPv4 address is used.  */
7791                 dns_so_tcp_recv_expect(so, 10);
7792                 so->state++;
7793         case DNS_SO_SOCKS_REQUEST_RECV:
7794                 if ((error = dns_so_tcp_recv(so)))
7795                         goto error;
7796
7797                 buffer = dns_so_tcp_recv_buffer(so);
7798                 if (buffer[0] != 5 || buffer[2] != 0) {
7799                         /* Socks server returned wrong version or the
7800                            reserved field is not zero.  */
7801                         error = EPROTO;
7802                         goto error;
7803                 }
7804                 if (buffer[1]) {
7805                         switch (buffer[1]) {
7806                         case 0x01: /* general SOCKS server failure.  */
7807                                 error = ENETDOWN;
7808                                 break;
7809                         case 0x02: /* connection not allowed by ruleset.  */
7810                                 error = EACCES;
7811                                 break;
7812                         case 0x03: /* Network unreachable */
7813                                 error = ENETUNREACH;
7814                                 break;
7815                         case 0x04: /* Host unreachable */
7816                                 error = EHOSTUNREACH;
7817                                 break;
7818                         case 0x05: /* Connection refused */
7819                                 error = ECONNREFUSED;
7820                                 break;
7821                         case 0x06: /* TTL expired */
7822                                 error = ETIMEDOUT;
7823                                 break;
7824                         case 0x08: /* Address type not supported */
7825                                 error = EPROTONOSUPPORT;
7826                                 break;
7827                         case 0x07: /* Command not supported */
7828                         default:
7829                                 error = ENOTSUP; /* Fixme: Is there a better error? */
7830                                 break;
7831                         }
7832                         goto error;
7833                 }
7834
7835                 if (buffer[3] == 1) {
7836                         /* This was indeed an IPv4 address.  */
7837                         so->state = DNS_SO_SOCKS_HANDSHAKE_DONE;
7838                         goto retry;
7839                 }
7840
7841                 if (buffer[3] != 4) {
7842                         error = ENOTSUP;
7843                         goto error;
7844                 }
7845
7846                 /* Expect receive twelve octets.  This accounts for
7847                  * the remaining bytes assuming an IPv6 address is
7848                  * used.  */
7849                 dns_so_tcp_recv_expect(so, 12);
7850                 so->state++;
7851         case DNS_SO_SOCKS_REQUEST_RECV_V6:
7852                 if ((error = dns_so_tcp_recv(so)))
7853                         goto error;
7854
7855                 so->state++;
7856         case DNS_SO_SOCKS_HANDSHAKE_DONE:
7857                 /* We have not way to store the actual address used by
7858                  * the server.  Then again, we don't really care.  */
7859
7860                 /* Restore the query.  */
7861                 dns_p_movptr(&so->query, &so->query_backup);
7862
7863                 /* Reset cursors.  */
7864                 so->qout = 0;
7865                 so->apos = 0;
7866                 so->alen = 0;
7867
7868                 /* SOCKS handshake is done.  Proceed with the
7869                  * lookup.  */
7870                 so->state = DNS_SO_TCP_SEND;
7871                 goto retry;
7872         default:
7873                 error   = DNS_EUNKNOWN;
7874
7875                 goto error;
7876         } /* switch() */
7877
7878 trash:
7879         DNS_CARP("discarding packet");
7880         goto retry;
7881 error:
7882         switch (error) {
7883         case DNS_EINTR:
7884                 goto retry;
7885         case DNS_EINPROGRESS:
7886                 /* FALL THROUGH */
7887         case DNS_EALREADY:
7888                 /* FALL THROUGH */
7889 #if DNS_EWOULDBLOCK != DNS_EAGAIN
7890         case DNS_EWOULDBLOCK:
7891                 /* FALL THROUGH */
7892 #endif
7893                 error   = DNS_EAGAIN;
7894
7895                 break;
7896         } /* switch() */
7897
7898         return error;
7899 } /* dns_so_check() */
7900
7901
7902 struct dns_packet *dns_so_fetch(struct dns_socket *so, int *error) {
7903         struct dns_packet *answer;
7904
7905         switch (so->state) {
7906         case DNS_SO_UDP_DONE:
7907         case DNS_SO_TCP_DONE:
7908                 answer          = so->answer;
7909                 so->answer      = 0;
7910                 dns_trace_so_fetch(so->trace, answer, 0);
7911
7912                 return answer;
7913         default:
7914                 *error  = DNS_EUNKNOWN;
7915                 dns_trace_so_fetch(so->trace, NULL, *error);
7916
7917                 return 0;
7918         }
7919 } /* dns_so_fetch() */
7920
7921
7922 struct dns_packet *dns_so_query(struct dns_socket *so, struct dns_packet *Q, struct sockaddr *host, int *error_) {
7923         struct dns_packet *A;
7924         int error;
7925
7926         if (!so->state) {
7927                 if ((error = dns_so_submit(so, Q, host)))
7928                         goto error;
7929         }
7930
7931         if ((error = dns_so_check(so)))
7932                 goto error;
7933
7934         if (!(A = dns_so_fetch(so, &error)))
7935                 goto error;
7936
7937         dns_so_reset(so);
7938
7939         return A;
7940 error:
7941         *error_ = error;
7942
7943         return 0;
7944 } /* dns_so_query() */
7945
7946
7947 time_t dns_so_elapsed(struct dns_socket *so) {
7948         return dns_elapsed(&so->elapsed);
7949 } /* dns_so_elapsed() */
7950
7951
7952 void dns_so_clear(struct dns_socket *so) {
7953         dns_so_closefds(so, DNS_SO_CLOSE_OLD);
7954 } /* dns_so_clear() */
7955
7956
7957 static int dns_so_events2(struct dns_socket *so, enum dns_events type) {
7958         int events = 0;
7959
7960         switch (so->state) {
7961         case DNS_SO_UDP_CONN:
7962         case DNS_SO_UDP_SEND:
7963                 events |= DNS_POLLOUT;
7964
7965                 break;
7966         case DNS_SO_UDP_RECV:
7967                 events |= DNS_POLLIN;
7968
7969                 break;
7970         case DNS_SO_TCP_CONN:
7971         case DNS_SO_TCP_SEND:
7972                 events |= DNS_POLLOUT;
7973
7974                 break;
7975         case DNS_SO_TCP_RECV:
7976                 events |= DNS_POLLIN;
7977
7978                 break;
7979         } /* switch() */
7980
7981         switch (type) {
7982         case DNS_LIBEVENT:
7983                 return DNS_POLL2EV(events);
7984         default:
7985                 return events;
7986         } /* switch() */
7987 } /* dns_so_events2() */
7988
7989
7990 int dns_so_events(struct dns_socket *so) {
7991         return dns_so_events2(so, so->opts.events);
7992 } /* dns_so_events() */
7993
7994
7995 int dns_so_pollfd(struct dns_socket *so) {
7996         switch (so->state) {
7997         case DNS_SO_UDP_CONN:
7998         case DNS_SO_UDP_SEND:
7999         case DNS_SO_UDP_RECV:
8000                 return so->udp;
8001         case DNS_SO_TCP_CONN:
8002         case DNS_SO_TCP_SEND:
8003         case DNS_SO_TCP_RECV:
8004                 return so->tcp;
8005         } /* switch() */
8006
8007         return -1;
8008 } /* dns_so_pollfd() */
8009
8010
8011 int dns_so_poll(struct dns_socket *so, int timeout) {
8012         return dns_poll(dns_so_pollfd(so), dns_so_events2(so, DNS_SYSPOLL), timeout);
8013 } /* dns_so_poll() */
8014
8015
8016 const struct dns_stat *dns_so_stat(struct dns_socket *so) {
8017         return &so->stat;
8018 } /* dns_so_stat() */
8019
8020
8021 struct dns_trace *dns_so_trace(struct dns_socket *so) {
8022         return so->trace;
8023 } /* dns_so_trace() */
8024
8025
8026 void dns_so_settrace(struct dns_socket *so, struct dns_trace *trace) {
8027         struct dns_trace *otrace = so->trace;
8028         so->trace = dns_trace_acquire_p(trace);
8029         dns_trace_close(otrace);
8030 } /* dns_so_settrace() */
8031
8032
8033 /*
8034  * R E S O L V E R  R O U T I N E S
8035  *
8036  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8037
8038 enum dns_res_state {
8039         DNS_R_INIT,
8040         DNS_R_GLUE,
8041         DNS_R_SWITCH,           /* (B)IND, (F)ILE, (C)ACHE */
8042
8043         DNS_R_FILE,             /* Lookup in local hosts database */
8044
8045         DNS_R_CACHE,            /* Lookup in application cache */
8046         DNS_R_SUBMIT,
8047         DNS_R_CHECK,
8048         DNS_R_FETCH,
8049
8050         DNS_R_BIND,             /* Lookup in the network */
8051         DNS_R_SEARCH,
8052         DNS_R_HINTS,
8053         DNS_R_ITERATE,
8054         DNS_R_FOREACH_NS,
8055         DNS_R_RESOLV0_NS,       /* Prologue: Setup next frame and recurse */
8056         DNS_R_RESOLV1_NS,       /* Epilog: Inspect answer */
8057         DNS_R_FOREACH_A,
8058         DNS_R_QUERY_A,
8059         DNS_R_CNAME0_A,
8060         DNS_R_CNAME1_A,
8061
8062         DNS_R_FINISH,
8063         DNS_R_SMART0_A,
8064         DNS_R_SMART1_A,
8065         DNS_R_DONE,
8066         DNS_R_SERVFAIL,
8067 }; /* enum dns_res_state */
8068
8069
8070 #define DNS_R_MAXDEPTH  8
8071 #define DNS_R_ENDFRAME  (DNS_R_MAXDEPTH - 1)
8072
8073 struct dns_resolver {
8074         struct dns_socket so;
8075
8076         struct dns_resolv_conf *resconf;
8077         struct dns_hosts *hosts;
8078         struct dns_hints *hints;
8079         struct dns_cache *cache;
8080         struct dns_trace *trace;
8081
8082         dns_atomic_t refcount;
8083
8084         /* Reset zeroes everything below here. */
8085
8086         char qname[DNS_D_MAXNAME + 1];
8087         size_t qlen;
8088
8089         enum dns_type qtype;
8090         enum dns_class qclass;
8091
8092         struct dns_clock elapsed;
8093
8094         dns_resconf_i_t search;
8095
8096         struct dns_rr_i smart;
8097
8098         struct dns_packet *nodata; /* answer if nothing better */
8099
8100         unsigned sp;
8101
8102         struct dns_res_frame {
8103                 enum dns_res_state state;
8104
8105                 int error;
8106                 int which;      /* (B)IND, (F)ILE; index into resconf->lookup */
8107                 int qflags;
8108
8109                 unsigned attempts;
8110
8111                 struct dns_packet *query, *answer, *hints;
8112
8113                 struct dns_rr_i hints_i, hints_j;
8114                 struct dns_rr hints_ns, ans_cname;
8115         } stack[DNS_R_MAXDEPTH];
8116 }; /* struct dns_resolver */
8117
8118
8119 static int dns_res_tcp2type(int tcp) {
8120         switch (tcp) {
8121         case DNS_RESCONF_TCP_ONLY:
8122         case DNS_RESCONF_TCP_SOCKS:
8123                 return SOCK_STREAM;
8124         case DNS_RESCONF_TCP_DISABLE:
8125                 return SOCK_DGRAM;
8126         default:
8127                 return 0;
8128         }
8129 } /* dns_res_tcp2type() */
8130
8131 struct dns_resolver *dns_res_open(struct dns_resolv_conf *resconf, struct dns_hosts *hosts, struct dns_hints *hints, struct dns_cache *cache, const struct dns_options *opts, int *_error) {
8132         static const struct dns_resolver R_initializer
8133                 = { .refcount = 1, };
8134         struct dns_resolver *R  = 0;
8135         int type, error;
8136
8137         /*
8138          * Grab ref count early because the caller may have passed us a mortal
8139          * reference, and we want to do the right thing if we return early
8140          * from an error.
8141          */
8142         if (resconf)
8143                 dns_resconf_acquire(resconf);
8144         if (hosts)
8145                 dns_hosts_acquire(hosts);
8146         if (hints)
8147                 dns_hints_acquire(hints);
8148         if (cache)
8149                 dns_cache_acquire(cache);
8150
8151         /*
8152          * Don't try to load it ourselves because a NULL object might be an
8153          * error from, say, dns_resconf_root(), and loading
8154          * dns_resconf_local() by default would create undesirable surpises.
8155          */
8156         if (!resconf || !hosts || !hints) {
8157                 if (!*_error)
8158                         *_error = EINVAL;
8159                 goto _error;
8160         }
8161
8162         if (!(R = malloc(sizeof *R)))
8163                 goto syerr;
8164
8165         *R      = R_initializer;
8166         type    = dns_res_tcp2type(resconf->options.tcp);
8167
8168         if (!dns_so_init(&R->so, (struct sockaddr *)&resconf->iface, type, opts, &error))
8169                 goto error;
8170
8171         R->resconf      = resconf;
8172         R->hosts        = hosts;
8173         R->hints        = hints;
8174         R->cache        = cache;
8175
8176         return R;
8177 syerr:
8178         error   = dns_syerr();
8179 error:
8180         *_error = error;
8181 _error:
8182         dns_res_close(R);
8183
8184         dns_resconf_close(resconf);
8185         dns_hosts_close(hosts);
8186         dns_hints_close(hints);
8187         dns_cache_close(cache);
8188
8189         return 0;
8190 } /* dns_res_open() */
8191
8192
8193 struct dns_resolver *dns_res_stub(const struct dns_options *opts, int *error) {
8194         struct dns_resolv_conf *resconf = 0;
8195         struct dns_hosts *hosts         = 0;
8196         struct dns_hints *hints         = 0;
8197         struct dns_resolver *res        = 0;
8198
8199         if (!(resconf = dns_resconf_local(error)))
8200                 goto epilog;
8201
8202         if (!(hosts = dns_hosts_local(error)))
8203                 goto epilog;
8204
8205         if (!(hints = dns_hints_local(resconf, error)))
8206                 goto epilog;
8207
8208         if (!(res = dns_res_open(resconf, hosts, hints, NULL, opts, error)))
8209                 goto epilog;
8210
8211 epilog:
8212         dns_resconf_close(resconf);
8213         dns_hosts_close(hosts);
8214         dns_hints_close(hints);
8215
8216         return res;
8217 } /* dns_res_stub() */
8218
8219
8220 static void dns_res_frame_destroy(struct dns_resolver *R, struct dns_res_frame *frame) {
8221         (void)R;
8222
8223         dns_p_setptr(&frame->query, NULL);
8224         dns_p_setptr(&frame->answer, NULL);
8225         dns_p_setptr(&frame->hints, NULL);
8226 } /* dns_res_frame_destroy() */
8227
8228
8229 static void dns_res_frame_init(struct dns_resolver *R, struct dns_res_frame *frame) {
8230         memset(frame, '\0', sizeof *frame);
8231
8232         /*
8233          * NB: Can be invoked from dns_res_open, before R->resconf has been
8234          * initialized.
8235          */
8236         if (R->resconf) {
8237                 if (!R->resconf->options.recurse)
8238                         frame->qflags |= DNS_Q_RD;
8239                 if (R->resconf->options.edns0)
8240                         frame->qflags |= DNS_Q_EDNS0;
8241         }
8242 } /* dns_res_frame_init() */
8243
8244
8245 static void dns_res_frame_reset(struct dns_resolver *R, struct dns_res_frame *frame) {
8246         dns_res_frame_destroy(R, frame);
8247         dns_res_frame_init(R, frame);
8248 } /* dns_res_frame_reset() */
8249
8250
8251 static dns_error_t dns_res_frame_prepare(struct dns_resolver *R, struct dns_res_frame *F, const char *qname, enum dns_type qtype, enum dns_class qclass) {
8252         struct dns_packet *P = NULL;
8253
8254         if (!(F < endof(R->stack)))
8255                 return DNS_EUNKNOWN;
8256
8257         dns_p_movptr(&P, &F->query);
8258         dns_res_frame_reset(R, F);
8259         dns_p_movptr(&F->query, &P);
8260
8261         return dns_q_make(&F->query, qname, qtype, qclass, F->qflags);
8262 } /* dns_res_frame_prepare() */
8263
8264
8265 void dns_res_reset(struct dns_resolver *R) {
8266         unsigned i;
8267
8268         dns_so_reset(&R->so);
8269         dns_p_setptr(&R->nodata, NULL);
8270
8271         for (i = 0; i < lengthof(R->stack); i++)
8272                 dns_res_frame_destroy(R, &R->stack[i]);
8273
8274         memset(&R->qname, '\0', sizeof *R - offsetof(struct dns_resolver, qname));
8275
8276         for (i = 0; i < lengthof(R->stack); i++)
8277                 dns_res_frame_init(R, &R->stack[i]);
8278 } /* dns_res_reset() */
8279
8280
8281 void dns_res_close(struct dns_resolver *R) {
8282         if (!R || 1 < dns_res_release(R))
8283                 return;
8284
8285         dns_res_reset(R);
8286
8287         dns_so_destroy(&R->so);
8288
8289         dns_hints_close(R->hints);
8290         dns_hosts_close(R->hosts);
8291         dns_resconf_close(R->resconf);
8292         dns_cache_close(R->cache);
8293         dns_trace_close(R->trace);
8294
8295         free(R);
8296 } /* dns_res_close() */
8297
8298
8299 dns_refcount_t dns_res_acquire(struct dns_resolver *R) {
8300         return dns_atomic_fetch_add(&R->refcount);
8301 } /* dns_res_acquire() */
8302
8303
8304 dns_refcount_t dns_res_release(struct dns_resolver *R) {
8305         return dns_atomic_fetch_sub(&R->refcount);
8306 } /* dns_res_release() */
8307
8308
8309 struct dns_resolver *dns_res_mortal(struct dns_resolver *res) {
8310         if (res)
8311                 dns_res_release(res);
8312         return res;
8313 } /* dns_res_mortal() */
8314
8315
8316 static struct dns_packet *dns_res_merge(struct dns_packet *P0, struct dns_packet *P1, int *error_) {
8317         size_t bufsiz   = P0->end + P1->end;
8318         struct dns_packet *P[3] = { P0, P1, 0 };
8319         struct dns_rr rr[3];
8320         int error, copy, i;
8321         enum dns_section section;
8322
8323 retry:
8324         if (!(P[2] = dns_p_make(bufsiz, &error)))
8325                 goto error;
8326
8327         dns_rr_foreach(&rr[0], P[0], .section = DNS_S_QD) {
8328                 if ((error = dns_rr_copy(P[2], &rr[0], P[0])))
8329                         goto error;
8330         }
8331
8332         for (section = DNS_S_AN; (DNS_S_ALL & section); section <<= 1) {
8333                 for (i = 0; i < 2; i++) {
8334                         dns_rr_foreach(&rr[i], P[i], .section = section) {
8335                                 copy    = 1;
8336
8337                                 dns_rr_foreach(&rr[2], P[2], .type = rr[i].type, .section = (DNS_S_ALL & ~DNS_S_QD)) {
8338                                         if (0 == dns_rr_cmp(&rr[i], P[i], &rr[2], P[2])) {
8339                                                 copy    = 0;
8340
8341                                                 break;
8342                                         }
8343                                 }
8344
8345                                 if (copy && (error = dns_rr_copy(P[2], &rr[i], P[i]))) {
8346                                         if (error == DNS_ENOBUFS && bufsiz < 65535) {
8347                                                 dns_p_setptr(&P[2], NULL);
8348
8349                                                 bufsiz  = DNS_PP_MAX(65535, bufsiz * 2);
8350
8351                                                 goto retry;
8352                                         }
8353
8354                                         goto error;
8355                                 }
8356                         } /* foreach(rr) */
8357                 } /* foreach(packet) */
8358         } /* foreach(section) */
8359
8360         return P[2];
8361 error:
8362         *error_ = error;
8363
8364         dns_p_free(P[2]);
8365
8366         return 0;
8367 } /* dns_res_merge() */
8368
8369
8370 static struct dns_packet *dns_res_glue(struct dns_resolver *R, struct dns_packet *Q) {
8371         struct dns_packet *P    = dns_p_new(512);
8372         char qname[DNS_D_MAXNAME + 1];
8373         size_t qlen;
8374         enum dns_type qtype;
8375         struct dns_rr rr;
8376         unsigned sp;
8377         int error;
8378
8379         if (!(qlen = dns_d_expand(qname, sizeof qname, 12, Q, &error))
8380         ||  qlen >= sizeof qname)
8381                 return 0;
8382
8383         if (!(qtype = dns_rr_type(12, Q)))
8384                 return 0;
8385
8386         if ((error = dns_p_push(P, DNS_S_QD, qname, strlen(qname), qtype, DNS_C_IN, 0, 0)))
8387                 return 0;
8388
8389         for (sp = 0; sp <= R->sp; sp++) {
8390                 if (!R->stack[sp].answer)
8391                         continue;
8392
8393                 dns_rr_foreach(&rr, R->stack[sp].answer, .name = qname, .type = qtype, .section = (DNS_S_ALL & ~DNS_S_QD)) {
8394                         rr.section      = DNS_S_AN;
8395
8396                         if ((error = dns_rr_copy(P, &rr, R->stack[sp].answer)))
8397                                 return 0;
8398                 }
8399         }
8400
8401         if (dns_p_count(P, DNS_S_AN) > 0)
8402                 goto copy;
8403
8404         /* Otherwise, look for a CNAME */
8405         for (sp = 0; sp <= R->sp; sp++) {
8406                 if (!R->stack[sp].answer)
8407                         continue;
8408
8409                 dns_rr_foreach(&rr, R->stack[sp].answer, .name = qname, .type = DNS_T_CNAME, .section = (DNS_S_ALL & ~DNS_S_QD)) {
8410                         rr.section      = DNS_S_AN;
8411
8412                         if ((error = dns_rr_copy(P, &rr, R->stack[sp].answer)))
8413                                 return 0;
8414                 }
8415         }
8416
8417         if (!dns_p_count(P, DNS_S_AN))
8418                 return 0;
8419
8420 copy:
8421         return dns_p_copy(dns_p_make(P->end, &error), P);
8422 } /* dns_res_glue() */
8423
8424
8425 /*
8426  * Sort NS records by three criteria:
8427  *
8428  *      1) Whether glue is present.
8429  *      2) Whether glue record is original or of recursive lookup.
8430  *      3) Randomly shuffle records which share the above criteria.
8431  *
8432  * NOTE: Assumes only NS records passed, AND ASSUMES no new NS records will
8433  *       be added during an iteration.
8434  *
8435  * FIXME: Only groks A glue, not AAAA glue.
8436  */
8437 static int dns_res_nameserv_cmp(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) {
8438         _Bool glued[2] = { 0 };
8439         struct dns_rr x = { 0 }, y = { 0 };
8440         struct dns_ns ns;
8441         int cmp, error;
8442
8443         if (!(error = dns_ns_parse(&ns, a, P)))
8444                 glued[0] = !!dns_rr_grep(&x, 1, dns_rr_i_new(P, .section = (DNS_S_ALL & ~DNS_S_QD), .name = ns.host, .type = DNS_T_A), P, &error);
8445
8446         if (!(error = dns_ns_parse(&ns, b, P)))
8447                 glued[1] = !!dns_rr_grep(&y, 1, dns_rr_i_new(P, .section = (DNS_S_ALL & ~DNS_S_QD), .name = ns.host, .type = DNS_T_A), P, &error);
8448
8449         if ((cmp = glued[1] - glued[0])) {
8450                 return cmp;
8451         } else if ((cmp = (dns_rr_offset(&y) < i->args[0]) - (dns_rr_offset(&x) < i->args[0]))) {
8452                 return cmp;
8453         } else {
8454                 return dns_rr_i_shuffle(a, b, i, P);
8455         }
8456 } /* dns_res_nameserv_cmp() */
8457
8458
8459 #define dgoto(sp, i)    \
8460         do { R->stack[(sp)].state = (i); goto exec; } while (0)
8461
8462 static int dns_res_exec(struct dns_resolver *R) {
8463         struct dns_res_frame *F;
8464         struct dns_packet *P;
8465         union {
8466                 char host[DNS_D_MAXNAME + 1];
8467                 char name[DNS_D_MAXNAME + 1];
8468                 struct dns_ns ns;
8469                 struct dns_cname cname;
8470         } u;
8471         size_t len;
8472         struct dns_rr rr;
8473         int error;
8474
8475 exec:
8476
8477         F       = &R->stack[R->sp];
8478
8479         switch (F->state) {
8480         case DNS_R_INIT:
8481                 F->state++;
8482         case DNS_R_GLUE:
8483                 if (R->sp == 0)
8484                         dgoto(R->sp, DNS_R_SWITCH);
8485
8486                 if (!F->query)
8487                         goto noquery;
8488
8489                 if (!(F->answer = dns_res_glue(R, F->query)))
8490                         dgoto(R->sp, DNS_R_SWITCH);
8491
8492                 if (!(len = dns_d_expand(u.name, sizeof u.name, 12, F->query, &error)))
8493                         goto error;
8494                 else if (len >= sizeof u.name)
8495                         goto toolong;
8496
8497                 dns_rr_foreach(&rr, F->answer, .name = u.name, .type = dns_rr_type(12, F->query), .section = DNS_S_AN) {
8498                         dgoto(R->sp, DNS_R_FINISH);
8499                 }
8500
8501                 dns_rr_foreach(&rr, F->answer, .name = u.name, .type = DNS_T_CNAME, .section = DNS_S_AN) {
8502                         F->ans_cname    = rr;
8503
8504                         dgoto(R->sp, DNS_R_CNAME0_A);
8505                 }
8506
8507                 F->state++;
8508         case DNS_R_SWITCH:
8509                 while (F->which < (int)sizeof R->resconf->lookup && R->resconf->lookup[F->which]) {
8510                         switch (R->resconf->lookup[F->which++]) {
8511                         case 'b': case 'B':
8512                                 dgoto(R->sp, DNS_R_BIND);
8513                         case 'f': case 'F':
8514                                 dgoto(R->sp, DNS_R_FILE);
8515                         case 'c': case 'C':
8516                                 if (R->cache)
8517                                         dgoto(R->sp, DNS_R_CACHE);
8518
8519                                 break;
8520                         default:
8521                                 break;
8522                         }
8523                 }
8524
8525                 /*
8526                  * FIXME: Examine more closely whether our logic is correct
8527                  * and DNS_R_SERVFAIL is the correct default response.
8528                  *
8529                  * Case 1: We got here because we never got an answer on the
8530                  *   wire. All queries timed-out and we reached maximum
8531                  *   attempts count. See DNS_R_FOREACH_NS. In that case
8532                  *   DNS_R_SERVFAIL is the correct state, unless we want to
8533                  *   return DNS_ETIMEDOUT.
8534                  *
8535                  * Case 2: We were a stub resolver and got an unsatisfactory
8536                  *   answer (empty ANSWER section) which caused us to jump
8537                  *   back to DNS_R_SEARCH and ultimately to DNS_R_SWITCH. We
8538                  *   return the answer returned from the wire, which we
8539                  *   stashed in R->nodata.
8540                  *
8541                  * Case 3: We reached maximum attempts count as in case #1,
8542                  *   but never got an authoritative response which caused us
8543                  *   to short-circuit. See end of DNS_R_QUERY_A case. We
8544                  *   should probably prepare R->nodata as in case #2.
8545                  */
8546                 if (R->sp == 0 && R->nodata) { /* XXX: can we just return nodata regardless? */
8547                         dns_p_movptr(&F->answer, &R->nodata);
8548                         dgoto(R->sp, DNS_R_FINISH);
8549                 }
8550
8551                 dgoto(R->sp, DNS_R_SERVFAIL);
8552         case DNS_R_FILE:
8553                 if (R->sp > 0) {
8554                         if (!dns_p_setptr(&F->answer, dns_hosts_query(R->hosts, F->query, &error)))
8555                                 goto error;
8556
8557                         if (dns_p_count(F->answer, DNS_S_AN) > 0)
8558                                 dgoto(R->sp, DNS_R_FINISH);
8559
8560                         dns_p_setptr(&F->answer, NULL);
8561                 } else {
8562                         R->search = 0;
8563
8564                         while ((len = dns_resconf_search(u.name, sizeof u.name, R->qname, R->qlen, R->resconf, &R->search))) {
8565                                 if ((error = dns_q_make2(&F->query, u.name, len, R->qtype, R->qclass, F->qflags)))
8566                                         goto error;
8567
8568                                 if (!dns_p_setptr(&F->answer, dns_hosts_query(R->hosts, F->query, &error)))
8569                                         goto error;
8570
8571                                 if (dns_p_count(F->answer, DNS_S_AN) > 0)
8572                                         dgoto(R->sp, DNS_R_FINISH);
8573
8574                                 dns_p_setptr(&F->answer, NULL);
8575                         }
8576                 }
8577
8578                 dgoto(R->sp, DNS_R_SWITCH);
8579         case DNS_R_CACHE:
8580                 error = 0;
8581
8582                 if (!F->query && (error = dns_q_make(&F->query, R->qname, R->qtype, R->qclass, F->qflags)))
8583                         goto error;
8584
8585                 if (dns_p_setptr(&F->answer, R->cache->query(F->query, R->cache, &error))) {
8586                         if (dns_p_count(F->answer, DNS_S_AN) > 0)
8587                                 dgoto(R->sp, DNS_R_FINISH);
8588
8589                         dns_p_setptr(&F->answer, NULL);
8590
8591                         dgoto(R->sp, DNS_R_SWITCH);
8592                 } else if (error)
8593                         goto error;
8594
8595                 F->state++;
8596         case DNS_R_SUBMIT:
8597                 if ((error = R->cache->submit(F->query, R->cache)))
8598                         goto error;
8599
8600                 F->state++;
8601         case DNS_R_CHECK:
8602                 if ((error = R->cache->check(R->cache)))
8603                         goto error;
8604
8605                 F->state++;
8606         case DNS_R_FETCH:
8607                 error = 0;
8608
8609                 if (dns_p_setptr(&F->answer, R->cache->fetch(R->cache, &error))) {
8610                         if (dns_p_count(F->answer, DNS_S_AN) > 0)
8611                                 dgoto(R->sp, DNS_R_FINISH);
8612
8613                         dns_p_setptr(&F->answer, NULL);
8614
8615                         dgoto(R->sp, DNS_R_SWITCH);
8616                 } else if (error)
8617                         goto error;
8618
8619                 dgoto(R->sp, DNS_R_SWITCH);
8620         case DNS_R_BIND:
8621                 if (R->sp > 0) {
8622                         if (!F->query)
8623                                 goto noquery;
8624
8625                         dgoto(R->sp, DNS_R_HINTS);
8626                 }
8627
8628                 R->search = 0;
8629
8630                 F->state++;
8631         case DNS_R_SEARCH:
8632                 /*
8633                  * XXX: We probably should only apply the domain search
8634                  * algorithm if R->sp == 0.
8635                  */
8636                 if (!(len = dns_resconf_search(u.name, sizeof u.name, R->qname, R->qlen, R->resconf, &R->search)))
8637                         dgoto(R->sp, DNS_R_SWITCH);
8638
8639                 if ((error = dns_q_make2(&F->query, u.name, len, R->qtype, R->qclass, F->qflags)))
8640                         goto error;
8641
8642                 F->state++;
8643         case DNS_R_HINTS:
8644                 if (!dns_p_setptr(&F->hints, dns_hints_query(R->hints, F->query, &error)))
8645                         goto error;
8646
8647                 F->state++;
8648         case DNS_R_ITERATE:
8649                 dns_rr_i_init(&F->hints_i, F->hints);
8650
8651                 F->hints_i.section      = DNS_S_AUTHORITY;
8652                 F->hints_i.type         = DNS_T_NS;
8653                 F->hints_i.sort         = &dns_res_nameserv_cmp;
8654                 F->hints_i.args[0]      = F->hints->end;
8655
8656                 F->state++;
8657         case DNS_R_FOREACH_NS:
8658                 dns_rr_i_save(&F->hints_i);
8659
8660                 /* Load our next nameserver host. */
8661                 if (!dns_rr_grep(&F->hints_ns, 1, &F->hints_i, F->hints, &error)) {
8662                         if (++F->attempts < R->resconf->options.attempts)
8663                                 dgoto(R->sp, DNS_R_ITERATE);
8664
8665                         dgoto(R->sp, DNS_R_SWITCH);
8666                 }
8667
8668                 dns_rr_i_init(&F->hints_j, F->hints);
8669
8670                 /* Assume there are glue records */
8671                 dgoto(R->sp, DNS_R_FOREACH_A);
8672         case DNS_R_RESOLV0_NS:
8673                 /* Have we reached our max depth? */
8674                 if (&F[1] >= endof(R->stack))
8675                         dgoto(R->sp, DNS_R_FOREACH_NS);
8676
8677                 if ((error = dns_ns_parse(&u.ns, &F->hints_ns, F->hints)))
8678                         goto error;
8679                 if ((error = dns_res_frame_prepare(R, &F[1], u.ns.host, DNS_T_A, DNS_C_IN)))
8680                         goto error;
8681
8682                 F->state++;
8683
8684                 dgoto(++R->sp, DNS_R_INIT);
8685         case DNS_R_RESOLV1_NS:
8686                 if (!(len = dns_d_expand(u.host, sizeof u.host, 12, F[1].query, &error)))
8687                         goto error;
8688                 else if (len >= sizeof u.host)
8689                         goto toolong;
8690
8691                 dns_rr_foreach(&rr, F[1].answer, .name = u.host, .type = DNS_T_A, .section = (DNS_S_ALL & ~DNS_S_QD)) {
8692                         rr.section      = DNS_S_AR;
8693
8694                         if ((error = dns_rr_copy(F->hints, &rr, F[1].answer)))
8695                                 goto error;
8696
8697                         dns_rr_i_rewind(&F->hints_i);   /* Now there's glue. */
8698                 }
8699
8700                 dgoto(R->sp, DNS_R_FOREACH_NS);
8701         case DNS_R_FOREACH_A: {
8702                 struct dns_a a;
8703                 struct sockaddr_in sin;
8704
8705                 /*
8706                  * NOTE: Iterator initialized in DNS_R_FOREACH_NS because
8707                  * this state is re-entrant, but we need to reset
8708                  * .name to a valid pointer each time.
8709                  */
8710                 if ((error = dns_ns_parse(&u.ns, &F->hints_ns, F->hints)))
8711                         goto error;
8712
8713                 F->hints_j.name         = u.ns.host;
8714                 F->hints_j.type         = DNS_T_A;
8715                 F->hints_j.section      = DNS_S_ALL & ~DNS_S_QD;
8716
8717                 if (!dns_rr_grep(&rr, 1, &F->hints_j, F->hints, &error)) {
8718                         if (!dns_rr_i_count(&F->hints_j))
8719                                 dgoto(R->sp, DNS_R_RESOLV0_NS);
8720
8721                         dgoto(R->sp, DNS_R_FOREACH_NS);
8722                 }
8723
8724                 if ((error = dns_a_parse(&a, &rr, F->hints)))
8725                         goto error;
8726
8727                 memset(&sin, '\0', sizeof sin); /* NB: silence valgrind */
8728                 sin.sin_family  = AF_INET;
8729                 sin.sin_addr    = a.addr;
8730                 if (R->sp == 0)
8731                         sin.sin_port = dns_hints_port(R->hints, AF_INET, &sin.sin_addr);
8732                 else
8733                         sin.sin_port = htons(53);
8734
8735                 if (DNS_DEBUG) {
8736                         char addr[INET_ADDRSTRLEN + 1];
8737                         dns_a_print(addr, sizeof addr, &a);
8738                         dns_header(F->query)->qid = dns_so_mkqid(&R->so);
8739                         DNS_SHOW(F->query, "ASKING: %s/%s @ DEPTH: %u)", u.ns.host, addr, R->sp);
8740                 }
8741
8742                 dns_trace_setcname(R->trace, u.ns.host, (struct sockaddr *)&sin);
8743
8744                 if ((error = dns_so_submit(&R->so, F->query, (struct sockaddr *)&sin)))
8745                         goto error;
8746
8747                 F->state++;
8748         }
8749         case DNS_R_QUERY_A:
8750                 if (dns_so_elapsed(&R->so) >= dns_resconf_timeout(R->resconf))
8751                         dgoto(R->sp, DNS_R_FOREACH_A);
8752
8753                 if ((error = dns_so_check(&R->so)))
8754                         goto error;
8755
8756                 if (!dns_p_setptr(&F->answer, dns_so_fetch(&R->so, &error)))
8757                         goto error;
8758
8759                 if (DNS_DEBUG) {
8760                         DNS_SHOW(F->answer, "ANSWER @ DEPTH: %u)", R->sp);
8761                 }
8762
8763                 if (dns_p_rcode(F->answer) == DNS_RC_FORMERR ||
8764                     dns_p_rcode(F->answer) == DNS_RC_NOTIMP ||
8765                     dns_p_rcode(F->answer) == DNS_RC_BADVERS) {
8766                         /* Temporarily disable EDNS0 and try again. */
8767                         if (F->qflags & DNS_Q_EDNS0) {
8768                                 F->qflags &= ~DNS_Q_EDNS0;
8769                                 if ((error = dns_q_remake(&F->query, F->qflags)))
8770                                         goto error;
8771
8772                                 dgoto(R->sp, DNS_R_FOREACH_A);
8773                         }
8774                 }
8775
8776                 if ((error = dns_rr_parse(&rr, 12, F->query)))
8777                         goto error;
8778
8779                 if (!(len = dns_d_expand(u.name, sizeof u.name, rr.dn.p, F->query, &error)))
8780                         goto error;
8781                 else if (len >= sizeof u.name)
8782                         goto toolong;
8783
8784                 dns_rr_foreach(&rr, F->answer, .section = DNS_S_AN, .name = u.name, .type = rr.type) {
8785                         dgoto(R->sp, DNS_R_FINISH);     /* Found */
8786                 }
8787
8788                 dns_rr_foreach(&rr, F->answer, .section = DNS_S_AN, .name = u.name, .type = DNS_T_CNAME) {
8789                         F->ans_cname    = rr;
8790
8791                         dgoto(R->sp, DNS_R_CNAME0_A);
8792                 }
8793
8794                 /*
8795                  * XXX: The condition here should probably check whether
8796                  * R->sp == 0, because DNS_R_SEARCH runs regardless of
8797                  * options.recurse. See DNS_R_BIND.
8798                  */
8799                 if (!R->resconf->options.recurse) {
8800                         /* Make first answer our tentative answer */
8801                         if (!R->nodata)
8802                                 dns_p_movptr(&R->nodata, &F->answer);
8803
8804                         dgoto(R->sp, DNS_R_SEARCH);
8805                 }
8806
8807                 dns_rr_foreach(&rr, F->answer, .section = DNS_S_NS, .type = DNS_T_NS) {
8808                         dns_p_movptr(&F->hints, &F->answer);
8809
8810                         dgoto(R->sp, DNS_R_ITERATE);
8811                 }
8812
8813                 /* XXX: Should this go further up? */
8814                 if (dns_header(F->answer)->aa)
8815                         dgoto(R->sp, DNS_R_FINISH);
8816
8817                 /* XXX: Should we copy F->answer to R->nodata? */
8818
8819                 dgoto(R->sp, DNS_R_FOREACH_A);
8820         case DNS_R_CNAME0_A:
8821                 if (&F[1] >= endof(R->stack))
8822                         dgoto(R->sp, DNS_R_FINISH);
8823
8824                 if ((error = dns_cname_parse(&u.cname, &F->ans_cname, F->answer)))
8825                         goto error;
8826                 if ((error = dns_res_frame_prepare(R, &F[1], u.cname.host, dns_rr_type(12, F->query), DNS_C_IN)))
8827                         goto error;
8828
8829                 F->state++;
8830
8831                 dgoto(++R->sp, DNS_R_INIT);
8832         case DNS_R_CNAME1_A:
8833                 if (!(P = dns_res_merge(F->answer, F[1].answer, &error)))
8834                         goto error;
8835
8836                 dns_p_setptr(&F->answer, P);
8837
8838                 dgoto(R->sp, DNS_R_FINISH);
8839         case DNS_R_FINISH:
8840                 if (!F->answer)
8841                         goto noanswer;
8842
8843                 if (!R->resconf->options.smart || R->sp > 0)
8844                         dgoto(R->sp, DNS_R_DONE);
8845
8846                 R->smart.section        = DNS_S_AN;
8847                 R->smart.type           = R->qtype;
8848
8849                 dns_rr_i_init(&R->smart, F->answer);
8850
8851                 F->state++;
8852         case DNS_R_SMART0_A:
8853                 if (&F[1] >= endof(R->stack))
8854                         dgoto(R->sp, DNS_R_DONE);
8855
8856                 while (dns_rr_grep(&rr, 1, &R->smart, F->answer, &error)) {
8857                         union {
8858                                 struct dns_ns ns;
8859                                 struct dns_mx mx;
8860                                 struct dns_srv srv;
8861                         } rd;
8862                         const char *qname;
8863                         enum dns_type qtype;
8864                         enum dns_class qclass;
8865
8866                         switch (rr.type) {
8867                         case DNS_T_NS:
8868                                 if ((error = dns_ns_parse(&rd.ns, &rr, F->answer)))
8869                                         goto error;
8870
8871                                 qname   = rd.ns.host;
8872                                 qtype   = DNS_T_A;
8873                                 qclass  = DNS_C_IN;
8874
8875                                 break;
8876                         case DNS_T_MX:
8877                                 if ((error = dns_mx_parse(&rd.mx, &rr, F->answer)))
8878                                         goto error;
8879
8880                                 qname   = rd.mx.host;
8881                                 qtype   = DNS_T_A;
8882                                 qclass  = DNS_C_IN;
8883
8884                                 break;
8885                         case DNS_T_SRV:
8886                                 if ((error = dns_srv_parse(&rd.srv, &rr, F->answer)))
8887                                         goto error;
8888
8889                                 qname   = rd.srv.target;
8890                                 qtype   = DNS_T_A;
8891                                 qclass  = DNS_C_IN;
8892
8893                                 break;
8894                         default:
8895                                 continue;
8896                         } /* switch() */
8897
8898                         if ((error = dns_res_frame_prepare(R, &F[1], qname, qtype, qclass)))
8899                                 goto error;
8900
8901                         F->state++;
8902
8903                         dgoto(++R->sp, DNS_R_INIT);
8904                 } /* while() */
8905
8906                 /*
8907                  * NOTE: SMTP specification says to fallback to A record.
8908                  *
8909                  * XXX: Should we add a mock MX answer?
8910                  */
8911                 if (R->qtype == DNS_T_MX && R->smart.state.count == 0) {
8912                         if ((error = dns_res_frame_prepare(R, &F[1], R->qname, DNS_T_A, DNS_C_IN)))
8913                                 goto error;
8914
8915                         R->smart.state.count++;
8916                         F->state++;
8917
8918                         dgoto(++R->sp, DNS_R_INIT);
8919                 }
8920
8921                 dgoto(R->sp, DNS_R_DONE);
8922         case DNS_R_SMART1_A:
8923                 if (!F[1].answer)
8924                         goto noanswer;
8925
8926                 /*
8927                  * FIXME: For CNAME chains (which are typically illegal in
8928                  * this context), we should rewrite the record host name
8929                  * to the original smart qname. All the user cares about
8930                  * is locating that A/AAAA record.
8931                  */
8932                 dns_rr_foreach(&rr, F[1].answer, .section = DNS_S_AN, .type = DNS_T_A) {
8933                         rr.section      = DNS_S_AR;
8934
8935                         if (dns_rr_exists(&rr, F[1].answer, F->answer))
8936                                 continue;
8937
8938                         while ((error = dns_rr_copy(F->answer, &rr, F[1].answer))) {
8939                                 if (error != DNS_ENOBUFS)
8940                                         goto error;
8941                                 if ((error = dns_p_grow(&F->answer)))
8942                                         goto error;
8943                         }
8944                 }
8945
8946                 dgoto(R->sp, DNS_R_SMART0_A);
8947         case DNS_R_DONE:
8948                 if (!F->answer)
8949                         goto noanswer;
8950
8951                 if (R->sp > 0)
8952                         dgoto(--R->sp, F[-1].state);
8953
8954                 break;
8955         case DNS_R_SERVFAIL:
8956                 if (!dns_p_setptr(&F->answer, dns_p_make(DNS_P_QBUFSIZ, &error)))
8957                         goto error;
8958
8959                 dns_header(F->answer)->qr       = 1;
8960                 dns_header(F->answer)->rcode    = DNS_RC_SERVFAIL;
8961
8962                 if ((error = dns_p_push(F->answer, DNS_S_QD, R->qname, strlen(R->qname), R->qtype, R->qclass, 0, 0)))
8963                         goto error;
8964
8965                 dgoto(R->sp, DNS_R_DONE);
8966         default:
8967                 error   = EINVAL;
8968
8969                 goto error;
8970         } /* switch () */
8971
8972         return 0;
8973 noquery:
8974         error = DNS_ENOQUERY;
8975
8976         goto error;
8977 noanswer:
8978         error = DNS_ENOANSWER;
8979
8980         goto error;
8981 toolong:
8982         error = DNS_EILLEGAL;
8983
8984         /* FALL THROUGH */
8985 error:
8986         return error;
8987 } /* dns_res_exec() */
8988
8989 #undef goto
8990
8991
8992 void dns_res_clear(struct dns_resolver *R) {
8993         switch (R->stack[R->sp].state) {
8994         case DNS_R_CHECK:
8995                 R->cache->clear(R->cache);
8996                 break;
8997         default:
8998                 dns_so_clear(&R->so);
8999                 break;
9000         }
9001 } /* dns_res_clear() */
9002
9003
9004 static int dns_res_events2(struct dns_resolver *R, enum dns_events type) {
9005         int events;
9006
9007         switch (R->stack[R->sp].state) {
9008         case DNS_R_CHECK:
9009                 events = R->cache->events(R->cache);
9010
9011                 return (type == DNS_LIBEVENT)? DNS_POLL2EV(events) : events;
9012         default:
9013                 return dns_so_events2(&R->so, type);
9014         }
9015 } /* dns_res_events2() */
9016
9017
9018 int dns_res_events(struct dns_resolver *R) {
9019         return dns_res_events2(R, R->so.opts.events);
9020 } /* dns_res_events() */
9021
9022
9023 int dns_res_pollfd(struct dns_resolver *R) {
9024         switch (R->stack[R->sp].state) {
9025         case DNS_R_CHECK:
9026                 return R->cache->pollfd(R->cache);
9027         default:
9028                 return dns_so_pollfd(&R->so);
9029         }
9030 } /* dns_res_pollfd() */
9031
9032
9033 time_t dns_res_timeout(struct dns_resolver *R) {
9034         time_t elapsed;
9035
9036         switch (R->stack[R->sp].state) {
9037 #if 0
9038         case DNS_R_QUERY_AAAA:
9039 #endif
9040         case DNS_R_QUERY_A:
9041                 elapsed = dns_so_elapsed(&R->so);
9042
9043                 if (elapsed <= dns_resconf_timeout(R->resconf))
9044                         return R->resconf->options.timeout - elapsed;
9045
9046                 break;
9047         default:
9048                 break;
9049         } /* switch() */
9050
9051         /*
9052          * NOTE: We're not in a pollable state, or the user code hasn't
9053          * called dns_res_check properly. The calling code is probably
9054          * broken. Put them into a slow-burn pattern.
9055          */
9056         return 1;
9057 } /* dns_res_timeout() */
9058
9059
9060 time_t dns_res_elapsed(struct dns_resolver *R) {
9061         return dns_elapsed(&R->elapsed);
9062 } /* dns_res_elapsed() */
9063
9064
9065 int dns_res_poll(struct dns_resolver *R, int timeout) {
9066         return dns_poll(dns_res_pollfd(R), dns_res_events2(R, DNS_SYSPOLL), timeout);
9067 } /* dns_res_poll() */
9068
9069
9070 int dns_res_submit2(struct dns_resolver *R, const char *qname, size_t qlen, enum dns_type qtype, enum dns_class qclass) {
9071         dns_res_reset(R);
9072
9073         /* Don't anchor; that can conflict with searchlist generation. */
9074         dns_d_init(R->qname, sizeof R->qname, qname, (R->qlen = qlen), 0);
9075
9076         R->qtype        = qtype;
9077         R->qclass       = qclass;
9078
9079         dns_begin(&R->elapsed);
9080
9081         dns_trace_res_submit(R->trace, R->qname, R->qtype, R->qclass, 0);
9082
9083         return 0;
9084 } /* dns_res_submit2() */
9085
9086
9087 int dns_res_submit(struct dns_resolver *R, const char *qname, enum dns_type qtype, enum dns_class qclass) {
9088         return dns_res_submit2(R, qname, strlen(qname), qtype, qclass);
9089 } /* dns_res_submit() */
9090
9091
9092 int dns_res_check(struct dns_resolver *R) {
9093         int error;
9094
9095         if (R->stack[0].state != DNS_R_DONE) {
9096                 if ((error = dns_res_exec(R)))
9097                         return error;
9098         }
9099
9100         return 0;
9101 } /* dns_res_check() */
9102
9103
9104 struct dns_packet *dns_res_fetch(struct dns_resolver *R, int *_error) {
9105         struct dns_packet *P = NULL;
9106         int error;
9107
9108         if (R->stack[0].state != DNS_R_DONE) {
9109                 error = DNS_EUNKNOWN;
9110                 goto error;
9111         }
9112
9113         if (!dns_p_movptr(&P, &R->stack[0].answer)) {
9114                 error = DNS_EFETCHED;
9115                 goto error;
9116         }
9117
9118         dns_trace_res_fetch(R->trace, P, 0);
9119
9120         return P;
9121 error:
9122         *_error = error;
9123         dns_trace_res_fetch(R->trace, NULL, error);
9124         return NULL;
9125 } /* dns_res_fetch() */
9126
9127
9128 static struct dns_packet *dns_res_fetch_and_study(struct dns_resolver *R, int *_error) {
9129         struct dns_packet *P = NULL;
9130         int error;
9131
9132         if (!(P = dns_res_fetch(R, &error)))
9133                 goto error;
9134         if ((error = dns_p_study(P)))
9135                 goto error;
9136
9137         return P;
9138 error:
9139         *_error = error;
9140
9141         dns_p_free(P);
9142
9143         return NULL;
9144 } /* dns_res_fetch_and_study() */
9145
9146
9147 struct dns_packet *dns_res_query(struct dns_resolver *res, const char *qname, enum dns_type qtype, enum dns_class qclass, int timeout, int *error_) {
9148         int error;
9149
9150         if ((error = dns_res_submit(res, qname, qtype, qclass)))
9151                 goto error;
9152
9153         while ((error = dns_res_check(res))) {
9154                 if (dns_res_elapsed(res) > timeout)
9155                         error = DNS_ETIMEDOUT;
9156
9157                 if (error != DNS_EAGAIN)
9158                         goto error;
9159
9160                 if ((error = dns_res_poll(res, 1)))
9161                         goto error;
9162         }
9163
9164         return dns_res_fetch(res, error_);
9165 error:
9166         *error_ = error;
9167
9168         return 0;
9169 } /* dns_res_query() */
9170
9171
9172 const struct dns_stat *dns_res_stat(struct dns_resolver *res) {
9173         return dns_so_stat(&res->so);
9174 } /* dns_res_stat() */
9175
9176
9177 void dns_res_sethints(struct dns_resolver *res, struct dns_hints *hints) {
9178         dns_hints_acquire(hints); /* acquire first in case same hints object */
9179         dns_hints_close(res->hints);
9180         res->hints = hints;
9181 } /* dns_res_sethints() */
9182
9183
9184 struct dns_trace *dns_res_trace(struct dns_resolver *res) {
9185         return res->trace;
9186 } /* dns_res_trace() */
9187
9188
9189 void dns_res_settrace(struct dns_resolver *res, struct dns_trace *trace) {
9190         struct dns_trace *otrace = res->trace;
9191         res->trace = dns_trace_acquire_p(trace);
9192         dns_trace_close(otrace);
9193         dns_so_settrace(&res->so, trace);
9194 } /* dns_res_settrace() */
9195
9196
9197 /*
9198  * A D D R I N F O  R O U T I N E S
9199  *
9200  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9201
9202 struct dns_addrinfo {
9203         struct addrinfo hints;
9204         struct dns_resolver *res;
9205         struct dns_trace *trace;
9206
9207         char qname[DNS_D_MAXNAME + 1];
9208         enum dns_type qtype;
9209         unsigned short qport, port;
9210
9211         struct {
9212                 unsigned long todo;
9213                 int state;
9214                 int atype;
9215                 enum dns_type qtype;
9216         } af;
9217
9218         struct dns_packet *answer;
9219         struct dns_packet *glue;
9220
9221         struct dns_rr_i i, g;
9222         struct dns_rr rr;
9223
9224         char cname[DNS_D_MAXNAME + 1];
9225         char i_cname[DNS_D_MAXNAME + 1], g_cname[DNS_D_MAXNAME + 1];
9226
9227         int g_depth;
9228
9229         int state;
9230         int found;
9231
9232         struct dns_stat st;
9233 }; /* struct dns_addrinfo */
9234
9235
9236 #define DNS_AI_AFMAX 32
9237 #define DNS_AI_AF2INDEX(af) (1UL << ((af) - 1))
9238
9239 static inline unsigned long dns_ai_af2index(int af) {
9240         dns_static_assert(dns_same_type(unsigned long, DNS_AI_AF2INDEX(1), 1), "internal type mismatch");
9241         dns_static_assert(dns_same_type(unsigned long, ((struct dns_addrinfo *)0)->af.todo, 1), "internal type mismatch");
9242
9243         return (af > 0 && af <= DNS_AI_AFMAX)? DNS_AI_AF2INDEX(af) : 0;
9244 }
9245
9246 static int dns_ai_setaf(struct dns_addrinfo *ai, int af, int qtype) {
9247         ai->af.atype = af;
9248         ai->af.qtype = qtype;
9249
9250         ai->af.todo &= ~dns_ai_af2index(af);
9251
9252         return af;
9253 } /* dns_ai_setaf() */
9254
9255 #define DNS_SM_RESTORE \
9256         do { pc = 0xff & (ai->af.state >> 0); i = 0xff & (ai->af.state >> 8); } while (0)
9257 #define DNS_SM_SAVE \
9258         do { ai->af.state = ((0xff & pc) << 0) | ((0xff & i) << 8); } while (0)
9259
9260 static int dns_ai_nextaf(struct dns_addrinfo *ai) {
9261         int i, pc;
9262
9263         dns_static_assert(AF_UNSPEC == 0, "AF_UNSPEC constant not 0");
9264         dns_static_assert(AF_INET <= DNS_AI_AFMAX, "AF_INET constant too large");
9265         dns_static_assert(AF_INET6 <= DNS_AI_AFMAX, "AF_INET6 constant too large");
9266
9267         DNS_SM_ENTER;
9268
9269         if (ai->res) {
9270                 /*
9271                  * NB: On OpenBSD, at least, the types of entries resolved
9272                  * is the intersection of the /etc/resolv.conf families and
9273                  * the families permitted by the .ai_type hint. So if
9274                  * /etc/resolv.conf has "family inet4" and .ai_type
9275                  * is AF_INET6, then the address ::1 will return 0 entries
9276                  * even if AI_NUMERICHOST is specified in .ai_flags.
9277                  */
9278                 while (i < (int)lengthof(ai->res->resconf->family)) {
9279                         int af = ai->res->resconf->family[i++];
9280
9281                         if (af == AF_UNSPEC) {
9282                                 DNS_SM_EXIT;
9283                         } else if (af < 0 || af > DNS_AI_AFMAX) {
9284                                 continue;
9285                         } else if (!(DNS_AI_AF2INDEX(af) & ai->af.todo)) {
9286                                 continue;
9287                         } else if (af == AF_INET) {
9288                                 DNS_SM_YIELD(dns_ai_setaf(ai, AF_INET, DNS_T_A));
9289                         } else if (af == AF_INET6) {
9290                                 DNS_SM_YIELD(dns_ai_setaf(ai, AF_INET6, DNS_T_AAAA));
9291                         }
9292                 }
9293         } else {
9294                 /*
9295                  * NB: If we get here than AI_NUMERICFLAGS should be set and
9296                  * order shouldn't matter.
9297                  */
9298                 if (DNS_AI_AF2INDEX(AF_INET) & ai->af.todo)
9299                         DNS_SM_YIELD(dns_ai_setaf(ai, AF_INET, DNS_T_A));
9300                 if (DNS_AI_AF2INDEX(AF_INET6) & ai->af.todo)
9301                         DNS_SM_YIELD(dns_ai_setaf(ai, AF_INET6, DNS_T_AAAA));
9302         }
9303
9304         DNS_SM_LEAVE;
9305
9306         return dns_ai_setaf(ai, AF_UNSPEC, 0);
9307 } /* dns_ai_nextaf() */
9308
9309 #undef DNS_SM_RESTORE
9310 #undef DNS_SM_SAVE
9311
9312 static enum dns_type dns_ai_qtype(struct dns_addrinfo *ai) {
9313         return (ai->qtype)? ai->qtype : ai->af.qtype;
9314 } /* dns_ai_qtype() */
9315
9316 /* JW: This is not defined on mingw.  */
9317 #ifndef AI_NUMERICSERV
9318 #define AI_NUMERICSERV  0
9319 #endif
9320
9321 static dns_error_t dns_ai_parseport(unsigned short *port, const char *serv, const struct addrinfo *hints) {
9322         const char *cp = serv;
9323         unsigned long n = 0;
9324
9325         while (*cp >= '0' && *cp <= '9' && n < 65536) {
9326                 n *= 10;
9327                 n += *cp++ - '0';
9328         }
9329
9330         if (*cp == '\0') {
9331                 if (cp == serv || n >= 65536)
9332                         return DNS_ESERVICE;
9333
9334                 *port = n;
9335
9336                 return 0;
9337         }
9338
9339         if (hints->ai_flags & AI_NUMERICSERV)
9340                 return DNS_ESERVICE;
9341
9342         /* TODO: try getaddrinfo(NULL, serv, { .ai_flags = AI_NUMERICSERV }) */
9343
9344         return DNS_ESERVICE;
9345 } /* dns_ai_parseport() */
9346
9347
9348 struct dns_addrinfo *dns_ai_open(const char *host, const char *serv, enum dns_type qtype, const struct addrinfo *hints, struct dns_resolver *res, int *_error) {
9349         static const struct dns_addrinfo ai_initializer;
9350         struct dns_addrinfo *ai;
9351         int error;
9352
9353         if (res) {
9354                 dns_res_acquire(res);
9355         } else if (!(hints->ai_flags & AI_NUMERICHOST)) {
9356                 /*
9357                  * NOTE: it's assumed that *_error is set from a previous
9358                  * API function call, such as dns_res_stub(). Should change
9359                  * this semantic, but it's applied elsewhere, too.
9360                  */
9361                 if (!*_error)
9362                         *_error = EINVAL;
9363                 return NULL;
9364         }
9365
9366         if (!(ai = malloc(sizeof *ai)))
9367                 goto syerr;
9368
9369         *ai = ai_initializer;
9370         ai->hints = *hints;
9371
9372         ai->res = res;
9373         res = NULL;
9374
9375         if (sizeof ai->qname <= dns_strlcpy(ai->qname, host, sizeof ai->qname))
9376                 { error = ENAMETOOLONG; goto error; }
9377
9378         ai->qtype = qtype;
9379         ai->qport = 0;
9380
9381         if (serv && (error = dns_ai_parseport(&ai->qport, serv, hints)))
9382                 goto error;
9383         ai->port = ai->qport;
9384
9385         /*
9386          * FIXME: If an explicit A or AAAA record type conflicts with
9387          * .ai_family or with resconf.family (i.e. AAAA specified but
9388          * AF_INET6 not in interection of .ai_family and resconf.family),
9389          * then what?
9390          */
9391         switch (ai->qtype) {
9392         case DNS_T_A:
9393                 ai->af.todo = DNS_AI_AF2INDEX(AF_INET);
9394                 break;
9395         case DNS_T_AAAA:
9396                 ai->af.todo = DNS_AI_AF2INDEX(AF_INET6);
9397                 break;
9398         default: /* 0, MX, SRV, etc */
9399                 switch (ai->hints.ai_family) {
9400                 case AF_UNSPEC:
9401                         ai->af.todo = DNS_AI_AF2INDEX(AF_INET) | DNS_AI_AF2INDEX(AF_INET6);
9402                         break;
9403                 case AF_INET:
9404                         ai->af.todo = DNS_AI_AF2INDEX(AF_INET);
9405                         break;
9406                 case AF_INET6:
9407                         ai->af.todo = DNS_AI_AF2INDEX(AF_INET6);
9408                         break;
9409                 default:
9410                         break;
9411                 }
9412         }
9413
9414         return ai;
9415 syerr:
9416         error = dns_syerr();
9417 error:
9418         *_error = error;
9419
9420         dns_ai_close(ai);
9421         dns_res_close(res);
9422
9423         return NULL;
9424 } /* dns_ai_open() */
9425
9426
9427 void dns_ai_close(struct dns_addrinfo *ai) {
9428         if (!ai)
9429                 return;
9430
9431         dns_res_close(ai->res);
9432         dns_trace_close(ai->trace);
9433
9434         if (ai->answer != ai->glue)
9435                 dns_p_free(ai->glue);
9436
9437         dns_p_free(ai->answer);
9438         free(ai);
9439 } /* dns_ai_close() */
9440
9441
9442 static int dns_ai_setent(struct addrinfo **ent, union dns_any *any, enum dns_type type, struct dns_addrinfo *ai) {
9443         union u {
9444                 struct sockaddr_in sin;
9445                 struct sockaddr_in6 sin6;
9446                 struct sockaddr_storage ss;
9447         } addr;
9448         const char *cname;
9449         size_t clen;
9450
9451         switch (type) {
9452         case DNS_T_A:
9453                 memset(&addr.sin, '\0', sizeof addr.sin);
9454
9455                 addr.sin.sin_family     = AF_INET;
9456                 addr.sin.sin_port       = htons(ai->port);
9457
9458                 memcpy(&addr.sin.sin_addr, any, sizeof addr.sin.sin_addr);
9459
9460                 break;
9461         case DNS_T_AAAA:
9462                 memset(&addr.sin6, '\0', sizeof addr.sin6);
9463
9464                 addr.sin6.sin6_family   = AF_INET6;
9465                 addr.sin6.sin6_port     = htons(ai->port);
9466
9467                 memcpy(&addr.sin6.sin6_addr, any, sizeof addr.sin6.sin6_addr);
9468
9469                 break;
9470         default:
9471                 return EINVAL;
9472         } /* switch() */
9473
9474         if (ai->hints.ai_flags & AI_CANONNAME) {
9475                 cname   = (*ai->cname)? ai->cname : ai->qname;
9476                 clen    = strlen(cname);
9477         } else {
9478                 cname   = NULL;
9479                 clen    = 0;
9480         }
9481
9482         if (!(*ent = malloc(sizeof **ent + dns_sa_len(&addr) + ((ai->hints.ai_flags & AI_CANONNAME)? clen + 1 : 0))))
9483                 return dns_syerr();
9484
9485         memset(*ent, '\0', sizeof **ent);
9486
9487         (*ent)->ai_family       = addr.ss.ss_family;
9488         (*ent)->ai_socktype     = ai->hints.ai_socktype;
9489         (*ent)->ai_protocol     = ai->hints.ai_protocol;
9490
9491         (*ent)->ai_addr         = memcpy((unsigned char *)*ent + sizeof **ent, &addr, dns_sa_len(&addr));
9492         (*ent)->ai_addrlen      = dns_sa_len(&addr);
9493
9494         if (ai->hints.ai_flags & AI_CANONNAME)
9495                 (*ent)->ai_canonname    = memcpy((unsigned char *)*ent + sizeof **ent + dns_sa_len(&addr), cname, clen + 1);
9496
9497         ai->found++;
9498
9499         return 0;
9500 } /* dns_ai_setent() */
9501
9502
9503 enum dns_ai_state {
9504         DNS_AI_S_INIT,
9505         DNS_AI_S_NEXTAF,
9506         DNS_AI_S_NUMERIC,
9507         DNS_AI_S_SUBMIT,
9508         DNS_AI_S_CHECK,
9509         DNS_AI_S_FETCH,
9510         DNS_AI_S_FOREACH_I,
9511         DNS_AI_S_INIT_G,
9512         DNS_AI_S_ITERATE_G,
9513         DNS_AI_S_FOREACH_G,
9514         DNS_AI_S_SUBMIT_G,
9515         DNS_AI_S_CHECK_G,
9516         DNS_AI_S_FETCH_G,
9517         DNS_AI_S_DONE,
9518 }; /* enum dns_ai_state */
9519
9520 #define dns_ai_goto(which)      do { ai->state = (which); goto exec; } while (0)
9521
9522 int dns_ai_nextent(struct addrinfo **ent, struct dns_addrinfo *ai) {
9523         struct dns_packet *ans, *glue;
9524         struct dns_rr rr;
9525         char qname[DNS_D_MAXNAME + 1];
9526         union dns_any any;
9527         size_t qlen, clen;
9528         int error;
9529
9530         *ent = 0;
9531
9532 exec:
9533
9534         switch (ai->state) {
9535         case DNS_AI_S_INIT:
9536                 ai->state++;
9537         case DNS_AI_S_NEXTAF:
9538                 if (!dns_ai_nextaf(ai))
9539                         dns_ai_goto(DNS_AI_S_DONE);
9540
9541                 ai->state++;
9542         case DNS_AI_S_NUMERIC:
9543                 if (1 == dns_inet_pton(AF_INET, ai->qname, &any.a)) {
9544                         if (ai->af.atype == AF_INET) {
9545                                 ai->state = DNS_AI_S_NEXTAF;
9546                                 return dns_ai_setent(ent, &any, DNS_T_A, ai);
9547                         } else {
9548                                 dns_ai_goto(DNS_AI_S_NEXTAF);
9549                         }
9550                 }
9551
9552                 if (1 == dns_inet_pton(AF_INET6, ai->qname, &any.aaaa)) {
9553                         if (ai->af.atype == AF_INET6) {
9554                                 ai->state = DNS_AI_S_NEXTAF;
9555                                 return dns_ai_setent(ent, &any, DNS_T_AAAA, ai);
9556                         } else {
9557                                 dns_ai_goto(DNS_AI_S_NEXTAF);
9558                         }
9559                 }
9560
9561                 if (ai->hints.ai_flags & AI_NUMERICHOST)
9562                         dns_ai_goto(DNS_AI_S_NEXTAF);
9563
9564                 ai->state++;
9565         case DNS_AI_S_SUBMIT:
9566                 assert(ai->res);
9567
9568                 if ((error = dns_res_submit(ai->res, ai->qname, dns_ai_qtype(ai), DNS_C_IN)))
9569                         return error;
9570
9571                 ai->state++;
9572         case DNS_AI_S_CHECK:
9573                 if ((error = dns_res_check(ai->res)))
9574                         return error;
9575
9576                 ai->state++;
9577         case DNS_AI_S_FETCH:
9578                 if (!(ans = dns_res_fetch_and_study(ai->res, &error)))
9579                         return error;
9580                 if (ai->glue != ai->answer)
9581                         dns_p_free(ai->glue);
9582                 ai->glue = dns_p_movptr(&ai->answer, &ans);
9583
9584                 /* Search generator may have changed the qname. */
9585                 if (!(qlen = dns_d_expand(qname, sizeof qname, 12, ai->answer, &error)))
9586                         return error;
9587                 else if (qlen >= sizeof qname)
9588                         return DNS_EILLEGAL;
9589                 if (!dns_d_cname(ai->cname, sizeof ai->cname, qname, qlen, ai->answer, &error))
9590                         return error;
9591
9592                 dns_strlcpy(ai->i_cname, ai->cname, sizeof ai->i_cname);
9593                 dns_rr_i_init(&ai->i, ai->answer);
9594                 ai->i.section = DNS_S_AN;
9595                 ai->i.name    = ai->i_cname;
9596                 ai->i.type    = dns_ai_qtype(ai);
9597                 ai->i.sort    = &dns_rr_i_order;
9598
9599                 ai->state++;
9600         case DNS_AI_S_FOREACH_I:
9601                 if (!dns_rr_grep(&rr, 1, &ai->i, ai->answer, &error))
9602                         dns_ai_goto(DNS_AI_S_NEXTAF);
9603
9604                 if ((error = dns_any_parse(&any, &rr, ai->answer)))
9605                         return error;
9606
9607                 ai->port = ai->qport;
9608
9609                 switch (rr.type) {
9610                 case DNS_T_A:
9611                 case DNS_T_AAAA:
9612                         return dns_ai_setent(ent, &any, rr.type, ai);
9613                 default:
9614                         if (!(clen = dns_any_cname(ai->cname, sizeof ai->cname, &any, rr.type)))
9615                                 dns_ai_goto(DNS_AI_S_FOREACH_I);
9616
9617                         /*
9618                          * Find the "real" canonical name. Some authorities
9619                          * publish aliases where an RFC defines a canonical
9620                          * name. We trust that the resolver followed any
9621                          * CNAME chains on it's own, regardless of whether
9622                          * the "smart" option is enabled.
9623                          */
9624                         if (!dns_d_cname(ai->cname, sizeof ai->cname, ai->cname, clen, ai->answer, &error))
9625                                 return error;
9626
9627                         if (rr.type == DNS_T_SRV)
9628                                 ai->port = any.srv.port;
9629
9630                         break;
9631                 } /* switch() */
9632
9633                 ai->state++;
9634         case DNS_AI_S_INIT_G:
9635                 ai->g_depth = 0;
9636
9637                 ai->state++;
9638         case DNS_AI_S_ITERATE_G:
9639                 dns_strlcpy(ai->g_cname, ai->cname, sizeof ai->g_cname);
9640                 dns_rr_i_init(&ai->g, ai->glue);
9641                 ai->g.section = DNS_S_ALL & ~DNS_S_QD;
9642                 ai->g.name    = ai->g_cname;
9643                 ai->g.type    = ai->af.qtype;
9644
9645                 ai->state++;
9646         case DNS_AI_S_FOREACH_G:
9647                 if (!dns_rr_grep(&rr, 1, &ai->g, ai->glue, &error)) {
9648                         if (dns_rr_i_count(&ai->g) > 0)
9649                                 dns_ai_goto(DNS_AI_S_FOREACH_I);
9650                         else
9651                                 dns_ai_goto(DNS_AI_S_SUBMIT_G);
9652                 }
9653
9654                 if ((error = dns_any_parse(&any, &rr, ai->glue)))
9655                         return error;
9656
9657                 return dns_ai_setent(ent, &any, rr.type, ai);
9658         case DNS_AI_S_SUBMIT_G:
9659                 /* skip if already queried */
9660                 if (dns_rr_grep(&rr, 1, dns_rr_i_new(ai->glue, .section = DNS_S_QD, .name = ai->g.name, .type = ai->g.type), ai->glue, &error))
9661                         dns_ai_goto(DNS_AI_S_FOREACH_I);
9662                 /* skip if we recursed (CNAME chains should have been handled in the resolver) */
9663                 if (++ai->g_depth > 1)
9664                         dns_ai_goto(DNS_AI_S_FOREACH_I);
9665
9666                 if ((error = dns_res_submit(ai->res, ai->g.name, ai->g.type, DNS_C_IN)))
9667                         return error;
9668
9669                 ai->state++;
9670         case DNS_AI_S_CHECK_G:
9671                 if ((error = dns_res_check(ai->res)))
9672                         return error;
9673
9674                 ai->state++;
9675         case DNS_AI_S_FETCH_G:
9676                 if (!(ans = dns_res_fetch_and_study(ai->res, &error)))
9677                         return error;
9678
9679                 glue = dns_p_merge(ai->glue, DNS_S_ALL, ans, DNS_S_ALL, &error);
9680                 dns_p_setptr(&ans, NULL);
9681                 if (!glue)
9682                         return error;
9683
9684                 if (ai->glue != ai->answer)
9685                         dns_p_free(ai->glue);
9686                 ai->glue = glue;
9687
9688                 if (!dns_d_cname(ai->cname, sizeof ai->cname, ai->g.name, strlen(ai->g.name), ai->glue, &error))
9689                         dns_ai_goto(DNS_AI_S_FOREACH_I);
9690
9691                 dns_ai_goto(DNS_AI_S_ITERATE_G);
9692         case DNS_AI_S_DONE:
9693                 if (ai->found) {
9694                         return ENOENT; /* TODO: Just return 0 */
9695                 } else if (ai->answer) {
9696                         switch (dns_p_rcode(ai->answer)) {
9697                         case DNS_RC_NOERROR:
9698                                 /* FALL THROUGH */
9699                         case DNS_RC_NXDOMAIN:
9700                                 return DNS_ENONAME;
9701                         default:
9702                                 return DNS_EFAIL;
9703                         }
9704                 } else {
9705                         return DNS_EFAIL;
9706                 }
9707         default:
9708                 return EINVAL;
9709         } /* switch() */
9710 } /* dns_ai_nextent() */
9711
9712
9713 time_t dns_ai_elapsed(struct dns_addrinfo *ai) {
9714         return (ai->res)? dns_res_elapsed(ai->res) : 0;
9715 } /* dns_ai_elapsed() */
9716
9717
9718 void dns_ai_clear(struct dns_addrinfo *ai) {
9719         if (ai->res)
9720                 dns_res_clear(ai->res);
9721 } /* dns_ai_clear() */
9722
9723
9724 int dns_ai_events(struct dns_addrinfo *ai) {
9725         return (ai->res)? dns_res_events(ai->res) : 0;
9726 } /* dns_ai_events() */
9727
9728
9729 int dns_ai_pollfd(struct dns_addrinfo *ai) {
9730         return (ai->res)? dns_res_pollfd(ai->res) : -1;
9731 } /* dns_ai_pollfd() */
9732
9733
9734 time_t dns_ai_timeout(struct dns_addrinfo *ai) {
9735         return (ai->res)? dns_res_timeout(ai->res) : 0;
9736 } /* dns_ai_timeout() */
9737
9738
9739 int dns_ai_poll(struct dns_addrinfo *ai, int timeout) {
9740         return (ai->res)? dns_res_poll(ai->res, timeout) : 0;
9741 } /* dns_ai_poll() */
9742
9743
9744 size_t dns_ai_print(void *_dst, size_t lim, struct addrinfo *ent, struct dns_addrinfo *ai) {
9745         struct dns_buf dst = DNS_B_INTO(_dst, lim);
9746         char addr[DNS_PP_MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) + 1];
9747
9748         dns_b_puts(&dst, "[ ");
9749         dns_b_puts(&dst, ai->qname);
9750         dns_b_puts(&dst, " IN ");
9751         if (ai->qtype) {
9752                 dns_b_puts(&dst, dns_strtype(ai->qtype));
9753         } else if (ent->ai_family == AF_INET) {
9754                 dns_b_puts(&dst, dns_strtype(DNS_T_A));
9755         } else if (ent->ai_family == AF_INET6) {
9756                 dns_b_puts(&dst, dns_strtype(DNS_T_AAAA));
9757         } else {
9758                 dns_b_puts(&dst, "0");
9759         }
9760         dns_b_puts(&dst, " ]\n");
9761
9762         dns_b_puts(&dst, ".ai_family    = ");
9763         switch (ent->ai_family) {
9764         case AF_INET:
9765                 dns_b_puts(&dst, "AF_INET");
9766                 break;
9767         case AF_INET6:
9768                 dns_b_puts(&dst, "AF_INET6");
9769                 break;
9770         default:
9771                 dns_b_fmtju(&dst, ent->ai_family, 0);
9772                 break;
9773         }
9774         dns_b_putc(&dst, '\n');
9775
9776         dns_b_puts(&dst, ".ai_socktype  = ");
9777         switch (ent->ai_socktype) {
9778         case SOCK_STREAM:
9779                 dns_b_puts(&dst, "SOCK_STREAM");
9780                 break;
9781         case SOCK_DGRAM:
9782                 dns_b_puts(&dst, "SOCK_DGRAM");
9783                 break;
9784         default:
9785                 dns_b_fmtju(&dst, ent->ai_socktype, 0);
9786                 break;
9787         }
9788         dns_b_putc(&dst, '\n');
9789
9790         dns_inet_ntop(dns_sa_family(ent->ai_addr), dns_sa_addr(dns_sa_family(ent->ai_addr), ent->ai_addr, NULL), addr, sizeof addr);
9791         dns_b_puts(&dst, ".ai_addr      = [");
9792         dns_b_puts(&dst, addr);
9793         dns_b_puts(&dst, "]:");
9794         dns_b_fmtju(&dst, ntohs(*dns_sa_port(dns_sa_family(ent->ai_addr), ent->ai_addr)), 0);
9795         dns_b_putc(&dst, '\n');
9796
9797         dns_b_puts(&dst, ".ai_canonname = ");
9798         dns_b_puts(&dst, (ent->ai_canonname)? ent->ai_canonname : "[NULL]");
9799         dns_b_putc(&dst, '\n');
9800
9801         return dns_b_strllen(&dst);
9802 } /* dns_ai_print() */
9803
9804
9805 const struct dns_stat *dns_ai_stat(struct dns_addrinfo *ai) {
9806         return (ai->res)? dns_res_stat(ai->res) : &ai->st;
9807 } /* dns_ai_stat() */
9808
9809
9810 struct dns_trace *dns_ai_trace(struct dns_addrinfo *ai) {
9811         return ai->trace;
9812 } /* dns_ai_trace() */
9813
9814
9815 void dns_ai_settrace(struct dns_addrinfo *ai, struct dns_trace *trace) {
9816         struct dns_trace *otrace = ai->trace;
9817         ai->trace = dns_trace_acquire_p(trace);
9818         dns_trace_close(otrace);
9819         if (ai->res)
9820                 dns_res_settrace(ai->res, trace);
9821 } /* dns_ai_settrace() */
9822
9823
9824 /*
9825  * M I S C E L L A N E O U S  R O U T I N E S
9826  *
9827  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9828
9829 static const struct {
9830         char name[16];
9831         enum dns_section type;
9832 } dns_sections[] = {
9833         { "QUESTION",   DNS_S_QUESTION },
9834         { "QD",         DNS_S_QUESTION },
9835         { "ANSWER",     DNS_S_ANSWER },
9836         { "AN",         DNS_S_ANSWER },
9837         { "AUTHORITY",  DNS_S_AUTHORITY },
9838         { "NS",         DNS_S_AUTHORITY },
9839         { "ADDITIONAL", DNS_S_ADDITIONAL },
9840         { "AR",         DNS_S_ADDITIONAL },
9841 };
9842
9843 const char *(dns_strsection)(enum dns_section section, void *_dst, size_t lim) {
9844         struct dns_buf dst = DNS_B_INTO(_dst, lim);
9845         unsigned i;
9846
9847         for (i = 0; i < lengthof(dns_sections); i++) {
9848                 if (dns_sections[i].type & section) {
9849                         dns_b_puts(&dst, dns_sections[i].name);
9850                         section &= ~dns_sections[i].type;
9851                         if (section)
9852                                 dns_b_putc(&dst, '|');
9853                 }
9854         }
9855
9856         if (section || dst.p == dst.base)
9857                 dns_b_fmtju(&dst, (0xffff & section), 0);
9858
9859         return dns_b_tostring(&dst);
9860 } /* dns_strsection() */
9861
9862
9863 enum dns_section dns_isection(const char *src) {
9864         enum dns_section section = 0;
9865         char sbuf[128];
9866         char *name, *next;
9867         unsigned i;
9868
9869         dns_strlcpy(sbuf, src, sizeof sbuf);
9870         next = sbuf;
9871
9872         while ((name = dns_strsep(&next, "|+, \t"))) {
9873                 for (i = 0; i < lengthof(dns_sections); i++) {
9874                         if (!strcasecmp(dns_sections[i].name, name)) {
9875                                 section |= dns_sections[i].type;
9876                                 break;
9877                         }
9878                 }
9879         }
9880
9881         return section;
9882 } /* dns_isection() */
9883
9884
9885 static const struct {
9886         char name[8];
9887         enum dns_class type;
9888 } dns_classes[] = {
9889         { "IN", DNS_C_IN },
9890 };
9891
9892 const char *(dns_strclass)(enum dns_class type, void *_dst, size_t lim) {
9893         struct dns_buf dst = DNS_B_INTO(_dst, lim);
9894         unsigned i;
9895
9896         for (i = 0; i < lengthof(dns_classes); i++) {
9897                 if (dns_classes[i].type == type) {
9898                         dns_b_puts(&dst, dns_classes[i].name);
9899                         break;
9900                 }
9901         }
9902
9903         if (dst.p == dst.base)
9904                 dns_b_fmtju(&dst, (0xffff & type), 0);
9905
9906         return dns_b_tostring(&dst);
9907 } /* dns_strclass() */
9908
9909
9910 enum dns_class dns_iclass(const char *name) {
9911         unsigned i, class;
9912
9913         for (i = 0; i < lengthof(dns_classes); i++) {
9914                 if (!strcasecmp(dns_classes[i].name, name))
9915                         return dns_classes[i].type;
9916         }
9917
9918         class = 0;
9919         while (dns_isdigit(*name)) {
9920                 class *= 10;
9921                 class += *name++ - '0';
9922         }
9923
9924         return DNS_PP_MIN(class, 0xffff);
9925 } /* dns_iclass() */
9926
9927
9928 const char *(dns_strtype)(enum dns_type type, void *_dst, size_t lim) {
9929         struct dns_buf dst = DNS_B_INTO(_dst, lim);
9930         unsigned i;
9931
9932         for (i = 0; i < lengthof(dns_rrtypes); i++) {
9933                 if (dns_rrtypes[i].type == type) {
9934                         dns_b_puts(&dst, dns_rrtypes[i].name);
9935                         break;
9936                 }
9937         }
9938
9939         if (dst.p == dst.base)
9940                 dns_b_fmtju(&dst, (0xffff & type), 0);
9941
9942         return dns_b_tostring(&dst);
9943 } /* dns_strtype() */
9944
9945
9946 enum dns_type dns_itype(const char *name) {
9947         unsigned i, type;
9948
9949         for (i = 0; i < lengthof(dns_rrtypes); i++) {
9950                 if (!strcasecmp(dns_rrtypes[i].name, name))
9951                         return dns_rrtypes[i].type;
9952         }
9953
9954         type = 0;
9955         while (dns_isdigit(*name)) {
9956                 type *= 10;
9957                 type += *name++ - '0';
9958         }
9959
9960         return DNS_PP_MIN(type, 0xffff);
9961 } /* dns_itype() */
9962
9963
9964 static char dns_opcodes[16][16] = {
9965         [DNS_OP_QUERY]  = "QUERY",
9966         [DNS_OP_IQUERY] = "IQUERY",
9967         [DNS_OP_STATUS] = "STATUS",
9968         [DNS_OP_NOTIFY] = "NOTIFY",
9969         [DNS_OP_UPDATE] = "UPDATE",
9970 };
9971
9972 static const char *dns__strcode(int code, volatile char *dst, size_t lim) {
9973         char _tmp[48] = "";
9974         struct dns_buf tmp;
9975         size_t p;
9976
9977         assert(lim > 0);
9978         dns_b_fmtju(dns_b_into(&tmp, _tmp, DNS_PP_MIN(sizeof _tmp, lim - 1)), code, 0);
9979
9980         /* copy downwards so first byte is copied last (see below) */
9981         p = (size_t)(tmp.p - tmp.base);
9982         dst[p] = '\0';
9983         while (p--)
9984                 dst[p] = _tmp[p];
9985
9986         return (const char *)dst;
9987 }
9988
9989 const char *dns_stropcode(enum dns_opcode opcode) {
9990         opcode = (unsigned)opcode % lengthof(dns_opcodes);
9991
9992         if ('\0' == dns_opcodes[opcode][0])
9993                 return dns__strcode(opcode, dns_opcodes[opcode], sizeof dns_opcodes[opcode]);
9994
9995         return dns_opcodes[opcode];
9996 } /* dns_stropcode() */
9997
9998
9999 enum dns_opcode dns_iopcode(const char *name) {
10000         unsigned opcode;
10001
10002         for (opcode = 0; opcode < lengthof(dns_opcodes); opcode++) {
10003                 if (!strcasecmp(name, dns_opcodes[opcode]))
10004                         return opcode;
10005         }
10006
10007         opcode = 0;
10008         while (dns_isdigit(*name)) {
10009                 opcode *= 10;
10010                 opcode += *name++ - '0';
10011         }
10012
10013         return DNS_PP_MIN(opcode, 0x0f);
10014 } /* dns_iopcode() */
10015
10016
10017 static char dns_rcodes[32][16] = {
10018         [DNS_RC_NOERROR]  = "NOERROR",
10019         [DNS_RC_FORMERR]  = "FORMERR",
10020         [DNS_RC_SERVFAIL] = "SERVFAIL",
10021         [DNS_RC_NXDOMAIN] = "NXDOMAIN",
10022         [DNS_RC_NOTIMP]   = "NOTIMP",
10023         [DNS_RC_REFUSED]  = "REFUSED",
10024         [DNS_RC_YXDOMAIN] = "YXDOMAIN",
10025         [DNS_RC_YXRRSET]  = "YXRRSET",
10026         [DNS_RC_NXRRSET]  = "NXRRSET",
10027         [DNS_RC_NOTAUTH]  = "NOTAUTH",
10028         [DNS_RC_NOTZONE]  = "NOTZONE",
10029         /* EDNS(0) extended RCODEs ... */
10030         [DNS_RC_BADVERS]  = "BADVERS",
10031 };
10032
10033 const char *dns_strrcode(enum dns_rcode rcode) {
10034         rcode = (unsigned)rcode % lengthof(dns_rcodes);
10035
10036         if ('\0' == dns_rcodes[rcode][0])
10037                 return dns__strcode(rcode, dns_rcodes[rcode], sizeof dns_rcodes[rcode]);
10038
10039         return dns_rcodes[rcode];
10040 } /* dns_strrcode() */
10041
10042
10043 enum dns_rcode dns_ircode(const char *name) {
10044         unsigned rcode;
10045
10046         for (rcode = 0; rcode < lengthof(dns_rcodes); rcode++) {
10047                 if (!strcasecmp(name, dns_rcodes[rcode]))
10048                         return rcode;
10049         }
10050
10051         rcode = 0;
10052         while (dns_isdigit(*name)) {
10053                 rcode *= 10;
10054                 rcode += *name++ - '0';
10055         }
10056
10057         return DNS_PP_MIN(rcode, 0xfff);
10058 } /* dns_ircode() */
10059
10060
10061 \f
10062 /*
10063  * C O M M A N D - L I N E / R E G R E S S I O N  R O U T I N E S
10064  *
10065  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
10066 #if DNS_MAIN
10067
10068 #include <stdarg.h>
10069 #include <stdlib.h>
10070 #include <stdio.h>
10071
10072 #include <ctype.h>
10073
10074 #if _WIN32
10075 #include <getopt.h>
10076 #endif
10077
10078 #if !_WIN32
10079 #include <err.h>
10080 #endif
10081
10082
10083 struct {
10084         struct {
10085                 const char *path[8];
10086                 unsigned count;
10087         } resconf, nssconf, hosts, cache;
10088
10089         const char *qname;
10090         enum dns_type qtype;
10091
10092         int (*sort)();
10093
10094         const char *trace;
10095
10096         int verbose;
10097
10098         struct {
10099                 struct dns_resolv_conf *resconf;
10100                 struct dns_hosts *hosts;
10101                 struct dns_trace *trace;
10102         } memo;
10103
10104         struct sockaddr_storage socks_host;
10105         const char *socks_user;
10106         const char *socks_password;
10107 } MAIN = {
10108         .sort   = &dns_rr_i_packet,
10109 };
10110
10111
10112 static void hexdump(const unsigned char *src, size_t len, FILE *fp) {
10113         struct dns_hxd_lines_i lines = { 0 };
10114         char line[128];
10115
10116         while (dns_hxd_lines(line, sizeof line, src, len, &lines)) {
10117                 fputs(line, fp);
10118         }
10119 } /* hexdump() */
10120
10121
10122 DNS_NORETURN static void panic(const char *fmt, ...) {
10123         va_list ap;
10124
10125         va_start(ap, fmt);
10126
10127 #if _WIN32
10128         vfprintf(stderr, fmt, ap);
10129
10130         exit(EXIT_FAILURE);
10131 #else
10132         verrx(EXIT_FAILURE, fmt, ap);
10133 #endif
10134 } /* panic() */
10135
10136 #define panic_(fn, ln, fmt, ...)        \
10137         panic(fmt "%0s", (fn), (ln), __VA_ARGS__)
10138 #define panic(...)                      \
10139         panic_(__func__, __LINE__, "(%s:%d) " __VA_ARGS__, "")
10140
10141
10142 static void *grow(unsigned char *p, size_t size) {
10143         void *tmp;
10144
10145         if (!(tmp = realloc(p, size)))
10146                 panic("realloc(%"PRIuZ"): %s", size, dns_strerror(errno));
10147
10148         return tmp;
10149 } /* grow() */
10150
10151
10152 static size_t add(size_t a, size_t b) {
10153         if (~a < b)
10154                 panic("%"PRIuZ" + %"PRIuZ": integer overflow", a, b);
10155
10156         return a + b;
10157 } /* add() */
10158
10159
10160 static size_t append(unsigned char **dst, size_t osize, const void *src, size_t len) {
10161         size_t size = add(osize, len);
10162
10163         *dst = grow(*dst, size);
10164         memcpy(*dst + osize, src, len);
10165
10166         return size;
10167 } /* append() */
10168
10169
10170 static size_t slurp(unsigned char **dst, size_t osize, FILE *fp, const char *path) {
10171         size_t size = osize;
10172         unsigned char buf[1024];
10173         size_t count;
10174
10175         while ((count = fread(buf, 1, sizeof buf, fp)))
10176                 size = append(dst, size, buf, count);
10177
10178         if (ferror(fp))
10179                 panic("%s: %s", path, dns_strerror(errno));
10180
10181         return size;
10182 } /* slurp() */
10183
10184
10185 static struct dns_resolv_conf *resconf(void) {
10186         struct dns_resolv_conf **resconf = &MAIN.memo.resconf;
10187         const char *path;
10188         unsigned i;
10189         int error;
10190
10191         if (*resconf)
10192                 return *resconf;
10193
10194         if (!(*resconf = dns_resconf_open(&error)))
10195                 panic("dns_resconf_open: %s", dns_strerror(error));
10196
10197         if (!MAIN.resconf.count)
10198                 MAIN.resconf.path[MAIN.resconf.count++] = "/etc/resolv.conf";
10199
10200         for (i = 0; i < MAIN.resconf.count; i++) {
10201                 path    = MAIN.resconf.path[i];
10202
10203                 if (0 == strcmp(path, "-"))
10204                         error   = dns_resconf_loadfile(*resconf, stdin);
10205                 else
10206                         error   = dns_resconf_loadpath(*resconf, path);
10207
10208                 if (error)
10209                         panic("%s: %s", path, dns_strerror(error));
10210         }
10211
10212         for (i = 0; i < MAIN.nssconf.count; i++) {
10213                 path    = MAIN.nssconf.path[i];
10214
10215                 if (0 == strcmp(path, "-"))
10216                         error   = dns_nssconf_loadfile(*resconf, stdin);
10217                 else
10218                         error   = dns_nssconf_loadpath(*resconf, path);
10219
10220                 if (error)
10221                         panic("%s: %s", path, dns_strerror(error));
10222         }
10223
10224         if (!MAIN.nssconf.count) {
10225                 path = "/etc/nsswitch.conf";
10226
10227                 if (!(error = dns_nssconf_loadpath(*resconf, path)))
10228                         MAIN.nssconf.path[MAIN.nssconf.count++] = path;
10229                 else if (error != ENOENT)
10230                         panic("%s: %s", path, dns_strerror(error));
10231         }
10232
10233         return *resconf;
10234 } /* resconf() */
10235
10236
10237 static struct dns_hosts *hosts(void) {
10238         struct dns_hosts **hosts = &MAIN.memo.hosts;
10239         const char *path;
10240         unsigned i;
10241         int error;
10242
10243         if (*hosts)
10244                 return *hosts;
10245
10246         if (!MAIN.hosts.count) {
10247                 MAIN.hosts.path[MAIN.hosts.count++]     = "/etc/hosts";
10248
10249                 /* Explicitly test dns_hosts_local() */
10250                 if (!(*hosts = dns_hosts_local(&error)))
10251                         panic("%s: %s", "/etc/hosts", dns_strerror(error));
10252
10253                 return *hosts;
10254         }
10255
10256         if (!(*hosts = dns_hosts_open(&error)))
10257                 panic("dns_hosts_open: %s", dns_strerror(error));
10258
10259         for (i = 0; i < MAIN.hosts.count; i++) {
10260                 path    = MAIN.hosts.path[i];
10261
10262                 if (0 == strcmp(path, "-"))
10263                         error   = dns_hosts_loadfile(*hosts, stdin);
10264                 else
10265                         error   = dns_hosts_loadpath(*hosts, path);
10266
10267                 if (error)
10268                         panic("%s: %s", path, dns_strerror(error));
10269         }
10270
10271         return *hosts;
10272 } /* hosts() */
10273
10274
10275 #if DNS_CACHE
10276 #include "cache.h"
10277
10278 static struct dns_cache *cache(void) {
10279         static struct cache *cache;
10280         const char *path;
10281         unsigned i;
10282         int error;
10283
10284         if (cache)
10285                 return cache_resi(cache);
10286         if (!MAIN.cache.count)
10287                 return NULL;
10288
10289         if (!(cache = cache_open(&error)))
10290                 panic("%s: %s", MAIN.cache.path[0], dns_strerror(error));
10291
10292         for (i = 0; i < MAIN.cache.count; i++) {
10293                 path = MAIN.cache.path[i];
10294
10295                 if (!strcmp(path, "-")) {
10296                         if ((error = cache_loadfile(cache, stdin, NULL, 0)))
10297                                 panic("%s: %s", path, dns_strerror(error));
10298                 } else if ((error = cache_loadpath(cache, path, NULL, 0)))
10299                         panic("%s: %s", path, dns_strerror(error));
10300         }
10301
10302         return cache_resi(cache);
10303 } /* cache() */
10304 #else
10305 static struct dns_cache *cache(void) { return NULL; }
10306 #endif
10307
10308
10309 static struct dns_trace *trace(const char *mode) {
10310         static char omode[64] = "";
10311         struct dns_trace **trace = &MAIN.memo.trace;
10312         FILE *fp;
10313         int error;
10314
10315         if (*trace && 0 == strcmp(omode, mode))
10316                 return *trace;
10317         if (!MAIN.trace)
10318                 return NULL;
10319
10320         if (!(fp = fopen(MAIN.trace, mode)))
10321                 panic("%s: %s", MAIN.trace, strerror(errno));
10322         dns_trace_close(*trace);
10323         if (!(*trace = dns_trace_open(fp, &error)))
10324                 panic("%s: %s", MAIN.trace, dns_strerror(error));
10325         dns_strlcpy(omode, mode, sizeof omode);
10326
10327         return *trace;
10328 }
10329
10330
10331 static void print_packet(struct dns_packet *P, FILE *fp) {
10332         dns_p_dump3(P, dns_rr_i_new(P, .sort = MAIN.sort), fp);
10333
10334         if (MAIN.verbose > 2)
10335                 hexdump(P->data, P->end, fp);
10336 } /* print_packet() */
10337
10338
10339 static int parse_packet(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
10340         struct dns_packet *P    = dns_p_new(512);
10341         struct dns_packet *Q    = dns_p_new(512);
10342         enum dns_section section;
10343         struct dns_rr rr;
10344         int error;
10345         union dns_any any;
10346         char pretty[sizeof any * 2];
10347         size_t len;
10348
10349         P->end  = fread(P->data, 1, P->size, stdin);
10350
10351         fputs(";; [HEADER]\n", stdout);
10352         fprintf(stdout, ";;     qr : %s(%d)\n", (dns_header(P)->qr)? "RESPONSE" : "QUERY", dns_header(P)->qr);
10353         fprintf(stdout, ";; opcode : %s(%d)\n", dns_stropcode(dns_header(P)->opcode), dns_header(P)->opcode);
10354         fprintf(stdout, ";;     aa : %s(%d)\n", (dns_header(P)->aa)? "AUTHORITATIVE" : "NON-AUTHORITATIVE", dns_header(P)->aa);
10355         fprintf(stdout, ";;     tc : %s(%d)\n", (dns_header(P)->tc)? "TRUNCATED" : "NOT-TRUNCATED", dns_header(P)->tc);
10356         fprintf(stdout, ";;     rd : %s(%d)\n", (dns_header(P)->rd)? "RECURSION-DESIRED" : "RECURSION-NOT-DESIRED", dns_header(P)->rd);
10357         fprintf(stdout, ";;     ra : %s(%d)\n", (dns_header(P)->ra)? "RECURSION-ALLOWED" : "RECURSION-NOT-ALLOWED", dns_header(P)->ra);
10358         fprintf(stdout, ";;  rcode : %s(%d)\n", dns_strrcode(dns_p_rcode(P)), dns_p_rcode(P));
10359
10360         section = 0;
10361
10362         dns_rr_foreach(&rr, P, .sort = MAIN.sort) {
10363                 if (section != rr.section)
10364                         fprintf(stdout, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(P, rr.section));
10365
10366                 if ((len = dns_rr_print(pretty, sizeof pretty, &rr, P, &error)))
10367                         fprintf(stdout, "%s\n", pretty);
10368
10369                 dns_rr_copy(Q, &rr, P);
10370
10371                 section = rr.section;
10372         }
10373
10374         fputs("; ; ; ; ; ; ; ;\n\n", stdout);
10375
10376         section = 0;
10377
10378 #if 0
10379         dns_rr_foreach(&rr, Q, .name = "ns8.yahoo.com.") {
10380 #else
10381         struct dns_rr rrset[32];
10382         struct dns_rr_i *rri    = dns_rr_i_new(Q, .name = dns_d_new("ns8.yahoo.com", DNS_D_ANCHOR), .sort = MAIN.sort);
10383         unsigned rrcount        = dns_rr_grep(rrset, lengthof(rrset), rri, Q, &error);
10384
10385         for (unsigned i = 0; i < rrcount; i++) {
10386                 rr      = rrset[i];
10387 #endif
10388                 if (section != rr.section)
10389                         fprintf(stdout, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(Q, rr.section));
10390
10391                 if ((len = dns_rr_print(pretty, sizeof pretty, &rr, Q, &error)))
10392                         fprintf(stdout, "%s\n", pretty);
10393
10394                 section = rr.section;
10395         }
10396
10397         if (MAIN.verbose > 1) {
10398                 fprintf(stderr, "orig:%"PRIuZ"\n", P->end);
10399                 hexdump(P->data, P->end, stdout);
10400
10401                 fprintf(stderr, "copy:%"PRIuZ"\n", Q->end);
10402                 hexdump(Q->data, Q->end, stdout);
10403         }
10404
10405         return 0;
10406 } /* parse_packet() */
10407
10408
10409 static int parse_domain(int argc, char *argv[]) {
10410         char *dn;
10411
10412         dn      = (argc > 1)? argv[1] : "f.l.google.com";
10413
10414         printf("[%s]\n", dn);
10415
10416         dn      = dns_d_new(dn);
10417
10418         do {
10419                 puts(dn);
10420         } while (dns_d_cleave(dn, strlen(dn) + 1, dn, strlen(dn)));
10421
10422         return 0;
10423 } /* parse_domain() */
10424
10425
10426 static int trim_domain(int argc, char **argv) {
10427         for (argc--, argv++; argc > 0; argc--, argv++) {
10428                 char name[DNS_D_MAXNAME + 1];
10429
10430                 dns_d_trim(name, sizeof name, *argv, strlen(*argv), DNS_D_ANCHOR);
10431
10432                 puts(name);
10433         }
10434
10435         return 0;
10436 } /* trim_domain() */
10437
10438
10439 static int expand_domain(int argc, char *argv[]) {
10440         unsigned short rp = 0;
10441         unsigned char *src = NULL;
10442         unsigned char *dst;
10443         struct dns_packet *pkt;
10444         size_t lim = 0, len;
10445         int error;
10446
10447         if (argc > 1)
10448                 rp = atoi(argv[1]);
10449
10450         len = slurp(&src, 0, stdin, "-");
10451
10452         if (!(pkt = dns_p_make(len, &error)))
10453                 panic("malloc(%"PRIuZ"): %s", len, dns_strerror(error));
10454
10455         memcpy(pkt->data, src, len);
10456         pkt->end = len;
10457
10458         lim = 1;
10459         dst = grow(NULL, lim);
10460
10461         while (lim <= (len = dns_d_expand(dst, lim, rp, pkt, &error))) {
10462                 lim = add(len, 1);
10463                 dst = grow(dst, lim);
10464         }
10465
10466         if (!len)
10467                 panic("expand: %s", dns_strerror(error));
10468
10469         fwrite(dst, 1, len, stdout);
10470         fflush(stdout);
10471
10472         free(src);
10473         free(dst);
10474         free(pkt);
10475
10476         return 0;
10477 } /* expand_domain() */
10478
10479
10480 static int show_resconf(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
10481         unsigned i;
10482
10483         resconf(); /* load it */
10484
10485         fputs("; SOURCES\n", stdout);
10486
10487         for (i = 0; i < MAIN.resconf.count; i++)
10488                 fprintf(stdout, ";   %s\n", MAIN.resconf.path[i]);
10489
10490         for (i = 0; i < MAIN.nssconf.count; i++)
10491                 fprintf(stdout, ";   %s\n", MAIN.nssconf.path[i]);
10492
10493         fputs(";\n", stdout);
10494
10495         dns_resconf_dump(resconf(), stdout);
10496
10497         return 0;
10498 } /* show_resconf() */
10499
10500
10501 static int show_nssconf(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
10502         unsigned i;
10503
10504         resconf();
10505
10506         fputs("# SOURCES\n", stdout);
10507
10508         for (i = 0; i < MAIN.resconf.count; i++)
10509                 fprintf(stdout, "#   %s\n", MAIN.resconf.path[i]);
10510
10511         for (i = 0; i < MAIN.nssconf.count; i++)
10512                 fprintf(stdout, "#   %s\n", MAIN.nssconf.path[i]);
10513
10514         fputs("#\n", stdout);
10515
10516         dns_nssconf_dump(resconf(), stdout);
10517
10518         return 0;
10519 } /* show_nssconf() */
10520
10521
10522 static int show_hosts(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
10523         unsigned i;
10524
10525         hosts();
10526
10527         fputs("# SOURCES\n", stdout);
10528
10529         for (i = 0; i < MAIN.hosts.count; i++)
10530                 fprintf(stdout, "#   %s\n", MAIN.hosts.path[i]);
10531
10532         fputs("#\n", stdout);
10533
10534         dns_hosts_dump(hosts(), stdout);
10535
10536         return 0;
10537 } /* show_hosts() */
10538
10539
10540 static int query_hosts(int argc, char *argv[]) {
10541         struct dns_packet *Q    = dns_p_new(512);
10542         struct dns_packet *A;
10543         char qname[DNS_D_MAXNAME + 1];
10544         size_t qlen;
10545         int error;
10546
10547         if (!MAIN.qname)
10548                 MAIN.qname      = (argc > 1)? argv[1] : "localhost";
10549         if (!MAIN.qtype)
10550                 MAIN.qtype      = DNS_T_A;
10551
10552         hosts();
10553
10554         if (MAIN.qtype == DNS_T_PTR && !strstr(MAIN.qname, "arpa")) {
10555                 union { struct in_addr a; struct in6_addr a6; } addr;
10556                 int af  = (strchr(MAIN.qname, ':'))? AF_INET6 : AF_INET;
10557
10558                 if ((error = dns_pton(af, MAIN.qname, &addr)))
10559                         panic("%s: %s", MAIN.qname, dns_strerror(error));
10560
10561                 qlen    = dns_ptr_qname(qname, sizeof qname, af, &addr);
10562         } else
10563                 qlen    = dns_strlcpy(qname, MAIN.qname, sizeof qname);
10564
10565         if ((error = dns_p_push(Q, DNS_S_QD, qname, qlen, MAIN.qtype, DNS_C_IN, 0, 0)))
10566                 panic("%s: %s", qname, dns_strerror(error));
10567
10568         if (!(A = dns_hosts_query(hosts(), Q, &error)))
10569                 panic("%s: %s", qname, dns_strerror(error));
10570
10571         print_packet(A, stdout);
10572
10573         free(A);
10574
10575         return 0;
10576 } /* query_hosts() */
10577
10578
10579 static int search_list(int argc, char *argv[]) {
10580         const char *qname       = (argc > 1)? argv[1] : "f.l.google.com";
10581         unsigned long i         = 0;
10582         char name[DNS_D_MAXNAME + 1];
10583
10584         printf("[%s]\n", qname);
10585
10586         while (dns_resconf_search(name, sizeof name, qname, strlen(qname), resconf(), &i))
10587                 puts(name);
10588
10589         return 0;
10590 } /* search_list() */
10591
10592
10593 static int permute_set(int argc, char *argv[]) {
10594         unsigned lo, hi, i;
10595         struct dns_k_permutor p;
10596
10597         hi      = (--argc > 0)? atoi(argv[argc]) : 8;
10598         lo      = (--argc > 0)? atoi(argv[argc]) : 0;
10599
10600         fprintf(stderr, "[%u .. %u]\n", lo, hi);
10601
10602         dns_k_permutor_init(&p, lo, hi);
10603
10604         for (i = lo; i <= hi; i++)
10605                 fprintf(stdout, "%u\n", dns_k_permutor_step(&p));
10606 //              printf("%u -> %u -> %u\n", i, dns_k_permutor_E(&p, i), dns_k_permutor_D(&p, dns_k_permutor_E(&p, i)));
10607
10608         return 0;
10609 } /* permute_set() */
10610
10611
10612 static int shuffle_16(int argc, char *argv[]) {
10613         unsigned n, r;
10614
10615         if (--argc > 0) {
10616                 n = 0xffff & atoi(argv[argc]);
10617                 r = (--argc > 0)? (unsigned)atoi(argv[argc]) : dns_random();
10618
10619                 fprintf(stdout, "%hu\n", dns_k_shuffle16(n, r));
10620         } else {
10621                 r = dns_random();
10622
10623                 for (n = 0; n < 65536; n++)
10624                         fprintf(stdout, "%hu\n", dns_k_shuffle16(n, r));
10625         }
10626
10627         return 0;
10628 } /* shuffle_16() */
10629
10630
10631 static int dump_random(int argc, char *argv[]) {
10632         unsigned char b[32];
10633         unsigned i, j, n, r;
10634
10635         n       = (argc > 1)? atoi(argv[1]) : 32;
10636
10637         while (n) {
10638                 i       = 0;
10639
10640                 do {
10641                         r       = dns_random();
10642
10643                         for (j = 0; j < sizeof r && i < n && i < sizeof b; i++, j++) {
10644                                 b[i]    = 0xff & r;
10645                                 r       >>= 8;
10646                         }
10647                 } while (i < n && i < sizeof b);
10648
10649                 hexdump(b, i, stdout);
10650
10651                 n       -= i;
10652         }
10653
10654         return 0;
10655 } /* dump_random() */
10656
10657
10658 static int send_query(int argc, char *argv[]) {
10659         struct dns_packet *A, *Q        = dns_p_new(512);
10660         char host[INET6_ADDRSTRLEN + 1];
10661         struct sockaddr_storage ss;
10662         struct dns_socket *so;
10663         int error, type;
10664
10665         if (argc > 1) {
10666                 ss.ss_family    = (strchr(argv[1], ':'))? AF_INET6 : AF_INET;
10667
10668                 if ((error = dns_pton(ss.ss_family, argv[1], dns_sa_addr(ss.ss_family, &ss, NULL))))
10669                         panic("%s: %s", argv[1], dns_strerror(error));
10670
10671                 *dns_sa_port(ss.ss_family, &ss) = htons(53);
10672         } else
10673                 memcpy(&ss, &resconf()->nameserver[0], dns_sa_len(&resconf()->nameserver[0]));
10674
10675         if (!dns_inet_ntop(ss.ss_family, dns_sa_addr(ss.ss_family, &ss, NULL), host, sizeof host))
10676                 panic("bad host address, or none provided");
10677
10678         if (!MAIN.qname)
10679                 MAIN.qname      = "ipv6.google.com";
10680         if (!MAIN.qtype)
10681                 MAIN.qtype      = DNS_T_AAAA;
10682
10683         if ((error = dns_p_push(Q, DNS_S_QD, MAIN.qname, strlen(MAIN.qname), MAIN.qtype, DNS_C_IN, 0, 0)))
10684                 panic("dns_p_push: %s", dns_strerror(error));
10685
10686         dns_header(Q)->rd       = 1;
10687
10688         if (strstr(argv[0], "udp"))
10689                 type    = SOCK_DGRAM;
10690         else if (strstr(argv[0], "tcp"))
10691                 type    = SOCK_STREAM;
10692         else
10693                 type    = dns_res_tcp2type(resconf()->options.tcp);
10694
10695         fprintf(stderr, "querying %s for %s IN %s\n", host, MAIN.qname, dns_strtype(MAIN.qtype));
10696
10697         if (!(so = dns_so_open((struct sockaddr *)&resconf()->iface, type, dns_opts(), &error)))
10698                 panic("dns_so_open: %s", dns_strerror(error));
10699
10700         while (!(A = dns_so_query(so, Q, (struct sockaddr *)&ss, &error))) {
10701                 if (error != DNS_EAGAIN)
10702                         panic("dns_so_query: %s (%d)", dns_strerror(error), error);
10703                 if (dns_so_elapsed(so) > 10)
10704                         panic("query timed-out");
10705
10706                 dns_so_poll(so, 1);
10707         }
10708
10709         print_packet(A, stdout);
10710
10711         dns_so_close(so);
10712
10713         return 0;
10714 } /* send_query() */
10715
10716
10717 static int print_arpa(int argc, char *argv[]) {
10718         const char *ip  = (argc > 1)? argv[1] : "::1";
10719         int af          = (strchr(ip, ':'))? AF_INET6 : AF_INET;
10720         union { struct in_addr a4; struct in6_addr a6; } addr;
10721         char host[DNS_D_MAXNAME + 1];
10722
10723         if (1 != dns_inet_pton(af, ip, &addr) || 0 == dns_ptr_qname(host, sizeof host, af, &addr))
10724                 panic("%s: invalid address", ip);
10725
10726         fprintf(stdout, "%s\n", host);
10727
10728         return 0;
10729 } /* print_arpa() */
10730
10731
10732 static int show_hints(int argc, char *argv[]) {
10733         struct dns_hints *(*load)(struct dns_resolv_conf *, int *);
10734         const char *which, *how, *who;
10735         struct dns_hints *hints;
10736         int error;
10737
10738         which   = (argc > 1)? argv[1] : "local";
10739         how     = (argc > 2)? argv[2] : "plain";
10740         who     = (argc > 3)? argv[3] : "google.com";
10741
10742         load    = (0 == strcmp(which, "local"))
10743                 ? &dns_hints_local
10744                 : &dns_hints_root;
10745
10746         if (!(hints = load(resconf(), &error)))
10747                 panic("%s: %s", argv[0], dns_strerror(error));
10748
10749         if (0 == strcmp(how, "plain")) {
10750                 dns_hints_dump(hints, stdout);
10751         } else {
10752                 struct dns_packet *query, *answer;
10753
10754                 query   = dns_p_new(512);
10755
10756                 if ((error = dns_p_push(query, DNS_S_QUESTION, who, strlen(who), DNS_T_A, DNS_C_IN, 0, 0)))
10757                         panic("%s: %s", who, dns_strerror(error));
10758
10759                 if (!(answer = dns_hints_query(hints, query, &error)))
10760                         panic("%s: %s", who, dns_strerror(error));
10761
10762                 print_packet(answer, stdout);
10763
10764                 free(answer);
10765         }
10766
10767         dns_hints_close(hints);
10768
10769         return 0;
10770 } /* show_hints() */
10771
10772
10773 static int resolve_query(int argc DNS_NOTUSED, char *argv[]) {
10774         _Bool recurse = !!strstr(argv[0], "recurse");
10775         struct dns_hints *(*hints)() = (recurse)? &dns_hints_root : &dns_hints_local;
10776         struct dns_resolver *R;
10777         struct dns_packet *ans;
10778         const struct dns_stat *st;
10779         int error;
10780
10781         if (!MAIN.qname)
10782                 MAIN.qname = "www.google.com";
10783         if (!MAIN.qtype)
10784                 MAIN.qtype = DNS_T_A;
10785
10786         resconf()->options.recurse = recurse;
10787
10788         if (!(R = dns_res_open(resconf(), hosts(), dns_hints_mortal(hints(resconf(), &error)), cache(),
10789                                dns_opts(.socks_host=&MAIN.socks_host,
10790                                         .socks_user=MAIN.socks_user,
10791                                         .socks_password=MAIN.socks_password), &error)))
10792                 panic("%s: %s", MAIN.qname, dns_strerror(error));
10793
10794         dns_res_settrace(R, trace("w+b"));
10795
10796         if ((error = dns_res_submit(R, MAIN.qname, MAIN.qtype, DNS_C_IN)))
10797                 panic("%s: %s", MAIN.qname, dns_strerror(error));
10798
10799         while ((error = dns_res_check(R))) {
10800                 if (error != DNS_EAGAIN)
10801                         panic("dns_res_check: %s (%d)", dns_strerror(error), error);
10802                 if (dns_res_elapsed(R) > 30)
10803                         panic("query timed-out");
10804
10805                 dns_res_poll(R, 1);
10806         }
10807
10808         ans = dns_res_fetch(R, &error);
10809         print_packet(ans, stdout);
10810         free(ans);
10811
10812         st = dns_res_stat(R);
10813         putchar('\n');
10814         printf(";; queries:  %"PRIuZ"\n", st->queries);
10815         printf(";; udp sent: %"PRIuZ" in %"PRIuZ" bytes\n", st->udp.sent.count, st->udp.sent.bytes);
10816         printf(";; udp rcvd: %"PRIuZ" in %"PRIuZ" bytes\n", st->udp.rcvd.count, st->udp.rcvd.bytes);
10817         printf(";; tcp sent: %"PRIuZ" in %"PRIuZ" bytes\n", st->tcp.sent.count, st->tcp.sent.bytes);
10818         printf(";; tcp rcvd: %"PRIuZ" in %"PRIuZ" bytes\n", st->tcp.rcvd.count, st->tcp.rcvd.bytes);
10819
10820         dns_res_close(R);
10821
10822         return 0;
10823 } /* resolve_query() */
10824
10825
10826 static int resolve_addrinfo(int argc DNS_NOTUSED, char *argv[]) {
10827         _Bool recurse = !!strstr(argv[0], "recurse");
10828         struct dns_hints *(*hints)() = (recurse)? &dns_hints_root : &dns_hints_local;
10829         struct dns_resolver *res = NULL;
10830         struct dns_addrinfo *ai = NULL;
10831         struct addrinfo ai_hints = { .ai_family = PF_UNSPEC, .ai_socktype = SOCK_STREAM, .ai_flags = AI_CANONNAME };
10832         struct addrinfo *ent;
10833         char pretty[512];
10834         int error;
10835
10836         if (!MAIN.qname)
10837                 MAIN.qname = "www.google.com";
10838         /* NB: MAIN.qtype of 0 means obey hints.ai_family */
10839
10840         resconf()->options.recurse = recurse;
10841
10842         if (!(res = dns_res_open(resconf(), hosts(), dns_hints_mortal(hints(resconf(), &error)), cache(), dns_opts(), &error)))
10843                 panic("%s: %s", MAIN.qname, dns_strerror(error));
10844
10845         if (!(ai = dns_ai_open(MAIN.qname, "80", MAIN.qtype, &ai_hints, res, &error)))
10846                 panic("%s: %s", MAIN.qname, dns_strerror(error));
10847
10848         dns_ai_settrace(ai, trace("w+b"));
10849
10850         do {
10851                 switch (error = dns_ai_nextent(&ent, ai)) {
10852                 case 0:
10853                         dns_ai_print(pretty, sizeof pretty, ent, ai);
10854
10855                         fputs(pretty, stdout);
10856
10857                         free(ent);
10858
10859                         break;
10860                 case ENOENT:
10861                         break;
10862                 case DNS_EAGAIN:
10863                         if (dns_ai_elapsed(ai) > 30)
10864                                 panic("query timed-out");
10865
10866                         dns_ai_poll(ai, 1);
10867
10868                         break;
10869                 default:
10870                         panic("dns_ai_nextent: %s (%d)", dns_strerror(error), error);
10871                 }
10872         } while (error != ENOENT);
10873
10874         dns_res_close(res);
10875         dns_ai_close(ai);
10876
10877         return 0;
10878 } /* resolve_addrinfo() */
10879
10880
10881 static int dump_trace(int argc DNS_NOTUSED, char *argv[]) {
10882         int error;
10883
10884         if (!MAIN.trace)
10885                 panic("no trace file specified");
10886
10887         if ((error = dns_trace_dump(trace("r"), stdout)))
10888                 panic("dump_trace: %s", dns_strerror(error));
10889
10890         return 0;
10891 } /* dump_trace() */
10892
10893
10894 static int echo_port(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
10895         union {
10896                 struct sockaddr sa;
10897                 struct sockaddr_in sin;
10898         } port;
10899         int fd;
10900
10901         memset(&port, 0, sizeof port);
10902         port.sin.sin_family = AF_INET;
10903         port.sin.sin_port = htons(5354);
10904         port.sin.sin_addr.s_addr = inet_addr("127.0.0.1");
10905
10906         if (-1 == (fd = socket(PF_INET, SOCK_DGRAM, 0)))
10907                 panic("socket: %s", strerror(errno));
10908
10909         if (0 != bind(fd, &port.sa, sizeof port.sa))
10910                 panic("127.0.0.1:5353: %s", dns_strerror(errno));
10911
10912         for (;;) {
10913                 struct dns_packet *pkt = dns_p_new(512);
10914                 struct sockaddr_storage ss;
10915                 socklen_t slen = sizeof ss;
10916                 ssize_t count;
10917 #if defined(MSG_WAITALL) /* MinGW issue */
10918                 int rflags = MSG_WAITALL;
10919 #else
10920                 int rflags = 0;
10921 #endif
10922
10923                 count = recvfrom(fd, (char *)pkt->data, pkt->size, rflags, (struct sockaddr *)&ss, &slen);
10924
10925                 if (!count || count < 0)
10926                         panic("recvfrom: %s", strerror(errno));
10927
10928                 pkt->end = count;
10929
10930                 dns_p_dump(pkt, stdout);
10931
10932                 (void)sendto(fd, (char *)pkt->data, pkt->end, 0, (struct sockaddr *)&ss, slen);
10933         }
10934
10935         return 0;
10936 } /* echo_port() */
10937
10938
10939 static int isection(int argc, char *argv[]) {
10940         const char *name = (argc > 1)? argv[1] : "";
10941         int type;
10942
10943         type = dns_isection(name);
10944         name = dns_strsection(type);
10945
10946         printf("%s (%d)\n", name, type);
10947
10948         return 0;
10949 } /* isection() */
10950
10951
10952 static int iclass(int argc, char *argv[]) {
10953         const char *name = (argc > 1)? argv[1] : "";
10954         int type;
10955
10956         type = dns_iclass(name);
10957         name = dns_strclass(type);
10958
10959         printf("%s (%d)\n", name, type);
10960
10961         return 0;
10962 } /* iclass() */
10963
10964
10965 static int itype(int argc, char *argv[]) {
10966         const char *name = (argc > 1)? argv[1] : "";
10967         int type;
10968
10969         type = dns_itype(name);
10970         name = dns_strtype(type);
10971
10972         printf("%s (%d)\n", name, type);
10973
10974         return 0;
10975 } /* itype() */
10976
10977
10978 static int iopcode(int argc, char *argv[]) {
10979         const char *name = (argc > 1)? argv[1] : "";
10980         int type;
10981
10982         type = dns_iopcode(name);
10983         name = dns_stropcode(type);
10984
10985         printf("%s (%d)\n", name, type);
10986
10987         return 0;
10988 } /* iopcode() */
10989
10990
10991 static int ircode(int argc, char *argv[]) {
10992         const char *name = (argc > 1)? argv[1] : "";
10993         int type;
10994
10995         type = dns_ircode(name);
10996         name = dns_strrcode(type);
10997
10998         printf("%s (%d)\n", name, type);
10999
11000         return 0;
11001 } /* ircode() */
11002
11003
11004 #define SIZE1(x) { DNS_PP_STRINGIFY(x), sizeof (x) }
11005 #define SIZE2(x, ...) SIZE1(x), SIZE1(__VA_ARGS__)
11006 #define SIZE3(x, ...) SIZE1(x), SIZE2(__VA_ARGS__)
11007 #define SIZE4(x, ...) SIZE1(x), SIZE3(__VA_ARGS__)
11008 #define SIZE(...) DNS_PP_CALL(DNS_PP_XPASTE(SIZE, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__)
11009
11010 static int sizes(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
11011         static const struct { const char *name; size_t size; } type[] = {
11012                 SIZE(struct dns_header, struct dns_packet, struct dns_rr, struct dns_rr_i),
11013                 SIZE(struct dns_a, struct dns_aaaa, struct dns_mx, struct dns_ns),
11014                 SIZE(struct dns_cname, struct dns_soa, struct dns_ptr, struct dns_srv),
11015                 SIZE(struct dns_sshfp, struct dns_txt, union dns_any),
11016                 SIZE(struct dns_resolv_conf, struct dns_hosts, struct dns_hints, struct dns_hints_i),
11017                 SIZE(struct dns_options, struct dns_socket, struct dns_resolver, struct dns_addrinfo),
11018                 SIZE(struct dns_cache), SIZE(size_t), SIZE(void *), SIZE(long)
11019         };
11020         unsigned i, max;
11021
11022         for (i = 0, max = 0; i < lengthof(type); i++)
11023                 max = DNS_PP_MAX(max, strlen(type[i].name));
11024
11025         for (i = 0; i < lengthof(type); i++)
11026                 printf("%*s : %"PRIuZ"\n", max, type[i].name, type[i].size);
11027
11028         return 0;
11029 } /* sizes() */
11030
11031
11032 static const struct { const char *cmd; int (*run)(); const char *help; } cmds[] = {
11033         { "parse-packet",       &parse_packet,          "parse binary packet from stdin" },
11034         { "parse-domain",       &parse_domain,          "anchor and iteratively cleave domain" },
11035         { "trim-domain",        &trim_domain,           "trim and anchor domain name" },
11036         { "expand-domain",      &expand_domain,         "expand domain at offset NN in packet from stdin" },
11037         { "show-resconf",       &show_resconf,          "show resolv.conf data" },
11038         { "show-hosts",         &show_hosts,            "show hosts data" },
11039         { "show-nssconf",       &show_nssconf,          "show nsswitch.conf data" },
11040         { "query-hosts",        &query_hosts,           "query A, AAAA or PTR in hosts data" },
11041         { "search-list",        &search_list,           "generate query search list from domain" },
11042         { "permute-set",        &permute_set,           "generate random permutation -> (0 .. N or N .. M)" },
11043         { "shuffle-16",         &shuffle_16,            "simple 16-bit permutation" },
11044         { "dump-random",        &dump_random,           "generate random bytes" },
11045         { "send-query",         &send_query,            "send query to host" },
11046         { "send-query-udp",     &send_query,            "send udp query to host" },
11047         { "send-query-tcp",     &send_query,            "send tcp query to host" },
11048         { "print-arpa",         &print_arpa,            "print arpa. zone name of address" },
11049         { "show-hints",         &show_hints,            "print hints: show-hints [local|root] [plain|packet]" },
11050         { "resolve-stub",       &resolve_query,         "resolve as stub resolver" },
11051         { "resolve-recurse",    &resolve_query,         "resolve as recursive resolver" },
11052         { "addrinfo-stub",      &resolve_addrinfo,      "resolve through getaddrinfo clone" },
11053         { "addrinfo-recurse",   &resolve_addrinfo,      "resolve through getaddrinfo clone" },
11054 /*      { "resolve-nameinfo",   &resolve_query,         "resolve as recursive resolver" }, */
11055         { "dump-trace",         &dump_trace,            "dump the contents of a trace file" },
11056         { "echo",               &echo_port,             "server echo mode, for nmap fuzzing" },
11057         { "isection",           &isection,              "parse section string" },
11058         { "iclass",             &iclass,                "parse class string" },
11059         { "itype",              &itype,                 "parse type string" },
11060         { "iopcode",            &iopcode,               "parse opcode string" },
11061         { "ircode",             &ircode,                "parse rcode string" },
11062         { "sizes",              &sizes,                 "print data structure sizes" },
11063 };
11064
11065
11066 static void print_usage(const char *progname, FILE *fp) {
11067         static const char *usage        =
11068                 " [OPTIONS] COMMAND [ARGS]\n"
11069                 "  -c PATH   Path to resolv.conf\n"
11070                 "  -n PATH   Path to nsswitch.conf\n"
11071                 "  -l PATH   Path to local hosts\n"
11072                 "  -z PATH   Path to zone cache\n"
11073                 "  -q QNAME  Query name\n"
11074                 "  -t QTYPE  Query type\n"
11075                 "  -s HOW    Sort records\n"
11076                 "  -S ADDR   Address of SOCKS server to use\n"
11077                 "  -P PORT   Port of SOCKS server to use\n"
11078                 "  -A USER:PASSWORD Credentials for the SOCKS server\n"
11079                 "  -f PATH   Path to trace file\n"
11080                 "  -v        Be more verbose (-vv show packets; -vvv hexdump packets)\n"
11081                 "  -V        Print version info\n"
11082                 "  -h        Print this usage message\n"
11083                 "\n";
11084         unsigned i, n, m;
11085
11086         fputs(progname, fp);
11087         fputs(usage, fp);
11088
11089         for (i = 0, m = 0; i < lengthof(cmds); i++) {
11090                 if (strlen(cmds[i].cmd) > m)
11091                         m       = strlen(cmds[i].cmd);
11092         }
11093
11094         for (i = 0; i < lengthof(cmds); i++) {
11095                 fprintf(fp, "  %s  ", cmds[i].cmd);
11096
11097                 for (n = strlen(cmds[i].cmd); n < m; n++)
11098                         putc(' ', fp);
11099
11100                 fputs(cmds[i].help, fp);
11101                 putc('\n', fp);
11102         }
11103
11104         fputs("\nReport bugs to William Ahern <william@25thandClement.com>\n", fp);
11105 } /* print_usage() */
11106
11107
11108 static void print_version(const char *progname, FILE *fp) {
11109         fprintf(fp, "%s (dns.c) %.8X\n", progname, dns_v_rel());
11110         fprintf(fp, "vendor  %s\n", dns_vendor());
11111         fprintf(fp, "release %.8X\n", dns_v_rel());
11112         fprintf(fp, "abi     %.8X\n", dns_v_abi());
11113         fprintf(fp, "api     %.8X\n", dns_v_api());
11114 } /* print_version() */
11115
11116
11117 static void main_exit(void) {
11118         dns_trace_close(MAIN.memo.trace);
11119         MAIN.memo.trace = NULL;
11120         dns_hosts_close(MAIN.memo.hosts);
11121         MAIN.memo.hosts = NULL;
11122         dns_resconf_close(MAIN.memo.resconf);
11123         MAIN.memo.resconf = NULL;
11124 } /* main_exit() */
11125
11126 int main(int argc, char **argv) {
11127         extern int optind;
11128         extern char *optarg;
11129         const char *progname    = argv[0];
11130         unsigned i;
11131         int ch;
11132
11133         atexit(&main_exit);
11134
11135         while (-1 != (ch = getopt(argc, argv, "q:t:c:n:l:z:s:S:P:A:f:vVh"))) {
11136                 switch (ch) {
11137                 case 'c':
11138                         assert(MAIN.resconf.count < lengthof(MAIN.resconf.path));
11139
11140                         MAIN.resconf.path[MAIN.resconf.count++] = optarg;
11141
11142                         break;
11143                 case 'n':
11144                         assert(MAIN.nssconf.count < lengthof(MAIN.nssconf.path));
11145
11146                         MAIN.nssconf.path[MAIN.nssconf.count++] = optarg;
11147
11148                         break;
11149                 case 'l':
11150                         assert(MAIN.hosts.count < lengthof(MAIN.hosts.path));
11151
11152                         MAIN.hosts.path[MAIN.hosts.count++]     = optarg;
11153
11154                         break;
11155                 case 'z':
11156                         assert(MAIN.cache.count < lengthof(MAIN.cache.path));
11157
11158                         MAIN.cache.path[MAIN.cache.count++]     = optarg;
11159
11160                         break;
11161                 case 'q':
11162                         MAIN.qname      = optarg;
11163
11164                         break;
11165                 case 't':
11166                         for (i = 0; i < lengthof(dns_rrtypes); i++) {
11167                                 if (0 == strcasecmp(dns_rrtypes[i].name, optarg))
11168                                         { MAIN.qtype = dns_rrtypes[i].type; break; }
11169                         }
11170
11171                         if (MAIN.qtype)
11172                                 break;
11173
11174                         for (i = 0; dns_isdigit(optarg[i]); i++) {
11175                                 MAIN.qtype      *= 10;
11176                                 MAIN.qtype      += optarg[i] - '0';
11177                         }
11178
11179                         if (!MAIN.qtype)
11180                                 panic("%s: invalid query type", optarg);
11181
11182                         break;
11183                 case 's':
11184                         if (0 == strcasecmp(optarg, "packet"))
11185                                 MAIN.sort       = &dns_rr_i_packet;
11186                         else if (0 == strcasecmp(optarg, "shuffle"))
11187                                 MAIN.sort       = &dns_rr_i_shuffle;
11188                         else if (0 == strcasecmp(optarg, "order"))
11189                                 MAIN.sort       = &dns_rr_i_order;
11190                         else
11191                                 panic("%s: invalid sort method", optarg);
11192
11193                         break;
11194                 case 'S': {
11195                         dns_error_t error;
11196                         struct dns_resolv_conf *conf = resconf();
11197                         conf->options.tcp = DNS_RESCONF_TCP_SOCKS;
11198
11199                         MAIN.socks_host.ss_family = (strchr(optarg, ':')) ? AF_INET6 : AF_INET;
11200                         if ((error = dns_pton(MAIN.socks_host.ss_family, optarg,
11201                                               dns_sa_addr(MAIN.socks_host.ss_family,
11202                                                           &MAIN.socks_host, NULL))))
11203                                 panic("%s: %s", optarg, dns_strerror(error));
11204
11205                         *dns_sa_port(MAIN.socks_host.ss_family, &MAIN.socks_host) = htons(1080);
11206
11207                         break;
11208                 }
11209                 case 'P':
11210                         if (! MAIN.socks_host.ss_family)
11211                                 panic("-P without prior -S");
11212                         *dns_sa_port(MAIN.socks_host.ss_family, &MAIN.socks_host) = htons(atoi(optarg));
11213
11214                         break;
11215                 case 'A': {
11216                         char *password;
11217                         if (! MAIN.socks_host.ss_family)
11218                                 panic("-A without prior -S");
11219                         if (! (password = strchr(optarg, ':')))
11220                                 panic("Usage: -A USER:PASSWORD");
11221                         *password = 0;
11222                         password += 1;
11223                         MAIN.socks_user = optarg;
11224                         MAIN.socks_password = password;
11225                         break;
11226                 }
11227                 case 'f':
11228                         MAIN.trace = optarg;
11229
11230                         break;
11231                 case 'v':
11232                         dns_debug = ++MAIN.verbose;
11233
11234                         break;
11235                 case 'V':
11236                         print_version(progname, stdout);
11237
11238                         return 0;
11239                 case 'h':
11240                         print_usage(progname, stdout);
11241
11242                         return 0;
11243                 default:
11244                         print_usage(progname, stderr);
11245
11246                         return EXIT_FAILURE;
11247                 } /* switch() */
11248         } /* while() */
11249
11250         argc    -= optind;
11251         argv    += optind;
11252
11253         for (i = 0; i < lengthof(cmds) && argv[0]; i++) {
11254                 if (0 == strcmp(cmds[i].cmd, argv[0]))
11255                         return cmds[i].run(argc, argv);
11256         }
11257
11258         print_usage(progname, stderr);
11259
11260         return EXIT_FAILURE;
11261 } /* main() */
11262
11263
11264 #endif /* DNS_MAIN */
11265
11266
11267 /*
11268  * pop file-scoped compiler annotations
11269  */
11270 #if __clang__
11271 #pragma clang diagnostic pop
11272 #elif DNS_GNUC_PREREQ(4,6,0)
11273 #pragma GCC diagnostic pop
11274 #endif