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