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