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