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