Tizen 2.1 base
[framework/uifw/ecore.git] / src / lib / ecore_con / dns.c
1 /* ==========================================================================
2  * dns.c - Recursive, Reentrant DNS Resolver.
3  * --------------------------------------------------------------------------
4  * Copyright (c) 2008, 2009, 2010  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 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #if !defined(__FreeBSD__)
31 #ifndef _XOPEN_SOURCE
32 #define _XOPEN_SOURCE   600
33 #endif
34
35 #undef _BSD_SOURCE
36 #define _BSD_SOURCE
37
38 #undef _DARWIN_C_SOURCE
39 #define _DARWIN_C_SOURCE
40
41 #undef _NETBSD_SOURCE
42 #define _NETBSD_SOURCE
43 #endif
44
45 #include <stddef.h>             /* offsetof() */
46 #include <stdint.h>             /* uint32_t */
47 #include <stdlib.h>             /* malloc(3) realloc(3) free(3) rand(3) random(3) arc4random(3) */
48 #include <stdio.h>              /* FILE fopen(3) fclose(3) getc(3) rewind(3) */
49
50 #include <string.h>             /* memcpy(3) strlen(3) memmove(3) memchr(3) memcmp(3) strchr(3) strsep(3) strcspn(3) */
51 #include <strings.h>            /* strcasecmp(3) strncasecmp(3) */
52
53 #include <ctype.h>              /* isspace(3) isdigit(3) */
54
55 #include <time.h>               /* time_t time(2) */
56
57 #include <signal.h>             /* sig_atomic_t */
58
59 #include <errno.h>              /* errno EINVAL ENOENT */
60
61 #undef NDEBUG
62 #include <assert.h>             /* assert(3) */
63
64 #if _WIN32
65 #include <winsock2.h>
66 #include <ws2tcpip.h>
67 #else
68 #include <sys/types.h>          /* FD_SETSIZE socklen_t */
69 #include <sys/select.h>         /* FD_ZERO FD_SET fd_set select(2) */
70 #include <sys/socket.h>         /* AF_INET AF_INET6 AF_UNIX struct sockaddr struct sockaddr_in struct sockaddr_in6 socket(2) */
71
72 #if defined(AF_UNIX)
73 #include <sys/un.h>             /* struct sockaddr_un */
74 #endif
75
76 #include <fcntl.h>              /* F_SETFD F_GETFL F_SETFL O_NONBLOCK fcntl(2) */
77
78 #include <unistd.h>             /* gethostname(3) close(2) */
79
80 #include <poll.h>               /* POLLIN POLLOUT */
81
82 #include <netinet/in.h>         /* struct sockaddr_in struct sockaddr_in6 */
83
84 #include <arpa/inet.h>          /* inet_pton(3) inet_ntop(3) htons(3) ntohs(3) */
85
86 #include <netdb.h>              /* struct addrinfo */
87 #endif
88
89 #include "dns.h"
90
91
92 /*
93  * S T A N D A R D  M A C R O S
94  *
95  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
96
97 #ifndef MIN
98 #define MIN(a, b)       (((a) < (b))? (a) : (b))
99 #endif
100
101
102 #ifndef MAX
103 #define MAX(a, b)       (((a) > (b))? (a) : (b))
104 #endif
105
106
107 #ifndef lengthof
108 #define lengthof(a)     (sizeof (a) / sizeof (a)[0])
109 #endif
110
111 #ifndef endof
112 #define endof(a)        (&(a)[lengthof((a))])
113 #endif
114
115
116 /*
117  * D E B U G  M A C R O S
118  *
119  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
120
121 int dns_debug = 0;
122
123 #if DNS_DEBUG
124
125 #undef DNS_DEBUG
126 #define DNS_DEBUG dns_debug
127
128 #define DNS_SAY_(fmt, ...) \
129         do { if (DNS_DEBUG > 0) fprintf(stderr, fmt "%.1s", __func__, __LINE__, __VA_ARGS__); } while (0)
130 #define DNS_SAY(...) DNS_SAY_("@@ (%s:%d) " __VA_ARGS__, "\n")
131 #define DNS_HAI DNS_SAY("HAI")
132
133 #define DNS_SHOW_(P, fmt, ...)  do {                                    \
134         if (DNS_DEBUG > 1) {                                            \
135         fprintf(stderr, "@@ BEGIN * * * * * * * * * * * *\n");          \
136         fprintf(stderr, "@@ " fmt "%.0s\n", __VA_ARGS__);               \
137         dns_p_dump((P), stderr);                                        \
138         fprintf(stderr, "@@ END * * * * * * * * * * * * *\n\n");        \
139         }                                                               \
140 } while (0)
141
142 #define DNS_SHOW(...)   DNS_SHOW_(__VA_ARGS__, "")
143
144 #else /* !DNS_DEBUG */
145
146 #undef DNS_DEBUG
147 #define DNS_DEBUG 0
148
149 #define DNS_SAY(...)
150 #define DNS_HAI
151 #define DNS_SHOW(...)
152
153 #endif /* DNS_DEBUG */
154
155
156 /*
157  * V E R S I O N  R O U T I N E S
158  *
159  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
160
161 const char *dns_vendor(void) {
162         return DNS_VENDOR;
163 } /* dns_vendor() */
164
165
166 int dns_v_rel(void) {
167         return DNS_V_REL;
168 } /* dns_v_rel() */
169
170
171 int dns_v_abi(void) {
172         return DNS_V_ABI;
173 } /* dns_v_abi() */
174
175
176 int dns_v_api(void) {
177         return DNS_V_API;
178 } /* dns_v_api() */
179
180
181 /*
182  * E R R O R  R O U T I N E S
183  *
184  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
185
186 #if _WIN32
187
188 #define DNS_EINTR       WSAEINTR
189 #define DNS_EINPROGRESS WSAEINPROGRESS
190 #define DNS_EISCONN     WSAEISCONN
191 #define DNS_EWOULDBLOCK WSAEWOULDBLOCK
192 #define DNS_EALREADY    WSAEALREADY
193 #define DNS_EAGAIN      EAGAIN
194 #define DNS_ETIMEDOUT   WSAETIMEDOUT
195
196 #define dns_syerr()     ((int)GetLastError())
197 #define dns_soerr()     ((int)WSAGetLastError())
198
199 #else
200
201 #define DNS_EINTR       EINTR
202 #define DNS_EINPROGRESS EINPROGRESS
203 #define DNS_EISCONN     EISCONN
204 #define DNS_EWOULDBLOCK EWOULDBLOCK
205 #define DNS_EALREADY    EALREADY
206 #define DNS_EAGAIN      EAGAIN
207 #define DNS_ETIMEDOUT   ETIMEDOUT
208
209 #define dns_syerr()     errno
210 #define dns_soerr()     errno
211
212 #endif
213
214
215 const char *dns_strerror(int error) {
216         switch (error) {
217         case DNS_ENOBUFS:
218                 return "DNS packet buffer too small";
219         case DNS_EILLEGAL:
220                 return "Illegal DNS RR name or data";
221         case DNS_EORDER:
222                 return "Attempt to push RR out of section order";
223         case DNS_ESECTION:
224                 return "Invalid section specified";
225         case DNS_EUNKNOWN:
226                 return "Unknown DNS error";
227         default:
228                 return strerror(error);
229         } /* switch() */
230 } /* dns_strerror() */
231
232
233 /*
234  * A T O M I C  R O U T I N E S
235  *
236  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
237
238 static unsigned dns_atomic_inc(dns_atomic_t *i) {
239         return (*i)++;
240 } /* dns_atomic_inc() */
241
242
243 static unsigned dns_atomic_dec(dns_atomic_t *i) {
244         return (*i)--;
245 } /* dns_atomic_dec() */
246
247
248 /*
249  * C R Y P T O  R O U T I N E S
250  *
251  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
252
253 /*
254  * P R N G 
255  */
256
257 #ifndef DNS_RANDOM
258 #if defined(HAVE_ARC4RANDOM)    \
259  || defined(__OpenBSD__)        \
260  || defined(__FreeBSD__)        \
261  || defined(__NetBSD__)         \
262  || defined(__APPLE__)
263 #define DNS_RANDOM      arc4random
264 #elif __linux
265 #define DNS_RANDOM      random
266 #else
267 #define DNS_RANDOM      rand
268 #endif
269 #endif
270
271 #define DNS_RANDOM_arc4random   1
272 #define DNS_RANDOM_random       2
273 #define DNS_RANDOM_rand         3
274 #define DNS_RANDOM_RAND_bytes   4
275
276 #define DNS_RANDOM_OPENSSL      (DNS_RANDOM_RAND_bytes == DNS_PP_XPASTE(DNS_RANDOM_, DNS_RANDOM))
277
278 #if DNS_RANDOM_OPENSSL
279 #include <openssl/rand.h>
280 #endif
281
282 static unsigned dns_random_(void) {
283 #if DNS_RANDOM_OPENSSL
284         unsigned r;
285
286         assert(1 == RAND_bytes((unsigned char *)&r, sizeof r));
287
288         return r;
289 #else
290         return DNS_RANDOM();
291 #endif
292 } /* dns_random_() */
293
294 unsigned (*dns_random)(void) __attribute__((weak))      = &dns_random_;
295
296
297 /*
298  * P E R M U T A T I O N  G E N E R A T O R
299  */
300
301 #define DNS_K_TEA_KEY_SIZE      16
302 #define DNS_K_TEA_BLOCK_SIZE    8
303 #define DNS_K_TEA_CYCLES        32
304 #define DNS_K_TEA_MAGIC         0x9E3779B9U
305
306 struct dns_k_tea {
307         uint32_t key[DNS_K_TEA_KEY_SIZE / sizeof (uint32_t)];
308         unsigned cycles;
309 }; /* struct dns_k_tea */
310
311
312 static void dns_k_tea_init(struct dns_k_tea *tea, uint32_t key[], unsigned cycles) {
313         memcpy(tea->key, key, sizeof tea->key);
314
315         tea->cycles     = (cycles)? cycles : DNS_K_TEA_CYCLES;
316 } /* dns_k_tea_init() */
317
318
319 static void dns_k_tea_encrypt(struct dns_k_tea *tea, uint32_t v[], uint32_t *w) {
320         uint32_t y, z, sum, n;
321
322         y       = v[0];
323         z       = v[1];
324         sum     = 0;
325
326         for (n = 0; n < tea->cycles; n++) {
327                 sum     += DNS_K_TEA_MAGIC;
328                 y       += ((z << 4) + tea->key[0]) ^ (z + sum) ^ ((z >> 5) + tea->key[1]);
329                 z       += ((y << 4) + tea->key[2]) ^ (y + sum) ^ ((y >> 5) + tea->key[3]);
330         }
331
332         w[0]    = y;
333         w[1]    = z;
334
335         return /* void */;
336 } /* dns_k_tea_encrypt() */
337
338
339 /*
340  * Permutation generator, based on a Luby-Rackoff Feistel construction.
341  *
342  * Specifically, this is a generic balanced Feistel block cipher using TEA
343  * (another block cipher) as the pseudo-random function, F. At best it's as
344  * strong as F (TEA), notwithstanding the seeding. F could be AES, SHA-1, or
345  * perhaps Bernstein's Salsa20 core; I am naively trying to keep things
346  * simple.
347  *
348  * The generator can create a permutation of any set of numbers, as long as
349  * the size of the set is an even power of 2. This limitation arises either
350  * out of an inherent property of balanced Feistel constructions, or by my
351  * own ignorance. I'll tackle an unbalanced construction after I wrap my
352  * head around Schneier and Kelsey's paper.
353  *
354  * CAVEAT EMPTOR. IANAC.
355  */
356 #define DNS_K_PERMUTOR_ROUNDS   8
357
358 struct dns_k_permutor {
359         unsigned stepi, length, limit;
360         unsigned shift, mask, rounds;
361
362         struct dns_k_tea tea;
363 }; /* struct dns_k_permutor */
364
365
366 static inline unsigned dns_k_permutor_powof(unsigned n) {
367         unsigned m, i = 0;
368
369         for (m = 1; m < n; m <<= 1, i++)
370                 ;;
371
372         return i;
373 } /* dns_k_permutor_powof() */
374
375 static void dns_k_permutor_init(struct dns_k_permutor *p, unsigned low, unsigned high) {
376         uint32_t key[DNS_K_TEA_KEY_SIZE / sizeof (uint32_t)];
377         unsigned width, i;
378
379         p->stepi        = 0;
380
381         p->length       = (high - low) + 1;
382         p->limit        = high;
383
384         width           = dns_k_permutor_powof(p->length);
385         width           += width % 2;
386
387         p->shift        = width / 2;
388         p->mask         = (1U << p->shift) - 1;
389         p->rounds       = DNS_K_PERMUTOR_ROUNDS;
390
391         for (i = 0; i < lengthof(key); i++)
392                 key[i]  = dns_random();
393
394         dns_k_tea_init(&p->tea, key, 0);
395
396         return /* void */;
397 } /* dns_k_permutor_init() */
398
399
400 static unsigned dns_k_permutor_F(struct dns_k_permutor *p, unsigned k, unsigned x) {
401         uint32_t in[DNS_K_TEA_BLOCK_SIZE / sizeof (uint32_t)], out[DNS_K_TEA_BLOCK_SIZE / sizeof (uint32_t)];
402
403         memset(in, '\0', sizeof in);
404
405         in[0]   = k;
406         in[1]   = x;
407
408         dns_k_tea_encrypt(&p->tea, in, out);
409
410         return p->mask & out[0];
411 } /* dns_k_permutor_F() */
412
413
414 static unsigned dns_k_permutor_E(struct dns_k_permutor *p, unsigned n) {
415         unsigned l[2], r[2];
416         unsigned i;
417
418         i       = 0;
419         l[i]    = p->mask & (n >> p->shift);
420         r[i]    = p->mask & (n >> 0);
421
422         do {
423                 l[(i + 1) % 2]  = r[i % 2];
424                 r[(i + 1) % 2]  = l[i % 2] ^ dns_k_permutor_F(p, i, r[i % 2]);
425
426                 i++;
427         } while (i < p->rounds - 1);
428
429         return ((l[i % 2] & p->mask) << p->shift) | ((r[i % 2] & p->mask) << 0);
430 } /* dns_k_permutor_E() */
431
432 static unsigned dns_k_permutor_step(struct dns_k_permutor *p) {
433         unsigned n;
434
435         do {
436                 n       = dns_k_permutor_E(p, p->stepi++);
437         } while (n >= p->length);
438
439         return n + (p->limit + 1 - p->length);
440 } /* dns_k_permutor_step() */
441
442
443 /*
444  * Simple permutation box. Useful for shuffling rrsets from an iterator.
445  * Uses AES s-box to provide good diffusion.
446  *
447  * Seems to pass muster under runs test.
448  *
449  * $ for i in 0 1 2 3 4 5 6 7 8 9; do ./dns shuffle-16 > /tmp/out; done
450  * $ R -q -f /dev/stdin 2>/dev/null <<-EOF | awk '/p-value/{ print $8 }'
451  *      library(lawstat)
452  *      runs.test(scan(file="/tmp/out"))
453  * EOF
454  */
455 static unsigned short dns_k_shuffle16(unsigned short n, unsigned s) {
456         static const unsigned char sbox[256] =
457         { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
458           0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
459           0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
460           0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
461           0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
462           0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
463           0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
464           0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
465           0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
466           0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
467           0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
468           0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
469           0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
470           0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
471           0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
472           0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
473           0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
474           0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
475           0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
476           0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
477           0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
478           0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
479           0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
480           0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
481           0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
482           0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
483           0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
484           0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
485           0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
486           0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
487           0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
488           0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };
489         unsigned char a, b;
490         unsigned i;
491
492         a = 0xff & (n >> 0);
493         b = 0xff & (n >> 8);
494
495         for (i = 0; i < 4; i++) {
496                 a ^= 0xff & s;
497                 a = sbox[a] ^ b;
498                 b = sbox[b] ^ a;
499                 s >>= 8;
500         }
501
502         return ((0xff00 & (a << 8)) | (0x00ff & (b << 0)));
503 } /* dns_k_shuffle16() */
504
505
506 /*
507  * U T I L I T Y  R O U T I N E S
508  *
509  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
510
511 /*
512  * Monotonic Time
513  *
514  */
515 static time_t dns_now(void) {
516         /* XXX: Assumes sizeof (time_t) <= sizeof (sig_atomic_t) */
517         static volatile sig_atomic_t last, tick;
518         volatile sig_atomic_t tmp_last, tmp_tick;
519         time_t now;
520
521         time(&now);
522
523         tmp_last        = last;
524
525         if (now > tmp_last) {
526                 tmp_tick        = tick;
527                 tmp_tick        += now - tmp_last;
528                 tick            = tmp_tick;
529         }
530
531         last    = now;
532
533         return tick;
534 } /* dns_now() */
535
536 static time_t dns_elapsed(time_t from) {
537         time_t now      = dns_now();
538
539         return (now > from)? now - from : 0;
540 } /* dns_elpased() */
541
542
543 static size_t dns_af_len(int af) {
544         static const size_t table[AF_MAX]       = {
545                 [AF_INET6]      = sizeof (struct sockaddr_in6),
546                 [AF_INET]       = sizeof (struct sockaddr_in),
547 #if defined(AF_UNIX) && !defined(_WIN32)
548                 [AF_UNIX]       = sizeof (struct sockaddr_un),
549 #endif
550         };
551
552         return table[af];
553 } /* dns_af_len() */
554
555 #define dns_sa_len(sa)          dns_af_len(dns_sa_family(sa))
556
557
558 #define DNS_SA_NOPORT   &dns_sa_noport
559 static unsigned short dns_sa_noport;
560
561 unsigned short *dns_sa_port(int af, void *sa) {
562         switch (af) {
563         case AF_INET6:
564                 return &((struct sockaddr_in6 *)sa)->sin6_port;
565         case AF_INET:
566                 return &((struct sockaddr_in *)sa)->sin_port;
567         default:
568                 return DNS_SA_NOPORT;
569         }
570 } /* dns_sa_port() */
571
572
573 void *dns_sa_addr(int af, void *sa) {
574         switch (af) {
575         case AF_INET6:
576                 return &((struct sockaddr_in6 *)sa)->sin6_addr;
577         case AF_INET:
578                 return &((struct sockaddr_in *)sa)->sin_addr;
579         default:
580                 return 0;
581         }
582 } /* dns_sa_addr() */
583
584
585 #if _WIN32
586 static int dns_inet_pton(int af, const void *src, void *dst) {
587         union { struct sockaddr_in sin; struct sockaddr_in6 sin6; } u;
588
589         u.sin.sin_family        = af;
590
591         if (0 != WSAStringToAddressA((void *)src, af, (void *)0, (struct sockaddr *)&u, &(int){ sizeof u }))
592                 return -1;
593
594         switch (af) {
595         case AF_INET6:
596                 *(struct in6_addr *)dst = u.sin6.sin6_addr;
597
598                 return 1;
599         case AF_INET:
600                 *(struct in_addr *)dst  = u.sin.sin_addr;
601
602                 return 1;
603         default:
604                 return 0;
605         }
606 } /* dns_inet_pton() */
607
608 const char *dns_inet_ntop(int af, const void *src, void *dst, unsigned long lim) {
609         union { struct sockaddr_in sin; struct sockaddr_in6 sin6; } u;
610
611         /* NOTE: WSAAddressToString will print .sin_port unless zeroed. */
612         memset(&u, 0, sizeof u);
613
614         u.sin.sin_family        = af;
615
616         switch (af) {
617         case AF_INET6:
618                 u.sin6.sin6_addr        = *(struct in6_addr *)src;
619                 break;
620         case AF_INET:
621                 u.sin.sin_addr          = *(struct in_addr *)src;
622
623                 break;
624         default:
625                 return 0;
626         }
627
628         if (0 != WSAAddressToStringA((struct sockaddr *)&u, dns_sa_len(&u), (void *)0, dst, &lim))
629                 return 0;
630
631         return dst;
632 } /* dns_inet_ntop() */
633 #endif
634
635
636 size_t dns_strlcpy(char *dst, const char *src, size_t lim) {
637         char *d         = dst;
638         char *e         = &dst[lim];
639         const char *s   = src;
640
641         if (d < e) {
642                 do {
643                         if ('\0' == (*d++ = *s++))
644                                 return s - src - 1;
645                 } while (d < e);
646
647                 d[-1]   = '\0';
648         }
649
650         while (*s++ != '\0')
651                 ;;
652
653         return s - src - 1;
654 } /* dns_strlcpy() */
655
656
657 size_t dns_strlcat(char *dst, const char *src, size_t lim) {
658         char *d = memchr(dst, '\0', lim);
659         char *e = &dst[lim];
660         const char *s = src;
661         const char *p;
662
663         if (d && d < e) {
664                 do {
665                         if ('\0' == (*d++ = *s++))
666                                 return d - dst - 1;
667                 } while (d < e);
668
669                 d[-1] = '\0';
670         }
671
672         p = s;
673
674         while (*s++ != '\0')
675                 ;;
676
677         return lim + (s - p - 1);
678 } /* dns_strlcat() */
679
680
681 #if _WIN32
682
683 static char *dns_strsep(char **sp, const char *delim) {
684         char *p;
685
686         if (!(p = *sp))
687                 return 0;
688
689         *sp += strcspn(p, delim);
690
691         if (**sp != '\0') {
692                 **sp = '\0';
693                 ++*sp;
694         } else
695                 *sp = NULL;
696
697         return p;
698 } /* dns_strsep() */
699
700 #else
701 #define dns_strsep(...) strsep(__VA_ARGS__)
702 #endif
703
704
705 #if _WIN32
706 #define strcasecmp(...)         _stricmp(__VA_ARGS__)
707 #define strncasecmp(...)        _strnicmp(__VA_ARGS__)
708 #endif
709
710
711 static int dns_poll(int fd, short events, int timeout) {
712         fd_set rset, wset;
713
714         if (!events)
715                 return 0;
716
717         assert(fd >= 0 && fd < FD_SETSIZE);
718
719         FD_ZERO(&rset);
720         FD_ZERO(&wset);
721
722         if (events & DNS_POLLIN)
723                 FD_SET(fd, &rset);
724
725         if (events & DNS_POLLOUT)
726                 FD_SET(fd, &wset);
727
728         select(fd + 1, &rset, &wset, 0, (timeout >= 0)? &(struct timeval){ timeout, 0 } : NULL);
729
730         return 0;
731 } /* dns_poll() */
732
733
734 /*
735  * P A C K E T  R O U T I N E S
736  *
737  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
738
739 unsigned dns_p_count(struct dns_packet *P, enum dns_section section) {
740         unsigned count;
741
742         switch (section) {
743         case DNS_S_QD:
744                 return ntohs(dns_header(P)->qdcount);
745         case DNS_S_AN:
746                 return ntohs(dns_header(P)->ancount);
747         case DNS_S_NS:
748                 return ntohs(dns_header(P)->nscount);
749         case DNS_S_AR:
750                 return ntohs(dns_header(P)->arcount);
751         default:
752                 count = 0;
753
754                 if (section & DNS_S_QD)
755                         count += ntohs(dns_header(P)->qdcount);
756                 if (section & DNS_S_AN)
757                         count += ntohs(dns_header(P)->ancount);
758                 if (section & DNS_S_NS)
759                         count += ntohs(dns_header(P)->nscount);
760                 if (section & DNS_S_AR)
761                         count += ntohs(dns_header(P)->arcount);
762
763                 return count;
764         }
765 } /* dns_p_count() */
766
767
768 struct dns_packet *dns_p_init(struct dns_packet *P, size_t size) {
769         if (!P)
770                 return 0;
771
772         assert(size >= offsetof(struct dns_packet, data) + 12);
773
774         memset(P, 0, sizeof *P);
775         P->size = size - offsetof(struct dns_packet, data);
776         P->end  = 12;
777
778         memset(P->data, '\0', 12);
779
780         return P;
781 } /* dns_p_init() */
782
783
784 static unsigned short dns_p_qend(struct dns_packet *P) {
785         unsigned short qend     = 12;
786         unsigned i, count       = dns_p_count(P, DNS_S_QD);
787
788         for (i = 0; i < count && qend < P->end; i++) {
789                 if (P->end == (qend = dns_d_skip(qend, P)))
790                         goto invalid;
791
792                 if (P->end - qend < 4)
793                         goto invalid;
794
795                 qend    += 4;
796         }
797
798         return MIN(qend, P->end);
799 invalid:
800         return P->end;
801 } /* dns_p_qend() */
802
803
804 struct dns_packet *dns_p_make(size_t len, int *error) {
805         struct dns_packet *P;
806         size_t size = dns_p_calcsize(len);
807
808         if (!(P = dns_p_init(malloc(size), size)))
809                 *error = dns_syerr();
810
811         return P;
812 } /* dns_p_make() */
813
814
815 int dns_p_grow(struct dns_packet **P) {
816         struct dns_packet *tmp;
817         size_t size;
818         int error;
819
820         if (!*P) {
821                 if (!(*P = dns_p_make(DNS_P_QBUFSIZ, &error)))
822                         return error;
823
824                 return 0;
825         }
826
827         size = dns_p_sizeof(*P);
828         size |= size >> 1;
829         size |= size >> 2;
830         size |= size >> 4;
831         size |= size >> 8;
832         size++;
833
834         if (size > 65536)
835                 return DNS_ENOBUFS;
836
837         if (!(tmp = realloc(*P, dns_p_calcsize(size))))
838                 return dns_syerr();
839
840         tmp->size = size;
841         *P = tmp;
842
843         return 0;
844 } /* dns_p_grow() */
845
846
847 struct dns_packet *dns_p_copy(struct dns_packet *P, const struct dns_packet *P0) {
848         if (!P)
849                 return 0;
850
851         P->end  = MIN(P->size, P0->end);
852
853         memcpy(P->data, P0->data, P->end);
854
855         return P;
856 } /* dns_p_copy() */
857
858
859 struct dns_packet *dns_p_merge(struct dns_packet *A, enum dns_section Amask, struct dns_packet *B, enum dns_section Bmask, int *error_) {
860         size_t bufsiz = MIN(65535, ((A)? A->end : 0) + ((B)? B->end : 0));
861         struct dns_packet *M;
862         enum dns_section section;
863         struct dns_rr rr, mr;
864         int error, copy;
865
866         if (!A && B) {
867                 A = B;
868                 Amask = Bmask;
869                 B = 0;
870         }
871
872 merge:
873         if (!(M = dns_p_make(bufsiz, &error)))
874                 goto error;
875
876         for (section = DNS_S_QD; (DNS_S_ALL & section); section <<= 1) {
877                 if (A && (section & Amask)) {
878                         dns_rr_foreach(&rr, A, .section = section) {
879                                 if ((error = dns_rr_copy(M, &rr, A)))
880                                         goto error;
881                         }
882                 }
883
884                 if (B && (section & Bmask)) {
885                         dns_rr_foreach(&rr, B, .section = section) {
886                                 copy = 1;
887
888                                 dns_rr_foreach(&mr, M, .type = rr.type, .section = DNS_S_ALL) {
889                                         if (!(copy = dns_rr_cmp(&rr, B, &mr, M)))
890                                                 break;
891                                 }
892
893                                 if (copy && (error = dns_rr_copy(M, &rr, B)))
894                                         goto error;
895                         }
896                 }
897         }
898
899         return M;
900 error:
901         free(M); M = 0;
902
903         if (error == DNS_ENOBUFS && bufsiz < 65535) {
904                 bufsiz = MIN(65535, bufsiz * 2);
905
906                 goto merge;
907         }
908
909         *error_ = error;
910
911         return 0;
912 } /* dns_p_merge() */
913
914
915 static unsigned short dns_l_skip(unsigned short, const unsigned char *, size_t);
916
917 void dns_p_dictadd(struct dns_packet *P, unsigned short dn) {
918         unsigned short lp, lptr, i;
919
920         lp      = dn;
921
922         while (lp < P->end) {
923                 if (0xc0 == (0xc0 & P->data[lp]) && P->end - lp >= 2 && lp != dn) {
924                         lptr    = ((0x3f & P->data[lp + 0]) << 8)
925                                 | ((0xff & P->data[lp + 1]) << 0);
926
927                         for (i = 0; i < lengthof(P->dict) && P->dict[i]; i++) {
928                                 if (P->dict[i] == lptr) {
929                                         P->dict[i]      = dn;
930
931                                         return;
932                                 }
933                         }
934                 }
935
936                 lp      = dns_l_skip(lp, P->data, P->end);
937         }
938
939         for (i = 0; i < lengthof(P->dict); i++) {
940                 if (!P->dict[i]) {
941                         P->dict[i]      = dn;
942
943                         break;
944                 }
945         }
946 } /* dns_p_dictadd() */
947
948
949 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) {
950         size_t end = P->end;
951         int error;
952
953         if ((error = dns_d_push(P, dn, dnlen)))
954                 goto error;
955
956         if (P->size - P->end < 4)
957                 goto nobufs;
958
959         P->data[P->end++] = 0xff & (type >> 8);
960         P->data[P->end++] = 0xff & (type >> 0);
961
962         P->data[P->end++] = 0xff & (class >> 8);
963         P->data[P->end++] = 0xff & (class >> 0);
964
965         if (section == DNS_S_QD)
966                 goto update;
967
968         if (P->size - P->end < 6)
969                 goto nobufs;
970
971         P->data[P->end++] = 0x7f & (ttl >> 24);
972         P->data[P->end++] = 0xff & (ttl >> 16);
973         P->data[P->end++] = 0xff & (ttl >> 8);
974         P->data[P->end++] = 0xff & (ttl >> 0);
975
976         if ((error = dns_any_push(P, (union dns_any *)any, type)))
977                 goto error;
978
979 update:
980         switch (section) {
981         case DNS_S_QD:
982                 if (dns_p_count(P, DNS_S_AN|DNS_S_NS|DNS_S_AR))
983                         goto order;
984
985                 if (!P->qd.base && (error = dns_p_study(P)))
986                         goto error;
987
988                 dns_header(P)->qdcount = htons(ntohs(dns_header(P)->qdcount) + 1);
989
990                 P->qd.end  = P->end;
991                 P->an.base = P->end;
992                 P->an.end  = P->end;
993                 P->ns.base = P->end;
994                 P->ns.end  = P->end;
995                 P->ar.base = P->end;
996                 P->ar.end  = P->end;
997
998                 break;
999         case DNS_S_AN:
1000                 if (dns_p_count(P, DNS_S_NS|DNS_S_AR))
1001                         goto order;
1002
1003                 if (!P->an.base && (error = dns_p_study(P)))
1004                         goto error;
1005
1006                 dns_header(P)->ancount = htons(ntohs(dns_header(P)->ancount) + 1);
1007
1008                 P->an.end  = P->end;
1009                 P->ns.base = P->end;
1010                 P->ns.end  = P->end;
1011                 P->ar.base = P->end;
1012                 P->ar.end  = P->end;
1013
1014                 break;
1015         case DNS_S_NS:
1016                 if (dns_p_count(P, DNS_S_AR))
1017                         goto order;
1018
1019                 if (!P->ns.base && (error = dns_p_study(P)))
1020                         goto error;
1021
1022                 dns_header(P)->nscount = htons(ntohs(dns_header(P)->nscount) + 1);
1023
1024                 P->ns.end  = P->end;
1025                 P->ar.base = P->end;
1026                 P->ar.end  = P->end;
1027
1028                 break;
1029         case DNS_S_AR:
1030                 if (!P->ar.base && (error = dns_p_study(P)))
1031                         goto error;
1032
1033                 dns_header(P)->arcount = htons(ntohs(dns_header(P)->arcount) + 1);
1034
1035                 P->ar.end = P->end;
1036
1037                 break;
1038         default:
1039                 error = DNS_ESECTION;
1040
1041                 goto error;
1042         } /* switch() */
1043
1044         return 0;
1045 nobufs:
1046         error = DNS_ENOBUFS;
1047
1048         goto error;
1049 order:
1050         error = DNS_EORDER;
1051
1052         goto error;
1053 error:
1054         P->end = end;
1055
1056         return error;
1057 } /* dns_p_push() */
1058
1059
1060 static void dns_p_dump3(struct dns_packet *P, struct dns_rr_i *I, FILE *fp) {
1061         enum dns_section section;
1062         struct dns_rr rr;
1063         int error;
1064         union dns_any any;
1065         char pretty[sizeof any * 2];
1066         size_t len;
1067
1068         fputs(";; [HEADER]\n", fp);
1069         fprintf(fp, ";;     qr : %s(%d)\n", (dns_header(P)->qr)? "RESPONSE" : "QUERY", dns_header(P)->qr);
1070         fprintf(fp, ";; opcode : %s(%d)\n", dns_stropcode(dns_header(P)->opcode), dns_header(P)->opcode);
1071         fprintf(fp, ";;     aa : %s(%d)\n", (dns_header(P)->aa)? "AUTHORITATIVE" : "NON-AUTHORITATIVE", dns_header(P)->aa);
1072         fprintf(fp, ";;     tc : %s(%d)\n", (dns_header(P)->tc)? "TRUNCATED" : "NOT-TRUNCATED", dns_header(P)->tc);
1073         fprintf(fp, ";;     rd : %s(%d)\n", (dns_header(P)->rd)? "RECURSION-DESIRED" : "RECURSION-NOT-DESIRED", dns_header(P)->rd);
1074         fprintf(fp, ";;     ra : %s(%d)\n", (dns_header(P)->ra)? "RECURSION-ALLOWED" : "RECURSION-NOT-ALLOWED", dns_header(P)->ra);
1075         fprintf(fp, ";;  rcode : %s(%d)\n", dns_strrcode(dns_header(P)->rcode), dns_header(P)->rcode);
1076
1077         section = 0;
1078
1079         while (dns_rr_grep(&rr, 1, I, P, &error)) {
1080                 if (section != rr.section)
1081                         fprintf(fp, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(P, rr.section));
1082
1083                 if ((len = dns_rr_print(pretty, sizeof pretty, &rr, P, &error)))
1084                         fprintf(fp, "%s\n", pretty);
1085
1086                 section = rr.section;
1087         }
1088 } /* dns_p_dump3() */
1089
1090
1091 void dns_p_dump(struct dns_packet *P, FILE *fp) {
1092         dns_p_dump3(P, dns_rr_i_new(P, .section = 0), fp);
1093 } /* dns_p_dump() */
1094
1095
1096 static void dns_s_unstudy(struct dns_s_memo *m)
1097         { m->base = 0; m->end = 0; }
1098
1099 static void dns_p_unstudy(struct dns_packet *P) {
1100         dns_s_unstudy(&P->qd);
1101         dns_s_unstudy(&P->an);
1102         dns_s_unstudy(&P->ns);
1103         dns_s_unstudy(&P->ar);
1104 } /* dns_p_unstudy() */
1105
1106 static int dns_s_study(struct dns_s_memo *m, enum dns_section section, unsigned base, struct dns_packet *P) {
1107         unsigned short count, rp;
1108
1109         count = dns_p_count(P, section);
1110
1111         for (rp = base; count && rp < P->end; count--)
1112                 rp = dns_rr_skip(rp, P);
1113
1114         m->base = base;
1115         m->end  = rp;
1116
1117         return 0;
1118 } /* dns_s_study() */
1119
1120 int dns_p_study(struct dns_packet *P) {
1121         int error;
1122
1123         if ((error = dns_s_study(&P->qd, DNS_S_QD, 12, P)))
1124                 goto error;
1125
1126         if ((error = dns_s_study(&P->an, DNS_S_AN, P->qd.end, P)))
1127                 goto error;
1128
1129         if ((error = dns_s_study(&P->ns, DNS_S_NS, P->an.end, P)))
1130                 goto error;
1131
1132         if ((error = dns_s_study(&P->ar, DNS_S_AR, P->ns.end, P)))
1133                 goto error;
1134
1135         return 0;
1136 error:
1137         dns_p_unstudy(P);
1138
1139         return error;
1140 } /* dns_p_study() */
1141
1142
1143 /*
1144  * D O M A I N  N A M E  R O U T I N E S
1145  *
1146  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1147
1148 #ifndef DNS_D_MAXPTRS
1149 #define DNS_D_MAXPTRS   127     /* Arbitrary; possible, valid depth is something like packet size / 2 + fudge. */
1150 #endif
1151
1152 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) {
1153         unsigned short len;
1154         unsigned nptrs  = 0;
1155
1156 retry:
1157         if (src >= end)
1158                 goto invalid;
1159
1160         switch (0x03 & (data[src] >> 6)) {
1161         case 0x00:
1162                 len     = (0x3f & (data[src++]));
1163
1164                 if (end - src < len)
1165                         goto invalid;
1166
1167                 if (lim > 0) {
1168                         memcpy(dst, &data[src], MIN(lim, len));
1169
1170                         dst[MIN(lim - 1, len)]  = '\0';
1171                 }
1172
1173                 *nxt    = src + len;
1174
1175                 return len;
1176         case 0x01:
1177                 goto invalid;
1178         case 0x02:
1179                 goto invalid;
1180         case 0x03:
1181                 if (++nptrs > DNS_D_MAXPTRS)
1182                         goto invalid;
1183
1184                 if (end - src < 2)
1185                         goto invalid;
1186
1187                 src     = ((0x3f & data[src + 0]) << 8)
1188                         | ((0xff & data[src + 1]) << 0);
1189
1190                 goto retry;
1191         } /* switch() */
1192
1193         /* NOT REACHED */
1194 invalid:
1195         *nxt    = end;
1196
1197         return 0;
1198 } /* dns_l_expand() */
1199
1200
1201 static unsigned short dns_l_skip(unsigned short src, const unsigned char *data, size_t end) {
1202         unsigned short len;
1203
1204         if (src >= end)
1205                 goto invalid;
1206
1207         switch (0x03 & (data[src] >> 6)) {
1208         case 0x00:
1209                 len     = (0x3f & (data[src++]));
1210
1211                 if (end - src < len)
1212                         goto invalid;
1213
1214                 return (len)? src + len : end;
1215         case 0x01:
1216                 goto invalid;
1217         case 0x02:
1218                 goto invalid;
1219         case 0x03:
1220                 return end;
1221         } /* switch() */
1222
1223         /* NOT REACHED */
1224 invalid:
1225         return end;
1226 } /* dns_l_skip() */
1227
1228
1229 size_t dns_d_trim(void *dst_, size_t lim, const void *src_, size_t len, int flags) {
1230         unsigned char *dst = dst_;
1231         const unsigned char *src = src_;
1232         size_t dp = 0, sp = 0;
1233         int lc;
1234
1235         /* trim any leading dot(s) */
1236         while (sp < len && src[sp] == '.')
1237                 sp++;
1238
1239         for (lc = 0; sp < len; lc = src[sp]) {
1240                 if (dp < lim)
1241                         dst[dp] = src[sp];
1242
1243                 sp++;
1244                 dp++;
1245
1246                 /* trim extra dot(s) */
1247                 while (sp < len && src[sp] == '.')
1248                         sp++;
1249         }
1250
1251         if ((flags & DNS_D_ANCHOR) && lc != '.') {
1252                 if (dp < lim)
1253                         dst[dp] = '.';
1254
1255                 dp++;
1256         }
1257
1258         if (lim > 0)
1259                 dst[MIN(dp, lim - 1)] = '\0';
1260
1261         return dp;
1262 } /* dns_d_trim() */
1263
1264
1265 char *dns_d_init(void *dst, size_t lim, const void *src, size_t len, int flags) {
1266         if (flags & DNS_D_TRIM) {
1267                 dns_d_trim(dst, lim, src, len, flags);
1268         } if (flags & DNS_D_ANCHOR) {
1269                 dns_d_anchor(dst, lim, src, len);
1270         } else {
1271                 memmove(dst, src, MIN(lim, len));
1272
1273                 if (lim > 0)
1274                         ((char *)dst)[MIN(len, lim - 1)]        = '\0';
1275         }
1276
1277         return dst;
1278 } /* dns_d_init() */
1279
1280
1281 size_t dns_d_anchor(void *dst, size_t lim, const void *src, size_t len) {
1282         if (len == 0)
1283                 return 0;
1284
1285         memmove(dst, src, MIN(lim, len));
1286
1287         if (((const char *)src)[len - 1] != '.') {
1288                 if (len < lim)
1289                         ((char *)dst)[len]      = '.';
1290                 len++;
1291         }
1292
1293         if (lim > 0)
1294                 ((char *)dst)[MIN(lim - 1, len)]        = '\0';
1295
1296         return len;
1297 } /* dns_d_anchor() */
1298
1299
1300 size_t dns_d_cleave(void *dst, size_t lim, const void *src, size_t len) {
1301         const char *dot;
1302
1303         /* XXX: Skip any leading dot. Handles cleaving root ".". */
1304         if (len == 0 || !(dot = memchr((const char *)src + 1, '.', len - 1)))
1305                 return 0;
1306
1307         len     -= dot - (const char *)src;
1308
1309         /* XXX: Unless root, skip the label's trailing dot. */
1310         if (len > 1) {
1311                 src     = ++dot;
1312                 len--;
1313         } else
1314                 src     = dot;
1315
1316         memmove(dst, src, MIN(lim, len));
1317
1318         if (lim > 0)
1319                 ((char *)dst)[MIN(lim - 1, len)]        = '\0';
1320
1321         return len;
1322 } /* dns_d_cleave() */
1323
1324
1325 size_t dns_d_comp(void *dst_, size_t lim, const void *src_, size_t len, struct dns_packet *P, int *error __UNUSED__) {
1326         struct { unsigned char *b; size_t p, x; } dst, src;
1327         unsigned char ch        = '.';
1328
1329         dst.b   = dst_;
1330         dst.p   = 0;
1331         dst.x   = 1;
1332
1333         src.b   = (unsigned char *)src_;
1334         src.p   = 0;
1335         src.x   = 0;
1336
1337         while (src.x < len) {
1338                 ch      = src.b[src.x];
1339
1340                 if (ch == '.') {
1341                         if (dst.p < lim)
1342                                 dst.b[dst.p]    = (0x3f & (src.x - src.p));
1343
1344                         dst.p   = dst.x++;
1345                         src.p   = ++src.x;
1346                 } else {
1347                         if (dst.x < lim)
1348                                 dst.b[dst.x]    = ch;
1349
1350                         dst.x++;
1351                         src.x++;
1352                 }
1353         } /* while() */
1354
1355         if (src.x > src.p) {
1356                 if (dst.p < lim)
1357                         dst.b[dst.p]    = (0x3f & (src.x - src.p));
1358
1359                 dst.p   = dst.x;
1360         }
1361
1362         if (dst.p > 1) {
1363                 if (dst.p < lim)
1364                         dst.b[dst.p]    = 0x00;
1365
1366                 dst.p++;
1367         }
1368
1369 #if 1
1370         if (dst.p < lim) {
1371                 struct { unsigned char label[DNS_D_MAXLABEL + 1]; size_t len; unsigned short p, x, y; } a, b;
1372                 unsigned i;
1373
1374                 a.p     = 0;
1375
1376                 while ((a.len = dns_l_expand(a.label, sizeof a.label, a.p, &a.x, dst.b, lim))) {
1377                         for (i = 0; i < lengthof(P->dict) && P->dict[i]; i++) {
1378                                 b.p     = P->dict[i];
1379
1380                                 while ((b.len = dns_l_expand(b.label, sizeof b.label, b.p, &b.x, P->data, P->end))) {
1381                                         a.y     = a.x;
1382                                         b.y     = b.x;
1383
1384                                         while (a.len && b.len && 0 == strcasecmp((char *)a.label, (char *)b.label)) {
1385                                                 a.len = dns_l_expand(a.label, sizeof a.label, a.y, &a.y, dst.b, lim);
1386                                                 b.len = dns_l_expand(b.label, sizeof b.label, b.y, &b.y, P->data, P->end);
1387                                         }
1388
1389                                         if (a.len == 0 && b.len == 0 && b.p <= 0x3fff) {
1390                                                 dst.b[a.p++]    = 0xc0
1391                                                                 | (0x3f & (b.p >> 8));
1392                                                 dst.b[a.p++]    = (0xff & (b.p >> 0));
1393
1394                                                 return a.p;
1395                                         }
1396
1397                                         b.p     = b.x;
1398                                 } /* while() */
1399                         } /* for() */
1400
1401                         a.p     = a.x;
1402                 } /* while() */
1403         } /* if () */
1404 #endif
1405
1406         return dst.p;
1407 } /* dns_d_comp() */
1408
1409
1410 unsigned short dns_d_skip(unsigned short src, struct dns_packet *P) {
1411         unsigned short len;
1412
1413         while (src < P->end) {
1414                 switch (0x03 & (P->data[src] >> 6)) {
1415                 case 0x00:      /* FOLLOWS */
1416                         len     = (0x3f & P->data[src++]);
1417
1418                         if (0 == len) {
1419 /* success ==> */               return src;
1420                         } else if (P->end - src > len) {
1421                                 src     += len;
1422
1423                                 break;
1424                         } else
1425                                 goto invalid;
1426
1427                         /* NOT REACHED */
1428                 case 0x01:      /* RESERVED */
1429                         goto invalid;
1430                 case 0x02:      /* RESERVED */
1431                         goto invalid;
1432                 case 0x03:      /* POINTER */
1433                         if (P->end - src < 2)
1434                                 goto invalid;
1435
1436                         src     += 2;
1437
1438 /* success ==> */       return src;
1439                 } /* switch() */
1440         } /* while() */
1441
1442 invalid:
1443 //assert(0);
1444         return P->end;
1445 } /* dns_d_skip() */
1446
1447
1448 #include <stdio.h>
1449
1450 size_t dns_d_expand(void *dst, size_t lim, unsigned short src, struct dns_packet *P, int *error) {
1451         size_t dstp     = 0;
1452         unsigned nptrs  = 0;
1453         unsigned char len;
1454
1455         while (src < P->end) {
1456                 switch ((0x03 & (P->data[src] >> 6))) {
1457                 case 0x00:      /* FOLLOWS */
1458                         len     = (0x3f & P->data[src]);
1459
1460                         if (0 == len) {
1461                                 if (dstp == 0) {
1462                                         if (dstp < lim)
1463                                                 ((unsigned char *)dst)[dstp]    = '.';
1464
1465                                         dstp++;
1466                                 }
1467
1468                                 /* NUL terminate */
1469                                 if (lim > 0)
1470                                         ((unsigned char *)dst)[MIN(dstp, lim - 1)]      = '\0';
1471
1472 /* success ==> */               return dstp;
1473                         }
1474
1475                         src++;
1476
1477                         if (P->end - src < len)
1478                                 goto toolong;
1479
1480                         if (dstp < lim)
1481                                 memcpy(&((unsigned char *)dst)[dstp], &P->data[src], MIN(len, lim - dstp));
1482
1483                         src     += len;
1484                         dstp    += len;
1485
1486                         if (dstp < lim)
1487                                 ((unsigned char *)dst)[dstp]    = '.';
1488
1489                         dstp++;
1490
1491                         nptrs   = 0;
1492
1493                         continue;
1494                 case 0x01:      /* RESERVED */
1495                         goto reserved;
1496                 case 0x02:      /* RESERVED */
1497                         goto reserved;
1498                 case 0x03:      /* POINTER */
1499                         if (++nptrs > DNS_D_MAXPTRS)
1500                                 goto toolong;
1501
1502                         if (P->end - src < 2)
1503                                 goto toolong;
1504
1505                         src     = ((0x3f & P->data[src + 0]) << 8)
1506                                 | ((0xff & P->data[src + 1]) << 0);
1507
1508                         continue;
1509                 } /* switch() */
1510         } /* while() */
1511
1512 toolong:
1513         *error  = DNS_EILLEGAL;
1514
1515         if (lim > 0)
1516                 ((unsigned char *)dst)[MIN(dstp, lim - 1)]      = '\0';
1517
1518         return 0;
1519 reserved:
1520         *error  = DNS_EILLEGAL;
1521
1522         if (lim > 0)
1523                 ((unsigned char *)dst)[MIN(dstp, lim - 1)]      = '\0';
1524
1525         return 0;
1526 } /* dns_d_expand() */
1527
1528
1529 int dns_d_push(struct dns_packet *P, const void *dn, size_t len) {
1530         size_t lim      = P->size - P->end;
1531         unsigned dp     = P->end;
1532         int error;
1533
1534         len     = dns_d_comp(&P->data[dp], lim, dn, len, P, &error);
1535
1536         if (len == 0)
1537                 return error;
1538         if (len > lim)
1539                 return DNS_ENOBUFS;
1540
1541         P->end  += len;
1542
1543         dns_p_dictadd(P, dp);
1544
1545         return 0;
1546 } /* dns_d_push() */
1547
1548
1549 size_t dns_d_cname(void *dst, size_t lim, const void *dn, size_t len, struct dns_packet *P, int *error_) {
1550         char host[DNS_D_MAXNAME + 1];
1551         struct dns_rr_i i;
1552         struct dns_rr rr;
1553         unsigned depth;
1554         int error;
1555
1556         if (sizeof host <= dns_d_anchor(host, sizeof host, dn, len))
1557                 { error = ENAMETOOLONG; goto error; }
1558
1559         for (depth = 0; depth < 7; depth++) {
1560                 dns_rr_i_init(memset(&i, 0, sizeof i), P);
1561
1562                 i.section       = DNS_S_ALL & ~DNS_S_QD;
1563                 i.name          = host;
1564                 i.type          = DNS_T_CNAME;
1565
1566                 if (!dns_rr_grep(&rr, 1, &i, P, &error))
1567                         break;
1568
1569                 if ((error = dns_cname_parse((struct dns_cname *)host, &rr, P)))
1570                         goto error;
1571         }
1572
1573         return dns_strlcpy(dst, host, lim);
1574 error:
1575         *error_ = error;
1576
1577         return 0;
1578 } /* dns_d_cname() */
1579
1580
1581 /*
1582  * R E S O U R C E  R E C O R D  R O U T I N E S
1583  *
1584  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1585
1586 int dns_rr_copy(struct dns_packet *P, struct dns_rr *rr, struct dns_packet *Q) {
1587         unsigned char dn[DNS_D_MAXNAME + 1];
1588         union dns_any any;
1589         size_t len;
1590         int error;
1591
1592         if (!(len = dns_d_expand(dn, sizeof dn, rr->dn.p, Q, &error)))
1593                 return error;
1594         else if (len >= sizeof dn)
1595                 return DNS_EILLEGAL;
1596
1597         if (rr->section != DNS_S_QD && (error = dns_any_parse(dns_any_init(&any, sizeof any), rr, Q)))
1598                 return error;
1599
1600         return dns_p_push(P, rr->section, dn, len, rr->type, rr->class, rr->ttl, &any);
1601 } /* dns_rr_copy() */
1602
1603
1604 int dns_rr_parse(struct dns_rr *rr, unsigned short src, struct dns_packet *P) {
1605         unsigned short p        = src;
1606
1607         if (src >= P->end)
1608                 goto invalid;
1609
1610         rr->dn.p        = p;
1611         rr->dn.len      = (p = dns_d_skip(p, P)) - rr->dn.p;
1612
1613         if (P->end - p < 4)
1614                 goto invalid;
1615
1616         rr->type        = ((0xff & P->data[p + 0]) << 8)
1617                         | ((0xff & P->data[p + 1]) << 0);
1618
1619         rr->class       = ((0xff & P->data[p + 2]) << 8)
1620                         | ((0xff & P->data[p + 3]) << 0);
1621
1622         p       += 4;
1623
1624         if (src < dns_p_qend(P)) {
1625                 rr->section     = DNS_S_QUESTION;
1626
1627                 rr->ttl         = 0;
1628                 rr->rd.p        = 0;
1629                 rr->rd.len      = 0;
1630
1631                 return 0;
1632         }
1633
1634         if (P->end - p < 4)
1635                 goto invalid;
1636
1637         rr->ttl         = ((0x7f & P->data[p + 0]) << 24)
1638                         | ((0xff & P->data[p + 1]) << 16)
1639                         | ((0xff & P->data[p + 2]) << 8)
1640                         | ((0xff & P->data[p + 3]) << 0);
1641
1642         p       += 4;
1643
1644         if (P->end - p < 2)
1645                 goto invalid;
1646
1647         rr->rd.len      = ((0xff & P->data[p + 0]) << 8)
1648                         | ((0xff & P->data[p + 1]) << 0);
1649         rr->rd.p        = p + 2;
1650
1651         p       += 2;
1652
1653         if (P->end - p < rr->rd.len)
1654                 goto invalid;
1655
1656         return 0;
1657 invalid:
1658 //assert(0);
1659         return DNS_EILLEGAL;
1660 } /* dns_rr_parse() */
1661
1662
1663 static unsigned short dns_rr_len(const unsigned short src, struct dns_packet *P) {
1664         unsigned short rp, rdlen;
1665
1666         rp      = dns_d_skip(src, P);
1667
1668         if (P->end - rp < 4)
1669                 return P->end - src;
1670
1671         rp      += 4;   /* TYPE, CLASS */
1672
1673         if (rp <= dns_p_qend(P))
1674                 return rp - src;
1675
1676         if (P->end - rp < 6)
1677                 return P->end - src;
1678
1679         rp      += 6;   /* TTL, RDLEN */
1680
1681         rdlen   = ((0xff & P->data[rp - 2]) << 8)
1682                 | ((0xff & P->data[rp - 1]) << 0);
1683
1684         if (P->end - rp < rdlen)
1685                 return P->end - src;
1686
1687         rp      += rdlen;
1688
1689         return rp - src;
1690 } /* dns_rr_len() */
1691
1692
1693 unsigned short dns_rr_skip(unsigned short src, struct dns_packet *P) {
1694         return src + dns_rr_len(src, P);
1695 } /* dns_rr_skip() */
1696
1697
1698 static enum dns_section dns_rr_section(unsigned short src, struct dns_packet *P) {
1699         enum dns_section section;
1700         unsigned count, ind;
1701         unsigned short rp;
1702
1703         if (src >= P->qd.base && src < P->qd.end)
1704                 return DNS_S_QD;
1705         if (src >= P->an.base && src < P->an.end)
1706                 return DNS_S_AN;
1707         if (src >= P->ns.base && src < P->ns.end)
1708                 return DNS_S_NS;
1709         if (src >= P->ar.base && src < P->ar.end)
1710                 return DNS_S_AR;
1711
1712         /* NOTE: Possibly bad memoization. Try it the hard-way. */
1713
1714         for (rp = 12, ind = 0; rp < src && rp < P->end; ind++)
1715                 rp = dns_rr_skip(rp, P);
1716
1717         section = DNS_S_QD;
1718         count   = dns_p_count(P, section);
1719
1720         while (ind >= count && section <= DNS_S_AR) {
1721                 section <<= 1;
1722                 count += dns_p_count(P, section);
1723         }
1724
1725         return DNS_S_ALL & section;
1726 } /* dns_rr_section() */
1727
1728
1729 static enum dns_type dns_rr_type(unsigned short src, struct dns_packet *P) {
1730         struct dns_rr rr;
1731         int error;
1732
1733         if ((error = dns_rr_parse(&rr, src, P)))
1734                 return 0;
1735
1736         return rr.type;
1737 } /* dns_rr_type() */
1738
1739
1740 int dns_rr_cmp(struct dns_rr *r0, struct dns_packet *P0, struct dns_rr *r1, struct dns_packet *P1) {
1741         char host0[DNS_D_MAXNAME + 1], host1[DNS_D_MAXNAME + 1];
1742         union dns_any any0, any1;
1743         int cmp, error;
1744         size_t len;
1745
1746         if ((cmp = r0->type - r1->type))
1747                 return cmp;
1748
1749         if ((cmp = r0->class - r1->class))
1750                 return cmp;
1751
1752         /*
1753          * FIXME: Do label-by-label comparison to handle illegally long names?
1754          */
1755
1756         if (!(len = dns_d_expand(host0, sizeof host0, r0->dn.p, P0, &error))
1757         ||  len >= sizeof host0)
1758                 return -1;
1759
1760         if (!(len = dns_d_expand(host1, sizeof host1, r1->dn.p, P1, &error))
1761         ||  len >= sizeof host1)
1762                 return 1;
1763
1764         if ((cmp = strcasecmp(host0, host1)))
1765                 return cmp;
1766
1767         if (DNS_S_QD & (r0->section | r1->section)) {
1768                 if (r0->section == r1->section)
1769                         return 0;
1770
1771                 return (r0->section == DNS_S_QD)? -1 : 1;
1772         }
1773
1774         if ((error = dns_any_parse(&any0, r0, P0)))
1775                 return -1;
1776
1777         if ((error = dns_any_parse(&any1, r1, P1)))
1778                 return 1;
1779
1780         return dns_any_cmp(&any0, r0->type, &any1, r1->type);
1781 } /* dns_rr_cmp() */
1782
1783
1784 static _Bool dns_rr_exists(struct dns_rr *rr0, struct dns_packet *P0, struct dns_packet *P1) {
1785         struct dns_rr rr1;
1786
1787         dns_rr_foreach(&rr1, P1, .section = rr0->section, .type = rr0->type) {
1788                 if (0 == dns_rr_cmp(rr0, P0, &rr1, P1))
1789                         return 1;
1790         }
1791
1792         return 0;
1793 } /* dns_rr_exists() */
1794
1795
1796 static unsigned short dns_rr_offset(struct dns_rr *rr) {
1797         return rr->dn.p;
1798 } /* dns_rr_offset() */
1799
1800
1801 static _Bool dns_rr_i_match(struct dns_rr *rr, struct dns_rr_i *i, struct dns_packet *P) {
1802         if (i->section && !(rr->section & i->section))
1803                 return 0;
1804
1805         if (i->type && rr->type != i->type && i->type != DNS_T_ALL)
1806                 return 0;
1807
1808         if (i->class && rr->class != i->class && i->class != DNS_C_ANY)
1809                 return 0;
1810
1811         if (i->name) {
1812                 char dn[DNS_D_MAXNAME + 1];
1813                 size_t len;
1814                 int error;
1815
1816                 if (!(len = dns_d_expand(dn, sizeof dn, rr->dn.p, P, &error))
1817                 ||  len >= sizeof dn)
1818                         return 0;
1819
1820                 if (0 != strcasecmp(dn, i->name))
1821                         return 0;
1822         }
1823
1824         if (i->data && i->type && rr->section > DNS_S_QD) {
1825                 union dns_any rd;
1826                 int error;
1827
1828                 if ((error = dns_any_parse(&rd, rr, P)))
1829                         return 0;
1830
1831                 if (0 != dns_any_cmp(&rd, rr->type, i->data, i->type))
1832                         return 0;
1833         }
1834
1835         return 1;
1836 } /* dns_rr_i_match() */
1837
1838
1839 static unsigned short dns_rr_i_start(struct dns_rr_i *i, struct dns_packet *P) {
1840         unsigned short rp;
1841         struct dns_rr r0, rr;
1842         int error;
1843
1844         if ((i->section & DNS_S_QD) && P->qd.base)
1845                 rp = P->qd.base;
1846         else if ((i->section & DNS_S_AN) && P->an.base)
1847                 rp = P->an.base;
1848         else if ((i->section & DNS_S_NS) && P->ns.base)
1849                 rp = P->ns.base;
1850         else if ((i->section & DNS_S_AR) && P->ar.base)
1851                 rp = P->ar.base;
1852         else
1853                 rp = 12;
1854
1855         for (rp = 12; rp < P->end; rp = dns_rr_skip(rp, P)) {
1856                 if ((error = dns_rr_parse(&rr, rp, P)))
1857                         continue;
1858
1859                 rr.section = dns_rr_section(rp, P);
1860
1861                 if (!dns_rr_i_match(&rr, i, P))
1862                         continue;
1863
1864                 r0 = rr;
1865
1866                 goto lower;
1867         }
1868
1869         return P->end;
1870 lower:
1871         if (i->sort == &dns_rr_i_packet)
1872                 return dns_rr_offset(&r0);
1873
1874         while ((rp = dns_rr_skip(rp, P)) < P->end) {
1875                 if ((error = dns_rr_parse(&rr, rp, P)))
1876                         continue;
1877
1878                 rr.section = dns_rr_section(rp, P);
1879
1880                 if (!dns_rr_i_match(&rr, i, P))
1881                         continue;
1882
1883                 if (i->sort(&rr, &r0, i, P) < 0)
1884                         r0 = rr;
1885         }
1886
1887         return dns_rr_offset(&r0);
1888 } /* dns_rr_i_start() */
1889
1890
1891 static unsigned short dns_rr_i_skip(unsigned short rp, struct dns_rr_i *i, struct dns_packet *P) {
1892         struct dns_rr r0, r1, rr;
1893         int error;
1894
1895         if ((error = dns_rr_parse(&r0, rp, P)))
1896                 return P->end;
1897
1898         r0.section = dns_rr_section(rp, P);
1899
1900         rp = (i->sort == &dns_rr_i_packet)? dns_rr_skip(rp, P) : 12;
1901
1902         for (; rp < P->end; rp = dns_rr_skip(rp, P)) {
1903                 if ((error = dns_rr_parse(&rr, rp, P)))
1904                         continue;
1905
1906                 rr.section = dns_rr_section(rp, P);
1907
1908                 if (!dns_rr_i_match(&rr, i, P))
1909                         continue;
1910
1911                 if (i->sort(&rr, &r0, i, P) <= 0)
1912                         continue;
1913
1914                 r1 = rr;
1915
1916                 goto lower;
1917         }
1918
1919         return P->end;
1920 lower:
1921         if (i->sort == &dns_rr_i_packet)
1922                 return dns_rr_offset(&r1);
1923
1924         while ((rp = dns_rr_skip(rp, P)) < P->end) {
1925                 if ((error = dns_rr_parse(&rr, rp, P)))
1926                         continue;
1927
1928                 rr.section = dns_rr_section(rp, P);
1929
1930                 if (!dns_rr_i_match(&rr, i, P))
1931                         continue;
1932
1933                 if (i->sort(&rr, &r0, i, P) <= 0)
1934                         continue;
1935
1936                 if (i->sort(&rr, &r1, i, P) >= 0)
1937                         continue;
1938
1939                 r1 = rr;
1940         }
1941
1942         return dns_rr_offset(&r1);
1943 } /* dns_rr_i_skip() */
1944
1945
1946 int dns_rr_i_packet(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i __UNUSED__, struct dns_packet *P __UNUSED__) {
1947         return (int)a->dn.p - (int)b->dn.p;
1948 } /* dns_rr_i_packet() */
1949
1950
1951 int dns_rr_i_order(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i __UNUSED__, struct dns_packet *P) {
1952         int cmp;
1953
1954         if ((cmp = a->section - b->section))
1955                 return cmp;
1956
1957         if (a->type != b->type)
1958                 return (int)a->dn.p - (int)b->dn.p;
1959
1960         return dns_rr_cmp(a, P, b, P);
1961 } /* dns_rr_i_order() */
1962
1963
1964 int dns_rr_i_shuffle(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P __UNUSED__) {
1965         int cmp;
1966
1967         while (!i->state.regs[0])
1968                 i->state.regs[0]        = dns_random();
1969
1970         if ((cmp = a->section - b->section))
1971                 return cmp;
1972
1973         return dns_k_shuffle16(a->dn.p, i->state.regs[0]) - dns_k_shuffle16(b->dn.p, i->state.regs[0]);
1974 } /* dns_rr_i_shuffle() */
1975
1976
1977 struct dns_rr_i *dns_rr_i_init(struct dns_rr_i *i, struct dns_packet *P __UNUSED__) {
1978         static const struct dns_rr_i i_initializer;
1979
1980         i->state        = i_initializer.state;
1981         i->saved        = i->state;
1982
1983         return i;
1984 } /* dns_rr_i_init() */
1985
1986
1987 unsigned dns_rr_grep(struct dns_rr *rr, unsigned lim, struct dns_rr_i *i, struct dns_packet *P, int *error_) {
1988         unsigned count  = 0;
1989         int error;
1990
1991         switch (i->state.exec) {
1992         case 0:
1993                 if (!i->sort)
1994                         i->sort = &dns_rr_i_packet;
1995
1996                 i->state.next   = dns_rr_i_start(i, P);
1997                 i->state.exec++;
1998
1999                 /* FALL THROUGH */
2000         case 1:
2001                 while (count < lim && i->state.next < P->end) {
2002                         if ((error = dns_rr_parse(rr, i->state.next, P)))
2003                                 goto error;
2004
2005                         rr->section     = dns_rr_section(i->state.next, P);
2006
2007                         rr++;
2008                         count++;
2009                         i->state.count++;
2010
2011                         i->state.next   = dns_rr_i_skip(i->state.next, i, P);
2012                 } /* while() */
2013
2014                 break;
2015         } /* switch() */
2016
2017         return count;
2018 error:
2019         *error_ = error;
2020
2021         return count;
2022 } /* dns_rr_grep() */
2023
2024
2025 static size_t dns__printchar(void *dst, size_t lim, size_t cp, unsigned char ch) {
2026         if (cp < lim)
2027                 ((unsigned char *)dst)[cp]      = ch;
2028
2029         return 1;
2030 } /* dns__printchar() */
2031
2032
2033 static size_t dns__printstring(void *dst, size_t lim, size_t cp, const void *src, size_t len) {
2034         if (cp < lim)
2035                 memcpy(&((unsigned char *)dst)[cp], src, MIN(len, lim - cp));
2036
2037         return len;
2038 } /* dns__printstring() */
2039
2040 #define dns__printstring5(a, b, c, d, e)        dns__printstring((a), (b), (c), (d), (e))
2041 #define dns__printstring4(a, b, c, d)           dns__printstring((a), (b), (c), (d), strlen((d)))
2042 #define dns__printstring(...)                   DNS_PP_CALL(DNS_PP_XPASTE(dns__printstring, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__)
2043
2044
2045 static void dns__printnul(void *dst, size_t lim, size_t off) {
2046         if (lim > 0)
2047                 ((unsigned char *)dst)[MIN(off, lim - 1)]       = '\0';
2048 } /* dns__printnul() */
2049
2050
2051 static size_t dns__print10(void *dst, size_t lim, size_t off, unsigned n, unsigned pad) {
2052         unsigned char tmp[32];
2053         unsigned dp     = off;
2054         unsigned cp     = 0;
2055         unsigned d      = 1000000000;
2056         unsigned ch;
2057
2058         pad     = MAX(1, pad);
2059         
2060         while (d) {
2061                 if ((ch = n / d) || cp > 0) {
2062                         n       -= ch * d;
2063
2064                         tmp[cp] = '0' + ch;
2065
2066                         cp++;
2067                 }
2068
2069                 d       /= 10;
2070         }
2071
2072         while (cp < pad) {
2073                 dp      += dns__printchar(dst, lim, dp, '0');
2074                 pad--;
2075         }
2076
2077         dp      += dns__printstring(dst, lim, dp, tmp, cp);
2078
2079         return dp - off;
2080 } /* dns__print10() */
2081
2082
2083 size_t dns_rr_print(void *dst, size_t lim, struct dns_rr *rr, struct dns_packet *P, int *error_) {
2084         union dns_any any;
2085         size_t cp, n, rdlen;
2086         void *rd;
2087         int error;
2088
2089         cp      = 0;
2090
2091         if (rr->section == DNS_S_QD)
2092                 cp      += dns__printchar(dst, lim, cp, ';');
2093
2094         if (!(n = dns_d_expand(&((unsigned char *)dst)[cp], (cp < lim)? lim - cp : 0, rr->dn.p, P, &error)))
2095                 goto error;
2096
2097         cp      += n;
2098
2099         if (rr->section != DNS_S_QD) {
2100                 cp      += dns__printchar(dst, lim, cp, ' ');
2101                 cp      += dns__print10(dst, lim, cp, rr->ttl, 0);
2102         }
2103
2104         cp      += dns__printchar(dst, lim, cp, ' ');
2105         cp      += dns__printstring(dst, lim, cp, dns_strclass(rr->class), strlen(dns_strclass(rr->class)));
2106         cp      += dns__printchar(dst, lim, cp, ' ');
2107         cp      += dns__printstring(dst, lim, cp, dns_strtype(rr->type), strlen(dns_strtype(rr->type)));
2108
2109         if (rr->section == DNS_S_QD)
2110                 goto epilog;
2111
2112         cp      += dns__printchar(dst, lim, cp, ' ');
2113
2114         if ((error = dns_any_parse(dns_any_init(&any, sizeof any), rr, P)))
2115                 goto error;
2116
2117         if (cp < lim) {
2118                 rd      = &((unsigned char *)dst)[cp];
2119                 rdlen   = lim - cp;
2120         } else {
2121                 rd      = 0;
2122                 rdlen   = 0;
2123         }
2124
2125         cp      += dns_any_print(rd, rdlen, &any, rr->type);
2126
2127 epilog:
2128         dns__printnul(dst, lim, cp);
2129
2130         return cp;
2131 error:
2132         *error_ = error;
2133
2134         return 0;
2135 } /* dns_rr_print() */
2136
2137
2138 int dns_a_parse(struct dns_a *a, struct dns_rr *rr, struct dns_packet *P) {
2139         unsigned long addr;
2140
2141         if (rr->rd.len != 4)
2142                 return DNS_EILLEGAL;
2143
2144         addr    = ((0xff & P->data[rr->rd.p + 0]) << 24)
2145                 | ((0xff & P->data[rr->rd.p + 1]) << 16)
2146                 | ((0xff & P->data[rr->rd.p + 2]) << 8)
2147                 | ((0xff & P->data[rr->rd.p + 3]) << 0);
2148
2149         a->addr.s_addr  = htonl(addr);
2150
2151         return 0;
2152 } /* dns_a_parse() */
2153
2154
2155 int dns_a_push(struct dns_packet *P, struct dns_a *a) {
2156         unsigned long addr;
2157
2158         if (P->size - P->end < 6)
2159                 return DNS_ENOBUFS;
2160
2161         P->data[P->end++]       = 0x00;
2162         P->data[P->end++]       = 0x04;
2163
2164         addr    = ntohl(a->addr.s_addr);
2165
2166         P->data[P->end++]       = 0xff & (addr >> 24);
2167         P->data[P->end++]       = 0xff & (addr >> 16);
2168         P->data[P->end++]       = 0xff & (addr >> 8);
2169         P->data[P->end++]       = 0xff & (addr >> 0);
2170
2171         return 0;
2172 } /* dns_a_push() */
2173
2174
2175 size_t dns_a_arpa(void *dst, size_t lim, const struct dns_a *a) {
2176         unsigned long a4        = ntohl(a->addr.s_addr);
2177         size_t cp               = 0;
2178         unsigned i;
2179
2180         for (i = 4; i > 0; i--) {
2181                 cp      += dns__print10(dst, lim, cp, (0xff & a4), 0);
2182                 cp      += dns__printchar(dst, lim, cp, '.');
2183                 a4      >>= 8;
2184         }
2185
2186         cp      += dns__printstring(dst, lim, cp, "in-addr.arpa.");
2187
2188         dns__printnul(dst, lim, cp);
2189
2190         return cp;
2191 } /* dns_a_arpa() */
2192
2193
2194 int dns_a_cmp(const struct dns_a *a, const struct dns_a *b) {
2195         if (ntohl(a->addr.s_addr) < ntohl(b->addr.s_addr))
2196                 return -1;
2197         if (ntohl(a->addr.s_addr) > ntohl(b->addr.s_addr))
2198                 return 1;
2199
2200         return 0;
2201 } /* dns_a_cmp() */
2202
2203
2204 size_t dns_a_print(void *dst, size_t lim, struct dns_a *a) {
2205         char addr[INET_ADDRSTRLEN + 1]  = "0.0.0.0";
2206         size_t len;
2207
2208         dns_inet_ntop(AF_INET, &a->addr, addr, sizeof addr);
2209
2210         dns__printnul(dst, lim, (len = dns__printstring(dst, lim, 0, addr)));
2211
2212         return len;
2213 } /* dns_a_print() */
2214
2215
2216 int dns_aaaa_parse(struct dns_aaaa *aaaa, struct dns_rr *rr, struct dns_packet *P) {
2217         if (rr->rd.len != sizeof aaaa->addr.s6_addr)
2218                 return DNS_EILLEGAL;
2219
2220         memcpy(aaaa->addr.s6_addr, &P->data[rr->rd.p], sizeof aaaa->addr.s6_addr);
2221
2222         return 0;
2223 } /* dns_aaaa_parse() */
2224
2225
2226 int dns_aaaa_push(struct dns_packet *P, struct dns_aaaa *aaaa) {
2227         if (P->size - P->end < 2 + sizeof aaaa->addr.s6_addr)
2228                 return DNS_ENOBUFS;
2229
2230         P->data[P->end++]       = 0x00;
2231         P->data[P->end++]       = 0x10;
2232
2233         memcpy(&P->data[P->end], aaaa->addr.s6_addr, sizeof aaaa->addr.s6_addr);
2234
2235         P->end  += sizeof aaaa->addr.s6_addr;
2236
2237         return 0;
2238 } /* dns_aaaa_push() */
2239
2240
2241 int dns_aaaa_cmp(const struct dns_aaaa *a, const struct dns_aaaa *b) {
2242         unsigned i;
2243         int cmp;
2244
2245         for (i = 0; i < lengthof(a->addr.s6_addr); i++) {
2246                 if ((cmp = (a->addr.s6_addr[i] - b->addr.s6_addr[i])))
2247                         return cmp;
2248         }
2249
2250         return 0;
2251 } /* dns_aaaa_cmp() */
2252
2253
2254 size_t dns_aaaa_arpa(void *dst, size_t lim, const struct dns_aaaa *aaaa) {
2255         static const unsigned char hex[16]      = "0123456789abcdef";
2256         size_t cp               = 0;
2257         unsigned nyble;
2258         int i, j;
2259
2260         for (i = sizeof aaaa->addr.s6_addr - 1; i >= 0; i--) {
2261                 nyble   = aaaa->addr.s6_addr[i];
2262
2263                 for (j = 0; j < 2; j++) {
2264                         cp      += dns__printchar(dst, lim, cp, hex[0x0f & nyble]);
2265                         cp      += dns__printchar(dst, lim, cp, '.');
2266                         nyble   >>= 4;
2267                 }
2268         }
2269
2270         cp      += dns__printstring(dst, lim, cp, "ip6.arpa.");
2271
2272         dns__printnul(dst, lim, cp);
2273
2274         return cp;
2275 } /* dns_aaaa_arpa() */
2276
2277
2278 size_t dns_aaaa_print(void *dst, size_t lim, struct dns_aaaa *aaaa) {
2279         char addr[INET6_ADDRSTRLEN + 1] = "::";
2280         size_t len;
2281
2282         dns_inet_ntop(AF_INET6, &aaaa->addr, addr, sizeof addr);
2283
2284         dns__printnul(dst, lim, (len = dns__printstring(dst, lim, 0, addr)));
2285
2286         return len;
2287 } /* dns_aaaa_print() */
2288
2289
2290 int dns_mx_parse(struct dns_mx *mx, struct dns_rr *rr, struct dns_packet *P) {
2291         size_t len;
2292         int error;
2293
2294         if (rr->rd.len < 3)
2295                 return DNS_EILLEGAL;
2296
2297         mx->preference  = (0xff00 & (P->data[rr->rd.p + 0] << 8))
2298                         | (0x00ff & (P->data[rr->rd.p + 1] << 0));
2299
2300         if (!(len = dns_d_expand(mx->host, sizeof mx->host, rr->rd.p + 2, P, &error)))
2301                 return error;
2302         else if (len >= sizeof mx->host)
2303                 return DNS_EILLEGAL;
2304
2305         return 0;
2306 } /* dns_mx_parse() */
2307
2308
2309 int dns_mx_push(struct dns_packet *P, struct dns_mx *mx) {
2310         size_t end, len;
2311         int error;
2312
2313         if (P->size - P->end < 5)
2314                 return DNS_ENOBUFS;
2315
2316         end     = P->end;
2317         P->end  += 2;
2318
2319         P->data[P->end++]       = 0xff & (mx->preference >> 8);
2320         P->data[P->end++]       = 0xff & (mx->preference >> 0);
2321
2322         if ((error = dns_d_push(P, mx->host, strlen(mx->host))))
2323                 goto error;
2324
2325         len     = P->end - end - 2;
2326
2327         P->data[end + 0]        = 0xff & (len >> 8);
2328         P->data[end + 1]        = 0xff & (len >> 0);
2329
2330         return 0;
2331 error:
2332         P->end  = end;
2333
2334         return error;
2335 } /* dns_mx_push() */
2336
2337
2338 int dns_mx_cmp(const struct dns_mx *a, const struct dns_mx *b) {
2339         int cmp;
2340
2341         if ((cmp = a->preference - b->preference))
2342                 return cmp;
2343
2344         return strcasecmp(a->host, b->host);
2345 } /* dns_mx_cmp() */
2346
2347
2348 size_t dns_mx_print(void *dst, size_t lim, struct dns_mx *mx) {
2349         size_t cp       = 0;
2350
2351         cp      += dns__print10(dst, lim, cp, mx->preference, 0);
2352         cp      += dns__printchar(dst, lim, cp, ' ');
2353         cp      += dns__printstring(dst, lim, cp, mx->host, strlen(mx->host));
2354
2355         dns__printnul(dst, lim, cp);
2356
2357         return cp;
2358 } /* dns_mx_print() */
2359
2360
2361 size_t dns_mx_cname(void *dst, size_t lim, struct dns_mx *mx) {
2362         return dns_strlcpy(dst, mx->host, lim);
2363 } /* dns_mx_cname() */
2364
2365
2366 int dns_ns_parse(struct dns_ns *ns, struct dns_rr *rr, struct dns_packet *P) {
2367         size_t len;
2368         int error;
2369
2370         if (!(len = dns_d_expand(ns->host, sizeof ns->host, rr->rd.p, P, &error)))
2371                 return error;
2372         else if (len >= sizeof ns->host)
2373                 return DNS_EILLEGAL;
2374
2375         return 0;
2376 } /* dns_ns_parse() */
2377
2378
2379 int dns_ns_push(struct dns_packet *P, struct dns_ns *ns) {
2380         size_t end, len;
2381         int error;
2382
2383         if (P->size - P->end < 3)
2384                 return DNS_ENOBUFS;
2385
2386         end     = P->end;
2387         P->end  += 2;
2388
2389         if ((error = dns_d_push(P, ns->host, strlen(ns->host))))
2390                 goto error;
2391
2392         len     = P->end - end - 2;
2393
2394         P->data[end + 0]        = 0xff & (len >> 8);
2395         P->data[end + 1]        = 0xff & (len >> 0);
2396
2397         return 0;
2398 error:
2399         P->end  = end;
2400
2401         return error;
2402 } /* dns_ns_push() */
2403
2404
2405 int dns_ns_cmp(const struct dns_ns *a, const struct dns_ns *b) {
2406         return strcasecmp(a->host, b->host);
2407 } /* dns_ns_cmp() */
2408
2409
2410 size_t dns_ns_print(void *dst, size_t lim, struct dns_ns *ns) {
2411         size_t cp;
2412
2413         cp      = dns__printstring(dst, lim, 0, ns->host, strlen(ns->host));
2414
2415         dns__printnul(dst, lim, cp);
2416
2417         return cp;
2418 } /* dns_ns_print() */
2419
2420
2421 size_t dns_ns_cname(void *dst, size_t lim, struct dns_ns *ns) {
2422         return dns_strlcpy(dst, ns->host, lim);
2423 } /* dns_ns_cname() */
2424
2425
2426 int dns_cname_parse(struct dns_cname *cname, struct dns_rr *rr, struct dns_packet *P) {
2427         return dns_ns_parse((struct dns_ns *)cname, rr, P);
2428 } /* dns_cname_parse() */
2429
2430
2431 int dns_cname_push(struct dns_packet *P, struct dns_cname *cname) {
2432         return dns_ns_push(P, (struct dns_ns *)cname);
2433 } /* dns_cname_push() */
2434
2435
2436 int dns_cname_cmp(const struct dns_cname *a, const struct dns_cname *b) {
2437         return strcasecmp(a->host, b->host);
2438 } /* dns_cname_cmp() */
2439
2440
2441 size_t dns_cname_print(void *dst, size_t lim, struct dns_cname *cname) {
2442         return dns_ns_print(dst, lim, (struct dns_ns *)cname);
2443 } /* dns_cname_print() */
2444
2445
2446 size_t dns_cname_cname(void *dst, size_t lim, struct dns_cname *cname) {
2447         return dns_strlcpy(dst, cname->host, lim);
2448 } /* dns_cname_cname() */
2449
2450
2451 int dns_soa_parse(struct dns_soa *soa, struct dns_rr *rr, struct dns_packet *P) {
2452         struct { void *dst; size_t lim; } dn[] =
2453                 { { soa->mname, sizeof soa->mname },
2454                   { soa->rname, sizeof soa->rname } };
2455         unsigned *ts[] =
2456                 { &soa->serial, &soa->refresh, &soa->retry, &soa->expire, &soa->minimum };
2457         unsigned short rp;
2458         unsigned i, j, n;
2459         int error;
2460
2461         /* MNAME / RNAME */
2462         if ((rp = rr->rd.p) >= P->end)
2463                 return DNS_EILLEGAL;
2464
2465         for (i = 0; i < lengthof(dn); i++) {
2466                 if (!(n = dns_d_expand(dn[i].dst, dn[i].lim, rp, P, &error)))
2467                         return error;
2468                 else if (n >= dn[i].lim)
2469                         return DNS_EILLEGAL;
2470
2471                 if ((rp = dns_d_skip(rp, P)) >= P->end)
2472                         return DNS_EILLEGAL;
2473         }
2474
2475         /* SERIAL / REFRESH / RETRY / EXPIRE / MINIMUM */
2476         for (i = 0; i < lengthof(ts); i++) {
2477                 for (j = 0; j < 4; j++, rp++) {
2478                         if (rp >= P->end)
2479                                 return DNS_EILLEGAL;
2480
2481                         *ts[i]  <<= 8;
2482                         *ts[i]  |= (0xff & P->data[rp]);
2483                 }
2484         }
2485
2486         return 0;
2487 } /* dns_soa_parse() */
2488
2489
2490 int dns_soa_push(struct dns_packet *P, struct dns_soa *soa) {
2491         void *dn[]      = { soa->mname, soa->rname };
2492         unsigned ts[]   = { (0xffffffff & soa->serial),
2493                             (0x7fffffff & soa->refresh),
2494                             (0x7fffffff & soa->retry),
2495                             (0x7fffffff & soa->expire),
2496                             (0xffffffff & soa->minimum) };
2497         unsigned i, j;
2498         size_t end, len;
2499         int error;
2500
2501         end     = P->end;
2502
2503         if ((P->end += 2) >= P->size)
2504                 goto toolong;
2505
2506         /* MNAME / RNAME */
2507         for (i = 0; i < lengthof(dn); i++) {
2508                 if ((error = dns_d_push(P, dn[i], strlen(dn[i]))))
2509                         goto error;
2510         }
2511
2512         /* SERIAL / REFRESH / RETRY / EXPIRE / MINIMUM */
2513         for (i = 0; i < lengthof(ts); i++) {
2514                 if ((P->end += 4) >= P->size)
2515                         goto toolong;
2516
2517                 for (j = 1; j <= 4; j++) {
2518                         P->data[P->end - j]     = (0xff & ts[i]);
2519                         ts[i]                   >>= 8;
2520                 }
2521         }
2522
2523         len                     = P->end - end - 2;
2524         P->data[end + 0]        = (0xff & (len >> 8));
2525         P->data[end + 1]        = (0xff & (len >> 0));
2526
2527         return 0;
2528 toolong:
2529         error   = DNS_ENOBUFS;
2530
2531         /* FALL THROUGH */
2532 error:
2533         P->end  = end;
2534
2535         return error;
2536 } /* dns_soa_push() */
2537
2538
2539 int dns_soa_cmp(const struct dns_soa *a, const struct dns_soa *b) {
2540         int cmp;
2541         
2542         if ((cmp = strcasecmp(a->mname, b->mname)))
2543                 return cmp;
2544
2545         if ((cmp = strcasecmp(a->rname, b->rname)))
2546                 return cmp;
2547
2548         if (a->serial > b->serial)
2549                 return -1;
2550         else if (a->serial < b->serial)
2551                 return 1;
2552
2553         if (a->refresh > b->refresh)
2554                 return -1;
2555         else if (a->refresh < b->refresh)
2556                 return 1;
2557
2558         if (a->retry > b->retry)
2559                 return -1;
2560         else if (a->retry < b->retry)
2561                 return 1;
2562
2563         if (a->expire > b->expire)
2564                 return -1;
2565         else if (a->expire < b->expire)
2566                 return 1;
2567
2568         if (a->minimum > b->minimum)
2569                 return -1;
2570         else if (a->minimum < b->minimum)
2571                 return 1;
2572
2573         return 0;
2574 } /* dns_soa_cmp() */
2575
2576
2577 size_t dns_soa_print(void *dst, size_t lim, struct dns_soa *soa) {
2578         size_t cp       = 0;
2579
2580         cp      += dns__printstring(dst, lim, cp, soa->mname, strlen(soa->mname));
2581         cp      += dns__printchar(dst, lim, cp, ' ');
2582         cp      += dns__printstring(dst, lim, cp, soa->rname, strlen(soa->rname));
2583         cp      += dns__printchar(dst, lim, cp, ' ');
2584         cp      += dns__print10(dst, lim, cp, soa->serial, 0);
2585         cp      += dns__printchar(dst, lim, cp, ' ');
2586         cp      += dns__print10(dst, lim, cp, soa->refresh, 0);
2587         cp      += dns__printchar(dst, lim, cp, ' ');
2588         cp      += dns__print10(dst, lim, cp, soa->retry, 0);
2589         cp      += dns__printchar(dst, lim, cp, ' ');
2590         cp      += dns__print10(dst, lim, cp, soa->expire, 0);
2591         cp      += dns__printchar(dst, lim, cp, ' ');
2592         cp      += dns__print10(dst, lim, cp, soa->minimum, 0);
2593
2594         dns__printnul(dst, lim, cp);
2595
2596         return cp;
2597 } /* dns_soa_print() */
2598
2599
2600 int dns_srv_parse(struct dns_srv *srv, struct dns_rr *rr, struct dns_packet *P) {
2601         unsigned short rp;
2602         unsigned i;
2603         size_t n;
2604         int error;
2605
2606         memset(srv, '\0', sizeof *srv);
2607
2608         rp      = rr->rd.p;
2609
2610         if (P->size - P->end < 6)
2611                 return DNS_EILLEGAL;
2612
2613         for (i = 0; i < 2; i++, rp++) {
2614                 srv->priority   <<= 8;
2615                 srv->priority   |= (0xff & P->data[rp]);
2616         }
2617
2618         for (i = 0; i < 2; i++, rp++) {
2619                 srv->weight     <<= 8;
2620                 srv->weight     |= (0xff & P->data[rp]);
2621         }
2622
2623         for (i = 0; i < 2; i++, rp++) {
2624                 srv->port       <<= 8;
2625                 srv->port       |= (0xff & P->data[rp]);
2626         }
2627
2628         if (!(n = dns_d_expand(srv->target, sizeof srv->target, rp, P, &error)))
2629                 return error;
2630         else if (n >= sizeof srv->target)
2631                 return DNS_EILLEGAL;
2632
2633         return 0;
2634 } /* dns_srv_parse() */
2635
2636
2637 int dns_srv_push(struct dns_packet *P, struct dns_srv *srv) {
2638         size_t end, len;
2639         int error;
2640
2641         end     = P->end;
2642
2643         if (P->size - P->end < 2)
2644                 goto toolong;
2645
2646         P->end  += 2;
2647
2648         if (P->size - P->end < 6)
2649                 goto toolong;
2650
2651         P->data[P->end++]       = 0xff & (srv->priority >> 8);
2652         P->data[P->end++]       = 0xff & (srv->priority >> 0);
2653
2654         P->data[P->end++]       = 0xff & (srv->weight >> 8);
2655         P->data[P->end++]       = 0xff & (srv->weight >> 0);
2656
2657         P->data[P->end++]       = 0xff & (srv->port >> 8);
2658         P->data[P->end++]       = 0xff & (srv->port >> 0);
2659
2660         if (0 == (len = dns_d_comp(&P->data[P->end], P->size - P->end, srv->target, strlen(srv->target), P, &error)))
2661                 goto error;
2662         else if (P->size - P->end < len)
2663                 goto toolong;
2664
2665         P->end  += len;
2666
2667         if (P->end > 65535)
2668                 goto toolong;
2669
2670         len     = P->end - end - 2;
2671
2672         P->data[end + 0]        = 0xff & (len >> 8);
2673         P->data[end + 1]        = 0xff & (len >> 0);
2674
2675         return 0;
2676 toolong:
2677         error   = DNS_ENOBUFS;
2678
2679         /* FALL THROUGH */
2680 error:
2681         P->end  = end;
2682
2683         return error;
2684 } /* dns_srv_push() */
2685
2686
2687 int dns_srv_cmp(const struct dns_srv *a, const struct dns_srv *b) {
2688         int cmp;
2689         
2690         if ((cmp = a->priority - b->priority))
2691                 return cmp;
2692
2693         /*
2694          * FIXME: We need some sort of random seed to implement the dynamic
2695          * weighting required by RFC 2782.
2696          */
2697         if ((cmp = a->weight - b->weight))
2698                 return cmp;
2699
2700         if ((cmp = a->port - b->port))
2701                 return cmp;
2702
2703         return strcasecmp(a->target, b->target);
2704 } /* dns_srv_cmp() */
2705
2706
2707 size_t dns_srv_print(void *dst, size_t lim, struct dns_srv *srv) {
2708         size_t cp       = 0;
2709
2710         cp      += dns__print10(dst, lim, cp, srv->priority, 0);
2711         cp      += dns__printchar(dst, lim, cp, ' ');
2712         cp      += dns__print10(dst, lim, cp, srv->weight, 0);
2713         cp      += dns__printchar(dst, lim, cp, ' ');
2714         cp      += dns__print10(dst, lim, cp, srv->port, 0);
2715         cp      += dns__printchar(dst, lim, cp, ' ');
2716         cp      += dns__printstring(dst, lim, cp, srv->target, strlen(srv->target));
2717
2718         dns__printnul(dst, lim, cp);
2719
2720         return cp;
2721 } /* dns_srv_print() */
2722
2723
2724 size_t dns_srv_cname(void *dst, size_t lim, struct dns_srv *srv) {
2725         return dns_strlcpy(dst, srv->target, lim);
2726 } /* dns_srv_cname() */
2727
2728
2729 int dns_ptr_parse(struct dns_ptr *ptr, struct dns_rr *rr, struct dns_packet *P) {
2730         return dns_ns_parse((struct dns_ns *)ptr, rr, P);
2731 } /* dns_ptr_parse() */
2732
2733
2734 int dns_ptr_push(struct dns_packet *P, struct dns_ptr *ptr) {
2735         return dns_ns_push(P, (struct dns_ns *)ptr);
2736 } /* dns_ptr_push() */
2737
2738
2739 size_t dns_ptr_qname(void *dst, size_t lim, int af, void *addr) {
2740         unsigned len    = (af == AF_INET6)
2741                         ? dns_aaaa_arpa(dst, lim, addr)
2742                         : dns_a_arpa(dst, lim, addr);
2743
2744         dns__printnul(dst, lim, len);
2745
2746         return len;
2747 } /* dns_ptr_qname() */
2748
2749
2750 int dns_ptr_cmp(const struct dns_ptr *a, const struct dns_ptr *b) {
2751         return strcasecmp(a->host, b->host);
2752 } /* dns_ptr_cmp() */
2753
2754
2755 size_t dns_ptr_print(void *dst, size_t lim, struct dns_ptr *ptr) {
2756         return dns_ns_print(dst, lim, (struct dns_ns *)ptr);
2757 } /* dns_ptr_print() */
2758
2759
2760 size_t dns_ptr_cname(void *dst, size_t lim, struct dns_ptr *ptr) {
2761         return dns_strlcpy(dst, ptr->host, lim);
2762 } /* dns_ptr_cname() */
2763
2764
2765 int dns_sshfp_parse(struct dns_sshfp *fp, struct dns_rr *rr, struct dns_packet *P) {
2766         unsigned p = rr->rd.p, pe = rr->rd.p + rr->rd.len;
2767
2768         if (pe - p < 2)
2769                 return DNS_EILLEGAL;
2770
2771         fp->algo = P->data[p++];
2772         fp->type = P->data[p++];
2773
2774         switch (fp->type) {
2775         case DNS_SSHFP_SHA1:
2776                 if (pe - p < sizeof fp->digest.sha1)
2777                         return DNS_EILLEGAL;
2778
2779                 memcpy(fp->digest.sha1, &P->data[p], sizeof fp->digest.sha1);
2780
2781                 break;
2782         default:
2783                 break;
2784         } /* switch() */
2785
2786         return 0;
2787 } /* dns_sshfp_parse() */
2788
2789
2790 int dns_sshfp_push(struct dns_packet *P, struct dns_sshfp *fp) {
2791         unsigned p = P->end, pe = P->size, n;
2792
2793         if (pe - p < 4)
2794                 return DNS_ENOBUFS;
2795
2796         p += 2;
2797         P->data[p++] = 0xff & fp->algo;
2798         P->data[p++] = 0xff & fp->type;
2799
2800         switch (fp->type) {
2801         case DNS_SSHFP_SHA1:
2802                 if (pe - p < sizeof fp->digest.sha1)
2803                         return DNS_ENOBUFS;
2804
2805                 memcpy(&P->data[p], fp->digest.sha1, sizeof fp->digest.sha1);
2806                 p += sizeof fp->digest.sha1;
2807
2808                 break;
2809         default:
2810                 return DNS_EILLEGAL;
2811         } /* switch() */
2812
2813         n = p - P->end - 2;
2814         P->data[P->end++] = 0xff & (n >> 8);
2815         P->data[P->end++] = 0xff & (n >> 0);
2816         P->end = p;
2817
2818         return 0;
2819 } /* dns_sshfp_push() */
2820
2821
2822 int dns_sshfp_cmp(const struct dns_sshfp *a, const struct dns_sshfp *b) {
2823         int cmp;
2824
2825         if ((cmp = a->algo - b->algo) || (cmp - a->type - b->type))
2826                 return cmp;
2827
2828         switch (a->type) {
2829         case DNS_SSHFP_SHA1:
2830                 return memcmp(a->digest.sha1, b->digest.sha1, sizeof a->digest.sha1);
2831         default:
2832                 return 0;
2833         } /* switch() */
2834
2835         /* NOT REACHED */
2836 } /* dns_sshfp_cmp() */
2837
2838
2839 size_t dns_sshfp_print(void *dst, size_t lim, struct dns_sshfp *fp) {
2840         static const unsigned char hex[16] = "0123456789abcdef";
2841         size_t i, p = 0;
2842
2843         p += dns__print10(dst, lim, p, fp->algo, 0);
2844         p += dns__printchar(dst, lim, p, ' ');
2845         p += dns__print10(dst, lim, p, fp->type, 0);
2846         p += dns__printchar(dst, lim, p, ' ');
2847
2848         switch (fp->type) {
2849         case DNS_SSHFP_SHA1:
2850                 for (i = 0; i < sizeof fp->digest.sha1; i++) {
2851                         p += dns__printchar(dst, lim, p, hex[0x0f & (fp->digest.sha1[i] >> 4)]);
2852                         p += dns__printchar(dst, lim, p, hex[0x0f & (fp->digest.sha1[i] >> 0)]);
2853                 }
2854
2855                 break;
2856         default:
2857                 p += dns__printchar(dst, lim, p, '0');
2858
2859                 break;
2860         } /* switch() */
2861
2862         dns__printnul(dst, lim, p);
2863
2864         return p;
2865 } /* dns_sshfp_print() */
2866
2867
2868 struct dns_txt *dns_txt_init(struct dns_txt *txt, size_t size) {
2869         assert(size > offsetof(struct dns_txt, data));
2870
2871         txt->size       = size - offsetof(struct dns_txt, data);
2872         txt->len        = 0;
2873
2874         return txt;
2875 } /* dns_txt_init() */
2876
2877
2878 int dns_txt_parse(struct dns_txt *txt, struct dns_rr *rr, struct dns_packet *P) {
2879         struct { unsigned char *b; size_t p, end; } dst, src;
2880         unsigned n;
2881
2882         dst.b   = txt->data;
2883         dst.p   = 0;
2884         dst.end = txt->size;
2885
2886         src.b   = P->data;
2887         src.p   = rr->rd.p;
2888         src.end = src.p + rr->rd.len;
2889
2890         while (src.p < src.end) {
2891                 n       = 0xff & P->data[src.p++];
2892
2893                 if (src.end - src.p < n || dst.end - dst.p < n)
2894                         return DNS_EILLEGAL;
2895
2896                 memcpy(&dst.b[dst.p], &src.b[src.p], n);
2897
2898                 dst.p   += n;
2899                 src.p   += n;
2900         }
2901
2902         txt->len        = dst.p;
2903
2904         return 0;
2905 } /* dns_txt_parse() */
2906
2907
2908 int dns_txt_push(struct dns_packet *P, struct dns_txt *txt) {
2909         struct { unsigned char *b; size_t p, end; } dst, src;
2910         unsigned n;
2911
2912         dst.b   = P->data;
2913         dst.p   = P->end;
2914         dst.end = P->size;
2915
2916         src.b   = txt->data;
2917         src.p   = 0;
2918         src.end = txt->len;
2919
2920         if (dst.end - dst.p < 2)
2921                 return DNS_ENOBUFS;
2922
2923         n       = txt->len + ((txt->len + 254) / 255);
2924
2925         dst.b[dst.p++]  = 0xff & (n >> 8);
2926         dst.b[dst.p++]  = 0xff & (n >> 0);
2927
2928         while (src.p < src.end) {
2929                 n       = MIN(255, src.end - src.p);
2930
2931                 if (dst.p >= dst.end)
2932                         return DNS_ENOBUFS;
2933
2934                 dst.b[dst.p++]  = n;
2935
2936                 if (dst.end - dst.p < n)
2937                         return DNS_ENOBUFS;
2938
2939                 memcpy(&dst.b[dst.p], &src.b[src.p], n);
2940
2941                 dst.p   += n;
2942                 src.p   += n;
2943         }
2944
2945         P->end  = dst.p;
2946
2947         return 0;
2948 } /* dns_txt_push() */
2949
2950
2951 int dns_txt_cmp(const struct dns_txt *a __UNUSED__, const struct dns_txt *b __UNUSED__) {
2952         return -1;
2953 } /* dns_txt_cmp() */
2954
2955
2956 size_t dns_txt_print(void *dst_, size_t lim, struct dns_txt *txt) {
2957         struct { unsigned char *b; size_t p, end; } dst, src;
2958         unsigned ch;
2959
2960         dst.b   = dst_;
2961         dst.end = lim;
2962         dst.p   = 0;
2963
2964         src.b   = txt->data;
2965         src.end = txt->len;
2966         src.p   = 0;
2967
2968         dst.p   += dns__printchar(dst.b, dst.end, dst.p, '"');
2969
2970         while (src.p < src.end) {
2971                 ch      = src.b[src.p];
2972
2973                 if (0 == (src.p++ % 255) && src.p != 1) {
2974                         dst.p   += dns__printchar(dst.b, dst.end, dst.p, '"');
2975                         dst.p   += dns__printchar(dst.b, dst.end, dst.p, ' ');
2976                         dst.p   += dns__printchar(dst.b, dst.end, dst.p, '"');
2977                 }
2978
2979                 if (ch < 32 || ch > 126 || ch == '"' || ch == '\\') {
2980                         dst.p   += dns__printchar(dst.b, dst.end, dst.p, '\\');
2981                         dst.p   += dns__print10(dst.b, dst.end, dst.p, ch, 3);
2982                 } else {
2983                         dst.p   += dns__printchar(dst.b, dst.end, dst.p, ch);
2984                 }
2985         }
2986
2987         dst.p   += dns__printchar(dst.b, dst.end, dst.p, '"');
2988
2989         dns__printnul(dst.b, dst.end, dst.p);
2990
2991         return dst.p;
2992 } /* dns_txt_print() */
2993
2994
2995 static const struct {
2996         enum dns_type type;
2997         const char *name;
2998         int (*parse)();
2999         int (*push)();
3000         int (*cmp)();
3001         size_t (*print)();
3002         size_t (*cname)();
3003 } dns_rrtypes[] = {
3004         { DNS_T_A,      "A",      &dns_a_parse,      &dns_a_push,      &dns_a_cmp,      &dns_a_print,      0                },
3005         { DNS_T_AAAA,   "AAAA",   &dns_aaaa_parse,   &dns_aaaa_push,   &dns_aaaa_cmp,   &dns_aaaa_print,   0                },
3006         { DNS_T_MX,     "MX",     &dns_mx_parse,     &dns_mx_push,     &dns_mx_cmp,     &dns_mx_print,     &dns_mx_cname    },
3007         { DNS_T_NS,     "NS",     &dns_ns_parse,     &dns_ns_push,     &dns_ns_cmp,     &dns_ns_print,     &dns_ns_cname    },
3008         { DNS_T_CNAME,  "CNAME",  &dns_cname_parse,  &dns_cname_push,  &dns_cname_cmp,  &dns_cname_print,  &dns_cname_cname },
3009         { DNS_T_SOA,    "SOA",    &dns_soa_parse,    &dns_soa_push,    &dns_soa_cmp,    &dns_soa_print,    0                },
3010         { DNS_T_SRV,    "SRV",    &dns_srv_parse,    &dns_srv_push,    &dns_srv_cmp,    &dns_srv_print,    &dns_srv_cname   },
3011         { DNS_T_PTR,    "PTR",    &dns_ptr_parse,    &dns_ptr_push,    &dns_ptr_cmp,    &dns_ptr_print,    &dns_ptr_cname   },
3012         { DNS_T_TXT,    "TXT",    &dns_txt_parse,    &dns_txt_push,    &dns_txt_cmp,    &dns_txt_print,    0                },
3013         { DNS_T_SPF,    "SPF",    &dns_txt_parse,    &dns_txt_push,    &dns_txt_cmp,    &dns_txt_print,    0                },
3014         { DNS_T_SSHFP,  "SSHFP",  &dns_sshfp_parse,  &dns_sshfp_push,  &dns_sshfp_cmp,  &dns_sshfp_print,  0                },
3015 }; /* dns_rrtypes[] */
3016
3017
3018 union dns_any *dns_any_init(union dns_any *any, size_t size) {
3019         return (union dns_any *)dns_txt_init(&any->rdata, size);
3020 } /* dns_any_init() */
3021
3022
3023 int dns_any_parse(union dns_any *any, struct dns_rr *rr, struct dns_packet *P) {
3024         unsigned i;
3025
3026         for (i = 0; i < lengthof(dns_rrtypes); i++) {
3027                 if (dns_rrtypes[i].type == rr->type)
3028                         return dns_rrtypes[i].parse(any, rr, P);
3029         }
3030
3031         if (rr->rd.len > any->rdata.size)
3032                 return DNS_EILLEGAL;
3033
3034         memcpy(any->rdata.data, &P->data[rr->rd.p], rr->rd.len);
3035         any->rdata.len  = rr->rd.len;
3036
3037         return 0;
3038 } /* dns_any_parse() */
3039
3040
3041 int dns_any_push(struct dns_packet *P, union dns_any *any, enum dns_type type) {
3042         unsigned i;
3043
3044         for (i = 0; i < lengthof(dns_rrtypes); i++) {
3045                 if (dns_rrtypes[i].type == type)
3046                         return dns_rrtypes[i].push(P, any);
3047         }
3048
3049         if (P->size - P->end < any->rdata.len + 2)
3050                 return DNS_ENOBUFS;
3051
3052         P->data[P->end++]       = 0xff & (any->rdata.len >> 8);
3053         P->data[P->end++]       = 0xff & (any->rdata.len >> 0);
3054
3055         memcpy(&P->data[P->end], any->rdata.data, any->rdata.len);
3056         P->end  += any->rdata.len;
3057
3058         return 0;
3059 } /* dns_any_push() */
3060
3061
3062 int dns_any_cmp(const union dns_any *a, enum dns_type x, const union dns_any *b, enum dns_type y) {
3063         unsigned i;
3064         int cmp;
3065
3066         if ((cmp = x - y))
3067                 return cmp;
3068
3069         for (i = 0; i < lengthof(dns_rrtypes); i++) {
3070                 if (dns_rrtypes[i].type == x)
3071                         return dns_rrtypes[i].cmp(a, b);
3072         }
3073
3074         return -1;
3075 } /* dns_any_cmp() */
3076
3077
3078 size_t dns_any_print(void *dst_, size_t lim, union dns_any *any, enum dns_type type) {
3079         struct { unsigned char *b; size_t p, end; } dst, src;
3080         unsigned i, ch;
3081
3082         for (i = 0; i < lengthof(dns_rrtypes); i++) {
3083                 if (dns_rrtypes[i].type == type)
3084                         return dns_rrtypes[i].print(dst_, lim, any);
3085         }
3086
3087         dst.b   = dst_;
3088         dst.end = lim;
3089         dst.p   = 0;
3090
3091         src.b   = any->rdata.data;
3092         src.end = any->rdata.len;
3093         src.p   = 0;
3094
3095         dst.p   += dns__printchar(dst.b, dst.end, dst.p, '"');
3096
3097         while (src.p < src.end) {
3098                 ch      = src.b[src.p++];
3099
3100                 dst.p   += dns__printchar(dst.b, dst.end, dst.p, '\\');
3101                 dst.p   += dns__print10(dst.b, dst.end, dst.p, ch, 3);
3102         }
3103
3104         dst.p   += dns__printchar(dst.b, dst.end, dst.p, '"');
3105
3106         dns__printnul(dst.b, dst.end, dst.p);
3107
3108         return dst.p;
3109 } /* dns_any_print() */
3110
3111
3112 size_t dns_any_cname(void *dst, size_t lim, union dns_any *any, enum dns_type type) {
3113         unsigned i;
3114
3115         for (i = 0; i < lengthof(dns_rrtypes); i++) {
3116                 if (dns_rrtypes[i].type == type)
3117                         return (dns_rrtypes[i].cname)? dns_rrtypes[i].cname(dst, lim, any) : 0;
3118         }
3119
3120         return 0;
3121 } /* dns_any_cname() */
3122
3123
3124 /*
3125  * H O S T S  R O U T I N E S
3126  *
3127  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3128
3129 struct dns_hosts {
3130         struct dns_hosts_entry {
3131                 char host[DNS_D_MAXNAME + 1];
3132                 char arpa[73 + 1];
3133
3134                 int af;
3135
3136                 union {
3137                         struct in_addr a4;
3138                         struct in6_addr a6;
3139                 } addr;
3140
3141                 _Bool alias;
3142
3143                 struct dns_hosts_entry *next;
3144         } *head, **tail;
3145
3146         dns_atomic_t refcount;
3147 }; /* struct dns_hosts */
3148
3149
3150 struct dns_hosts *dns_hosts_open(int *error) {
3151         static const struct dns_hosts hosts_initializer = { .refcount = 1 };
3152         struct dns_hosts *hosts;
3153
3154         if (!(hosts = malloc(sizeof *hosts)))
3155                 goto syerr;
3156
3157         *hosts  = hosts_initializer;
3158
3159         hosts->tail     = &hosts->head;
3160
3161         return hosts;
3162 syerr:
3163         *error  = dns_syerr();
3164
3165         free(hosts);
3166
3167         return 0;
3168 } /* dns_hosts_open() */
3169
3170
3171 void dns_hosts_close(struct dns_hosts *hosts) {
3172         struct dns_hosts_entry *ent, *xnt;
3173
3174         if (!hosts || 1 != dns_hosts_release(hosts))
3175                 return;
3176
3177         for (ent = hosts->head; ent; ent = xnt) {
3178                 xnt     = ent->next;
3179
3180                 free(ent);
3181         }
3182
3183         free(hosts);
3184
3185         return;
3186 } /* dns_hosts_close() */
3187
3188
3189 unsigned dns_hosts_acquire(struct dns_hosts *hosts) {
3190         return dns_atomic_inc(&hosts->refcount);
3191 } /* dns_hosts_acquire() */
3192
3193
3194 unsigned dns_hosts_release(struct dns_hosts *hosts) {
3195         return dns_atomic_dec(&hosts->refcount);
3196 } /* dns_hosts_release() */
3197
3198
3199 struct dns_hosts *dns_hosts_mortal(struct dns_hosts *hosts) {
3200         if (hosts)
3201                 dns_hosts_release(hosts);
3202
3203         return hosts;
3204 } /* dns_hosts_mortal() */
3205
3206
3207 struct dns_hosts *dns_hosts_local(int *error_) {
3208         struct dns_hosts *hosts;
3209         int error;
3210
3211         if (!(hosts = dns_hosts_open(&error)))
3212                 goto error;
3213                 
3214         if ((error = dns_hosts_loadpath(hosts, "/etc/hosts")))
3215                 goto error;
3216
3217         return hosts;
3218 error:
3219         *error_ = error;
3220
3221         dns_hosts_close(hosts);
3222
3223         return 0;
3224 } /* dns_hosts_local() */
3225
3226
3227 #define dns_hosts_issep(ch)     (isspace(ch))
3228 #define dns_hosts_iscom(ch)     ((ch) == '#' || (ch) == ';')
3229
3230 int dns_hosts_loadfile(struct dns_hosts *hosts, FILE *fp) {
3231         struct dns_hosts_entry ent;
3232         char word[MAX(INET6_ADDRSTRLEN, DNS_D_MAXNAME) + 1];
3233         unsigned wp, wc, skip;
3234         int ch, error;
3235
3236         rewind(fp);
3237
3238         do {
3239                 memset(&ent, '\0', sizeof ent);
3240                 wc      = 0;
3241                 skip    = 0;
3242
3243                 do {
3244                         memset(word, '\0', sizeof word);
3245                         wp      = 0;
3246
3247                         while (EOF != (ch = fgetc(fp)) && ch != '\n') {
3248                                 skip    |= !!dns_hosts_iscom(ch);
3249
3250                                 if (skip)
3251                                         continue;
3252
3253                                 if (dns_hosts_issep(ch))
3254                                         break;
3255
3256                                 if (wp < sizeof word - 1)
3257                                         word[wp]        = ch;
3258                                 wp++;
3259                         }
3260
3261                         if (!wp)
3262                                 continue;
3263
3264                         wc++;
3265
3266                         switch (wc) {
3267                         case 0:
3268                                 break;
3269                         case 1:
3270                                 ent.af  = (strchr(word, ':'))? AF_INET6 : AF_INET;
3271                                 skip    = (1 != dns_inet_pton(ent.af, word, &ent.addr));
3272
3273                                 break;
3274                         default:
3275                                 if (!wp)
3276                                         break;
3277
3278                                 dns_d_anchor(ent.host, sizeof ent.host, word, wp);
3279
3280                                 if ((error = dns_hosts_insert(hosts, ent.af, &ent.addr, ent.host, (wc > 2))))
3281                                         return error;
3282
3283                                 break;
3284                         } /* switch() */
3285                 } while (ch != EOF && ch != '\n');
3286         } while (ch != EOF);
3287
3288         return 0;
3289 } /* dns_hosts_loadfile() */
3290
3291
3292 int dns_hosts_loadpath(struct dns_hosts *hosts, const char *path) {
3293         FILE *fp;
3294         int error;
3295
3296         if (!(fp = fopen(path, "r")))
3297                 return dns_syerr();
3298
3299         error   = dns_hosts_loadfile(hosts, fp);
3300
3301         fclose(fp);
3302
3303         return error;
3304 } /* dns_hosts_loadpath() */
3305
3306
3307 int dns_hosts_dump(struct dns_hosts *hosts, FILE *fp) {
3308         struct dns_hosts_entry *ent, *xnt;
3309         char addr[INET6_ADDRSTRLEN + 1];
3310         unsigned i;
3311
3312         for (ent = hosts->head; ent; ent = xnt) {
3313                 xnt     = ent->next;
3314
3315                 dns_inet_ntop(ent->af, &ent->addr, addr, sizeof addr);
3316
3317                 fputs(addr, fp);
3318
3319                 for (i = strlen(addr); i < INET_ADDRSTRLEN; i++)
3320                         fputc(' ', fp);
3321
3322                 fputc(' ', fp);
3323
3324                 fputs(ent->host, fp);
3325                 fputc('\n', fp);
3326         }
3327
3328         return 0;
3329 } /* dns_hosts_dump() */
3330
3331
3332 int dns_hosts_insert(struct dns_hosts *hosts, int af, const void *addr, const void *host, _Bool alias) {
3333         struct dns_hosts_entry *ent;
3334         int error;
3335
3336         if (!(ent = malloc(sizeof *ent)))
3337                 goto syerr;
3338
3339         dns_d_anchor(ent->host, sizeof ent->host, host, strlen(host));
3340
3341         switch ((ent->af = af)) {
3342         case AF_INET6:
3343                 memcpy(&ent->addr.a6, addr, sizeof ent->addr.a6);
3344
3345                 dns_aaaa_arpa(ent->arpa, sizeof ent->arpa, addr);
3346
3347                 break;
3348         case AF_INET:
3349                 memcpy(&ent->addr.a4, addr, sizeof ent->addr.a4);
3350
3351                 dns_a_arpa(ent->arpa, sizeof ent->arpa, addr);
3352
3353                 break;
3354         default:
3355                 error   = EINVAL;
3356
3357                 goto error;
3358         } /* switch() */
3359
3360         ent->alias      = alias;
3361
3362         ent->next       = 0;
3363         *hosts->tail    = ent;
3364         hosts->tail     = &ent->next;
3365
3366         return 0;
3367 syerr:
3368         error   = dns_syerr();
3369 error:
3370         free(ent);
3371
3372         return error;
3373 } /* dns_hosts_insert() */
3374
3375
3376 struct dns_packet *dns_hosts_query(struct dns_hosts *hosts, struct dns_packet *Q, int *error_) {
3377         struct dns_packet *P    = dns_p_new(512);
3378         struct dns_packet *A    = 0;
3379         struct dns_rr rr;
3380         struct dns_hosts_entry *ent;
3381         int error, af;
3382         char qname[DNS_D_MAXNAME + 1];
3383         size_t qlen;
3384
3385         if ((error = dns_rr_parse(&rr, 12, Q)))
3386                 goto error;
3387
3388         if (!(qlen = dns_d_expand(qname, sizeof qname, rr.dn.p, Q, &error)))
3389                 goto error;
3390         else if (qlen >= sizeof qname)
3391                 goto toolong;
3392
3393         if ((error = dns_p_push(P, DNS_S_QD, qname, qlen, rr.type, rr.class, 0, 0)))
3394                 goto error;
3395
3396         switch (rr.type) {
3397         case DNS_T_PTR:
3398                 for (ent = hosts->head; ent; ent = ent->next) {
3399                         if (ent->alias || 0 != strcasecmp(qname, ent->arpa))
3400                                 continue;
3401
3402                         if ((error = dns_p_push(P, DNS_S_AN, qname, qlen, rr.type, rr.class, 0, ent->host)))
3403                                 goto error;
3404                 }
3405
3406                 break;
3407         case DNS_T_AAAA:
3408                 af      = AF_INET6;
3409
3410                 goto loop;
3411         case DNS_T_A:
3412                 af      = AF_INET;
3413
3414 loop:           for (ent = hosts->head; ent; ent = ent->next) {
3415                         if (ent->af != af || 0 != strcasecmp(qname, ent->host))
3416                                 continue;
3417
3418                         if ((error = dns_p_push(P, DNS_S_AN, qname, qlen, rr.type, rr.class, 0, &ent->addr)))
3419                                 goto error;
3420                 }
3421
3422                 break;
3423         default:
3424                 break;
3425         } /* switch() */
3426
3427
3428         if (!(A = dns_p_copy(dns_p_make(P->end, &error), P)))
3429                 goto error;
3430
3431         return A;
3432 toolong:
3433         error = DNS_EILLEGAL;
3434 error:
3435         *error_ = error;
3436
3437         free(A);
3438
3439         return 0;
3440 } /* dns_hosts_query() */
3441
3442
3443 /*
3444  * R E S O L V . C O N F  R O U T I N E S
3445  *
3446  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3447
3448 struct dns_resolv_conf *dns_resconf_open(int *error) {
3449         static const struct dns_resolv_conf resconf_initializer
3450                 = { .lookup = "bf", .options = { .ndots = 1, .timeout = 5, .attempts = 2, .tcp = DNS_RESCONF_TCP_ENABLE, },
3451                     .iface = { .ss_family = AF_INET }, };
3452         struct dns_resolv_conf *resconf;
3453         struct sockaddr_in *sin;
3454
3455         if (!(resconf = malloc(sizeof *resconf)))
3456                 goto syerr;
3457
3458         *resconf = resconf_initializer;
3459
3460         sin = (struct sockaddr_in *)&resconf->nameserver[0];
3461         sin->sin_family      = AF_INET;
3462         sin->sin_addr.s_addr = INADDR_ANY;
3463         sin->sin_port        = htons(53);
3464 #if defined(SA_LEN)
3465         sin->sin_len         = sizeof *sin;
3466 #endif
3467
3468         if (0 != gethostname(resconf->search[0], sizeof resconf->search[0]))
3469                 goto syerr;
3470
3471         dns_d_anchor(resconf->search[0], sizeof resconf->search[0], resconf->search[0], strlen(resconf->search[0]));
3472         dns_d_cleave(resconf->search[0], sizeof resconf->search[0], resconf->search[0], strlen(resconf->search[0]));
3473
3474         /*
3475          * XXX: If gethostname() returned a string without any label
3476          *      separator, then search[0][0] should be NUL.
3477          */
3478
3479         dns_resconf_acquire(resconf);
3480
3481         return resconf;
3482 syerr:
3483         *error  = dns_syerr();
3484
3485         free(resconf);
3486
3487         return 0;
3488 } /* dns_resconf_open() */
3489
3490
3491 void dns_resconf_close(struct dns_resolv_conf *resconf) {
3492         if (!resconf || 1 != dns_resconf_release(resconf))
3493                 return /* void */;
3494
3495         free(resconf);
3496 } /* dns_resconf_close() */
3497
3498
3499 unsigned dns_resconf_acquire(struct dns_resolv_conf *resconf) {
3500         return dns_atomic_inc(&resconf->_.refcount);
3501 } /* dns_resconf_acquire() */
3502
3503
3504 unsigned dns_resconf_release(struct dns_resolv_conf *resconf) {
3505         return dns_atomic_dec(&resconf->_.refcount);
3506 } /* dns_resconf_release() */
3507
3508
3509 struct dns_resolv_conf *dns_resconf_mortal(struct dns_resolv_conf *resconf) {
3510         if (resconf)
3511                 dns_resconf_release(resconf);
3512
3513         return resconf;
3514 } /* dns_resconf_mortal() */
3515
3516
3517 struct dns_resolv_conf *dns_resconf_local(int *error_) {
3518         struct dns_resolv_conf *resconf;
3519         int error;
3520
3521         if (!(resconf = dns_resconf_open(&error)))
3522                 goto error;
3523
3524         if ((error = dns_resconf_loadpath(resconf, "/etc/resolv.conf")))
3525                 goto error;
3526
3527         return resconf;
3528 error:
3529         *error_ = error;
3530
3531         dns_resconf_close(resconf);
3532
3533         return 0;
3534 } /* dns_resconf_local() */
3535
3536
3537 struct dns_resolv_conf *dns_resconf_root(int *error_) {
3538         struct dns_resolv_conf *resconf;
3539         int error;
3540
3541         if (!(resconf = dns_resconf_open(&error)))
3542                 goto error;
3543
3544         if ((error = dns_resconf_loadpath(resconf, "/etc/resolv.conf")))
3545                 goto error;
3546
3547         resconf->options.recurse        = 1;
3548
3549         return resconf;
3550 error:
3551         *error_ = error;
3552
3553         dns_resconf_close(resconf);
3554
3555         return 0;
3556 } /* dns_resconf_root() */
3557
3558
3559 enum dns_resconf_keyword {
3560         DNS_RESCONF_NAMESERVER,
3561         DNS_RESCONF_DOMAIN,
3562         DNS_RESCONF_SEARCH,
3563         DNS_RESCONF_LOOKUP,
3564         DNS_RESCONF_FILE,
3565         DNS_RESCONF_BIND,
3566         DNS_RESCONF_CACHE,
3567         DNS_RESCONF_OPTIONS,
3568         DNS_RESCONF_EDNS0,
3569         DNS_RESCONF_NDOTS,
3570         DNS_RESCONF_TIMEOUT,
3571         DNS_RESCONF_ATTEMPTS,
3572         DNS_RESCONF_ROTATE,
3573         DNS_RESCONF_RECURSE,
3574         DNS_RESCONF_SMART,
3575         DNS_RESCONF_TCP,
3576         DNS_RESCONF_TCPx,
3577         DNS_RESCONF_INTERFACE,
3578         DNS_RESCONF_ZERO,
3579         DNS_RESCONF_ONE,
3580         DNS_RESCONF_ENABLE,
3581         DNS_RESCONF_ONLY,
3582         DNS_RESCONF_DISABLE,
3583 }; /* enum dns_resconf_keyword */ 
3584
3585 static enum dns_resconf_keyword dns_resconf_keyword(const char *word) {
3586         static const char *words[]      = {
3587                 [DNS_RESCONF_NAMESERVER]        = "nameserver",
3588                 [DNS_RESCONF_DOMAIN]            = "domain",
3589                 [DNS_RESCONF_SEARCH]            = "search",
3590                 [DNS_RESCONF_LOOKUP]            = "lookup",
3591                 [DNS_RESCONF_FILE]              = "file",
3592                 [DNS_RESCONF_BIND]              = "bind",
3593                 [DNS_RESCONF_CACHE]             = "cache",
3594                 [DNS_RESCONF_OPTIONS]           = "options",
3595                 [DNS_RESCONF_EDNS0]             = "edns0",
3596                 [DNS_RESCONF_ROTATE]            = "rotate",
3597                 [DNS_RESCONF_RECURSE]           = "recurse",
3598                 [DNS_RESCONF_SMART]             = "smart",
3599                 [DNS_RESCONF_TCP]               = "tcp",
3600                 [DNS_RESCONF_INTERFACE]         = "interface",
3601                 [DNS_RESCONF_ZERO]              = "0",
3602                 [DNS_RESCONF_ONE]               = "1",
3603                 [DNS_RESCONF_ENABLE]            = "enable",
3604                 [DNS_RESCONF_ONLY]              = "only",
3605                 [DNS_RESCONF_DISABLE]           = "disable",
3606         };
3607         unsigned i;
3608
3609         for (i = 0; i < lengthof(words); i++) {
3610                 if (words[i] && 0 == strcasecmp(words[i], word))
3611                         return i;
3612         }
3613
3614         if (0 == strncasecmp(word, "ndots:", sizeof "ndots:" - 1))
3615                 return DNS_RESCONF_NDOTS;
3616
3617         if (0 == strncasecmp(word, "timeout:", sizeof "timeout:" - 1))
3618                 return DNS_RESCONF_TIMEOUT;
3619
3620         if (0 == strncasecmp(word, "attempts:", sizeof "attempts:" - 1))
3621                 return DNS_RESCONF_ATTEMPTS;
3622
3623         if (0 == strncasecmp(word, "tcp:", sizeof "tcp:" - 1))
3624                 return DNS_RESCONF_TCPx;
3625
3626         return -1;
3627 } /* dns_resconf_keyword() */
3628
3629
3630 /** OpenBSD-style "[1.2.3.4]:53" nameserver syntax */
3631 static int dns_resconf_pton(struct sockaddr_storage *ss, const char *src) {
3632         struct { char buf[128], *p; } addr = { "", addr.buf };
3633         unsigned short port = 0;
3634         int ch, af = AF_INET;
3635
3636         while ((ch = *src++)) {
3637                 switch (ch) {
3638                 case ' ':
3639                         /* FALL THROUGH */
3640                 case '\t':
3641                         break;
3642                 case '[':
3643                         break;
3644                 case ']':
3645                         while ((ch = *src++)) {
3646                                 if (isdigit((unsigned char)ch)) {
3647                                         port *= 10;
3648                                         port += ch - '0';
3649                                 }
3650                         }
3651
3652                         goto inet;
3653                 case ':':
3654                         af = AF_INET6;
3655
3656                         /* FALL THROUGH */
3657                 default:
3658                         if (addr.p < endof(addr.buf) - 1)
3659                                 *addr.p++ = ch;
3660
3661                         break;
3662                 } /* switch() */
3663         } /* while() */
3664 inet:
3665
3666         switch (dns_inet_pton(af, addr.buf, dns_sa_addr(af, ss))) {
3667         case -1:
3668                 return errno;
3669         case 0:
3670                 return EINVAL;
3671         } /* switch() */
3672
3673         port = (!port)? 53 : port;
3674         *dns_sa_port(af, ss) = htons(port);
3675         dns_sa_family(ss) = af;
3676
3677         return 0;
3678 } /* dns_resconf_pton() */
3679
3680 #define dns_resconf_issep(ch)   (isspace(ch) || (ch) == ',')
3681 #define dns_resconf_iscom(ch)   ((ch) == '#' || (ch) == ';')
3682
3683 int dns_resconf_loadfile(struct dns_resolv_conf *resconf, FILE *fp) {
3684         unsigned sa_count       = 0;
3685         char words[6][DNS_D_MAXNAME + 1];
3686         unsigned wp, wc, i, j, n;
3687         int ch, error;
3688
3689         rewind(fp);
3690
3691         do {
3692                 memset(words, '\0', sizeof words);
3693                 wp      = 0;
3694                 wc      = 0;
3695
3696                 while (EOF != (ch = getc(fp)) && ch != '\n') {
3697                         if (dns_resconf_issep(ch)) {
3698                                 if (wp > 0) {
3699                                         wp      = 0;
3700
3701                                         if (++wc >= lengthof(words))
3702                                                 goto skip;
3703                                 }
3704                         } else if (dns_resconf_iscom(ch)) {
3705 skip:
3706                                 do {
3707                                         ch      = getc(fp);
3708                                 } while (ch != EOF && ch != '\n');
3709
3710                                 break;
3711                         } else {
3712                                 dns__printchar(words[wc], sizeof words[wc], wp, ch);
3713                                 wp++;
3714                         }
3715                 }
3716
3717                 if (wp > 0)
3718                         wc++;
3719
3720                 if (wc < 2)
3721                         continue;
3722
3723                 switch (dns_resconf_keyword(words[0])) {
3724                 case DNS_RESCONF_NAMESERVER:
3725                         if (sa_count >= lengthof(resconf->nameserver))
3726                                 continue;
3727
3728                         if ((error = dns_resconf_pton(&resconf->nameserver[sa_count], words[1])))
3729                                 continue;
3730
3731                         sa_count++;
3732
3733                         break;
3734                 case DNS_RESCONF_DOMAIN:
3735                 case DNS_RESCONF_SEARCH:
3736                         memset(resconf->search, '\0', sizeof resconf->search);
3737
3738                         for (i = 1, j = 0; i < wc && j < lengthof(resconf->search); i++, j++)
3739                                 dns_d_anchor(resconf->search[j], sizeof resconf->search[j], words[i], strlen(words[i]));
3740
3741                         break;
3742                 case DNS_RESCONF_LOOKUP:
3743                         for (i = 1, j = 0; i < wc && j < lengthof(resconf->lookup); i++) {
3744                                 switch (dns_resconf_keyword(words[i])) {
3745                                 case DNS_RESCONF_FILE:
3746                                         resconf->lookup[j++]    = 'f';
3747
3748                                         break;
3749                                 case DNS_RESCONF_BIND:
3750                                         resconf->lookup[j++]    = 'b';
3751
3752                                         break;
3753                                 case DNS_RESCONF_CACHE:
3754                                         resconf->lookup[j++]    = 'c';
3755
3756                                         break;
3757                                 default:
3758                                         break;
3759                                 } /* switch() */
3760                         } /* for() */
3761
3762                         break;
3763                 case DNS_RESCONF_OPTIONS:
3764                         for (i = 1; i < wc; i++) {
3765                                 switch (dns_resconf_keyword(words[i])) {
3766                                 case DNS_RESCONF_EDNS0:
3767                                         resconf->options.edns0  = 1;
3768
3769                                         break;
3770                                 case DNS_RESCONF_NDOTS:
3771                                         for (j = sizeof "ndots:" - 1, n = 0; isdigit((int)words[i][j]); j++) {
3772                                                 n       *= 10;
3773                                                 n       += words[i][j] - '0';
3774                                         } /* for() */
3775
3776                                         resconf->options.ndots  = n;
3777
3778                                         break;
3779                                 case DNS_RESCONF_TIMEOUT:
3780                                         for (j = sizeof "timeout:" - 1, n = 0; isdigit((int)words[i][j]); j++) {
3781                                                 n       *= 10;
3782                                                 n       += words[i][j] - '0';
3783                                         } /* for() */
3784
3785                                         resconf->options.timeout        = n;
3786
3787                                         break;
3788                                 case DNS_RESCONF_ATTEMPTS:
3789                                         for (j = sizeof "attempts:" - 1, n = 0; isdigit((int)words[i][j]); j++) {
3790                                                 n       *= 10;
3791                                                 n       += words[i][j] - '0';
3792                                         } /* for() */
3793
3794                                         resconf->options.attempts       = n;
3795
3796                                         break;
3797                                 case DNS_RESCONF_ROTATE:
3798                                         resconf->options.rotate         = 1;
3799
3800                                         break;
3801                                 case DNS_RESCONF_RECURSE:
3802                                         resconf->options.recurse        = 1;
3803
3804                                         break;
3805                                 case DNS_RESCONF_SMART:
3806                                         resconf->options.smart          = 1;
3807
3808                                         break;
3809                                 case DNS_RESCONF_TCP:
3810                                         resconf->options.tcp            = DNS_RESCONF_TCP_ONLY;
3811
3812                                         break;
3813                                 case DNS_RESCONF_TCPx:
3814                                         switch (dns_resconf_keyword(&words[i][sizeof "tcp:" - 1])) {
3815                                         case DNS_RESCONF_ENABLE:
3816                                                 resconf->options.tcp    = DNS_RESCONF_TCP_ENABLE;
3817
3818                                                 break;
3819                                         case DNS_RESCONF_ONE:
3820                                         case DNS_RESCONF_ONLY:
3821                                                 resconf->options.tcp    = DNS_RESCONF_TCP_ONLY;
3822
3823                                                 break;
3824                                         case DNS_RESCONF_ZERO:
3825                                         case DNS_RESCONF_DISABLE:
3826                                                 resconf->options.tcp    = DNS_RESCONF_TCP_DISABLE;
3827
3828                                                 break;
3829                                         default:
3830                                                 break;
3831                                         } /* switch() */
3832
3833                                         break;
3834                                 default:
3835                                         break;
3836                                 } /* switch() */
3837                         } /* for() */
3838
3839                         break;
3840                 case DNS_RESCONF_INTERFACE:
3841                         for (i = 0, n = 0; isdigit((int)words[2][i]); i++) {
3842                                 n       *= 10;
3843                                 n       += words[2][i] - '0';
3844                         }
3845
3846                         dns_resconf_setiface(resconf, words[1], n);
3847
3848                         break;
3849                 default:
3850                         break;
3851                 } /* switch() */
3852         } while (ch != EOF);
3853
3854         return 0;
3855 } /* dns_resconf_loadfile() */
3856
3857
3858 int dns_resconf_loadpath(struct dns_resolv_conf *resconf, const char *path) {
3859         FILE *fp;
3860         int error;
3861
3862         if (!(fp = fopen(path, "r")))
3863                 return dns_syerr();
3864
3865         error   = dns_resconf_loadfile(resconf, fp);
3866
3867         fclose(fp);
3868
3869         return error;
3870 } /* dns_resconf_loadpath() */
3871
3872
3873 int dns_resconf_setiface(struct dns_resolv_conf *resconf, const char *addr, unsigned short port) {
3874         int af  = (strchr(addr, ':'))? AF_INET6 : AF_INET;
3875
3876         if (1 != dns_inet_pton(af, addr, dns_sa_addr(af, &resconf->iface)))
3877                 return dns_soerr();
3878
3879         *dns_sa_port(af, &resconf->iface)       = htons(port);
3880         resconf->iface.ss_family                = af;
3881
3882         return 0;
3883 } /* dns_resconf_setiface() */
3884
3885
3886 size_t dns_resconf_search(void *dst, size_t lim, const void *qname, size_t qlen, struct dns_resolv_conf *resconf, dns_resconf_i_t *state) {
3887         unsigned srchi          = 0xff & (*state >> 8);
3888         unsigned ndots          = 0xff & (*state >> 16);
3889         unsigned slen, len      = 0;
3890         const char *qp, *qe;
3891
3892 //      assert(0xff > lengthof(resconf->search));
3893
3894         switch (0xff & *state) {
3895         case 0:
3896                 qp      = qname;
3897                 qe      = qp + qlen;
3898
3899                 while ((qp = memchr(qp, '.', qe - qp)))
3900                         { ndots++; qp++; }
3901
3902                 ++*state;
3903
3904                 if (ndots >= resconf->options.ndots) {
3905                         len     = dns_d_anchor(dst, lim, qname, qlen);
3906
3907                         break;
3908                 }
3909
3910                 /* FALL THROUGH */
3911         case 1:
3912                 if (srchi < lengthof(resconf->search) && (slen = strlen(resconf->search[srchi]))) {
3913                         len     = dns__printstring(dst, lim, 0, qname, qlen);
3914                         len     = dns_d_anchor(dst, lim, dst, len);
3915                         len     += dns__printstring(dst, lim, len, resconf->search[srchi], slen);
3916
3917                         srchi++;
3918
3919                         break;
3920                 }
3921
3922                 ++*state;
3923
3924                 /* FALL THROUGH */
3925         case 2:
3926                 ++*state;
3927
3928                 if (ndots < resconf->options.ndots) {
3929                         len     = dns_d_anchor(dst, lim, qname, qlen);
3930
3931                         break;
3932                 }
3933
3934                 /* FALL THROUGH */
3935         default:
3936                 break;
3937         } /* switch() */
3938
3939         dns__printnul(dst, lim, len);
3940
3941         *state  = ((0xff & *state) << 0)
3942                 | ((0xff & srchi) << 8)
3943                 | ((0xff & ndots) << 16);
3944
3945         return len;
3946 } /* dns_resconf_search() */
3947
3948
3949 int dns_resconf_dump(struct dns_resolv_conf *resconf, FILE *fp) {
3950         unsigned i;
3951         int af;
3952
3953         for (i = 0; i < lengthof(resconf->nameserver) && (af = resconf->nameserver[i].ss_family) != AF_UNSPEC; i++) {
3954                 char addr[INET6_ADDRSTRLEN + 1] = "[INVALID]";
3955                 unsigned short port;
3956
3957                 dns_inet_ntop(af, dns_sa_addr(af, &resconf->nameserver[i]), addr, sizeof addr);
3958                 port = ntohs(*dns_sa_port(af, &resconf->nameserver[i]));
3959
3960                 if (port == 53)
3961                         fprintf(fp, "nameserver %s\n", addr);
3962                 else
3963                         fprintf(fp, "nameserver [%s]:%hu\n", addr, port);
3964         }
3965
3966
3967         fprintf(fp, "search");
3968
3969         for (i = 0; i < lengthof(resconf->search) && resconf->search[i][0]; i++)
3970                 fprintf(fp, " %s", resconf->search[i]);
3971
3972         fputc('\n', fp);
3973
3974
3975         fprintf(fp, "lookup");
3976
3977         for (i = 0; i < lengthof(resconf->lookup) && resconf->lookup[i]; i++) {
3978                 switch (resconf->lookup[i]) {
3979                 case 'b':
3980                         fprintf(fp, " bind"); break;
3981                 case 'f':
3982                         fprintf(fp, " file"); break;
3983                 case 'c':
3984                         fprintf(fp, " cache"); break;
3985                 }
3986         }
3987
3988         fputc('\n', fp);
3989
3990
3991         fprintf(fp, "options ndots:%u timeout:%u attempts:%u", resconf->options.ndots, resconf->options.timeout, resconf->options.attempts);
3992
3993         if (resconf->options.edns0)
3994                 fprintf(fp, " edns0");
3995         if (resconf->options.rotate)
3996                 fprintf(fp, " rotate");
3997         if (resconf->options.recurse)
3998                 fprintf(fp, " recurse");
3999         if (resconf->options.smart)
4000                 fprintf(fp, " smart");
4001
4002         fputc('\n', fp);
4003
4004
4005         if ((af = resconf->iface.ss_family) != AF_UNSPEC) {
4006                 char addr[INET6_ADDRSTRLEN + 1] = "[INVALID]";
4007
4008                 dns_inet_ntop(af, dns_sa_addr(af, &resconf->iface), addr, sizeof addr);
4009
4010                 fprintf(fp, "interface %s %hu\n", addr, ntohs(*dns_sa_port(af, &resconf->iface)));
4011         }
4012
4013         return 0;
4014 } /* dns_resconf_dump() */
4015
4016
4017 /*
4018  * H I N T  S E R V E R  R O U T I N E S
4019  *
4020  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4021
4022 struct dns_hints_soa {
4023         unsigned char zone[DNS_D_MAXNAME + 1];
4024         
4025         struct {
4026                 struct sockaddr_storage ss;
4027                 unsigned priority;
4028         } addrs[16];
4029
4030         unsigned count;
4031
4032         struct dns_hints_soa *next;
4033 }; /* struct dns_hints_soa */
4034
4035
4036 struct dns_hints {
4037         dns_atomic_t refcount;
4038
4039         struct dns_hints_soa *head;
4040 }; /* struct dns_hints */
4041
4042
4043 struct dns_hints *dns_hints_open(struct dns_resolv_conf *resconf __UNUSED__, int *error) {
4044         static const struct dns_hints H_initializer;
4045         struct dns_hints *H;
4046
4047         if (!(H = malloc(sizeof *H)))
4048                 goto syerr;
4049
4050         *H      = H_initializer;
4051
4052         dns_hints_acquire(H);
4053
4054         return H;
4055 syerr:
4056         *error  = dns_syerr();
4057
4058         free(H);
4059
4060         return 0;
4061 } /* dns_hints_open() */
4062
4063
4064 void dns_hints_close(struct dns_hints *H) {
4065         struct dns_hints_soa *soa, *nxt;
4066
4067         if (!H || 1 != dns_hints_release(H))
4068                 return /* void */;
4069
4070         for (soa = H->head; soa; soa = nxt) {
4071                 nxt     = soa->next;
4072
4073                 free(soa);
4074         }
4075
4076         free(H);
4077
4078         return /* void */;
4079 } /* dns_hints_close() */
4080
4081
4082 unsigned dns_hints_acquire(struct dns_hints *H) {
4083         return dns_atomic_inc(&H->refcount);
4084 } /* dns_hints_acquire() */
4085
4086
4087 unsigned dns_hints_release(struct dns_hints *H) {
4088         return dns_atomic_dec(&H->refcount);
4089 } /* dns_hints_release() */
4090
4091
4092 struct dns_hints *dns_hints_mortal(struct dns_hints *hints) {
4093         if (hints)
4094                 dns_hints_release(hints);
4095
4096         return hints;
4097 } /* dns_hints_mortal() */
4098
4099
4100 struct dns_hints *dns_hints_local(struct dns_resolv_conf *resconf, int *error_) {
4101         struct dns_hints *hints         = 0;
4102         int error;
4103
4104         if (resconf)
4105                 dns_resconf_acquire(resconf);
4106         else if (!(resconf = dns_resconf_local(&error)))
4107                 goto error;
4108
4109         if (!(hints = dns_hints_open(resconf, &error)))
4110                 goto error;
4111
4112         error   = 0;
4113
4114         if (0 == dns_hints_insert_resconf(hints, ".", resconf, &error) && error)
4115                 goto error;
4116
4117         dns_resconf_close(resconf);
4118
4119         return hints;
4120 error:
4121         *error_ = error;
4122
4123         dns_resconf_close(resconf);
4124         dns_hints_close(hints);
4125
4126         return 0;
4127 } /* dns_hints_local() */
4128
4129
4130 struct dns_hints *dns_hints_root(struct dns_resolv_conf *resconf, int *error_) {
4131         static const struct {
4132                 int af;
4133                 char addr[INET6_ADDRSTRLEN];
4134         } root_hints[] = {
4135                 { AF_INET,      "198.41.0.4"            },      /* A.ROOT-SERVERS.NET. */
4136                 { AF_INET6,     "2001:503:ba3e::2:30"   },      /* A.ROOT-SERVERS.NET. */
4137                 { AF_INET,      "192.228.79.201"        },      /* B.ROOT-SERVERS.NET. */
4138                 { AF_INET,      "192.33.4.12"           },      /* C.ROOT-SERVERS.NET. */
4139                 { AF_INET,      "128.8.10.90"           },      /* D.ROOT-SERVERS.NET. */
4140                 { AF_INET,      "192.203.230.10"        },      /* E.ROOT-SERVERS.NET. */
4141                 { AF_INET,      "192.5.5.241"           },      /* F.ROOT-SERVERS.NET. */
4142                 { AF_INET6,     "2001:500:2f::f"        },      /* F.ROOT-SERVERS.NET. */
4143                 { AF_INET,      "192.112.36.4"          },      /* G.ROOT-SERVERS.NET. */
4144                 { AF_INET,      "128.63.2.53"           },      /* H.ROOT-SERVERS.NET. */
4145                 { AF_INET6,     "2001:500:1::803f:235"  },      /* H.ROOT-SERVERS.NET. */
4146                 { AF_INET,      "192.36.148.17"         },      /* I.ROOT-SERVERS.NET. */
4147                 { AF_INET,      "192.58.128.30"         },      /* J.ROOT-SERVERS.NET. */
4148                 { AF_INET6,     "2001:503:c27::2:30"    },      /* J.ROOT-SERVERS.NET. */
4149         };
4150         struct dns_hints *hints         = 0;
4151         struct sockaddr_storage ss;
4152         unsigned i;
4153         int error, af;
4154
4155         if (!(hints = dns_hints_open(resconf, &error)))
4156                 goto error;
4157
4158         for (i = 0; i < lengthof(root_hints); i++) {
4159                 af      = root_hints[i].af;
4160
4161                 if (1 != dns_inet_pton(af, root_hints[i].addr, dns_sa_addr(af, &ss)))
4162                         goto soerr;
4163
4164                 *dns_sa_port(af, &ss)   = htons(53);
4165                 ss.ss_family            = af;
4166
4167                 if ((error = dns_hints_insert(hints, ".", (struct sockaddr *)&ss, 1)))
4168                         goto error;
4169         }
4170
4171         return hints;
4172 soerr:
4173         error   = dns_soerr();
4174
4175         goto error;
4176 error:
4177         *error_ = error;
4178
4179         dns_hints_close(hints);
4180
4181         return 0;
4182 } /* dns_hints_root() */
4183
4184
4185 static struct dns_hints_soa *dns_hints_fetch(struct dns_hints *H, const char *zone) {
4186         struct dns_hints_soa *soa;
4187
4188         for (soa = H->head; soa; soa = soa->next) {
4189                 if (0 == strcasecmp(zone, (char *)soa->zone))
4190                         return soa;
4191         }
4192
4193         return 0;
4194 } /* dns_hints_fetch() */
4195
4196
4197 int dns_hints_insert(struct dns_hints *H, const char *zone, const struct sockaddr *sa, unsigned priority) {
4198         static const struct dns_hints_soa soa_initializer;
4199         struct dns_hints_soa *soa;
4200         unsigned i;
4201
4202         if (!(soa = dns_hints_fetch(H, zone))) {
4203                 if (!(soa = malloc(sizeof *soa)))
4204                         return dns_syerr();
4205
4206                 *soa    = soa_initializer;
4207
4208                 dns__printstring(soa->zone, sizeof soa->zone, 0, zone);
4209
4210                 soa->next       = H->head;
4211                 H->head         = soa;
4212         }
4213
4214         i       = soa->count % lengthof(soa->addrs);
4215
4216         memcpy(&soa->addrs[i].ss, sa, dns_sa_len(sa));
4217
4218         soa->addrs[i].priority  = MAX(1, priority);
4219
4220         if (soa->count < lengthof(soa->addrs))
4221                 soa->count++;
4222
4223         return 0;
4224 } /* dns_hints_insert() */
4225
4226
4227 unsigned dns_hints_insert_resconf(struct dns_hints *H, const char *zone, const struct dns_resolv_conf *resconf, int *error_) {
4228         unsigned i, n, p;
4229         int error;
4230
4231         for (i = 0, n = 0, p = 1; i < lengthof(resconf->nameserver) && resconf->nameserver[i].ss_family != AF_UNSPEC; i++, n++) {
4232                 if ((error = dns_hints_insert(H, zone, (struct sockaddr *)&resconf->nameserver[i], p)))
4233                         goto error;
4234
4235                 p       += !resconf->options.rotate;
4236         }
4237
4238         return n;
4239 error:
4240         *error_ = error;
4241
4242         return n;
4243 } /* dns_hints_insert_resconf() */
4244
4245
4246 static int dns_hints_i_cmp(unsigned a, unsigned b, struct dns_hints_i *i, struct dns_hints_soa *soa) {
4247         int cmp;
4248
4249         if ((cmp = soa->addrs[a].priority - soa->addrs[b].priority))
4250                 return cmp;
4251
4252         return dns_k_shuffle16(a, i->state.seed) - dns_k_shuffle16(b, i->state.seed);
4253 } /* dns_hints_i_cmp() */
4254
4255
4256 static unsigned dns_hints_i_start(struct dns_hints_i *i, struct dns_hints_soa *soa) {
4257         unsigned p0, p;
4258
4259         p0      = 0;
4260
4261         for (p = 1; p < soa->count; p++) {
4262                 if (dns_hints_i_cmp(p, p0, i, soa) < 0)
4263                         p0      = p;
4264         }
4265
4266         return p0;
4267 } /* dns_hints_i_start() */
4268
4269
4270 static unsigned dns_hints_i_skip(unsigned p0, struct dns_hints_i *i, struct dns_hints_soa *soa) {
4271         unsigned pZ, p;
4272
4273         for (pZ = 0; pZ < soa->count; pZ++) {
4274                 if (dns_hints_i_cmp(pZ, p0, i, soa) > 0)
4275                         goto cont;
4276         }
4277
4278         return soa->count;
4279 cont:
4280         for (p = pZ + 1; p < soa->count; p++) {
4281                 if (dns_hints_i_cmp(p, p0, i, soa) <= 0)
4282                         continue;
4283
4284                 if (dns_hints_i_cmp(p, pZ, i, soa) >= 0)
4285                         continue;
4286
4287                 pZ      = p;
4288         }
4289
4290
4291         return pZ;
4292 } /* dns_hints_i_skip() */
4293
4294
4295 struct dns_hints_i *dns_hints_i_init(struct dns_hints_i *i, struct dns_hints *hints) {
4296         static const struct dns_hints_i i_initializer;
4297         struct dns_hints_soa *soa;
4298
4299         i->state        = i_initializer.state;
4300
4301         do {
4302                 i->state.seed   = dns_random();
4303         } while (0 == i->state.seed);
4304
4305         if ((soa = dns_hints_fetch(hints, i->zone))) {
4306                 i->state.next   = dns_hints_i_start(i, soa);
4307         }
4308
4309         return i;
4310 } /* dns_hints_i_init() */
4311
4312
4313 unsigned dns_hints_grep(struct sockaddr **sa, socklen_t *sa_len, unsigned lim, struct dns_hints_i *i, struct dns_hints *H) {
4314         struct dns_hints_soa *soa;
4315         unsigned n;
4316
4317         if (!(soa = dns_hints_fetch(H, i->zone)))
4318                 return 0;
4319
4320         n       = 0;
4321
4322         while (i->state.next < soa->count && n < lim) {
4323                 *sa     = (struct sockaddr *)&soa->addrs[i->state.next].ss;
4324                 *sa_len = dns_sa_len(*sa);
4325
4326                 sa++;
4327                 sa_len++;
4328                 n++;
4329
4330                 i->state.next   = dns_hints_i_skip(i->state.next, i, soa);
4331         }
4332
4333         return n;
4334 } /* dns_hints_grep() */
4335
4336
4337 struct dns_packet *dns_hints_query(struct dns_hints *hints, struct dns_packet *Q, int *error_) {
4338         struct dns_packet *A, *P;
4339         struct dns_rr rr;
4340         char zone[DNS_D_MAXNAME + 1];
4341         size_t zlen;
4342         struct dns_hints_i i;
4343         struct sockaddr *sa;
4344         socklen_t slen;
4345         int error;
4346
4347         if (!dns_rr_grep(&rr, 1, dns_rr_i_new(Q, .section = DNS_S_QUESTION), Q, &error))
4348                 goto error;
4349
4350         if (!(zlen = dns_d_expand(zone, sizeof zone, rr.dn.p, Q, &error)))
4351                 goto error;
4352         else if (zlen >= sizeof zone)
4353                 goto toolong;
4354
4355         P                       = dns_p_new(512);
4356         dns_header(P)->qr       = 1;
4357
4358         if ((error = dns_rr_copy(P, &rr, Q)))
4359                 goto error;
4360
4361         if ((error = dns_p_push(P, DNS_S_AUTHORITY, ".", strlen("."), DNS_T_NS, DNS_C_IN, 0, "hints.local.")))
4362                 goto error;
4363
4364         do {
4365                 i.zone  = zone;
4366
4367                 dns_hints_i_init(&i, hints);
4368
4369                 while (dns_hints_grep(&sa, &slen, 1, &i, hints)) {
4370                         int af          = sa->sa_family;
4371                         int rtype       = (af == AF_INET6)? DNS_T_AAAA : DNS_T_A;
4372
4373                         if ((error = dns_p_push(P, DNS_S_ADDITIONAL, "hints.local.", strlen("hints.local."), rtype, DNS_C_IN, 0, dns_sa_addr(af, sa))))
4374                                 goto error;
4375                 }
4376         } while ((zlen = dns_d_cleave(zone, sizeof zone, zone, zlen)));
4377
4378         if (!(A = dns_p_copy(dns_p_make(P->end, &error), P)))
4379                 goto error;
4380
4381         return A;
4382 toolong:
4383         error = DNS_EILLEGAL;
4384 error:
4385         *error_ = error;
4386
4387         return 0;
4388 } /* dns_hints_query() */
4389
4390
4391 /** ugly hack to support specifying ports other than 53 in resolv.conf. */
4392 static unsigned short dns_hints_port(struct dns_hints *hints, int af, void *addr) {
4393         struct dns_hints_soa *soa;
4394         unsigned short port;
4395         unsigned i;
4396
4397         for (soa = hints->head; soa; soa = soa->next) {
4398                 for (i = 0; i < soa->count; i++) {
4399                         if (af != soa->addrs[i].ss.ss_family)
4400                                 continue;
4401
4402                         if (memcmp(addr, dns_sa_addr(af, &soa->addrs[i].ss), (af == AF_INET6)? sizeof (struct in6_addr) : sizeof (struct in_addr)))
4403                                 continue;
4404
4405                         port = *dns_sa_port(af, &soa->addrs[i].ss);
4406
4407                         return (port)? port : htons(53);
4408                 }
4409         }
4410
4411         return htons(53);
4412 } /* dns_hints_port() */
4413
4414
4415 int dns_hints_dump(struct dns_hints *hints, FILE *fp) {
4416         struct dns_hints_soa *soa;
4417         char addr[INET6_ADDRSTRLEN];
4418         unsigned i;
4419         int af;
4420
4421         for (soa = hints->head; soa; soa = soa->next) {
4422                 fprintf(fp, "ZONE \"%s\"\n", soa->zone);
4423
4424                 for (i = 0; i < soa->count; i++) {
4425                         af      = soa->addrs[i].ss.ss_family;
4426                         if (!dns_inet_ntop(af, dns_sa_addr(af, &soa->addrs[i].ss), addr, sizeof addr))
4427                                 return dns_soerr();
4428
4429                         fprintf(fp, "\t(%d) [%s]:%hu\n", (int)soa->addrs[i].priority, addr, ntohs(*dns_sa_port(af, &soa->addrs[i].ss)));
4430                 }
4431         }
4432
4433         return 0;
4434 } /* dns_hints_dump() */
4435
4436
4437 /*
4438  * C A C H E  R O U T I N E S
4439  *
4440  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4441
4442 static dns_atomic_t dns_cache_acquire(struct dns_cache *cache __UNUSED__) {
4443         return 0;
4444 } /* dns_cache_acquire() */
4445
4446
4447 static dns_atomic_t dns_cache_release(struct dns_cache *cache __UNUSED__) {
4448         return 0;
4449 } /* dns_cache_release() */
4450
4451
4452 static struct dns_packet *dns_cache_query(struct dns_packet *query __UNUSED__, struct dns_cache *cache __UNUSED__, int *error __UNUSED__) {
4453         return 0;
4454 } /* dns_cache_submit() */
4455
4456
4457 static int dns_cache_submit(struct dns_packet *query __UNUSED__, struct dns_cache *cache __UNUSED__) {
4458         return 0;
4459 } /* dns_cache_submit() */
4460
4461
4462 static int dns_cache_check(struct dns_cache *cache __UNUSED__) {
4463         return 0;
4464 } /* dns_cache_check() */
4465
4466
4467 static struct dns_packet *dns_cache_fetch(struct dns_cache *cache __UNUSED__, int *error __UNUSED__) {
4468         return 0;
4469 } /* dns_cache_fetch() */
4470
4471
4472 static int dns_cache_pollfd(struct dns_cache *cache __UNUSED__) {
4473         return -1;
4474 } /* dns_cache_pollfd() */
4475
4476
4477 static short dns_cache_events(struct dns_cache *cache __UNUSED__) {
4478         return 0;
4479 } /* dns_cache_events() */
4480
4481
4482 static void dns_cache_clear(struct dns_cache *cache __UNUSED__) {
4483         return;
4484 } /* dns_cache_clear() */
4485
4486
4487 struct dns_cache *dns_cache_init(struct dns_cache *cache) {
4488         static const struct dns_cache c_init = {
4489                 .acquire = &dns_cache_acquire,
4490                 .release = &dns_cache_release,
4491                 .query   = &dns_cache_query,
4492                 .submit  = &dns_cache_submit,
4493                 .check   = &dns_cache_check,
4494                 .fetch   = &dns_cache_fetch,
4495                 .pollfd  = &dns_cache_pollfd,
4496                 .events  = &dns_cache_events,
4497                 .clear   = &dns_cache_clear,
4498         };
4499
4500         *cache = c_init;
4501
4502         return cache;
4503 } /* dns_cache_init() */
4504
4505
4506 void dns_cache_close(struct dns_cache *cache) {
4507         if (cache)
4508                 cache->release(cache);
4509 } /* dns_cache_close() */
4510
4511
4512 /*
4513  * S O C K E T  R O U T I N E S
4514  *
4515  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4516
4517 static void dns_socketclose(int *fd) {
4518         if (*fd != -1) {
4519 #if _WIN32
4520                 closesocket(*fd);
4521 #else
4522                 close(*fd);
4523 #endif
4524                 *fd     = -1;
4525         }
4526 } /* dns_socketclose() */
4527
4528
4529 #define DNS_SO_MAXTRY   7
4530
4531 static int dns_socket(struct sockaddr *local, int type, int *error_) {
4532         int error, fd   = -1;
4533 #if defined(O_NONBLOCK)
4534         int flags;
4535 #elif defined(FIONBIO)
4536         unsigned long opt;
4537 #endif
4538
4539         if (-1 == (fd = socket(local->sa_family, type, 0)))
4540                 goto soerr;
4541
4542 #if defined(F_SETFD)
4543         if (-1 == fcntl(fd, F_SETFD, 1))
4544                 goto syerr;
4545 #endif
4546
4547 #if defined(O_NONBLOCK)
4548         if (-1 == (flags = fcntl(fd, F_GETFL)))
4549                 goto syerr;
4550
4551         if (-1 == fcntl(fd, F_SETFL, flags | O_NONBLOCK))
4552                 goto syerr;
4553 #elif defined(FIONBIO)
4554         opt     = 1;
4555
4556         if (0 != ioctlsocket(fd, FIONBIO, &opt))
4557                 goto soerr;
4558 #endif
4559
4560         if (local->sa_family != AF_INET && local->sa_family != AF_INET6)
4561                 return fd;
4562
4563         if (type != SOCK_DGRAM)
4564                 return fd;
4565
4566         if (*dns_sa_port(local->sa_family, local) == 0) {
4567                 struct sockaddr_storage tmp;
4568                 unsigned i, port;
4569
4570                 memcpy(&tmp, local, dns_sa_len(local));
4571
4572                 for (i = 0; i < DNS_SO_MAXTRY; i++) {
4573                         port    = 1025 + (dns_random() % 64510);
4574
4575                         *dns_sa_port(tmp.ss_family, &tmp)       = htons(port);
4576
4577                         if (0 == bind(fd, (struct sockaddr *)&tmp, dns_sa_len(&tmp)))
4578                                 return fd;
4579                 }
4580         }
4581         
4582         if (0 == bind(fd, local, dns_sa_len(local)))
4583                 return fd;
4584
4585         /* FALL THROUGH */
4586 soerr:
4587         error   = dns_soerr();
4588
4589         goto error;
4590 syerr:
4591         error   = dns_syerr();
4592
4593         goto error;
4594 error:
4595         *error_ = error;
4596
4597         dns_socketclose(&fd);
4598
4599         return -1;
4600 } /* dns_socket() */
4601
4602
4603 enum {
4604         DNS_SO_UDP_INIT = 1,
4605         DNS_SO_UDP_CONN,
4606         DNS_SO_UDP_SEND,
4607         DNS_SO_UDP_RECV,
4608         DNS_SO_UDP_DONE,
4609
4610         DNS_SO_TCP_INIT,
4611         DNS_SO_TCP_CONN,
4612         DNS_SO_TCP_SEND,
4613         DNS_SO_TCP_RECV,
4614         DNS_SO_TCP_DONE,
4615 };
4616
4617 struct dns_socket {
4618         struct dns_options opts;
4619
4620         int udp;
4621         int tcp;
4622
4623         int *old;
4624         unsigned onum, olim;
4625
4626         int type;
4627
4628         struct sockaddr_storage local, remote;
4629
4630         struct dns_k_permutor qids;
4631
4632         struct dns_stat stat;
4633
4634         /*
4635          * NOTE: dns_so_reset() zeroes everything from here down.
4636          */
4637         int state;
4638
4639         unsigned short qid;
4640         char qname[DNS_D_MAXNAME + 1];
4641         size_t qlen;
4642         enum dns_type qtype;
4643         enum dns_class qclass;
4644
4645         struct dns_packet *query;
4646         size_t qout;
4647
4648         time_t began;
4649
4650         struct dns_packet *answer;
4651         size_t alen, apos;
4652 }; /* struct dns_socket() */
4653
4654
4655 /*
4656  * NOTE: Actual closure delayed so that kqueue(2) and epoll(2) callers have
4657  * a chance to recognize a state change after installing a persistent event
4658  * and where sequential descriptors with the same integer value returned
4659  * from _pollfd() would be ambiguous. See dns_so_closefds().
4660  */
4661 static int dns_so_closefd(struct dns_socket *so, int *fd) {
4662         int error;
4663
4664         if (*fd == -1)
4665                 return 0;
4666
4667         if (so->opts.closefd.cb) {
4668                 if ((error = so->opts.closefd.cb(fd, so->opts.closefd.arg))) {
4669                         return error;
4670                 } else if (*fd == -1)
4671                         return 0;
4672         }
4673
4674         if (!(so->onum < so->olim)) {
4675                 unsigned olim = MAX(4, so->olim * 2);
4676                 void *old;
4677
4678                 if (!(old = realloc(so->old, sizeof so->old[0] * olim)))
4679                         return dns_syerr();
4680
4681                 so->old  = old;
4682                 so->olim = olim;
4683         }
4684
4685         so->old[so->onum++] = *fd;
4686         *fd = -1;
4687
4688         return 0;
4689 } /* dns_so_closefd() */
4690
4691
4692 #define DNS_SO_CLOSE_UDP 0x01
4693 #define DNS_SO_CLOSE_TCP 0x02
4694 #define DNS_SO_CLOSE_OLD 0x04
4695 #define DNS_SO_CLOSE_ALL (DNS_SO_CLOSE_UDP|DNS_SO_CLOSE_TCP|DNS_SO_CLOSE_OLD)
4696
4697 static void dns_so_closefds(struct dns_socket *so, int which) {
4698         if (DNS_SO_CLOSE_UDP & which)
4699                 dns_socketclose(&so->udp);
4700         if (DNS_SO_CLOSE_TCP & which)
4701                 dns_socketclose(&so->tcp);
4702         if (DNS_SO_CLOSE_OLD & which) {
4703                 unsigned i;
4704                 for (i = 0; i < so->onum; i++)
4705                         dns_socketclose(&so->old[i]);
4706                 so->onum = 0;
4707                 free(so->old);
4708                 so->old  = 0;
4709                 so->olim = 0;
4710         }
4711 } /* dns_so_closefds() */
4712
4713
4714 static void dns_so_destroy(struct dns_socket *);
4715
4716 static struct dns_socket *dns_so_init(struct dns_socket *so, const struct sockaddr *local, int type, const struct dns_options *opts, int *error) {
4717         static const struct dns_socket so_initializer = { .opts = DNS_OPTS_INITIALIZER, .udp = -1, .tcp = -1, };
4718
4719         *so             = so_initializer;
4720         so->type        = type;
4721
4722         if (opts)
4723                 so->opts = *opts;
4724
4725         if (local)
4726                 memcpy(&so->local, local, dns_sa_len(local));
4727
4728         if (-1 == (so->udp = dns_socket((struct sockaddr *)&so->local, SOCK_DGRAM, error)))
4729                 goto error;
4730
4731         dns_k_permutor_init(&so->qids, 1, 65535);
4732
4733         return so;
4734 error:
4735         dns_so_destroy(so);
4736
4737         return 0;       
4738 } /* dns_so_init() */
4739
4740
4741 struct dns_socket *dns_so_open(const struct sockaddr *local, int type, const struct dns_options *opts, int *error) {
4742         struct dns_socket *so;
4743
4744         if (!(so = malloc(sizeof *so)))
4745                 goto syerr;
4746
4747         if (!dns_so_init(so, local, type, opts, error))
4748                 goto error;
4749
4750         return so;
4751 syerr:
4752         *error  = dns_syerr();
4753 error:
4754         dns_so_close(so);
4755
4756         return 0;       
4757 } /* dns_so_open() */
4758
4759
4760 static void dns_so_destroy(struct dns_socket *so) {
4761         dns_so_reset(so);
4762         dns_so_closefds(so, DNS_SO_CLOSE_ALL);
4763 } /* dns_so_destroy() */
4764
4765
4766 void dns_so_close(struct dns_socket *so) {
4767         if (!so)
4768                 return;
4769
4770         dns_so_destroy(so);
4771
4772         free(so);
4773 } /* dns_so_close() */
4774
4775
4776 void dns_so_reset(struct dns_socket *so) {
4777         free(so->answer);
4778
4779         memset(&so->state, '\0', sizeof *so - offsetof(struct dns_socket, state));
4780 } /* dns_so_reset() */
4781
4782
4783 unsigned short dns_so_mkqid(struct dns_socket *so) {
4784         return dns_k_permutor_step(&so->qids);
4785 } /* dns_so_mkqid() */
4786
4787
4788 #define DNS_SO_MINBUF   768
4789
4790 static int dns_so_newanswer(struct dns_socket *so, size_t len) {
4791         size_t size     = offsetof(struct dns_packet, data) + MAX(len, DNS_SO_MINBUF);
4792         void *p;
4793
4794         if (!(p = realloc(so->answer, size)))
4795                 return dns_syerr();
4796
4797         so->answer      = dns_p_init(p, size);
4798
4799         return 0;
4800 } /* dns_so_newanswer() */
4801
4802
4803 int dns_so_submit(struct dns_socket *so, struct dns_packet *Q, struct sockaddr *host) {
4804         struct dns_rr rr;
4805         int error       = -1;
4806
4807         dns_so_reset(so);
4808
4809         if ((error = dns_rr_parse(&rr, 12, Q)))
4810                 goto error;
4811
4812         if (!(so->qlen = dns_d_expand(so->qname, sizeof so->qname, rr.dn.p, Q, &error)))
4813                 goto error;
4814         /*
4815          * NOTE: don't bail if expansion is too long; caller may be
4816          * intentionally sending long names. However, we won't be able to
4817          * verify it on return.
4818          */
4819
4820         so->qtype       = rr.type;
4821         so->qclass      = rr.class;
4822
4823         if ((error = dns_so_newanswer(so, DNS_SO_MINBUF)))
4824                 goto syerr;
4825
4826         memcpy(&so->remote, host, dns_sa_len(host));
4827
4828         so->query       = Q;
4829         so->qout        = 0;
4830         so->began       = dns_now();
4831
4832         if (dns_header(so->query)->qid == 0)
4833                 dns_header(so->query)->qid      = dns_so_mkqid(so);
4834
4835         so->qid         = dns_header(so->query)->qid;
4836         so->state       = (so->type == SOCK_STREAM)? DNS_SO_TCP_INIT : DNS_SO_UDP_INIT;
4837
4838         so->stat.queries++;
4839
4840         return 0;
4841 syerr:
4842         error   = dns_syerr();
4843 error:
4844         dns_so_reset(so);
4845
4846         return error;
4847 } /* dns_so_submit() */
4848
4849
4850 static int dns_so_verify(struct dns_socket *so, struct dns_packet *P) {
4851         char qname[DNS_D_MAXNAME + 1];
4852         size_t qlen;
4853         struct dns_rr rr;
4854         int error       = -1;
4855
4856         if (so->qid != dns_header(so->answer)->qid)
4857                 return DNS_EUNKNOWN;
4858
4859         if (!dns_p_count(so->answer, DNS_S_QD))
4860                 return DNS_EUNKNOWN;
4861
4862         if (0 != dns_rr_parse(&rr, 12, so->answer))
4863                 return DNS_EUNKNOWN;
4864
4865         if (rr.type != so->qtype || rr.class != so->qclass)
4866                 return DNS_EUNKNOWN;
4867
4868         if (!(qlen = dns_d_expand(qname, sizeof qname, rr.dn.p, P, &error)))
4869                 return error;
4870         else if (qlen >= sizeof qname || qlen != so->qlen)
4871                 return DNS_EUNKNOWN;
4872
4873         if (0 != strcasecmp(so->qname, qname))
4874                 return DNS_EUNKNOWN;
4875
4876         return 0;
4877 } /* dns_so_verify() */
4878
4879
4880 static int dns_so_tcp_send(struct dns_socket *so) {
4881         unsigned char *qsrc;
4882         size_t qend;
4883         long n;
4884
4885         so->query->data[-2] = 0xff & (so->query->end >> 8);
4886         so->query->data[-1] = 0xff & (so->query->end >> 0);
4887
4888         qsrc = &so->query->data[-2] + so->qout;
4889         qend = so->query->end + 2;
4890
4891         while (so->qout < qend) {
4892                 if (0 > (n = send(so->tcp, (void *)&qsrc[so->qout], qend - so->qout, 0)))
4893                         return dns_soerr();
4894
4895                 so->qout += n;
4896                 so->stat.tcp.sent.bytes += n;
4897         }
4898
4899         so->stat.tcp.sent.count++;
4900
4901         return 0;
4902 } /* dns_so_tcp_send() */
4903
4904
4905 static int dns_so_tcp_recv(struct dns_socket *so) {
4906         unsigned char *asrc;
4907         size_t aend, alen;
4908         int error;
4909         long n;
4910
4911         aend = so->alen + 2;
4912
4913         while (so->apos < aend) {
4914                 asrc = &so->answer->data[-2];
4915
4916                 if (0 > (n = recv(so->tcp, (void *)&asrc[so->apos], aend - so->apos, 0)))
4917                         return dns_soerr();
4918                 else if (n == 0)
4919                         return DNS_EUNKNOWN;    /* FIXME */
4920
4921                 so->apos += n;
4922                 so->stat.tcp.rcvd.bytes += n;
4923
4924                 if (so->alen == 0 && so->apos >= 2) {
4925                         alen = ((0xff & so->answer->data[-2]) << 8)
4926                              | ((0xff & so->answer->data[-1]) << 0);
4927
4928                         if ((error = dns_so_newanswer(so, alen)))
4929                                 return error;
4930
4931                         so->alen = alen;
4932                         aend = alen + 2;
4933                 }
4934         }
4935
4936         so->answer->end = so->alen;
4937         so->stat.tcp.rcvd.count++;
4938
4939         return 0;
4940 } /* dns_so_tcp_recv() */
4941
4942
4943 int dns_so_check(struct dns_socket *so) {
4944         int error;
4945         long n;
4946
4947 retry:
4948         switch (so->state) {
4949         case DNS_SO_UDP_INIT:
4950                 so->state++;
4951         case DNS_SO_UDP_CONN:
4952                 if (0 != connect(so->udp, (struct sockaddr *)&so->remote, dns_sa_len(&so->remote)))
4953                         goto soerr;
4954
4955                 so->state++;
4956         case DNS_SO_UDP_SEND:
4957                 if (0 > (n = send(so->udp, (void *)so->query->data, so->query->end, 0)))
4958                         goto soerr;
4959
4960                 so->stat.udp.sent.bytes += n;
4961                 so->stat.udp.sent.count++;
4962
4963                 so->state++;
4964         case DNS_SO_UDP_RECV:
4965                 if (0 > (n = recv(so->udp, (void *)so->answer->data, so->answer->size, 0)))
4966                         goto soerr;
4967
4968                 so->stat.udp.rcvd.bytes += n;
4969                 so->stat.udp.rcvd.count++;
4970
4971                 if ((so->answer->end = n) < 12)
4972                         goto trash;
4973
4974                 if ((error = dns_so_verify(so, so->answer)))
4975                         goto trash;
4976
4977                 so->state++;
4978         case DNS_SO_UDP_DONE:
4979                 if (!dns_header(so->answer)->tc || so->type == SOCK_DGRAM)
4980                         return 0;
4981
4982                 so->state++;
4983         case DNS_SO_TCP_INIT:
4984                 if ((error = dns_so_closefd(so, &so->tcp)))
4985                         goto error;
4986
4987                 if (-1 == (so->tcp = dns_socket((struct sockaddr *)&so->local, SOCK_STREAM, &error)))
4988                         goto error;
4989
4990                 so->state++;
4991         case DNS_SO_TCP_CONN:
4992                 if (0 != connect(so->tcp, (struct sockaddr *)&so->remote, dns_sa_len(&so->remote))) {
4993                         if (dns_soerr() != DNS_EISCONN)
4994                                 goto soerr;
4995                 }
4996
4997                 so->state++;
4998         case DNS_SO_TCP_SEND:
4999                 if ((error = dns_so_tcp_send(so)))
5000                         goto error;
5001
5002                 so->state++;
5003         case DNS_SO_TCP_RECV:
5004                 if ((error = dns_so_tcp_recv(so)))
5005                         goto error;
5006
5007                 so->state++;
5008         case DNS_SO_TCP_DONE:
5009                 if ((error = dns_so_closefd(so, &so->tcp)))
5010                         goto error;
5011
5012                 if (so->answer->end < 12)
5013                         return DNS_EILLEGAL;
5014
5015                 if ((error = dns_so_verify(so, so->answer)))
5016                         goto error;
5017
5018                 return 0;
5019         default:
5020                 error   = DNS_EUNKNOWN;
5021
5022                 goto error;
5023         } /* switch() */
5024
5025 trash:
5026         goto retry;
5027 soerr:
5028         error   = dns_soerr();
5029
5030         goto error;
5031 error:
5032         switch (error) {
5033         case DNS_EINTR:
5034                 goto retry;
5035         case DNS_EINPROGRESS:
5036                 /* FALL THROUGH */
5037         case DNS_EALREADY:
5038                 /* FALL THROUGH */
5039 #if DNS_EWOULDBLOCK != DNS_EAGAIN
5040         case DNS_EWOULDBLOCK:
5041                 /* FALL THROUGH */
5042 #endif
5043                 error   = DNS_EAGAIN;
5044
5045                 break;
5046         } /* switch() */
5047
5048         return error;
5049 } /* dns_so_check() */
5050
5051
5052 struct dns_packet *dns_so_fetch(struct dns_socket *so, int *error) {
5053         struct dns_packet *answer;
5054
5055         switch (so->state) {
5056         case DNS_SO_UDP_DONE:
5057         case DNS_SO_TCP_DONE:
5058                 answer          = so->answer;
5059                 so->answer      = 0;
5060
5061                 return answer;
5062         default:
5063                 *error  = DNS_EUNKNOWN;
5064
5065                 return 0;
5066         }
5067 } /* dns_so_fetch() */
5068
5069
5070 struct dns_packet *dns_so_query(struct dns_socket *so, struct dns_packet *Q, struct sockaddr *host, int *error_) {
5071         struct dns_packet *A;
5072         int error;
5073
5074         if (!so->state) {
5075                 if ((error = dns_so_submit(so, Q, host)))
5076                         goto error;
5077         }
5078
5079         if ((error = dns_so_check(so)))
5080                 goto error;
5081
5082         if (!(A = dns_so_fetch(so, &error)))
5083                 goto error;
5084
5085         dns_so_reset(so);
5086
5087         return A;
5088 error:
5089         *error_ = error;
5090
5091         return 0;
5092 } /* dns_so_query() */
5093
5094
5095 time_t dns_so_elapsed(struct dns_socket *so) {
5096         return dns_elapsed(so->began);
5097 } /* dns_so_elapsed() */
5098
5099
5100 void dns_so_clear(struct dns_socket *so) {
5101         dns_so_closefds(so, DNS_SO_CLOSE_OLD);
5102 } /* dns_so_clear() */
5103
5104
5105 static int dns_so_events2(struct dns_socket *so, enum dns_events type) {
5106         int events = 0;
5107
5108         switch (so->state) {
5109         case DNS_SO_UDP_CONN:
5110         case DNS_SO_UDP_SEND:
5111                 events |= DNS_POLLOUT;
5112
5113                 break;
5114         case DNS_SO_UDP_RECV:
5115                 events |= DNS_POLLIN;
5116
5117                 break;
5118         case DNS_SO_TCP_CONN:
5119         case DNS_SO_TCP_SEND:
5120                 events |= DNS_POLLOUT;
5121
5122                 break;
5123         case DNS_SO_TCP_RECV:
5124                 events |= DNS_POLLIN;
5125
5126                 break;
5127         } /* switch() */
5128
5129         switch (type) {
5130         case DNS_LIBEVENT:
5131                 return DNS_POLL2EV(events);
5132         default:
5133                 return events;
5134         } /* switch() */
5135 } /* dns_so_events2() */
5136
5137
5138 int dns_so_events(struct dns_socket *so) {
5139         return dns_so_events2(so, so->opts.events);
5140 } /* dns_so_events() */
5141
5142
5143 int dns_so_pollfd(struct dns_socket *so) {
5144         switch (so->state) {
5145         case DNS_SO_UDP_CONN:
5146         case DNS_SO_UDP_SEND:
5147         case DNS_SO_UDP_RECV:
5148                 return so->udp;
5149         case DNS_SO_TCP_CONN:
5150         case DNS_SO_TCP_SEND:
5151         case DNS_SO_TCP_RECV:
5152                 return so->tcp;
5153         } /* switch() */
5154
5155         return -1;
5156 } /* dns_so_pollfd() */
5157
5158
5159 int dns_so_poll(struct dns_socket *so, int timeout) {
5160         return dns_poll(dns_so_pollfd(so), dns_so_events2(so, DNS_SYSPOLL), timeout);
5161 } /* dns_so_poll() */
5162
5163
5164 const struct dns_stat *dns_so_stat(struct dns_socket *so) {
5165         return &so->stat;
5166 } /* dns_so_stat() */
5167
5168
5169 /*
5170  * R E S O L V E R  R O U T I N E S
5171  *
5172  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5173
5174 enum dns_res_state {
5175         DNS_R_INIT,
5176         DNS_R_GLUE,
5177         DNS_R_SWITCH,           /* (B)IND, (F)ILE, (C)ACHE */
5178
5179         DNS_R_FILE,             /* Lookup in local hosts database */
5180
5181         DNS_R_CACHE,            /* Lookup in application cache */
5182         DNS_R_SUBMIT,
5183         DNS_R_CHECK,
5184         DNS_R_FETCH,
5185
5186         DNS_R_BIND,             /* Lookup in the network */
5187         DNS_R_SEARCH,
5188         DNS_R_HINTS,
5189         DNS_R_ITERATE,
5190         DNS_R_FOREACH_NS,
5191         DNS_R_RESOLV0_NS,       /* Prologue: Setup next frame and recurse */
5192         DNS_R_RESOLV1_NS,       /* Epilog: Inspect answer */
5193         DNS_R_FOREACH_A,
5194         DNS_R_QUERY_A,
5195         DNS_R_CNAME0_A,
5196         DNS_R_CNAME1_A,
5197
5198         DNS_R_FINISH,
5199         DNS_R_SMART0_A,
5200         DNS_R_SMART1_A,
5201         DNS_R_DONE,
5202         DNS_R_SERVFAIL,
5203 }; /* enum dns_res_state */
5204
5205
5206 #define DNS_R_MAXDEPTH  8
5207 #define DNS_R_ENDFRAME  (DNS_R_MAXDEPTH - 1)
5208
5209 struct dns_resolver {
5210         struct dns_socket so;
5211
5212         struct dns_resolv_conf *resconf;
5213         struct dns_hosts *hosts;
5214         struct dns_hints *hints;
5215         struct dns_cache *cache;
5216
5217         dns_atomic_t refcount;
5218
5219         /* Reset zeroes everything below here. */
5220
5221         char qname[DNS_D_MAXNAME + 1];
5222         size_t qlen;
5223
5224         enum dns_type qtype;
5225         enum dns_class qclass;
5226
5227         time_t began;
5228
5229         dns_resconf_i_t search;
5230
5231         struct dns_rr_i smart;
5232
5233         struct dns_res_frame {
5234                 enum dns_res_state state;
5235
5236                 int error;
5237                 int which;      /* (B)IND, (F)ILE; index into resconf->lookup */
5238
5239                 unsigned attempts;
5240
5241                 struct dns_packet *query, *answer, *hints;
5242
5243                 struct dns_rr_i hints_i, hints_j;
5244                 struct dns_rr hints_ns, ans_cname;
5245         } stack[DNS_R_MAXDEPTH];
5246
5247         unsigned sp;
5248 }; /* struct dns_resolver */
5249
5250
5251 static int dns_res_tcp2type(int tcp) {
5252         switch (tcp) {
5253         case DNS_RESCONF_TCP_ONLY:
5254                 return SOCK_STREAM;
5255         case DNS_RESCONF_TCP_DISABLE:
5256                 return SOCK_DGRAM;
5257         default:
5258                 return 0;
5259         }
5260 } /* dns_res_tcp2type() */
5261
5262 struct dns_resolver *dns_res_open(struct dns_resolv_conf *resconf, struct dns_hosts *hosts, struct dns_hints *hints, struct dns_cache *cache, const struct dns_options *opts, int *error_) {
5263         static const struct dns_resolver R_initializer
5264                 = { .refcount = 1, };
5265         struct dns_resolver *R  = 0;
5266         int type, error;
5267
5268         /*
5269          * Grab ref count early because the caller may have passed us a mortal
5270          * reference, and we want to do the right thing if we return early
5271          * from an error.
5272          */ 
5273         if (resconf)
5274                 dns_resconf_acquire(resconf);
5275         if (hosts)
5276                 dns_hosts_acquire(hosts);
5277         if (hints)
5278                 dns_hints_acquire(hints);
5279         if (cache)
5280                 dns_cache_acquire(cache);
5281
5282         /*
5283          * Don't try to load it ourselves because a NULL object might be an
5284          * error from, say, dns_resconf_root(), and loading
5285          * dns_resconf_local() by default would create undesirable surpises.
5286          */
5287         if (!resconf || !hosts || !hints)
5288                 goto error;
5289
5290         if (!(R = malloc(sizeof *R)))
5291                 goto syerr;
5292
5293         *R      = R_initializer;
5294         type    = dns_res_tcp2type(resconf->options.tcp);
5295
5296         if (!dns_so_init(&R->so, (struct sockaddr *)&resconf->iface, type, opts, &error))
5297                 goto error;
5298
5299         R->resconf      = resconf;
5300         R->hosts        = hosts;
5301         R->hints        = hints;
5302         R->cache        = cache;
5303
5304         return R;
5305 syerr:
5306         error   = dns_syerr();
5307 error:
5308         *error_ = error;
5309
5310         dns_res_close(R);
5311
5312         dns_resconf_close(resconf);
5313         dns_hosts_close(hosts);
5314         dns_hints_close(hints);
5315         dns_cache_close(cache);
5316
5317         return 0;
5318 } /* dns_res_open() */
5319
5320
5321 struct dns_resolver *dns_res_stub(const struct dns_options *opts, int *error) {
5322         struct dns_resolv_conf *resconf = 0;
5323         struct dns_hosts *hosts         = 0;
5324         struct dns_hints *hints         = 0;
5325         struct dns_resolver *res        = 0;
5326
5327         if (!(resconf = dns_resconf_local(error)))
5328                 goto epilog;
5329
5330         if (!(hosts = dns_hosts_local(error)))
5331                 goto epilog;
5332
5333         if (!(hints = dns_hints_local(resconf, error)))
5334                 goto epilog;
5335
5336         if (!(res = dns_res_open(resconf, hosts, hints, NULL, opts, error)))
5337                 goto epilog;
5338
5339 epilog:
5340         dns_resconf_close(resconf);
5341         dns_hosts_close(hosts);
5342         dns_hints_close(hints);
5343
5344         return res;
5345 } /* dns_res_stub() */
5346
5347
5348 static void dns_res_reset_frame(struct dns_resolver *R __UNUSED__, struct dns_res_frame *frame) {
5349         free(frame->query);
5350         free(frame->answer);
5351         free(frame->hints);
5352
5353         memset(frame, '\0', sizeof *frame);
5354 } /* dns_res_reset_frame() */
5355
5356
5357 void dns_res_reset(struct dns_resolver *R) {
5358         unsigned i;
5359
5360         dns_so_reset(&R->so);
5361
5362         for (i = 0; i < lengthof(R->stack); i++)
5363                 dns_res_reset_frame(R, &R->stack[i]);
5364
5365         memset(&R->qname, '\0', sizeof *R - offsetof(struct dns_resolver, qname));
5366 } /* dns_res_reset() */
5367
5368
5369 void dns_res_close(struct dns_resolver *R) {
5370         if (!R || 1 < dns_res_release(R))
5371                 return;
5372
5373         dns_res_reset(R);
5374
5375         dns_so_destroy(&R->so);
5376
5377         dns_hints_close(R->hints);
5378         dns_hosts_close(R->hosts);
5379         dns_resconf_close(R->resconf);
5380         dns_cache_close(R->cache);
5381
5382         free(R);
5383 } /* dns_res_close() */
5384
5385
5386 unsigned dns_res_acquire(struct dns_resolver *R) {
5387         return dns_atomic_inc(&R->refcount);
5388 } /* dns_res_acquire() */
5389
5390
5391 unsigned dns_res_release(struct dns_resolver *R) {
5392         return dns_atomic_dec(&R->refcount);
5393 } /* dns_res_release() */
5394
5395
5396 struct dns_resolver *dns_res_mortal(struct dns_resolver *res) {
5397         if (res)
5398                 dns_res_release(res);
5399         return res;
5400 } /* dns_res_mortal() */
5401
5402
5403 static struct dns_packet *dns_res_merge(struct dns_packet *P0, struct dns_packet *P1, int *error_) {
5404         size_t bufsiz   = P0->end + P1->end;
5405         struct dns_packet *P[3] = { P0, P1, 0 };
5406         struct dns_rr rr[3];
5407         int error, copy, i;
5408         enum dns_section section;
5409
5410 retry:
5411         if (!(P[2] = dns_p_make(bufsiz, &error)))
5412                 goto error;
5413
5414         dns_rr_foreach(&rr[0], P[0], .section = DNS_S_QD) {
5415                 if ((error = dns_rr_copy(P[2], &rr[0], P[0])))
5416                         goto error;
5417         }
5418
5419         for (section = DNS_S_AN; (DNS_S_ALL & section); section <<= 1) {
5420                 for (i = 0; i < 2; i++) {
5421                         dns_rr_foreach(&rr[i], P[i], .section = section) {
5422                                 copy    = 1;
5423
5424                                 dns_rr_foreach(&rr[2], P[2], .type = rr[i].type, .section = (DNS_S_ALL & ~DNS_S_QD)) {
5425                                         if (0 == dns_rr_cmp(&rr[i], P[i], &rr[2], P[2])) {
5426                                                 copy    = 0;
5427
5428                                                 break;
5429                                         }
5430                                 }
5431
5432                                 if (copy && (error = dns_rr_copy(P[2], &rr[i], P[i]))) {
5433                                         if (error == DNS_ENOBUFS && bufsiz < 65535) {
5434                                                 free(P[2]); P[2] = 0;
5435
5436                                                 bufsiz  = MAX(65535, bufsiz * 2);
5437
5438                                                 goto retry;
5439                                         }
5440
5441                                         goto error;
5442                                 }
5443                         } /* foreach(rr) */
5444                 } /* foreach(packet) */
5445         } /* foreach(section) */
5446
5447         return P[2];
5448 error:
5449         *error_ = error;
5450
5451         free(P[2]);
5452
5453         return 0;
5454 } /* dns_res_merge() */
5455
5456
5457 static struct dns_packet *dns_res_glue(struct dns_resolver *R, struct dns_packet *Q) {
5458         struct dns_packet *P    = dns_p_new(512);
5459         char qname[DNS_D_MAXNAME + 1];
5460         size_t qlen;
5461         enum dns_type qtype;
5462         struct dns_rr rr;
5463         unsigned sp;
5464         int error;
5465
5466         if (!(qlen = dns_d_expand(qname, sizeof qname, 12, Q, &error))
5467         ||  qlen >= sizeof qname)
5468                 return 0;
5469
5470         if (!(qtype = dns_rr_type(12, Q)))
5471                 return 0;
5472
5473         if ((error = dns_p_push(P, DNS_S_QD, qname, strlen(qname), qtype, DNS_C_IN, 0, 0)))
5474                 return 0;
5475
5476         for (sp = 0; sp <= R->sp; sp++) {
5477                 if (!R->stack[sp].answer)
5478                         continue;
5479
5480                 dns_rr_foreach(&rr, R->stack[sp].answer, .name = qname, .type = qtype, .section = (DNS_S_ALL & ~DNS_S_QD)) {
5481                         rr.section      = DNS_S_AN;
5482
5483                         if ((error = dns_rr_copy(P, &rr, R->stack[sp].answer)))
5484                                 return 0;
5485                 }
5486         }
5487
5488         if (dns_p_count(P, DNS_S_AN) > 0)
5489                 goto copy;
5490
5491         /* Otherwise, look for a CNAME */
5492         for (sp = 0; sp <= R->sp; sp++) {
5493                 if (!R->stack[sp].answer)
5494                         continue;
5495
5496                 dns_rr_foreach(&rr, R->stack[sp].answer, .name = qname, .type = DNS_T_CNAME, .section = (DNS_S_ALL & ~DNS_S_QD)) {
5497                         rr.section      = DNS_S_AN;
5498
5499                         if ((error = dns_rr_copy(P, &rr, R->stack[sp].answer)))
5500                                 return 0;
5501                 }
5502         }
5503
5504         if (!dns_p_count(P, DNS_S_AN))
5505                 return 0;
5506
5507 copy:
5508         return dns_p_copy(dns_p_make(P->end, &error), P);
5509 } /* dns_res_glue() */
5510
5511
5512 static struct dns_packet *dns_res_mkquery(struct dns_resolver *R, const char *qname, enum dns_type qtype, enum dns_class qclass, int *error_) {
5513         struct dns_packet *Q    = 0;
5514         int error;
5515
5516         if (!(Q = dns_p_init(malloc(DNS_P_QBUFSIZ), DNS_P_QBUFSIZ)))
5517                 goto syerr;
5518
5519         if ((error = dns_p_push(Q, DNS_S_QD, qname, strlen(qname), qtype, qclass, 0, 0)))
5520                 goto error;
5521
5522         dns_header(Q)->rd       = !R->resconf->options.recurse;
5523
5524         return Q;
5525 syerr:
5526         error   = dns_syerr();
5527 error:
5528         free(Q);
5529
5530         *error_ = error;
5531
5532         return 0;
5533 } /* dns_res_mkquery() */
5534
5535
5536 /*
5537  * Sort NS records by three criteria:
5538  *
5539  *      1) Whether glue is present.
5540  *      2) Whether glue record is original or of recursive lookup.
5541  *      3) Randomly shuffle records which share the above criteria.
5542  *
5543  * NOTE: Assumes only NS records passed, AND ASSUMES no new NS records will
5544  *       be added during an iteration.
5545  *
5546  * FIXME: Only groks A glue, not AAAA glue.
5547  */
5548 static int dns_res_nameserv_cmp(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) {
5549         _Bool glued[2]  = { 0 };
5550         struct dns_ns ns;
5551         struct dns_rr x, y;
5552         int cmp, error;
5553
5554         if (!(error = dns_ns_parse(&ns, a, P)))
5555                 if (!(glued[0] = !!dns_rr_grep(&x, 1, dns_rr_i_new(P, .section = (DNS_S_ALL & ~DNS_S_QD), .name = ns.host, .type = DNS_T_A), P, &error)))
5556                         x.dn.p  = 0;
5557
5558         if (!(error = dns_ns_parse(&ns, b, P)))
5559                 if (!(glued[1] = !!dns_rr_grep(&y, 1, dns_rr_i_new(P, .section = (DNS_S_ALL & ~DNS_S_QD), .name = ns.host, .type = DNS_T_A), P, &error)))
5560                         y.dn.p  = 0;
5561
5562         if ((cmp = glued[1] - glued[0]))
5563                 return cmp;
5564         else if ((cmp = (dns_rr_offset(&y) < i->args[0]) - (dns_rr_offset(&x) < i->args[0])))
5565                 return cmp;
5566         else
5567                 return dns_rr_i_shuffle(a, b, i, P);
5568 } /* dns_res_nameserv_cmp() */
5569
5570
5571 #define goto(sp, i)     \
5572         do { R->stack[(sp)].state = (i); goto exec; } while (0)
5573
5574 static int dns_res_exec(struct dns_resolver *R) {
5575         struct dns_res_frame *F;
5576         struct dns_packet *P;
5577         char host[DNS_D_MAXNAME + 1];
5578         size_t len;
5579         struct dns_rr rr;
5580         struct sockaddr_in sin;
5581         int error;
5582
5583 exec:
5584
5585         F       = &R->stack[R->sp];
5586
5587         switch (F->state) {
5588         case DNS_R_INIT:
5589                 F->state++;
5590         case DNS_R_GLUE:
5591                 if (R->sp == 0)
5592                         goto(R->sp, DNS_R_SWITCH);
5593
5594                 assert(F->query);
5595
5596                 if (!(F->answer = dns_res_glue(R, F->query)))
5597                         goto(R->sp, DNS_R_SWITCH);
5598
5599                 if (!(len = dns_d_expand(host, sizeof host, 12, F->query, &error)))
5600                         goto error;
5601                 else if (len >= sizeof host)
5602                         goto toolong;
5603
5604                 dns_rr_foreach(&rr, F->answer, .name = host, .type = dns_rr_type(12, F->query), .section = DNS_S_AN) {
5605                         goto(R->sp, DNS_R_FINISH);
5606                 }
5607
5608                 dns_rr_foreach(&rr, F->answer, .name = host, .type = DNS_T_CNAME, .section = DNS_S_AN) {
5609                         F->ans_cname    = rr;
5610
5611                         goto(R->sp, DNS_R_CNAME0_A);
5612                 }
5613
5614                 F->state++;
5615         case DNS_R_SWITCH:
5616                 while (F->which < (int)sizeof R->resconf->lookup) {
5617                         switch (R->resconf->lookup[F->which++]) {
5618                         case 'b': case 'B':
5619                                 goto(R->sp, DNS_R_BIND);
5620                         case 'f': case 'F':
5621                                 goto(R->sp, DNS_R_FILE);
5622                         case 'c': case 'C':
5623                                 if (R->cache)
5624                                         goto(R->sp, DNS_R_CACHE);
5625
5626                                 break;
5627                         default:
5628                                 break;
5629                         }
5630                 }
5631
5632                 goto(R->sp, DNS_R_SERVFAIL);    /* FIXME: Right behavior? */
5633         case DNS_R_FILE:
5634                 if (R->sp > 0) {
5635                         free(F->answer);
5636
5637                         if (!(F->answer = dns_hosts_query(R->hosts, F->query, &error)))
5638                                 goto error;
5639
5640                         if (dns_p_count(F->answer, DNS_S_AN) > 0)
5641                                 goto(R->sp, DNS_R_FINISH);
5642
5643                         free(F->answer); F->answer = 0;
5644                 } else {
5645                         R->search       = 0;
5646
5647                         while ((len = dns_resconf_search(host, sizeof host, R->qname, R->qlen, R->resconf, &R->search))) {
5648 /*
5649  * FIXME: Some sort of bug, either with this code or with GCC 3.3.5 on
5650  * OpenBSD 4.4, overwites the stack guard. If the bug is in this file, it
5651  * appears to be localized somewhere around here. It can also be mitigated
5652  * in dns_hosts_query(). In any event, the bug manifests only when using
5653  * compound literals. alloca(), malloc(), calloc(), etc, all work fine. 
5654  * Valgrind (tested on Linux) cannot detect any issues, but stack issues are
5655  * not Valgrind's forte. Neither can I spot anything in the assembly, but
5656  * that's not my forte.
5657  */
5658 #if __OpenBSD__ && __GNUC__
5659                                 struct dns_packet *query        = __builtin_alloca(DNS_P_QBUFSIZ);
5660
5661                                 dns_p_init(query, DNS_P_QBUFSIZ);
5662 #else
5663                                 struct dns_packet *query        = dns_p_new(DNS_P_QBUFSIZ);
5664 #endif
5665
5666                                 if ((error = dns_p_push(query, DNS_S_QD, host, len, R->qtype, R->qclass, 0, 0)))
5667                                         goto error;
5668
5669                                 free(F->answer);
5670
5671                                 if (!(F->answer = dns_hosts_query(R->hosts, query, &error)))
5672                                         goto error;
5673
5674                                 if (dns_p_count(F->answer, DNS_S_AN) > 0)
5675                                         goto(R->sp, DNS_R_FINISH);
5676
5677                                 free(F->answer); F->answer = 0;
5678                         }
5679                 }
5680
5681                 goto(R->sp, DNS_R_SWITCH);
5682         case DNS_R_CACHE:
5683                 error = 0;
5684
5685                 if (!F->query && !(F->query = dns_res_mkquery(R, R->qname, R->qtype, R->qclass, &error)))
5686                         goto error;
5687
5688                 free(F->answer);
5689
5690                 if ((F->answer = R->cache->query(F->query, R->cache, &error))) {
5691                         if (dns_p_count(F->answer, DNS_S_AN) > 0)
5692                                 goto(R->sp, DNS_R_FINISH);
5693
5694                         free(F->answer); F->answer = 0;
5695
5696                         goto(R->sp, DNS_R_SWITCH);
5697                 } else if (error)
5698                         goto error;
5699
5700                 F->state++;
5701         case DNS_R_SUBMIT:
5702                 if ((error = R->cache->submit(F->query, R->cache)))
5703                         goto error;
5704
5705                 F->state++;
5706         case DNS_R_CHECK:
5707                 if ((error = R->cache->check(R->cache)))
5708                         goto error;
5709
5710                 F->state++;
5711         case DNS_R_FETCH:
5712                 error = 0;
5713
5714                 free(F->answer);
5715
5716                 if ((F->answer = R->cache->fetch(R->cache, &error))) {
5717                         if (dns_p_count(F->answer, DNS_S_AN) > 0)
5718                                 goto(R->sp, DNS_R_FINISH);
5719
5720                         free(F->answer); F->answer = 0;
5721
5722                         goto(R->sp, DNS_R_SWITCH);
5723                 } else if (error)
5724                         goto error;
5725
5726                 goto(R->sp, DNS_R_SWITCH);
5727         case DNS_R_BIND:
5728                 if (R->sp > 0) {
5729                         assert(F->query);
5730
5731                         goto(R->sp, DNS_R_HINTS);
5732                 }
5733
5734                 R->search       = 0;
5735
5736                 F->state++;
5737         case DNS_R_SEARCH:
5738                 if (!(len = dns_resconf_search(host, sizeof host, R->qname, R->qlen, R->resconf, &R->search)))
5739                         goto(R->sp, DNS_R_SWITCH);
5740
5741                 if (!(P = dns_p_make(DNS_P_QBUFSIZ, &error)))
5742                         goto error;
5743
5744                 dns_header(P)->rd       = !R->resconf->options.recurse;
5745
5746                 free(F->query); F->query = P;
5747
5748                 if ((error = dns_p_push(F->query, DNS_S_QD, host, len, R->qtype, R->qclass, 0, 0)))
5749                         goto error;
5750
5751                 F->state++;
5752         case DNS_R_HINTS:
5753                 if (!(F->hints = dns_hints_query(R->hints, F->query, &error)))
5754                         goto error;
5755
5756                 F->state++;
5757         case DNS_R_ITERATE:
5758                 dns_rr_i_init(&F->hints_i, F->hints);
5759
5760                 F->hints_i.section      = DNS_S_AUTHORITY;
5761                 F->hints_i.type         = DNS_T_NS;
5762                 F->hints_i.sort         = &dns_res_nameserv_cmp;
5763                 F->hints_i.args[0]      = F->hints->end;
5764
5765                 F->state++;
5766         case DNS_R_FOREACH_NS:
5767                 dns_rr_i_save(&F->hints_i);
5768
5769                 /* Load our next nameserver host. */
5770                 if (!dns_rr_grep(&F->hints_ns, 1, &F->hints_i, F->hints, &error)) {
5771                         if (++F->attempts < R->resconf->options.attempts)
5772                                 goto(R->sp, DNS_R_ITERATE);
5773
5774                         goto(R->sp, DNS_R_SWITCH);
5775                 }
5776
5777                 dns_rr_i_init(&F->hints_j, F->hints);
5778
5779                 /* Assume there are glue records */
5780                 goto(R->sp, DNS_R_FOREACH_A);
5781         case DNS_R_RESOLV0_NS:
5782                 /* Have we reached our max depth? */
5783                 if (&F[1] >= endof(R->stack))
5784                         goto(R->sp, DNS_R_FOREACH_NS);
5785
5786                 dns_res_reset_frame(R, &F[1]);
5787
5788                 if (!(F[1].query = dns_p_make(DNS_P_QBUFSIZ, &error)))
5789                         goto error;
5790
5791                 if ((error = dns_ns_parse((struct dns_ns *)host, &F->hints_ns, F->hints)))
5792                         goto error;
5793
5794                 if ((error = dns_p_push(F[1].query, DNS_S_QD, host, strlen(host), DNS_T_A, DNS_C_IN, 0, 0)))
5795                         goto error;
5796
5797                 F->state++;
5798
5799                 goto(++R->sp, DNS_R_INIT);
5800         case DNS_R_RESOLV1_NS:
5801                 if (!(len = dns_d_expand(host, sizeof host, 12, F[1].query, &error)))
5802                         goto error;
5803                 else if (len >= sizeof host)
5804                         goto toolong;
5805
5806                 dns_rr_foreach(&rr, F[1].answer, .name = host, .type = DNS_T_A, .section = (DNS_S_ALL & ~DNS_S_QD)) {
5807                         rr.section      = DNS_S_AR;
5808
5809                         if ((error = dns_rr_copy(F->hints, &rr, F[1].answer)))
5810                                 goto error;
5811
5812                         dns_rr_i_rewind(&F->hints_i);   /* Now there's glue. */
5813                 }
5814
5815                 goto(R->sp, DNS_R_FOREACH_NS);
5816         case DNS_R_FOREACH_A:
5817                 /*
5818                  * NOTE: Iterator initialized in DNS_R_FOREACH_NS because
5819                  * this state is re-entrant, but we need to reset
5820                  * .name to a valid pointer each time.
5821                  */
5822                 if ((error = dns_ns_parse((struct dns_ns *)host, &F->hints_ns, F->hints)))
5823                         goto error;
5824
5825                 F->hints_j.name         = host;
5826                 F->hints_j.type         = DNS_T_A;
5827                 F->hints_j.section      = DNS_S_ALL & ~DNS_S_QD;
5828
5829                 if (!dns_rr_grep(&rr, 1, &F->hints_j, F->hints, &error)) {
5830                         if (!dns_rr_i_count(&F->hints_j))
5831                                 goto(R->sp, DNS_R_RESOLV0_NS);
5832
5833                         goto(R->sp, DNS_R_FOREACH_NS);
5834                 }
5835
5836                 sin.sin_family  = AF_INET;
5837
5838                 if ((error = dns_a_parse((struct dns_a *)&sin.sin_addr, &rr, F->hints)))
5839                         goto error;
5840
5841                 if (R->sp == 0)
5842                         sin.sin_port = dns_hints_port(R->hints, AF_INET, (struct sockaddr *)&sin.sin_addr);
5843                 else
5844                         sin.sin_port = htons(53);
5845
5846                 if (DNS_DEBUG) {
5847                         char addr[INET_ADDRSTRLEN + 1];
5848                         dns_a_print(addr, sizeof addr, (struct dns_a *)&sin.sin_addr);
5849                         DNS_SHOW(F->query, "ASKING: %s/%s @ DEPTH: %u)", host, addr, R->sp);
5850                 }
5851
5852                 if ((error = dns_so_submit(&R->so, F->query, (struct sockaddr *)&sin)))
5853                         goto error;
5854
5855                 F->state++;
5856         case DNS_R_QUERY_A:
5857                 if (dns_so_elapsed(&R->so) >= (time_t)R->resconf->options.timeout)
5858                         goto(R->sp, DNS_R_FOREACH_A);
5859
5860                 if ((error = dns_so_check(&R->so)))
5861                         goto error;
5862
5863                 free(F->answer);
5864
5865                 if (!(F->answer = dns_so_fetch(&R->so, &error)))
5866                         goto error;
5867
5868                 if (DNS_DEBUG) {
5869                         DNS_SHOW(F->answer, "ANSWER @ DEPTH: %u)", R->sp);
5870                 }
5871
5872                 if ((error = dns_rr_parse(&rr, 12, F->query)))
5873                         goto error;
5874
5875                 if (!(len = dns_d_expand(host, sizeof host, rr.dn.p, F->query, &error)))
5876                         goto error;
5877                 else if (len >= sizeof host)
5878                         goto toolong;
5879
5880                 dns_rr_foreach(&rr, F->answer, .section = DNS_S_AN, .name = host, .type = rr.type) {
5881                         goto(R->sp, DNS_R_FINISH);      /* Found */
5882                 }
5883
5884                 dns_rr_foreach(&rr, F->answer, .section = DNS_S_AN, .name = host, .type = DNS_T_CNAME) {
5885                         F->ans_cname    = rr;
5886
5887                         goto(R->sp, DNS_R_CNAME0_A);
5888                 }
5889
5890                 if (!R->resconf->options.recurse)
5891                         goto(R->sp, DNS_R_SWITCH);
5892
5893                 dns_rr_foreach(&rr, F->answer, .section = DNS_S_NS, .type = DNS_T_NS) {
5894                         free(F->hints);
5895
5896                         F->hints        = F->answer;
5897                         F->answer       = 0;
5898
5899                         goto(R->sp, DNS_R_ITERATE);
5900                 }
5901
5902                 /* XXX: Should this go further up? */
5903                 if (dns_header(F->answer)->aa)
5904                         goto(R->sp, DNS_R_FINISH);
5905
5906                 goto(R->sp, DNS_R_FOREACH_A);
5907         case DNS_R_CNAME0_A:
5908                 if (&F[1] >= endof(R->stack))
5909                         goto(R->sp, DNS_R_FINISH);
5910
5911                 if ((error = dns_cname_parse((struct dns_cname *)host, &F->ans_cname, F->answer)))
5912                         goto error;
5913
5914                 dns_res_reset_frame(R, &F[1]);
5915
5916                 if (!(F[1].query = dns_p_make(DNS_P_QBUFSIZ, &error)))
5917                         goto error;
5918
5919                 if ((error = dns_p_push(F[1].query, DNS_S_QD, host, strlen(host), dns_rr_type(12, F->query), DNS_C_IN, 0, 0)))
5920                         goto error;
5921
5922                 F->state++;
5923
5924                 goto(++R->sp, DNS_R_INIT);
5925         case DNS_R_CNAME1_A:
5926                 if (!(P = dns_res_merge(F->answer, F[1].answer, &error)))
5927                         goto error;
5928
5929                 free(F->answer); F->answer = P;
5930
5931                 goto(R->sp, DNS_R_FINISH);
5932         case DNS_R_FINISH:
5933                 assert(F->answer);
5934
5935                 if (!R->resconf->options.smart || R->sp > 0)
5936                         goto(R->sp, DNS_R_DONE);
5937
5938                 R->smart.section        = DNS_S_AN;
5939                 R->smart.type           = R->qtype;
5940
5941                 dns_rr_i_init(&R->smart, F->answer);
5942
5943                 F->state++;
5944         case DNS_R_SMART0_A:
5945                 if (&F[1] >= endof(R->stack))
5946                         goto(R->sp, DNS_R_DONE);
5947
5948                 while (dns_rr_grep(&rr, 1, &R->smart, F->answer, &error)) {
5949                         union {
5950                                 struct dns_ns ns;
5951                                 struct dns_mx mx;
5952                                 struct dns_srv srv;
5953                         } rd;
5954                         const char *qname;
5955                         enum dns_type qtype;
5956                         enum dns_class qclass;
5957
5958                         switch (rr.type) {
5959                         case DNS_T_NS:
5960                                 if ((error = dns_ns_parse(&rd.ns, &rr, F->answer)))
5961                                         goto error;
5962
5963                                 qname   = rd.ns.host;
5964                                 qtype   = DNS_T_A;
5965                                 qclass  = DNS_C_IN;
5966
5967                                 break;
5968                         case DNS_T_MX:
5969                                 if ((error = dns_mx_parse(&rd.mx, &rr, F->answer)))
5970                                         goto error;
5971
5972                                 qname   = rd.mx.host;
5973                                 qtype   = DNS_T_A;
5974                                 qclass  = DNS_C_IN;
5975
5976                                 break;
5977                         case DNS_T_SRV:
5978                                 if ((error = dns_srv_parse(&rd.srv, &rr, F->answer)))
5979                                         goto error;
5980
5981                                 qname   = rd.srv.target;
5982                                 qtype   = DNS_T_A;
5983                                 qclass  = DNS_C_IN;
5984
5985                                 break;
5986                         default:
5987                                 continue;
5988                         } /* switch() */
5989
5990                         dns_res_reset_frame(R, &F[1]);
5991
5992                         if (!(F[1].query = dns_res_mkquery(R, qname, qtype, qclass, &error)))
5993                                 goto error;
5994
5995                         F->state++;
5996
5997                         goto(++R->sp, DNS_R_INIT);
5998                 } /* while() */
5999
6000                 /*
6001                  * NOTE: SMTP specification says to fallback to A record.
6002                  *
6003                  * XXX: Should we add a mock MX answer?
6004                  */
6005                 if (R->qtype == DNS_T_MX && R->smart.state.count == 0) {
6006                         dns_res_reset_frame(R, &F[1]);
6007
6008                         if (!(F[1].query = dns_res_mkquery(R, R->qname, DNS_T_A, DNS_C_IN, &error)))
6009                                 goto error;
6010
6011                         R->smart.state.count++;
6012                         F->state++;
6013
6014                         goto(++R->sp, DNS_R_INIT);
6015                 }
6016
6017                 goto(R->sp, DNS_R_DONE);
6018         case DNS_R_SMART1_A:
6019                 assert(F[1].answer);
6020
6021                 /*
6022                  * FIXME: For CNAME chains (which are typically illegal in
6023                  * this context), we should rewrite the record host name
6024                  * to the original smart qname. All the user cares about
6025                  * is locating that A/AAAA record.
6026                  */
6027                 dns_rr_foreach(&rr, F[1].answer, .section = DNS_S_AN, .type = DNS_T_A) {
6028                         rr.section      = DNS_S_AR;
6029
6030                         if (dns_rr_exists(&rr, F[1].answer, F->answer))
6031                                 continue;
6032
6033                         while ((error = dns_rr_copy(F->answer, &rr, F[1].answer))) {
6034                                 if (error != DNS_ENOBUFS)
6035                                         goto error;
6036                                 if ((error = dns_p_grow(&F->answer)))
6037                                         goto error;
6038                         }
6039                 }
6040
6041                 goto(R->sp, DNS_R_SMART0_A);
6042         case DNS_R_DONE:
6043                 assert(F->answer);
6044
6045                 if (R->sp > 0)
6046                         goto(--R->sp, F[-1].state);
6047
6048                 break;
6049         case DNS_R_SERVFAIL:
6050                 free(F->answer);
6051
6052                 if (!(F->answer = dns_p_make(DNS_P_QBUFSIZ, &error)))
6053                         goto error;
6054
6055                 dns_header(F->answer)->qr       = 1;
6056                 dns_header(F->answer)->rcode    = DNS_RC_SERVFAIL;
6057
6058                 if ((error = dns_p_push(F->answer, DNS_S_QD, R->qname, strlen(R->qname), R->qtype, R->qclass, 0, 0)))
6059                         goto error;
6060
6061                 goto(R->sp, DNS_R_DONE);
6062         default:
6063                 error   = EINVAL;
6064
6065                 goto error;
6066         } /* switch () */
6067
6068         return 0;
6069 toolong:
6070         error = DNS_EILLEGAL;
6071 error:
6072         return error;
6073 } /* dns_res_exec() */
6074
6075 #undef goto
6076
6077
6078 void dns_res_clear(struct dns_resolver *R) {
6079         switch (R->stack[R->sp].state) {
6080         case DNS_R_CHECK:
6081                 return R->cache->clear(R->cache);
6082         default:
6083                 return dns_so_clear(&R->so);
6084         }
6085 } /* dns_res_clear() */
6086
6087
6088 static int dns_res_events2(struct dns_resolver *R, enum dns_events type) {
6089         int events;
6090
6091         switch (R->stack[R->sp].state) {
6092         case DNS_R_CHECK:
6093                 events = R->cache->events(R->cache);
6094
6095                 return (type == DNS_LIBEVENT)? DNS_POLL2EV(events) : events;
6096         default:
6097                 return dns_so_events2(&R->so, type);
6098         }
6099 } /* dns_res_events2() */
6100
6101
6102 int dns_res_events(struct dns_resolver *R) {
6103         return dns_res_events2(R, R->so.opts.events);
6104 } /* dns_res_events() */
6105
6106
6107 int dns_res_pollfd(struct dns_resolver *R) {
6108         switch (R->stack[R->sp].state) {
6109         case DNS_R_CHECK:
6110                 return R->cache->pollfd(R->cache);
6111         default:
6112                 return dns_so_pollfd(&R->so);
6113         }
6114 } /* dns_res_pollfd() */
6115
6116
6117 time_t dns_res_elapsed(struct dns_resolver *R) {
6118         return dns_elapsed(R->began);
6119 } /* dns_res_elapsed() */
6120
6121
6122 int dns_res_poll(struct dns_resolver *R, int timeout) {
6123         return dns_poll(dns_res_pollfd(R), dns_res_events2(R, DNS_SYSPOLL), timeout);
6124 } /* dns_res_poll() */
6125
6126
6127 int dns_res_submit(struct dns_resolver *R, const char *qname, enum dns_type qtype, enum dns_class qclass) {
6128         dns_res_reset(R);
6129
6130         /* Don't anchor; that can conflict with searchlist generation. */
6131         dns_d_init(R->qname, sizeof R->qname, qname, (R->qlen = strlen(qname)), 0);
6132
6133         R->qtype        = qtype;
6134         R->qclass       = qclass;
6135
6136         R->began        = dns_now();
6137
6138         return 0;
6139 } /* dns_res_submit() */
6140
6141
6142 int dns_res_check(struct dns_resolver *R) {
6143         int error;
6144
6145         if ((error = dns_res_exec(R)))
6146                 return error;
6147
6148         return 0;
6149 } /* dns_res_check() */
6150
6151
6152 struct dns_packet *dns_res_fetch(struct dns_resolver *R, int *error) {
6153         struct dns_packet *answer;
6154
6155         if (R->stack[0].state != DNS_R_DONE) {
6156                 *error  = DNS_EUNKNOWN;
6157
6158                 return 0;
6159         }
6160
6161         answer                  = R->stack[0].answer;
6162         R->stack[0].answer      = 0;
6163
6164         return answer;
6165 } /* dns_res_fetch() */
6166
6167
6168 struct dns_packet *dns_res_query(struct dns_resolver *res, const char *qname, enum dns_type qtype, enum dns_class qclass, int timeout, int *error_) {
6169         int error;
6170
6171         if ((error = dns_res_submit(res, qname, qtype, qclass)))
6172                 goto error;
6173
6174         while ((error = dns_res_check(res))) {
6175                 if (dns_res_elapsed(res) > timeout)
6176                         error = DNS_ETIMEDOUT;
6177
6178                 if (error != DNS_EAGAIN)
6179                         goto error;
6180
6181                 if ((error = dns_res_poll(res, 1)))
6182                         goto error;
6183         }
6184
6185         return dns_res_fetch(res, error_);
6186 error:
6187         *error_ = error;
6188
6189         return 0;
6190 } /* dns_res_query() */
6191
6192
6193 const struct dns_stat *dns_res_stat(struct dns_resolver *res) {
6194         return dns_so_stat(&res->so);
6195 } /* dns_res_stat() */
6196
6197
6198 /*
6199  * A D D R I N F O  R O U T I N E S
6200  *
6201  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6202
6203 struct dns_addrinfo {
6204         struct addrinfo hints;
6205         struct dns_resolver *res;
6206
6207         char qname[DNS_D_MAXNAME + 1];
6208         enum dns_type qtype;
6209         unsigned short qport, port;
6210
6211         struct dns_packet *answer;
6212         struct dns_packet *glue;
6213
6214         struct dns_rr_i i, g;
6215         struct dns_rr rr;
6216
6217         char cname[DNS_D_MAXNAME + 1];
6218
6219         int state;
6220 }; /* struct dns_addrinfo */
6221
6222
6223 struct dns_addrinfo *dns_ai_open(const char *host, const char *serv, enum dns_type qtype, const struct addrinfo *hints, struct dns_resolver *res, int *error_) {
6224         static const struct dns_addrinfo ai_initializer;
6225         struct dns_addrinfo *ai;
6226         int error;
6227
6228         if (!res)
6229                 return 0;
6230
6231         dns_res_acquire(res);
6232
6233         if (!(ai = malloc(sizeof *ai)))
6234                 goto syerr;
6235
6236         *ai             = ai_initializer;
6237         ai->hints       = *hints;
6238
6239         ai->res         = res;
6240         res             = 0;
6241
6242         if (sizeof ai->qname <= dns_strlcpy(ai->qname, host, sizeof ai->qname))
6243                 { error = ENAMETOOLONG; goto error; }
6244
6245         ai->qtype       = qtype;
6246         ai->qport       = 0;
6247
6248         if (serv) {
6249                 while (isdigit((unsigned char)*serv)) {
6250                         ai->qport       *= 10;
6251                         ai->qport       += *serv++ - '0';
6252                 }
6253         }
6254
6255         ai->port        = ai->qport;
6256
6257         return ai;
6258 syerr:
6259         error   = dns_syerr();
6260 error:
6261         *error_ = error;
6262
6263         dns_ai_close(ai);
6264         dns_res_close(res);
6265
6266         return 0;
6267 } /* dns_ai_open() */
6268
6269
6270 void dns_ai_close(struct dns_addrinfo *ai) {
6271         if (!ai)
6272                 return;
6273
6274         dns_res_close(ai->res);
6275
6276         if (ai->answer != ai->glue)
6277                 free(ai->glue);
6278
6279         free(ai->answer);
6280         free(ai);
6281 } /* dns_ai_close() */
6282
6283
6284 static int dns_ai_setent(struct addrinfo **ent, union dns_any *any, enum dns_type type, struct dns_addrinfo *ai) {
6285         struct sockaddr *saddr;
6286         struct sockaddr_in sin;
6287         struct sockaddr_in6 sin6;
6288         const char *cname;
6289         size_t clen;
6290
6291         switch (type) {
6292         case DNS_T_A:
6293                 saddr   = memset(&sin, '\0', sizeof sin);
6294
6295                 sin.sin_family  = AF_INET;
6296                 sin.sin_port    = htons(ai->port);
6297
6298                 memcpy(&sin.sin_addr, any, sizeof sin.sin_addr);
6299
6300                 break;
6301         case DNS_T_AAAA:
6302                 saddr   = memset(&sin6, '\0', sizeof sin6);
6303
6304                 sin6.sin6_family        = AF_INET6;
6305                 sin6.sin6_port          = htons(ai->port);
6306
6307                 memcpy(&sin6.sin6_addr, any, sizeof sin6.sin6_addr);
6308
6309                 break;
6310         default:
6311                 return EINVAL;
6312         } /* switch() */
6313
6314         if (ai->hints.ai_flags & AI_CANONNAME) {
6315                 cname   = (*ai->cname)? ai->cname : ai->qname;
6316                 clen    = strlen(cname);
6317         } else {
6318                 cname   = NULL;
6319                 clen    = 0;
6320         }
6321
6322         if (!(*ent = malloc(sizeof **ent + dns_sa_len(saddr) + ((ai->hints.ai_flags & AI_CANONNAME)? clen + 1 : 0))))
6323                 return dns_syerr();
6324
6325         memset(*ent, '\0', sizeof **ent);
6326
6327         (*ent)->ai_family       = saddr->sa_family;
6328         (*ent)->ai_socktype     = ai->hints.ai_socktype;
6329         (*ent)->ai_protocol     = ai->hints.ai_protocol;
6330
6331         (*ent)->ai_addr         = memcpy((unsigned char *)*ent + sizeof **ent, saddr, dns_sa_len(saddr));
6332         (*ent)->ai_addrlen      = dns_sa_len(saddr);
6333
6334         if (ai->hints.ai_flags & AI_CANONNAME)
6335                 (*ent)->ai_canonname    = memcpy((unsigned char *)*ent + sizeof **ent + dns_sa_len(saddr), cname, clen + 1);
6336
6337         return 0;
6338 } /* dns_ai_setent() */
6339
6340
6341 enum dns_ai_state {
6342         DNS_AI_S_INIT,
6343         DNS_AI_S_NUMERIC,
6344         DNS_AI_S_SUBMIT,
6345         DNS_AI_S_CHECK,
6346         DNS_AI_S_FETCH,
6347         DNS_AI_S_FOREACH_I,
6348         DNS_AI_S_FOREACH_G,
6349         DNS_AI_S_SUBMIT_G,
6350         DNS_AI_S_CHECK_G,
6351         DNS_AI_S_FETCH_G,
6352         DNS_AI_S_DONE,
6353 }; /* enum dns_ai_state */
6354
6355 #define dns_ai_goto(which)      do { ai->state = (which); goto exec; } while (0)
6356
6357 int dns_ai_nextent(struct addrinfo **ent, struct dns_addrinfo *ai) {
6358         struct dns_packet *ans, *glue;
6359         struct dns_rr rr;
6360         char qname[DNS_D_MAXNAME + 1];
6361         union dns_any any;
6362         size_t len;
6363         int error;
6364
6365         *ent = 0;
6366
6367 exec:
6368
6369         switch (ai->state) {
6370         case DNS_AI_S_INIT:
6371                 ai->state++;
6372         case DNS_AI_S_NUMERIC:
6373                 if (1 == dns_inet_pton(AF_INET, ai->qname, &any.a)) {
6374                         ai->state = DNS_AI_S_DONE;
6375
6376                         return dns_ai_setent(ent, &any, DNS_T_A, ai);
6377                 }
6378
6379                 if (1 == dns_inet_pton(AF_INET6, ai->qname, &any.aaaa)) {
6380                         ai->state = DNS_AI_S_DONE;
6381
6382                         return dns_ai_setent(ent, &any, DNS_T_AAAA, ai);
6383                 }
6384
6385                 if (ai->hints.ai_flags & AI_NUMERICHOST)
6386                         dns_ai_goto(DNS_AI_S_DONE);
6387
6388                 ai->state++;
6389         case DNS_AI_S_SUBMIT:
6390                 if ((error = dns_res_submit(ai->res, ai->qname, ai->qtype, DNS_C_IN)))
6391                         return error;
6392
6393                 ai->state++;
6394         case DNS_AI_S_CHECK:
6395                 if ((error = dns_res_check(ai->res)))
6396                         return error;
6397
6398                 ai->state++;
6399         case DNS_AI_S_FETCH:
6400                 if (!(ai->answer = dns_res_fetch(ai->res, &error)))
6401                         return error;
6402
6403                 if ((error = dns_p_study(ai->answer)))
6404                         return error;
6405
6406                 ai->glue = ai->answer;
6407
6408                 dns_rr_i_init(&ai->i, ai->answer);
6409
6410                 ai->i.section = DNS_S_AN;
6411                 ai->i.type    = ai->qtype;
6412                 ai->i.sort    = &dns_rr_i_order;
6413
6414                 ai->state++;
6415         case DNS_AI_S_FOREACH_I:
6416                 /* Search generator may have changed our qname. */
6417                 if (!(len = dns_d_expand(qname, sizeof qname, 12, ai->answer, &error)))
6418                         return error;
6419                 else if (len >= sizeof qname)
6420                         return DNS_EILLEGAL;
6421
6422                 if (!dns_d_cname(ai->cname, sizeof ai->cname, qname, strlen(qname), ai->answer, &error))
6423                         return error;
6424
6425                 ai->i.name = ai->cname;
6426
6427                 if (!dns_rr_grep(&rr, 1, &ai->i, ai->answer, &error))
6428                         dns_ai_goto(DNS_AI_S_DONE);
6429
6430                 if ((error = dns_any_parse(&any, &rr, ai->answer)))
6431                         return error;
6432
6433                 ai->port = ai->qport;
6434
6435                 switch (rr.type) {
6436                 case DNS_T_A:
6437                 case DNS_T_AAAA:
6438                         return dns_ai_setent(ent, &any, rr.type, ai);
6439                 default:
6440                         if (!dns_any_cname(ai->cname, sizeof ai->cname, &any, rr.type))
6441                                 dns_ai_goto(DNS_AI_S_FOREACH_I);
6442
6443                         /*
6444                          * Find the "real" canonical name. Some authorities
6445                          * publish aliases where an RFC defines a canonical
6446                          * name. We trust that the resolver followed any
6447                          * CNAME chains on it's own, regardless of whether
6448                          * the "smart" option is enabled.
6449                          */
6450                         if (!dns_d_cname(ai->cname, sizeof ai->cname, ai->cname, strlen(ai->cname), ai->answer, &error))
6451                                 return error;
6452
6453                         if (rr.type == DNS_T_SRV)
6454                                 ai->port = any.srv.port;
6455
6456                         break;
6457                 } /* switch() */
6458
6459                 dns_rr_i_init(&ai->g, ai->glue);
6460
6461                 ai->g.section = DNS_S_ALL & ~DNS_S_QD;
6462                 ai->g.name    = ai->cname;
6463                 ai->g.type    = (ai->hints.ai_family == AF_INET6)? DNS_T_AAAA : DNS_T_A;
6464
6465                 ai->state++;
6466         case DNS_AI_S_FOREACH_G:
6467                 if (!dns_rr_grep(&rr, 1, &ai->g, ai->glue, &error)) {
6468                         if (dns_rr_i_count(&ai->g) > 0)
6469                                 dns_ai_goto(DNS_AI_S_FOREACH_I);
6470                         else
6471                                 dns_ai_goto(DNS_AI_S_SUBMIT_G);
6472                 }
6473
6474                 if ((error = dns_any_parse(&any, &rr, ai->glue)))
6475                         return error;
6476
6477                 return dns_ai_setent(ent, &any, rr.type, ai);
6478         case DNS_AI_S_SUBMIT_G:
6479                 if (dns_rr_grep(&rr, 1, dns_rr_i_new(ai->glue, .section = DNS_S_QD, .name = ai->g.name, .type = ai->g.type), ai->glue, &error))
6480                         dns_ai_goto(DNS_AI_S_FOREACH_I);
6481
6482                 if ((error = dns_res_submit(ai->res, ai->g.name, ai->g.type, DNS_C_IN)))
6483                         return error;
6484
6485                 ai->state++;
6486         case DNS_AI_S_CHECK_G:
6487                 if ((error = dns_res_check(ai->res)))
6488                         return error;
6489
6490                 ai->state++;
6491         case DNS_AI_S_FETCH_G:
6492                 if (!(ans = dns_res_fetch(ai->res, &error)))
6493                         return error;
6494
6495                 dns_p_study(ans);
6496
6497                 glue = dns_p_merge(ai->glue, DNS_S_ALL, ans, DNS_S_ALL, &error);
6498
6499                 free(ans);
6500
6501                 if (!glue)
6502                         return error;
6503
6504                 if (ai->glue != ai->answer)
6505                         free(ai->glue);
6506
6507                 ai->glue = glue;
6508
6509                 dns_rr_i_init(&ai->g, ai->glue);
6510
6511                 /* ai->g.name should already point to ai->cname */
6512                 if (!dns_d_cname(ai->cname, sizeof ai->cname, ai->cname, strlen(ai->cname), ai->glue, &error))
6513                         dns_ai_goto(DNS_AI_S_FOREACH_I);
6514
6515                 /* NOTE: Keep all the other iterator filters */
6516
6517                 dns_ai_goto(DNS_AI_S_FOREACH_G);
6518         case DNS_AI_S_DONE:
6519                 return ENOENT;
6520         default:
6521                 return EINVAL;
6522         } /* switch() */
6523 } /* dns_ai_nextent() */
6524
6525
6526 time_t dns_ai_elapsed(struct dns_addrinfo *ai) {
6527         return dns_res_elapsed(ai->res);
6528 } /* dns_ai_elapsed() */
6529
6530
6531 void dns_ai_clear(struct dns_addrinfo *ai) {
6532         return dns_res_clear(ai->res);
6533 } /* dns_ai_clear() */
6534
6535
6536 int dns_ai_events(struct dns_addrinfo *ai) {
6537         return dns_res_events(ai->res);
6538 } /* dns_ai_events() */
6539
6540
6541 int dns_ai_pollfd(struct dns_addrinfo *ai) {
6542         return dns_res_pollfd(ai->res);
6543 } /* dns_ai_pollfd() */
6544
6545
6546 int dns_ai_poll(struct dns_addrinfo *ai, int timeout) {
6547         return dns_res_poll(ai->res, timeout);
6548 } /* dns_ai_poll() */
6549
6550
6551 size_t dns_ai_print(void *dst, size_t lim, struct addrinfo *ent, struct dns_addrinfo *ai) {
6552         char addr[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) + 1];
6553         size_t cp       = 0;
6554
6555         cp      += dns__printstring(dst, lim, cp, "[ ");
6556         cp      += dns__printstring(dst, lim, cp, ai->qname);
6557         cp      += dns__printstring(dst, lim, cp, " IN ");
6558         cp      += dns__printstring(dst, lim, cp, dns_strtype(ai->qtype));
6559         cp      += dns__printstring(dst, lim, cp, " ]\n");
6560
6561         cp      += dns__printstring(dst, lim, cp, ".ai_family    = ");
6562
6563         switch (ent->ai_family) {
6564         case AF_INET:
6565                 cp      += dns__printstring(dst, lim, cp, "AF_INET");
6566                 break;
6567         case AF_INET6:
6568                 cp      += dns__printstring(dst, lim, cp, "AF_INET6");
6569                 break;
6570         default:
6571                 cp      += dns__print10(dst, lim, cp, ent->ai_family, 0);
6572                 break;
6573         }
6574
6575         cp      += dns__printchar(dst, lim, cp, '\n');
6576
6577         cp      += dns__printstring(dst, lim, cp, ".ai_socktype  = ");
6578
6579         switch (ent->ai_socktype) {
6580         case SOCK_STREAM:
6581                 cp      += dns__printstring(dst, lim, cp, "SOCK_STREAM");
6582                 break;
6583         case SOCK_DGRAM:
6584                 cp      += dns__printstring(dst, lim, cp, "SOCK_DGRAM");
6585                 break;
6586         default:
6587                 cp      += dns__print10(dst, lim, cp, ent->ai_socktype, 0);
6588                 break;
6589         }
6590
6591         cp      += dns__printchar(dst, lim, cp, '\n');
6592
6593         cp      += dns__printstring(dst, lim, cp, ".ai_addr      = [");
6594
6595         dns_inet_ntop(dns_sa_family(ent->ai_addr), dns_sa_addr(dns_sa_family(ent->ai_addr), ent->ai_addr), addr, sizeof addr);
6596
6597         cp      += dns__printstring(dst, lim, cp, addr);
6598         cp      += dns__printstring(dst, lim, cp, "]:");
6599
6600         cp      += dns__print10(dst, lim, cp, ntohs(*dns_sa_port(dns_sa_family(ent->ai_addr), ent->ai_addr)), 0);
6601         cp      += dns__printchar(dst, lim, cp, '\n');
6602
6603         cp      += dns__printstring(dst, lim, cp, ".ai_canonname = ");
6604         cp      += dns__printstring(dst, lim, cp, (ent->ai_canonname)? ent->ai_canonname : "[NULL]");
6605         cp      += dns__printchar(dst, lim, cp, '\n');
6606
6607         dns__printnul(dst, lim, cp);
6608
6609         return cp;
6610 } /* dns_ai_print() */
6611
6612
6613 const struct dns_stat *dns_ai_stat(struct dns_addrinfo *ai) {
6614         return dns_res_stat(ai->res);
6615 } /* dns_ai_stat() */
6616
6617
6618 /*
6619  * M I S C E L L A N E O U S  R O U T I N E S
6620  *
6621  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6622
6623 static const struct {
6624         char name[16];
6625         enum dns_section type;
6626 } dns_sections[] = {
6627         { "QUESTION",   DNS_S_QUESTION },
6628         { "QD",         DNS_S_QUESTION },
6629         { "ANSWER",     DNS_S_ANSWER },
6630         { "AN",         DNS_S_ANSWER },
6631         { "AUTHORITY",  DNS_S_AUTHORITY },
6632         { "NS",         DNS_S_AUTHORITY },
6633         { "ADDITIONAL", DNS_S_ADDITIONAL },
6634         { "AR",         DNS_S_ADDITIONAL },
6635 };
6636
6637 const char *(dns_strsection)(enum dns_section section, void *dst, size_t lim) {
6638         unsigned i, p = 0;
6639
6640         for (i = 0; i < lengthof(dns_sections); i++) {
6641                 if (dns_sections[i].type & section) {
6642                         if (p > 0)
6643                                 p += dns__printchar(dst, lim, p, '|');
6644
6645                         p += dns__printstring(dst, lim, p, dns_sections[i].name);
6646
6647                         section &= ~dns_sections[i].type;
6648                 }
6649         }
6650
6651         if (!p)
6652                 p += dns__print10(dst, lim, 0, (0xffff & section), 0);
6653
6654         dns__printnul(dst, lim, p);
6655
6656         return dst;
6657 } /* dns_strsection() */
6658
6659
6660 enum dns_section dns_isection(const char *src) {
6661         enum dns_section section = 0;
6662         char sbuf[128];
6663         char *name, *next;
6664         unsigned i;
6665
6666         dns_strlcpy(sbuf, src, sizeof sbuf);
6667         next = sbuf;
6668
6669         while ((name = dns_strsep(&next, "|+, \t"))) {
6670                 for (i = 0; i < lengthof(dns_sections); i++) {
6671                         if (!strcasecmp(dns_sections[i].name, name)) {
6672                                 section |= dns_sections[i].type;
6673                                 break;
6674                         }
6675                 }
6676         }
6677
6678         return section;
6679 } /* dns_isection() */
6680
6681
6682 static const struct {
6683         char name[8];
6684         enum dns_class type;
6685 } dns_classes[] = {
6686         { "IN", DNS_C_IN },
6687 };
6688
6689 const char *(dns_strclass)(enum dns_class type, void *dst, size_t lim) {
6690         unsigned i;
6691
6692         for (i = 0; i < lengthof(dns_classes); i++) {
6693                 if (dns_classes[i].type == type) {
6694                         dns__printnul(dst, lim, dns__printstring(dst, lim, 0, dns_classes[i].name));
6695
6696                         return dst;
6697                 }
6698         }
6699
6700         dns__printnul(dst, lim, dns__print10(dst, lim, 0, (0xffff & type), 0));
6701
6702         return dst;
6703 } /* dns_strclass() */
6704
6705
6706 enum dns_class dns_iclass(const char *name) {
6707         unsigned i;
6708
6709         for (i = 0; i < lengthof(dns_classes); i++) {
6710                 if (!strcasecmp(dns_classes[i].name, name))
6711                         return dns_classes[i].type;
6712         }
6713
6714         return 0;
6715 } /* dns_iclass() */
6716
6717
6718 const char *(dns_strtype)(enum dns_type type, void *dst, size_t lim) {
6719         unsigned i;
6720
6721         for (i = 0; i < lengthof(dns_rrtypes); i++) {
6722                 if (dns_rrtypes[i].type == type) {
6723                         dns__printnul(dst, lim, dns__printstring(dst, lim, 0, dns_rrtypes[i].name));
6724
6725                         return dst;
6726                 }
6727         }
6728
6729         dns__printnul(dst, lim, dns__print10(dst, lim, 0, (0xffff & type), 0));
6730
6731         return dst;
6732 } /* dns_strtype() */
6733
6734
6735 enum dns_type dns_itype(const char *type) {
6736         unsigned i;
6737
6738         for (i = 0; i < lengthof(dns_rrtypes); i++) {
6739                 if (!strcasecmp(dns_rrtypes[i].name, type))
6740                         return dns_rrtypes[i].type;
6741         }
6742
6743         return 0;
6744 } /* dns_itype() */
6745
6746
6747 static char dns_opcodes[16][16] = {
6748         [DNS_OP_QUERY]  = "QUERY",
6749         [DNS_OP_IQUERY] = "IQUERY",
6750         [DNS_OP_STATUS] = "STATUS",
6751         [DNS_OP_NOTIFY] = "NOTIFY",
6752         [DNS_OP_UPDATE] = "UPDATE",
6753 };
6754
6755 const char *dns_stropcode(enum dns_opcode opcode) {
6756         opcode &= 0xf;
6757
6758         if ('\0' == dns_opcodes[opcode][0])
6759                 dns__printnul(dns_opcodes[opcode], sizeof dns_opcodes[opcode], dns__print10(dns_opcodes[opcode], sizeof dns_opcodes[opcode], 0, opcode, 0));
6760
6761         return dns_opcodes[opcode];
6762 } /* dns_stropcode() */
6763
6764
6765 enum dns_opcode dns_iopcode(const char *name) {
6766         unsigned opcode;
6767
6768         for (opcode = 0; opcode < lengthof(dns_opcodes); opcode++) {
6769                 if (!strcasecmp(name, dns_opcodes[opcode]))
6770                         return opcode;
6771         }
6772
6773         return lengthof(dns_opcodes) - 1;
6774 } /* dns_iopcode() */
6775
6776
6777 static char dns_rcodes[16][16] = {
6778         [DNS_RC_NOERROR]  = "NOERROR",
6779         [DNS_RC_FORMERR]  = "FORMERR",
6780         [DNS_RC_SERVFAIL] = "SERVFAIL",
6781         [DNS_RC_NXDOMAIN] = "NXDOMAIN",
6782         [DNS_RC_NOTIMP]   = "NOTIMP",
6783         [DNS_RC_REFUSED]  = "REFUSED",
6784         [DNS_RC_YXDOMAIN] = "YXDOMAIN",
6785         [DNS_RC_YXRRSET]  = "YXRRSET",
6786         [DNS_RC_NXRRSET]  = "NXRRSET",
6787         [DNS_RC_NOTAUTH]  = "NOTAUTH",
6788         [DNS_RC_NOTZONE]  = "NOTZONE",
6789 };
6790
6791 const char *dns_strrcode(enum dns_rcode rcode) {
6792         rcode &= 0xf;
6793
6794         if ('\0' == dns_rcodes[rcode][0])
6795                 dns__printnul(dns_rcodes[rcode], sizeof dns_rcodes[rcode], dns__print10(dns_rcodes[rcode], sizeof dns_rcodes[rcode], 0, rcode, 0));
6796
6797         return dns_rcodes[rcode];
6798 } /* dns_strrcode() */
6799
6800
6801 enum dns_rcode dns_ircode(const char *name) {
6802         unsigned rcode;
6803
6804         for (rcode = 0; rcode < lengthof(dns_rcodes); rcode++) {
6805                 if (!strcasecmp(name, dns_rcodes[rcode]))
6806                         return rcode;
6807         }
6808
6809         return lengthof(dns_rcodes) - 1;
6810 } /* dns_ircode() */
6811
6812
6813 /*
6814  * C O M M A N D - L I N E / R E G R E S S I O N  R O U T I N E S
6815  *
6816  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6817 #if DNS_MAIN
6818
6819 #include <stdarg.h>
6820 #include <stdlib.h>
6821 #include <stdio.h>
6822
6823 #include <ctype.h>
6824
6825 #if _WIN32
6826 #include <getopt.h>
6827 #endif
6828
6829 #if !_WIN32
6830 #include <err.h>
6831 #endif
6832
6833
6834 struct {
6835         struct {
6836                 const char *path[8];
6837                 unsigned count;
6838         } resconf;
6839
6840         struct {
6841                 const char *path[8];
6842                 unsigned count;
6843         } hosts;
6844
6845         struct {
6846                 const char *path[8];
6847                 unsigned count;
6848         } cache;
6849
6850         const char *qname;
6851         enum dns_type qtype;
6852
6853         int (*sort)();
6854
6855         int verbose;
6856 } MAIN = {
6857         .sort   = &dns_rr_i_packet,
6858 };
6859
6860
6861 void hexdump(const unsigned char *src, size_t len, FILE *fp) {
6862         static const unsigned char hex[]        = "0123456789abcdef";
6863         static const unsigned char tmpl[]       = "                                                    |                |\n";
6864         unsigned char ln[sizeof tmpl];
6865         const unsigned char *sp, *se;
6866         unsigned char *h, *g;
6867         unsigned i, n;
6868
6869         sp      = src;
6870         se      = sp + len;
6871
6872         while (sp < se) {
6873                 memcpy(ln, tmpl, sizeof ln);
6874
6875                 h       = &ln[2];
6876                 g       = &ln[53];
6877
6878                 for (n = 0; n < 2; n++) {
6879                         for (i = 0; i < 8 && se - sp > 0; i++, sp++) {
6880                                 h[0]    = hex[0x0f & (*sp >> 4)];
6881                                 h[1]    = hex[0x0f & (*sp >> 0)];
6882                                 h       += 3;
6883
6884                                 *g++    = (isgraph(*sp))? *sp : '.';
6885                         }
6886
6887                         h++;
6888                 }
6889
6890                 fputs((char *)ln, fp);
6891         }
6892
6893         return /* void */;
6894 } /* hexdump() */
6895
6896
6897 static void panic(const char *fmt, ...) {
6898         va_list ap;
6899
6900         va_start(ap, fmt);
6901
6902 #if _WIN32
6903         vfprintf(stderr, fmt, ap);
6904
6905         exit(EXIT_FAILURE);
6906 #else
6907         verrx(EXIT_FAILURE, fmt, ap);
6908 #endif
6909 } /* panic() */
6910
6911 #define panic_(fn, ln, fmt, ...)        \
6912         panic(fmt "%0s", (fn), (ln), __VA_ARGS__)
6913 #define panic(...)                      \
6914         panic_(__func__, __LINE__, "(%s:%d) " __VA_ARGS__, "")
6915
6916
6917 static void *grow(unsigned char *p, size_t size) {
6918         void *tmp;
6919
6920         if (!(tmp = realloc(p, size)))
6921                 panic("realloc(%zu): %s", size, dns_strerror(errno));
6922
6923         return tmp;
6924 } /* grow() */
6925
6926
6927 static size_t add(size_t a, size_t b) {
6928         if (~a < b)
6929                 panic("%zu + %zu: integer overflow", a, b);
6930
6931         return a + b;
6932 } /* add() */
6933
6934
6935 static size_t append(unsigned char **dst, size_t osize, const void *src, size_t len) {
6936         size_t size = add(osize, len);
6937
6938         *dst = grow(*dst, size);
6939         memcpy(*dst + osize, src, len);
6940
6941         return size;
6942 } /* append() */
6943
6944
6945 static size_t slurp(unsigned char **dst, size_t osize, FILE *fp, const char *path) {
6946         size_t size = osize;
6947         unsigned char buf[1024];
6948         size_t count;
6949
6950         while ((count = fread(buf, 1, sizeof buf, fp)))
6951                 size = append(dst, size, buf, count);
6952
6953         if (ferror(fp))
6954                 panic("%s: %s", path, dns_strerror(errno));
6955
6956         return size;
6957 } /* slurp() */
6958
6959
6960 static struct dns_resolv_conf *resconf(void) {
6961         static struct dns_resolv_conf *resconf;
6962         const char *path;
6963         unsigned i;
6964         int error;
6965
6966         if (resconf)
6967                 return resconf;
6968
6969         if (!(resconf = dns_resconf_open(&error)))
6970                 panic("dns_resconf_open: %s", dns_strerror(error));
6971
6972         if (!MAIN.resconf.count)
6973                 MAIN.resconf.path[MAIN.resconf.count++] = "/etc/resolv.conf";
6974
6975         for (i = 0; i < MAIN.resconf.count; i++) {
6976                 path    = MAIN.resconf.path[i];
6977
6978                 if (0 == strcmp(path, "-"))
6979                         error   = dns_resconf_loadfile(resconf, stdin);
6980                 else
6981                         error   = dns_resconf_loadpath(resconf, path);
6982
6983                 if (error)
6984                         panic("%s: %s", path, dns_strerror(error));
6985         }
6986
6987         return resconf;
6988 } /* resconf() */
6989
6990
6991 static struct dns_hosts *hosts(void) {
6992         static struct dns_hosts *hosts;
6993         const char *path;
6994         unsigned i;
6995         int error;
6996
6997         if (hosts)
6998                 return hosts;
6999
7000         if (!MAIN.hosts.count) {
7001                 MAIN.hosts.path[MAIN.hosts.count++]     = "/etc/hosts";
7002
7003                 /* Explicitly test dns_hosts_local() */
7004                 if (!(hosts = dns_hosts_local(&error)))
7005                         panic("%s: %s", "/etc/hosts", dns_strerror(error));
7006
7007                 return hosts;
7008         }
7009
7010         if (!(hosts = dns_hosts_open(&error)))
7011                 panic("dns_hosts_open: %s", dns_strerror(error));
7012
7013         for (i = 0; i < MAIN.hosts.count; i++) {
7014                 path    = MAIN.hosts.path[i];
7015
7016                 if (0 == strcmp(path, "-"))
7017                         error   = dns_hosts_loadfile(hosts, stdin);
7018                 else
7019                         error   = dns_hosts_loadpath(hosts, path);
7020                 
7021                 if (error)
7022                         panic("%s: %s", path, dns_strerror(error));
7023         }
7024
7025         return hosts;
7026 } /* hosts() */
7027
7028
7029 #if DNS_CACHE
7030 #include "cache.h"
7031
7032 struct dns_cache *cache(void) {
7033         static struct cache *cache;
7034         const char *path;
7035         unsigned i;
7036         int error;
7037
7038         if (cache)
7039                 return cache_resi(cache);
7040         if (!MAIN.cache.count)
7041                 return NULL;
7042
7043         if (!(cache = cache_open(&error)))
7044                 panic("%s: %s", MAIN.cache.path[0], dns_strerror(error));
7045
7046         for (i = 0; i < MAIN.cache.count; i++) {
7047                 path = MAIN.cache.path[i];
7048
7049                 if (!strcmp(path, "-")) {
7050                         if ((error = cache_loadfile(cache, stdin, NULL, 0)))
7051                                 panic("%s: %s", path, dns_strerror(error));
7052                 } else if ((error = cache_loadpath(cache, path, NULL, 0)))
7053                         panic("%s: %s", path, dns_strerror(error));
7054         }
7055
7056         return cache_resi(cache);
7057 } /* cache() */
7058 #else
7059 struct dns_cache *cache(void) { return NULL; }
7060 #endif
7061
7062
7063 static void print_packet(struct dns_packet *P, FILE *fp) {
7064         dns_p_dump3(P, dns_rr_i_new(P, .sort = MAIN.sort), fp);
7065
7066         if (MAIN.verbose > 2)
7067                 hexdump(P->data, P->end, fp);
7068 } /* print_packet() */
7069
7070
7071 static int parse_packet(int argc, char *argv[]) {
7072         struct dns_packet *P    = dns_p_new(512);
7073         struct dns_packet *Q    = dns_p_new(512);
7074         enum dns_section section;
7075         struct dns_rr rr;
7076         int error;
7077         union dns_any any;
7078         char pretty[sizeof any * 2];
7079         size_t len;
7080
7081         P->end  = fread(P->data, 1, P->size, stdin);
7082
7083         fputs(";; [HEADER]\n", stdout);
7084         fprintf(stdout, ";;     qr : %s(%d)\n", (dns_header(P)->qr)? "QUERY" : "RESPONSE", dns_header(P)->qr);
7085         fprintf(stdout, ";; opcode : %s(%d)\n", dns_stropcode(dns_header(P)->opcode), dns_header(P)->opcode);
7086         fprintf(stdout, ";;     aa : %s(%d)\n", (dns_header(P)->aa)? "AUTHORITATIVE" : "NON-AUTHORITATIVE", dns_header(P)->aa);
7087         fprintf(stdout, ";;     tc : %s(%d)\n", (dns_header(P)->tc)? "TRUNCATED" : "NOT-TRUNCATED", dns_header(P)->tc);
7088         fprintf(stdout, ";;     rd : %s(%d)\n", (dns_header(P)->rd)? "RECURSION-DESIRED" : "RECURSION-NOT-DESIRED", dns_header(P)->rd);
7089         fprintf(stdout, ";;     ra : %s(%d)\n", (dns_header(P)->ra)? "RECURSION-ALLOWED" : "RECURSION-NOT-ALLOWED", dns_header(P)->ra);
7090         fprintf(stdout, ";;  rcode : %s(%d)\n", dns_strrcode(dns_header(P)->rcode), dns_header(P)->rcode);
7091
7092         section = 0;
7093
7094         dns_rr_foreach(&rr, P, .sort = MAIN.sort) {
7095                 if (section != rr.section)
7096                         fprintf(stdout, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(P, rr.section));
7097
7098                 if ((len = dns_rr_print(pretty, sizeof pretty, &rr, P, &error)))
7099                         fprintf(stdout, "%s\n", pretty);
7100
7101                 dns_rr_copy(Q, &rr, P);
7102
7103                 section = rr.section;
7104         }
7105
7106         fputs("; ; ; ; ; ; ; ;\n\n", stdout);
7107
7108         section = 0;
7109
7110 #if 0
7111         dns_rr_foreach(&rr, Q, .name = "ns8.yahoo.com.") {
7112 #else
7113         struct dns_rr rrset[32];
7114         struct dns_rr_i *rri    = dns_rr_i_new(Q, .name = dns_d_new("ns8.yahoo.com", DNS_D_ANCHOR), .sort = MAIN.sort);
7115         unsigned rrcount        = dns_rr_grep(rrset, lengthof(rrset), rri, Q, &error);
7116         unsigned i;
7117
7118         for (i = 0; i < rrcount; i++) {
7119                 rr      = rrset[i];
7120 #endif
7121                 if (section != rr.section)
7122                         fprintf(stdout, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(Q, rr.section));
7123
7124                 if ((len = dns_rr_print(pretty, sizeof pretty, &rr, Q, &error)))
7125                         fprintf(stdout, "%s\n", pretty);
7126
7127                 section = rr.section;
7128         }
7129
7130         if (MAIN.verbose > 1) {
7131                 fprintf(stderr, "orig:%zu\n", P->end);
7132                 hexdump(P->data, P->end, stdout);
7133
7134                 fprintf(stderr, "copy:%zu\n", Q->end);
7135                 hexdump(Q->data, Q->end, stdout);
7136         }
7137
7138         return 0;
7139 } /* parse_packet() */
7140
7141
7142 static int parse_domain(int argc, char *argv[]) {
7143         char *dn;
7144
7145         dn      = (argc > 1)? argv[1] : "f.l.google.com";
7146
7147         printf("[%s]\n", dn);
7148
7149         dn      = dns_d_new(dn);
7150
7151         do {
7152                 puts(dn);
7153         } while (dns_d_cleave(dn, strlen(dn) + 1, dn, strlen(dn)));
7154
7155         return 0;
7156 } /* parse_domain() */
7157
7158
7159 static int expand_domain(int argc, char *argv[]) {
7160         unsigned short rp = 0;
7161         unsigned char *src = NULL;
7162         unsigned char *dst;
7163         struct dns_packet *pkt;
7164         size_t lim = 0, len;
7165         int error;
7166
7167         if (argv[1])
7168                 rp = atoi(argv[1]);
7169
7170         len = slurp(&src, 0, stdin, "-");
7171
7172         if (!(pkt = dns_p_make(len, &error)))
7173                 panic("malloc(%zu): %s", len, dns_strerror(error));
7174
7175         memcpy(pkt->data, src, len);
7176         pkt->end = len;
7177
7178         lim = 1;
7179         dst = grow(NULL, lim);
7180
7181         while (lim <= (len = dns_d_expand(dst, lim, rp, pkt, &error))) {
7182                 lim = add(len, 1);
7183                 dst = grow(dst, lim);
7184         }
7185
7186         if (!len)
7187                 panic("expand: %s", dns_strerror(error));
7188
7189         fwrite(dst, 1, len, stdout);
7190         fflush(stdout);
7191
7192         free(src);
7193         free(dst);
7194         free(pkt);
7195
7196         return 0;
7197 } /* expand_domain() */
7198
7199
7200 static int show_resconf(int argc, char *argv[]) {
7201         unsigned i;
7202
7203         resconf();      /* load it */
7204
7205         fputs("; SOURCES\n", stdout);
7206
7207         for (i = 0; i < MAIN.resconf.count; i++)
7208                 fprintf(stdout, ";   %s\n", MAIN.resconf.path[i]);
7209
7210         fputs(";\n", stdout);
7211
7212         dns_resconf_dump(resconf(), stdout);
7213
7214         return 0;
7215 } /* show_resconf() */
7216
7217
7218 static int show_hosts(int argc, char *argv[]) {
7219         unsigned i;
7220
7221         hosts();
7222
7223         fputs("# SOURCES\n", stdout);
7224
7225         for (i = 0; i < MAIN.hosts.count; i++)
7226                 fprintf(stdout, "#   %s\n", MAIN.hosts.path[i]);
7227
7228         fputs("#\n", stdout);
7229
7230         dns_hosts_dump(hosts(), stdout);
7231
7232         return 0;
7233 } /* show_hosts() */
7234
7235
7236 static int query_hosts(int argc, char *argv[]) {
7237         struct dns_packet *Q    = dns_p_new(512);
7238         struct dns_packet *A;
7239         char qname[DNS_D_MAXNAME + 1];
7240         size_t qlen;
7241         int error;
7242
7243         if (!MAIN.qname)
7244                 MAIN.qname      = (argc > 1)? argv[1] : "localhost";
7245         if (!MAIN.qtype)
7246                 MAIN.qtype      = DNS_T_A;
7247
7248         hosts();
7249
7250         if (MAIN.qtype == DNS_T_PTR && !strstr(MAIN.qname, "arpa")) {
7251                 union { struct in_addr a; struct in6_addr a6; } addr;
7252                 int af  = (strchr(MAIN.qname, ':'))? AF_INET6 : AF_INET;
7253
7254                 if (1 != dns_inet_pton(af, MAIN.qname, &addr))
7255                         panic("%s: %s", MAIN.qname, dns_strerror(error));
7256
7257                 qlen    = dns_ptr_qname(qname, sizeof qname, af, &addr);
7258         } else
7259                 qlen    = dns__printstring(qname, sizeof qname, 0, MAIN.qname);
7260
7261         if ((error = dns_p_push(Q, DNS_S_QD, qname, qlen, MAIN.qtype, DNS_C_IN, 0, 0)))
7262                 panic("%s: %s", qname, dns_strerror(error));
7263
7264         if (!(A = dns_hosts_query(hosts(), Q, &error)))
7265                 panic("%s: %s", qname, dns_strerror(error));
7266
7267         print_packet(A, stdout);
7268
7269         free(A);
7270
7271         return 0;
7272 } /* query_hosts() */
7273
7274
7275 static int search_list(int argc, char *argv[]) {
7276         const char *qname       = (argc > 1)? argv[1] : "f.l.google.com";
7277         unsigned long i         = 0;
7278         char name[DNS_D_MAXNAME + 1];
7279
7280         printf("[%s]\n", qname);
7281
7282         while (dns_resconf_search(name, sizeof name, qname, strlen(qname), resconf(), &i))
7283                 puts(name);
7284
7285         return 0;
7286 } /* search_list() */
7287
7288
7289 int permute_set(int argc, char *argv[]) {
7290         unsigned lo, hi, i;
7291         struct dns_k_permutor p;
7292
7293         hi      = (--argc > 0)? atoi(argv[argc]) : 8;
7294         lo      = (--argc > 0)? atoi(argv[argc]) : 0;
7295
7296         fprintf(stderr, "[%u .. %u]\n", lo, hi);
7297
7298         dns_k_permutor_init(&p, lo, hi);
7299
7300         for (i = lo; i <= hi; i++)
7301                 fprintf(stdout, "%u\n", dns_k_permutor_step(&p));
7302 //              printf("%u -> %u -> %u\n", i, dns_k_permutor_E(&p, i), dns_k_permutor_D(&p, dns_k_permutor_E(&p, i)));
7303
7304         return 0;
7305 } /* permute_set() */
7306
7307
7308 int shuffle_16(int argc, char *argv[]) {
7309         unsigned n, r;
7310
7311         if (--argc > 0) {
7312                 n = 0xffff & atoi(argv[argc]);
7313                 r = (--argc > 0)? (unsigned)atoi(argv[argc]) : dns_random();
7314
7315                 fprintf(stdout, "%hu\n", dns_k_shuffle16(n, r));
7316         } else {
7317                 r = dns_random();
7318
7319                 for (n = 0; n < 65536; n++)
7320                         fprintf(stdout, "%hu\n", dns_k_shuffle16(n, r));
7321         }
7322
7323         return 0;
7324 } /* shuffle_16() */
7325
7326
7327 int dump_random(int argc, char *argv[]) {
7328         unsigned char b[32];
7329         unsigned i, j, n, r;
7330
7331         n       = (argc > 1)? atoi(argv[1]) : 32;
7332
7333         while (n) {
7334                 i       = 0;
7335
7336                 do {
7337                         r       = dns_random();
7338
7339                         for (j = 0; j < sizeof r && i < n && i < sizeof b; i++, j++) {
7340                                 b[i]    = 0xff & r;
7341                                 r       >>= 8;
7342                         }
7343                 } while (i < n && i < sizeof b);
7344
7345                 hexdump(b, i, stdout);
7346
7347                 n       -= i;
7348         }
7349
7350         return 0;
7351 } /* dump_random() */
7352
7353
7354 static int send_query(int argc, char *argv[]) {
7355         struct dns_packet *A, *Q        = dns_p_new(512);
7356         char host[INET6_ADDRSTRLEN + 1];
7357         struct sockaddr_storage ss;
7358         struct dns_socket *so;
7359         int error, type;
7360
7361         if (argc > 1) {
7362                 ss.ss_family    = (strchr(argv[1], ':'))? AF_INET6 : AF_INET;
7363                 
7364                 if (1 != dns_inet_pton(ss.ss_family, argv[1], dns_sa_addr(ss.ss_family, &ss)))
7365                         panic("%s: invalid host address", argv[1]);
7366
7367                 *dns_sa_port(ss.ss_family, &ss) = htons(53);
7368         } else
7369                 memcpy(&ss, &resconf()->nameserver[0], dns_sa_len(&resconf()->nameserver[0]));
7370
7371         if (!dns_inet_ntop(ss.ss_family, dns_sa_addr(ss.ss_family, &ss), host, sizeof host))
7372                 panic("bad host address, or none provided");
7373
7374         if (!MAIN.qname)
7375                 MAIN.qname      = "ipv6.google.com";
7376         if (!MAIN.qtype)
7377                 MAIN.qtype      = DNS_T_AAAA;
7378
7379         if ((error = dns_p_push(Q, DNS_S_QD, MAIN.qname, strlen(MAIN.qname), MAIN.qtype, DNS_C_IN, 0, 0)))
7380                 panic("dns_p_push: %s", dns_strerror(error));
7381
7382         dns_header(Q)->rd       = 1;
7383
7384         if (strstr(argv[0], "udp"))
7385                 type    = SOCK_DGRAM;
7386         else if (strstr(argv[0], "tcp"))
7387                 type    = SOCK_STREAM;
7388         else
7389                 type    = dns_res_tcp2type(resconf()->options.tcp);
7390
7391         fprintf(stderr, "querying %s for %s IN %s\n", host, MAIN.qname, dns_strtype(MAIN.qtype));
7392
7393         if (!(so = dns_so_open((struct sockaddr *)&resconf()->iface, type, dns_opts(), &error)))
7394                 panic("dns_so_open: %s", dns_strerror(error));
7395
7396         while (!(A = dns_so_query(so, Q, (struct sockaddr *)&ss, &error))) {
7397                 if (error != EAGAIN)
7398                         panic("dns_so_query: %s (%d)", dns_strerror(error), error);
7399                 if (dns_so_elapsed(so) > 10)
7400                         panic("query timed-out");
7401
7402                 dns_so_poll(so, 1);
7403         }
7404
7405         print_packet(A, stdout);
7406
7407         dns_so_close(so);
7408
7409         return 0;
7410 } /* send_query() */
7411
7412
7413 static int print_arpa(int argc, char *argv[]) {
7414         const char *ip  = (argc > 1)? argv[1] : "::1";
7415         int af          = (strchr(ip, ':'))? AF_INET6 : AF_INET;
7416         union { struct in_addr a4; struct in6_addr a6; } addr;
7417         char host[DNS_D_MAXNAME + 1];
7418
7419         if (1 != dns_inet_pton(af, ip, &addr) || 0 == dns_ptr_qname(host, sizeof host, af, &addr))
7420                 panic("%s: invalid address", ip);
7421
7422         fprintf(stdout, "%s\n", host);
7423
7424         return 0;
7425 } /* print_arpa() */
7426
7427
7428 static int show_hints(int argc, char *argv[]) {
7429         struct dns_hints *(*load)(struct dns_resolv_conf *, int *);
7430         const char *which, *how, *who;
7431         struct dns_hints *hints;
7432         int error;
7433
7434         which   = (argc > 1)? argv[1] : "local";
7435         how     = (argc > 2)? argv[2] : "plain";
7436         who     = (argc > 3)? argv[3] : "google.com";
7437
7438         load    = (0 == strcmp(which, "local"))
7439                 ? &dns_hints_local
7440                 : &dns_hints_root;
7441
7442         if (!(hints = load(resconf(), &error)))
7443                 panic("%s: %s", argv[0], dns_strerror(error));
7444
7445         if (0 == strcmp(how, "plain")) {
7446                 dns_hints_dump(hints, stdout);
7447         } else {
7448                 struct dns_packet *query, *answer;
7449
7450                 query   = dns_p_new(512);
7451
7452                 if ((error = dns_p_push(query, DNS_S_QUESTION, who, strlen(who), DNS_T_A, DNS_C_IN, 0, 0)))
7453                         panic("%s: %s", who, dns_strerror(error));
7454
7455                 if (!(answer = dns_hints_query(hints, query, &error)))
7456                         panic("%s: %s", who, dns_strerror(error));
7457
7458                 print_packet(answer, stdout);
7459
7460                 free(answer);
7461         }
7462
7463         dns_hints_close(hints);
7464
7465         return 0;
7466 } /* show_hints() */
7467
7468
7469 static int resolve_query(int argc, char *argv[]) {
7470         struct dns_hints *(*hints)()    = (strstr(argv[0], "recurse"))? &dns_hints_root : &dns_hints_local;
7471         struct dns_resolver *R;
7472         struct dns_packet *ans;
7473         const struct dns_stat *st;
7474         int error;
7475
7476         if (!MAIN.qname)
7477                 MAIN.qname      = "www.google.com";
7478         if (!MAIN.qtype)        
7479                 MAIN.qtype      = DNS_T_A;
7480
7481         resconf()->options.recurse      = (0 != strstr(argv[0], "recurse"));
7482
7483         if (!(R = dns_res_open(resconf(), hosts(), dns_hints_mortal(hints(resconf(), &error)), cache(), dns_opts(), &error)))
7484                 panic("%s: %s", MAIN.qname, dns_strerror(error));
7485
7486         if ((error = dns_res_submit(R, MAIN.qname, MAIN.qtype, DNS_C_IN)))
7487                 panic("%s: %s", MAIN.qname, dns_strerror(error));
7488
7489         while ((error = dns_res_check(R))) {
7490                 if (error != EAGAIN)
7491                         panic("dns_res_check: %s (%d)", dns_strerror(error), error);
7492                 if (dns_res_elapsed(R) > 30)
7493                         panic("query timed-out");
7494
7495                 dns_res_poll(R, 1);
7496         }
7497
7498         ans = dns_res_fetch(R, &error);
7499         print_packet(ans, stdout);
7500         free(ans);
7501
7502         st = dns_res_stat(R);
7503         putchar('\n');
7504         printf(";; queries:  %zu\n", st->queries);
7505         printf(";; udp sent: %zu in %zu bytes\n", st->udp.sent.count, st->udp.sent.bytes);
7506         printf(";; udp rcvd: %zu in %zu bytes\n", st->udp.rcvd.count, st->udp.rcvd.bytes);
7507         printf(";; tcp sent: %zu in %zu bytes\n", st->tcp.sent.count, st->tcp.sent.bytes);
7508         printf(";; tcp rcvd: %zu in %zu bytes\n", st->tcp.rcvd.count, st->tcp.rcvd.bytes);
7509
7510         dns_res_close(R);
7511
7512         return 0;
7513 } /* resolve_query() */
7514
7515
7516 static int resolve_addrinfo(int argc, char *argv[]) {
7517         struct dns_hints *(*hints)()    = (strstr(argv[0], "recurse"))? &dns_hints_root : &dns_hints_local;
7518         struct dns_resolver *res        = 0;
7519         struct dns_addrinfo *ai         = 0;
7520         struct addrinfo ai_hints        = { .ai_family = PF_UNSPEC, .ai_socktype = SOCK_STREAM, .ai_flags = AI_CANONNAME };
7521         struct addrinfo *ent;
7522         char pretty[512];
7523         int error;
7524
7525         if (!MAIN.qname)
7526                 MAIN.qname      = "www.google.com";
7527         if (!MAIN.qtype)        
7528                 MAIN.qtype      = DNS_T_A;
7529
7530         resconf()->options.recurse      = (0 != strstr(argv[0], "recurse"));
7531
7532         if (!(res = dns_res_open(resconf(), hosts(), dns_hints_mortal(hints(resconf(), &error)), cache(), dns_opts(), &error)))
7533                 panic("%s: %s", MAIN.qname, dns_strerror(error));
7534
7535         if (!(ai = dns_ai_open(MAIN.qname, "80", MAIN.qtype, &ai_hints, res, &error)))
7536                 panic("%s: %s", MAIN.qname, dns_strerror(error));
7537
7538         do {
7539                 switch (error = dns_ai_nextent(&ent, ai)) {
7540                 case 0:
7541                         dns_ai_print(pretty, sizeof pretty, ent, ai);
7542
7543                         fputs(pretty, stdout);
7544
7545                         free(ent);
7546
7547                         break;
7548                 case ENOENT:
7549                         break;
7550                 case EAGAIN:
7551                         if (dns_ai_elapsed(ai) > 30)
7552                                 panic("query timed-out");
7553
7554                         dns_ai_poll(ai, 1);
7555
7556                         break;
7557                 default:
7558                         panic("dns_ai_nextent: %s (%d)", dns_strerror(error), error);
7559                 }
7560         } while (error != ENOENT);
7561
7562         dns_res_close(res);
7563         dns_ai_close(ai);
7564
7565         return 0;
7566 } /* resolve_addrinfo() */
7567
7568
7569 static int echo_port(int argc, char *argv[]) {
7570         union {
7571                 struct sockaddr sa;
7572                 struct sockaddr_in sin;
7573         } port;
7574         int fd;
7575         
7576         memset(&port, 0, sizeof port);
7577         port.sin.sin_family = AF_INET;
7578         port.sin.sin_port = htons(5354);
7579         port.sin.sin_addr.s_addr = inet_addr("127.0.0.1");
7580
7581         if (-1 == (fd = socket(PF_INET, SOCK_DGRAM, 0)))
7582                 panic("socket: %s", strerror(errno));
7583
7584         if (0 != bind(fd, &port.sa, sizeof port.sa))
7585                 panic("127.0.0.1:5353: %s", dns_strerror(errno));
7586
7587         for (;;) {
7588                 struct dns_packet *pkt = dns_p_new(512);
7589                 struct sockaddr_storage ss;
7590                 socklen_t slen = sizeof ss;
7591                 ssize_t count;
7592 #if defined(MSG_WAITALL) /* MinGW issue */
7593                 int rflags = MSG_WAITALL;
7594 #else
7595                 int rflags = 0;
7596 #endif
7597
7598                 count = recvfrom(fd, (char *)pkt->data, pkt->size, rflags, (struct sockaddr *)&ss, &slen);
7599
7600
7601                 if (!count || count < 0)
7602                         panic("recvfrom: %s", strerror(errno));
7603
7604                 pkt->end = count;
7605
7606                 dns_p_dump(pkt, stdout);
7607
7608                 (void)sendto(fd, (char *)pkt->data, pkt->end, 0, (struct sockaddr *)&ss, slen);
7609         }
7610
7611         return 0;
7612 } /* echo_port() */
7613
7614
7615 static int isection(int argc, char *argv[]) {
7616         const char *name = (argv[1])? argv[1] : "";
7617         int type;
7618
7619         type = dns_isection(name);
7620         name = dns_strsection(type);
7621
7622         printf("%s (%d)\n", name, type);
7623
7624         return 0;
7625 } /* isection() */
7626
7627
7628 static int iclass(int argc, char *argv[]) {
7629         const char *name = (argv[1])? argv[1] : "";
7630         int type;
7631
7632         type = dns_iclass(name);
7633         name = dns_strclass(type);
7634
7635         printf("%s (%d)\n", name, type);
7636
7637         return 0;
7638 } /* iclass() */
7639
7640
7641 static int itype(int argc, char *argv[]) {
7642         const char *name = (argv[1])? argv[1] : "";
7643         int type;
7644
7645         type = dns_itype(name);
7646         name = dns_strtype(type);
7647
7648         printf("%s (%d)\n", name, type);
7649
7650         return 0;
7651 } /* itype() */
7652
7653
7654 static int iopcode(int argc, char *argv[]) {
7655         const char *name = (argv[1])? argv[1] : "";
7656         int type;
7657
7658         type = dns_iopcode(name);
7659         name = dns_stropcode(type);
7660
7661         printf("%s (%d)\n", name, type);
7662
7663         return 0;
7664 } /* iopcode() */
7665
7666
7667 static int ircode(int argc, char *argv[]) {
7668         const char *name = (argv[1])? argv[1] : "";
7669         int type;
7670
7671         type = dns_ircode(name);
7672         name = dns_strrcode(type);
7673
7674         printf("%s (%d)\n", name, type);
7675
7676         return 0;
7677 } /* ircode() */
7678
7679
7680 #define SIZE1(x) { DNS_PP_STRINGIFY(x), sizeof (x) }
7681 #define SIZE2(x, ...) SIZE1(x), SIZE1(__VA_ARGS__)
7682 #define SIZE3(x, ...) SIZE1(x), SIZE2(__VA_ARGS__)
7683 #define SIZE4(x, ...) SIZE1(x), SIZE3(__VA_ARGS__)
7684 #define SIZE(...) DNS_PP_CALL(DNS_PP_XPASTE(SIZE, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__)
7685
7686 static int sizes(int argc, char *argv[]) {
7687         static const struct { const char *name; size_t size; } type[] = {
7688                 SIZE(struct dns_header, struct dns_packet, struct dns_rr, struct dns_rr_i),
7689                 SIZE(struct dns_a, struct dns_aaaa, struct dns_mx, struct dns_ns),
7690                 SIZE(struct dns_cname, struct dns_soa, struct dns_ptr, struct dns_srv),
7691                 SIZE(struct dns_sshfp, struct dns_txt, union dns_any),
7692                 SIZE(struct dns_resolv_conf, struct dns_hosts, struct dns_hints, struct dns_hints_i),
7693                 SIZE(struct dns_options, struct dns_socket, struct dns_resolver, struct dns_addrinfo),
7694                 SIZE(struct dns_cache),
7695         };
7696         unsigned i, max;
7697
7698         for (i = 0, max = 0; i < lengthof(type); i++)
7699                 max = MAX(max, strlen(type[i].name));
7700
7701         for (i = 0; i < lengthof(type); i++)
7702                 printf("%*s : %zu\n", max, type[i].name, type[i].size);
7703
7704         return 0;
7705 } /* sizes() */
7706
7707
7708 static const struct { const char *cmd; int (*run)(); const char *help; } cmds[] = {
7709         { "parse-packet",       &parse_packet,          "parse binary packet from stdin" },
7710         { "parse-domain",       &parse_domain,          "anchor and iteratively cleave domain" },
7711         { "expand-domain",      &expand_domain,         "expand domain at offset NN in packet from stdin" },
7712         { "show-resconf",       &show_resconf,          "show resolv.conf data" },
7713         { "show-hosts",         &show_hosts,            "show hosts data" },
7714         { "query-hosts",        &query_hosts,           "query A, AAAA or PTR in hosts data" },
7715         { "search-list",        &search_list,           "generate query search list from domain" },
7716         { "permute-set",        &permute_set,           "generate random permutation -> (0 .. N or N .. M)" },
7717         { "shuffle-16",         &shuffle_16,            "simple 16-bit permutation" },
7718         { "dump-random",        &dump_random,           "generate random bytes" },
7719         { "send-query",         &send_query,            "send query to host" },
7720         { "send-query-udp",     &send_query,            "send udp query to host" },
7721         { "send-query-tcp",     &send_query,            "send tcp query to host" },
7722         { "print-arpa",         &print_arpa,            "print arpa. zone name of address" },
7723         { "show-hints",         &show_hints,            "print hints: show-hints [local|root] [plain|packet]" },
7724         { "resolve-stub",       &resolve_query,         "resolve as stub resolver" },
7725         { "resolve-recurse",    &resolve_query,         "resolve as recursive resolver" },
7726         { "addrinfo-stub",      &resolve_addrinfo,      "resolve through getaddrinfo clone" },
7727         { "addrinfo-recurse",   &resolve_addrinfo,      "resolve through getaddrinfo clone" },
7728 /*      { "resolve-nameinfo",   &resolve_query,         "resolve as recursive resolver" }, */
7729         { "echo",               &echo_port,             "server echo mode, for nmap fuzzing" },
7730         { "isection",           &isection,              "parse section string" },
7731         { "iclass",             &iclass,                "parse class string" },
7732         { "itype",              &itype,                 "parse type string" },
7733         { "iopcode",            &iopcode,               "parse opcode string" },
7734         { "ircode",             &ircode,                "parse rcode string" },
7735         { "sizes",              &sizes,                 "print data structure sizes" },
7736 };
7737
7738
7739 static void print_usage(const char *progname, FILE *fp) {
7740         static const char *usage        = 
7741                 " [OPTIONS] COMMAND [ARGS]\n"
7742                 "  -c PATH   Path to resolv.conf\n"
7743                 "  -l PATH   Path to local hosts\n"
7744                 "  -z PATH   Path to zone cache\n"
7745                 "  -q QNAME  Query name\n"
7746                 "  -t QTYPE  Query type\n"
7747                 "  -s HOW    Sort records\n"
7748                 "  -v        Be more verbose (-vv show packets; -vvv hexdump packets)\n"
7749                 "  -V        Print version info\n"
7750                 "  -h        Print this usage message\n"
7751                 "\n";
7752         unsigned i, n, m;
7753
7754         fputs(progname, fp);
7755         fputs(usage, fp);
7756
7757         for (i = 0, m = 0; i < lengthof(cmds); i++) {
7758                 if (strlen(cmds[i].cmd) > m)
7759                         m       = strlen(cmds[i].cmd);
7760         }
7761
7762         for (i = 0; i < lengthof(cmds); i++) {
7763                 fprintf(fp, "  %s  ", cmds[i].cmd);
7764
7765                 for (n = strlen(cmds[i].cmd); n < m; n++)
7766                         putc(' ', fp);
7767
7768                 fputs(cmds[i].help, fp);
7769                 putc('\n', fp);
7770         }
7771
7772         fputs("\nReport bugs to William Ahern <william@25thandClement.com>\n", fp);
7773 } /* print_usage() */
7774
7775
7776 static void print_version(const char *progname, FILE *fp) {
7777         fprintf(fp, "%s (dns.c) %.8X\n", progname, dns_v_rel());
7778         fprintf(fp, "vendor  %s\n", dns_vendor());
7779         fprintf(fp, "release %.8X\n", dns_v_rel());
7780         fprintf(fp, "abi     %.8X\n", dns_v_abi());
7781         fprintf(fp, "api     %.8X\n", dns_v_api());
7782 } /* print_version() */
7783
7784
7785 int main(int argc, char **argv) {
7786         extern int optind;
7787         extern char *optarg;
7788         const char *progname    = argv[0];
7789         unsigned i;
7790         int ch;
7791
7792         while (-1 != (ch = getopt(argc, argv, "q:t:c:l:z:s:vVh"))) {
7793                 switch (ch) {
7794                 case 'c':
7795                         assert(MAIN.resconf.count < lengthof(MAIN.resconf.path));
7796
7797                         MAIN.resconf.path[MAIN.resconf.count++] = optarg;
7798
7799                         break;
7800                 case 'l':
7801                         assert(MAIN.hosts.count < lengthof(MAIN.hosts.path));
7802
7803                         MAIN.hosts.path[MAIN.hosts.count++]     = optarg;
7804
7805                         break;
7806                 case 'z':
7807                         assert(MAIN.cache.count < lengthof(MAIN.cache.path));
7808
7809                         MAIN.cache.path[MAIN.cache.count++]     = optarg;
7810
7811                         break;
7812                 case 'q':
7813                         MAIN.qname      = optarg;
7814
7815                         break;
7816                 case 't':
7817                         for (i = 0; i < lengthof(dns_rrtypes); i++) {
7818                                 if (0 == strcasecmp(dns_rrtypes[i].name, optarg))
7819                                         { MAIN.qtype = dns_rrtypes[i].type; break; }
7820                         }
7821
7822                         if (MAIN.qtype)
7823                                 break;
7824
7825                         for (i = 0; isdigit((int)optarg[i]); i++) {
7826                                 MAIN.qtype      *= 10;
7827                                 MAIN.qtype      += optarg[i] - '0';
7828                         }
7829
7830                         if (!MAIN.qtype)
7831                                 panic("%s: invalid query type", optarg);
7832
7833                         break;
7834                 case 's':
7835                         if (0 == strcasecmp(optarg, "packet"))
7836                                 MAIN.sort       = &dns_rr_i_packet;
7837                         else if (0 == strcasecmp(optarg, "shuffle"))
7838                                 MAIN.sort       = &dns_rr_i_shuffle;
7839                         else if (0 == strcasecmp(optarg, "order"))
7840                                 MAIN.sort       = &dns_rr_i_order;
7841                         else
7842                                 panic("%s: invalid sort method", optarg);
7843
7844                         break;
7845                 case 'v':
7846                         dns_debug = ++MAIN.verbose;
7847
7848                         break;
7849                 case 'V':
7850                         print_version(progname, stdout);
7851
7852                         return 0;
7853                 case 'h':
7854                         print_usage(progname, stdout);
7855
7856                         return 0;
7857                 default:
7858                         print_usage(progname, stderr);
7859
7860                         return EXIT_FAILURE;
7861                 } /* switch() */
7862         } /* while() */
7863
7864         argc    -= optind;
7865         argv    += optind;
7866
7867         for (i = 0; i < lengthof(cmds) && argv[0]; i++) {
7868                 if (0 == strcmp(cmds[i].cmd, argv[0]))
7869                         return cmds[i].run(argc, argv);
7870         }
7871
7872         print_usage(progname, stderr);
7873
7874         return EXIT_FAILURE;
7875 } /* main() */
7876
7877
7878 #endif /* DNS_MAIN */