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