gpg: Do not bail on an invalid packet in the local keyring.
[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         int size_of_u = (int)sizeof u;
948
949         u.sin.sin_family        = af;
950
951         if (0 != WSAStringToAddressA((void *)src, af, (void *)0, (struct sockaddr *)&u, &size_of_u))
952                 return -1;
953
954         switch (af) {
955         case AF_INET6:
956                 *(struct in6_addr *)dst = u.sin6.sin6_addr;
957
958                 return 1;
959         case AF_INET:
960                 *(struct in_addr *)dst  = u.sin.sin_addr;
961
962                 return 1;
963         default:
964                 return 0;
965         }
966 } /* dns_inet_pton() */
967
968 static const char *dns_inet_ntop(int af, const void *src, void *dst, unsigned long lim) {
969         union { struct sockaddr_in sin; struct sockaddr_in6 sin6; } u;
970
971         /* NOTE: WSAAddressToString will print .sin_port unless zeroed. */
972         memset(&u, 0, sizeof u);
973
974         u.sin.sin_family        = af;
975
976         switch (af) {
977         case AF_INET6:
978                 u.sin6.sin6_addr        = *(struct in6_addr *)src;
979                 break;
980         case AF_INET:
981                 u.sin.sin_addr          = *(struct in_addr *)src;
982
983                 break;
984         default:
985                 return 0;
986         }
987
988         if (0 != WSAAddressToStringA((struct sockaddr *)&u, dns_sa_len(&u), (void *)0, dst, &lim))
989                 return 0;
990
991         return dst;
992 } /* dns_inet_ntop() */
993 #else
994 #define dns_inet_pton(...)      inet_pton(__VA_ARGS__)
995 #define dns_inet_ntop(...)      inet_ntop(__VA_ARGS__)
996 #endif
997
998
999 static dns_error_t dns_pton(int af, const void *src, void *dst) {
1000         switch (dns_inet_pton(af, src, dst)) {
1001         case 1:
1002                 return 0;
1003         case -1:
1004                 return dns_soerr();
1005         default:
1006                 return DNS_EADDRESS;
1007         }
1008 } /* dns_pton() */
1009
1010
1011 static dns_error_t dns_ntop(int af, const void *src, void *dst, unsigned long lim) {
1012         return (dns_inet_ntop(af, src, dst, lim))? 0 : dns_soerr();
1013 } /* dns_ntop() */
1014
1015
1016 size_t dns_strlcpy(char *dst, const char *src, size_t lim) {
1017         char *d         = dst;
1018         char *e         = &dst[lim];
1019         const char *s   = src;
1020
1021         if (d < e) {
1022                 do {
1023                         if ('\0' == (*d++ = *s++))
1024                                 return s - src - 1;
1025                 } while (d < e);
1026
1027                 d[-1]   = '\0';
1028         }
1029
1030         while (*s++ != '\0')
1031                 ;;
1032
1033         return s - src - 1;
1034 } /* dns_strlcpy() */
1035
1036
1037 size_t dns_strlcat(char *dst, const char *src, size_t lim) {
1038         char *d = memchr(dst, '\0', lim);
1039         char *e = &dst[lim];
1040         const char *s = src;
1041         const char *p;
1042
1043         if (d && d < e) {
1044                 do {
1045                         if ('\0' == (*d++ = *s++))
1046                                 return d - dst - 1;
1047                 } while (d < e);
1048
1049                 d[-1] = '\0';
1050         }
1051
1052         p = s;
1053
1054         while (*s++ != '\0')
1055                 ;;
1056
1057         return lim + (s - p - 1);
1058 } /* dns_strlcat() */
1059
1060
1061 static void *dns_reallocarray(void *p, size_t nmemb, size_t size, dns_error_t *error) {
1062         void *rp;
1063
1064         if (nmemb > 0 && SIZE_MAX / nmemb < size) {
1065                 *error = EOVERFLOW;
1066                 return NULL;
1067         }
1068
1069         if (!(rp = realloc(p, nmemb * size)))
1070                 *error = (errno)? errno : EINVAL;
1071
1072         return rp;
1073 } /* dns_reallocarray() */
1074
1075
1076 #if _WIN32
1077
1078 static char *dns_strsep(char **sp, const char *delim) {
1079         char *p;
1080
1081         if (!(p = *sp))
1082                 return 0;
1083
1084         *sp += strcspn(p, delim);
1085
1086         if (**sp != '\0') {
1087                 **sp = '\0';
1088                 ++*sp;
1089         } else
1090                 *sp = NULL;
1091
1092         return p;
1093 } /* dns_strsep() */
1094
1095 #else
1096 #define dns_strsep(...) strsep(__VA_ARGS__)
1097 #endif
1098
1099
1100 #if _WIN32
1101 #define strcasecmp(...)         _stricmp(__VA_ARGS__)
1102 #define strncasecmp(...)        _strnicmp(__VA_ARGS__)
1103 #endif
1104
1105
1106 static inline _Bool dns_isalpha(unsigned char c) {
1107         return isalpha(c);
1108 } /* dns_isalpha() */
1109
1110 static inline _Bool dns_isdigit(unsigned char c) {
1111         return isdigit(c);
1112 } /* dns_isdigit() */
1113
1114 static inline _Bool dns_isalnum(unsigned char c) {
1115         return isalnum(c);
1116 } /* dns_isalnum() */
1117
1118 static inline _Bool dns_isspace(unsigned char c) {
1119         return isspace(c);
1120 } /* dns_isspace() */
1121
1122 static inline _Bool dns_isgraph(unsigned char c) {
1123         return isgraph(c);
1124 } /* dns_isgraph() */
1125
1126
1127 static int dns_poll(int fd, short events, int timeout) {
1128         fd_set rset, wset;
1129         struct timeval tv = { timeout, 0 };
1130
1131         if (!events)
1132                 return 0;
1133
1134         if (fd < 0 || (unsigned)fd >= FD_SETSIZE)
1135           return EINVAL;
1136
1137         FD_ZERO(&rset);
1138         FD_ZERO(&wset);
1139
1140         if (events & DNS_POLLIN)
1141                 FD_SET(fd, &rset);
1142
1143         if (events & DNS_POLLOUT)
1144                 FD_SET(fd, &wset);
1145
1146         select(fd + 1, &rset, &wset, 0, (timeout >= 0)? &tv : NULL);
1147
1148         return 0;
1149 } /* dns_poll() */
1150
1151
1152 #if !_WIN32
1153 DNS_NOTUSED static int dns_sigmask(int how, const sigset_t *set, sigset_t *oset) {
1154 #if DNS_THREAD_SAFE
1155         return pthread_sigmask(how, set, oset);
1156 #else
1157         return (0 == sigprocmask(how, set, oset))? 0 : errno;
1158 #endif
1159 } /* dns_sigmask() */
1160 #endif
1161
1162
1163 static size_t dns_send(int fd, const void *src, size_t len, int flags, dns_error_t *error) {
1164         long n = send(fd, src, len, flags);
1165
1166         if (n < 0) {
1167                 *error = dns_soerr();
1168                 return 0;
1169         } else {
1170                 *error = 0;
1171                 return n;
1172         }
1173 } /* dns_send() */
1174
1175 static size_t dns_recv(int fd, void *dst, size_t lim, int flags, dns_error_t *error) {
1176         long n = recv(fd, dst, lim, flags);
1177
1178         if (n < 0) {
1179                 *error = dns_soerr();
1180                 return 0;
1181         } else if (n == 0) {
1182                 *error = (lim > 0)? DNS_ECONNFIN : EINVAL;
1183                 return 0;
1184         } else {
1185                 *error = 0;
1186                 return n;
1187         }
1188 } /* dns_recv() */
1189
1190 static size_t dns_send_nopipe(int fd, const void *src, size_t len, int flags, dns_error_t *_error) {
1191 #if _WIN32 || !defined SIGPIPE || defined SO_NOSIGPIPE
1192         return dns_send(fd, src, len, flags, _error);
1193 #elif defined MSG_NOSIGNAL
1194         return dns_send(fd, src, len, (flags|MSG_NOSIGNAL), _error);
1195 #elif _POSIX_REALTIME_SIGNALS > 0 /* require sigtimedwait */
1196         /*
1197          * SIGPIPE handling similar to the approach described in
1198          * http://krokisplace.blogspot.com/2010/02/suppressing-sigpipe-in-library.html
1199          */
1200         sigset_t pending, blocked, piped;
1201         size_t count;
1202         int error;
1203
1204         sigemptyset(&pending);
1205         sigpending(&pending);
1206
1207         if (!sigismember(&pending, SIGPIPE)) {
1208                 sigemptyset(&piped);
1209                 sigaddset(&piped, SIGPIPE);
1210                 sigemptyset(&blocked);
1211
1212                 if ((error = dns_sigmask(SIG_BLOCK, &piped, &blocked)))
1213                         goto error;
1214         }
1215
1216         count = dns_send(fd, src, len, flags, &error);
1217
1218         if (!sigismember(&pending, SIGPIPE)) {
1219                 int saved = error;
1220                 const struct timespec ts = { 0, 0 };
1221
1222                 if (!count && error == EPIPE) {
1223                         while (-1 == sigtimedwait(&piped, NULL, &ts) && errno == EINTR)
1224                                 ;;
1225                 }
1226
1227                 if ((error = dns_sigmask(SIG_SETMASK, &blocked, NULL)))
1228                         goto error;
1229
1230                 error = saved;
1231         }
1232
1233         *_error = error;
1234         return count;
1235 error:
1236         *_error = error;
1237         return 0;
1238 #else
1239 #error "unable to suppress SIGPIPE"
1240         return dns_send(fd, src, len, flags, _error);
1241 #endif
1242 } /* dns_send_nopipe() */
1243
1244
1245 static dns_error_t dns_connect(int fd, const struct sockaddr *addr, socklen_t addrlen) {
1246         if (0 != connect(fd, addr, addrlen))
1247                 return dns_soerr();
1248         return 0;
1249 } /* dns_connect() */
1250
1251
1252 #define DNS_FOPEN_STDFLAGS "rwabt+"
1253
1254 static dns_error_t dns_fopen_addflag(char *dst, const char *src, size_t lim, int fc) {
1255         char *p = dst, *pe = dst + lim;
1256
1257         /* copy standard flags */
1258         while (*src && strchr(DNS_FOPEN_STDFLAGS, *src)) {
1259                 if (!(p < pe))
1260                         return ENOMEM;
1261                 *p++ = *src++;
1262         }
1263
1264         /* append flag to standard flags */
1265         if (!(p < pe))
1266                 return ENOMEM;
1267         *p++ = fc;
1268
1269         /* copy remaining mode string, including '\0' */
1270         do {
1271                 if (!(p < pe))
1272                         return ENOMEM;
1273         } while ((*p++ = *src++));
1274
1275         return 0;
1276 } /* dns_fopen_addflag() */
1277
1278 static FILE *dns_fopen(const char *path, const char *mode, dns_error_t *_error) {
1279         FILE *fp;
1280         char mode_cloexec[32];
1281         int error;
1282
1283         assert(path && mode && *mode);
1284         if (!*path) {
1285                 error = EINVAL;
1286                 goto error;
1287         }
1288
1289 #if _WIN32 || _WIN64
1290         if ((error = dns_fopen_addflag(mode_cloexec, mode, sizeof mode_cloexec, 'N')))
1291                 goto error;
1292         if (!(fp = fopen(path, mode_cloexec)))
1293                 goto syerr;
1294 #else
1295         if ((error = dns_fopen_addflag(mode_cloexec, mode, sizeof mode_cloexec, 'e')))
1296                 goto error;
1297         if (!(fp = fopen(path, mode_cloexec))) {
1298                 if (errno != EINVAL)
1299                         goto syerr;
1300                 if (!(fp = fopen(path, mode)))
1301                         goto syerr;
1302         }
1303 #endif
1304
1305         return fp;
1306 syerr:
1307         error = dns_syerr();
1308 error:
1309         *_error = error;
1310
1311         return NULL;
1312 } /* dns_fopen() */
1313
1314
1315 struct dns_hxd_lines_i {
1316         int pc;
1317         size_t p;
1318 };
1319
1320 #define DNS_SM_RESTORE \
1321         do { \
1322                 pc = state->pc; \
1323                 sp = src + state->p; \
1324                 se = src + len; \
1325         } while (0)
1326 #define DNS_SM_SAVE \
1327         do { \
1328                 state->p = sp - src; \
1329                 state->pc = pc; \
1330         } while (0)
1331
1332 static size_t dns_hxd_lines(void *dst, size_t lim, const unsigned char *src, size_t len, struct dns_hxd_lines_i *state) {
1333         static const unsigned char hex[] = "0123456789abcdef";
1334         static const unsigned char tmpl[] = "                                                    |                |\n";
1335         unsigned char ln[sizeof tmpl];
1336         const unsigned char *sp, *se;
1337         unsigned char *h, *g;
1338         unsigned i, n;
1339         int pc;
1340
1341         DNS_SM_ENTER;
1342
1343         while (sp < se) {
1344                 memcpy(ln, tmpl, sizeof ln);
1345
1346                 h = &ln[2];
1347                 g = &ln[53];
1348
1349                 for (n = 0; n < 2; n++) {
1350                         for (i = 0; i < 8 && se - sp > 0; i++, sp++) {
1351                                 h[0] = hex[0x0f & (*sp >> 4)];
1352                                 h[1] = hex[0x0f & (*sp >> 0)];
1353                                 h += 3;
1354
1355                                 *g++ = (dns_isgraph(*sp))? *sp : '.';
1356                         }
1357
1358                         h++;
1359                 }
1360
1361                 n = dns_strlcpy(dst, (char *)ln, lim);
1362                 DNS_SM_YIELD(n);
1363         }
1364
1365         DNS_SM_EXIT;
1366         DNS_SM_LEAVE;
1367
1368         return 0;
1369 }
1370
1371 #undef DNS_SM_SAVE
1372 #undef DNS_SM_RESTORE
1373
1374 /*
1375  * A R I T H M E T I C  R O U T I N E S
1376  *
1377  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1378
1379 #define DNS_CHECK_OVERFLOW(error, r, f, ...) \
1380         do { \
1381                 uintmax_t _r; \
1382                 *(error) = f(&_r, __VA_ARGS__); \
1383                 *(r) = _r; \
1384         } while (0)
1385
1386 static dns_error_t dns_clamp_overflow(uintmax_t *r, uintmax_t n, uintmax_t clamp) {
1387         if (n > clamp) {
1388                 *r = clamp;
1389                 return ERANGE;
1390         } else {
1391                 *r = n;
1392                 return 0;
1393         }
1394 } /* dns_clamp_overflow() */
1395
1396 static dns_error_t dns_add_overflow(uintmax_t *r, uintmax_t a, uintmax_t b, uintmax_t clamp) {
1397         if (~a < b) {
1398                 *r = DNS_PP_MIN(clamp, ~UINTMAX_C(0));
1399                 return ERANGE;
1400         } else {
1401                 return dns_clamp_overflow(r, a + b, clamp);
1402         }
1403 } /* dns_add_overflow() */
1404
1405 static dns_error_t dns_mul_overflow(uintmax_t *r, uintmax_t a, uintmax_t b, uintmax_t clamp) {
1406         if (a > 0 && UINTMAX_MAX / a < b) {
1407                 *r = DNS_PP_MIN(clamp, ~UINTMAX_C(0));
1408                 return ERANGE;
1409         } else {
1410                 return dns_clamp_overflow(r, a * b, clamp);
1411         }
1412 } /* dns_mul_overflow() */
1413
1414 /*
1415  * F I X E D - S I Z E D  B U F F E R  R O U T I N E S
1416  *
1417  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1418
1419 #define DNS_B_INIT(src, n) { \
1420         (unsigned char *)(src), \
1421         (unsigned char *)(src), \
1422         (unsigned char *)(src) + (n), \
1423 }
1424
1425 #define DNS_B_FROM(src, n) DNS_B_INIT((src), (n))
1426 #define DNS_B_INTO(src, n) DNS_B_INIT((src), (n))
1427
1428 struct dns_buf {
1429         const unsigned char *base;
1430         unsigned char *p;
1431         const unsigned char *pe;
1432         dns_error_t error;
1433         size_t overflow;
1434 }; /* struct dns_buf */
1435
1436 static inline size_t
1437 dns_b_tell(struct dns_buf *b)
1438 {
1439         return b->p - b->base;
1440 }
1441
1442 static inline dns_error_t
1443 dns_b_setoverflow(struct dns_buf *b, size_t n, dns_error_t error)
1444 {
1445         b->overflow += n;
1446         return b->error = error;
1447 }
1448
1449 DNS_NOTUSED static struct dns_buf *
1450 dns_b_into(struct dns_buf *b, void *src, size_t n)
1451 {
1452         *b = (struct dns_buf)DNS_B_INTO(src, n);
1453
1454         return b;
1455 }
1456
1457 static dns_error_t
1458 dns_b_putc(struct dns_buf *b, unsigned char uc)
1459 {
1460         if (!(b->p < b->pe))
1461                 return dns_b_setoverflow(b, 1, DNS_ENOBUFS);
1462
1463         *b->p++ = uc;
1464
1465         return 0;
1466 }
1467
1468 static dns_error_t
1469 dns_b_pputc(struct dns_buf *b, unsigned char uc, size_t p)
1470 {
1471         size_t pe = b->pe - b->base;
1472         if (pe <= p)
1473                 return dns_b_setoverflow(b, p - pe + 1, DNS_ENOBUFS);
1474
1475         *((unsigned char *)b->base + p) = uc;
1476
1477         return 0;
1478 }
1479
1480 static inline dns_error_t
1481 dns_b_put16(struct dns_buf *b, uint16_t u)
1482 {
1483         return dns_b_putc(b, u >> 8), dns_b_putc(b, u >> 0);
1484 }
1485
1486 static inline dns_error_t
1487 dns_b_pput16(struct dns_buf *b, uint16_t u, size_t p)
1488 {
1489         if (dns_b_pputc(b, u >> 8, p) || dns_b_pputc(b, u >> 0, p + 1))
1490                 return b->error;
1491
1492         return 0;
1493 }
1494
1495 DNS_NOTUSED static inline dns_error_t
1496 dns_b_put32(struct dns_buf *b, uint32_t u)
1497 {
1498         return dns_b_putc(b, u >> 24), dns_b_putc(b, u >> 16),
1499             dns_b_putc(b, u >> 8), dns_b_putc(b, u >> 0);
1500 }
1501
1502 static dns_error_t
1503 dns_b_put(struct dns_buf *b, const void *src, size_t len)
1504 {
1505         size_t n = DNS_PP_MIN((size_t)(b->pe - b->p), len);
1506
1507         memcpy(b->p, src, n);
1508         b->p += n;
1509
1510         if (n < len)
1511                 return dns_b_setoverflow(b, len - n, DNS_ENOBUFS);
1512
1513         return 0;
1514 }
1515
1516 static dns_error_t
1517 dns_b_puts(struct dns_buf *b, const void *src)
1518 {
1519         return dns_b_put(b, src, strlen(src));
1520 }
1521
1522 DNS_NOTUSED static inline dns_error_t
1523 dns_b_fmtju(struct dns_buf *b, const uintmax_t u, const unsigned width)
1524 {
1525         size_t digits, padding, overflow;
1526         uintmax_t r;
1527         unsigned char *tp, *te, tc;
1528
1529         digits = 0;
1530         r = u;
1531         do {
1532                 digits++;
1533                 r /= 10;
1534         } while (r);
1535
1536         padding = width - DNS_PP_MIN(digits, width);
1537         overflow = (digits + padding) - DNS_PP_MIN((size_t)(b->pe - b->p), (digits + padding));
1538
1539         while (padding--) {
1540                 dns_b_putc(b, '0');
1541         }
1542
1543         digits = 0;
1544         tp = b->p;
1545         r = u;
1546         do {
1547                 if (overflow < ++digits)
1548                         dns_b_putc(b, '0' + (r % 10));
1549                 r /= 10;
1550         } while (r);
1551
1552         te = b->p;
1553         while (tp < te) {
1554                 tc = *--te;
1555                 *te = *tp;
1556                 *tp++ = tc;
1557         }
1558
1559         return b->error;
1560 }
1561
1562 static void
1563 dns_b_popc(struct dns_buf *b)
1564 {
1565         if (b->overflow && !--b->overflow)
1566                 b->error = 0;
1567         if (b->p > b->base)
1568                 b->p--;
1569 }
1570
1571 static inline const char *
1572 dns_b_tolstring(struct dns_buf *b, size_t *n)
1573 {
1574         if (b->p < b->pe) {
1575                 *b->p = '\0';
1576                 *n = b->p - b->base;
1577
1578                 return (const char *)b->base;
1579         } else if (b->p > b->base) {
1580                 if (b->p[-1] != '\0') {
1581                         dns_b_setoverflow(b, 1, DNS_ENOBUFS);
1582                         b->p[-1] = '\0';
1583                 }
1584                 *n = &b->p[-1] - b->base;
1585
1586                 return (const char *)b->base;
1587         } else {
1588                 *n = 0;
1589
1590                 return "";
1591         }
1592 }
1593
1594 static inline const char *
1595 dns_b_tostring(struct dns_buf *b)
1596 {
1597         size_t n;
1598         return dns_b_tolstring(b, &n);
1599 }
1600
1601 static inline size_t
1602 dns_b_strlen(struct dns_buf *b)
1603 {
1604         size_t n;
1605         dns_b_tolstring(b, &n);
1606         return n;
1607 }
1608
1609 static inline size_t
1610 dns_b_strllen(struct dns_buf *b)
1611 {
1612         size_t n = dns_b_strlen(b);
1613         return n + b->overflow;
1614 }
1615
1616 DNS_NOTUSED static const struct dns_buf *
1617 dns_b_from(const struct dns_buf *b, const void *src, size_t n)
1618 {
1619         *(struct dns_buf *)b = (struct dns_buf)DNS_B_FROM(src, n);
1620
1621         return b;
1622 }
1623
1624 static inline int
1625 dns_b_getc(const struct dns_buf *_b, const int eof)
1626 {
1627         struct dns_buf *b = (struct dns_buf *)_b;
1628
1629         if (!(b->p < b->pe))
1630                 return dns_b_setoverflow(b, 1, DNS_EILLEGAL), eof;
1631
1632         return *b->p++;
1633 }
1634
1635 static inline intmax_t
1636 dns_b_get16(const struct dns_buf *b, const intmax_t eof)
1637 {
1638         intmax_t n;
1639
1640         n = (dns_b_getc(b, 0) << 8);
1641         n |= (dns_b_getc(b, 0) << 0);
1642
1643         return (!b->overflow)? n : eof;
1644 }
1645
1646 DNS_NOTUSED static inline intmax_t
1647 dns_b_get32(const struct dns_buf *b, const intmax_t eof)
1648 {
1649         intmax_t n;
1650
1651         n = (dns_b_get16(b, 0) << 16);
1652         n |= (dns_b_get16(b, 0) << 0);
1653
1654         return (!b->overflow)? n : eof;
1655 }
1656
1657 static inline dns_error_t
1658 dns_b_move(struct dns_buf *dst, const struct dns_buf *_src, size_t n)
1659 {
1660         struct dns_buf *src = (struct dns_buf *)_src;
1661         size_t src_n = DNS_PP_MIN((size_t)(src->pe - src->p), n);
1662         size_t src_r = n - src_n;
1663
1664         dns_b_put(dst, src->p, src_n);
1665         src->p += src_n;
1666
1667         if (src_r)
1668                 return dns_b_setoverflow(src, src_r, DNS_EILLEGAL);
1669
1670         return dst->error;
1671 }
1672
1673 /*
1674  * T I M E  R O U T I N E S
1675  *
1676  * Most functions still rely on the older time routines defined in the
1677  * utility routines section, above.
1678  *
1679  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1680
1681 #define DNS_TIME_C(n) UINT64_C(n)
1682 #define DNS_TIME_INF (~DNS_TIME_C(0))
1683
1684 typedef uint64_t dns_time_t;
1685 typedef dns_time_t dns_microseconds_t;
1686
1687 static dns_error_t dns_time_add(dns_time_t *r, dns_time_t a, dns_time_t b) {
1688         int error;
1689         DNS_CHECK_OVERFLOW(&error, r, dns_add_overflow, a, b, DNS_TIME_INF);
1690         return error;
1691 }
1692
1693 static dns_error_t dns_time_mul(dns_time_t *r, dns_time_t a, dns_time_t b) {
1694         int error;
1695         DNS_CHECK_OVERFLOW(&error, r, dns_mul_overflow, a, b, DNS_TIME_INF);
1696         return error;
1697 }
1698
1699 static dns_error_t dns_time_diff(dns_time_t *r, dns_time_t a, dns_time_t b) {
1700         if (a < b) {
1701                 *r = DNS_TIME_C(0);
1702                 return ERANGE;
1703         } else {
1704                 *r = a - b;
1705                 return 0;
1706         }
1707 }
1708
1709 static dns_microseconds_t dns_ts2us(const struct timespec *ts, _Bool rup) {
1710         if (ts) {
1711                 dns_time_t sec = DNS_PP_MAX(0, ts->tv_sec);
1712                 dns_time_t nsec = DNS_PP_MAX(0, ts->tv_nsec);
1713                 dns_time_t usec = nsec / 1000;
1714                 dns_microseconds_t r;
1715
1716                 if (rup && nsec % 1000 > 0)
1717                         usec++;
1718                 dns_time_mul(&r, sec, DNS_TIME_C(1000000));
1719                 dns_time_add(&r, r, usec);
1720
1721                 return r;
1722         } else {
1723                 return DNS_TIME_INF;
1724         }
1725 } /* dns_ts2us() */
1726
1727 static struct timespec *dns_tv2ts(struct timespec *ts, const struct timeval *tv) {
1728         if (tv) {
1729                 ts->tv_sec = tv->tv_sec;
1730                 ts->tv_nsec = tv->tv_usec * 1000;
1731
1732                 return ts;
1733         } else {
1734                 return NULL;
1735         }
1736 } /* dns_tv2ts() */
1737
1738 static size_t dns_utime_print(void *_dst, size_t lim, dns_microseconds_t us) {
1739         struct dns_buf dst = DNS_B_INTO(_dst, lim);
1740
1741         dns_b_fmtju(&dst, us / 1000000, 1);
1742         dns_b_putc(&dst, '.');
1743         dns_b_fmtju(&dst, us % 1000000, 6);
1744
1745         return dns_b_strllen(&dst);
1746 } /* dns_utime_print() */
1747
1748 /*
1749  * P A C K E T  R O U T I N E S
1750  *
1751  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1752
1753 unsigned dns_p_count(struct dns_packet *P, enum dns_section section) {
1754         unsigned count;
1755
1756         switch (section) {
1757         case DNS_S_QD:
1758                 return ntohs(dns_header(P)->qdcount);
1759         case DNS_S_AN:
1760                 return ntohs(dns_header(P)->ancount);
1761         case DNS_S_NS:
1762                 return ntohs(dns_header(P)->nscount);
1763         case DNS_S_AR:
1764                 return ntohs(dns_header(P)->arcount);
1765         default:
1766                 count = 0;
1767
1768                 if (section & DNS_S_QD)
1769                         count += ntohs(dns_header(P)->qdcount);
1770                 if (section & DNS_S_AN)
1771                         count += ntohs(dns_header(P)->ancount);
1772                 if (section & DNS_S_NS)
1773                         count += ntohs(dns_header(P)->nscount);
1774                 if (section & DNS_S_AR)
1775                         count += ntohs(dns_header(P)->arcount);
1776
1777                 return count;
1778         }
1779 } /* dns_p_count() */
1780
1781
1782 struct dns_packet *dns_p_init(struct dns_packet *P, size_t size) {
1783         if (!P)
1784                 return 0;
1785
1786         assert(size >= offsetof(struct dns_packet, data) + 12);
1787
1788         memset(P, 0, sizeof *P);
1789         P->size = size - offsetof(struct dns_packet, data);
1790         P->end  = 12;
1791
1792         memset(P->data, '\0', 12);
1793
1794         return P;
1795 } /* dns_p_init() */
1796
1797
1798 static struct dns_packet *dns_p_reset(struct dns_packet *P) {
1799         return dns_p_init(P, offsetof(struct dns_packet, data) + P->size);
1800 } /* dns_p_reset() */
1801
1802
1803 static unsigned short dns_p_qend(struct dns_packet *P) {
1804         unsigned short qend     = 12;
1805         unsigned i, count       = dns_p_count(P, DNS_S_QD);
1806
1807         for (i = 0; i < count && qend < P->end; i++) {
1808                 if (P->end == (qend = dns_d_skip(qend, P)))
1809                         goto invalid;
1810
1811                 if (P->end - qend < 4)
1812                         goto invalid;
1813
1814                 qend    += 4;
1815         }
1816
1817         return DNS_PP_MIN(qend, P->end);
1818 invalid:
1819         return P->end;
1820 } /* dns_p_qend() */
1821
1822
1823 struct dns_packet *dns_p_make(size_t len, int *error) {
1824         struct dns_packet *P;
1825         size_t size = dns_p_calcsize(len);
1826
1827         if (!(P = dns_p_init(malloc(size), size)))
1828                 *error = dns_syerr();
1829
1830         return P;
1831 } /* dns_p_make() */
1832
1833
1834 static void dns_p_free(struct dns_packet *P) {
1835         free(P);
1836 } /* dns_p_free() */
1837
1838
1839 /* convenience routine to free any existing packet before storing new packet */
1840 static struct dns_packet *dns_p_setptr(struct dns_packet **dst, struct dns_packet *src) {
1841         dns_p_free(*dst);
1842
1843         *dst = src;
1844
1845         return src;
1846 } /* dns_p_setptr() */
1847
1848
1849 static struct dns_packet *dns_p_movptr(struct dns_packet **dst, struct dns_packet **src) {
1850         dns_p_setptr(dst, *src);
1851
1852         *src = NULL;
1853
1854         return *dst;
1855 } /* dns_p_movptr() */
1856
1857
1858 int dns_p_grow(struct dns_packet **P) {
1859         struct dns_packet *tmp;
1860         size_t size;
1861         int error;
1862
1863         if (!*P) {
1864                 if (!(*P = dns_p_make(DNS_P_QBUFSIZ, &error)))
1865                         return error;
1866
1867                 return 0;
1868         }
1869
1870         size = dns_p_sizeof(*P);
1871         size |= size >> 1;
1872         size |= size >> 2;
1873         size |= size >> 4;
1874         size |= size >> 8;
1875         size++;
1876
1877         if (size > 65536)
1878                 return DNS_ENOBUFS;
1879
1880         if (!(tmp = realloc(*P, dns_p_calcsize(size))))
1881                 return dns_syerr();
1882
1883         tmp->size = size;
1884         *P = tmp;
1885
1886         return 0;
1887 } /* dns_p_grow() */
1888
1889
1890 struct dns_packet *dns_p_copy(struct dns_packet *P, const struct dns_packet *P0) {
1891         if (!P)
1892                 return 0;
1893
1894         P->end  = DNS_PP_MIN(P->size, P0->end);
1895
1896         memcpy(P->data, P0->data, P->end);
1897
1898         return P;
1899 } /* dns_p_copy() */
1900
1901
1902 struct dns_packet *dns_p_merge(struct dns_packet *A, enum dns_section Amask, struct dns_packet *B, enum dns_section Bmask, int *error_) {
1903         size_t bufsiz = DNS_PP_MIN(65535, ((A)? A->end : 0) + ((B)? B->end : 0));
1904         struct dns_packet *M;
1905         enum dns_section section;
1906         struct dns_rr rr, mr;
1907         int error, copy;
1908
1909         if (!A && B) {
1910                 A = B;
1911                 Amask = Bmask;
1912                 B = 0;
1913         }
1914
1915 merge:
1916         if (!(M = dns_p_make(bufsiz, &error)))
1917                 goto error;
1918
1919         for (section = DNS_S_QD; (DNS_S_ALL & section); section <<= 1) {
1920                 if (A && (section & Amask)) {
1921                         dns_rr_foreach(&rr, A, .section = section) {
1922                                 if ((error = dns_rr_copy(M, &rr, A)))
1923                                         goto error;
1924                         }
1925                 }
1926
1927                 if (B && (section & Bmask)) {
1928                         dns_rr_foreach(&rr, B, .section = section) {
1929                                 copy = 1;
1930
1931                                 dns_rr_foreach(&mr, M, .type = rr.type, .section = DNS_S_ALL) {
1932                                         if (!(copy = dns_rr_cmp(&rr, B, &mr, M)))
1933                                                 break;
1934                                 }
1935
1936                                 if (copy && (error = dns_rr_copy(M, &rr, B)))
1937                                         goto error;
1938                         }
1939                 }
1940         }
1941
1942         return M;
1943 error:
1944         dns_p_setptr(&M, NULL);
1945
1946         if (error == DNS_ENOBUFS && bufsiz < 65535) {
1947                 bufsiz = DNS_PP_MIN(65535, bufsiz * 2);
1948
1949                 goto merge;
1950         }
1951
1952         *error_ = error;
1953
1954         return 0;
1955 } /* dns_p_merge() */
1956
1957
1958 static unsigned short dns_l_skip(unsigned short, const unsigned char *, size_t);
1959
1960 void dns_p_dictadd(struct dns_packet *P, unsigned short dn) {
1961         unsigned short lp, lptr, i;
1962
1963         lp      = dn;
1964
1965         while (lp < P->end) {
1966                 if (0xc0 == (0xc0 & P->data[lp]) && P->end - lp >= 2 && lp != dn) {
1967                         lptr    = ((0x3f & P->data[lp + 0]) << 8)
1968                                 | ((0xff & P->data[lp + 1]) << 0);
1969
1970                         for (i = 0; i < lengthof(P->dict) && P->dict[i]; i++) {
1971                                 if (P->dict[i] == lptr) {
1972                                         P->dict[i]      = dn;
1973
1974                                         return;
1975                                 }
1976                         }
1977                 }
1978
1979                 lp      = dns_l_skip(lp, P->data, P->end);
1980         }
1981
1982         for (i = 0; i < lengthof(P->dict); i++) {
1983                 if (!P->dict[i]) {
1984                         P->dict[i]      = dn;
1985
1986                         break;
1987                 }
1988         }
1989 } /* dns_p_dictadd() */
1990
1991
1992 static inline uint16_t
1993 plus1_ns (uint16_t count_net)
1994 {
1995   uint16_t count = ntohs (count_net);
1996
1997   count++;
1998   return htons (count);
1999 }
2000
2001 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) {
2002         size_t end = P->end;
2003         int error;
2004
2005         if ((error = dns_d_push(P, dn, dnlen)))
2006                 goto error;
2007
2008         if (P->size - P->end < 4)
2009                 goto nobufs;
2010
2011         P->data[P->end++] = 0xff & (type >> 8);
2012         P->data[P->end++] = 0xff & (type >> 0);
2013
2014         P->data[P->end++] = 0xff & (class >> 8);
2015         P->data[P->end++] = 0xff & (class >> 0);
2016
2017         if (section == DNS_S_QD)
2018                 goto update;
2019
2020         if (P->size - P->end < 6)
2021                 goto nobufs;
2022
2023         if (type != DNS_T_OPT)
2024                 ttl = DNS_PP_MIN(ttl, 0x7fffffffU);
2025         P->data[P->end++] = ttl >> 24;
2026         P->data[P->end++] = ttl >> 16;
2027         P->data[P->end++] = ttl >> 8;
2028         P->data[P->end++] = ttl >> 0;
2029
2030         if ((error = dns_any_push(P, (union dns_any *)any, type)))
2031                 goto error;
2032
2033 update:
2034         switch (section) {
2035         case DNS_S_QD:
2036                 if (dns_p_count(P, DNS_S_AN|DNS_S_NS|DNS_S_AR))
2037                         goto order;
2038
2039                 if (!P->memo.qd.base && (error = dns_p_study(P)))
2040                         goto error;
2041
2042                 dns_header(P)->qdcount = plus1_ns (dns_header(P)->qdcount);
2043
2044                 P->memo.qd.end  = P->end;
2045                 P->memo.an.base = P->end;
2046                 P->memo.an.end  = P->end;
2047                 P->memo.ns.base = P->end;
2048                 P->memo.ns.end  = P->end;
2049                 P->memo.ar.base = P->end;
2050                 P->memo.ar.end  = P->end;
2051
2052                 break;
2053         case DNS_S_AN:
2054                 if (dns_p_count(P, DNS_S_NS|DNS_S_AR))
2055                         goto order;
2056
2057                 if (!P->memo.an.base && (error = dns_p_study(P)))
2058                         goto error;
2059
2060                 dns_header(P)->ancount = plus1_ns (dns_header(P)->ancount);
2061
2062                 P->memo.an.end  = P->end;
2063                 P->memo.ns.base = P->end;
2064                 P->memo.ns.end  = P->end;
2065                 P->memo.ar.base = P->end;
2066                 P->memo.ar.end  = P->end;
2067
2068                 break;
2069         case DNS_S_NS:
2070                 if (dns_p_count(P, DNS_S_AR))
2071                         goto order;
2072
2073                 if (!P->memo.ns.base && (error = dns_p_study(P)))
2074                         goto error;
2075
2076                 dns_header(P)->nscount = plus1_ns (dns_header(P)->nscount);
2077
2078                 P->memo.ns.end  = P->end;
2079                 P->memo.ar.base = P->end;
2080                 P->memo.ar.end  = P->end;
2081
2082                 break;
2083         case DNS_S_AR:
2084                 if (!P->memo.ar.base && (error = dns_p_study(P)))
2085                         goto error;
2086
2087                 dns_header(P)->arcount = plus1_ns (dns_header(P)->arcount);
2088
2089                 P->memo.ar.end = P->end;
2090
2091                 if (type == DNS_T_OPT && !P->memo.opt.p) {
2092                         P->memo.opt.p = end;
2093                         P->memo.opt.maxudp = class;
2094                         P->memo.opt.ttl = ttl;
2095                 }
2096
2097                 break;
2098         default:
2099                 error = DNS_ESECTION;
2100
2101                 goto error;
2102         } /* switch() */
2103
2104         return 0;
2105 nobufs:
2106         error = DNS_ENOBUFS;
2107
2108         goto error;
2109 order:
2110         error = DNS_EORDER;
2111
2112         goto error;
2113 error:
2114         P->end = end;
2115
2116         return error;
2117 } /* dns_p_push() */
2118
2119 #define DNS_SM_RESTORE do { pc = state->pc; error = state->error; } while (0)
2120 #define DNS_SM_SAVE do { state->error = error; state->pc = pc; } while (0)
2121
2122 struct dns_p_lines_i {
2123         int pc;
2124         enum dns_section section;
2125         struct dns_rr rr;
2126         int error;
2127 };
2128
2129 static size_t dns_p_lines_fmt(void *dst, size_t lim, dns_error_t *_error, const char *fmt, ...) {
2130         va_list ap;
2131         int error = 0, n;
2132
2133         va_start(ap, fmt);
2134         if ((n = vsnprintf(dst, lim, fmt, ap)) < 0)
2135                 error = errno;
2136         va_end(ap);
2137
2138         *_error = error;
2139         return DNS_PP_MAX(n, 0);
2140 } /* dns_p_lines_fmt() */
2141
2142 #define DNS_P_LINE(...) \
2143         do { \
2144                 len = dns_p_lines_fmt(dst, lim, &error, __VA_ARGS__); \
2145                 if (len == 0 && error) \
2146                         goto error; \
2147                 DNS_SM_YIELD(len); \
2148         } while (0)
2149
2150 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) {
2151         int error, pc;
2152         size_t len;
2153
2154         *_error = 0;
2155
2156         DNS_SM_ENTER;
2157
2158         DNS_P_LINE(";; [HEADER]\n");
2159         DNS_P_LINE(";;    qid : %d\n", ntohs(dns_header(P)->qid));
2160         DNS_P_LINE(";;     qr : %s(%d)\n", (dns_header(P)->qr)? "RESPONSE" : "QUERY", dns_header(P)->qr);
2161         DNS_P_LINE(";; opcode : %s(%d)\n", dns_stropcode(dns_header(P)->opcode), dns_header(P)->opcode);
2162         DNS_P_LINE(";;     aa : %s(%d)\n", (dns_header(P)->aa)? "AUTHORITATIVE" : "NON-AUTHORITATIVE", dns_header(P)->aa);
2163         DNS_P_LINE(";;     tc : %s(%d)\n", (dns_header(P)->tc)? "TRUNCATED" : "NOT-TRUNCATED", dns_header(P)->tc);
2164         DNS_P_LINE(";;     rd : %s(%d)\n", (dns_header(P)->rd)? "RECURSION-DESIRED" : "RECURSION-NOT-DESIRED", dns_header(P)->rd);
2165         DNS_P_LINE(";;     ra : %s(%d)\n", (dns_header(P)->ra)? "RECURSION-ALLOWED" : "RECURSION-NOT-ALLOWED", dns_header(P)->ra);
2166         DNS_P_LINE(";;  rcode : %s(%d)\n", dns_strrcode(dns_p_rcode(P)), dns_p_rcode(P));
2167
2168         while (dns_rr_grep(&state->rr, 1, I, P, &error)) {
2169                 if (state->section != state->rr.section) {
2170                         DNS_P_LINE("\n");
2171                         DNS_P_LINE(";; [%s:%d]\n", dns_strsection(state->rr.section), dns_p_count(P, state->rr.section));
2172                 }
2173
2174                 if (!(len = dns_rr_print(dst, lim, &state->rr, P, &error)))
2175                         goto error;
2176                 dns_strlcat(dst, "\n", lim);
2177                 DNS_SM_YIELD(len + 1);
2178
2179                 state->section = state->rr.section;
2180         }
2181
2182         if (error)
2183                 goto error;
2184
2185         DNS_SM_EXIT;
2186 error:
2187         for (;;) {
2188                 *_error = error;
2189                 DNS_SM_YIELD(0);
2190         }
2191
2192         DNS_SM_LEAVE;
2193
2194         *_error = 0;
2195         return 0;
2196 } /* dns_p_lines() */
2197
2198 #undef DNS_P_LINE
2199 #undef DNS_SM_SAVE
2200 #undef DNS_SM_RESTORE
2201
2202 static void dns_p_dump3(struct dns_packet *P, struct dns_rr_i *I, FILE *fp) {
2203         struct dns_p_lines_i lines = { 0 };
2204         char line[sizeof (union dns_any) * 2];
2205         size_t len;
2206         int error;
2207
2208         while ((len = dns_p_lines(line, sizeof line, &error, P, I, &lines))) {
2209                 if (len < sizeof line) {
2210                         fwrite(line, 1, len, fp);
2211                 } else {
2212                         fwrite(line, 1, sizeof line - 1, fp);
2213                         fputc('\n', fp);
2214                 }
2215         }
2216 } /* dns_p_dump3() */
2217
2218
2219 void dns_p_dump(struct dns_packet *P, FILE *fp) {
2220         struct dns_rr_i I_instance = { 0 };
2221         dns_p_dump3(P, &I_instance, fp);
2222 } /* dns_p_dump() */
2223
2224
2225 static void dns_s_unstudy(struct dns_s_memo *m)
2226         { m->base = 0; m->end = 0; }
2227
2228 static void dns_m_unstudy(struct dns_p_memo *m) {
2229         dns_s_unstudy(&m->qd);
2230         dns_s_unstudy(&m->an);
2231         dns_s_unstudy(&m->ns);
2232         dns_s_unstudy(&m->ar);
2233         m->opt.p = 0;
2234         m->opt.maxudp = 0;
2235         m->opt.ttl = 0;
2236 } /* dns_m_unstudy() */
2237
2238 static int dns_s_study(struct dns_s_memo *m, enum dns_section section, unsigned short base, struct dns_packet *P) {
2239         unsigned short count, rp;
2240
2241         count = dns_p_count(P, section);
2242
2243         for (rp = base; count && rp < P->end; count--)
2244                 rp = dns_rr_skip(rp, P);
2245
2246         m->base = base;
2247         m->end  = rp;
2248
2249         return 0;
2250 } /* dns_s_study() */
2251
2252 static int dns_m_study(struct dns_p_memo *m, struct dns_packet *P) {
2253         struct dns_rr rr;
2254         int error;
2255
2256         if ((error = dns_s_study(&m->qd, DNS_S_QD, 12, P)))
2257                 goto error;
2258         if ((error = dns_s_study(&m->an, DNS_S_AN, m->qd.end, P)))
2259                 goto error;
2260         if ((error = dns_s_study(&m->ns, DNS_S_NS, m->an.end, P)))
2261                 goto error;
2262         if ((error = dns_s_study(&m->ar, DNS_S_AR, m->ns.end, P)))
2263                 goto error;
2264
2265         m->opt.p = 0;
2266         m->opt.maxudp = 0;
2267         m->opt.ttl = 0;
2268         dns_rr_foreach(&rr, P, .type = DNS_T_OPT, .section = DNS_S_AR) {
2269                 m->opt.p = rr.dn.p;
2270                 m->opt.maxudp = rr.class;
2271                 m->opt.ttl = rr.ttl;
2272                 break;
2273         }
2274
2275         return 0;
2276 error:
2277         dns_m_unstudy(m);
2278
2279         return error;
2280 } /* dns_m_study() */
2281
2282 int dns_p_study(struct dns_packet *P) {
2283         return dns_m_study(&P->memo, P);
2284 } /* dns_p_study() */
2285
2286
2287 enum dns_rcode dns_p_rcode(struct dns_packet *P) {
2288         return 0xfff & ((P->memo.opt.ttl >> 20) | dns_header(P)->rcode);
2289 } /* dns_p_rcode() */
2290
2291
2292 /*
2293  * Q U E R Y  P A C K E T  R O U T I N E S
2294  *
2295  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2296
2297 #define DNS_Q_RD    0x1 /* recursion desired */
2298 #define DNS_Q_EDNS0 0x2 /* include OPT RR */
2299
2300 static dns_error_t
2301 dns_q_make2(struct dns_packet **_Q, const char *qname, size_t qlen, enum dns_type qtype, enum dns_class qclass, int qflags)
2302 {
2303         struct dns_packet *Q = NULL;
2304         int error;
2305
2306         if (dns_p_movptr(&Q, _Q)) {
2307                 dns_p_reset(Q);
2308         } else if (!(Q = dns_p_make(DNS_P_QBUFSIZ, &error))) {
2309                 goto error;
2310         }
2311
2312         if ((error = dns_p_push(Q, DNS_S_QD, qname, qlen, qtype, qclass, 0, 0)))
2313                 goto error;
2314
2315         dns_header(Q)->rd = !!(qflags & DNS_Q_RD);
2316
2317         if (qflags & DNS_Q_EDNS0) {
2318                 struct dns_opt opt = DNS_OPT_INIT(&opt);
2319
2320                 opt.version = 0; /* RFC 6891 version */
2321                 opt.maxudp = 4096;
2322
2323                 if ((error = dns_p_push(Q, DNS_S_AR, ".", 1, DNS_T_OPT, dns_opt_class(&opt), dns_opt_ttl(&opt), &opt)))
2324                         goto error;
2325         }
2326
2327         *_Q = Q;
2328
2329         return 0;
2330 error:
2331         dns_p_free(Q);
2332
2333         return error;
2334 }
2335
2336 static dns_error_t
2337 dns_q_make(struct dns_packet **Q, const char *qname, enum dns_type qtype, enum dns_class qclass, int qflags)
2338 {
2339         return dns_q_make2(Q, qname, strlen(qname), qtype, qclass, qflags);
2340 }
2341
2342 static dns_error_t
2343 dns_q_remake(struct dns_packet **Q, int qflags)
2344 {
2345         char qname[DNS_D_MAXNAME + 1];
2346         size_t qlen;
2347         struct dns_rr rr;
2348         int error;
2349
2350         assert(Q && *Q);
2351         if ((error = dns_rr_parse(&rr, 12, *Q)))
2352                 return error;
2353         if (!(qlen = dns_d_expand(qname, sizeof qname, rr.dn.p, *Q, &error)))
2354                 return error;
2355         if (qlen >= sizeof qname)
2356                 return DNS_EILLEGAL;
2357         return dns_q_make2(Q, qname, qlen, rr.type, rr.class, qflags);
2358 }
2359
2360 /*
2361  * D O M A I N  N A M E  R O U T I N E S
2362  *
2363  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2364
2365 #ifndef DNS_D_MAXPTRS
2366 #define DNS_D_MAXPTRS   127     /* Arbitrary; possible, valid depth is something like packet size / 2 + fudge. */
2367 #endif
2368
2369 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) {
2370         unsigned short len;
2371         unsigned nptrs  = 0;
2372
2373 retry:
2374         if (src >= end)
2375                 goto invalid;
2376
2377         switch (0x03 & (data[src] >> 6)) {
2378         case 0x00:
2379                 len     = (0x3f & (data[src++]));
2380
2381                 if (end - src < len)
2382                         goto invalid;
2383
2384                 if (lim > 0) {
2385                         memcpy(dst, &data[src], DNS_PP_MIN(lim, len));
2386
2387                         dst[DNS_PP_MIN(lim - 1, len)]   = '\0';
2388                 }
2389
2390                 *nxt    = src + len;
2391
2392                 return len;
2393         case 0x01:
2394                 goto invalid;
2395         case 0x02:
2396                 goto invalid;
2397         case 0x03:
2398                 if (++nptrs > DNS_D_MAXPTRS)
2399                         goto invalid;
2400
2401                 if (end - src < 2)
2402                         goto invalid;
2403
2404                 src     = ((0x3f & data[src + 0]) << 8)
2405                         | ((0xff & data[src + 1]) << 0);
2406
2407                 goto retry;
2408         } /* switch() */
2409
2410         /* NOT REACHED */
2411 invalid:
2412         *nxt    = end;
2413
2414         return 0;
2415 } /* dns_l_expand() */
2416
2417
2418 static unsigned short dns_l_skip(unsigned short src, const unsigned char *data, size_t end) {
2419         unsigned short len;
2420
2421         if (src >= end)
2422                 goto invalid;
2423
2424         switch (0x03 & (data[src] >> 6)) {
2425         case 0x00:
2426                 len     = (0x3f & (data[src++]));
2427
2428                 if (end - src < len)
2429                         goto invalid;
2430
2431                 return (len)? src + len : end;
2432         case 0x01:
2433                 goto invalid;
2434         case 0x02:
2435                 goto invalid;
2436         case 0x03:
2437                 return end;
2438         } /* switch() */
2439
2440         /* NOT REACHED */
2441 invalid:
2442         return end;
2443 } /* dns_l_skip() */
2444
2445
2446 static _Bool dns_d_isanchored(const void *_src, size_t len) {
2447         const unsigned char *src = _src;
2448         return len > 0 && src[len - 1] == '.';
2449 } /* dns_d_isanchored() */
2450
2451
2452 static size_t dns_d_ndots(const void *_src, size_t len) {
2453         const unsigned char *p = _src, *pe = p + len;
2454         size_t ndots = 0;
2455
2456         while ((p = memchr(p, '.', pe - p))) {
2457                 ndots++;
2458                 p++;
2459         }
2460
2461         return ndots;
2462 } /* dns_d_ndots() */
2463
2464
2465 static size_t dns_d_trim(void *dst_, size_t lim, const void *src_, size_t len, int flags) {
2466         unsigned char *dst = dst_;
2467         const unsigned char *src = src_;
2468         size_t dp = 0, sp = 0;
2469         int lc;
2470
2471         /* trim any leading dot(s) */
2472         while (sp < len && src[sp] == '.')
2473                 sp++;
2474
2475         for (lc = 0; sp < len; lc = src[sp++]) {
2476                 /* trim extra dot(s) */
2477                 if (src[sp] == '.' && lc == '.')
2478                         continue;
2479
2480                 if (dp < lim)
2481                         dst[dp] = src[sp];
2482
2483                 dp++;
2484         }
2485
2486         if ((flags & DNS_D_ANCHOR) && lc != '.') {
2487                 if (dp < lim)
2488                         dst[dp] = '.';
2489
2490                 dp++;
2491         }
2492
2493         if (lim > 0)
2494                 dst[DNS_PP_MIN(dp, lim - 1)] = '\0';
2495
2496         return dp;
2497 } /* dns_d_trim() */
2498
2499
2500 char *dns_d_init(void *dst, size_t lim, const void *src, size_t len, int flags) {
2501         if (flags & DNS_D_TRIM) {
2502                 dns_d_trim(dst, lim, src, len, flags);
2503         } if (flags & DNS_D_ANCHOR) {
2504                 dns_d_anchor(dst, lim, src, len);
2505         } else {
2506                 memmove(dst, src, DNS_PP_MIN(lim, len));
2507
2508                 if (lim > 0)
2509                         ((char *)dst)[DNS_PP_MIN(len, lim - 1)] = '\0';
2510         }
2511
2512         return dst;
2513 } /* dns_d_init() */
2514
2515
2516 size_t dns_d_anchor(void *dst, size_t lim, const void *src, size_t len) {
2517         if (len == 0)
2518                 return 0;
2519
2520         memmove(dst, src, DNS_PP_MIN(lim, len));
2521
2522         if (((const char *)src)[len - 1] != '.') {
2523                 if (len < lim)
2524                         ((char *)dst)[len]      = '.';
2525                 len++;
2526         }
2527
2528         if (lim > 0)
2529                 ((char *)dst)[DNS_PP_MIN(lim - 1, len)] = '\0';
2530
2531         return len;
2532 } /* dns_d_anchor() */
2533
2534
2535 size_t dns_d_cleave(void *dst, size_t lim, const void *src, size_t len) {
2536         const char *dot;
2537
2538         /* XXX: Skip any leading dot. Handles cleaving root ".". */
2539         if (len == 0 || !(dot = memchr((const char *)src + 1, '.', len - 1)))
2540                 return 0;
2541
2542         len     -= dot - (const char *)src;
2543
2544         /* XXX: Unless root, skip the label's trailing dot. */
2545         if (len > 1) {
2546                 src     = ++dot;
2547                 len--;
2548         } else
2549                 src     = dot;
2550
2551         memmove(dst, src, DNS_PP_MIN(lim, len));
2552
2553         if (lim > 0)
2554                 ((char *)dst)[DNS_PP_MIN(lim - 1, len)] = '\0';
2555
2556         return len;
2557 } /* dns_d_cleave() */
2558
2559
2560 size_t dns_d_comp(void *dst_, size_t lim, const void *src_, size_t len, struct dns_packet *P, int *error) {
2561         struct { unsigned char *b; size_t p, x; } dst, src;
2562         unsigned char ch        = '.';
2563
2564         dst.b   = dst_;
2565         dst.p   = 0;
2566         dst.x   = 1;
2567
2568         src.b   = (unsigned char *)src_;
2569         src.p   = 0;
2570         src.x   = 0;
2571
2572         while (src.x < len) {
2573                 ch      = src.b[src.x];
2574
2575                 if (ch == '.') {
2576                         if (dst.p < lim)
2577                                 dst.b[dst.p]    = (0x3f & (src.x - src.p));
2578
2579                         dst.p   = dst.x++;
2580                         src.p   = ++src.x;
2581                 } else {
2582                         if (dst.x < lim)
2583                                 dst.b[dst.x]    = ch;
2584
2585                         dst.x++;
2586                         src.x++;
2587                 }
2588         } /* while() */
2589
2590         if (src.x > src.p) {
2591                 if (dst.p < lim)
2592                         dst.b[dst.p]    = (0x3f & (src.x - src.p));
2593
2594                 dst.p   = dst.x;
2595         }
2596
2597         if (dst.p > 1) {
2598                 if (dst.p < lim)
2599                         dst.b[dst.p]    = 0x00;
2600
2601                 dst.p++;
2602         }
2603
2604 #if 1
2605         if (dst.p < lim) {
2606                 struct { unsigned char label[DNS_D_MAXLABEL + 1]; size_t len; unsigned short p, x, y; } a, b;
2607                 unsigned i;
2608
2609                 a.p     = 0;
2610
2611                 while ((a.len = dns_l_expand(a.label, sizeof a.label, a.p, &a.x, dst.b, lim))) {
2612                         for (i = 0; i < lengthof(P->dict) && P->dict[i]; i++) {
2613                                 b.p     = P->dict[i];
2614
2615                                 while ((b.len = dns_l_expand(b.label, sizeof b.label, b.p, &b.x, P->data, P->end))) {
2616                                         a.y     = a.x;
2617                                         b.y     = b.x;
2618
2619                                         while (a.len && b.len && 0 == strcasecmp((char *)a.label, (char *)b.label)) {
2620                                                 a.len = dns_l_expand(a.label, sizeof a.label, a.y, &a.y, dst.b, lim);
2621                                                 b.len = dns_l_expand(b.label, sizeof b.label, b.y, &b.y, P->data, P->end);
2622                                         }
2623
2624                                         if (a.len == 0 && b.len == 0 && b.p <= 0x3fff) {
2625                                                 dst.b[a.p++]    = 0xc0
2626                                                                 | (0x3f & (b.p >> 8));
2627                                                 dst.b[a.p++]    = (0xff & (b.p >> 0));
2628
2629                                                 /* silence static analyzers */
2630                                                 dns_assume(a.p > 0);
2631
2632                                                 return a.p;
2633                                         }
2634
2635                                         b.p     = b.x;
2636                                 } /* while() */
2637                         } /* for() */
2638
2639                         a.p     = a.x;
2640                 } /* while() */
2641         } /* if () */
2642 #endif
2643
2644         if (!dst.p)
2645                 *error = DNS_EILLEGAL;
2646
2647         return dst.p;
2648 } /* dns_d_comp() */
2649
2650
2651 unsigned short dns_d_skip(unsigned short src, struct dns_packet *P) {
2652         unsigned short len;
2653
2654         while (src < P->end) {
2655                 switch (0x03 & (P->data[src] >> 6)) {
2656                 case 0x00:      /* FOLLOWS */
2657                         len     = (0x3f & P->data[src++]);
2658
2659                         if (0 == len) {
2660 /* success ==> */               return src;
2661                         } else if (P->end - src > len) {
2662                                 src     += len;
2663
2664                                 break;
2665                         } else
2666                                 goto invalid;
2667
2668                         /* NOT REACHED */
2669                 case 0x01:      /* RESERVED */
2670                         goto invalid;
2671                 case 0x02:      /* RESERVED */
2672                         goto invalid;
2673                 case 0x03:      /* POINTER */
2674                         if (P->end - src < 2)
2675                                 goto invalid;
2676
2677                         src     += 2;
2678
2679 /* success ==> */       return src;
2680                 } /* switch() */
2681         } /* while() */
2682
2683 invalid:
2684         return P->end;
2685 } /* dns_d_skip() */
2686
2687
2688 #include <stdio.h>
2689
2690 size_t dns_d_expand(void *dst, size_t lim, unsigned short src, struct dns_packet *P, int *error) {
2691         size_t dstp     = 0;
2692         unsigned nptrs  = 0;
2693         unsigned char len;
2694
2695         while (src < P->end) {
2696                 switch ((0x03 & (P->data[src] >> 6))) {
2697                 case 0x00:      /* FOLLOWS */
2698                         len     = (0x3f & P->data[src]);
2699
2700                         if (0 == len) {
2701                                 if (dstp == 0) {
2702                                         if (dstp < lim)
2703                                                 ((unsigned char *)dst)[dstp]    = '.';
2704
2705                                         dstp++;
2706                                 }
2707
2708                                 /* NUL terminate */
2709                                 if (lim > 0)
2710                                         ((unsigned char *)dst)[DNS_PP_MIN(dstp, lim - 1)]       = '\0';
2711
2712 /* success ==> */               return dstp;
2713                         }
2714
2715                         src++;
2716
2717                         if (P->end - src < len)
2718                                 goto toolong;
2719
2720                         if (dstp < lim)
2721                                 memcpy(&((unsigned char *)dst)[dstp], &P->data[src], DNS_PP_MIN(len, lim - dstp));
2722
2723                         src     += len;
2724                         dstp    += len;
2725
2726                         if (dstp < lim)
2727                                 ((unsigned char *)dst)[dstp]    = '.';
2728
2729                         dstp++;
2730
2731                         nptrs   = 0;
2732
2733                         continue;
2734                 case 0x01:      /* RESERVED */
2735                         goto reserved;
2736                 case 0x02:      /* RESERVED */
2737                         goto reserved;
2738                 case 0x03:      /* POINTER */
2739                         if (++nptrs > DNS_D_MAXPTRS)
2740                                 goto toolong;
2741
2742                         if (P->end - src < 2)
2743                                 goto toolong;
2744
2745                         src     = ((0x3f & P->data[src + 0]) << 8)
2746                                 | ((0xff & P->data[src + 1]) << 0);
2747
2748                         continue;
2749                 } /* switch() */
2750         } /* while() */
2751
2752 toolong:
2753         *error  = DNS_EILLEGAL;
2754
2755         if (lim > 0)
2756                 ((unsigned char *)dst)[DNS_PP_MIN(dstp, lim - 1)]       = '\0';
2757
2758         return 0;
2759 reserved:
2760         *error  = DNS_EILLEGAL;
2761
2762         if (lim > 0)
2763                 ((unsigned char *)dst)[DNS_PP_MIN(dstp, lim - 1)]       = '\0';
2764
2765         return 0;
2766 } /* dns_d_expand() */
2767
2768
2769 int dns_d_push(struct dns_packet *P, const void *dn, size_t len) {
2770         size_t lim      = P->size - P->end;
2771         unsigned dp     = P->end;
2772         int error       = DNS_EILLEGAL; /* silence compiler */
2773
2774         len     = dns_d_comp(&P->data[dp], lim, dn, len, P, &error);
2775
2776         if (len == 0)
2777                 return error;
2778         if (len > lim)
2779                 return DNS_ENOBUFS;
2780
2781         P->end  += len;
2782
2783         dns_p_dictadd(P, dp);
2784
2785         return 0;
2786 } /* dns_d_push() */
2787
2788
2789 size_t dns_d_cname(void *dst, size_t lim, const void *dn, size_t len, struct dns_packet *P, int *error_) {
2790         char host[DNS_D_MAXNAME + 1];
2791         struct dns_rr_i i;
2792         struct dns_rr rr;
2793         unsigned depth;
2794         int error;
2795
2796         if (sizeof host <= dns_d_anchor(host, sizeof host, dn, len))
2797                 { error = ENAMETOOLONG; goto error; }
2798
2799         for (depth = 0; depth < 7; depth++) {
2800                 memset(&i, 0, sizeof i);
2801                 i.section       = DNS_S_ALL & ~DNS_S_QD;
2802                 i.name          = host;
2803                 i.type          = DNS_T_CNAME;
2804
2805                 if (!dns_rr_grep(&rr, 1, &i, P, &error))
2806                         break;
2807
2808                 if ((error = dns_cname_parse((struct dns_cname *)host, &rr, P)))
2809                         goto error;
2810         }
2811
2812         return dns_strlcpy(dst, host, lim);
2813 error:
2814         *error_ = error;
2815
2816         return 0;
2817 } /* dns_d_cname() */
2818
2819
2820 /*
2821  * R E S O U R C E  R E C O R D  R O U T I N E S
2822  *
2823  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2824
2825 int dns_rr_copy(struct dns_packet *P, struct dns_rr *rr, struct dns_packet *Q) {
2826         unsigned char dn[DNS_D_MAXNAME + 1];
2827         union dns_any any;
2828         size_t len;
2829         int error;
2830
2831         if (!(len = dns_d_expand(dn, sizeof dn, rr->dn.p, Q, &error)))
2832                 return error;
2833         else if (len >= sizeof dn)
2834                 return DNS_EILLEGAL;
2835
2836         if (rr->section != DNS_S_QD && (error = dns_any_parse(dns_any_init(&any, sizeof any), rr, Q)))
2837                 return error;
2838
2839         return dns_p_push(P, rr->section, dn, len, rr->type, rr->class, rr->ttl, &any);
2840 } /* dns_rr_copy() */
2841
2842
2843 int dns_rr_parse(struct dns_rr *rr, unsigned short src, struct dns_packet *P) {
2844         unsigned short p        = src;
2845
2846         if (src >= P->end)
2847                 goto invalid;
2848
2849         rr->dn.p   = p;
2850         rr->dn.len = (p = dns_d_skip(p, P)) - rr->dn.p;
2851
2852         if (P->end - p < 4)
2853                 goto invalid;
2854
2855         rr->type = ((0xff & P->data[p + 0]) << 8)
2856                  | ((0xff & P->data[p + 1]) << 0);
2857
2858         rr->class = ((0xff & P->data[p + 2]) << 8)
2859                   | ((0xff & P->data[p + 3]) << 0);
2860
2861         p += 4;
2862
2863         if (src < dns_p_qend(P)) {
2864                 rr->section = DNS_S_QUESTION;
2865
2866                 rr->ttl    = 0;
2867                 rr->rd.p   = 0;
2868                 rr->rd.len = 0;
2869
2870                 return 0;
2871         }
2872
2873         if (P->end - p < 4)
2874                 goto invalid;
2875
2876         rr->ttl = ((0xff & P->data[p + 0]) << 24)
2877                 | ((0xff & P->data[p + 1]) << 16)
2878                 | ((0xff & P->data[p + 2]) << 8)
2879                 | ((0xff & P->data[p + 3]) << 0);
2880         if (rr->type != DNS_T_OPT)
2881                 rr->ttl = DNS_PP_MIN(rr->ttl, 0x7fffffffU);
2882
2883         p += 4;
2884
2885         if (P->end - p < 2)
2886                 goto invalid;
2887
2888         rr->rd.len = ((0xff & P->data[p + 0]) << 8)
2889                    | ((0xff & P->data[p + 1]) << 0);
2890         rr->rd.p = p + 2;
2891
2892         p += 2;
2893
2894         if (P->end - p < rr->rd.len)
2895                 goto invalid;
2896
2897         return 0;
2898 invalid:
2899         return DNS_EILLEGAL;
2900 } /* dns_rr_parse() */
2901
2902
2903 static unsigned short dns_rr_len(const unsigned short src, struct dns_packet *P) {
2904         unsigned short rp, rdlen;
2905
2906         rp      = dns_d_skip(src, P);
2907
2908         if (P->end - rp < 4)
2909                 return P->end - src;
2910
2911         rp      += 4;   /* TYPE, CLASS */
2912
2913         if (rp <= dns_p_qend(P))
2914                 return rp - src;
2915
2916         if (P->end - rp < 6)
2917                 return P->end - src;
2918
2919         rp      += 6;   /* TTL, RDLEN */
2920
2921         rdlen   = ((0xff & P->data[rp - 2]) << 8)
2922                 | ((0xff & P->data[rp - 1]) << 0);
2923
2924         if (P->end - rp < rdlen)
2925                 return P->end - src;
2926
2927         rp      += rdlen;
2928
2929         return rp - src;
2930 } /* dns_rr_len() */
2931
2932
2933 unsigned short dns_rr_skip(unsigned short src, struct dns_packet *P) {
2934         return src + dns_rr_len(src, P);
2935 } /* dns_rr_skip() */
2936
2937
2938 static enum dns_section dns_rr_section(unsigned short src, struct dns_packet *P) {
2939         enum dns_section section;
2940         unsigned count, index;
2941         unsigned short rp;
2942
2943         if (src >= P->memo.qd.base && src < P->memo.qd.end)
2944                 return DNS_S_QD;
2945         if (src >= P->memo.an.base && src < P->memo.an.end)
2946                 return DNS_S_AN;
2947         if (src >= P->memo.ns.base && src < P->memo.ns.end)
2948                 return DNS_S_NS;
2949         if (src >= P->memo.ar.base && src < P->memo.ar.end)
2950                 return DNS_S_AR;
2951
2952         /* NOTE: Possibly bad memoization. Try it the hard-way. */
2953
2954         for (rp = 12, index = 0; rp < src && rp < P->end; index++)
2955                 rp = dns_rr_skip(rp, P);
2956
2957         section = DNS_S_QD;
2958         count   = dns_p_count(P, section);
2959
2960         while (index >= count && section <= DNS_S_AR) {
2961                 section <<= 1;
2962                 count += dns_p_count(P, section);
2963         }
2964
2965         return DNS_S_ALL & section;
2966 } /* dns_rr_section() */
2967
2968
2969 static enum dns_type dns_rr_type(unsigned short src, struct dns_packet *P) {
2970         struct dns_rr rr;
2971         int error;
2972
2973         if ((error = dns_rr_parse(&rr, src, P)))
2974                 return 0;
2975
2976         return rr.type;
2977 } /* dns_rr_type() */
2978
2979
2980 int dns_rr_cmp(struct dns_rr *r0, struct dns_packet *P0, struct dns_rr *r1, struct dns_packet *P1) {
2981         char host0[DNS_D_MAXNAME + 1], host1[DNS_D_MAXNAME + 1];
2982         union dns_any any0, any1;
2983         int cmp, error;
2984         size_t len;
2985
2986         if ((cmp = r0->type - r1->type))
2987                 return cmp;
2988
2989         if ((cmp = r0->class - r1->class))
2990                 return cmp;
2991
2992         /*
2993          * FIXME: Do label-by-label comparison to handle illegally long names?
2994          */
2995
2996         if (!(len = dns_d_expand(host0, sizeof host0, r0->dn.p, P0, &error))
2997         ||  len >= sizeof host0)
2998                 return -1;
2999
3000         if (!(len = dns_d_expand(host1, sizeof host1, r1->dn.p, P1, &error))
3001         ||  len >= sizeof host1)
3002                 return 1;
3003
3004         if ((cmp = strcasecmp(host0, host1)))
3005                 return cmp;
3006
3007         if (DNS_S_QD & (r0->section | r1->section)) {
3008                 if (r0->section == r1->section)
3009                         return 0;
3010
3011                 return (r0->section == DNS_S_QD)? -1 : 1;
3012         }
3013
3014         if ((error = dns_any_parse(&any0, r0, P0)))
3015                 return -1;
3016
3017         if ((error = dns_any_parse(&any1, r1, P1)))
3018                 return 1;
3019
3020         return dns_any_cmp(&any0, r0->type, &any1, r1->type);
3021 } /* dns_rr_cmp() */
3022
3023
3024 static _Bool dns_rr_exists(struct dns_rr *rr0, struct dns_packet *P0, struct dns_packet *P1) {
3025         struct dns_rr rr1;
3026
3027         dns_rr_foreach(&rr1, P1, .section = rr0->section, .type = rr0->type) {
3028                 if (0 == dns_rr_cmp(rr0, P0, &rr1, P1))
3029                         return 1;
3030         }
3031
3032         return 0;
3033 } /* dns_rr_exists() */
3034
3035
3036 static unsigned short dns_rr_offset(struct dns_rr *rr) {
3037         return rr->dn.p;
3038 } /* dns_rr_offset() */
3039
3040
3041 static _Bool dns_rr_i_match(struct dns_rr *rr, struct dns_rr_i *i, struct dns_packet *P) {
3042         if (i->section && !(rr->section & i->section))
3043                 return 0;
3044
3045         if (i->type && rr->type != i->type && i->type != DNS_T_ALL)
3046                 return 0;
3047
3048         if (i->class && rr->class != i->class && i->class != DNS_C_ANY)
3049                 return 0;
3050
3051         if (i->name) {
3052                 char dn[DNS_D_MAXNAME + 1];
3053                 size_t len;
3054                 int error;
3055
3056                 if (!(len = dns_d_expand(dn, sizeof dn, rr->dn.p, P, &error))
3057                 ||  len >= sizeof dn)
3058                         return 0;
3059
3060                 if (0 != strcasecmp(dn, i->name))
3061                         return 0;
3062         }
3063
3064         if (i->data && i->type && rr->section > DNS_S_QD) {
3065                 union dns_any rd;
3066                 int error;
3067
3068                 if ((error = dns_any_parse(&rd, rr, P)))
3069                         return 0;
3070
3071                 if (0 != dns_any_cmp(&rd, rr->type, i->data, i->type))
3072                         return 0;
3073         }
3074
3075         return 1;
3076 } /* dns_rr_i_match() */
3077
3078
3079 static unsigned short dns_rr_i_start(struct dns_rr_i *i, struct dns_packet *P) {
3080         unsigned short rp;
3081         struct dns_rr r0, rr;
3082         int error;
3083
3084         if ((i->section & DNS_S_QD) && P->memo.qd.base)
3085                 rp = P->memo.qd.base;
3086         else if ((i->section & DNS_S_AN) && P->memo.an.base)
3087                 rp = P->memo.an.base;
3088         else if ((i->section & DNS_S_NS) && P->memo.ns.base)
3089                 rp = P->memo.ns.base;
3090         else if ((i->section & DNS_S_AR) && P->memo.ar.base)
3091                 rp = P->memo.ar.base;
3092         else
3093                 rp = 12;
3094
3095         for (; rp < P->end; rp = dns_rr_skip(rp, P)) {
3096                 if ((error = dns_rr_parse(&rr, rp, P)))
3097                         continue;
3098
3099                 rr.section = dns_rr_section(rp, P);
3100
3101                 if (!dns_rr_i_match(&rr, i, P))
3102                         continue;
3103
3104                 r0 = rr;
3105
3106                 goto lower;
3107         }
3108
3109         return P->end;
3110 lower:
3111         if (i->sort == &dns_rr_i_packet)
3112                 return dns_rr_offset(&r0);
3113
3114         while ((rp = dns_rr_skip(rp, P)) < P->end) {
3115                 if ((error = dns_rr_parse(&rr, rp, P)))
3116                         continue;
3117
3118                 rr.section = dns_rr_section(rp, P);
3119
3120                 if (!dns_rr_i_match(&rr, i, P))
3121                         continue;
3122
3123                 if (i->sort(&rr, &r0, i, P) < 0)
3124                         r0 = rr;
3125         }
3126
3127         return dns_rr_offset(&r0);
3128 } /* dns_rr_i_start() */
3129
3130
3131 static unsigned short dns_rr_i_skip(unsigned short rp, struct dns_rr_i *i, struct dns_packet *P) {
3132         struct dns_rr r0, r1, rr;
3133         int error;
3134
3135         if ((error = dns_rr_parse(&r0, rp, P)))
3136                 return P->end;
3137
3138         r0.section = dns_rr_section(rp, P);
3139
3140         rp = (i->sort == &dns_rr_i_packet)? dns_rr_skip(rp, P) : 12;
3141
3142         for (; rp < P->end; rp = dns_rr_skip(rp, P)) {
3143                 if ((error = dns_rr_parse(&rr, rp, P)))
3144                         continue;
3145
3146                 rr.section = dns_rr_section(rp, P);
3147
3148                 if (!dns_rr_i_match(&rr, i, P))
3149                         continue;
3150
3151                 if (i->sort(&rr, &r0, i, P) <= 0)
3152                         continue;
3153
3154                 r1 = rr;
3155
3156                 goto lower;
3157         }
3158
3159         return P->end;
3160 lower:
3161         if (i->sort == &dns_rr_i_packet)
3162                 return dns_rr_offset(&r1);
3163
3164         while ((rp = dns_rr_skip(rp, P)) < P->end) {
3165                 if ((error = dns_rr_parse(&rr, rp, P)))
3166                         continue;
3167
3168                 rr.section = dns_rr_section(rp, P);
3169
3170                 if (!dns_rr_i_match(&rr, i, P))
3171                         continue;
3172
3173                 if (i->sort(&rr, &r0, i, P) <= 0)
3174                         continue;
3175
3176                 if (i->sort(&rr, &r1, i, P) >= 0)
3177                         continue;
3178
3179                 r1 = rr;
3180         }
3181
3182         return dns_rr_offset(&r1);
3183 } /* dns_rr_i_skip() */
3184
3185
3186 int dns_rr_i_packet(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) {
3187         (void)i;
3188         (void)P;
3189
3190         return (int)a->dn.p - (int)b->dn.p;
3191 } /* dns_rr_i_packet() */
3192
3193
3194 int dns_rr_i_order(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) {
3195         int cmp;
3196
3197         (void)i;
3198
3199         if ((cmp = a->section - b->section))
3200                 return cmp;
3201
3202         if (a->type != b->type)
3203                 return (int)a->dn.p - (int)b->dn.p;
3204
3205         return dns_rr_cmp(a, P, b, P);
3206 } /* dns_rr_i_order() */
3207
3208
3209 int dns_rr_i_shuffle(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) {
3210         int cmp;
3211
3212         (void)i;
3213         (void)P;
3214
3215         while (!i->state.regs[0])
3216                 i->state.regs[0]        = dns_random();
3217
3218         if ((cmp = a->section - b->section))
3219                 return cmp;
3220
3221         return dns_k_shuffle16(a->dn.p, i->state.regs[0]) - dns_k_shuffle16(b->dn.p, i->state.regs[0]);
3222 } /* dns_rr_i_shuffle() */
3223
3224
3225 void dns_rr_i_init(struct dns_rr_i *i) {
3226         static const struct dns_rr_i i_initializer;
3227
3228         i->state        = i_initializer.state;
3229         i->saved        = i->state;
3230 } /* dns_rr_i_init() */
3231
3232
3233 unsigned dns_rr_grep(struct dns_rr *rr, unsigned lim, struct dns_rr_i *i, struct dns_packet *P, int *error_) {
3234         unsigned count  = 0;
3235         int error;
3236
3237         switch (i->state.exec) {
3238         case 0:
3239                 if (!i->sort)
3240                         i->sort = &dns_rr_i_packet;
3241
3242                 i->state.next   = dns_rr_i_start(i, P);
3243                 i->state.exec++;
3244
3245                 /* FALL THROUGH */
3246         case 1:
3247                 while (count < lim && i->state.next < P->end) {
3248                         if ((error = dns_rr_parse(rr, i->state.next, P)))
3249                                 goto error;
3250
3251                         rr->section     = dns_rr_section(i->state.next, P);
3252
3253                         rr++;
3254                         count++;
3255                         i->state.count++;
3256
3257                         i->state.next   = dns_rr_i_skip(i->state.next, i, P);
3258                 } /* while() */
3259
3260                 break;
3261         } /* switch() */
3262
3263         return count;
3264 error:
3265         if (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
3574 size_t dns_ns_print(void *dst, size_t lim, struct dns_ns *ns) {
3575         return dns_strlcpy(dst, ns->host, lim);
3576 } /* dns_ns_print() */
3577
3578
3579 size_t dns_ns_cname(void *dst, size_t lim, struct dns_ns *ns) {
3580         return dns_strlcpy(dst, ns->host, lim);
3581 } /* dns_ns_cname() */
3582
3583
3584 int dns_cname_parse(struct dns_cname *cname, struct dns_rr *rr, struct dns_packet *P) {
3585         return dns_ns_parse((struct dns_ns *)cname, rr, P);
3586 } /* dns_cname_parse() */
3587
3588
3589 int dns_cname_push(struct dns_packet *P, struct dns_cname *cname) {
3590         return dns_ns_push(P, (struct dns_ns *)cname);
3591 } /* dns_cname_push() */
3592
3593
3594 int dns_cname_cmp(const struct dns_cname *a, const struct dns_cname *b) {
3595         return strcasecmp(a->host, b->host);
3596 } /* dns_cname_cmp() */
3597
3598
3599 size_t dns_cname_print(void *dst, size_t lim, struct dns_cname *cname) {
3600         return dns_ns_print(dst, lim, (struct dns_ns *)cname);
3601 } /* dns_cname_print() */
3602
3603
3604 size_t dns_cname_cname(void *dst, size_t lim, struct dns_cname *cname) {
3605         return dns_strlcpy(dst, cname->host, lim);
3606 } /* dns_cname_cname() */
3607
3608
3609 int dns_soa_parse(struct dns_soa *soa, struct dns_rr *rr, struct dns_packet *P) {
3610         struct { void *dst; size_t lim; } dn[] =
3611                 { { soa->mname, sizeof soa->mname },
3612                   { soa->rname, sizeof soa->rname } };
3613         unsigned *ts[] =
3614                 { &soa->serial, &soa->refresh, &soa->retry, &soa->expire, &soa->minimum };
3615         unsigned short rp;
3616         unsigned i, j, n;
3617         int error;
3618
3619         /* MNAME / RNAME */
3620         if ((rp = rr->rd.p) >= P->end)
3621                 return DNS_EILLEGAL;
3622
3623         for (i = 0; i < lengthof(dn); i++) {
3624                 if (!(n = dns_d_expand(dn[i].dst, dn[i].lim, rp, P, &error)))
3625                         return error;
3626                 else if (n >= dn[i].lim)
3627                         return DNS_EILLEGAL;
3628
3629                 if ((rp = dns_d_skip(rp, P)) >= P->end)
3630                         return DNS_EILLEGAL;
3631         }
3632
3633         /* SERIAL / REFRESH / RETRY / EXPIRE / MINIMUM */
3634         for (i = 0; i < lengthof(ts); i++) {
3635                 for (j = 0; j < 4; j++, rp++) {
3636                         if (rp >= P->end)
3637                                 return DNS_EILLEGAL;
3638
3639                         *ts[i]  <<= 8;
3640                         *ts[i]  |= (0xff & P->data[rp]);
3641                 }
3642         }
3643
3644         return 0;
3645 } /* dns_soa_parse() */
3646
3647
3648 int dns_soa_push(struct dns_packet *P, struct dns_soa *soa) {
3649         void *dn[]      = { soa->mname, soa->rname };
3650         unsigned ts[]   = { (0xffffffff & soa->serial),
3651                             (0x7fffffff & soa->refresh),
3652                             (0x7fffffff & soa->retry),
3653                             (0x7fffffff & soa->expire),
3654                             (0xffffffff & soa->minimum) };
3655         unsigned i, j;
3656         size_t end, len;
3657         int error;
3658
3659         end     = P->end;
3660
3661         if ((P->end += 2) >= P->size)
3662                 goto toolong;
3663
3664         /* MNAME / RNAME */
3665         for (i = 0; i < lengthof(dn); i++) {
3666                 if ((error = dns_d_push(P, dn[i], strlen(dn[i]))))
3667                         goto error;
3668         }
3669
3670         /* SERIAL / REFRESH / RETRY / EXPIRE / MINIMUM */
3671         for (i = 0; i < lengthof(ts); i++) {
3672                 if ((P->end += 4) >= P->size)
3673                         goto toolong;
3674
3675                 for (j = 1; j <= 4; j++) {
3676                         P->data[P->end - j]     = (0xff & ts[i]);
3677                         ts[i]                   >>= 8;
3678                 }
3679         }
3680
3681         len                     = P->end - end - 2;
3682         P->data[end + 0]        = (0xff & (len >> 8));
3683         P->data[end + 1]        = (0xff & (len >> 0));
3684
3685         return 0;
3686 toolong:
3687         error   = DNS_ENOBUFS;
3688
3689         /* FALL THROUGH */
3690 error:
3691         P->end  = end;
3692
3693         return error;
3694 } /* dns_soa_push() */
3695
3696
3697 int dns_soa_cmp(const struct dns_soa *a, const struct dns_soa *b) {
3698         int cmp;
3699
3700         if ((cmp = strcasecmp(a->mname, b->mname)))
3701                 return cmp;
3702
3703         if ((cmp = strcasecmp(a->rname, b->rname)))
3704                 return cmp;
3705
3706         if (a->serial > b->serial)
3707                 return -1;
3708         else if (a->serial < b->serial)
3709                 return 1;
3710
3711         if (a->refresh > b->refresh)
3712                 return -1;
3713         else if (a->refresh < b->refresh)
3714                 return 1;
3715
3716         if (a->retry > b->retry)
3717                 return -1;
3718         else if (a->retry < b->retry)
3719                 return 1;
3720
3721         if (a->expire > b->expire)
3722                 return -1;
3723         else if (a->expire < b->expire)
3724                 return 1;
3725
3726         if (a->minimum > b->minimum)
3727                 return -1;
3728         else if (a->minimum < b->minimum)
3729                 return 1;
3730
3731         return 0;
3732 } /* dns_soa_cmp() */
3733
3734
3735 size_t dns_soa_print(void *_dst, size_t lim, struct dns_soa *soa) {
3736         struct dns_buf dst = DNS_B_INTO(_dst, lim);
3737
3738         dns_b_puts(&dst, soa->mname);
3739         dns_b_putc(&dst, ' ');
3740         dns_b_puts(&dst, soa->rname);
3741         dns_b_putc(&dst, ' ');
3742         dns_b_fmtju(&dst, soa->serial, 0);
3743         dns_b_putc(&dst, ' ');
3744         dns_b_fmtju(&dst, soa->refresh, 0);
3745         dns_b_putc(&dst, ' ');
3746         dns_b_fmtju(&dst, soa->retry, 0);
3747         dns_b_putc(&dst, ' ');
3748         dns_b_fmtju(&dst, soa->expire, 0);
3749         dns_b_putc(&dst, ' ');
3750         dns_b_fmtju(&dst, soa->minimum, 0);
3751
3752         return dns_b_strllen(&dst);
3753 } /* dns_soa_print() */
3754
3755
3756 int dns_srv_parse(struct dns_srv *srv, struct dns_rr *rr, struct dns_packet *P) {
3757         unsigned short rp;
3758         unsigned i;
3759         size_t n;
3760         int error;
3761
3762         memset(srv, '\0', sizeof *srv);
3763
3764         rp      = rr->rd.p;
3765
3766         if (rr->rd.len < 7)
3767                 return DNS_EILLEGAL;
3768
3769         for (i = 0; i < 2; i++, rp++) {
3770                 srv->priority   <<= 8;
3771                 srv->priority   |= (0xff & P->data[rp]);
3772         }
3773
3774         for (i = 0; i < 2; i++, rp++) {
3775                 srv->weight     <<= 8;
3776                 srv->weight     |= (0xff & P->data[rp]);
3777         }
3778
3779         for (i = 0; i < 2; i++, rp++) {
3780                 srv->port       <<= 8;
3781                 srv->port       |= (0xff & P->data[rp]);
3782         }
3783
3784         if (!(n = dns_d_expand(srv->target, sizeof srv->target, rp, P, &error)))
3785                 return error;
3786         else if (n >= sizeof srv->target)
3787                 return DNS_EILLEGAL;
3788
3789         return 0;
3790 } /* dns_srv_parse() */
3791
3792
3793 int dns_srv_push(struct dns_packet *P, struct dns_srv *srv) {
3794         size_t end, len;
3795         int error;
3796
3797         end     = P->end;
3798
3799         if (P->size - P->end < 2)
3800                 goto toolong;
3801
3802         P->end  += 2;
3803
3804         if (P->size - P->end < 6)
3805                 goto toolong;
3806
3807         P->data[P->end++]       = 0xff & (srv->priority >> 8);
3808         P->data[P->end++]       = 0xff & (srv->priority >> 0);
3809
3810         P->data[P->end++]       = 0xff & (srv->weight >> 8);
3811         P->data[P->end++]       = 0xff & (srv->weight >> 0);
3812
3813         P->data[P->end++]       = 0xff & (srv->port >> 8);
3814         P->data[P->end++]       = 0xff & (srv->port >> 0);
3815
3816         if (0 == (len = dns_d_comp(&P->data[P->end], P->size - P->end, srv->target, strlen(srv->target), P, &error)))
3817                 goto error;
3818         else if (P->size - P->end < len)
3819                 goto toolong;
3820
3821         P->end  += len;
3822
3823         if (P->end > 65535)
3824                 goto toolong;
3825
3826         len     = P->end - end - 2;
3827
3828         P->data[end + 0]        = 0xff & (len >> 8);
3829         P->data[end + 1]        = 0xff & (len >> 0);
3830
3831         return 0;
3832 toolong:
3833         error   = DNS_ENOBUFS;
3834
3835         /* FALL THROUGH */
3836 error:
3837         P->end  = end;
3838
3839         return error;
3840 } /* dns_srv_push() */
3841
3842
3843 int dns_srv_cmp(const struct dns_srv *a, const struct dns_srv *b) {
3844         int cmp;
3845
3846         if ((cmp = a->priority - b->priority))
3847                 return cmp;
3848
3849         /*
3850          * FIXME: We need some sort of random seed to implement the dynamic
3851          * weighting required by RFC 2782.
3852          */
3853         if ((cmp = a->weight - b->weight))
3854                 return cmp;
3855
3856         if ((cmp = a->port - b->port))
3857                 return cmp;
3858
3859         return strcasecmp(a->target, b->target);
3860 } /* dns_srv_cmp() */
3861
3862
3863 size_t dns_srv_print(void *_dst, size_t lim, struct dns_srv *srv) {
3864         struct dns_buf dst = DNS_B_INTO(_dst, lim);
3865
3866         dns_b_fmtju(&dst, srv->priority, 0);
3867         dns_b_putc(&dst, ' ');
3868         dns_b_fmtju(&dst, srv->weight, 0);
3869         dns_b_putc(&dst, ' ');
3870         dns_b_fmtju(&dst, srv->port, 0);
3871         dns_b_putc(&dst, ' ');
3872         dns_b_puts(&dst, srv->target);
3873
3874         return dns_b_strllen(&dst);
3875 } /* dns_srv_print() */
3876
3877
3878 size_t dns_srv_cname(void *dst, size_t lim, struct dns_srv *srv) {
3879         return dns_strlcpy(dst, srv->target, lim);
3880 } /* dns_srv_cname() */
3881
3882
3883 unsigned int dns_opt_ttl(const struct dns_opt *opt) {
3884         unsigned int ttl = 0;
3885
3886         ttl |= (0xffU & opt->rcode) << 24;
3887         ttl |= (0xffU & opt->version) << 16;
3888         ttl |= (0xffffU & opt->flags) << 0;
3889
3890         return ttl;
3891 } /* dns_opt_ttl() */
3892
3893
3894 unsigned short dns_opt_class(const struct dns_opt *opt) {
3895         return opt->maxudp;
3896 } /* dns_opt_class() */
3897
3898
3899 struct dns_opt *dns_opt_init(struct dns_opt *opt, size_t size) {
3900         assert(size >= offsetof(struct dns_opt, data));
3901
3902         opt->size = size - offsetof(struct dns_opt, data);
3903         opt->len  = 0;
3904
3905         opt->rcode   = 0;
3906         opt->version = 0;
3907         opt->maxudp  = 0;
3908
3909         return opt;
3910 } /* dns_opt_init() */
3911
3912
3913 static union dns_any *dns_opt_initany(union dns_any *any, size_t size) {
3914         return dns_opt_init(&any->opt, size), any;
3915 } /* dns_opt_initany() */
3916
3917
3918 int dns_opt_parse(struct dns_opt *opt, struct dns_rr *rr, struct dns_packet *P) {
3919         const struct dns_buf src = DNS_B_FROM(&P->data[rr->rd.p], rr->rd.len);
3920         struct dns_buf dst = DNS_B_INTO(opt->data, opt->size);
3921         int error;
3922
3923         opt->rcode = 0xfff & ((rr->ttl >> 20) | dns_header(P)->rcode);
3924         opt->version = 0xff & (rr->ttl >> 16);
3925         opt->flags = 0xffff & rr->ttl;
3926         opt->maxudp = 0xffff & rr->class;
3927
3928         while (src.p < src.pe) {
3929                 int code, len;
3930
3931                 if (-1 == (code = dns_b_get16(&src, -1)))
3932                         return src.error;
3933                 if (-1 == (len = dns_b_get16(&src, -1)))
3934                         return src.error;
3935
3936                 switch (code) {
3937                 default:
3938                         dns_b_put16(&dst, code);
3939                         dns_b_put16(&dst, len);
3940                         if ((error = dns_b_move(&dst, &src, len)))
3941                                 return error;
3942                         break;
3943                 }
3944         }
3945
3946         return 0;
3947 } /* dns_opt_parse() */
3948
3949
3950 int dns_opt_push(struct dns_packet *P, struct dns_opt *opt) {
3951         const struct dns_buf src = DNS_B_FROM(opt->data, opt->len);
3952         struct dns_buf dst = DNS_B_INTO(&P->data[P->end], (P->size - P->end));
3953         int error;
3954
3955         /* rdata length (see below) */
3956         if ((error = dns_b_put16(&dst, 0)))
3957                 goto error;
3958
3959         /* ... push known options here */
3960
3961         /* push opaque option data */
3962         if ((error = dns_b_move(&dst, &src, (size_t)(src.pe - src.p))))
3963                 goto error;
3964
3965         /* rdata length */
3966         if ((error = dns_b_pput16(&dst, dns_b_tell(&dst) - 2, 0)))
3967                 goto error;
3968
3969 #if !DNS_DEBUG_OPT_FORMERR
3970         P->end += dns_b_tell(&dst);
3971 #endif
3972
3973         return 0;
3974 error:
3975         return error;
3976 } /* dns_opt_push() */
3977
3978
3979 int dns_opt_cmp(const struct dns_opt *a, const struct dns_opt *b) {
3980         (void)a;
3981         (void)b;
3982
3983         return -1;
3984 } /* dns_opt_cmp() */
3985
3986
3987 size_t dns_opt_print(void *_dst, size_t lim, struct dns_opt *opt) {
3988         struct dns_buf dst = DNS_B_INTO(_dst, lim);
3989         size_t p;
3990
3991         dns_b_putc(&dst, '"');
3992
3993         for (p = 0; p < opt->len; p++) {
3994                 dns_b_putc(&dst, '\\');
3995                 dns_b_fmtju(&dst, opt->data[p], 3);
3996         }
3997
3998         dns_b_putc(&dst, '"');
3999
4000         return dns_b_strllen(&dst);
4001 } /* dns_opt_print() */
4002
4003
4004 int dns_ptr_parse(struct dns_ptr *ptr, struct dns_rr *rr, struct dns_packet *P) {
4005         return dns_ns_parse((struct dns_ns *)ptr, rr, P);
4006 } /* dns_ptr_parse() */
4007
4008
4009 int dns_ptr_push(struct dns_packet *P, struct dns_ptr *ptr) {
4010         return dns_ns_push(P, (struct dns_ns *)ptr);
4011 } /* dns_ptr_push() */
4012
4013
4014 size_t dns_ptr_qname(void *dst, size_t lim, int af, void *addr) {
4015         switch (af) {
4016         case AF_INET6:
4017                 return dns_aaaa_arpa(dst, lim, addr);
4018         case AF_INET:
4019                 return dns_a_arpa(dst, lim, addr);
4020         default: {
4021                 struct dns_a a;
4022                 a.addr.s_addr = INADDR_NONE;
4023                 return dns_a_arpa(dst, lim, &a);
4024         }
4025         }
4026 } /* dns_ptr_qname() */
4027
4028
4029 int dns_ptr_cmp(const struct dns_ptr *a, const struct dns_ptr *b) {
4030         return strcasecmp(a->host, b->host);
4031 } /* dns_ptr_cmp() */
4032
4033
4034 size_t dns_ptr_print(void *dst, size_t lim, struct dns_ptr *ptr) {
4035         return dns_ns_print(dst, lim, (struct dns_ns *)ptr);
4036 } /* dns_ptr_print() */
4037
4038
4039 size_t dns_ptr_cname(void *dst, size_t lim, struct dns_ptr *ptr) {
4040         return dns_strlcpy(dst, ptr->host, lim);
4041 } /* dns_ptr_cname() */
4042
4043
4044 int dns_sshfp_parse(struct dns_sshfp *fp, struct dns_rr *rr, struct dns_packet *P) {
4045         unsigned p = rr->rd.p, pe = rr->rd.p + rr->rd.len;
4046
4047         if (pe - p < 2)
4048                 return DNS_EILLEGAL;
4049
4050         fp->algo = P->data[p++];
4051         fp->type = P->data[p++];
4052
4053         switch (fp->type) {
4054         case DNS_SSHFP_SHA1:
4055                 if (pe - p < sizeof fp->digest.sha1)
4056                         return DNS_EILLEGAL;
4057
4058                 memcpy(fp->digest.sha1, &P->data[p], sizeof fp->digest.sha1);
4059
4060                 break;
4061         default:
4062                 break;
4063         } /* switch() */
4064
4065         return 0;
4066 } /* dns_sshfp_parse() */
4067
4068
4069 int dns_sshfp_push(struct dns_packet *P, struct dns_sshfp *fp) {
4070         unsigned p = P->end, pe = P->size, n;
4071
4072         if (pe - p < 4)
4073                 return DNS_ENOBUFS;
4074
4075         p += 2;
4076         P->data[p++] = 0xff & fp->algo;
4077         P->data[p++] = 0xff & fp->type;
4078
4079         switch (fp->type) {
4080         case DNS_SSHFP_SHA1:
4081                 if (pe - p < sizeof fp->digest.sha1)
4082                         return DNS_ENOBUFS;
4083
4084                 memcpy(&P->data[p], fp->digest.sha1, sizeof fp->digest.sha1);
4085                 p += sizeof fp->digest.sha1;
4086
4087                 break;
4088         default:
4089                 return DNS_EILLEGAL;
4090         } /* switch() */
4091
4092         n = p - P->end - 2;
4093         P->data[P->end++] = 0xff & (n >> 8);
4094         P->data[P->end++] = 0xff & (n >> 0);
4095         P->end = p;
4096
4097         return 0;
4098 } /* dns_sshfp_push() */
4099
4100
4101 int dns_sshfp_cmp(const struct dns_sshfp *a, const struct dns_sshfp *b) {
4102         int cmp;
4103
4104         if ((cmp = a->algo - b->algo) || (cmp = a->type - b->type))
4105                 return cmp;
4106
4107         switch (a->type) {
4108         case DNS_SSHFP_SHA1:
4109                 return memcmp(a->digest.sha1, b->digest.sha1, sizeof a->digest.sha1);
4110         default:
4111                 return 0;
4112         } /* switch() */
4113
4114         /* NOT REACHED */
4115 } /* dns_sshfp_cmp() */
4116
4117
4118 size_t dns_sshfp_print(void *_dst, size_t lim, struct dns_sshfp *fp) {
4119         static const unsigned char hex[16] = "0123456789abcdef";
4120         struct dns_buf dst = DNS_B_INTO(_dst, lim);
4121         size_t i;
4122
4123         dns_b_fmtju(&dst, fp->algo, 0);
4124         dns_b_putc(&dst, ' ');
4125         dns_b_fmtju(&dst, fp->type, 0);
4126         dns_b_putc(&dst, ' ');
4127
4128         switch (fp->type) {
4129         case DNS_SSHFP_SHA1:
4130                 for (i = 0; i < sizeof fp->digest.sha1; i++) {
4131                         dns_b_putc(&dst, hex[0x0f & (fp->digest.sha1[i] >> 4)]);
4132                         dns_b_putc(&dst, hex[0x0f & (fp->digest.sha1[i] >> 0)]);
4133                 }
4134
4135                 break;
4136         default:
4137                 dns_b_putc(&dst, '0');
4138
4139                 break;
4140         } /* switch() */
4141
4142         return dns_b_strllen(&dst);
4143 } /* dns_sshfp_print() */
4144
4145
4146 struct dns_txt *dns_txt_init(struct dns_txt *txt, size_t size) {
4147         assert(size > offsetof(struct dns_txt, data));
4148
4149         txt->size       = size - offsetof(struct dns_txt, data);
4150         txt->len        = 0;
4151
4152         return txt;
4153 } /* dns_txt_init() */
4154
4155
4156 static union dns_any *dns_txt_initany(union dns_any *any, size_t size) {
4157         /* NB: union dns_any is already initialized as struct dns_txt */
4158         (void)size;
4159         return any;
4160 } /* dns_txt_initany() */
4161
4162
4163 int dns_txt_parse(struct dns_txt *txt, struct dns_rr *rr, struct dns_packet *P) {
4164         struct { unsigned char *b; size_t p, end; } dst, src;
4165         unsigned n;
4166
4167         dst.b   = txt->data;
4168         dst.p   = 0;
4169         dst.end = txt->size;
4170
4171         src.b   = P->data;
4172         src.p   = rr->rd.p;
4173         src.end = src.p + rr->rd.len;
4174
4175         while (src.p < src.end) {
4176                 n       = 0xff & P->data[src.p++];
4177
4178                 if (src.end - src.p < n || dst.end - dst.p < n)
4179                         return DNS_EILLEGAL;
4180
4181                 memcpy(&dst.b[dst.p], &src.b[src.p], n);
4182
4183                 dst.p   += n;
4184                 src.p   += n;
4185         }
4186
4187         txt->len        = dst.p;
4188
4189         return 0;
4190 } /* dns_txt_parse() */
4191
4192
4193 int dns_txt_push(struct dns_packet *P, struct dns_txt *txt) {
4194         struct { unsigned char *b; size_t p, end; } dst, src;
4195         unsigned n;
4196
4197         dst.b   = P->data;
4198         dst.p   = P->end;
4199         dst.end = P->size;
4200
4201         src.b   = txt->data;
4202         src.p   = 0;
4203         src.end = txt->len;
4204
4205         if (dst.end - dst.p < 2)
4206                 return DNS_ENOBUFS;
4207
4208         n       = txt->len + ((txt->len + 254) / 255);
4209
4210         dst.b[dst.p++]  = 0xff & (n >> 8);
4211         dst.b[dst.p++]  = 0xff & (n >> 0);
4212
4213         while (src.p < src.end) {
4214                 n       = DNS_PP_MIN(255, src.end - src.p);
4215
4216                 if (dst.p >= dst.end)
4217                         return DNS_ENOBUFS;
4218
4219                 dst.b[dst.p++]  = n;
4220
4221                 if (dst.end - dst.p < n)
4222                         return DNS_ENOBUFS;
4223
4224                 memcpy(&dst.b[dst.p], &src.b[src.p], n);
4225
4226                 dst.p   += n;
4227                 src.p   += n;
4228         }
4229
4230         P->end  = dst.p;
4231
4232         return 0;
4233 } /* dns_txt_push() */
4234
4235
4236 int dns_txt_cmp(const struct dns_txt *a, const struct dns_txt *b) {
4237         (void)a;
4238         (void)b;
4239
4240         return -1;
4241 } /* dns_txt_cmp() */
4242
4243
4244 size_t dns_txt_print(void *_dst, size_t lim, struct dns_txt *txt) {
4245         struct dns_buf src = DNS_B_FROM(txt->data, txt->len);
4246         struct dns_buf dst = DNS_B_INTO(_dst, lim);
4247         unsigned i;
4248
4249         if (src.p < src.pe) {
4250                 do {
4251                         dns_b_putc(&dst, '"');
4252
4253                         for (i = 0; i < 256 && src.p < src.pe; i++, src.p++) {
4254                                 if (*src.p < 32 || *src.p > 126 || *src.p == '"' || *src.p == '\\') {
4255                                         dns_b_putc(&dst, '\\');
4256                                         dns_b_fmtju(&dst, *src.p, 3);
4257                                 } else {
4258                                         dns_b_putc(&dst, *src.p);
4259                                 }
4260                         }
4261
4262                         dns_b_putc(&dst, '"');
4263                         dns_b_putc(&dst, ' ');
4264                 } while (src.p < src.pe);
4265
4266                 dns_b_popc(&dst);
4267         } else {
4268                 dns_b_putc(&dst, '"');
4269                 dns_b_putc(&dst, '"');
4270         }
4271
4272         return dns_b_strllen(&dst);
4273 } /* dns_txt_print() */
4274
4275
4276 /* Some of the function pointers of DNS_RRTYPES are initialized with
4277  * slighlly different functions, thus we can't use prototypes.  */
4278 DNS_PRAGMA_PUSH
4279 #if __clang__
4280 #pragma clang diagnostic ignored "-Wstrict-prototypes"
4281 #elif DNS_GNUC_PREREQ(4,6,0)
4282 #pragma GCC   diagnostic ignored "-Wstrict-prototypes"
4283 #endif
4284
4285 static const struct dns_rrtype {
4286         enum dns_type type;
4287         const char *name;
4288         union dns_any *(*init)(union dns_any *, size_t);
4289         int (*parse)();
4290         int (*push)();
4291         int (*cmp)();
4292         size_t (*print)();
4293         size_t (*cname)();
4294 } dns_rrtypes[] = {
4295         { DNS_T_A,      "A",      0,                 &dns_a_parse,      &dns_a_push,      &dns_a_cmp,      &dns_a_print,      0,                },
4296         { DNS_T_AAAA,   "AAAA",   0,                 &dns_aaaa_parse,   &dns_aaaa_push,   &dns_aaaa_cmp,   &dns_aaaa_print,   0,                },
4297         { DNS_T_MX,     "MX",     0,                 &dns_mx_parse,     &dns_mx_push,     &dns_mx_cmp,     &dns_mx_print,     &dns_mx_cname,    },
4298         { DNS_T_NS,     "NS",     0,                 &dns_ns_parse,     &dns_ns_push,     &dns_ns_cmp,     &dns_ns_print,     &dns_ns_cname,    },
4299         { DNS_T_CNAME,  "CNAME",  0,                 &dns_cname_parse,  &dns_cname_push,  &dns_cname_cmp,  &dns_cname_print,  &dns_cname_cname, },
4300         { DNS_T_SOA,    "SOA",    0,                 &dns_soa_parse,    &dns_soa_push,    &dns_soa_cmp,    &dns_soa_print,    0,                },
4301         { DNS_T_SRV,    "SRV",    0,                 &dns_srv_parse,    &dns_srv_push,    &dns_srv_cmp,    &dns_srv_print,    &dns_srv_cname,   },
4302         { DNS_T_OPT,    "OPT",    &dns_opt_initany,  &dns_opt_parse,    &dns_opt_push,    &dns_opt_cmp,    &dns_opt_print,    0,                },
4303         { DNS_T_PTR,    "PTR",    0,                 &dns_ptr_parse,    &dns_ptr_push,    &dns_ptr_cmp,    &dns_ptr_print,    &dns_ptr_cname,   },
4304         { DNS_T_TXT,    "TXT",    &dns_txt_initany,  &dns_txt_parse,    &dns_txt_push,    &dns_txt_cmp,    &dns_txt_print,    0,                },
4305         { DNS_T_SPF,    "SPF",    &dns_txt_initany,  &dns_txt_parse,    &dns_txt_push,    &dns_txt_cmp,    &dns_txt_print,    0,                },
4306         { DNS_T_SSHFP,  "SSHFP",  0,                 &dns_sshfp_parse,  &dns_sshfp_push,  &dns_sshfp_cmp,  &dns_sshfp_print,  0,                },
4307         { DNS_T_AXFR,   "AXFR",   0,                 0,                 0,                0,               0,                 0,                },
4308 }; /* dns_rrtypes[] */
4309
4310 DNS_PRAGMA_POP  /*(-Wstrict-prototypes)*/
4311
4312
4313
4314 static const struct dns_rrtype *dns_rrtype(enum dns_type type) {
4315         const struct dns_rrtype *t;
4316
4317         for (t = dns_rrtypes; t < endof(dns_rrtypes); t++) {
4318                 if (t->type == type && t->parse) {
4319                         return t;
4320                 }
4321         }
4322
4323         return NULL;
4324 } /* dns_rrtype() */
4325
4326
4327 union dns_any *dns_any_init(union dns_any *any, size_t size) {
4328         dns_static_assert(dns_same_type(any->txt, any->rdata, 1), "unexpected rdata type");
4329         return (union dns_any *)dns_txt_init(&any->rdata, size);
4330 } /* dns_any_init() */
4331
4332
4333 static size_t dns_any_sizeof(union dns_any *any) {
4334         dns_static_assert(dns_same_type(any->txt, any->rdata, 1), "unexpected rdata type");
4335         return offsetof(struct dns_txt, data) + any->rdata.size;
4336 } /* dns_any_sizeof() */
4337
4338 static union dns_any *dns_any_reinit(union dns_any *any, const struct dns_rrtype *t) {
4339         return (t->init)? t->init(any, dns_any_sizeof(any)) : any;
4340 } /* dns_any_reinit() */
4341
4342 int dns_any_parse(union dns_any *any, struct dns_rr *rr, struct dns_packet *P) {
4343         const struct dns_rrtype *t;
4344
4345         if ((t = dns_rrtype(rr->type)))
4346                 return t->parse(dns_any_reinit(any, t), rr, P);
4347
4348         if (rr->rd.len > any->rdata.size)
4349                 return DNS_EILLEGAL;
4350
4351         memcpy(any->rdata.data, &P->data[rr->rd.p], rr->rd.len);
4352         any->rdata.len  = rr->rd.len;
4353
4354         return 0;
4355 } /* dns_any_parse() */
4356
4357
4358 int dns_any_push(struct dns_packet *P, union dns_any *any, enum dns_type type) {
4359         const struct dns_rrtype *t;
4360
4361         if ((t = dns_rrtype(type)))
4362                 return t->push(P, any);
4363
4364         if (P->size - P->end < any->rdata.len + 2)
4365                 return DNS_ENOBUFS;
4366
4367         P->data[P->end++]       = 0xff & (any->rdata.len >> 8);
4368         P->data[P->end++]       = 0xff & (any->rdata.len >> 0);
4369
4370         memcpy(&P->data[P->end], any->rdata.data, any->rdata.len);
4371         P->end  += any->rdata.len;
4372
4373         return 0;
4374 } /* dns_any_push() */
4375
4376
4377 int dns_any_cmp(const union dns_any *a, enum dns_type x, const union dns_any *b, enum dns_type y) {
4378         const struct dns_rrtype *t;
4379         int cmp;
4380
4381         if ((cmp = x - y))
4382                 return cmp;
4383
4384         if ((t = dns_rrtype(x)))
4385                 return t->cmp(a, b);
4386
4387         return -1;
4388 } /* dns_any_cmp() */
4389
4390
4391 size_t dns_any_print(void *_dst, size_t lim, union dns_any *any, enum dns_type type) {
4392         const struct dns_rrtype *t;
4393         struct dns_buf src, dst;
4394
4395         if ((t = dns_rrtype(type)))
4396                 return t->print(_dst, lim, any);
4397
4398         dns_b_from(&src, any->rdata.data, any->rdata.len);
4399         dns_b_into(&dst, _dst, lim);
4400
4401         dns_b_putc(&dst, '"');
4402
4403         while (src.p < src.pe) {
4404                 dns_b_putc(&dst, '\\');
4405                 dns_b_fmtju(&dst, *src.p++, 3);
4406         }
4407
4408         dns_b_putc(&dst, '"');
4409
4410         return dns_b_strllen(&dst);
4411 } /* dns_any_print() */
4412
4413
4414 size_t dns_any_cname(void *dst, size_t lim, union dns_any *any, enum dns_type type) {
4415         const struct dns_rrtype *t;
4416
4417         if ((t = dns_rrtype(type)) && t->cname)
4418                 return t->cname(dst, lim, any);
4419
4420         return 0;
4421 } /* dns_any_cname() */
4422
4423
4424 /*
4425  * E V E N T  T R A C I N G  R O U T I N E S
4426  *
4427  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4428 #include <float.h> /* DBL_MANT_DIG */
4429 #include <inttypes.h> /* PRIu64 */
4430
4431 /* for default trace ID generation try to fit in lua_Number, usually double */
4432 #define DNS_TRACE_ID_BITS DNS_PP_MIN(DBL_MANT_DIG, (sizeof (dns_trace_id_t) * CHAR_BIT)) /* assuming FLT_RADIX == 2 */
4433 #define DNS_TRACE_ID_MASK (((DNS_TRACE_ID_C(1) << (DNS_TRACE_ID_BITS - 1)) - 1) | (DNS_TRACE_ID_C(1) << (DNS_TRACE_ID_BITS - 1)))
4434 #define DNS_TRACE_ID_PRI PRIu64
4435
4436 static inline dns_trace_id_t dns_trace_mkid(void) {
4437         dns_trace_id_t id = 0;
4438         unsigned r; /* return type of dns_random() */
4439         const size_t id_bit = sizeof id * CHAR_BIT;
4440         const size_t r_bit = sizeof r * CHAR_BIT;
4441
4442         for (size_t n = 0; n < id_bit; n += r_bit) {
4443                 r = dns_random();
4444                 id <<= r_bit;
4445                 id |= r;
4446         }
4447
4448         return DNS_TRACE_ID_MASK & id;
4449 }
4450
4451 struct dns_trace {
4452         dns_atomic_t refcount;
4453
4454         FILE *fp;
4455         dns_trace_id_t id;
4456
4457         struct {
4458                 struct dns_trace_cname {
4459                         char host[DNS_D_MAXNAME + 1];
4460                         struct sockaddr_storage addr;
4461                 } base[4];
4462                 size_t p;
4463         } cnames;
4464 };
4465
4466 static void dns_te_initname(struct sockaddr_storage *ss, int fd, int (* STDCALL f)(socket_fd_t, struct sockaddr *, socklen_t *)) {
4467         socklen_t n = sizeof *ss;
4468
4469         if (0 != f(fd, (struct sockaddr *)ss, &n))
4470                 goto unspec;
4471
4472         if (n > sizeof *ss)
4473                 goto unspec;
4474
4475         return;
4476 unspec:
4477         memset(ss, '\0', sizeof *ss);
4478         ss->ss_family = AF_UNSPEC;
4479 }
4480
4481 static void dns_te_initnames(struct sockaddr_storage *local, struct sockaddr_storage *remote, int fd) {
4482         dns_te_initname(local, fd, &getsockname);
4483         dns_te_initname(remote, fd, &getpeername);
4484 }
4485
4486 static struct dns_trace_event *dns_te_init(struct dns_trace_event *te, int type) {
4487         /* NB: silence valgrind */
4488         memset(te, '\0', offsetof(struct dns_trace_event, data));
4489         te->type = type;
4490         return te;
4491 }
4492
4493 int dns_trace_abi(void) {
4494         return DNS_TRACE_ABI;
4495 }
4496
4497 struct dns_trace *dns_trace_open(FILE *fp, dns_error_t *error) {
4498         static const struct dns_trace trace_initializer = { .refcount = 1 };
4499         struct dns_trace *trace;
4500
4501         if (!(trace = malloc(sizeof *trace)))
4502                 goto syerr;
4503
4504         *trace = trace_initializer;
4505
4506         if (fp) {
4507                 trace->fp = fp;
4508         } else if (!(fp = tmpfile())) {
4509                 goto syerr;
4510         }
4511
4512         trace->id = dns_trace_mkid();
4513
4514         return trace;
4515 syerr:
4516         *error = dns_syerr();
4517
4518         dns_trace_close(trace);
4519
4520         return NULL;
4521 } /* dns_trace_open() */
4522
4523 void dns_trace_close(struct dns_trace *trace) {
4524         if (!trace || 1 != dns_trace_release(trace))
4525                 return;
4526
4527         if (trace->fp)
4528                 fclose(trace->fp);
4529         free(trace);
4530 } /* dns_trace_close() */
4531
4532 dns_refcount_t dns_trace_acquire(struct dns_trace *trace) {
4533         return dns_atomic_fetch_add(&trace->refcount);
4534 } /* dns_trace_acquire() */
4535
4536 static struct dns_trace *dns_trace_acquire_p(struct dns_trace *trace) {
4537         return (trace)? dns_trace_acquire(trace), trace : NULL;
4538 } /* dns_trace_acquire_p() */
4539
4540 dns_refcount_t dns_trace_release(struct dns_trace *trace) {
4541         return dns_atomic_fetch_sub(&trace->refcount);
4542 } /* dns_trace_release() */
4543
4544 dns_trace_id_t dns_trace_id(struct dns_trace *trace) {
4545         return trace->id;
4546 } /* dns_trace_id() */
4547
4548 dns_trace_id_t dns_trace_setid(struct dns_trace *trace, dns_trace_id_t id) {
4549         trace->id = (id)? id : dns_trace_mkid();
4550         return trace->id;
4551 } /* dns_trace_setid() */
4552
4553 struct dns_trace_event *dns_trace_get(struct dns_trace *trace, struct dns_trace_event **tp, dns_error_t *error) {
4554         return dns_trace_fget(tp, trace->fp, error);
4555 } /* dns_trace_get() */
4556
4557 dns_error_t dns_trace_put(struct dns_trace *trace, const struct dns_trace_event *te, const void *data, size_t datasize) {
4558         return dns_trace_fput(te, data, datasize, trace->fp);
4559 } /* dns_trace_put() */
4560
4561 struct dns_trace_event *dns_trace_tag(struct dns_trace *trace, struct dns_trace_event *te) {
4562         struct timeval tv;
4563
4564         te->id = trace->id;
4565         gettimeofday(&tv, NULL);
4566         dns_tv2ts(&te->ts, &tv);
4567         te->abi = DNS_TRACE_ABI;
4568
4569         return te;
4570 } /* dns_trace_tag() */
4571
4572 static dns_error_t dns_trace_tag_and_put(struct dns_trace *trace, struct dns_trace_event *te, const void *data, size_t datasize) {
4573         return dns_trace_put(trace, dns_trace_tag(trace, te), data, datasize);
4574 } /* dns_trace_tag_and_put() */
4575
4576 struct dns_trace_event *dns_trace_fget(struct dns_trace_event **tp, FILE *fp, dns_error_t *error) {
4577         const size_t headsize = offsetof(struct dns_trace_event, data);
4578         struct dns_trace_event tmp, *te;
4579         size_t n;
4580
4581         errno = 0;
4582         if (!(n = fread(&tmp, 1, headsize, fp)))
4583                 goto none;
4584         if (n < offsetof(struct dns_trace_event, data))
4585                 goto some;
4586
4587         if (!(te = realloc(*tp, DNS_PP_MAX(headsize, tmp.size)))) {
4588                 *error = errno;
4589                 return NULL;
4590         }
4591
4592         *tp = te;
4593         memcpy(te, &tmp, offsetof(struct dns_trace_event, data));
4594
4595         if (dns_te_datasize(te)) {
4596                 errno = 0;
4597                 if (!(n = fread(te->data, 1, dns_te_datasize(te), fp)))
4598                         goto none;
4599                 if (n < dns_te_datasize(te))
4600                         goto some;
4601         }
4602
4603         return te;
4604 none:
4605         *error = (ferror(fp))? errno : 0;
4606         return NULL;
4607 some:
4608         *error = 0;
4609         return NULL;
4610 }
4611
4612 dns_error_t dns_trace_fput(const struct dns_trace_event *te, const void *data, size_t datasize, FILE *fp) {
4613         size_t headsize = offsetof(struct dns_trace_event, data);
4614         struct dns_trace_event tmp;
4615
4616         memcpy(&tmp, te, headsize);
4617         tmp.size = headsize + datasize;
4618
4619         /* NB: ignore seek error as fp might not point to a regular file */
4620         (void)fseek(fp, 0, SEEK_END);
4621
4622         if (fwrite(&tmp, 1, headsize, fp) < headsize)
4623                 return errno;
4624         if (data)
4625                 if (fwrite(data, 1, datasize, fp) < datasize)
4626                         return errno;
4627         if (fflush(fp))
4628                 return errno;
4629
4630         return 0;
4631 }
4632
4633 static void dns_trace_setcname(struct dns_trace *trace, const char *host, const struct sockaddr *addr) {
4634         struct dns_trace_cname *cname;
4635         if (!trace || !trace->fp)
4636                 return;
4637
4638         cname = &trace->cnames.base[trace->cnames.p];
4639         dns_strlcpy(cname->host, host, sizeof cname->host);
4640         memcpy(&cname->addr, addr, DNS_PP_MIN(dns_sa_len(addr), sizeof cname->addr));
4641
4642         trace->cnames.p = (trace->cnames.p + 1) % lengthof(trace->cnames.base);
4643 }
4644
4645 static const char *dns_trace_cname(struct dns_trace *trace, const struct sockaddr *addr) {
4646         if (!trace || !trace->fp)
4647                 return NULL;
4648
4649         /* NB: start search from the write cursor to  */
4650         for (const struct dns_trace_cname *cname = trace->cnames.base; cname < endof(trace->cnames.base); cname++) {
4651                 if (0 == dns_sa_cmp((struct sockaddr *)addr, (struct sockaddr *)&cname->addr))
4652                         return cname->host;
4653         }
4654
4655         return NULL;
4656 }
4657
4658 static void dns_trace_res_submit(struct dns_trace *trace, const char *qname, enum dns_type qtype, enum dns_class qclass, int error) {
4659         struct dns_trace_event te;
4660         if (!trace || !trace->fp)
4661                 return;
4662
4663         dns_te_init(&te, DNS_TE_RES_SUBMIT);
4664         dns_strlcpy(te.res_submit.qname, qname, sizeof te.res_submit.qname);
4665         te.res_submit.qtype = qtype;
4666         te.res_submit.qclass = qclass;
4667         te.res_submit.error = error;
4668         dns_trace_tag_and_put(trace, &te, NULL, 0);
4669 }
4670
4671 static void dns_trace_res_fetch(struct dns_trace *trace, const struct dns_packet *packet, int error) {
4672         struct dns_trace_event te;
4673         const void *data;
4674         size_t datasize;
4675         if (!trace || !trace->fp)
4676                 return;
4677
4678         dns_te_init(&te, DNS_TE_RES_FETCH);
4679         data = (packet)? packet->data : NULL;
4680         datasize = (packet)? packet->end : 0;
4681         te.res_fetch.error = error;
4682         dns_trace_tag_and_put(trace, &te, data, datasize);
4683 }
4684
4685 static void dns_trace_so_submit(struct dns_trace *trace, const struct dns_packet *packet, const struct sockaddr *haddr, int error) {
4686         struct dns_trace_event te;
4687         const char *cname;
4688         if (!trace || !trace->fp)
4689                 return;
4690
4691         dns_te_init(&te, DNS_TE_SO_SUBMIT);
4692         memcpy(&te.so_submit.haddr, haddr, DNS_PP_MIN(dns_sa_len(haddr), sizeof te.so_submit.haddr));
4693         if ((cname = dns_trace_cname(trace, haddr)))
4694                 dns_strlcpy(te.so_submit.hname, cname, sizeof te.so_submit.hname);
4695         te.so_submit.error = error;
4696         dns_trace_tag_and_put(trace, &te, packet->data, packet->end);
4697 }
4698
4699 static void dns_trace_so_verify(struct dns_trace *trace, const struct dns_packet *packet, int error) {
4700         struct dns_trace_event te;
4701         if (!trace || !trace->fp)
4702                 return;
4703
4704         dns_te_init(&te, DNS_TE_SO_VERIFY);
4705         te.so_verify.error = error;
4706         dns_trace_tag_and_put(trace, &te, packet->data, packet->end);
4707 }
4708
4709 static void dns_trace_so_fetch(struct dns_trace *trace, const struct dns_packet *packet, int error) {
4710         struct dns_trace_event te;
4711         const void *data;
4712         size_t datasize;
4713         if (!trace || !trace->fp)
4714                 return;
4715
4716         dns_te_init(&te, DNS_TE_SO_FETCH);
4717         data = (packet)? packet->data : NULL;
4718         datasize = (packet)? packet->end : 0;
4719         te.so_fetch.error = error;
4720         dns_trace_tag_and_put(trace, &te, data, datasize);
4721 }
4722
4723 static void dns_trace_sys_connect(struct dns_trace *trace, int fd, int socktype, const struct sockaddr *dst, int error) {
4724         struct dns_trace_event te;
4725         if (!trace || !trace->fp)
4726                 return;
4727
4728         dns_te_init(&te, DNS_TE_SYS_CONNECT);
4729         dns_te_initname(&te.sys_connect.src, fd, &getsockname);
4730         memcpy(&te.sys_connect.dst, dst, DNS_PP_MIN(dns_sa_len(dst), sizeof te.sys_connect.dst));
4731         te.sys_connect.socktype = socktype;
4732         te.sys_connect.error = error;
4733         dns_trace_tag_and_put(trace, &te, NULL, 0);
4734 }
4735
4736 static void dns_trace_sys_send(struct dns_trace *trace, int fd, int socktype, const void *data, size_t datasize, int error) {
4737         struct dns_trace_event te;
4738         if (!trace || !trace->fp)
4739                 return;
4740
4741         dns_te_init(&te, DNS_TE_SYS_SEND);
4742         dns_te_initnames(&te.sys_send.src, &te.sys_send.dst, fd);
4743         te.sys_send.socktype = socktype;
4744         te.sys_send.error = error;
4745         dns_trace_tag_and_put(trace, &te, data, datasize);
4746 }
4747
4748 static void dns_trace_sys_recv(struct dns_trace *trace, int fd, int socktype, const void *data, size_t datasize, int error) {
4749         struct dns_trace_event te;
4750         if (!trace || !trace->fp)
4751                 return;
4752
4753         dns_te_init(&te, DNS_TE_SYS_RECV);
4754         dns_te_initnames(&te.sys_recv.dst, &te.sys_recv.src, fd);
4755         te.sys_recv.socktype = socktype;
4756         te.sys_recv.error = error;
4757         dns_trace_tag_and_put(trace, &te, data, datasize);
4758 }
4759
4760 static dns_error_t dns_trace_dump_packet(struct dns_trace *trace, const char *prefix, const unsigned char *data, size_t datasize, FILE *fp) {
4761         struct dns_packet *packet = NULL;
4762         char *line = NULL, *p;
4763         size_t size = 1, skip = 0;
4764         struct dns_rr_i records;
4765         struct dns_p_lines_i lines;
4766         size_t len, count;
4767         int error;
4768
4769         if (!(packet = dns_p_make(datasize, &error)))
4770                 goto error;
4771
4772         memcpy(packet->data, data, datasize);
4773         packet->end = datasize;
4774         (void)dns_p_study(packet);
4775 resize:
4776         if (!(p = dns_reallocarray(line, size, 2, &error)))
4777                 goto error;
4778         line = p;
4779         size *= 2;
4780
4781         memset(&records, 0, sizeof records);
4782         memset(&lines, 0, sizeof lines);
4783         count = 0;
4784
4785         while ((len = dns_p_lines(line, size, &error, packet, &records, &lines))) {
4786                 if (!(len < size)) {
4787                         skip = count;
4788                         goto resize;
4789                 } else if (skip <= count) {
4790                         fputs(prefix, fp);
4791                         fwrite(line, 1, len, fp);
4792                 }
4793                 count++;
4794         }
4795
4796         if (error)
4797                 goto error;
4798
4799         error = 0;
4800 error:
4801         free(line);
4802         dns_p_free(packet);
4803
4804         return error;
4805 }
4806
4807 static dns_error_t dns_trace_dump_data(struct dns_trace *trace, const char *prefix, const unsigned char *data, size_t datasize, FILE *fp) {
4808         struct dns_hxd_lines_i lines = { 0 };
4809         char line[128];
4810         size_t len;
4811
4812         while ((len = dns_hxd_lines(line, sizeof line, data, datasize, &lines))) {
4813                 if (len >= sizeof line)
4814                         return EOVERFLOW; /* shouldn't be possible */
4815                 fputs(prefix, fp);
4816                 fwrite(line, 1, len, fp);
4817         }
4818
4819         return 0;
4820 }
4821
4822 static dns_error_t dns_trace_dump_addr(struct dns_trace *trace, const char *prefix, const struct sockaddr_storage *ss, FILE *fp) {
4823         const void *addr;
4824         const char *path;
4825         socklen_t len;
4826         int error;
4827
4828         if ((addr = dns_sa_addr(ss->ss_family, (struct sockaddr *)ss, NULL))) {
4829                 char ip[INET6_ADDRSTRLEN + 1];
4830
4831                 if ((error = dns_ntop(ss->ss_family, addr, ip, sizeof ip)))
4832                         return error;
4833                 fprintf(fp, "%s%s\n", prefix, ip);
4834         } else if ((path = dns_sa_path((struct sockaddr *)ss, &len))) {
4835                 fprintf(fp, "%sunix:%.*s", prefix, (int)len, path);
4836         } else {
4837                 return EINVAL;
4838         }
4839
4840         return 0;
4841 }
4842
4843 static dns_error_t dns_trace_dump_meta(struct dns_trace *trace, const char *prefix, const struct dns_trace_event *te, dns_microseconds_t elapsed, FILE *fp) {
4844         char time_s[48], elapsed_s[48];
4845
4846         dns_utime_print(time_s, sizeof time_s, dns_ts2us(&te->ts, 0));
4847         dns_utime_print(elapsed_s, sizeof elapsed_s, elapsed);
4848
4849         fprintf(fp, "%sid: %"DNS_TRACE_ID_PRI"\n", prefix, te->id);
4850         fprintf(fp, "%sts: %s (%s)\n", prefix, time_s, elapsed_s);
4851         fprintf(fp, "%sabi: 0x%x (0x%x)\n", prefix, te->abi, DNS_TRACE_ABI);
4852         return 0;
4853 }
4854
4855 static dns_error_t dns_trace_dump_error(struct dns_trace *trace, const char *prefix, int error, FILE *fp) {
4856         fprintf(fp, "%s%d (%s)\n", prefix, error, (error)? dns_strerror(error) : "none");
4857         return 0;
4858 }
4859
4860 dns_error_t dns_trace_dump(struct dns_trace *trace, FILE *fp) {
4861         struct dns_trace_event *te = NULL;
4862         struct {
4863                 dns_trace_id_t id;
4864                 dns_microseconds_t begin, elapsed;
4865         } state = { 0 };
4866         int error;
4867
4868       &nb