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