dirmngr: Make sure Tor mode is also set for DNS on SIGHUP.
[gnupg.git] / dirmngr / dns.c
1 /* ==========================================================================
2  * dns.c - Recursive, Reentrant DNS Resolver.
3  * --------------------------------------------------------------------------
4  * Copyright (c) 2008, 2009, 2010, 2012-2016  William Ahern
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to permit
11  * persons to whom the Software is furnished to do so, subject to the
12  * following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included
15  * in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
20  * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
21  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
23  * USE OR OTHER DEALINGS IN THE SOFTWARE.
24  * ==========================================================================
25  */
26 #if HAVE_CONFIG_H
27 #include "config.h"
28 #elif !defined _GNU_SOURCE
29 #define _GNU_SOURCE 1
30 #endif
31
32 #include <limits.h>             /* INT_MAX */
33 #include <stdarg.h>             /* va_list va_start va_end */
34 #include <stddef.h>             /* offsetof() */
35 #ifdef _WIN32
36 /* JW: This breaks our mingw build: #define uint32_t unsigned int */
37 #else
38 #include <stdint.h>             /* uint32_t */
39 #endif
40 #include <stdlib.h>             /* malloc(3) realloc(3) free(3) rand(3) random(3) arc4random(3) */
41 #include <stdio.h>              /* FILE fopen(3) fclose(3) getc(3) rewind(3) vsnprintf(3) */
42 #include <string.h>             /* memcpy(3) strlen(3) memmove(3) memchr(3) memcmp(3) strchr(3) strsep(3) strcspn(3) */
43 #include <strings.h>            /* strcasecmp(3) strncasecmp(3) */
44 #include <ctype.h>              /* isspace(3) isdigit(3) */
45 #include <time.h>               /* time_t time(2) difftime(3) */
46 #include <signal.h>             /* SIGPIPE sigemptyset(3) sigaddset(3) sigpending(2) sigprocmask(2) pthread_sigmask(3) sigtimedwait(2) */
47 #include <errno.h>              /* errno EINVAL ENOENT */
48 #undef NDEBUG
49 #include <assert.h>             /* assert(3) */
50
51 #if _WIN32
52 #ifndef FD_SETSIZE
53 #define FD_SETSIZE 1024
54 #endif
55 #include <winsock2.h>
56 #include <ws2tcpip.h>
57 #else
58 #include <sys/time.h>           /* gettimeofday(2) */
59 #include <sys/types.h>          /* FD_SETSIZE socklen_t */
60 #include <sys/select.h>         /* FD_ZERO FD_SET fd_set select(2) */
61 #include <sys/socket.h>         /* AF_INET AF_INET6 AF_UNIX struct sockaddr struct sockaddr_in struct sockaddr_in6 socket(2) */
62 #if defined(AF_UNIX)
63 #include <sys/un.h>             /* struct sockaddr_un */
64 #endif
65 #include <fcntl.h>              /* F_SETFD F_GETFL F_SETFL O_NONBLOCK fcntl(2) */
66 #include <unistd.h>             /* _POSIX_THREADS gethostname(3) close(2) */
67 #include <poll.h>               /* POLLIN POLLOUT */
68 #include <netinet/in.h>         /* struct sockaddr_in struct sockaddr_in6 */
69 #include <arpa/inet.h>          /* inet_pton(3) inet_ntop(3) htons(3) ntohs(3) */
70 #include <netdb.h>              /* struct addrinfo */
71 #endif
72
73 #include "dns.h"
74
75
76 /*
77  * C O M P I L E R  V E R S I O N  &  F E A T U R E  D E T E C T I O N
78  *
79  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
80
81 #define DNS_GNUC_2VER(M, m, p) (((M) * 10000) + ((m) * 100) + (p))
82 #define DNS_GNUC_PREREQ(M, m, p) (__GNUC__ > 0 && DNS_GNUC_2VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) >= DNS_GNUC_2VER((M), (m), (p)))
83
84 #define DNS_MSC_2VER(M, m, p) ((((M) + 6) * 10000000) + ((m) * 1000000) + (p))
85 #define DNS_MSC_PREREQ(M, m, p) (_MSC_VER_FULL > 0 && _MSC_VER_FULL >= DNS_MSC_2VER((M), (m), (p)))
86
87 #define DNS_SUNPRO_PREREQ(M, m, p) (__SUNPRO_C > 0 && __SUNPRO_C >= 0x ## M ## m ## p)
88
89 #if defined __has_builtin
90 #define dns_has_builtin(x) __has_builtin(x)
91 #else
92 #define dns_has_builtin(x) 0
93 #endif
94
95 #if defined __has_extension
96 #define dns_has_extension(x) __has_extension(x)
97 #else
98 #define dns_has_extension(x) 0
99 #endif
100
101 #ifndef HAVE___ASSUME
102 #define HAVE___ASSUME DNS_MSC_PREREQ(8,0,0)
103 #endif
104
105 #ifndef HAVE___BUILTIN_TYPES_COMPATIBLE_P
106 #define HAVE___BUILTIN_TYPES_COMPATIBLE_P (DNS_GNUC_PREREQ(3,1,1) || __clang__)
107 #endif
108
109 #ifndef HAVE___BUILTIN_UNREACHABLE
110 #define HAVE___BUILTIN_UNREACHABLE (DNS_GNUC_PREREQ(4,5,0) || dns_has_builtin(__builtin_unreachable))
111 #endif
112
113 #ifndef HAVE_PRAGMA_MESSAGE
114 #define HAVE_PRAGMA_MESSAGE (DNS_GNUC_PREREQ(4,4,0) || __clang__ || _MSC_VER)
115 #endif
116
117
118 /*
119  * C O M P I L E R  A N N O T A T I O N S
120  *
121  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
122
123 #if __GNUC__
124 #define DNS_NOTUSED __attribute__((unused))
125 #define DNS_NORETURN __attribute__((noreturn))
126 #else
127 #define DNS_NOTUSED
128 #define DNS_NORETURN
129 #endif
130
131 #if __clang__
132 #pragma clang diagnostic push
133 #pragma clang diagnostic ignored "-Wunused-parameter"
134 #pragma clang diagnostic ignored "-Wmissing-field-initializers"
135 #elif DNS_GNUC_PREREQ(4,6,0)
136 #pragma GCC diagnostic push
137 #pragma GCC diagnostic ignored "-Wunused-parameter"
138 #pragma GCC diagnostic ignored "-Wmissing-field-initializers"
139 #endif
140
141
142 /*
143  * S T A N D A R D  M A C R O S
144  *
145  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
146
147 #if HAVE___BUILTIN_TYPES_COMPATIBLE_P
148 #define dns_same_type(a, b, def) __builtin_types_compatible_p(__typeof__ (a), __typeof__ (b))
149 #else
150 #define dns_same_type(a, b, def) (def)
151 #endif
152 #define dns_isarray(a) (!dns_same_type((a), (&(a)[0]), 0))
153 /* NB: "_" field silences Sun Studio "zero-sized struct/union" error diagnostic */
154 #define dns_inline_assert(cond) ((void)(sizeof (struct { int:-!(cond); int _; })))
155
156 #if HAVE___ASSUME
157 #define dns_assume(cond) __assume(cond)
158 #elif HAVE___BUILTIN_UNREACHABLE
159 #define dns_assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0)
160 #else
161 #define dns_assume(cond) do { (void)(cond); } while (0)
162 #endif
163
164 #ifndef lengthof
165 #define lengthof(a) (dns_inline_assert(dns_isarray(a)), (sizeof (a) / sizeof (a)[0]))
166 #endif
167
168 #ifndef endof
169 #define endof(a) (dns_inline_assert(dns_isarray(a)), &(a)[lengthof((a))])
170 #endif
171
172
173 /*
174  * M I S C E L L A N E O U S  C O M P A T
175  *
176  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
177
178 #if _WIN32 || _WIN64
179 #define PRIuZ "Iu"
180 #else
181 #define PRIuZ "zu"
182 #endif
183
184 #ifndef DNS_THREAD_SAFE
185 #if (defined _REENTRANT || defined _THREAD_SAFE) && _POSIX_THREADS > 0
186 #define DNS_THREAD_SAFE 1
187 #else
188 #define DNS_THREAD_SAFE 0
189 #endif
190 #endif
191
192 #ifndef HAVE__STATIC_ASSERT
193 #define HAVE__STATIC_ASSERT \
194         (dns_has_extension(c_static_assert) || DNS_GNUC_PREREQ(4,6,0) || \
195          __C11FEATURES__ || __STDC_VERSION__ >= 201112L)
196 #endif
197
198 #ifndef HAVE_STATIC_ASSERT
199 #if DNS_GNUC_PREREQ(0,0,0) && !DNS_GNUC_PREREQ(4,6,0)
200 #define HAVE_STATIC_ASSERT 0 /* glibc doesn't check GCC version */
201 #else
202 #define HAVE_STATIC_ASSERT (defined static_assert)
203 #endif
204 #endif
205
206 #if HAVE_STATIC_ASSERT
207 #define dns_static_assert(cond, msg) static_assert(cond, msg)
208 #elif HAVE__STATIC_ASSERT
209 #define dns_static_assert(cond, msg) _Static_assert(cond, msg)
210 #else
211 #define dns_static_assert(cond, msg) extern char DNS_PP_XPASTE(dns_assert_, __LINE__)[sizeof (int[1 - 2*!(cond)])]
212 #endif
213
214
215 /*
216  * D E B U G  M A C R O S
217  *
218  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
219
220 int *dns_debug_p(void) {
221         static int debug;
222
223         return &debug;
224 } /* dns_debug_p() */
225
226 #if DNS_DEBUG
227
228 #undef DNS_DEBUG
229 #define DNS_DEBUG dns_debug
230
231 #define DNS_SAY_(fmt, ...) \
232         do { if (DNS_DEBUG > 0) fprintf(stderr, fmt "%.1s", __func__, __LINE__, __VA_ARGS__); } while (0)
233 #define DNS_SAY(...) DNS_SAY_("@@ (%s:%d) " __VA_ARGS__, "\n")
234 #define DNS_HAI DNS_SAY("HAI")
235
236 #define DNS_SHOW_(P, fmt, ...)  do {                                    \
237         if (DNS_DEBUG > 1) {                                            \
238         fprintf(stderr, "@@ BEGIN * * * * * * * * * * * *\n");          \
239         fprintf(stderr, "@@ " fmt "%.0s\n", __VA_ARGS__);               \
240         dns_p_dump((P), stderr);                                        \
241         fprintf(stderr, "@@ END * * * * * * * * * * * * *\n\n");        \
242         }                                                               \
243 } while (0)
244
245 #define DNS_SHOW(...)   DNS_SHOW_(__VA_ARGS__, "")
246
247 #else /* !DNS_DEBUG */
248
249 #undef DNS_DEBUG
250 #define DNS_DEBUG 0
251
252 #define DNS_SAY(...)
253 #define DNS_HAI
254 #define DNS_SHOW(...)
255
256 #endif /* DNS_DEBUG */
257
258 #define DNS_CARP(...) DNS_SAY(__VA_ARGS__)
259
260
261 /*
262  * V E R S I O N  R O U T I N E S
263  *
264  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
265
266 const char *dns_vendor(void) {
267         return DNS_VENDOR;
268 } /* dns_vendor() */
269
270
271 int dns_v_rel(void) {
272         return DNS_V_REL;
273 } /* dns_v_rel() */
274
275
276 int dns_v_abi(void) {
277         return DNS_V_ABI;
278 } /* dns_v_abi() */
279
280
281 int dns_v_api(void) {
282         return DNS_V_API;
283 } /* dns_v_api() */
284
285
286 /*
287  * E R R O R  R O U T I N E S
288  *
289  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
290
291 #if _WIN32
292
293 #define DNS_EINTR       WSAEINTR
294 #define DNS_EINPROGRESS WSAEINPROGRESS
295 #define DNS_EISCONN     WSAEISCONN
296 #define DNS_EWOULDBLOCK WSAEWOULDBLOCK
297 #define DNS_EALREADY    WSAEALREADY
298 #define DNS_EAGAIN      EAGAIN
299 #define DNS_ETIMEDOUT   WSAETIMEDOUT
300
301 #define dns_syerr()     ((int)GetLastError())
302 #define dns_soerr()     ((int)WSAGetLastError())
303
304 #else
305
306 #define DNS_EINTR       EINTR
307 #define DNS_EINPROGRESS EINPROGRESS
308 #define DNS_EISCONN     EISCONN
309 #define DNS_EWOULDBLOCK EWOULDBLOCK
310 #define DNS_EALREADY    EALREADY
311 #define DNS_EAGAIN      EAGAIN
312 #define DNS_ETIMEDOUT   ETIMEDOUT
313
314 #define dns_syerr()     errno
315 #define dns_soerr()     errno
316
317 #endif
318
319
320 const char *dns_strerror(int error) {
321         switch (error) {
322         case DNS_ENOBUFS:
323                 return "DNS packet buffer too small";
324         case DNS_EILLEGAL:
325                 return "Illegal DNS RR name or data";
326         case DNS_EORDER:
327                 return "Attempt to push RR out of section order";
328         case DNS_ESECTION:
329                 return "Invalid section specified";
330         case DNS_EUNKNOWN:
331                 return "Unknown DNS error";
332         case DNS_EADDRESS:
333                 return "Invalid textual address form";
334         case DNS_ENOQUERY:
335                 return "Bad execution state (missing query packet)";
336         case DNS_ENOANSWER:
337                 return "Bad execution state (missing answer packet)";
338         case DNS_EFETCHED:
339                 return "Answer already fetched";
340         case DNS_ESERVICE:
341                 return "The service passed was not recognized for the specified socket type";
342         case DNS_ENONAME:
343                 return "The name does not resolve for the supplied parameters";
344         case DNS_EFAIL:
345                 return "A non-recoverable error occurred when attempting to resolve the name";
346         case DNS_ECONNFIN:
347                 return "Connection closed";
348         case DNS_EVERIFY:
349                 return "Reply failed verification";
350         default:
351                 return strerror(error);
352         } /* switch() */
353 } /* dns_strerror() */
354
355
356 /*
357  * A T O M I C  R O U T I N E S
358  *
359  * Use GCC's __atomic built-ins if possible. Unlike the __sync built-ins, we
360  * can use the preprocessor to detect API and, more importantly, ISA
361  * support. We want to avoid linking headaches where the API depends on an
362  * external library if the ISA (e.g. i386) doesn't support lockless
363  * operation.
364  *
365  * TODO: Support C11's atomic API. Although that may require some finesse
366  * with how we define some public types, such as dns_atomic_t and struct
367  * dns_resolv_conf.
368  *
369  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
370
371 #ifndef HAVE___ATOMIC_FETCH_ADD
372 #define HAVE___ATOMIC_FETCH_ADD (defined __ATOMIC_RELAXED)
373 #endif
374
375 #ifndef HAVE___ATOMIC_FETCH_SUB
376 #define HAVE___ATOMIC_FETCH_SUB HAVE___ATOMIC_FETCH_ADD
377 #endif
378
379 #ifndef DNS_ATOMIC_FETCH_ADD
380 #if HAVE___ATOMIC_FETCH_ADD && __GCC_ATOMIC_LONG_LOCK_FREE == 2
381 #define DNS_ATOMIC_FETCH_ADD(i) __atomic_fetch_add((i), 1, __ATOMIC_RELAXED)
382 #else
383 #pragma message("no atomic_fetch_add available")
384 #define DNS_ATOMIC_FETCH_ADD(i) ((*(i))++)
385 #endif
386 #endif
387
388 #ifndef DNS_ATOMIC_FETCH_SUB
389 #if HAVE___ATOMIC_FETCH_SUB && __GCC_ATOMIC_LONG_LOCK_FREE == 2
390 #define DNS_ATOMIC_FETCH_SUB(i) __atomic_fetch_sub((i), 1, __ATOMIC_RELAXED)
391 #else
392 #pragma message("no atomic_fetch_sub available")
393 #define DNS_ATOMIC_FETCH_SUB(i) ((*(i))--)
394 #endif
395 #endif
396
397 static inline unsigned dns_atomic_fetch_add(dns_atomic_t *i) {
398         return DNS_ATOMIC_FETCH_ADD(i);
399 } /* dns_atomic_fetch_add() */
400
401
402 static inline unsigned dns_atomic_fetch_sub(dns_atomic_t *i) {
403         return DNS_ATOMIC_FETCH_SUB(i);
404 } /* dns_atomic_fetch_sub() */
405
406
407 /*
408  * C R Y P T O  R O U T I N E S
409  *
410  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
411
412 /*
413  * P R N G
414  */
415
416 #ifndef DNS_RANDOM
417 #if defined(HAVE_ARC4RANDOM)    \
418  || defined(__OpenBSD__)        \
419  || defined(__FreeBSD__)        \
420  || defined(__NetBSD__)         \
421  || defined(__APPLE__)
422 #define DNS_RANDOM      arc4random
423 #elif __linux
424 #define DNS_RANDOM      random
425 #else
426 #define DNS_RANDOM      rand
427 #endif
428 #endif
429
430 #define DNS_RANDOM_arc4random   1
431 #define DNS_RANDOM_random       2
432 #define DNS_RANDOM_rand         3
433 #define DNS_RANDOM_RAND_bytes   4
434
435 #define DNS_RANDOM_OPENSSL      (DNS_RANDOM_RAND_bytes == DNS_PP_XPASTE(DNS_RANDOM_, DNS_RANDOM))
436
437 #if DNS_RANDOM_OPENSSL
438 #include <openssl/rand.h>
439 #endif
440
441 static unsigned dns_random_(void) {
442 #if DNS_RANDOM_OPENSSL
443         unsigned r;
444         _Bool ok;
445
446         ok = (1 == RAND_bytes((unsigned char *)&r, sizeof r));
447         assert(ok && "1 == RAND_bytes()");
448
449         return r;
450 #else
451         return DNS_RANDOM();
452 #endif
453 } /* dns_random_() */
454
455 dns_random_f **dns_random_p(void) {
456         static dns_random_f *random_f = &dns_random_;
457
458         return &random_f;
459 } /* dns_random_p() */
460
461
462 /*
463  * P E R M U T A T I O N  G E N E R A T O R
464  */
465
466 #define DNS_K_TEA_KEY_SIZE      16
467 #define DNS_K_TEA_BLOCK_SIZE    8
468 #define DNS_K_TEA_CYCLES        32
469 #define DNS_K_TEA_MAGIC         0x9E3779B9U
470
471 struct dns_k_tea {
472         uint32_t key[DNS_K_TEA_KEY_SIZE / sizeof (uint32_t)];
473         unsigned cycles;
474 }; /* struct dns_k_tea */
475
476
477 static void dns_k_tea_init(struct dns_k_tea *tea, uint32_t key[], unsigned cycles) {
478         memcpy(tea->key, key, sizeof tea->key);
479
480         tea->cycles     = (cycles)? cycles : DNS_K_TEA_CYCLES;
481 } /* dns_k_tea_init() */
482
483
484 static void dns_k_tea_encrypt(struct dns_k_tea *tea, uint32_t v[], uint32_t *w) {
485         uint32_t y, z, sum, n;
486
487         y       = v[0];
488         z       = v[1];
489         sum     = 0;
490
491         for (n = 0; n < tea->cycles; n++) {
492                 sum     += DNS_K_TEA_MAGIC;
493                 y       += ((z << 4) + tea->key[0]) ^ (z + sum) ^ ((z >> 5) + tea->key[1]);
494                 z       += ((y << 4) + tea->key[2]) ^ (y + sum) ^ ((y >> 5) + tea->key[3]);
495         }
496
497         w[0]    = y;
498         w[1]    = z;
499
500         return /* void */;
501 } /* dns_k_tea_encrypt() */
502
503
504 /*
505  * Permutation generator, based on a Luby-Rackoff Feistel construction.
506  *
507  * Specifically, this is a generic balanced Feistel block cipher using TEA
508  * (another block cipher) as the pseudo-random function, F. At best it's as
509  * strong as F (TEA), notwithstanding the seeding. F could be AES, SHA-1, or
510  * perhaps Bernstein's Salsa20 core; I am naively trying to keep things
511  * simple.
512  *
513  * The generator can create a permutation of any set of numbers, as long as
514  * the size of the set is an even power of 2. This limitation arises either
515  * out of an inherent property of balanced Feistel constructions, or by my
516  * own ignorance. I'll tackle an unbalanced construction after I wrap my
517  * head around Schneier and Kelsey's paper.
518  *
519  * CAVEAT EMPTOR. IANAC.
520  */
521 #define DNS_K_PERMUTOR_ROUNDS   8
522
523 struct dns_k_permutor {
524         unsigned stepi, length, limit;
525         unsigned shift, mask, rounds;
526
527         struct dns_k_tea tea;
528 }; /* struct dns_k_permutor */
529
530
531 static inline unsigned dns_k_permutor_powof(unsigned n) {
532         unsigned m, i = 0;
533
534         for (m = 1; m < n; m <<= 1, i++)
535                 ;;
536
537         return i;
538 } /* dns_k_permutor_powof() */
539
540 static void dns_k_permutor_init(struct dns_k_permutor *p, unsigned low, unsigned high) {
541         uint32_t key[DNS_K_TEA_KEY_SIZE / sizeof (uint32_t)];
542         unsigned width, i;
543
544         p->stepi        = 0;
545
546         p->length       = (high - low) + 1;
547         p->limit        = high;
548
549         width           = dns_k_permutor_powof(p->length);
550         width           += width % 2;
551
552         p->shift        = width / 2;
553         p->mask         = (1U << p->shift) - 1;
554         p->rounds       = DNS_K_PERMUTOR_ROUNDS;
555
556         for (i = 0; i < lengthof(key); i++)
557                 key[i]  = dns_random();
558
559         dns_k_tea_init(&p->tea, key, 0);
560
561         return /* void */;
562 } /* dns_k_permutor_init() */
563
564
565 static unsigned dns_k_permutor_F(struct dns_k_permutor *p, unsigned k, unsigned x) {
566         uint32_t in[DNS_K_TEA_BLOCK_SIZE / sizeof (uint32_t)], out[DNS_K_TEA_BLOCK_SIZE / sizeof (uint32_t)];
567
568         memset(in, '\0', sizeof in);
569
570         in[0]   = k;
571         in[1]   = x;
572
573         dns_k_tea_encrypt(&p->tea, in, out);
574
575         return p->mask & out[0];
576 } /* dns_k_permutor_F() */
577
578
579 static unsigned dns_k_permutor_E(struct dns_k_permutor *p, unsigned n) {
580         unsigned l[2], r[2];
581         unsigned i;
582
583         i       = 0;
584         l[i]    = p->mask & (n >> p->shift);
585         r[i]    = p->mask & (n >> 0);
586
587         do {
588                 l[(i + 1) % 2]  = r[i % 2];
589                 r[(i + 1) % 2]  = l[i % 2] ^ dns_k_permutor_F(p, i, r[i % 2]);
590
591                 i++;
592         } while (i < p->rounds - 1);
593
594         return ((l[i % 2] & p->mask) << p->shift) | ((r[i % 2] & p->mask) << 0);
595 } /* dns_k_permutor_E() */
596
597
598 DNS_NOTUSED static unsigned dns_k_permutor_D(struct dns_k_permutor *p, unsigned n) {
599         unsigned l[2], r[2];
600         unsigned i;
601
602         i               = p->rounds - 1;
603         l[i % 2]        = p->mask & (n >> p->shift);
604         r[i % 2]        = p->mask & (n >> 0);
605
606         do {
607                 i--;
608
609                 r[i % 2]        = l[(i + 1) % 2];
610                 l[i % 2]        = r[(i + 1) % 2] ^ dns_k_permutor_F(p, i, l[(i + 1) % 2]);
611         } while (i > 0);
612
613         return ((l[i % 2] & p->mask) << p->shift) | ((r[i % 2] & p->mask) << 0);
614 } /* dns_k_permutor_D() */
615
616
617 static unsigned dns_k_permutor_step(struct dns_k_permutor *p) {
618         unsigned n;
619
620         do {
621                 n       = dns_k_permutor_E(p, p->stepi++);
622         } while (n >= p->length);
623
624         return n + (p->limit + 1 - p->length);
625 } /* dns_k_permutor_step() */
626
627
628 /*
629  * Simple permutation box. Useful for shuffling rrsets from an iterator.
630  * Uses AES s-box to provide good diffusion.
631  *
632  * Seems to pass muster under runs test.
633  *
634  * $ for i in 0 1 2 3 4 5 6 7 8 9; do ./dns shuffle-16 > /tmp/out; done
635  * $ R -q -f /dev/stdin 2>/dev/null <<-EOF | awk '/p-value/{ print $8 }'
636  *      library(lawstat)
637  *      runs.test(scan(file="/tmp/out"))
638  * EOF
639  */
640 static unsigned short dns_k_shuffle16(unsigned short n, unsigned s) {
641         static const unsigned char sbox[256] =
642         { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
643           0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
644           0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
645           0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
646           0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
647           0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
648           0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
649           0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
650           0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
651           0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
652           0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
653           0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
654           0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
655           0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
656           0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
657           0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
658           0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
659           0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
660           0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
661           0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
662           0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
663           0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
664           0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
665           0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
666           0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
667           0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
668           0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
669           0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
670           0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
671           0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
672           0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
673           0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };
674         unsigned char a, b;
675         unsigned i;
676
677         a = 0xff & (n >> 0);
678         b = 0xff & (n >> 8);
679
680         for (i = 0; i < 4; i++) {
681                 a ^= 0xff & s;
682                 a = sbox[a] ^ b;
683                 b = sbox[b] ^ a;
684                 s >>= 8;
685         }
686
687         return ((0xff00 & (a << 8)) | (0x00ff & (b << 0)));
688 } /* dns_k_shuffle16() */
689
690 /*
691  * S T A T E  M A C H I N E  R O U T I N E S
692  *
693  * Application code should define DNS_SM_RESTORE and DNS_SM_SAVE, and the
694  * local variable pc.
695  *
696  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
697
698 #define DNS_SM_ENTER \
699         do { \
700         static const int pc0 = __LINE__; \
701         DNS_SM_RESTORE; \
702         switch (pc0 + pc) { \
703         case __LINE__: (void)0
704
705 #define DNS_SM_SAVE_AND_DO(do_statement) \
706         do { \
707                 pc = __LINE__ - pc0; \
708                 DNS_SM_SAVE; \
709                 do_statement; \
710                 case __LINE__: (void)0; \
711         } while (0)
712
713 #define DNS_SM_YIELD(rv) \
714         DNS_SM_SAVE_AND_DO(return (rv))
715
716 #define DNS_SM_EXIT \
717         do { goto leave; } while (0)
718
719 #define DNS_SM_LEAVE \
720         leave: (void)0; \
721         DNS_SM_SAVE_AND_DO(break); \
722         } \
723         } while (0)
724
725 /*
726  * U T I L I T Y  R O U T I N E S
727  *
728  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
729
730 #define DNS_MAXINTERVAL 300
731
732 struct dns_clock {
733         time_t sample, elapsed;
734 }; /* struct dns_clock */
735
736 static void dns_begin(struct dns_clock *clk) {
737         clk->sample = time(0);
738         clk->elapsed = 0;
739 } /* dns_begin() */
740
741 static time_t dns_elapsed(struct dns_clock *clk) {
742         time_t curtime;
743
744         if ((time_t)-1 == time(&curtime))
745                 return clk->elapsed;
746
747         if (curtime > clk->sample)
748                 clk->elapsed += (time_t)DNS_PP_MIN(difftime(curtime, clk->sample), DNS_MAXINTERVAL);
749
750         clk->sample = curtime;
751
752         return clk->elapsed;
753 } /* dns_elapsed() */
754
755
756 DNS_NOTUSED static size_t dns_strnlen(const char *src, size_t m) {
757         size_t n = 0;
758
759         while (*src++ && n < m)
760                 ++n;
761
762         return n;
763 } /* dns_strnlen() */
764
765
766 DNS_NOTUSED static size_t dns_strnlcpy(char *dst, size_t lim, const char *src, size_t max) {
767         size_t len = dns_strnlen(src, max), n;
768
769         if (lim > 0) {
770                 n = DNS_PP_MIN(lim - 1, len);
771                 memcpy(dst, src, n);
772                 dst[n] = '\0';
773         }
774
775         return len;
776 } /* dns_strnlcpy() */
777
778
779 #define DNS_HAVE_SOCKADDR_UN (defined AF_UNIX && !defined _WIN32)
780
781 static size_t dns_af_len(int af) {
782         static const size_t table[AF_MAX]       = {
783                 [AF_INET6]      = sizeof (struct sockaddr_in6),
784                 [AF_INET]       = sizeof (struct sockaddr_in),
785 #if DNS_HAVE_SOCKADDR_UN
786                 [AF_UNIX]       = sizeof (struct sockaddr_un),
787 #endif
788         };
789
790         return table[af];
791 } /* dns_af_len() */
792
793 #define dns_sa_family(sa)       (((struct sockaddr *)(sa))->sa_family)
794
795 #define dns_sa_len(sa)          dns_af_len(dns_sa_family(sa))
796
797
798 #define DNS_SA_NOPORT   &dns_sa_noport
799 static unsigned short dns_sa_noport;
800
801 static unsigned short *dns_sa_port(int af, void *sa) {
802         switch (af) {
803         case AF_INET6:
804                 return &((struct sockaddr_in6 *)sa)->sin6_port;
805         case AF_INET:
806                 return &((struct sockaddr_in *)sa)->sin_port;
807         default:
808                 return DNS_SA_NOPORT;
809         }
810 } /* dns_sa_port() */
811
812
813 static void *dns_sa_addr(int af, const void *sa, socklen_t *size) {
814         switch (af) {
815         case AF_INET6: {
816                 struct in6_addr *in6 = &((struct sockaddr_in6 *)sa)->sin6_addr;
817
818                 if (size)
819                         *size = sizeof *in6;
820
821                 return in6;
822         }
823         case AF_INET: {
824                 struct in_addr *in = &((struct sockaddr_in *)sa)->sin_addr;
825
826                 if (size)
827                         *size = sizeof *in;
828
829                 return in;
830         }
831         default:
832                 if (size)
833                         *size = 0;
834
835                 return 0;
836         }
837 } /* dns_sa_addr() */
838
839
840 #if DNS_HAVE_SOCKADDR_UN
841 #define DNS_SUNPATHMAX (sizeof ((struct sockaddr_un *)0)->sun_path)
842 #endif
843
844 DNS_NOTUSED static void *dns_sa_path(void *sa, socklen_t *size) {
845         switch (dns_sa_family(sa)) {
846 #if DNS_HAVE_SOCKADDR_UN
847         case AF_UNIX: {
848                 char *path = ((struct sockaddr_un *)sa)->sun_path;
849
850                 if (size)
851                         *size = dns_strnlen(path, DNS_SUNPATHMAX);
852
853                 return path;
854         }
855 #endif
856         default:
857                 if (size)
858                         *size = 0;
859
860                 return NULL;
861         }
862 } /* dns_sa_path() */
863
864
865 static int dns_sa_cmp(void *a, void *b) {
866         int cmp, af;
867
868         if ((cmp = dns_sa_family(a) - dns_sa_family(b)))
869                 return cmp;
870
871         switch ((af = dns_sa_family(a))) {
872         case AF_INET: {
873                 struct in_addr *a4, *b4;
874
875                 if ((cmp = htons(*dns_sa_port(af, a)) - htons(*dns_sa_port(af, b))))
876                         return cmp;
877
878                 a4 = dns_sa_addr(af, a, NULL);
879                 b4 = dns_sa_addr(af, b, NULL);
880
881                 if (ntohl(a4->s_addr) < ntohl(b4->s_addr))
882                         return -1;
883                 if (ntohl(a4->s_addr) > ntohl(b4->s_addr))
884                         return 1;
885
886                 return 0;
887         }
888         case AF_INET6: {
889                 struct in6_addr *a6, *b6;
890                 size_t i;
891
892                 if ((cmp = htons(*dns_sa_port(af, a)) - htons(*dns_sa_port(af, b))))
893                         return cmp;
894
895                 a6 = dns_sa_addr(af, a, NULL);
896                 b6 = dns_sa_addr(af, b, NULL);
897
898                 /* XXX: do we need to use in6_clearscope()? */
899                 for (i = 0; i < sizeof a6->s6_addr; i++) {
900                         if ((cmp = a6->s6_addr[i] - b6->s6_addr[i]))
901                                 return cmp;
902                 }
903
904                 return 0;
905         }
906 #if DNS_HAVE_SOCKADDR_UN
907         case AF_UNIX: {
908                 char a_path[DNS_SUNPATHMAX + 1], b_path[sizeof a_path];
909
910                 dns_strnlcpy(a_path, sizeof a_path, dns_sa_path(a, NULL), DNS_SUNPATHMAX);
911                 dns_strnlcpy(b_path, sizeof b_path, dns_sa_path(b, NULL), DNS_SUNPATHMAX);
912
913                 return strcmp(a_path, b_path);
914         }
915 #endif
916         default:
917                 return -1;
918         }
919 } /* dns_sa_cmp() */
920
921
922 #if _WIN32
923 static int dns_inet_pton(int af, const void *src, void *dst) {
924         union { struct sockaddr_in sin; struct sockaddr_in6 sin6; } u;
925
926         u.sin.sin_family        = af;
927
928         if (0 != WSAStringToAddressA((void *)src, af, (void *)0, (struct sockaddr *)&u, &(int){ sizeof u }))
929                 return -1;
930
931         switch (af) {
932         case AF_INET6:
933                 *(struct in6_addr *)dst = u.sin6.sin6_addr;
934
935                 return 1;
936         case AF_INET:
937                 *(struct in_addr *)dst  = u.sin.sin_addr;
938
939                 return 1;
940         default:
941                 return 0;
942         }
943 } /* dns_inet_pton() */
944
945 static const char *dns_inet_ntop(int af, const void *src, void *dst, unsigned long lim) {
946         union { struct sockaddr_in sin; struct sockaddr_in6 sin6; } u;
947
948         /* NOTE: WSAAddressToString will print .sin_port unless zeroed. */
949         memset(&u, 0, sizeof u);
950
951         u.sin.sin_family        = af;
952
953         switch (af) {
954         case AF_INET6:
955                 u.sin6.sin6_addr        = *(struct in6_addr *)src;
956                 break;
957         case AF_INET:
958                 u.sin.sin_addr          = *(struct in_addr *)src;
959
960                 break;
961         default:
962                 return 0;
963         }
964
965         if (0 != WSAAddressToStringA((struct sockaddr *)&u, dns_sa_len(&u), (void *)0, dst, &lim))
966                 return 0;
967
968         return dst;
969 } /* dns_inet_ntop() */
970 #else
971 #define dns_inet_pton(...)      inet_pton(__VA_ARGS__)
972 #define dns_inet_ntop(...)      inet_ntop(__VA_ARGS__)
973 #endif
974
975
976 static dns_error_t dns_pton(int af, const void *src, void *dst) {
977         switch (dns_inet_pton(af, src, dst)) {
978         case 1:
979                 return 0;
980         case -1:
981                 return dns_soerr();
982         default:
983                 return DNS_EADDRESS;
984         }
985 } /* dns_pton() */
986
987
988 static dns_error_t dns_ntop(int af, const void *src, void *dst, unsigned long lim) {
989         return (dns_inet_ntop(af, src, dst, lim))? 0 : dns_soerr();
990 } /* dns_ntop() */
991
992
993 size_t dns_strlcpy(char *dst, const char *src, size_t lim) {
994         char *d         = dst;
995         char *e         = &dst[lim];
996         const char *s   = src;
997
998         if (d < e) {
999                 do {
1000                         if ('\0' == (*d++ = *s++))
1001                                 return s - src - 1;
1002                 } while (d < e);
1003
1004                 d[-1]   = '\0';
1005         }
1006
1007         while (*s++ != '\0')
1008                 ;;
1009
1010         return s - src - 1;
1011 } /* dns_strlcpy() */
1012
1013
1014 size_t dns_strlcat(char *dst, const char *src, size_t lim) {
1015         char *d = memchr(dst, '\0', lim);
1016         char *e = &dst[lim];
1017         const char *s = src;
1018         const char *p;
1019
1020         if (d && d < e) {
1021                 do {
1022                         if ('\0' == (*d++ = *s++))
1023                                 return d - dst - 1;
1024                 } while (d < e);
1025
1026                 d[-1] = '\0';
1027         }
1028
1029         p = s;
1030
1031         while (*s++ != '\0')
1032                 ;;
1033
1034         return lim + (s - p - 1);
1035 } /* dns_strlcat() */
1036
1037
1038 static void *dns_reallocarray(void *p, size_t nmemb, size_t size, dns_error_t *error) {
1039         void *rp;
1040
1041         if (nmemb > 0 && SIZE_MAX / nmemb < size) {
1042                 *error = EOVERFLOW;
1043                 return NULL;
1044         }
1045
1046         if (!(rp = realloc(p, nmemb * size)))
1047                 *error = (errno)? errno : EINVAL;
1048
1049         return rp;
1050 } /* dns_reallocarray() */
1051
1052
1053 #if _WIN32
1054
1055 static char *dns_strsep(char **sp, const char *delim) {
1056         char *p;
1057
1058         if (!(p = *sp))
1059                 return 0;
1060
1061         *sp += strcspn(p, delim);
1062
1063         if (**sp != '\0') {
1064                 **sp = '\0';
1065                 ++*sp;
1066         } else
1067                 *sp = NULL;
1068
1069         return p;
1070 } /* dns_strsep() */
1071
1072 #else
1073 #define dns_strsep(...) strsep(__VA_ARGS__)
1074 #endif
1075
1076
1077 #if _WIN32
1078 #define strcasecmp(...)         _stricmp(__VA_ARGS__)
1079 #define strncasecmp(...)        _strnicmp(__VA_ARGS__)
1080 #endif
1081
1082
1083 static inline _Bool dns_isalpha(unsigned char c) {
1084         return isalpha(c);
1085 } /* dns_isalpha() */
1086
1087 static inline _Bool dns_isdigit(unsigned char c) {
1088         return isdigit(c);
1089 } /* dns_isdigit() */
1090
1091 static inline _Bool dns_isalnum(unsigned char c) {
1092         return isalnum(c);
1093 } /* dns_isalnum() */
1094
1095 static inline _Bool dns_isspace(unsigned char c) {
1096         return isspace(c);
1097 } /* dns_isspace() */
1098
1099 static inline _Bool dns_isgraph(unsigned char c) {
1100         return isgraph(c);
1101 } /* dns_isgraph() */
1102
1103
1104 static int dns_poll(int fd, short events, int timeout) {
1105         fd_set rset, wset;
1106
1107         if (!events)
1108                 return 0;
1109
1110         if (fd < 0 || (unsigned)fd >= FD_SETSIZE)
1111           return EINVAL;
1112
1113         FD_ZERO(&rset);
1114         FD_ZERO(&wset);
1115
1116         if (events & DNS_POLLIN)
1117                 FD_SET(fd, &rset);
1118
1119         if (events & DNS_POLLOUT)
1120                 FD_SET(fd, &wset);
1121
1122         select(fd + 1, &rset, &wset, 0, (timeout >= 0)? &(struct timeval){ timeout, 0 } : NULL);
1123
1124         return 0;
1125 } /* dns_poll() */
1126
1127
1128 #if !_WIN32
1129 DNS_NOTUSED static int dns_sigmask(int how, const sigset_t *set, sigset_t *oset) {
1130 #if DNS_THREAD_SAFE
1131         return pthread_sigmask(how, set, oset);
1132 #else
1133         return (0 == sigprocmask(how, set, oset))? 0 : errno;
1134 #endif
1135 } /* dns_sigmask() */
1136 #endif
1137
1138
1139 static size_t dns_send(int fd, const void *src, size_t len, int flags, dns_error_t *error) {
1140         long n = send(fd, src, len, flags);
1141
1142         if (n < 0) {
1143                 *error = dns_soerr();
1144                 return 0;
1145         } else {
1146                 *error = 0;
1147                 return n;
1148         }
1149 } /* dns_send() */
1150
1151 static size_t dns_recv(int fd, void *dst, size_t lim, int flags, dns_error_t *error) {
1152         long n = recv(fd, dst, lim, flags);
1153
1154         if (n < 0) {
1155                 *error = dns_soerr();
1156                 return 0;
1157         } else if (n == 0) {
1158                 *error = (lim > 0)? DNS_ECONNFIN : EINVAL;
1159                 return 0;
1160         } else {
1161                 *error = 0;
1162                 return n;
1163         }
1164 } /* dns_recv() */
1165
1166 static size_t dns_send_nopipe(int fd, const void *src, size_t len, int flags, dns_error_t *_error) {
1167 #if _WIN32 || !defined SIGPIPE || defined SO_NOSIGPIPE
1168         return dns_send(fd, src, len, flags, _error);
1169 #elif defined MSG_NOSIGNAL
1170         return dns_send(fd, src, len, (flags|MSG_NOSIGNAL), _error);
1171 #elif _POSIX_REALTIME_SIGNALS > 0 /* require sigtimedwait */
1172         /*
1173          * SIGPIPE handling similar to the approach described in
1174          * http://krokisplace.blogspot.com/2010/02/suppressing-sigpipe-in-library.html
1175          */
1176         sigset_t pending, blocked, piped;
1177         size_t count;
1178         int error;
1179
1180         sigemptyset(&pending);
1181         sigpending(&pending);
1182
1183         if (!sigismember(&pending, SIGPIPE)) {
1184                 sigemptyset(&piped);
1185                 sigaddset(&piped, SIGPIPE);
1186                 sigemptyset(&blocked);
1187
1188                 if ((error = dns_sigmask(SIG_BLOCK, &piped, &blocked)))
1189                         goto error;
1190         }
1191
1192         count = dns_send(fd, src, len, flags, &error);
1193
1194         if (!sigismember(&pending, SIGPIPE)) {
1195                 int saved = error;
1196
1197                 if (!count && error == EPIPE) {
1198                         while (-1 == sigtimedwait(&piped, NULL, &(struct timespec){ 0, 0 }) && errno == EINTR)
1199                                 ;;
1200                 }
1201
1202                 if ((error = dns_sigmask(SIG_SETMASK, &blocked, NULL)))
1203                         goto error;
1204
1205                 error = saved;
1206         }
1207
1208         *_error = error;
1209         return count;
1210 error:
1211         *_error = error;
1212         return 0;
1213 #else
1214 #error "unable to suppress SIGPIPE"
1215         return dns_send(fd, src, len, flags, _error);
1216 #endif
1217 } /* dns_send_nopipe() */
1218
1219
1220 static dns_error_t dns_connect(int fd, const struct sockaddr *addr, socklen_t addrlen) {
1221         if (0 != connect(fd, addr, addrlen))
1222                 return dns_soerr();
1223         return 0;
1224 } /* dns_connect() */
1225
1226
1227 #define DNS_FOPEN_STDFLAGS "rwabt+"
1228
1229 static dns_error_t dns_fopen_addflag(char *dst, const char *src, size_t lim, int fc) {
1230         char *p = dst, *pe = dst + lim;
1231
1232         /* copy standard flags */
1233         while (*src && strchr(DNS_FOPEN_STDFLAGS, *src)) {
1234                 if (!(p < pe))
1235                         return ENOMEM;
1236                 *p++ = *src++;
1237         }
1238
1239         /* append flag to standard flags */
1240         if (!(p < pe))
1241                 return ENOMEM;
1242         *p++ = fc;
1243
1244         /* copy remaining mode string, including '\0' */
1245         do {
1246                 if (!(p < pe))
1247                         return ENOMEM;
1248         } while ((*p++ = *src++));
1249
1250         return 0;
1251 } /* dns_fopen_addflag() */
1252
1253 static FILE *dns_fopen(const char *path, const char *mode, dns_error_t *_error) {
1254         FILE *fp;
1255         char mode_cloexec[32];
1256         int error;
1257
1258         assert(path && mode && *mode);
1259         if (!*path) {
1260                 error = EINVAL;
1261                 goto error;
1262         }
1263
1264 #if _WIN32 || _WIN64
1265         if ((error = dns_fopen_addflag(mode_cloexec, mode, sizeof mode_cloexec, 'N')))
1266                 goto error;
1267         if (!(fp = fopen(path, mode_cloexec)))
1268                 goto syerr;
1269 #else
1270         if ((error = dns_fopen_addflag(mode_cloexec, mode, sizeof mode_cloexec, 'e')))
1271                 goto error;
1272         if (!(fp = fopen(path, mode_cloexec))) {
1273                 if (errno != EINVAL)
1274                         goto syerr;
1275                 if (!(fp = fopen(path, mode)))
1276                         goto syerr;
1277         }
1278 #endif
1279
1280         return fp;
1281 syerr:
1282         error = dns_syerr();
1283 error:
1284         *_error = error;
1285
1286         return NULL;
1287 } /* dns_fopen() */
1288
1289
1290 struct dns_hxd_lines_i {
1291         int pc;
1292         size_t p;
1293 };
1294
1295 #define DNS_SM_RESTORE \
1296         do { \
1297                 pc = state->pc; \
1298                 sp = src + state->p; \
1299                 se = src + len; \
1300         } while (0)
1301 #define DNS_SM_SAVE \
1302         do { \
1303                 state->p = sp - src; \
1304                 state->pc = pc; \
1305         } while (0)
1306
1307 static size_t dns_hxd_lines(void *dst, size_t lim, const unsigned char *src, size_t len, struct dns_hxd_lines_i *state) {
1308         static const unsigned char hex[] = "0123456789abcdef";
1309         static const unsigned char tmpl[] = "                                                    |                |\n";
1310         unsigned char ln[sizeof tmpl];
1311         const unsigned char *sp, *se;
1312         unsigned char *h, *g;
1313         unsigned i, n;
1314         int pc;
1315
1316         DNS_SM_ENTER;
1317
1318         while (sp < se) {
1319                 memcpy(ln, tmpl, sizeof ln);
1320
1321                 h = &ln[2];
1322                 g = &ln[53];
1323
1324                 for (n = 0; n < 2; n++) {
1325                         for (i = 0; i < 8 && se - sp > 0; i++, sp++) {
1326                                 h[0] = hex[0x0f & (*sp >> 4)];
1327                                 h[1] = hex[0x0f & (*sp >> 0)];
1328                                 h += 3;
1329
1330                                 *g++ = (dns_isgraph(*sp))? *sp : '.';
1331                         }
1332
1333                         h++;
1334                 }
1335
1336                 n = dns_strlcpy(dst, (char *)ln, lim);
1337                 DNS_SM_YIELD(n);
1338         }
1339
1340         DNS_SM_EXIT;
1341         DNS_SM_LEAVE;
1342
1343         return 0;
1344 }
1345
1346 #undef DNS_SM_SAVE
1347 #undef DNS_SM_RESTORE
1348
1349 /*
1350  * A R I T H M E T I C  R O U T I N E S
1351  *
1352  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1353
1354 #define DNS_CHECK_OVERFLOW(error, r, f, ...) \
1355         do { \
1356                 uintmax_t _r; \
1357                 *(error) = f(&_r, __VA_ARGS__); \
1358                 *(r) = _r; \
1359         } while (0)
1360
1361 static dns_error_t dns_clamp_overflow(uintmax_t *r, uintmax_t n, uintmax_t clamp) {
1362         if (n > clamp) {
1363                 *r = clamp;
1364                 return ERANGE;
1365         } else {
1366                 *r = n;
1367                 return 0;
1368         }
1369 } /* dns_clamp_overflow() */
1370
1371 static dns_error_t dns_add_overflow(uintmax_t *r, uintmax_t a, uintmax_t b, uintmax_t clamp) {
1372         if (~a < b) {
1373                 *r = DNS_PP_MIN(clamp, ~UINTMAX_C(0));
1374                 return ERANGE;
1375         } else {
1376                 return dns_clamp_overflow(r, a + b, clamp);
1377         }
1378 } /* dns_add_overflow() */
1379
1380 static dns_error_t dns_mul_overflow(uintmax_t *r, uintmax_t a, uintmax_t b, uintmax_t clamp) {
1381         if (a > 0 && UINTMAX_MAX / a < b) {
1382                 *r = DNS_PP_MIN(clamp, ~UINTMAX_C(0));
1383                 return ERANGE;
1384         } else {
1385                 return dns_clamp_overflow(r, a * b, clamp);
1386         }
1387 } /* dns_mul_overflow() */
1388
1389 /*
1390  * F I X E D - S I Z E D  B U F F E R  R O U T I N E S
1391  *
1392  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1393
1394 #define DNS_B_INIT(src, n) { \
1395         (unsigned char *)(src), \
1396         (unsigned char *)(src), \
1397         (unsigned char *)(src) + (n), \
1398 }
1399
1400 #define DNS_B_FROM(src, n) DNS_B_INIT((src), (n))
1401 #define DNS_B_INTO(src, n) DNS_B_INIT((src), (n))
1402
1403 struct dns_buf {
1404         const unsigned char *base;
1405         unsigned char *p;
1406         const unsigned char *pe;
1407         dns_error_t error;
1408         size_t overflow;
1409 }; /* struct dns_buf */
1410
1411 static inline size_t
1412 dns_b_tell(struct dns_buf *b)
1413 {
1414         return b->p - b->base;
1415 }
1416
1417 static inline dns_error_t
1418 dns_b_setoverflow(struct dns_buf *b, size_t n, dns_error_t error)
1419 {
1420         b->overflow += n;
1421         return b->error = error;
1422 }
1423
1424 DNS_NOTUSED static struct dns_buf *
1425 dns_b_into(struct dns_buf *b, void *src, size_t n)
1426 {
1427         *b = (struct dns_buf)DNS_B_INTO(src, n);
1428
1429         return b;
1430 }
1431
1432 static dns_error_t
1433 dns_b_putc(struct dns_buf *b, unsigned char uc)
1434 {
1435         if (!(b->p < b->pe))
1436                 return dns_b_setoverflow(b, 1, DNS_ENOBUFS);
1437
1438         *b->p++ = uc;
1439
1440         return 0;
1441 }
1442
1443 static dns_error_t
1444 dns_b_pputc(struct dns_buf *b, unsigned char uc, size_t p)
1445 {
1446         size_t pe = b->pe - b->base;
1447         if (pe <= p)
1448                 return dns_b_setoverflow(b, p - pe + 1, DNS_ENOBUFS);
1449
1450         *((unsigned char *)b->base + p) = uc;
1451
1452         return 0;
1453 }
1454
1455 static inline dns_error_t
1456 dns_b_put16(struct dns_buf *b, uint16_t u)
1457 {
1458         return dns_b_putc(b, u >> 8), dns_b_putc(b, u >> 0);
1459 }
1460
1461 static inline dns_error_t
1462 dns_b_pput16(struct dns_buf *b, uint16_t u, size_t p)
1463 {
1464         if (dns_b_pputc(b, u >> 8, p) || dns_b_pputc(b, u >> 0, p + 1))
1465                 return b->error;
1466
1467         return 0;
1468 }
1469
1470 DNS_NOTUSED static inline dns_error_t
1471 dns_b_put32(struct dns_buf *b, uint32_t u)
1472 {
1473         return dns_b_putc(b, u >> 24), dns_b_putc(b, u >> 16),
1474             dns_b_putc(b, u >> 8), dns_b_putc(b, u >> 0);
1475 }
1476
1477 static dns_error_t
1478 dns_b_put(struct dns_buf *b, const void *src, size_t len)
1479 {
1480         size_t n = DNS_PP_MIN((size_t)(b->pe - b->p), len);
1481
1482         memcpy(b->p, src, n);
1483         b->p += n;
1484
1485         if (n < len)
1486                 return dns_b_setoverflow(b, len - n, DNS_ENOBUFS);
1487
1488         return 0;
1489 }
1490
1491 static dns_error_t
1492 dns_b_puts(struct dns_buf *b, const void *src)
1493 {
1494         return dns_b_put(b, src, strlen(src));
1495 }
1496
1497 DNS_NOTUSED static inline dns_error_t
1498 dns_b_fmtju(struct dns_buf *b, const uintmax_t u, const unsigned width)
1499 {
1500         size_t digits, padding, overflow;
1501         uintmax_t r;
1502         unsigned char *tp, *te, tc;
1503
1504         digits = 0;
1505         r = u;
1506         do {
1507                 digits++;
1508                 r /= 10;
1509         } while (r);
1510
1511         padding = width - DNS_PP_MIN(digits, width);
1512         overflow = (digits + padding) - DNS_PP_MIN((size_t)(b->pe - b->p), (digits + padding));
1513
1514         while (padding--) {
1515                 dns_b_putc(b, '0');
1516         }
1517
1518         digits = 0;
1519         tp = b->p;
1520         r = u;
1521         do {
1522                 if (overflow < ++digits)
1523                         dns_b_putc(b, '0' + (r % 10));
1524                 r /= 10;
1525         } while (r);
1526
1527         te = b->p;
1528         while (tp < te) {
1529                 tc = *--te;
1530                 *te = *tp;
1531                 *tp++ = tc;
1532         }
1533
1534         return b->error;
1535 }
1536
1537 static void
1538 dns_b_popc(struct dns_buf *b)
1539 {
1540         if (b->overflow && !--b->overflow)
1541                 b->error = 0;
1542         if (b->p > b->base)
1543                 b->p--;
1544 }
1545
1546 static inline const char *
1547 dns_b_tolstring(struct dns_buf *b, size_t *n)
1548 {
1549         if (b->p < b->pe) {
1550                 *b->p = '\0';
1551                 *n = b->p - b->base;
1552
1553                 return (const char *)b->base;
1554         } else if (b->p > b->base) {
1555                 if (b->p[-1] != '\0') {
1556                         dns_b_setoverflow(b, 1, DNS_ENOBUFS);
1557                         b->p[-1] = '\0';
1558                 }
1559                 *n = &b->p[-1] - b->base;
1560
1561                 return (const char *)b->base;
1562         } else {
1563                 *n = 0;
1564
1565                 return "";
1566         }
1567 }
1568
1569 static inline const char *
1570 dns_b_tostring(struct dns_buf *b)
1571 {
1572         size_t n;
1573         return dns_b_tolstring(b, &n);
1574 }
1575
1576 static inline size_t
1577 dns_b_strlen(struct dns_buf *b)
1578 {
1579         size_t n;
1580         dns_b_tolstring(b, &n);
1581         return n;
1582 }
1583
1584 static inline size_t
1585 dns_b_strllen(struct dns_buf *b)
1586 {
1587         size_t n = dns_b_strlen(b);
1588         return n + b->overflow;
1589 }
1590
1591 DNS_NOTUSED static const struct dns_buf *
1592 dns_b_from(const struct dns_buf *b, const void *src, size_t n)
1593 {
1594         *(struct dns_buf *)b = (struct dns_buf)DNS_B_FROM(src, n);
1595
1596         return b;
1597 }
1598
1599 static inline int
1600 dns_b_getc(const struct dns_buf *_b, const int eof)
1601 {
1602         struct dns_buf *b = (struct dns_buf *)_b;
1603
1604         if (!(b->p < b->pe))
1605                 return dns_b_setoverflow(b, 1, DNS_EILLEGAL), eof;
1606
1607         return *b->p++;
1608 }
1609
1610 static inline intmax_t
1611 dns_b_get16(const struct dns_buf *b, const intmax_t eof)
1612 {
1613         intmax_t n;
1614
1615         n = (dns_b_getc(b, 0) << 8);
1616         n |= (dns_b_getc(b, 0) << 0);
1617
1618         return (!b->overflow)? n : eof;
1619 }
1620
1621 DNS_NOTUSED static inline intmax_t
1622 dns_b_get32(const struct dns_buf *b, const intmax_t eof)
1623 {
1624         intmax_t n;
1625
1626         n = (dns_b_get16(b, 0) << 16);
1627         n |= (dns_b_get16(b, 0) << 0);
1628
1629         return (!b->overflow)? n : eof;
1630 }
1631
1632 static inline dns_error_t
1633 dns_b_move(struct dns_buf *dst, const struct dns_buf *_src, size_t n)
1634 {
1635         struct dns_buf *src = (struct dns_buf *)_src;
1636         size_t src_n = DNS_PP_MIN((size_t)(src->pe - src->p), n);
1637         size_t src_r = n - src_n;
1638
1639         dns_b_put(dst, src->p, src_n);
1640         src->p += src_n;
1641
1642         if (src_r)
1643                 return dns_b_setoverflow(src, src_r, DNS_EILLEGAL);
1644
1645         return dst->error;
1646 }
1647
1648 /*
1649  * T I M E  R O U T I N E S
1650  *
1651  * Most functions still rely on the older time routines defined in the
1652  * utility routines section, above.
1653  *
1654  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1655
1656 #define DNS_TIME_C(n) UINT64_C(n)
1657 #define DNS_TIME_INF (~DNS_TIME_C(0))
1658
1659 typedef uint64_t dns_time_t;
1660 typedef dns_time_t dns_microseconds_t;
1661
1662 static dns_error_t dns_time_add(dns_time_t *r, dns_time_t a, dns_time_t b) {
1663         int error;
1664         DNS_CHECK_OVERFLOW(&error, r, dns_add_overflow, a, b, DNS_TIME_INF);
1665         return error;
1666 }
1667
1668 static dns_error_t dns_time_mul(dns_time_t *r, dns_time_t a, dns_time_t b) {
1669         int error;
1670         DNS_CHECK_OVERFLOW(&error, r, dns_mul_overflow, a, b, DNS_TIME_INF);
1671         return error;
1672 }
1673
1674 static dns_error_t dns_time_diff(dns_time_t *r, dns_time_t a, dns_time_t b) {
1675         if (a < b) {
1676                 *r = DNS_TIME_C(0);
1677                 return ERANGE;
1678         } else {
1679                 *r = a - b;
1680                 return 0;
1681         }
1682 }
1683
1684 static dns_microseconds_t dns_ts2us(const struct timespec *ts, _Bool rup) {
1685         if (ts) {
1686                 dns_time_t sec = DNS_PP_MAX(0, ts->tv_sec);
1687                 dns_time_t nsec = DNS_PP_MAX(0, ts->tv_nsec);
1688                 dns_time_t usec = nsec / 1000;
1689                 dns_microseconds_t r;
1690
1691                 if (rup && nsec % 1000 > 0)
1692                         usec++;
1693                 dns_time_mul(&r, sec, DNS_TIME_C(1000000));
1694                 dns_time_add(&r, r, usec);
1695
1696                 return r;
1697         } else {
1698                 return DNS_TIME_INF;
1699         }
1700 } /* dns_ts2us() */
1701
1702 static struct timespec *dns_tv2ts(struct timespec *ts, const struct timeval *tv) {
1703         if (tv) {
1704                 ts->tv_sec = tv->tv_sec;
1705                 ts->tv_nsec = tv->tv_usec * 1000;
1706
1707                 return ts;
1708         } else {
1709                 return NULL;
1710         }
1711 } /* dns_tv2ts() */
1712
1713 static size_t dns_utime_print(void *_dst, size_t lim, dns_microseconds_t us) {
1714         struct dns_buf dst = DNS_B_INTO(_dst, lim);
1715
1716         dns_b_fmtju(&dst, us / 1000000, 1);
1717         dns_b_putc(&dst, '.');
1718         dns_b_fmtju(&dst, us % 1000000, 6);
1719
1720         return dns_b_strllen(&dst);
1721 } /* dns_utime_print() */
1722
1723 /*
1724  * P A C K E T  R O U T I N E S
1725  *
1726  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1727
1728 unsigned dns_p_count(struct dns_packet *P, enum dns_section section) {
1729         unsigned count;
1730
1731         switch (section) {
1732         case DNS_S_QD:
1733                 return ntohs(dns_header(P)->qdcount);
1734         case DNS_S_AN:
1735                 return ntohs(dns_header(P)->ancount);
1736         case DNS_S_NS:
1737                 return ntohs(dns_header(P)->nscount);
1738         case DNS_S_AR:
1739                 return ntohs(dns_header(P)->arcount);
1740         default:
1741                 count = 0;
1742
1743                 if (section & DNS_S_QD)
1744                         count += ntohs(dns_header(P)->qdcount);
1745                 if (section & DNS_S_AN)
1746                         count += ntohs(dns_header(P)->ancount);
1747                 if (section & DNS_S_NS)
1748                         count += ntohs(dns_header(P)->nscount);
1749                 if (section & DNS_S_AR)
1750                         count += ntohs(dns_header(P)->arcount);
1751
1752                 return count;
1753         }
1754 } /* dns_p_count() */
1755
1756
1757 struct dns_packet *dns_p_init(struct dns_packet *P, size_t size) {
1758         if (!P)
1759                 return 0;
1760
1761         assert(size >= offsetof(struct dns_packet, data) + 12);
1762
1763         memset(P, 0, sizeof *P);
1764         P->size = size - offsetof(struct dns_packet, data);
1765         P->end  = 12;
1766
1767         memset(P->data, '\0', 12);
1768
1769         return P;
1770 } /* dns_p_init() */
1771
1772
1773 static struct dns_packet *dns_p_reset(struct dns_packet *P) {
1774         return dns_p_init(P, offsetof(struct dns_packet, data) + P->size);
1775 } /* dns_p_reset() */
1776
1777
1778 static unsigned short dns_p_qend(struct dns_packet *P) {
1779         unsigned short qend     = 12;
1780         unsigned i, count       = dns_p_count(P, DNS_S_QD);
1781
1782         for (i = 0; i < count && qend < P->end; i++) {
1783                 if (P->end == (qend = dns_d_skip(qend, P)))
1784                         goto invalid;
1785
1786                 if (P->end - qend < 4)
1787                         goto invalid;
1788
1789                 qend    += 4;
1790         }
1791
1792         return DNS_PP_MIN(qend, P->end);
1793 invalid:
1794         return P->end;
1795 } /* dns_p_qend() */
1796
1797
1798 struct dns_packet *dns_p_make(size_t len, int *error) {
1799         struct dns_packet *P;
1800         size_t size = dns_p_calcsize(len);
1801
1802         if (!(P = dns_p_init(malloc(size), size)))
1803                 *error = dns_syerr();
1804
1805         return P;
1806 } /* dns_p_make() */
1807
1808
1809 static void dns_p_free(struct dns_packet *P) {
1810         free(P);
1811 } /* dns_p_free() */
1812
1813
1814 /* convience routine to free any existing packet before storing new packet */
1815 static struct dns_packet *dns_p_setptr(struct dns_packet **dst, struct dns_packet *src) {
1816         dns_p_free(*dst);
1817
1818         *dst = src;
1819
1820         return src;
1821 } /* dns_p_setptr() */
1822
1823
1824 static struct dns_packet *dns_p_movptr(struct dns_packet **dst, struct dns_packet **src) {
1825         dns_p_setptr(dst, *src);
1826
1827         *src = NULL;
1828
1829         return *dst;
1830 } /* dns_p_movptr() */
1831
1832
1833 int dns_p_grow(struct dns_packet **P) {
1834         struct dns_packet *tmp;
1835         size_t size;
1836         int error;
1837
1838         if (!*P) {
1839                 if (!(*P = dns_p_make(DNS_P_QBUFSIZ, &error)))
1840                         return error;
1841
1842                 return 0;
1843         }
1844
1845         size = dns_p_sizeof(*P);
1846         size |= size >> 1;
1847         size |= size >> 2;
1848         size |= size >> 4;
1849         size |= size >> 8;
1850         size++;
1851
1852         if (size > 65536)
1853                 return DNS_ENOBUFS;
1854
1855         if (!(tmp = realloc(*P, dns_p_calcsize(size))))
1856                 return dns_syerr();
1857
1858         tmp->size = size;
1859         *P = tmp;
1860
1861         return 0;
1862 } /* dns_p_grow() */
1863
1864
1865 struct dns_packet *dns_p_copy(struct dns_packet *P, const struct dns_packet *P0) {
1866         if (!P)
1867                 return 0;
1868
1869         P->end  = DNS_PP_MIN(P->size, P0->end);
1870
1871         memcpy(P->data, P0->data, P->end);
1872
1873         return P;
1874 } /* dns_p_copy() */
1875
1876
1877 struct dns_packet *dns_p_merge(struct dns_packet *A, enum dns_section Amask, struct dns_packet *B, enum dns_section Bmask, int *error_) {
1878         size_t bufsiz = DNS_PP_MIN(65535, ((A)? A->end : 0) + ((B)? B->end : 0));
1879         struct dns_packet *M;
1880         enum dns_section section;
1881         struct dns_rr rr, mr;
1882         int error, copy;
1883
1884         if (!A && B) {
1885                 A = B;
1886                 Amask = Bmask;
1887                 B = 0;
1888         }
1889
1890 merge:
1891         if (!(M = dns_p_make(bufsiz, &error)))
1892                 goto error;
1893
1894         for (section = DNS_S_QD; (DNS_S_ALL & section); section <<= 1) {
1895                 if (A && (section & Amask)) {
1896                         dns_rr_foreach(&rr, A, .section = section) {
1897                                 if ((error = dns_rr_copy(M, &rr, A)))
1898                                         goto error;
1899                         }
1900                 }
1901
1902                 if (B && (section & Bmask)) {
1903                         dns_rr_foreach(&rr, B, .section = section) {
1904                                 copy = 1;
1905
1906                                 dns_rr_foreach(&mr, M, .type = rr.type, .section = DNS_S_ALL) {
1907                                         if (!(copy = dns_rr_cmp(&rr, B, &mr, M)))
1908                                                 break;
1909                                 }
1910
1911                                 if (copy && (error = dns_rr_copy(M, &rr, B)))
1912                                         goto error;
1913                         }
1914                 }
1915         }
1916
1917         return M;
1918 error:
1919         dns_p_setptr(&M, NULL);
1920
1921         if (error == DNS_ENOBUFS && bufsiz < 65535) {
1922                 bufsiz = DNS_PP_MIN(65535, bufsiz * 2);
1923
1924                 goto merge;
1925         }
1926
1927         *error_ = error;
1928
1929         return 0;
1930 } /* dns_p_merge() */
1931
1932
1933 static unsigned short dns_l_skip(unsigned short, const unsigned char *, size_t);
1934
1935 void dns_p_dictadd(struct dns_packet *P, unsigned short dn) {
1936         unsigned short lp, lptr, i;
1937
1938         lp      = dn;
1939
1940         while (lp < P->end) {
1941                 if (0xc0 == (0xc0 & P->data[lp]) && P->end - lp >= 2 && lp != dn) {
1942                         lptr    = ((0x3f & P->data[lp + 0]) << 8)
1943                                 | ((0xff & P->data[lp + 1]) << 0);
1944
1945                         for (i = 0; i < lengthof(P->dict) && P->dict[i]; i++) {
1946                                 if (P->dict[i] == lptr) {
1947                                         P->dict[i]      = dn;
1948
1949                                         return;
1950                                 }
1951                         }
1952                 }
1953
1954                 lp      = dns_l_skip(lp, P->data, P->end);
1955         }
1956
1957         for (i = 0; i < lengthof(P->dict); i++) {
1958                 if (!P->dict[i]) {
1959                         P->dict[i]      = dn;
1960
1961                         break;
1962                 }
1963         }
1964 } /* dns_p_dictadd() */
1965
1966
1967 int dns_p_push(struct dns_packet *P, enum dns_section section, const void *dn, size_t dnlen, enum dns_type type, enum dns_class class, unsigned ttl, const void *any) {
1968         size_t end = P->end;
1969         int error;
1970
1971         if ((error = dns_d_push(P, dn, dnlen)))
1972                 goto error;
1973
1974         if (P->size - P->end < 4)
1975                 goto nobufs;
1976
1977         P->data[P->end++] = 0xff & (type >> 8);
1978         P->data[P->end++] = 0xff & (type >> 0);
1979
1980         P->data[P->end++] = 0xff & (class >> 8);
1981         P->data[P->end++] = 0xff & (class >> 0);
1982
1983         if (section == DNS_S_QD)
1984                 goto update;
1985
1986         if (P->size - P->end < 6)
1987                 goto nobufs;
1988
1989         if (type != DNS_T_OPT)
1990                 ttl = DNS_PP_MIN(ttl, 0x7fffffffU);
1991         P->data[P->end++] = ttl >> 24;
1992         P->data[P->end++] = ttl >> 16;
1993         P->data[P->end++] = ttl >> 8;
1994         P->data[P->end++] = ttl >> 0;
1995
1996         if ((error = dns_any_push(P, (union dns_any *)any, type)))
1997                 goto error;
1998
1999 update:
2000         switch (section) {
2001         case DNS_S_QD:
2002                 if (dns_p_count(P, DNS_S_AN|DNS_S_NS|DNS_S_AR))
2003                         goto order;
2004
2005                 if (!P->memo.qd.base && (error = dns_p_study(P)))
2006                         goto error;
2007
2008                 dns_header(P)->qdcount = htons(ntohs(dns_header(P)->qdcount) + 1);
2009
2010                 P->memo.qd.end  = P->end;
2011                 P->memo.an.base = P->end;
2012                 P->memo.an.end  = P->end;
2013                 P->memo.ns.base = P->end;
2014                 P->memo.ns.end  = P->end;
2015                 P->memo.ar.base = P->end;
2016                 P->memo.ar.end  = P->end;
2017
2018                 break;
2019         case DNS_S_AN:
2020                 if (dns_p_count(P, DNS_S_NS|DNS_S_AR))
2021                         goto order;
2022
2023                 if (!P->memo.an.base && (error = dns_p_study(P)))
2024                         goto error;
2025
2026                 dns_header(P)->ancount = htons(ntohs(dns_header(P)->ancount) + 1);
2027
2028                 P->memo.an.end  = P->end;
2029                 P->memo.ns.base = P->end;
2030                 P->memo.ns.end  = P->end;
2031                 P->memo.ar.base = P->end;
2032                 P->memo.ar.end  = P->end;
2033
2034                 break;
2035         case DNS_S_NS:
2036                 if (dns_p_count(P, DNS_S_AR))
2037                         goto order;
2038
2039                 if (!P->memo.ns.base && (error = dns_p_study(P)))
2040                         goto error;
2041
2042                 dns_header(P)->nscount = htons(ntohs(dns_header(P)->nscount) + 1);
2043
2044                 P->memo.ns.end  = P->end;
2045                 P->memo.ar.base = P->end;
2046                 P->memo.ar.end  = P->end;
2047
2048                 break;
2049         case DNS_S_AR:
2050                 if (!P->memo.ar.base && (error = dns_p_study(P)))
2051                         goto error;
2052
2053                 dns_header(P)->arcount = htons(ntohs(dns_header(P)->arcount) + 1);
2054
2055                 P->memo.ar.end = P->end;
2056
2057                 if (type == DNS_T_OPT && !P->memo.opt.p) {
2058                         P->memo.opt.p = end;
2059                         P->memo.opt.maxudp = class;
2060                         P->memo.opt.ttl = ttl;
2061                 }
2062
2063                 break;
2064         default:
2065                 error = DNS_ESECTION;
2066
2067                 goto error;
2068         } /* switch() */
2069
2070         return 0;
2071 nobufs:
2072         error = DNS_ENOBUFS;
2073
2074         goto error;
2075 order:
2076         error = DNS_EORDER;
2077
2078         goto error;
2079 error:
2080         P->end = end;
2081
2082         return error;
2083 } /* dns_p_push() */
2084
2085 #define DNS_SM_RESTORE do { pc = state->pc; error = state->error; } while (0)
2086 #define DNS_SM_SAVE do { state->error = error; state->pc = pc; } while (0)
2087
2088 struct dns_p_lines_i {
2089         int pc;
2090         enum dns_section section;
2091         struct dns_rr rr;
2092         int error;
2093 };
2094
2095 static size_t dns_p_lines_fmt(void *dst, size_t lim, dns_error_t *_error, const char *fmt, ...) {
2096         va_list ap;
2097         int error = 0, n;
2098
2099         va_start(ap, fmt);
2100         if ((n = vsnprintf(dst, lim, fmt, ap)) < 0)
2101                 error = errno;
2102         va_end(ap);
2103
2104         *_error = error;
2105         return DNS_PP_MAX(n, 0);
2106 } /* dns_p_lines_fmt() */
2107
2108 #define DNS_P_LINE(...) \
2109         do { \
2110                 len = dns_p_lines_fmt(dst, lim, &error, __VA_ARGS__); \
2111                 if (len == 0 && error) \
2112                         goto error; \
2113                 DNS_SM_YIELD(len); \
2114         } while (0)
2115
2116 static size_t dns_p_lines(void *dst, size_t lim, dns_error_t *_error, struct dns_packet *P, struct dns_rr_i *I, struct dns_p_lines_i *state) {
2117         int error, pc;
2118         size_t len;
2119
2120         *_error = 0;
2121
2122         DNS_SM_ENTER;
2123
2124         DNS_P_LINE(";; [HEADER]\n");
2125         DNS_P_LINE(";;    qid : %d\n", ntohs(dns_header(P)->qid));
2126         DNS_P_LINE(";;     qr : %s(%d)\n", (dns_header(P)->qr)? "RESPONSE" : "QUERY", dns_header(P)->qr);
2127         DNS_P_LINE(";; opcode : %s(%d)\n", dns_stropcode(dns_header(P)->opcode), dns_header(P)->opcode);
2128         DNS_P_LINE(";;     aa : %s(%d)\n", (dns_header(P)->aa)? "AUTHORITATIVE" : "NON-AUTHORITATIVE", dns_header(P)->aa);
2129         DNS_P_LINE(";;     tc : %s(%d)\n", (dns_header(P)->tc)? "TRUNCATED" : "NOT-TRUNCATED", dns_header(P)->tc);
2130         DNS_P_LINE(";;     rd : %s(%d)\n", (dns_header(P)->rd)? "RECURSION-DESIRED" : "RECURSION-NOT-DESIRED", dns_header(P)->rd);
2131         DNS_P_LINE(";;     ra : %s(%d)\n", (dns_header(P)->ra)? "RECURSION-ALLOWED" : "RECURSION-NOT-ALLOWED", dns_header(P)->ra);
2132         DNS_P_LINE(";;  rcode : %s(%d)\n", dns_strrcode(dns_p_rcode(P)), dns_p_rcode(P));
2133
2134         while (dns_rr_grep(&state->rr, 1, I, P, &error)) {
2135                 if (state->section != state->rr.section) {
2136                         DNS_P_LINE("\n");
2137                         DNS_P_LINE(";; [%s:%d]\n", dns_strsection(state->rr.section), dns_p_count(P, state->rr.section));
2138                 }
2139
2140                 if (!(len = dns_rr_print(dst, lim, &state->rr, P, &error)))
2141                         goto error;
2142                 dns_strlcat(dst, "\n", lim);
2143                 DNS_SM_YIELD(len + 1);
2144
2145                 state->section = state->rr.section;
2146         }
2147
2148         if (error)
2149                 goto error;
2150
2151         DNS_SM_EXIT;
2152 error:
2153         for (;;) {
2154                 *_error = error;
2155                 DNS_SM_YIELD(0);
2156         }
2157
2158         DNS_SM_LEAVE;
2159
2160         *_error = 0;
2161         return 0;
2162 } /* dns_p_lines() */
2163
2164 #undef DNS_P_LINE
2165 #undef DNS_SM_SAVE
2166 #undef DNS_SM_RESTORE
2167
2168 static void dns_p_dump3(struct dns_packet *P, struct dns_rr_i *I, FILE *fp) {
2169         struct dns_p_lines_i lines = { 0 };
2170         char line[sizeof (union dns_any) * 2];
2171         size_t len;
2172         int error;
2173
2174         while ((len = dns_p_lines(line, sizeof line, &error, P, I, &lines))) {
2175                 if (len < sizeof line) {
2176                         fwrite(line, 1, len, fp);
2177                 } else {
2178                         fwrite(line, 1, sizeof line - 1, fp);
2179                         fputc('\n', fp);
2180                 }
2181         }
2182 } /* dns_p_dump3() */
2183
2184
2185 void dns_p_dump(struct dns_packet *P, FILE *fp) {
2186         dns_p_dump3(P, dns_rr_i_new(P, .section = 0), fp);
2187 } /* dns_p_dump() */
2188
2189
2190 static void dns_s_unstudy(struct dns_s_memo *m)
2191         { m->base = 0; m->end = 0; }
2192
2193 static void dns_m_unstudy(struct dns_p_memo *m) {
2194         dns_s_unstudy(&m->qd);
2195         dns_s_unstudy(&m->an);
2196         dns_s_unstudy(&m->ns);
2197         dns_s_unstudy(&m->ar);
2198         m->opt.p = 0;
2199         m->opt.maxudp = 0;
2200         m->opt.ttl = 0;
2201 } /* dns_m_unstudy() */
2202
2203 static int dns_s_study(struct dns_s_memo *m, enum dns_section section, unsigned short base, struct dns_packet *P) {
2204         unsigned short count, rp;
2205
2206         count = dns_p_count(P, section);
2207
2208         for (rp = base; count && rp < P->end; count--)
2209                 rp = dns_rr_skip(rp, P);
2210
2211         m->base = base;
2212         m->end  = rp;
2213
2214         return 0;
2215 } /* dns_s_study() */
2216
2217 static int dns_m_study(struct dns_p_memo *m, struct dns_packet *P) {
2218         struct dns_rr rr;
2219         int error;
2220
2221         if ((error = dns_s_study(&m->qd, DNS_S_QD, 12, P)))
2222                 goto error;
2223         if ((error = dns_s_study(&m->an, DNS_S_AN, m->qd.end, P)))
2224                 goto error;
2225         if ((error = dns_s_study(&m->ns, DNS_S_NS, m->an.end, P)))
2226                 goto error;
2227         if ((error = dns_s_study(&m->ar, DNS_S_AR, m->ns.end, P)))
2228                 goto error;
2229
2230         m->opt.p = 0;
2231         m->opt.maxudp = 0;
2232         m->opt.ttl = 0;
2233         dns_rr_foreach(&rr, P, .type = DNS_T_OPT, .section = DNS_S_AR) {
2234                 m->opt.p = rr.dn.p;
2235                 m->opt.maxudp = rr.class;
2236                 m->opt.ttl = rr.ttl;
2237                 break;
2238         }
2239
2240         return 0;
2241 error:
2242         dns_m_unstudy(m);
2243
2244         return error;
2245 } /* dns_m_study() */
2246
2247 int dns_p_study(struct dns_packet *P) {
2248         return dns_m_study(&P->memo, P);
2249 } /* dns_p_study() */
2250
2251
2252 enum dns_rcode dns_p_rcode(struct dns_packet *P) {
2253         return 0xfff & ((P->memo.opt.ttl >> 20) | dns_header(P)->rcode);
2254 } /* dns_p_rcode() */
2255
2256
2257 /*
2258  * Q U E R Y  P A C K E T  R O U T I N E S
2259  *
2260  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2261
2262 #define DNS_Q_RD    0x1 /* recursion desired */
2263 #define DNS_Q_EDNS0 0x2 /* include OPT RR */
2264
2265 static dns_error_t
2266 dns_q_make2(struct dns_packet **_Q, const char *qname, size_t qlen, enum dns_type qtype, enum dns_class qclass, int qflags)
2267 {
2268         struct dns_packet *Q = NULL;
2269         int error;
2270
2271         if (dns_p_movptr(&Q, _Q)) {
2272                 dns_p_reset(Q);
2273         } else if (!(Q = dns_p_make(DNS_P_QBUFSIZ, &error))) {
2274                 goto error;
2275         }
2276
2277         if ((error = dns_p_push(Q, DNS_S_QD, qname, qlen, qtype, qclass, 0, 0)))
2278                 goto error;
2279
2280         dns_header(Q)->rd = !!(qflags & DNS_Q_RD);
2281
2282         if (qflags & DNS_Q_EDNS0) {
2283                 struct dns_opt opt = DNS_OPT_INIT(&opt);
2284
2285                 opt.version = 0; /* RFC 6891 version */
2286                 opt.maxudp = 4096;
2287
2288                 if ((error = dns_p_push(Q, DNS_S_AR, ".", 1, DNS_T_OPT, dns_opt_class(&opt), dns_opt_ttl(&opt), &opt)))
2289                         goto error;
2290         }
2291
2292         *_Q = Q;
2293
2294         return 0;
2295 error:
2296         dns_p_free(Q);
2297
2298         return error;
2299 }
2300
2301 static dns_error_t
2302 dns_q_make(struct dns_packet **Q, const char *qname, enum dns_type qtype, enum dns_class qclass, int qflags)
2303 {
2304         return dns_q_make2(Q, qname, strlen(qname), qtype, qclass, qflags);
2305 }
2306
2307 static dns_error_t
2308 dns_q_remake(struct dns_packet **Q, int qflags)
2309 {
2310         char qname[DNS_D_MAXNAME + 1];
2311         size_t qlen;
2312         struct dns_rr rr;
2313         int error;
2314
2315         assert(Q && *Q);
2316         if ((error = dns_rr_parse(&rr, 12, *Q)))
2317                 return error;
2318         if (!(qlen = dns_d_expand(qname, sizeof qname, rr.dn.p, *Q, &error)))
2319                 return error;
2320         if (qlen >= sizeof qname)
2321                 return DNS_EILLEGAL;
2322         return dns_q_make2(Q, qname, qlen, rr.type, rr.class, qflags);
2323 }
2324
2325 /*
2326  * D O M A I N  N A M E  R O U T I N E S
2327  *
2328  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2329
2330 #ifndef DNS_D_MAXPTRS
2331 #define DNS_D_MAXPTRS   127     /* Arbitrary; possible, valid depth is something like packet size / 2 + fudge. */
2332 #endif
2333
2334 static size_t dns_l_expand(unsigned char *dst, size_t lim, unsigned short src, unsigned short *nxt, const unsigned char *data, size_t end) {
2335         unsigned short len;
2336         unsigned nptrs  = 0;
2337
2338 retry:
2339         if (src >= end)
2340                 goto invalid;
2341
2342         switch (0x03 & (data[src] >> 6)) {
2343         case 0x00:
2344                 len     = (0x3f & (data[src++]));
2345
2346                 if (end - src < len)
2347                         goto invalid;
2348
2349                 if (lim > 0) {
2350                         memcpy(dst, &data[src], DNS_PP_MIN(lim, len));
2351
2352                         dst[DNS_PP_MIN(lim - 1, len)]   = '\0';
2353                 }
2354
2355                 *nxt    = src + len;
2356
2357                 return len;
2358         case 0x01:
2359                 goto invalid;
2360         case 0x02:
2361                 goto invalid;
2362         case 0x03:
2363                 if (++nptrs > DNS_D_MAXPTRS)
2364                         goto invalid;
2365
2366                 if (end - src < 2)
2367                         goto invalid;
2368
2369                 src     = ((0x3f & data[src + 0]) << 8)
2370                         | ((0xff & data[src + 1]) << 0);
2371
2372                 goto retry;
2373         } /* switch() */
2374
2375         /* NOT REACHED */
2376 invalid:
2377         *nxt    = end;
2378
2379         return 0;
2380 } /* dns_l_expand() */
2381
2382
2383 static unsigned short dns_l_skip(unsigned short src, const unsigned char *data, size_t end) {
2384         unsigned short len;
2385
2386         if (src >= end)
2387                 goto invalid;
2388
2389         switch (0x03 & (data[src] >> 6)) {
2390         case 0x00:
2391                 len     = (0x3f & (data[src++]));
2392
2393                 if (end - src < len)
2394                         goto invalid;
2395
2396                 return (len)? src + len : end;
2397         case 0x01:
2398                 goto invalid;
2399         case 0x02:
2400                 goto invalid;
2401         case 0x03:
2402                 return end;
2403         } /* switch() */
2404
2405         /* NOT REACHED */
2406 invalid:
2407         return end;
2408 } /* dns_l_skip() */
2409
2410
2411 static _Bool dns_d_isanchored(const void *_src, size_t len) {
2412         const unsigned char *src = _src;
2413         return len > 0 && src[len - 1] == '.';
2414 } /* dns_d_isanchored() */
2415
2416
2417 static size_t dns_d_ndots(const void *_src, size_t len) {
2418         const unsigned char *p = _src, *pe = p + len;
2419         size_t ndots = 0;
2420
2421         while ((p = memchr(p, '.', pe - p))) {
2422                 ndots++;
2423                 p++;
2424         }
2425
2426         return ndots;
2427 } /* dns_d_ndots() */
2428
2429
2430 static size_t dns_d_trim(void *dst_, size_t lim, const void *src_, size_t len, int flags) {
2431         unsigned char *dst = dst_;
2432         const unsigned char *src = src_;
2433         size_t dp = 0, sp = 0;
2434         int lc;
2435
2436         /* trim any leading dot(s) */
2437         while (sp < len && src[sp] == '.')
2438                 sp++;
2439
2440         for (lc = 0; sp < len; lc = src[sp++]) {
2441                 /* trim extra dot(s) */
2442                 if (src[sp] == '.' && lc == '.')
2443                         continue;
2444
2445                 if (dp < lim)
2446                         dst[dp] = src[sp];
2447
2448                 dp++;
2449         }
2450
2451         if ((flags & DNS_D_ANCHOR) && lc != '.') {
2452                 if (dp < lim)
2453                         dst[dp] = '.';
2454
2455                 dp++;
2456         }
2457
2458         if (lim > 0)
2459                 dst[DNS_PP_MIN(dp, lim - 1)] = '\0';
2460
2461         return dp;
2462 } /* dns_d_trim() */
2463
2464
2465 char *dns_d_init(void *dst, size_t lim, const void *src, size_t len, int flags) {
2466         if (flags & DNS_D_TRIM) {
2467                 dns_d_trim(dst, lim, src, len, flags);
2468         } if (flags & DNS_D_ANCHOR) {
2469                 dns_d_anchor(dst, lim, src, len);
2470         } else {
2471                 memmove(dst, src, DNS_PP_MIN(lim, len));
2472
2473                 if (lim > 0)
2474                         ((char *)dst)[DNS_PP_MIN(len, lim - 1)] = '\0';
2475         }
2476
2477         return dst;
2478 } /* dns_d_init() */
2479
2480
2481 size_t dns_d_anchor(void *dst, size_t lim, const void *src, size_t len) {
2482         if (len == 0)
2483                 return 0;
2484
2485         memmove(dst, src, DNS_PP_MIN(lim, len));
2486
2487         if (((const char *)src)[len - 1] != '.') {
2488                 if (len < lim)
2489                         ((char *)dst)[len]      = '.';
2490                 len++;
2491         }
2492
2493         if (lim > 0)
2494                 ((char *)dst)[DNS_PP_MIN(lim - 1, len)] = '\0';
2495
2496         return len;
2497 } /* dns_d_anchor() */
2498
2499
2500 size_t dns_d_cleave(void *dst, size_t lim, const void *src, size_t len) {
2501         const char *dot;
2502
2503         /* XXX: Skip any leading dot. Handles cleaving root ".". */
2504         if (len == 0 || !(dot = memchr((const char *)src + 1, '.', len - 1)))
2505                 return 0;
2506
2507         len     -= dot - (const char *)src;
2508
2509         /* XXX: Unless root, skip the label's trailing dot. */
2510         if (len > 1) {
2511                 src     = ++dot;
2512                 len--;
2513         } else
2514                 src     = dot;
2515
2516         memmove(dst, src, DNS_PP_MIN(lim, len));
2517
2518         if (lim > 0)
2519                 ((char *)dst)[DNS_PP_MIN(lim - 1, len)] = '\0';
2520
2521         return len;
2522 } /* dns_d_cleave() */
2523
2524
2525 size_t dns_d_comp(void *dst_, size_t lim, const void *src_, size_t len, struct dns_packet *P, int *error) {
2526         struct { unsigned char *b; size_t p, x; } dst, src;
2527         unsigned char ch        = '.';
2528
2529         dst.b   = dst_;
2530         dst.p   = 0;
2531         dst.x   = 1;
2532
2533         src.b   = (unsigned char *)src_;
2534         src.p   = 0;
2535         src.x   = 0;
2536
2537         while (src.x < len) {
2538                 ch      = src.b[src.x];
2539
2540                 if (ch == '.') {
2541                         if (dst.p < lim)
2542                                 dst.b[dst.p]    = (0x3f & (src.x - src.p));
2543
2544                         dst.p   = dst.x++;
2545                         src.p   = ++src.x;
2546                 } else {
2547                         if (dst.x < lim)
2548                                 dst.b[dst.x]    = ch;
2549
2550                         dst.x++;
2551                         src.x++;
2552                 }
2553         } /* while() */
2554
2555         if (src.x > src.p) {
2556                 if (dst.p < lim)
2557                         dst.b[dst.p]    = (0x3f & (src.x - src.p));
2558
2559                 dst.p   = dst.x;
2560         }
2561
2562         if (dst.p > 1) {
2563                 if (dst.p < lim)
2564                         dst.b[dst.p]    = 0x00;
2565
2566                 dst.p++;
2567         }
2568
2569 #if 1
2570         if (dst.p < lim) {
2571                 struct { unsigned char label[DNS_D_MAXLABEL + 1]; size_t len; unsigned short p, x, y; } a, b;
2572                 unsigned i;
2573
2574                 a.p     = 0;
2575
2576                 while ((a.len = dns_l_expand(a.label, sizeof a.label, a.p, &a.x, dst.b, lim))) {
2577                         for (i = 0; i < lengthof(P->dict) && P->dict[i]; i++) {
2578                                 b.p     = P->dict[i];
2579
2580                                 while ((b.len = dns_l_expand(b.label, sizeof b.label, b.p, &b.x, P->data, P->end))) {
2581                                         a.y     = a.x;
2582                                         b.y     = b.x;
2583
2584                                         while (a.len && b.len && 0 == strcasecmp((char *)a.label, (char *)b.label)) {
2585                                                 a.len = dns_l_expand(a.label, sizeof a.label, a.y, &a.y, dst.b, lim);
2586                                                 b.len = dns_l_expand(b.label, sizeof b.label, b.y, &b.y, P->data, P->end);
2587                                         }
2588
2589                                         if (a.len == 0 && b.len == 0 && b.p <= 0x3fff) {
2590                                                 dst.b[a.p++]    = 0xc0
2591                                                                 | (0x3f & (b.p >> 8));
2592                                                 dst.b[a.p++]    = (0xff & (b.p >> 0));
2593
2594                                                 /* silence static analyzers */
2595                                                 dns_assume(a.p > 0);
2596
2597                                                 return a.p;
2598                                         }
2599
2600                                         b.p     = b.x;
2601                                 } /* while() */
2602                         } /* for() */
2603
2604                         a.p     = a.x;
2605                 } /* while() */
2606         } /* if () */
2607 #endif
2608
2609         if (!dst.p)
2610                 *error = DNS_EILLEGAL;
2611
2612         return dst.p;
2613 } /* dns_d_comp() */
2614
2615
2616 unsigned short dns_d_skip(unsigned short src, struct dns_packet *P) {
2617         unsigned short len;
2618
2619         while (src < P->end) {
2620                 switch (0x03 & (P->data[src] >> 6)) {
2621                 case 0x00:      /* FOLLOWS */
2622                         len     = (0x3f & P->data[src++]);
2623
2624                         if (0 == len) {
2625 /* success ==> */               return src;
2626                         } else if (P->end - src > len) {
2627                                 src     += len;
2628
2629                                 break;
2630                         } else
2631                                 goto invalid;
2632
2633                         /* NOT REACHED */
2634                 case 0x01:      /* RESERVED */
2635                         goto invalid;
2636                 case 0x02:      /* RESERVED */
2637                         goto invalid;
2638                 case 0x03:      /* POINTER */
2639                         if (P->end - src < 2)
2640                                 goto invalid;
2641
2642                         src     += 2;
2643
2644 /* success ==> */       return src;
2645                 } /* switch() */
2646         } /* while() */
2647
2648 invalid:
2649         return P->end;
2650 } /* dns_d_skip() */
2651
2652
2653 #include <stdio.h>
2654
2655 size_t dns_d_expand(void *dst, size_t lim, unsigned short src, struct dns_packet *P, int *error) {
2656         size_t dstp     = 0;
2657         unsigned nptrs  = 0;
2658         unsigned char len;
2659
2660         while (src < P->end) {
2661                 switch ((0x03 & (P->data[src] >> 6))) {
2662                 case 0x00:      /* FOLLOWS */
2663                         len     = (0x3f & P->data[src]);
2664
2665                         if (0 == len) {
2666                                 if (dstp == 0) {
2667                                         if (dstp < lim)
2668                                                 ((unsigned char *)dst)[dstp]    = '.';
2669
2670                                         dstp++;
2671                                 }
2672
2673                                 /* NUL terminate */
2674                                 if (lim > 0)
2675                                         ((unsigned char *)dst)[DNS_PP_MIN(dstp, lim - 1)]       = '\0';
2676
2677 /* success ==> */               return dstp;
2678                         }
2679
2680                         src++;
2681
2682                         if (P->end - src < len)
2683                                 goto toolong;
2684
2685                         if (dstp < lim)
2686                                 memcpy(&((unsigned char *)dst)[dstp], &P->data[src], DNS_PP_MIN(len, lim - dstp));
2687
2688                         src     += len;
2689                         dstp    += len;
2690
2691                         if (dstp < lim)
2692                                 ((unsigned char *)dst)[dstp]    = '.';
2693
2694                         dstp++;
2695
2696                         nptrs   = 0;
2697
2698                         continue;
2699                 case 0x01:      /* RESERVED */
2700                         goto reserved;
2701                 case 0x02:      /* RESERVED */
2702                         goto reserved;
2703                 case 0x03:      /* POINTER */
2704                         if (++nptrs > DNS_D_MAXPTRS)
2705                                 goto toolong;
2706
2707                         if (P->end - src < 2)
2708                                 goto toolong;
2709
2710                         src     = ((0x3f & P->data[src + 0]) << 8)
2711                                 | ((0xff & P->data[src + 1]) << 0);
2712
2713                         continue;
2714                 } /* switch() */
2715         } /* while() */
2716
2717 toolong:
2718         *error  = DNS_EILLEGAL;
2719
2720         if (lim > 0)
2721                 ((unsigned char *)dst)[DNS_PP_MIN(dstp, lim - 1)]       = '\0';
2722
2723         return 0;
2724 reserved:
2725         *error  = DNS_EILLEGAL;
2726
2727         if (lim > 0)
2728                 ((unsigned char *)dst)[DNS_PP_MIN(dstp, lim - 1)]       = '\0';
2729
2730         return 0;
2731 } /* dns_d_expand() */
2732
2733
2734 int dns_d_push(struct dns_packet *P, const void *dn, size_t len) {
2735         size_t lim      = P->size - P->end;
2736         unsigned dp     = P->end;
2737         int error       = DNS_EILLEGAL; /* silence compiler */
2738
2739         len     = dns_d_comp(&P->data[dp], lim, dn, len, P, &error);
2740
2741         if (len == 0)
2742                 return error;
2743         if (len > lim)
2744                 return DNS_ENOBUFS;
2745
2746         P->end  += len;
2747
2748         dns_p_dictadd(P, dp);
2749
2750         return 0;
2751 } /* dns_d_push() */
2752
2753
2754 size_t dns_d_cname(void *dst, size_t lim, const void *dn, size_t len, struct dns_packet *P, int *error_) {
2755         char host[DNS_D_MAXNAME + 1];
2756         struct dns_rr_i i;
2757         struct dns_rr rr;
2758         unsigned depth;
2759         int error;
2760
2761         if (sizeof host <= dns_d_anchor(host, sizeof host, dn, len))
2762                 { error = ENAMETOOLONG; goto error; }
2763
2764         for (depth = 0; depth < 7; depth++) {
2765                 dns_rr_i_init(memset(&i, 0, sizeof i), P);
2766
2767                 i.section       = DNS_S_ALL & ~DNS_S_QD;
2768                 i.name          = host;
2769                 i.type          = DNS_T_CNAME;
2770
2771                 if (!dns_rr_grep(&rr, 1, &i, P, &error))
2772                         break;
2773
2774                 if ((error = dns_cname_parse((struct dns_cname *)host, &rr, P)))
2775                         goto error;
2776         }
2777
2778         return dns_strlcpy(dst, host, lim);
2779 error:
2780         *error_ = error;
2781
2782         return 0;
2783 } /* dns_d_cname() */
2784
2785
2786 /*
2787  * R E S O U R C E  R E C O R D  R O U T I N E S
2788  *
2789  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2790
2791 int dns_rr_copy(struct dns_packet *P, struct dns_rr *rr, struct dns_packet *Q) {
2792         unsigned char dn[DNS_D_MAXNAME + 1];
2793         union dns_any any;
2794         size_t len;
2795         int error;
2796
2797         if (!(len = dns_d_expand(dn, sizeof dn, rr->dn.p, Q, &error)))
2798                 return error;
2799         else if (len >= sizeof dn)
2800                 return DNS_EILLEGAL;
2801
2802         if (rr->section != DNS_S_QD && (error = dns_any_parse(dns_any_init(&any, sizeof any), rr, Q)))
2803                 return error;
2804
2805         return dns_p_push(P, rr->section, dn, len, rr->type, rr->class, rr->ttl, &any);
2806 } /* dns_rr_copy() */
2807
2808
2809 int dns_rr_parse(struct dns_rr *rr, unsigned short src, struct dns_packet *P) {
2810         unsigned short p        = src;
2811
2812         if (src >= P->end)
2813                 goto invalid;
2814
2815         rr->dn.p   = p;
2816         rr->dn.len = (p = dns_d_skip(p, P)) - rr->dn.p;
2817
2818         if (P->end - p < 4)
2819                 goto invalid;
2820
2821         rr->type = ((0xff & P->data[p + 0]) << 8)
2822                  | ((0xff & P->data[p + 1]) << 0);
2823
2824         rr->class = ((0xff & P->data[p + 2]) << 8)
2825                   | ((0xff & P->data[p + 3]) << 0);
2826
2827         p += 4;
2828
2829         if (src < dns_p_qend(P)) {
2830                 rr->section = DNS_S_QUESTION;
2831
2832                 rr->ttl    = 0;
2833                 rr->rd.p   = 0;
2834                 rr->rd.len = 0;
2835
2836                 return 0;
2837         }
2838
2839         if (P->end - p < 4)
2840                 goto invalid;
2841
2842         rr->ttl = ((0xff & P->data[p + 0]) << 24)
2843                 | ((0xff & P->data[p + 1]) << 16)
2844                 | ((0xff & P->data[p + 2]) << 8)
2845                 | ((0xff & P->data[p + 3]) << 0);
2846         if (rr->type != DNS_T_OPT)
2847                 rr->ttl = DNS_PP_MIN(rr->ttl, 0x7fffffffU);
2848
2849         p += 4;
2850
2851         if (P->end - p < 2)
2852                 goto invalid;
2853
2854         rr->rd.len = ((0xff & P->data[p + 0]) << 8)
2855                    | ((0xff & P->data[p + 1]) << 0);
2856         rr->rd.p = p + 2;
2857
2858         p += 2;
2859
2860         if (P->end - p < rr->rd.len)
2861                 goto invalid;
2862
2863         return 0;
2864 invalid:
2865         return DNS_EILLEGAL;
2866 } /* dns_rr_parse() */
2867
2868
2869 static unsigned short dns_rr_len(const unsigned short src, struct dns_packet *P) {
2870         unsigned short rp, rdlen;
2871
2872         rp      = dns_d_skip(src, P);
2873
2874         if (P->end - rp < 4)
2875                 return P->end - src;
2876
2877         rp      += 4;   /* TYPE, CLASS */
2878
2879         if (rp <= dns_p_qend(P))
2880                 return rp - src;
2881
2882         if (P->end - rp < 6)
2883                 return P->end - src;
2884
2885         rp      += 6;   /* TTL, RDLEN */
2886
2887         rdlen   = ((0xff & P->data[rp - 2]) << 8)
2888                 | ((0xff & P->data[rp - 1]) << 0);
2889
2890         if (P->end - rp < rdlen)
2891                 return P->end - src;
2892
2893         rp      += rdlen;
2894
2895         return rp - src;
2896 } /* dns_rr_len() */
2897
2898
2899 unsigned short dns_rr_skip(unsigned short src, struct dns_packet *P) {
2900         return src + dns_rr_len(src, P);
2901 } /* dns_rr_skip() */
2902
2903
2904 static enum dns_section dns_rr_section(unsigned short src, struct dns_packet *P) {
2905         enum dns_section section;
2906         unsigned count, index;
2907         unsigned short rp;
2908
2909         if (src >= P->memo.qd.base && src < P->memo.qd.end)
2910                 return DNS_S_QD;
2911         if (src >= P->memo.an.base && src < P->memo.an.end)
2912                 return DNS_S_AN;
2913         if (src >= P->memo.ns.base && src < P->memo.ns.end)
2914                 return DNS_S_NS;
2915         if (src >= P->memo.ar.base && src < P->memo.ar.end)
2916                 return DNS_S_AR;
2917
2918         /* NOTE: Possibly bad memoization. Try it the hard-way. */
2919
2920         for (rp = 12, index = 0; rp < src && rp < P->end; index++)
2921                 rp = dns_rr_skip(rp, P);
2922
2923         section = DNS_S_QD;
2924         count   = dns_p_count(P, section);
2925
2926         while (index >= count && section <= DNS_S_AR) {
2927                 section <<= 1;
2928                 count += dns_p_count(P, section);
2929         }
2930
2931         return DNS_S_ALL & section;
2932 } /* dns_rr_section() */
2933
2934
2935 static enum dns_type dns_rr_type(unsigned short src, struct dns_packet *P) {
2936         struct dns_rr rr;
2937         int error;
2938
2939         if ((error = dns_rr_parse(&rr, src, P)))
2940                 return 0;
2941
2942         return rr.type;
2943 } /* dns_rr_type() */
2944
2945
2946 int dns_rr_cmp(struct dns_rr *r0, struct dns_packet *P0, struct dns_rr *r1, struct dns_packet *P1) {
2947         char host0[DNS_D_MAXNAME + 1], host1[DNS_D_MAXNAME + 1];
2948         union dns_any any0, any1;
2949         int cmp, error;
2950         size_t len;
2951
2952         if ((cmp = r0->type - r1->type))
2953                 return cmp;
2954
2955         if ((cmp = r0->class - r1->class))
2956                 return cmp;
2957
2958         /*
2959          * FIXME: Do label-by-label comparison to handle illegally long names?
2960          */
2961
2962         if (!(len = dns_d_expand(host0, sizeof host0, r0->dn.p, P0, &error))
2963         ||  len >= sizeof host0)
2964                 return -1;
2965
2966         if (!(len = dns_d_expand(host1, sizeof host1, r1->dn.p, P1, &error))
2967         ||  len >= sizeof host1)
2968                 return 1;
2969
2970         if ((cmp = strcasecmp(host0, host1)))
2971                 return cmp;
2972
2973         if (DNS_S_QD & (r0->section | r1->section)) {
2974                 if (r0->section == r1->section)
2975                         return 0;
2976
2977                 return (r0->section == DNS_S_QD)? -1 : 1;
2978         }
2979
2980         if ((error = dns_any_parse(&any0, r0, P0)))
2981                 return -1;
2982
2983         if ((error = dns_any_parse(&any1, r1, P1)))
2984                 return 1;
2985
2986         return dns_any_cmp(&any0, r0->type, &any1, r1->type);
2987 } /* dns_rr_cmp() */
2988
2989
2990 static _Bool dns_rr_exists(struct dns_rr *rr0, struct dns_packet *P0, struct dns_packet *P1) {
2991         struct dns_rr rr1;
2992
2993         dns_rr_foreach(&rr1, P1, .section = rr0->section, .type = rr0->type) {
2994                 if (0 == dns_rr_cmp(rr0, P0, &rr1, P1))
2995                         return 1;
2996         }
2997
2998         return 0;
2999 } /* dns_rr_exists() */
3000
3001
3002 static unsigned short dns_rr_offset(struct dns_rr *rr) {
3003         return rr->dn.p;
3004 } /* dns_rr_offset() */
3005
3006
3007 static _Bool dns_rr_i_match(struct dns_rr *rr, struct dns_rr_i *i, struct dns_packet *P) {
3008         if (i->section && !(rr->section & i->section))
3009                 return 0;
3010
3011         if (i->type && rr->type != i->type && i->type != DNS_T_ALL)
3012                 return 0;
3013
3014         if (i->class && rr->class != i->class && i->class != DNS_C_ANY)
3015                 return 0;
3016
3017         if (i->name) {
3018                 char dn[DNS_D_MAXNAME + 1];
3019                 size_t len;
3020                 int error;
3021
3022                 if (!(len = dns_d_expand(dn, sizeof dn, rr->dn.p, P, &error))
3023                 ||  len >= sizeof dn)
3024                         return 0;
3025
3026                 if (0 != strcasecmp(dn, i->name))
3027                         return 0;
3028         }
3029
3030         if (i->data && i->type && rr->section > DNS_S_QD) {
3031                 union dns_any rd;
3032                 int error;
3033
3034                 if ((error = dns_any_parse(&rd, rr, P)))
3035                         return 0;
3036
3037                 if (0 != dns_any_cmp(&rd, rr->type, i->data, i->type))
3038                         return 0;
3039         }
3040
3041         return 1;
3042 } /* dns_rr_i_match() */
3043
3044
3045 static unsigned short dns_rr_i_start(struct dns_rr_i *i, struct dns_packet *P) {
3046         unsigned short rp;
3047         struct dns_rr r0, rr;
3048         int error;
3049
3050         if ((i->section & DNS_S_QD) && P->memo.qd.base)
3051                 rp = P->memo.qd.base;
3052         else if ((i->section & DNS_S_AN) && P->memo.an.base)
3053                 rp = P->memo.an.base;
3054         else if ((i->section & DNS_S_NS) && P->memo.ns.base)
3055                 rp = P->memo.ns.base;
3056         else if ((i->section & DNS_S_AR) && P->memo.ar.base)
3057                 rp = P->memo.ar.base;
3058         else
3059                 rp = 12;
3060
3061         for (; rp < P->end; rp = dns_rr_skip(rp, P)) {
3062                 if ((error = dns_rr_parse(&rr, rp, P)))
3063                         continue;
3064
3065                 rr.section = dns_rr_section(rp, P);
3066
3067                 if (!dns_rr_i_match(&rr, i, P))
3068                         continue;
3069
3070                 r0 = rr;
3071
3072                 goto lower;
3073         }
3074
3075         return P->end;
3076 lower:
3077         if (i->sort == &dns_rr_i_packet)
3078                 return dns_rr_offset(&r0);
3079
3080         while ((rp = dns_rr_skip(rp, P)) < P->end) {
3081                 if ((error = dns_rr_parse(&rr, rp, P)))
3082                         continue;
3083
3084                 rr.section = dns_rr_section(rp, P);
3085
3086                 if (!dns_rr_i_match(&rr, i, P))
3087                         continue;
3088
3089                 if (i->sort(&rr, &r0, i, P) < 0)
3090                         r0 = rr;
3091         }
3092
3093         return dns_rr_offset(&r0);
3094 } /* dns_rr_i_start() */
3095
3096
3097 static unsigned short dns_rr_i_skip(unsigned short rp, struct dns_rr_i *i, struct dns_packet *P) {
3098         struct dns_rr r0, r1, rr;
3099         int error;
3100
3101         if ((error = dns_rr_parse(&r0, rp, P)))
3102                 return P->end;
3103
3104         r0.section = dns_rr_section(rp, P);
3105
3106         rp = (i->sort == &dns_rr_i_packet)? dns_rr_skip(rp, P) : 12;
3107
3108         for (; rp < P->end; rp = dns_rr_skip(rp, P)) {
3109                 if ((error = dns_rr_parse(&rr, rp, P)))
3110                         continue;
3111
3112                 rr.section = dns_rr_section(rp, P);
3113
3114                 if (!dns_rr_i_match(&rr, i, P))
3115                         continue;
3116
3117                 if (i->sort(&rr, &r0, i, P) <= 0)
3118                         continue;
3119
3120                 r1 = rr;
3121
3122                 goto lower;
3123         }
3124
3125         return P->end;
3126 lower:
3127         if (i->sort == &dns_rr_i_packet)
3128                 return dns_rr_offset(&r1);
3129
3130         while ((rp = dns_rr_skip(rp, P)) < P->end) {
3131                 if ((error = dns_rr_parse(&rr, rp, P)))
3132                         continue;
3133
3134                 rr.section = dns_rr_section(rp, P);
3135
3136                 if (!dns_rr_i_match(&rr, i, P))
3137                         continue;
3138
3139                 if (i->sort(&rr, &r0, i, P) <= 0)
3140                         continue;
3141
3142                 if (i->sort(&rr, &r1, i, P) >= 0)
3143                         continue;
3144
3145                 r1 = rr;
3146         }
3147
3148         return dns_rr_offset(&r1);
3149 } /* dns_rr_i_skip() */
3150
3151
3152 int dns_rr_i_packet(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) {
3153         (void)i;
3154         (void)P;
3155
3156         return (int)a->dn.p - (int)b->dn.p;
3157 } /* dns_rr_i_packet() */
3158
3159
3160 int dns_rr_i_order(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) {
3161         int cmp;
3162
3163         (void)i;
3164
3165         if ((cmp = a->section - b->section))
3166                 return cmp;
3167
3168         if (a->type != b->type)
3169                 return (int)a->dn.p - (int)b->dn.p;
3170
3171         return dns_rr_cmp(a, P, b, P);
3172 } /* dns_rr_i_order() */
3173
3174
3175 int dns_rr_i_shuffle(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) {
3176         int cmp;
3177
3178         (void)i;
3179         (void)P;
3180
3181         while (!i->state.regs[0])
3182                 i->state.regs[0]        = dns_random();
3183
3184         if ((cmp = a->section - b->section))
3185                 return cmp;
3186
3187         return dns_k_shuffle16(a->dn.p, i->state.regs[0]) - dns_k_shuffle16(b->dn.p, i->state.regs[0]);
3188 } /* dns_rr_i_shuffle() */
3189
3190
3191 struct dns_rr_i *dns_rr_i_init(struct dns_rr_i *i, struct dns_packet *P) {
3192         static const struct dns_rr_i i_initializer;
3193
3194         (void)P;
3195
3196         i->state        = i_initializer.state;
3197         i->saved        = i->state;
3198
3199         return i;
3200 } /* dns_rr_i_init() */
3201
3202
3203 unsigned dns_rr_grep(struct dns_rr *rr, unsigned lim, struct dns_rr_i *i, struct dns_packet *P, int *error_) {
3204         unsigned count  = 0;
3205         int error;
3206
3207         switch (i->state.exec) {
3208         case 0:
3209                 if (!i->sort)
3210                         i->sort = &dns_rr_i_packet;
3211
3212                 i->state.next   = dns_rr_i_start(i, P);
3213                 i->state.exec++;
3214
3215                 /* FALL THROUGH */
3216         case 1:
3217                 while (count < lim && i->state.next < P->end) {
3218                         if ((error = dns_rr_parse(rr, i->state.next, P)))
3219                                 goto error;
3220
3221                         rr->section     = dns_rr_section(i->state.next, P);
3222
3223                         rr++;
3224                         count++;
3225                         i->state.count++;
3226
3227                         i->state.next   = dns_rr_i_skip(i->state.next, i, P);
3228                 } /* while() */
3229
3230                 break;
3231         } /* switch() */
3232
3233         return count;
3234 error:
3235         *error_ = error;
3236
3237         return count;
3238 } /* dns_rr_grep() */
3239
3240
3241 size_t dns_rr_print(void *_dst, size_t lim, struct dns_rr *rr, struct dns_packet *P, int *_error) {
3242         struct dns_buf dst = DNS_B_INTO(_dst, lim);
3243         union dns_any any;
3244         size_t n;
3245         int error;
3246
3247         if (rr->section == DNS_S_QD)
3248                 dns_b_putc(&dst, ';');
3249
3250         if (!(n = dns_d_expand(any.ns.host, sizeof any.ns.host, rr->dn.p, P, &error)))
3251                 goto error;
3252         dns_b_put(&dst, any.ns.host, DNS_PP_MIN(n, sizeof any.ns.host - 1));
3253
3254         if (rr->section != DNS_S_QD) {
3255                 dns_b_putc(&dst, ' ');
3256                 dns_b_fmtju(&dst, rr->ttl, 0);
3257         }
3258
3259         dns_b_putc(&dst, ' ');
3260         dns_b_puts(&dst, dns_strclass(rr->class));
3261         dns_b_putc(&dst, ' ');
3262         dns_b_puts(&dst, dns_strtype(rr->type));
3263
3264         if (rr->section == DNS_S_QD)
3265                 goto epilog;
3266
3267         dns_b_putc(&dst, ' ');
3268
3269         if ((error = dns_any_parse(dns_any_init(&any, sizeof any), rr, P)))
3270                 goto error;
3271
3272         n = dns_any_print(dst.p, dst.pe - dst.p, &any, rr->type);
3273         dst.p += DNS_PP_MIN(n, (size_t)(dst.pe - dst.p));
3274 epilog:
3275         return dns_b_strllen(&dst);
3276 error:
3277         *_error = error;
3278
3279         return 0;
3280 } /* dns_rr_print() */
3281
3282
3283 int dns_a_parse(struct dns_a *a, struct dns_rr *rr, struct dns_packet *P) {
3284         unsigned long addr;
3285
3286         if (rr->rd.len != 4)
3287                 return DNS_EILLEGAL;
3288
3289         addr    = ((0xffU & P->data[rr->rd.p + 0]) << 24)
3290                 | ((0xffU & P->data[rr->rd.p + 1]) << 16)
3291                 | ((0xffU & P->data[rr->rd.p + 2]) << 8)
3292                 | ((0xffU & P->data[rr->rd.p + 3]) << 0);
3293
3294         a->addr.s_addr  = htonl(addr);
3295
3296         return 0;
3297 } /* dns_a_parse() */
3298
3299
3300 int dns_a_push(struct dns_packet *P, struct dns_a *a) {
3301         unsigned long addr;
3302
3303         if (P->size - P->end < 6)
3304                 return DNS_ENOBUFS;
3305
3306         P->data[P->end++]       = 0x00;
3307         P->data[P->end++]       = 0x04;
3308
3309         addr    = ntohl(a->addr.s_addr);
3310
3311         P->data[P->end++]       = 0xffU & (addr >> 24);
3312         P->data[P->end++]       = 0xffU & (addr >> 16);
3313         P->data[P->end++]       = 0xffU & (addr >> 8);
3314         P->data[P->end++]       = 0xffU & (addr >> 0);
3315
3316         return 0;
3317 } /* dns_a_push() */
3318
3319
3320 size_t dns_a_arpa(void *_dst, size_t lim, const struct dns_a *a) {
3321         struct dns_buf dst = DNS_B_INTO(_dst, lim);
3322         unsigned long octets = ntohl(a->addr.s_addr);
3323         unsigned i;
3324
3325         for (i = 0; i < 4; i++) {
3326                 dns_b_fmtju(&dst, 0xff & octets, 0);
3327                 dns_b_putc(&dst, '.');
3328                 octets >>= 8;
3329         }
3330
3331         dns_b_puts(&dst, "in-addr.arpa.");
3332
3333         return dns_b_strllen(&dst);
3334 } /* dns_a_arpa() */
3335
3336
3337 int dns_a_cmp(const struct dns_a *a, const struct dns_a *b) {
3338         if (ntohl(a->addr.s_addr) < ntohl(b->addr.s_addr))
3339                 return -1;
3340         if (ntohl(a->addr.s_addr) > ntohl(b->addr.s_addr))
3341                 return 1;
3342
3343         return 0;
3344 } /* dns_a_cmp() */
3345
3346
3347 size_t dns_a_print(void *dst, size_t lim, struct dns_a *a) {
3348         char addr[INET_ADDRSTRLEN + 1]  = "0.0.0.0";
3349
3350         dns_inet_ntop(AF_INET, &a->addr, addr, sizeof addr);
3351
3352         return dns_strlcpy(dst, addr, lim);
3353 } /* dns_a_print() */
3354
3355
3356 int dns_aaaa_parse(struct dns_aaaa *aaaa, struct dns_rr *rr, struct dns_packet *P) {
3357         if (rr->rd.len != sizeof aaaa->addr.s6_addr)
3358                 return DNS_EILLEGAL;
3359
3360         memcpy(aaaa->addr.s6_addr, &P->data[rr->rd.p], sizeof aaaa->addr.s6_addr);
3361
3362         return 0;
3363 } /* dns_aaaa_parse() */
3364
3365
3366 int dns_aaaa_push(struct dns_packet *P, struct dns_aaaa *aaaa) {
3367         if (P->size - P->end < 2 + sizeof aaaa->addr.s6_addr)
3368                 return DNS_ENOBUFS;
3369
3370         P->data[P->end++]       = 0x00;
3371         P->data[P->end++]       = 0x10;
3372
3373         memcpy(&P->data[P->end], aaaa->addr.s6_addr, sizeof aaaa->addr.s6_addr);
3374
3375         P->end  += sizeof aaaa->addr.s6_addr;
3376
3377         return 0;
3378 } /* dns_aaaa_push() */
3379
3380
3381 int dns_aaaa_cmp(const struct dns_aaaa *a, const struct dns_aaaa *b) {
3382         unsigned i;
3383         int cmp;
3384
3385         for (i = 0; i < lengthof(a->addr.s6_addr); i++) {
3386                 if ((cmp = (a->addr.s6_addr[i] - b->addr.s6_addr[i])))
3387                         return cmp;
3388         }
3389
3390         return 0;
3391 } /* dns_aaaa_cmp() */
3392
3393
3394 size_t dns_aaaa_arpa(void *_dst, size_t lim, const struct dns_aaaa *aaaa) {
3395         static const unsigned char hex[16] = "0123456789abcdef";
3396         struct dns_buf dst = DNS_B_INTO(_dst, lim);
3397         unsigned nyble;
3398         int i, j;
3399
3400         for (i = sizeof aaaa->addr.s6_addr - 1; i >= 0; i--) {
3401                 nyble = aaaa->addr.s6_addr[i];
3402
3403                 for (j = 0; j < 2; j++) {
3404                         dns_b_putc(&dst, hex[0x0f & nyble]);
3405                         dns_b_putc(&dst, '.');
3406                         nyble >>= 4;
3407                 }
3408         }
3409
3410         dns_b_puts(&dst, "ip6.arpa.");
3411
3412         return dns_b_strllen(&dst);
3413 } /* dns_aaaa_arpa() */
3414
3415
3416 size_t dns_aaaa_print(void *dst, size_t lim, struct dns_aaaa *aaaa) {
3417         char addr[INET6_ADDRSTRLEN + 1] = "::";
3418
3419         dns_inet_ntop(AF_INET6, &aaaa->addr, addr, sizeof addr);
3420
3421         return dns_strlcpy(dst, addr, lim);
3422 } /* dns_aaaa_print() */
3423
3424
3425 int dns_mx_parse(struct dns_mx *mx, struct dns_rr *rr, struct dns_packet *P) {
3426         size_t len;
3427         int error;
3428
3429         if (rr->rd.len < 3)
3430                 return DNS_EILLEGAL;
3431
3432         mx->preference  = (0xff00 & (P->data[rr->rd.p + 0] << 8))
3433                         | (0x00ff & (P->data[rr->rd.p + 1] << 0));
3434
3435         if (!(len = dns_d_expand(mx->host, sizeof mx->host, rr->rd.p + 2, P, &error)))
3436                 return error;
3437         else if (len >= sizeof mx->host)
3438                 return DNS_EILLEGAL;
3439
3440         return 0;
3441 } /* dns_mx_parse() */
3442
3443
3444 int dns_mx_push(struct dns_packet *P, struct dns_mx *mx) {
3445         size_t end, len;
3446         int error;
3447
3448         if (P->size - P->end < 5)
3449                 return DNS_ENOBUFS;
3450
3451         end     = P->end;
3452         P->end  += 2;
3453
3454         P->data[P->end++]       = 0xff & (mx->preference >> 8);
3455         P->data[P->end++]       = 0xff & (mx->preference >> 0);
3456
3457         if ((error = dns_d_push(P, mx->host, strlen(mx->host))))
3458                 goto error;
3459
3460         len     = P->end - end - 2;
3461
3462         P->data[end + 0]        = 0xff & (len >> 8);
3463         P->data[end + 1]        = 0xff & (len >> 0);
3464
3465         return 0;
3466 error:
3467         P->end  = end;
3468
3469         return error;
3470 } /* dns_mx_push() */
3471
3472
3473 int dns_mx_cmp(const struct dns_mx *a, const struct dns_mx *b) {
3474         int cmp;
3475
3476         if ((cmp = a->preference - b->preference))
3477                 return cmp;
3478
3479         return strcasecmp(a->host, b->host);
3480 } /* dns_mx_cmp() */
3481
3482
3483 size_t dns_mx_print(void *_dst, size_t lim, struct dns_mx *mx) {
3484         struct dns_buf dst = DNS_B_INTO(_dst, lim);
3485
3486         dns_b_fmtju(&dst, mx->preference, 0);
3487         dns_b_putc(&dst, ' ');
3488         dns_b_puts(&dst, mx->host);
3489
3490         return dns_b_strllen(&dst);
3491 } /* dns_mx_print() */
3492
3493
3494 size_t dns_mx_cname(void *dst, size_t lim, struct dns_mx *mx) {
3495         return dns_strlcpy(dst, mx->host, lim);
3496 } /* dns_mx_cname() */
3497
3498
3499 int dns_ns_parse(struct dns_ns *ns, struct dns_rr *rr, struct dns_packet *P) {
3500         size_t len;
3501         int error;
3502
3503         if (!(len = dns_d_expand(ns->host, sizeof ns->host, rr->rd.p, P, &error)))
3504                 return error;
3505         else if (len >= sizeof ns->host)
3506                 return DNS_EILLEGAL;
3507
3508         return 0;
3509 } /* dns_ns_parse() */
3510
3511
3512 int dns_ns_push(struct dns_packet *P, struct dns_ns *ns) {
3513         size_t end, len;
3514         int error;
3515
3516         if (P->size - P->end < 3)
3517                 return DNS_ENOBUFS;
3518
3519         end     = P->end;
3520         P->end  += 2;
3521
3522         if ((error = dns_d_push(P, ns->host, strlen(ns->host))))
3523                 goto error;
3524
3525         len     = P->end - end - 2;
3526
3527         P->data[end + 0]        = 0xff & (len >> 8);
3528         P->data[end + 1]        = 0xff & (len >> 0);
3529
3530         return 0;
3531 error:
3532         P->end  = end;
3533
3534         return error;
3535 } /* dns_ns_push() */
3536
3537
3538 int dns_ns_cmp(const struct dns_ns *a, const struct dns_ns *b) {
3539         return strcasecmp(a->host, b->host);
3540 } /* dns_ns_cmp() */
3541
3542
3543 size_t dns_ns_print(void *dst, size_t lim, struct dns_ns *ns) {
3544         return dns_strlcpy(dst, ns->host, lim);
3545 } /* dns_ns_print() */
3546
3547
3548 size_t dns_ns_cname(void *dst, size_t lim, struct dns_ns *ns) {
3549         return dns_strlcpy(dst, ns->host, lim);
3550 } /* dns_ns_cname() */
3551
3552
3553 int dns_cname_parse(struct dns_cname *cname, struct dns_rr *rr, struct dns_packet *P) {
3554         return dns_ns_parse((struct dns_ns *)cname, rr, P);
3555 } /* dns_cname_parse() */
3556
3557
3558 int dns_cname_push(struct dns_packet *P, struct dns_cname *cname) {
3559         return dns_ns_push(P, (struct dns_ns *)cname);
3560 } /* dns_cname_push() */
3561
3562
3563 int dns_cname_cmp(const struct dns_cname *a, const struct dns_cname *b) {
3564         return strcasecmp(a->host, b->host);
3565 } /* dns_cname_cmp() */
3566
3567
3568 size_t dns_cname_print(void *dst, size_t lim, struct dns_cname *cname) {
3569         return dns_ns_print(dst, lim, (struct dns_ns *)cname);
3570 } /* dns_cname_pr