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