1 /* ==========================================================================
2  * dns.c - Recursive, Reentrant DNS Resolver.
3  * --------------------------------------------------------------------------
4  * Copyright (c) 2008, 2009, 2010, 2012-2016  William Ahern
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to permit
11  * persons to whom the Software is furnished to do so, subject to the
12  * following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included
15  * in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
20  * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
21  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
23  * USE OR OTHER DEALINGS IN THE SOFTWARE.
24  * ==========================================================================
25  */
26 #if !defined(__FreeBSD__) && !defined(__sun) && !defined(__DragonFly__)
27 #ifndef _XOPEN_SOURCE
28 #define _XOPEN_SOURCE	600
29 #endif
30 
31 #undef _DEFAULT_SOURCE
32 #define _DEFAULT_SOURCE
33 
34 #undef _BSD_SOURCE
35 #define _BSD_SOURCE
36 
37 #undef _DARWIN_C_SOURCE
38 #define _DARWIN_C_SOURCE
39 
40 #undef _NETBSD_SOURCE
41 #define _NETBSD_SOURCE
42 #endif
43 
44 #include <limits.h>		/* INT_MAX */
45 #include <stddef.h>		/* offsetof() */
46 #ifdef _WIN32
47 #define uint32_t unsigned int
48 #else
49 #include <stdint.h>		/* uint32_t */
50 #endif
51 #include <stdlib.h>		/* malloc(3) realloc(3) free(3) rand(3) random(3) arc4random(3) */
52 #include <stdio.h>		/* FILE fopen(3) fclose(3) getc(3) rewind(3) */
53 #include <string.h>		/* memcpy(3) strlen(3) memmove(3) memchr(3) memcmp(3) strchr(3) strsep(3) strcspn(3) */
54 #include <strings.h>		/* strcasecmp(3) strncasecmp(3) */
55 #include <ctype.h>		/* isspace(3) isdigit(3) */
56 #include <time.h>		/* time_t time(2) difftime(3) */
57 #include <signal.h>		/* SIGPIPE sigemptyset(3) sigaddset(3) sigpending(2) sigprocmask(2) pthread_sigmask(3) sigtimedwait(2) */
58 #include <errno.h>		/* errno EINVAL ENOENT */
59 #undef NDEBUG
60 #include <assert.h>		/* assert(3) */
61 
62 #if _WIN32
63 #ifndef FD_SETSIZE
64 #define FD_SETSIZE 256
65 #endif
66 #include <winsock2.h>
67 #include <ws2tcpip.h>
68 #else
69 #include <sys/types.h>		/* FD_SETSIZE socklen_t */
70 #include <sys/select.h>		/* FD_ZERO FD_SET fd_set select(2) */
71 #include <sys/socket.h>		/* AF_INET AF_INET6 AF_UNIX struct sockaddr struct sockaddr_in struct sockaddr_in6 socket(2) */
72 #if defined(AF_UNIX)
73 #include <sys/un.h>		/* struct sockaddr_un */
74 #endif
75 #include <fcntl.h>		/* F_SETFD F_GETFL F_SETFL O_NONBLOCK fcntl(2) */
76 #include <unistd.h>		/* _POSIX_THREADS gethostname(3) close(2) */
77 #include <poll.h>		/* POLLIN POLLOUT */
78 #include <netinet/in.h>		/* struct sockaddr_in struct sockaddr_in6 */
79 #include <arpa/inet.h>		/* inet_pton(3) inet_ntop(3) htons(3) ntohs(3) */
80 #include <netdb.h>		/* struct addrinfo */
81 #endif
82 
83 #include "dns.h"
84 
85 
86 /*
87  * C O M P I L E R  V E R S I O N  &  F E A T U R E  D E T E C T I O N
88  *
89  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
90 
91 #define DNS_GNUC_2VER(M, m, p) (((M) * 10000) + ((m) * 100) + (p))
92 #define DNS_GNUC_PREREQ(M, m, p) (__GNUC__ > 0 && DNS_GNUC_2VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) >= DNS_GNUC_2VER((M), (m), (p)))
93 
94 #define DNS_MSC_2VER(M, m, p) ((((M) + 6) * 10000000) + ((m) * 1000000) + (p))
95 #define DNS_MSC_PREREQ(M, m, p) (_MSC_VER_FULL > 0 && _MSC_VER_FULL >= DNS_MSC_2VER((M), (m), (p)))
96 
97 #define DNS_SUNPRO_PREREQ(M, m, p) (__SUNPRO_C > 0 && __SUNPRO_C >= 0x ## M ## m ## p)
98 
99 #if defined __has_builtin
100 #define dns_has_builtin(x) __has_builtin(x)
101 #else
102 #define dns_has_builtin(x) 0
103 #endif
104 
105 #if defined __has_extension
106 #define dns_has_extension(x) __has_extension(x)
107 #else
108 #define dns_has_extension(x) 0
109 #endif
110 
111 #ifndef HAVE___ASSUME
112 #define HAVE___ASSUME DNS_MSC_PREREQ(8,0,0)
113 #endif
114 
115 #ifndef HAVE___BUILTIN_TYPES_COMPATIBLE_P
116 #define HAVE___BUILTIN_TYPES_COMPATIBLE_P (DNS_GNUC_PREREQ(3,1,1) || __clang__)
117 #endif
118 
119 #ifndef HAVE___BUILTIN_UNREACHABLE
120 #define HAVE___BUILTIN_UNREACHABLE (DNS_GNUC_PREREQ(4,5,0) || dns_has_builtin(__builtin_unreachable))
121 #endif
122 
123 #ifndef HAVE_PRAGMA_MESSAGE
124 #define HAVE_PRAGMA_MESSAGE (DNS_GNUC_PREREQ(4,4,0) || __clang__ || _MSC_VER)
125 #endif
126 
127 
128 /*
129  * C O M P I L E R  A N N O T A T I O N S
130  *
131  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
132 
133 #if __GNUC__
134 #define DNS_NOTUSED __attribute__((unused))
135 #define DNS_NORETURN __attribute__((noreturn))
136 #else
137 #define DNS_NOTUSED
138 #define DNS_NORETURN
139 #endif
140 
141 #if __clang__
142 #pragma clang diagnostic push
143 #pragma clang diagnostic ignored "-Wunused-parameter"
144 #pragma clang diagnostic ignored "-Wmissing-field-initializers"
145 #elif DNS_GNUC_PREREQ(4,6,0)
146 #pragma GCC diagnostic push
147 #pragma GCC diagnostic ignored "-Wunused-parameter"
148 #pragma GCC diagnostic ignored "-Wmissing-field-initializers"
149 #endif
150 
151 
152 /*
153  * S T A N D A R D  M A C R O S
154  *
155  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
156 
157 #if HAVE___BUILTIN_TYPES_COMPATIBLE_P
158 #define dns_same_type(a, b, def) __builtin_types_compatible_p(__typeof__ (a), __typeof__ (b))
159 #else
160 #define dns_same_type(a, b, def) (def)
161 #endif
162 #define dns_isarray(a) (!dns_same_type((a), (&(a)[0]), 0))
163 /* NB: "_" field silences Sun Studio "zero-sized struct/union" error diagnostic */
164 #define dns_inline_assert(cond) ((void)(sizeof (struct { int:-!(cond); int _; })))
165 
166 #if HAVE___ASSUME
167 #define dns_assume(cond) __assume(cond)
168 #elif HAVE___BUILTIN_UNREACHABLE
169 #define dns_assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0)
170 #else
171 #define dns_assume(cond) do { (void)(cond); } while (0)
172 #endif
173 
174 #ifndef lengthof
175 #define lengthof(a) (dns_inline_assert(dns_isarray(a)), (sizeof (a) / sizeof (a)[0]))
176 #endif
177 
178 #ifndef endof
179 #define endof(a) (dns_inline_assert(dns_isarray(a)), &(a)[lengthof((a))])
180 #endif
181 
182 
183 /*
184  * M I S C E L L A N E O U S  C O M P A T
185  *
186  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
187 
188 #if _WIN32 || _WIN64
189 #define PRIuZ "Iu"
190 #else
191 #define PRIuZ "zu"
192 #endif
193 
194 #ifndef DNS_THREAD_SAFE
195 #if (defined _REENTRANT || defined _THREAD_SAFE) && _POSIX_THREADS > 0
196 #define DNS_THREAD_SAFE 1
197 #else
198 #define DNS_THREAD_SAFE 0
199 #endif
200 #endif
201 
202 #ifndef HAVE__STATIC_ASSERT
203 #define HAVE__STATIC_ASSERT \
204 	(dns_has_extension(c_static_assert) || DNS_GNUC_PREREQ(4,6,0) || \
205 	 __C11FEATURES__ || __STDC_VERSION__ >= 201112L)
206 #endif
207 
208 #ifndef HAVE_STATIC_ASSERT
209 #if (defined static_assert) && \
210 	(!DNS_GNUC_PREREQ(0,0,0) || DNS_GNUC_PREREQ(4,6,0)) /* glibc doesn't check GCC version */
211 #define HAVE_STATIC_ASSERT 1
212 #else
213 #define HAVE_STATIC_ASSERT 0
214 #endif
215 #endif
216 
217 #if HAVE_STATIC_ASSERT
218 #define dns_static_assert(cond, msg) static_assert(cond, msg)
219 #elif HAVE__STATIC_ASSERT
220 #define dns_static_assert(cond, msg) _Static_assert(cond, msg)
221 #else
222 #define dns_static_assert(cond, msg) extern char DNS_PP_XPASTE(dns_assert_, __LINE__)[sizeof (int[1 - 2*!(cond)])]
223 #endif
224 
225 
226 /*
227  * D E B U G  M A C R O S
228  *
229  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
230 
dns_debug_p(void)231 int *dns_debug_p(void) {
232 	static int debug;
233 
234 	return &debug;
235 } /* dns_debug_p() */
236 
237 #if DNS_DEBUG
238 
239 #undef DNS_DEBUG
240 #define DNS_DEBUG dns_debug
241 
242 #define DNS_SAY_(fmt, ...) \
243 	do { if (DNS_DEBUG > 0) fprintf(stderr, fmt "%.1s", __func__, __LINE__, __VA_ARGS__); } while (0)
244 #define DNS_SAY(...) DNS_SAY_("@@ (%s:%d) " __VA_ARGS__, "\n")
245 #define DNS_HAI DNS_SAY("HAI")
246 
247 #define DNS_SHOW_(P, fmt, ...)	do {					\
248 	if (DNS_DEBUG > 1) {						\
249 	fprintf(stderr, "@@ BEGIN * * * * * * * * * * * *\n");		\
250 	fprintf(stderr, "@@ " fmt "%.0s\n", __VA_ARGS__);		\
251 	dns_p_dump((P), stderr);					\
252 	fprintf(stderr, "@@ END * * * * * * * * * * * * *\n\n");	\
253 	}								\
254 } while (0)
255 
256 #define DNS_SHOW(...)	DNS_SHOW_(__VA_ARGS__, "")
257 
258 #else /* !DNS_DEBUG */
259 
260 #undef DNS_DEBUG
261 #define DNS_DEBUG 0
262 
263 #define DNS_SAY(...)
264 #define DNS_HAI
265 #define DNS_SHOW(...)
266 
267 #endif /* DNS_DEBUG */
268 
269 #define DNS_CARP(...) DNS_SAY(__VA_ARGS__)
270 
271 
272 /*
273  * V E R S I O N  R O U T I N E S
274  *
275  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
276 
dns_vendor(void)277 const char *dns_vendor(void) {
278 	return DNS_VENDOR;
279 } /* dns_vendor() */
280 
281 
dns_v_rel(void)282 int dns_v_rel(void) {
283 	return DNS_V_REL;
284 } /* dns_v_rel() */
285 
286 
dns_v_abi(void)287 int dns_v_abi(void) {
288 	return DNS_V_ABI;
289 } /* dns_v_abi() */
290 
291 
dns_v_api(void)292 int dns_v_api(void) {
293 	return DNS_V_API;
294 } /* dns_v_api() */
295 
296 
297 /*
298  * E R R O R  R O U T I N E S
299  *
300  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
301 
302 #if _WIN32
303 
304 #define DNS_EINTR	WSAEINTR
305 #define DNS_EINPROGRESS	WSAEINPROGRESS
306 #define DNS_EISCONN	WSAEISCONN
307 #define DNS_EWOULDBLOCK	WSAEWOULDBLOCK
308 #define DNS_EALREADY	WSAEALREADY
309 #define DNS_EAGAIN	EAGAIN
310 #define DNS_ETIMEDOUT	WSAETIMEDOUT
311 
312 #define dns_syerr()	((int)GetLastError())
313 #define dns_soerr()	((int)WSAGetLastError())
314 
315 #else
316 
317 #define DNS_EINTR	EINTR
318 #define DNS_EINPROGRESS	EINPROGRESS
319 #define DNS_EISCONN	EISCONN
320 #define DNS_EWOULDBLOCK	EWOULDBLOCK
321 #define DNS_EALREADY	EALREADY
322 #define DNS_EAGAIN	EAGAIN
323 #define DNS_ETIMEDOUT	ETIMEDOUT
324 
325 #define dns_syerr()	errno
326 #define dns_soerr()	errno
327 
328 #endif
329 
330 
dns_strerror(int error)331 const char *dns_strerror(int error) {
332 	switch (error) {
333 	case DNS_ENOBUFS:
334 		return "DNS packet buffer too small";
335 	case DNS_EILLEGAL:
336 		return "Illegal DNS RR name or data";
337 	case DNS_EORDER:
338 		return "Attempt to push RR out of section order";
339 	case DNS_ESECTION:
340 		return "Invalid section specified";
341 	case DNS_EUNKNOWN:
342 		return "Unknown DNS error";
343 	case DNS_EADDRESS:
344 		return "Invalid textual address form";
345 	case DNS_ENOQUERY:
346 		return "Bad execution state (missing query packet)";
347 	case DNS_ENOANSWER:
348 		return "Bad execution state (missing answer packet)";
349 	case DNS_EFETCHED:
350 		return "Answer already fetched";
351 	case DNS_ESERVICE:
352 		return "The service passed was not recognized for the specified socket type";
353 	case DNS_ENONAME:
354 		return "The name does not resolve for the supplied parameters";
355 	case DNS_EFAIL:
356 		return "A non-recoverable error occurred when attempting to resolve the name";
357 	default:
358 		return strerror(error);
359 	} /* switch() */
360 } /* dns_strerror() */
361 
362 
363 /*
364  * A T O M I C  R O U T I N E S
365  *
366  * Use GCC's __atomic built-ins if possible. Unlike the __sync built-ins, we
367  * can use the preprocessor to detect API and, more importantly, ISA
368  * support. We want to avoid linking headaches where the API depends on an
369  * external library if the ISA (e.g. i386) doesn't support lockless
370  * operation.
371  *
372  * TODO: Support C11's atomic API. Although that may require some finesse
373  * with how we define some public types, such as dns_atomic_t and struct
374  * dns_resolv_conf.
375  *
376  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
377 
378 #ifndef HAVE___ATOMIC_FETCH_ADD
379 #ifdef __ATOMIC_RELAXED
380 #define HAVE___ATOMIC_FETCH_ADD 1
381 #else
382 #define HAVE___ATOMIC_FETCH_ADD 0
383 #endif
384 #endif
385 
386 #ifndef HAVE___ATOMIC_FETCH_SUB
387 #define HAVE___ATOMIC_FETCH_SUB HAVE___ATOMIC_FETCH_ADD
388 #endif
389 
390 #ifndef DNS_ATOMIC_FETCH_ADD
391 #if HAVE___ATOMIC_FETCH_ADD && __GCC_ATOMIC_LONG_LOCK_FREE == 2
392 #define DNS_ATOMIC_FETCH_ADD(i) __atomic_fetch_add((i), 1, __ATOMIC_RELAXED)
393 #else
394 #pragma message("no atomic_fetch_add available")
395 #define DNS_ATOMIC_FETCH_ADD(i) ((*(i))++)
396 #endif
397 #endif
398 
399 #ifndef DNS_ATOMIC_FETCH_SUB
400 #if HAVE___ATOMIC_FETCH_SUB && __GCC_ATOMIC_LONG_LOCK_FREE == 2
401 #define DNS_ATOMIC_FETCH_SUB(i) __atomic_fetch_sub((i), 1, __ATOMIC_RELAXED)
402 #else
403 #pragma message("no atomic_fetch_sub available")
404 #define DNS_ATOMIC_FETCH_SUB(i) ((*(i))--)
405 #endif
406 #endif
407 
dns_atomic_fetch_add(dns_atomic_t * i)408 static inline unsigned dns_atomic_fetch_add(dns_atomic_t *i) {
409 	return DNS_ATOMIC_FETCH_ADD(i);
410 } /* dns_atomic_fetch_add() */
411 
412 
dns_atomic_fetch_sub(dns_atomic_t * i)413 static inline unsigned dns_atomic_fetch_sub(dns_atomic_t *i) {
414 	return DNS_ATOMIC_FETCH_SUB(i);
415 } /* dns_atomic_fetch_sub() */
416 
417 
418 /*
419  * C R Y P T O  R O U T I N E S
420  *
421  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
422 
423 /*
424  * P R N G
425  */
426 
427 #ifndef DNS_RANDOM
428 #if defined(HAVE_ARC4RANDOM)	\
429  || defined(__OpenBSD__)	\
430  || defined(__FreeBSD__)	\
431  || defined(__NetBSD__)		\
432  || defined(__APPLE__)
433 #define DNS_RANDOM	arc4random
434 #elif __linux
435 #define DNS_RANDOM	random
436 #else
437 #define DNS_RANDOM	rand
438 #endif
439 #endif
440 
441 #define DNS_RANDOM_arc4random	1
442 #define DNS_RANDOM_random	2
443 #define DNS_RANDOM_rand		3
444 #define DNS_RANDOM_RAND_bytes	4
445 
446 #define DNS_RANDOM_OPENSSL	(DNS_RANDOM_RAND_bytes == DNS_PP_XPASTE(DNS_RANDOM_, DNS_RANDOM))
447 
448 #if DNS_RANDOM_OPENSSL
449 #include <openssl/rand.h>
450 #endif
451 
dns_random_(void)452 static unsigned dns_random_(void) {
453 #if DNS_RANDOM_OPENSSL
454 	unsigned r;
455 	_Bool ok;
456 
457 	ok = (1 == RAND_bytes((unsigned char *)&r, sizeof r));
458 	assert(ok && "1 == RAND_bytes()");
459 
460 	return r;
461 #else
462 	return DNS_RANDOM();
463 #endif
464 } /* dns_random_() */
465 
dns_random_p(void)466 dns_random_f **dns_random_p(void) {
467 	static dns_random_f *random_f = &dns_random_;
468 
469 	return &random_f;
470 } /* dns_random_p() */
471 
472 
473 /*
474  * P E R M U T A T I O N  G E N E R A T O R
475  */
476 
477 #define DNS_K_TEA_KEY_SIZE	16
478 #define DNS_K_TEA_BLOCK_SIZE	8
479 #define DNS_K_TEA_CYCLES	32
480 #define DNS_K_TEA_MAGIC		0x9E3779B9U
481 
482 struct dns_k_tea {
483 	uint32_t key[DNS_K_TEA_KEY_SIZE / sizeof (uint32_t)];
484 	unsigned cycles;
485 }; /* struct dns_k_tea */
486 
487 
dns_k_tea_init(struct dns_k_tea * tea,uint32_t key[],unsigned cycles)488 static void dns_k_tea_init(struct dns_k_tea *tea, uint32_t key[], unsigned cycles) {
489 	memcpy(tea->key, key, sizeof tea->key);
490 
491 	tea->cycles	= (cycles)? cycles : DNS_K_TEA_CYCLES;
492 } /* dns_k_tea_init() */
493 
494 
dns_k_tea_encrypt(struct dns_k_tea * tea,uint32_t v[],uint32_t * w)495 static void dns_k_tea_encrypt(struct dns_k_tea *tea, uint32_t v[], uint32_t *w) {
496 	uint32_t y, z, sum, n;
497 
498 	y	= v[0];
499 	z	= v[1];
500 	sum	= 0;
501 
502 	for (n = 0; n < tea->cycles; n++) {
503 		sum	+= DNS_K_TEA_MAGIC;
504 		y	+= ((z << 4) + tea->key[0]) ^ (z + sum) ^ ((z >> 5) + tea->key[1]);
505 		z	+= ((y << 4) + tea->key[2]) ^ (y + sum) ^ ((y >> 5) + tea->key[3]);
506 	}
507 
508 	w[0]	= y;
509 	w[1]	= z;
510 
511 	return /* void */;
512 } /* dns_k_tea_encrypt() */
513 
514 
515 /*
516  * Permutation generator, based on a Luby-Rackoff Feistel construction.
517  *
518  * Specifically, this is a generic balanced Feistel block cipher using TEA
519  * (another block cipher) as the pseudo-random function, F. At best it's as
520  * strong as F (TEA), notwithstanding the seeding. F could be AES, SHA-1, or
521  * perhaps Bernstein's Salsa20 core; I am naively trying to keep things
522  * simple.
523  *
524  * The generator can create a permutation of any set of numbers, as long as
525  * the size of the set is an even power of 2. This limitation arises either
526  * out of an inherent property of balanced Feistel constructions, or by my
527  * own ignorance. I'll tackle an unbalanced construction after I wrap my
528  * head around Schneier and Kelsey's paper.
529  *
530  * CAVEAT EMPTOR. IANAC.
531  */
532 #define DNS_K_PERMUTOR_ROUNDS	8
533 
534 struct dns_k_permutor {
535 	unsigned stepi, length, limit;
536 	unsigned shift, mask, rounds;
537 
538 	struct dns_k_tea tea;
539 }; /* struct dns_k_permutor */
540 
541 
dns_k_permutor_powof(unsigned n)542 static inline unsigned dns_k_permutor_powof(unsigned n) {
543 	unsigned m, i = 0;
544 
545 	for (m = 1; m < n; m <<= 1, i++)
546 		;;
547 
548 	return i;
549 } /* dns_k_permutor_powof() */
550 
dns_k_permutor_init(struct dns_k_permutor * p,unsigned low,unsigned high)551 static void dns_k_permutor_init(struct dns_k_permutor *p, unsigned low, unsigned high) {
552 	uint32_t key[DNS_K_TEA_KEY_SIZE / sizeof (uint32_t)];
553 	unsigned width, i;
554 
555 	p->stepi	= 0;
556 
557 	p->length	= (high - low) + 1;
558 	p->limit	= high;
559 
560 	width		= dns_k_permutor_powof(p->length);
561 	width		+= width % 2;
562 
563 	p->shift	= width / 2;
564 	p->mask		= (1U << p->shift) - 1;
565 	p->rounds	= DNS_K_PERMUTOR_ROUNDS;
566 
567 	for (i = 0; i < lengthof(key); i++)
568 		key[i]	= dns_random();
569 
570 	dns_k_tea_init(&p->tea, key, 0);
571 
572 	return /* void */;
573 } /* dns_k_permutor_init() */
574 
575 
dns_k_permutor_F(struct dns_k_permutor * p,unsigned k,unsigned x)576 static unsigned dns_k_permutor_F(struct dns_k_permutor *p, unsigned k, unsigned x) {
577 	uint32_t in[DNS_K_TEA_BLOCK_SIZE / sizeof (uint32_t)], out[DNS_K_TEA_BLOCK_SIZE / sizeof (uint32_t)];
578 
579 	memset(in, '\0', sizeof in);
580 
581 	in[0]	= k;
582 	in[1]	= x;
583 
584 	dns_k_tea_encrypt(&p->tea, in, out);
585 
586 	return p->mask & out[0];
587 } /* dns_k_permutor_F() */
588 
589 
dns_k_permutor_E(struct dns_k_permutor * p,unsigned n)590 static unsigned dns_k_permutor_E(struct dns_k_permutor *p, unsigned n) {
591 	unsigned l[2], r[2];
592 	unsigned i;
593 
594 	i	= 0;
595 	l[i]	= p->mask & (n >> p->shift);
596 	r[i]	= p->mask & (n >> 0);
597 
598 	do {
599 		l[(i + 1) % 2]	= r[i % 2];
600 		r[(i + 1) % 2]	= l[i % 2] ^ dns_k_permutor_F(p, i, r[i % 2]);
601 
602 		i++;
603 	} while (i < p->rounds - 1);
604 
605 	return ((l[i % 2] & p->mask) << p->shift) | ((r[i % 2] & p->mask) << 0);
606 } /* dns_k_permutor_E() */
607 
608 
dns_k_permutor_D(struct dns_k_permutor * p,unsigned n)609 DNS_NOTUSED static unsigned dns_k_permutor_D(struct dns_k_permutor *p, unsigned n) {
610 	unsigned l[2], r[2];
611 	unsigned i;
612 
613 	i		= p->rounds - 1;
614 	l[i % 2]	= p->mask & (n >> p->shift);
615 	r[i % 2]	= p->mask & (n >> 0);
616 
617 	do {
618 		i--;
619 
620 		r[i % 2]	= l[(i + 1) % 2];
621 		l[i % 2]	= r[(i + 1) % 2] ^ dns_k_permutor_F(p, i, l[(i + 1) % 2]);
622 	} while (i > 0);
623 
624 	return ((l[i % 2] & p->mask) << p->shift) | ((r[i % 2] & p->mask) << 0);
625 } /* dns_k_permutor_D() */
626 
627 
dns_k_permutor_step(struct dns_k_permutor * p)628 static unsigned dns_k_permutor_step(struct dns_k_permutor *p) {
629 	unsigned n;
630 
631 	do {
632 		n	= dns_k_permutor_E(p, p->stepi++);
633 	} while (n >= p->length);
634 
635 	return n + (p->limit + 1 - p->length);
636 } /* dns_k_permutor_step() */
637 
638 
639 /*
640  * Simple permutation box. Useful for shuffling rrsets from an iterator.
641  * Uses AES s-box to provide good diffusion.
642  *
643  * Seems to pass muster under runs test.
644  *
645  * $ for i in 0 1 2 3 4 5 6 7 8 9; do ./dns shuffle-16 > /tmp/out; done
646  * $ R -q -f /dev/stdin 2>/dev/null <<-EOF | awk '/p-value/{ print $8 }'
647  * 	library(lawstat)
648  * 	runs.test(scan(file="/tmp/out"))
649  * EOF
650  */
dns_k_shuffle16(unsigned short n,unsigned s)651 static unsigned short dns_k_shuffle16(unsigned short n, unsigned s) {
652 	static const unsigned char sbox[256] =
653 	{ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
654 	  0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
655 	  0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
656 	  0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
657 	  0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
658 	  0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
659 	  0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
660 	  0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
661 	  0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
662 	  0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
663 	  0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
664 	  0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
665 	  0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
666 	  0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
667 	  0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
668 	  0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
669 	  0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
670 	  0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
671 	  0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
672 	  0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
673 	  0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
674 	  0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
675 	  0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
676 	  0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
677 	  0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
678 	  0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
679 	  0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
680 	  0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
681 	  0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
682 	  0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
683 	  0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
684 	  0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };
685 	unsigned char a, b;
686 	unsigned i;
687 
688 	a = 0xff & (n >> 0);
689 	b = 0xff & (n >> 8);
690 
691 	for (i = 0; i < 4; i++) {
692 		a ^= 0xff & s;
693 		a = sbox[a] ^ b;
694 		b = sbox[b] ^ a;
695 		s >>= 8;
696 	}
697 
698 	return ((0xff00 & (a << 8)) | (0x00ff & (b << 0)));
699 } /* dns_k_shuffle16() */
700 
701 /*
702  * S T A T E  M A C H I N E  R O U T I N E S
703  *
704  * Application code should define DNS_SM_RESTORE and DNS_SM_SAVE, and the
705  * local variable pc.
706  *
707  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
708 
709 #define DNS_SM_ENTER \
710 	do { \
711 	static const int pc0 = __LINE__; \
712 	DNS_SM_RESTORE; \
713 	switch (pc0 + pc) { \
714 	case __LINE__: (void)0
715 
716 #define DNS_SM_SAVE_AND_DO(do_statement) \
717 	do { \
718 		pc = __LINE__ - pc0; \
719 		DNS_SM_SAVE; \
720 		do_statement; \
721 		case __LINE__: (void)0; \
722 	} while (0)
723 
724 #define DNS_SM_YIELD(rv) \
725 	DNS_SM_SAVE_AND_DO(return (rv))
726 
727 #define DNS_SM_EXIT \
728 	do { goto leave; } while (0)
729 
730 #define DNS_SM_LEAVE \
731 	leave: (void)0; \
732 	DNS_SM_SAVE_AND_DO(break); \
733 	} \
734 	} while (0)
735 
736 /*
737  * U T I L I T Y  R O U T I N E S
738  *
739  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
740 
741 #define DNS_MAXINTERVAL 300
742 
743 struct dns_clock {
744 	time_t sample, elapsed;
745 }; /* struct dns_clock */
746 
dns_begin(struct dns_clock * clk)747 static void dns_begin(struct dns_clock *clk) {
748 	clk->sample = time(0);
749 	clk->elapsed = 0;
750 } /* dns_begin() */
751 
dns_elapsed(struct dns_clock * clk)752 static time_t dns_elapsed(struct dns_clock *clk) {
753 	time_t curtime;
754 
755 	if ((time_t)-1 == time(&curtime))
756 		return clk->elapsed;
757 
758 	if (curtime > clk->sample)
759 		clk->elapsed += (time_t)DNS_PP_MIN(difftime(curtime, clk->sample), DNS_MAXINTERVAL);
760 
761 	clk->sample = curtime;
762 
763 	return clk->elapsed;
764 } /* dns_elapsed() */
765 
766 
dns_strnlen(const char * src,size_t m)767 DNS_NOTUSED static size_t dns_strnlen(const char *src, size_t m) {
768 	size_t n = 0;
769 
770 	while (*src++ && n < m)
771 		++n;
772 
773 	return n;
774 } /* dns_strnlen() */
775 
776 
dns_strnlcpy(char * dst,size_t lim,const char * src,size_t max)777 DNS_NOTUSED static size_t dns_strnlcpy(char *dst, size_t lim, const char *src, size_t max) {
778 	size_t len = dns_strnlen(src, max), n;
779 
780 	if (lim > 0) {
781 		n = DNS_PP_MIN(lim - 1, len);
782 		memcpy(dst, src, n);
783 		dst[n] = '\0';
784 	}
785 
786 	return len;
787 } /* dns_strnlcpy() */
788 
789 
790 #if (defined AF_UNIX && !defined _WIN32)
791 #define DNS_HAVE_SOCKADDR_UN 1
792 #else
793 #define DNS_HAVE_SOCKADDR_UN 0
794 #endif
795 
dns_af_len(int af)796 static size_t dns_af_len(int af) {
797 	static const size_t table[AF_MAX]	= {
798 		[AF_INET6]	= sizeof (struct sockaddr_in6),
799 		[AF_INET]	= sizeof (struct sockaddr_in),
800 #if DNS_HAVE_SOCKADDR_UN
801 		[AF_UNIX]	= sizeof (struct sockaddr_un),
802 #endif
803 	};
804 
805 	return table[af];
806 } /* dns_af_len() */
807 
808 #define dns_sa_family(sa)	(((struct sockaddr *)(sa))->sa_family)
809 
810 #define dns_sa_len(sa)		dns_af_len(dns_sa_family(sa))
811 
812 
813 #define DNS_SA_NOPORT	&dns_sa_noport
814 static unsigned short dns_sa_noport;
815 
dns_sa_port(int af,void * sa)816 static unsigned short *dns_sa_port(int af, void *sa) {
817 	switch (af) {
818 	case AF_INET6:
819 		return &((struct sockaddr_in6 *)sa)->sin6_port;
820 	case AF_INET:
821 		return &((struct sockaddr_in *)sa)->sin_port;
822 	default:
823 		return DNS_SA_NOPORT;
824 	}
825 } /* dns_sa_port() */
826 
827 
dns_sa_addr(int af,const void * sa,socklen_t * size)828 static void *dns_sa_addr(int af, const void *sa, socklen_t *size) {
829 	switch (af) {
830 	case AF_INET6: {
831 		struct in6_addr *in6 = &((struct sockaddr_in6 *)sa)->sin6_addr;
832 
833 		if (size)
834 			*size = sizeof *in6;
835 
836 		return in6;
837 	}
838 	case AF_INET: {
839 		struct in_addr *in = &((struct sockaddr_in *)sa)->sin_addr;
840 
841 		if (size)
842 			*size = sizeof *in;
843 
844 		return in;
845 	}
846 	default:
847 		if (size)
848 			*size = 0;
849 
850 		return 0;
851 	}
852 } /* dns_sa_addr() */
853 
854 
855 #if DNS_HAVE_SOCKADDR_UN
856 #define DNS_SUNPATHMAX (sizeof ((struct sockaddr_un *)0)->sun_path)
857 #endif
858 
dns_sa_path(void * sa,socklen_t * size)859 DNS_NOTUSED static void *dns_sa_path(void *sa, socklen_t *size) {
860 	switch (dns_sa_family(sa)) {
861 #if DNS_HAVE_SOCKADDR_UN
862 	case AF_UNIX: {
863 		char *path = ((struct sockaddr_un *)sa)->sun_path;
864 
865 		if (size)
866 			*size = dns_strnlen(path, DNS_SUNPATHMAX);
867 
868 		return path;
869 	}
870 #endif
871 	default:
872 		if (size)
873 			*size = 0;
874 
875 		return NULL;
876 	}
877 } /* dns_sa_path() */
878 
879 
dns_sa_cmp(void * a,void * b)880 static int dns_sa_cmp(void *a, void *b) {
881 	int cmp, af;
882 
883 	if ((cmp = dns_sa_family(a) - dns_sa_family(b)))
884 		return cmp;
885 
886 	switch ((af = dns_sa_family(a))) {
887 	case AF_INET: {
888 		struct in_addr *a4, *b4;
889 
890 		if ((cmp = htons(*dns_sa_port(af, a)) - htons(*dns_sa_port(af, b))))
891 			return cmp;
892 
893 		a4 = dns_sa_addr(af, a, NULL);
894 		b4 = dns_sa_addr(af, b, NULL);
895 
896 		if (ntohl(a4->s_addr) < ntohl(b4->s_addr))
897 			return -1;
898 		if (ntohl(a4->s_addr) > ntohl(b4->s_addr))
899 			return 1;
900 
901 		return 0;
902 	}
903 	case AF_INET6: {
904 		struct in6_addr *a6, *b6;
905 		size_t i;
906 
907 		if ((cmp = htons(*dns_sa_port(af, a)) - htons(*dns_sa_port(af, b))))
908 			return cmp;
909 
910 		a6 = dns_sa_addr(af, a, NULL);
911 		b6 = dns_sa_addr(af, b, NULL);
912 
913 		/* XXX: do we need to use in6_clearscope()? */
914 		for (i = 0; i < sizeof a6->s6_addr; i++) {
915 			if ((cmp = a6->s6_addr[i] - b6->s6_addr[i]))
916 				return cmp;
917 		}
918 
919 		return 0;
920 	}
921 #if DNS_HAVE_SOCKADDR_UN
922 	case AF_UNIX: {
923 		char a_path[DNS_SUNPATHMAX + 1], b_path[sizeof a_path];
924 
925 		dns_strnlcpy(a_path, sizeof a_path, dns_sa_path(a, NULL), DNS_SUNPATHMAX);
926 		dns_strnlcpy(b_path, sizeof b_path, dns_sa_path(b, NULL), DNS_SUNPATHMAX);
927 
928 		return strcmp(a_path, b_path);
929 	}
930 #endif
931 	default:
932 		return -1;
933 	}
934 } /* dns_sa_cmp() */
935 
936 
937 #if _WIN32
dns_inet_pton(int af,const void * src,void * dst)938 static int dns_inet_pton(int af, const void *src, void *dst) {
939 	union { struct sockaddr_in sin; struct sockaddr_in6 sin6; } u;
940 
941 	u.sin.sin_family	= af;
942 
943 	if (0 != WSAStringToAddressA((void *)src, af, (void *)0, (struct sockaddr *)&u, &(int){ sizeof u }))
944 		return -1;
945 
946 	switch (af) {
947 	case AF_INET6:
948 		*(struct in6_addr *)dst	= u.sin6.sin6_addr;
949 
950 		return 1;
951 	case AF_INET:
952 		*(struct in_addr *)dst	= u.sin.sin_addr;
953 
954 		return 1;
955 	default:
956 		return 0;
957 	}
958 } /* dns_inet_pton() */
959 
dns_inet_ntop(int af,const void * src,void * dst,unsigned long lim)960 static const char *dns_inet_ntop(int af, const void *src, void *dst, unsigned long lim) {
961 	union { struct sockaddr_in sin; struct sockaddr_in6 sin6; } u;
962 
963 	/* NOTE: WSAAddressToString will print .sin_port unless zeroed. */
964 	memset(&u, 0, sizeof u);
965 
966 	u.sin.sin_family	= af;
967 
968 	switch (af) {
969 	case AF_INET6:
970 		u.sin6.sin6_addr	= *(struct in6_addr *)src;
971 		break;
972 	case AF_INET:
973 		u.sin.sin_addr		= *(struct in_addr *)src;
974 
975 		break;
976 	default:
977 		return 0;
978 	}
979 
980 	if (0 != WSAAddressToStringA((struct sockaddr *)&u, dns_sa_len(&u), (void *)0, dst, &lim))
981 		return 0;
982 
983 	return dst;
984 } /* dns_inet_ntop() */
985 #else
986 #define dns_inet_pton(...)	inet_pton(__VA_ARGS__)
987 #define dns_inet_ntop(...)	inet_ntop(__VA_ARGS__)
988 #endif
989 
990 
dns_pton(int af,const void * src,void * dst)991 static dns_error_t dns_pton(int af, const void *src, void *dst) {
992 	switch (dns_inet_pton(af, src, dst)) {
993 	case 1:
994 		return 0;
995 	case -1:
996 		return dns_soerr();
997 	default:
998 		return DNS_EADDRESS;
999 	}
1000 } /* dns_pton() */
1001 
1002 
dns_ntop(int af,const void * src,void * dst,unsigned long lim)1003 static dns_error_t dns_ntop(int af, const void *src, void *dst, unsigned long lim) {
1004 	return (dns_inet_ntop(af, src, dst, lim))? 0 : dns_soerr();
1005 } /* dns_ntop() */
1006 
1007 
dns_strlcpy(char * dst,const char * src,size_t lim)1008 size_t dns_strlcpy(char *dst, const char *src, size_t lim) {
1009 	char *d		= dst;
1010 	char *e		= &dst[lim];
1011 	const char *s	= src;
1012 
1013 	if (d < e) {
1014 		do {
1015 			if ('\0' == (*d++ = *s++))
1016 				return s - src - 1;
1017 		} while (d < e);
1018 
1019 		d[-1]	= '\0';
1020 	}
1021 
1022 	while (*s++ != '\0')
1023 		;;
1024 
1025 	return s - src - 1;
1026 } /* dns_strlcpy() */
1027 
1028 
dns_strlcat(char * dst,const char * src,size_t lim)1029 size_t dns_strlcat(char *dst, const char *src, size_t lim) {
1030 	char *d = memchr(dst, '\0', lim);
1031 	char *e = &dst[lim];
1032 	const char *s = src;
1033 	const char *p;
1034 
1035 	if (d && d < e) {
1036 		do {
1037 			if ('\0' == (*d++ = *s++))
1038 				return d - dst - 1;
1039 		} while (d < e);
1040 
1041 		d[-1] = '\0';
1042 	}
1043 
1044 	p = s;
1045 
1046 	while (*s++ != '\0')
1047 		;;
1048 
1049 	return lim + (s - p - 1);
1050 } /* dns_strlcat() */
1051 
1052 
1053 #if _WIN32
1054 
dns_strsep(char ** sp,const char * delim)1055 static char *dns_strsep(char **sp, const char *delim) {
1056 	char *p;
1057 
1058 	if (!(p = *sp))
1059 		return 0;
1060 
1061 	*sp += strcspn(p, delim);
1062 
1063 	if (**sp != '\0') {
1064 		**sp = '\0';
1065 		++*sp;
1066 	} else
1067 		*sp = NULL;
1068 
1069 	return p;
1070 } /* dns_strsep() */
1071 
1072 #else
1073 #define dns_strsep(...)	strsep(__VA_ARGS__)
1074 #endif
1075 
1076 
1077 #if _WIN32
1078 #define strcasecmp(...)		_stricmp(__VA_ARGS__)
1079 #define strncasecmp(...)	_strnicmp(__VA_ARGS__)
1080 #endif
1081 
1082 
dns_isalpha(unsigned char c)1083 static inline _Bool dns_isalpha(unsigned char c) {
1084 	return isalpha(c);
1085 } /* dns_isalpha() */
1086 
dns_isdigit(unsigned char c)1087 static inline _Bool dns_isdigit(unsigned char c) {
1088 	return isdigit(c);
1089 } /* dns_isdigit() */
1090 
dns_isalnum(unsigned char c)1091 static inline _Bool dns_isalnum(unsigned char c) {
1092 	return isalnum(c);
1093 } /* dns_isalnum() */
1094 
dns_isspace(unsigned char c)1095 static inline _Bool dns_isspace(unsigned char c) {
1096 	return isspace(c);
1097 } /* dns_isspace() */
1098 
1099 
dns_poll(int fd,short events,int timeout)1100 static int dns_poll(int fd, short events, int timeout) {
1101 	fd_set rset, wset;
1102 
1103 	if (!events)
1104 		return 0;
1105 
1106 	assert(fd >= 0 && (unsigned)fd < FD_SETSIZE);
1107 
1108 	FD_ZERO(&rset);
1109 	FD_ZERO(&wset);
1110 
1111 	if (events & DNS_POLLIN)
1112 		FD_SET(fd, &rset);
1113 
1114 	if (events & DNS_POLLOUT)
1115 		FD_SET(fd, &wset);
1116 
1117 	select(fd + 1, &rset, &wset, 0, (timeout >= 0)? &(struct timeval){ timeout, 0 } : NULL);
1118 
1119 	return 0;
1120 } /* dns_poll() */
1121 
1122 
1123 #if !_WIN32
dns_sigmask(int how,const sigset_t * set,sigset_t * oset)1124 DNS_NOTUSED static int dns_sigmask(int how, const sigset_t *set, sigset_t *oset) {
1125 #if DNS_THREAD_SAFE
1126 	return pthread_sigmask(how, set, oset);
1127 #else
1128 	return (0 == sigprocmask(how, set, oset))? 0 : errno;
1129 #endif
1130 } /* dns_sigmask() */
1131 #endif
1132 
1133 
dns_send(int fd,const void * src,size_t lim,int flags)1134 static long dns_send(int fd, const void *src, size_t lim, int flags) {
1135 #if _WIN32 || !defined SIGPIPE || defined SO_NOSIGPIPE
1136 	return send(fd, src, lim, flags);
1137 #elif defined MSG_NOSIGNAL
1138 	return send(fd, src, lim, flags|MSG_NOSIGNAL);
1139 #elif _POSIX_REALTIME_SIGNALS > 0 /* require sigtimedwait */
1140 	/*
1141 	 * SIGPIPE handling similar to the approach described in
1142 	 * http://krokisplace.blogspot.com/2010/02/suppressing-sigpipe-in-library.html
1143 	 */
1144 	sigset_t pending, blocked, piped;
1145 	long count;
1146 	int saved, error;
1147 
1148 	sigemptyset(&pending);
1149 	sigpending(&pending);
1150 
1151 	if (!sigismember(&pending, SIGPIPE)) {
1152 		sigemptyset(&piped);
1153 		sigaddset(&piped, SIGPIPE);
1154 		sigemptyset(&blocked);
1155 
1156 		if ((error = dns_sigmask(SIG_BLOCK, &piped, &blocked)))
1157 			goto error;
1158 	}
1159 
1160 	count = send(fd, src, lim, flags);
1161 
1162 	if (!sigismember(&pending, SIGPIPE)) {
1163 		saved = errno;
1164 
1165 		if (count == -1 && errno == EPIPE) {
1166 			while (-1 == sigtimedwait(&piped, NULL, &(struct timespec){ 0, 0 }) && errno == EINTR)
1167 				;;
1168 		}
1169 
1170 		if ((error = dns_sigmask(SIG_SETMASK, &blocked, NULL)))
1171 			goto error;
1172 
1173 		errno = saved;
1174 	}
1175 
1176 	return count;
1177 error:
1178 	errno = error;
1179 
1180 	return -1;
1181 #else
1182 #error "unable to suppress SIGPIPE"
1183 	return send(fd, src, lim, flags);
1184 #endif
1185 } /* dns_send() */
1186 
1187 
1188 #define DNS_FOPEN_STDFLAGS "rwabt+"
1189 
dns_fopen_addflag(char * dst,const char * src,size_t lim,int fc)1190 static dns_error_t dns_fopen_addflag(char *dst, const char *src, size_t lim, int fc) {
1191 	char *p = dst, *pe = dst + lim;
1192 
1193 	/* copy standard flags */
1194 	while (*src && strchr(DNS_FOPEN_STDFLAGS, *src)) {
1195 		if (!(p < pe))
1196 			return ENOMEM;
1197 		*p++ = *src++;
1198 	}
1199 
1200 	/* append flag to standard flags */
1201 	if (!(p < pe))
1202 		return ENOMEM;
1203 	*p++ = fc;
1204 
1205 	/* copy remaining mode string, including '\0' */
1206 	do {
1207 		if (!(p < pe))
1208 			return ENOMEM;
1209 	} while ((*p++ = *src++));
1210 
1211 	return 0;
1212 } /* dns_fopen_addflag() */
1213 
dns_fopen(const char * path,const char * mode,dns_error_t * _error)1214 static FILE *dns_fopen(const char *path, const char *mode, dns_error_t *_error) {
1215 	FILE *fp;
1216 	char mode_cloexec[32];
1217 	int error;
1218 
1219 	assert(path && mode && *mode);
1220 	if (!*path) {
1221 		error = EINVAL;
1222 		goto error;
1223 	}
1224 
1225 #if _WIN32 || _WIN64
1226 	if ((error = dns_fopen_addflag(mode_cloexec, mode, sizeof mode_cloexec, 'N')))
1227 		goto error;
1228 	if (!(fp = fopen(path, mode_cloexec)))
1229 		goto syerr;
1230 #else
1231 	if ((error = dns_fopen_addflag(mode_cloexec, mode, sizeof mode_cloexec, 'e')))
1232 		goto error;
1233 	if (!(fp = fopen(path, mode_cloexec))) {
1234 		if (errno != EINVAL)
1235 			goto syerr;
1236 		if (!(fp = fopen(path, mode)))
1237 			goto syerr;
1238 	}
1239 #endif
1240 
1241 	return fp;
1242 syerr:
1243 	error = dns_syerr();
1244 error:
1245 	*_error = error;
1246 
1247 	return NULL;
1248 } /* dns_fopen() */
1249 
1250 
1251 /*
1252  * F I X E D - S I Z E D  B U F F E R  R O U T I N E S
1253  *
1254  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1255 
1256 #define DNS_B_INIT(src, n) { \
1257 	(unsigned char *)(src), \
1258 	(unsigned char *)(src), \
1259 	(unsigned char *)(src) + (n), \
1260 }
1261 
1262 #define DNS_B_FROM(src, n) DNS_B_INIT((src), (n))
1263 #define DNS_B_INTO(src, n) DNS_B_INIT((src), (n))
1264 
1265 struct dns_buf {
1266 	const unsigned char *base;
1267 	unsigned char *p;
1268 	const unsigned char *pe;
1269 	dns_error_t error;
1270 	size_t overflow;
1271 }; /* struct dns_buf */
1272 
1273 static inline size_t
dns_b_tell(struct dns_buf * b)1274 dns_b_tell(struct dns_buf *b)
1275 {
1276 	return b->p - b->base;
1277 }
1278 
1279 static inline dns_error_t
dns_b_setoverflow(struct dns_buf * b,size_t n,dns_error_t error)1280 dns_b_setoverflow(struct dns_buf *b, size_t n, dns_error_t error)
1281 {
1282 	b->overflow += n;
1283 	return b->error = error;
1284 }
1285 
1286 DNS_NOTUSED static struct dns_buf *
dns_b_into(struct dns_buf * b,void * src,size_t n)1287 dns_b_into(struct dns_buf *b, void *src, size_t n)
1288 {
1289 	*b = (struct dns_buf)DNS_B_INTO(src, n);
1290 
1291 	return b;
1292 }
1293 
1294 static dns_error_t
dns_b_putc(struct dns_buf * b,unsigned char uc)1295 dns_b_putc(struct dns_buf *b, unsigned char uc)
1296 {
1297 	if (!(b->p < b->pe))
1298 		return dns_b_setoverflow(b, 1, DNS_ENOBUFS);
1299 
1300 	*b->p++ = uc;
1301 
1302 	return 0;
1303 }
1304 
1305 static dns_error_t
dns_b_pputc(struct dns_buf * b,unsigned char uc,size_t p)1306 dns_b_pputc(struct dns_buf *b, unsigned char uc, size_t p)
1307 {
1308 	size_t pe = b->pe - b->base;
1309 	if (pe <= p)
1310 		return dns_b_setoverflow(b, p - pe + 1, DNS_ENOBUFS);
1311 
1312 	*((unsigned char *)b->base + p) = uc;
1313 
1314 	return 0;
1315 }
1316 
1317 static inline dns_error_t
dns_b_put16(struct dns_buf * b,uint16_t u)1318 dns_b_put16(struct dns_buf *b, uint16_t u)
1319 {
1320 	return dns_b_putc(b, u >> 8), dns_b_putc(b, u >> 0);
1321 }
1322 
1323 static inline dns_error_t
dns_b_pput16(struct dns_buf * b,uint16_t u,size_t p)1324 dns_b_pput16(struct dns_buf *b, uint16_t u, size_t p)
1325 {
1326 	if (dns_b_pputc(b, u >> 8, p) || dns_b_pputc(b, u >> 0, p + 1))
1327 		return b->error;
1328 
1329 	return 0;
1330 }
1331 
1332 DNS_NOTUSED static inline dns_error_t
dns_b_put32(struct dns_buf * b,uint32_t u)1333 dns_b_put32(struct dns_buf *b, uint32_t u)
1334 {
1335 	return dns_b_putc(b, u >> 24), dns_b_putc(b, u >> 16),
1336 	    dns_b_putc(b, u >> 8), dns_b_putc(b, u >> 0);
1337 }
1338 
1339 static dns_error_t
dns_b_put(struct dns_buf * b,const void * src,size_t len)1340 dns_b_put(struct dns_buf *b, const void *src, size_t len)
1341 {
1342 	size_t n = DNS_PP_MIN((size_t)(b->pe - b->p), len);
1343 
1344 	memcpy(b->p, src, n);
1345 	b->p += n;
1346 
1347 	if (n < len)
1348 		return dns_b_setoverflow(b, len - n, DNS_ENOBUFS);
1349 
1350 	return 0;
1351 }
1352 
1353 static dns_error_t
dns_b_puts(struct dns_buf * b,const void * src)1354 dns_b_puts(struct dns_buf *b, const void *src)
1355 {
1356 	return dns_b_put(b, src, strlen(src));
1357 }
1358 
1359 DNS_NOTUSED static inline dns_error_t
dns_b_fmtju(struct dns_buf * b,const uintmax_t u,const unsigned width)1360 dns_b_fmtju(struct dns_buf *b, const uintmax_t u, const unsigned width)
1361 {
1362 	size_t digits, padding, overflow;
1363 	uintmax_t r;
1364 	unsigned char *tp, *te, tc;
1365 
1366 	digits = 0;
1367 	r = u;
1368 	do {
1369 		digits++;
1370 		r /= 10;
1371 	} while (r);
1372 
1373 	padding = width - DNS_PP_MIN(digits, width);
1374 	overflow = (digits + padding) - DNS_PP_MIN((size_t)(b->pe - b->p), (digits + padding));
1375 
1376 	while (padding--) {
1377 		dns_b_putc(b, '0');
1378 	}
1379 
1380 	digits = 0;
1381 	tp = b->p;
1382 	r = u;
1383 	do {
1384 		if (overflow < ++digits)
1385 			dns_b_putc(b, '0' + (r % 10));
1386 		r /= 10;
1387 	} while (r);
1388 
1389 	te = b->p;
1390 	while (tp < te) {
1391 		tc = *--te;
1392 		*te = *tp;
1393 		*tp++ = tc;
1394 	}
1395 
1396 	return b->error;
1397 }
1398 
1399 static void
dns_b_popc(struct dns_buf * b)1400 dns_b_popc(struct dns_buf *b)
1401 {
1402 	if (b->overflow && !--b->overflow)
1403 		b->error = 0;
1404 	if (b->p > b->base)
1405 		b->p--;
1406 }
1407 
1408 static inline const char *
dns_b_tolstring(struct dns_buf * b,size_t * n)1409 dns_b_tolstring(struct dns_buf *b, size_t *n)
1410 {
1411 	if (b->p < b->pe) {
1412 		*b->p = '\0';
1413 		*n = b->p - b->base;
1414 
1415 		return (const char *)b->base;
1416 	} else if (b->p > b->base) {
1417 		if (b->p[-1] != '\0') {
1418 			dns_b_setoverflow(b, 1, DNS_ENOBUFS);
1419 			b->p[-1] = '\0';
1420 		}
1421 		*n = &b->p[-1] - b->base;
1422 
1423 		return (const char *)b->base;
1424 	} else {
1425 		*n = 0;
1426 
1427 		return "";
1428 	}
1429 }
1430 
1431 static inline const char *
dns_b_tostring(struct dns_buf * b)1432 dns_b_tostring(struct dns_buf *b)
1433 {
1434 	size_t n;
1435 	return dns_b_tolstring(b, &n);
1436 }
1437 
1438 static inline size_t
dns_b_strlen(struct dns_buf * b)1439 dns_b_strlen(struct dns_buf *b)
1440 {
1441 	size_t n;
1442 	dns_b_tolstring(b, &n);
1443 	return n;
1444 }
1445 
1446 static inline size_t
dns_b_strllen(struct dns_buf * b)1447 dns_b_strllen(struct dns_buf *b)
1448 {
1449 	size_t n = dns_b_strlen(b);
1450 	return n + b->overflow;
1451 }
1452 
1453 DNS_NOTUSED static const struct dns_buf *
dns_b_from(const struct dns_buf * b,const void * src,size_t n)1454 dns_b_from(const struct dns_buf *b, const void *src, size_t n)
1455 {
1456 	*(struct dns_buf *)b = (struct dns_buf)DNS_B_FROM(src, n);
1457 
1458 	return b;
1459 }
1460 
1461 static inline int
dns_b_getc(const struct dns_buf * _b,const int eof)1462 dns_b_getc(const struct dns_buf *_b, const int eof)
1463 {
1464 	struct dns_buf *b = (struct dns_buf *)_b;
1465 
1466 	if (!(b->p < b->pe))
1467 		return dns_b_setoverflow(b, 1, DNS_EILLEGAL), eof;
1468 
1469 	return *b->p++;
1470 }
1471 
1472 static inline intmax_t
dns_b_get16(const struct dns_buf * b,const intmax_t eof)1473 dns_b_get16(const struct dns_buf *b, const intmax_t eof)
1474 {
1475 	intmax_t n;
1476 
1477 	n = (dns_b_getc(b, 0) << 8);
1478 	n |= (dns_b_getc(b, 0) << 0);
1479 
1480 	return (!b->overflow)? n : eof;
1481 }
1482 
1483 DNS_NOTUSED static inline intmax_t
dns_b_get32(const struct dns_buf * b,const intmax_t eof)1484 dns_b_get32(const struct dns_buf *b, const intmax_t eof)
1485 {
1486 	intmax_t n;
1487 
1488 	n = (dns_b_get16(b, 0) << 16);
1489 	n |= (dns_b_get16(b, 0) << 0);
1490 
1491 	return (!b->overflow)? n : eof;
1492 }
1493 
1494 static inline dns_error_t
dns_b_move(struct dns_buf * dst,const struct dns_buf * _src,size_t n)1495 dns_b_move(struct dns_buf *dst, const struct dns_buf *_src, size_t n)
1496 {
1497 	struct dns_buf *src = (struct dns_buf *)_src;
1498 	size_t src_n = DNS_PP_MIN((size_t)(src->pe - src->p), n);
1499 	size_t src_r = n - src_n;
1500 
1501 	dns_b_put(dst, src->p, src_n);
1502 	src->p += src_n;
1503 
1504 	if (src_r)
1505 		return dns_b_setoverflow(src, src_r, DNS_EILLEGAL);
1506 
1507 	return dst->error;
1508 }
1509 
1510 
1511 /*
1512  * P A C K E T  R O U T I N E S
1513  *
1514  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1515 
dns_p_count(struct dns_packet * P,enum dns_section section)1516 unsigned dns_p_count(struct dns_packet *P, enum dns_section section) {
1517 	unsigned count;
1518 
1519 	switch (section) {
1520 	case DNS_S_QD:
1521 		return ntohs(dns_header(P)->qdcount);
1522 	case DNS_S_AN:
1523 		return ntohs(dns_header(P)->ancount);
1524 	case DNS_S_NS:
1525 		return ntohs(dns_header(P)->nscount);
1526 	case DNS_S_AR:
1527 		return ntohs(dns_header(P)->arcount);
1528 	default:
1529 		count = 0;
1530 
1531 		if (section & DNS_S_QD)
1532 			count += ntohs(dns_header(P)->qdcount);
1533 		if (section & DNS_S_AN)
1534 			count += ntohs(dns_header(P)->ancount);
1535 		if (section & DNS_S_NS)
1536 			count += ntohs(dns_header(P)->nscount);
1537 		if (section & DNS_S_AR)
1538 			count += ntohs(dns_header(P)->arcount);
1539 
1540 		return count;
1541 	}
1542 } /* dns_p_count() */
1543 
1544 
dns_p_init(struct dns_packet * P,size_t size)1545 struct dns_packet *dns_p_init(struct dns_packet *P, size_t size) {
1546 	if (!P)
1547 		return 0;
1548 
1549 	assert(size >= offsetof(struct dns_packet, data) + 12);
1550 
1551 	memset(P, 0, sizeof *P);
1552 	P->size = size - offsetof(struct dns_packet, data);
1553 	P->end  = 12;
1554 
1555 	memset(P->data, '\0', 12);
1556 
1557 	return P;
1558 } /* dns_p_init() */
1559 
1560 
dns_p_reset(struct dns_packet * P)1561 static struct dns_packet *dns_p_reset(struct dns_packet *P) {
1562 	return dns_p_init(P, offsetof(struct dns_packet, data) + P->size);
1563 } /* dns_p_reset() */
1564 
1565 
dns_p_qend(struct dns_packet * P)1566 static unsigned short dns_p_qend(struct dns_packet *P) {
1567 	unsigned short qend	= 12;
1568 	unsigned i, count	= dns_p_count(P, DNS_S_QD);
1569 
1570 	for (i = 0; i < count && qend < P->end; i++) {
1571 		if (P->end == (qend = dns_d_skip(qend, P)))
1572 			goto invalid;
1573 
1574 		if (P->end - qend < 4)
1575 			goto invalid;
1576 
1577 		qend	+= 4;
1578 	}
1579 
1580 	return DNS_PP_MIN(qend, P->end);
1581 invalid:
1582 	return P->end;
1583 } /* dns_p_qend() */
1584 
1585 
dns_p_make(size_t len,int * error)1586 struct dns_packet *dns_p_make(size_t len, int *error) {
1587 	struct dns_packet *P;
1588 	size_t size = dns_p_calcsize(len);
1589 
1590 	if (!(P = dns_p_init(malloc(size), size)))
1591 		*error = dns_syerr();
1592 
1593 	return P;
1594 } /* dns_p_make() */
1595 
1596 
dns_p_free(struct dns_packet * P)1597 static void dns_p_free(struct dns_packet *P) {
1598 	free(P);
1599 } /* dns_p_free() */
1600 
1601 
1602 /* convience routine to free any existing packet before storing new packet */
dns_p_setptr(struct dns_packet ** dst,struct dns_packet * src)1603 static struct dns_packet *dns_p_setptr(struct dns_packet **dst, struct dns_packet *src) {
1604 	dns_p_free(*dst);
1605 
1606 	*dst = src;
1607 
1608 	return src;
1609 } /* dns_p_setptr() */
1610 
1611 
dns_p_movptr(struct dns_packet ** dst,struct dns_packet ** src)1612 static struct dns_packet *dns_p_movptr(struct dns_packet **dst, struct dns_packet **src) {
1613 	dns_p_setptr(dst, *src);
1614 
1615 	*src = NULL;
1616 
1617 	return *dst;
1618 } /* dns_p_movptr() */
1619 
1620 
dns_p_grow(struct dns_packet ** P)1621 int dns_p_grow(struct dns_packet **P) {
1622 	struct dns_packet *tmp;
1623 	size_t size;
1624 	int error;
1625 
1626 	if (!*P) {
1627 		if (!(*P = dns_p_make(DNS_P_QBUFSIZ, &error)))
1628 			return error;
1629 
1630 		return 0;
1631 	}
1632 
1633 	size = dns_p_sizeof(*P);
1634 	size |= size >> 1;
1635 	size |= size >> 2;
1636 	size |= size >> 4;
1637 	size |= size >> 8;
1638 	size++;
1639 
1640 	if (size > 65536)
1641 		return DNS_ENOBUFS;
1642 
1643 	if (!(tmp = realloc(*P, dns_p_calcsize(size))))
1644 		return dns_syerr();
1645 
1646 	tmp->size = size;
1647 	*P = tmp;
1648 
1649 	return 0;
1650 } /* dns_p_grow() */
1651 
1652 
dns_p_copy(struct dns_packet * P,const struct dns_packet * P0)1653 struct dns_packet *dns_p_copy(struct dns_packet *P, const struct dns_packet *P0) {
1654 	if (!P)
1655 		return 0;
1656 
1657 	P->end	= DNS_PP_MIN(P->size, P0->end);
1658 
1659 	memcpy(P->data, P0->data, P->end);
1660 
1661 	return P;
1662 } /* dns_p_copy() */
1663 
1664 
dns_p_merge(struct dns_packet * A,enum dns_section Amask,struct dns_packet * B,enum dns_section Bmask,int * error_)1665 struct dns_packet *dns_p_merge(struct dns_packet *A, enum dns_section Amask, struct dns_packet *B, enum dns_section Bmask, int *error_) {
1666 	size_t bufsiz = DNS_PP_MIN(65535, ((A)? A->end : 0) + ((B)? B->end : 0));
1667 	struct dns_packet *M;
1668 	enum dns_section section;
1669 	struct dns_rr rr, mr;
1670 	int error, copy;
1671 
1672 	if (!A && B) {
1673 		A = B;
1674 		Amask = Bmask;
1675 		B = 0;
1676 	}
1677 
1678 merge:
1679 	if (!(M = dns_p_make(bufsiz, &error)))
1680 		goto error;
1681 
1682 	for (section = DNS_S_QD; (DNS_S_ALL & section); section <<= 1) {
1683 		if (A && (section & Amask)) {
1684 			dns_rr_foreach(&rr, A, .section = section) {
1685 				if ((error = dns_rr_copy(M, &rr, A)))
1686 					goto error;
1687 			}
1688 		}
1689 
1690 		if (B && (section & Bmask)) {
1691 			dns_rr_foreach(&rr, B, .section = section) {
1692 				copy = 1;
1693 
1694 				dns_rr_foreach(&mr, M, .type = rr.type, .section = DNS_S_ALL) {
1695 					if (!(copy = dns_rr_cmp(&rr, B, &mr, M)))
1696 						break;
1697 				}
1698 
1699 				if (copy && (error = dns_rr_copy(M, &rr, B)))
1700 					goto error;
1701 			}
1702 		}
1703 	}
1704 
1705 	return M;
1706 error:
1707 	dns_p_setptr(&M, NULL);
1708 
1709 	if (error == DNS_ENOBUFS && bufsiz < 65535) {
1710 		bufsiz = DNS_PP_MIN(65535, bufsiz * 2);
1711 
1712 		goto merge;
1713 	}
1714 
1715 	*error_	= error;
1716 
1717 	return 0;
1718 } /* dns_p_merge() */
1719 
1720 
1721 static unsigned short dns_l_skip(unsigned short, const unsigned char *, size_t);
1722 
dns_p_dictadd(struct dns_packet * P,unsigned short dn)1723 void dns_p_dictadd(struct dns_packet *P, unsigned short dn) {
1724 	unsigned short lp, lptr, i;
1725 
1726 	lp	= dn;
1727 
1728 	while (lp < P->end) {
1729 		if (0xc0 == (0xc0 & P->data[lp]) && P->end - lp >= 2 && lp != dn) {
1730 			lptr	= ((0x3f & P->data[lp + 0]) << 8)
1731 				| ((0xff & P->data[lp + 1]) << 0);
1732 
1733 			for (i = 0; i < lengthof(P->dict) && P->dict[i]; i++) {
1734 				if (P->dict[i] == lptr) {
1735 					P->dict[i]	= dn;
1736 
1737 					return;
1738 				}
1739 			}
1740 		}
1741 
1742 		lp	= dns_l_skip(lp, P->data, P->end);
1743 	}
1744 
1745 	for (i = 0; i < lengthof(P->dict); i++) {
1746 		if (!P->dict[i]) {
1747 			P->dict[i]	= dn;
1748 
1749 			break;
1750 		}
1751 	}
1752 } /* dns_p_dictadd() */
1753 
1754 
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)1755 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) {
1756 	size_t end = P->end;
1757 	int error;
1758 
1759 	if ((error = dns_d_push(P, dn, dnlen)))
1760 		goto error;
1761 
1762 	if (P->size - P->end < 4)
1763 		goto nobufs;
1764 
1765 	P->data[P->end++] = 0xff & (type >> 8);
1766 	P->data[P->end++] = 0xff & (type >> 0);
1767 
1768 	P->data[P->end++] = 0xff & (class >> 8);
1769 	P->data[P->end++] = 0xff & (class >> 0);
1770 
1771 	if (section == DNS_S_QD)
1772 		goto update;
1773 
1774 	if (P->size - P->end < 6)
1775 		goto nobufs;
1776 
1777 	if (type != DNS_T_OPT)
1778 		ttl = DNS_PP_MIN(ttl, 0x7fffffffU);
1779 	P->data[P->end++] = ttl >> 24;
1780 	P->data[P->end++] = ttl >> 16;
1781 	P->data[P->end++] = ttl >> 8;
1782 	P->data[P->end++] = ttl >> 0;
1783 
1784 	if ((error = dns_any_push(P, (union dns_any *)any, type)))
1785 		goto error;
1786 
1787 update:
1788 	switch (section) {
1789 	case DNS_S_QD:
1790 		if (dns_p_count(P, DNS_S_AN|DNS_S_NS|DNS_S_AR))
1791 			goto order;
1792 
1793 		if (!P->memo.qd.base && (error = dns_p_study(P)))
1794 			goto error;
1795 
1796 		dns_header(P)->qdcount = htons(ntohs(dns_header(P)->qdcount) + 1);
1797 
1798 		P->memo.qd.end  = P->end;
1799 		P->memo.an.base = P->end;
1800 		P->memo.an.end  = P->end;
1801 		P->memo.ns.base = P->end;
1802 		P->memo.ns.end  = P->end;
1803 		P->memo.ar.base = P->end;
1804 		P->memo.ar.end  = P->end;
1805 
1806 		break;
1807 	case DNS_S_AN:
1808 		if (dns_p_count(P, DNS_S_NS|DNS_S_AR))
1809 			goto order;
1810 
1811 		if (!P->memo.an.base && (error = dns_p_study(P)))
1812 			goto error;
1813 
1814 		dns_header(P)->ancount = htons(ntohs(dns_header(P)->ancount) + 1);
1815 
1816 		P->memo.an.end  = P->end;
1817 		P->memo.ns.base = P->end;
1818 		P->memo.ns.end  = P->end;
1819 		P->memo.ar.base = P->end;
1820 		P->memo.ar.end  = P->end;
1821 
1822 		break;
1823 	case DNS_S_NS:
1824 		if (dns_p_count(P, DNS_S_AR))
1825 			goto order;
1826 
1827 		if (!P->memo.ns.base && (error = dns_p_study(P)))
1828 			goto error;
1829 
1830 		dns_header(P)->nscount = htons(ntohs(dns_header(P)->nscount) + 1);
1831 
1832 		P->memo.ns.end  = P->end;
1833 		P->memo.ar.base = P->end;
1834 		P->memo.ar.end  = P->end;
1835 
1836 		break;
1837 	case DNS_S_AR:
1838 		if (!P->memo.ar.base && (error = dns_p_study(P)))
1839 			goto error;
1840 
1841 		dns_header(P)->arcount = htons(ntohs(dns_header(P)->arcount) + 1);
1842 
1843 		P->memo.ar.end = P->end;
1844 
1845 		if (type == DNS_T_OPT && !P->memo.opt.p) {
1846 			P->memo.opt.p = end;
1847 			P->memo.opt.maxudp = class;
1848 			P->memo.opt.ttl = ttl;
1849 		}
1850 
1851 		break;
1852 	default:
1853 		error = DNS_ESECTION;
1854 
1855 		goto error;
1856 	} /* switch() */
1857 
1858 	return 0;
1859 nobufs:
1860 	error = DNS_ENOBUFS;
1861 
1862 	goto error;
1863 order:
1864 	error = DNS_EORDER;
1865 
1866 	goto error;
1867 error:
1868 	P->end = end;
1869 
1870 	return error;
1871 } /* dns_p_push() */
1872 
1873 
dns_p_dump3(struct dns_packet * P,struct dns_rr_i * I,FILE * fp)1874 static void dns_p_dump3(struct dns_packet *P, struct dns_rr_i *I, FILE *fp) {
1875 	enum dns_section section;
1876 	struct dns_rr rr;
1877 	int error;
1878 	union dns_any any;
1879 	char pretty[sizeof any * 2];
1880 	size_t len;
1881 
1882 	fputs(";; [HEADER]\n", fp);
1883 	fprintf(fp, ";;    qid : %d\n", ntohs(dns_header(P)->qid));
1884 	fprintf(fp, ";;     qr : %s(%d)\n", (dns_header(P)->qr)? "RESPONSE" : "QUERY", dns_header(P)->qr);
1885 	fprintf(fp, ";; opcode : %s(%d)\n", dns_stropcode(dns_header(P)->opcode), dns_header(P)->opcode);
1886 	fprintf(fp, ";;     aa : %s(%d)\n", (dns_header(P)->aa)? "AUTHORITATIVE" : "NON-AUTHORITATIVE", dns_header(P)->aa);
1887 	fprintf(fp, ";;     tc : %s(%d)\n", (dns_header(P)->tc)? "TRUNCATED" : "NOT-TRUNCATED", dns_header(P)->tc);
1888 	fprintf(fp, ";;     rd : %s(%d)\n", (dns_header(P)->rd)? "RECURSION-DESIRED" : "RECURSION-NOT-DESIRED", dns_header(P)->rd);
1889 	fprintf(fp, ";;     ra : %s(%d)\n", (dns_header(P)->ra)? "RECURSION-ALLOWED" : "RECURSION-NOT-ALLOWED", dns_header(P)->ra);
1890 	fprintf(fp, ";;  rcode : %s(%d)\n", dns_strrcode(dns_p_rcode(P)), dns_p_rcode(P));
1891 
1892 	section	= 0;
1893 
1894 	while (dns_rr_grep(&rr, 1, I, P, &error)) {
1895 		if (section != rr.section)
1896 			fprintf(fp, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(P, rr.section));
1897 
1898 		if ((len = dns_rr_print(pretty, sizeof pretty, &rr, P, &error)))
1899 			fprintf(fp, "%s\n", pretty);
1900 
1901 		section	= rr.section;
1902 	}
1903 } /* dns_p_dump3() */
1904 
1905 
dns_p_dump(struct dns_packet * P,FILE * fp)1906 void dns_p_dump(struct dns_packet *P, FILE *fp) {
1907 	dns_p_dump3(P, dns_rr_i_new(P, .section = 0), fp);
1908 } /* dns_p_dump() */
1909 
1910 
dns_s_unstudy(struct dns_s_memo * m)1911 static void dns_s_unstudy(struct dns_s_memo *m)
1912 	{ m->base = 0; m->end = 0; }
1913 
dns_m_unstudy(struct dns_p_memo * m)1914 static void dns_m_unstudy(struct dns_p_memo *m) {
1915 	dns_s_unstudy(&m->qd);
1916 	dns_s_unstudy(&m->an);
1917 	dns_s_unstudy(&m->ns);
1918 	dns_s_unstudy(&m->ar);
1919 	m->opt.p = 0;
1920 	m->opt.maxudp = 0;
1921 	m->opt.ttl = 0;
1922 } /* dns_m_unstudy() */
1923 
dns_s_study(struct dns_s_memo * m,enum dns_section section,unsigned short base,struct dns_packet * P)1924 static int dns_s_study(struct dns_s_memo *m, enum dns_section section, unsigned short base, struct dns_packet *P) {
1925 	unsigned short count, rp;
1926 
1927 	count = dns_p_count(P, section);
1928 
1929 	for (rp = base; count && rp < P->end; count--)
1930 		rp = dns_rr_skip(rp, P);
1931 
1932 	m->base = base;
1933 	m->end  = rp;
1934 
1935 	return 0;
1936 } /* dns_s_study() */
1937 
dns_m_study(struct dns_p_memo * m,struct dns_packet * P)1938 static int dns_m_study(struct dns_p_memo *m, struct dns_packet *P) {
1939 	struct dns_rr rr;
1940 	int error;
1941 
1942 	if ((error = dns_s_study(&m->qd, DNS_S_QD, 12, P)))
1943 		goto error;
1944 	if ((error = dns_s_study(&m->an, DNS_S_AN, m->qd.end, P)))
1945 		goto error;
1946 	if ((error = dns_s_study(&m->ns, DNS_S_NS, m->an.end, P)))
1947 		goto error;
1948 	if ((error = dns_s_study(&m->ar, DNS_S_AR, m->ns.end, P)))
1949 		goto error;
1950 
1951 	m->opt.p = 0;
1952 	m->opt.maxudp = 0;
1953 	m->opt.ttl = 0;
1954 	dns_rr_foreach(&rr, P, .type = DNS_T_OPT, .section = DNS_S_AR) {
1955 		m->opt.p = rr.dn.p;
1956 		m->opt.maxudp = rr.class;
1957 		m->opt.ttl = rr.ttl;
1958 		break;
1959 	}
1960 
1961 	return 0;
1962 error:
1963 	dns_m_unstudy(m);
1964 
1965 	return error;
1966 } /* dns_m_study() */
1967 
dns_p_study(struct dns_packet * P)1968 int dns_p_study(struct dns_packet *P) {
1969 	return dns_m_study(&P->memo, P);
1970 } /* dns_p_study() */
1971 
1972 
dns_p_rcode(struct dns_packet * P)1973 enum dns_rcode dns_p_rcode(struct dns_packet *P) {
1974 	return 0xfff & ((P->memo.opt.ttl >> 20) | dns_header(P)->rcode);
1975 } /* dns_p_rcode() */
1976 
1977 
1978 /*
1979  * Q U E R Y  P A C K E T  R O U T I N E S
1980  *
1981  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1982 
1983 #define DNS_Q_RD    0x1 /* recursion desired */
1984 #define DNS_Q_EDNS0 0x2 /* include OPT RR */
1985 
1986 static dns_error_t
dns_q_make2(struct dns_packet ** _Q,const char * qname,size_t qlen,enum dns_type qtype,enum dns_class qclass,int qflags)1987 dns_q_make2(struct dns_packet **_Q, const char *qname, size_t qlen, enum dns_type qtype, enum dns_class qclass, int qflags)
1988 {
1989 	struct dns_packet *Q = NULL;
1990 	int error;
1991 
1992 	if (dns_p_movptr(&Q, _Q)) {
1993 		dns_p_reset(Q);
1994 	} else if (!(Q = dns_p_make(DNS_P_QBUFSIZ, &error))) {
1995 		goto error;
1996 	}
1997 
1998 	if ((error = dns_p_push(Q, DNS_S_QD, qname, qlen, qtype, qclass, 0, 0)))
1999 		goto error;
2000 
2001 	dns_header(Q)->rd = !!(qflags & DNS_Q_RD);
2002 
2003 	if (qflags & DNS_Q_EDNS0) {
2004 		struct dns_opt opt = DNS_OPT_INIT(&opt);
2005 
2006 		opt.version = 0; /* RFC 6891 version */
2007 		opt.maxudp = 4096;
2008 
2009 		if ((error = dns_p_push(Q, DNS_S_AR, ".", 1, DNS_T_OPT, dns_opt_class(&opt), dns_opt_ttl(&opt), &opt)))
2010 			goto error;
2011 	}
2012 
2013 	*_Q = Q;
2014 
2015 	return 0;
2016 error:
2017 	dns_p_free(Q);
2018 
2019 	return error;
2020 }
2021 
2022 static dns_error_t
dns_q_make(struct dns_packet ** Q,const char * qname,enum dns_type qtype,enum dns_class qclass,int qflags)2023 dns_q_make(struct dns_packet **Q, const char *qname, enum dns_type qtype, enum dns_class qclass, int qflags)
2024 {
2025 	return dns_q_make2(Q, qname, strlen(qname), qtype, qclass, qflags);
2026 }
2027 
2028 static dns_error_t
dns_q_remake(struct dns_packet ** Q,int qflags)2029 dns_q_remake(struct dns_packet **Q, int qflags)
2030 {
2031 	char qname[DNS_D_MAXNAME + 1];
2032 	size_t qlen;
2033 	struct dns_rr rr;
2034 	int error;
2035 
2036 	assert(Q && *Q);
2037 	if ((error = dns_rr_parse(&rr, 12, *Q)))
2038 		return error;
2039 	if (!(qlen = dns_d_expand(qname, sizeof qname, rr.dn.p, *Q, &error)))
2040 		return error;
2041 	if (qlen >= sizeof qname)
2042 		return DNS_EILLEGAL;
2043 	return dns_q_make2(Q, qname, qlen, rr.type, rr.class, qflags);
2044 }
2045 
2046 /*
2047  * D O M A I N  N A M E  R O U T I N E S
2048  *
2049  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2050 
2051 #ifndef DNS_D_MAXPTRS
2052 #define DNS_D_MAXPTRS	127	/* Arbitrary; possible, valid depth is something like packet size / 2 + fudge. */
2053 #endif
2054 
dns_l_expand(unsigned char * dst,size_t lim,unsigned short src,unsigned short * nxt,const unsigned char * data,size_t end)2055 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) {
2056 	unsigned short len;
2057 	unsigned nptrs	= 0;
2058 
2059 retry:
2060 	if (src >= end)
2061 		goto invalid;
2062 
2063 	switch (0x03 & (data[src] >> 6)) {
2064 	case 0x00:
2065 		len	= (0x3f & (data[src++]));
2066 
2067 		if (end - src < len)
2068 			goto invalid;
2069 
2070 		if (lim > 0) {
2071 			memcpy(dst, &data[src], DNS_PP_MIN(lim, len));
2072 
2073 			dst[DNS_PP_MIN(lim - 1, len)]	= '\0';
2074 		}
2075 
2076 		*nxt	= src + len;
2077 
2078 		return len;
2079 	case 0x01:
2080 		goto invalid;
2081 	case 0x02:
2082 		goto invalid;
2083 	case 0x03:
2084 		if (++nptrs > DNS_D_MAXPTRS)
2085 			goto invalid;
2086 
2087 		if (end - src < 2)
2088 			goto invalid;
2089 
2090 		src	= ((0x3f & data[src + 0]) << 8)
2091 			| ((0xff & data[src + 1]) << 0);
2092 
2093 		goto retry;
2094 	} /* switch() */
2095 
2096 	/* NOT REACHED */
2097 invalid:
2098 	*nxt	= end;
2099 
2100 	return 0;
2101 } /* dns_l_expand() */
2102 
2103 
dns_l_skip(unsigned short src,const unsigned char * data,size_t end)2104 static unsigned short dns_l_skip(unsigned short src, const unsigned char *data, size_t end) {
2105 	unsigned short len;
2106 
2107 	if (src >= end)
2108 		goto invalid;
2109 
2110 	switch (0x03 & (data[src] >> 6)) {
2111 	case 0x00:
2112 		len	= (0x3f & (data[src++]));
2113 
2114 		if (end - src < len)
2115 			goto invalid;
2116 
2117 		return (len)? src + len : end;
2118 	case 0x01:
2119 		goto invalid;
2120 	case 0x02:
2121 		goto invalid;
2122 	case 0x03:
2123 		return end;
2124 	} /* switch() */
2125 
2126 	/* NOT REACHED */
2127 invalid:
2128 	return end;
2129 } /* dns_l_skip() */
2130 
2131 
dns_d_isanchored(const void * _src,size_t len)2132 static _Bool dns_d_isanchored(const void *_src, size_t len) {
2133 	const unsigned char *src = _src;
2134 	return len > 0 && src[len - 1] == '.';
2135 } /* dns_d_isanchored() */
2136 
2137 
dns_d_ndots(const void * _src,size_t len)2138 static size_t dns_d_ndots(const void *_src, size_t len) {
2139 	const unsigned char *p = _src, *pe = p + len;
2140 	size_t ndots = 0;
2141 
2142 	while ((p = memchr(p, '.', pe - p))) {
2143 		ndots++;
2144 		p++;
2145 	}
2146 
2147 	return ndots;
2148 } /* dns_d_ndots() */
2149 
2150 
dns_d_trim(void * dst_,size_t lim,const void * src_,size_t len,int flags)2151 static size_t dns_d_trim(void *dst_, size_t lim, const void *src_, size_t len, int flags) {
2152 	unsigned char *dst = dst_;
2153 	const unsigned char *src = src_;
2154 	size_t dp = 0, sp = 0;
2155 	int lc;
2156 
2157 	/* trim any leading dot(s) */
2158 	while (sp < len && src[sp] == '.')
2159 		sp++;
2160 
2161 	for (lc = 0; sp < len; lc = src[sp++]) {
2162 		/* trim extra dot(s) */
2163 		if (src[sp] == '.' && lc == '.')
2164 			continue;
2165 
2166 		if (dp < lim)
2167 			dst[dp] = src[sp];
2168 
2169 		dp++;
2170 	}
2171 
2172 	if ((flags & DNS_D_ANCHOR) && lc != '.') {
2173 		if (dp < lim)
2174 			dst[dp] = '.';
2175 
2176 		dp++;
2177 	}
2178 
2179 	if (lim > 0)
2180 		dst[DNS_PP_MIN(dp, lim - 1)] = '\0';
2181 
2182 	return dp;
2183 } /* dns_d_trim() */
2184 
2185 
dns_d_init(void * dst,size_t lim,const void * src,size_t len,int flags)2186 char *dns_d_init(void *dst, size_t lim, const void *src, size_t len, int flags) {
2187 	if (flags & DNS_D_TRIM) {
2188 		dns_d_trim(dst, lim, src, len, flags);
2189 	} if (flags & DNS_D_ANCHOR) {
2190 		dns_d_anchor(dst, lim, src, len);
2191 	} else {
2192 		memmove(dst, src, DNS_PP_MIN(lim, len));
2193 
2194 		if (lim > 0)
2195 			((char *)dst)[DNS_PP_MIN(len, lim - 1)]	= '\0';
2196 	}
2197 
2198 	return dst;
2199 } /* dns_d_init() */
2200 
2201 
dns_d_anchor(void * dst,size_t lim,const void * src,size_t len)2202 size_t dns_d_anchor(void *dst, size_t lim, const void *src, size_t len) {
2203 	if (len == 0)
2204 		return 0;
2205 
2206 	memmove(dst, src, DNS_PP_MIN(lim, len));
2207 
2208 	if (((const char *)src)[len - 1] != '.') {
2209 		if (len < lim)
2210 			((char *)dst)[len]	= '.';
2211 		len++;
2212 	}
2213 
2214 	if (lim > 0)
2215 		((char *)dst)[DNS_PP_MIN(lim - 1, len)]	= '\0';
2216 
2217 	return len;
2218 } /* dns_d_anchor() */
2219 
2220 
dns_d_cleave(void * dst,size_t lim,const void * src,size_t len)2221 size_t dns_d_cleave(void *dst, size_t lim, const void *src, size_t len) {
2222 	const char *dot;
2223 
2224 	/* XXX: Skip any leading dot. Handles cleaving root ".". */
2225 	if (len == 0 || !(dot = memchr((const char *)src + 1, '.', len - 1)))
2226 		return 0;
2227 
2228 	len	-= dot - (const char *)src;
2229 
2230 	/* XXX: Unless root, skip the label's trailing dot. */
2231 	if (len > 1) {
2232 		src	= ++dot;
2233 		len--;
2234 	} else
2235 		src	= dot;
2236 
2237 	memmove(dst, src, DNS_PP_MIN(lim, len));
2238 
2239 	if (lim > 0)
2240 		((char *)dst)[DNS_PP_MIN(lim - 1, len)]	= '\0';
2241 
2242 	return len;
2243 } /* dns_d_cleave() */
2244 
2245 
dns_d_comp(void * dst_,size_t lim,const void * src_,size_t len,struct dns_packet * P,int * error)2246 size_t dns_d_comp(void *dst_, size_t lim, const void *src_, size_t len, struct dns_packet *P, int *error) {
2247 	struct { unsigned char *b; size_t p, x; } dst, src;
2248 	unsigned char ch	= '.';
2249 
2250 	dst.b	= dst_;
2251 	dst.p	= 0;
2252 	dst.x	= 1;
2253 
2254 	src.b	= (unsigned char *)src_;
2255 	src.p	= 0;
2256 	src.x	= 0;
2257 
2258 	while (src.x < len) {
2259 		ch	= src.b[src.x];
2260 
2261 		if (ch == '.') {
2262 			if (dst.p < lim)
2263 				dst.b[dst.p]	= (0x3f & (src.x - src.p));
2264 
2265 			dst.p	= dst.x++;
2266 			src.p	= ++src.x;
2267 		} else {
2268 			if (dst.x < lim)
2269 				dst.b[dst.x]	= ch;
2270 
2271 			dst.x++;
2272 			src.x++;
2273 		}
2274 	} /* while() */
2275 
2276 	if (src.x > src.p) {
2277 		if (dst.p < lim)
2278 			dst.b[dst.p]	= (0x3f & (src.x - src.p));
2279 
2280 		dst.p	= dst.x;
2281 	}
2282 
2283 	if (dst.p > 1) {
2284 		if (dst.p < lim)
2285 			dst.b[dst.p]	= 0x00;
2286 
2287 		dst.p++;
2288 	}
2289 
2290 #if 1
2291 	if (dst.p < lim) {
2292 		struct { unsigned char label[DNS_D_MAXLABEL + 1]; size_t len; unsigned short p, x, y; } a, b;
2293 		unsigned i;
2294 
2295 		a.p	= 0;
2296 
2297 		while ((a.len = dns_l_expand(a.label, sizeof a.label, a.p, &a.x, dst.b, lim))) {
2298 			for (i = 0; i < lengthof(P->dict) && P->dict[i]; i++) {
2299 				b.p	= P->dict[i];
2300 
2301 				while ((b.len = dns_l_expand(b.label, sizeof b.label, b.p, &b.x, P->data, P->end))) {
2302 					a.y	= a.x;
2303 					b.y	= b.x;
2304 
2305 					while (a.len && b.len && 0 == strcasecmp((char *)a.label, (char *)b.label)) {
2306 						a.len = dns_l_expand(a.label, sizeof a.label, a.y, &a.y, dst.b, lim);
2307 						b.len = dns_l_expand(b.label, sizeof b.label, b.y, &b.y, P->data, P->end);
2308 					}
2309 
2310 					if (a.len == 0 && b.len == 0 && b.p <= 0x3fff) {
2311 						dst.b[a.p++]	= 0xc0
2312 								| (0x3f & (b.p >> 8));
2313 						dst.b[a.p++]	= (0xff & (b.p >> 0));
2314 
2315 						/* silence static analyzers */
2316 						dns_assume(a.p > 0);
2317 
2318 						return a.p;
2319 					}
2320 
2321 					b.p	= b.x;
2322 				} /* while() */
2323 			} /* for() */
2324 
2325 			a.p	= a.x;
2326 		} /* while() */
2327 	} /* if () */
2328 #endif
2329 
2330 	if (!dst.p)
2331 		*error = DNS_EILLEGAL;
2332 
2333 	return dst.p;
2334 } /* dns_d_comp() */
2335 
2336 
dns_d_skip(unsigned short src,struct dns_packet * P)2337 unsigned short dns_d_skip(unsigned short src, struct dns_packet *P) {
2338 	unsigned short len;
2339 
2340 	while (src < P->end) {
2341 		switch (0x03 & (P->data[src] >> 6)) {
2342 		case 0x00:	/* FOLLOWS */
2343 			len	= (0x3f & P->data[src++]);
2344 
2345 			if (0 == len) {
2346 /* success ==> */		return src;
2347 			} else if (P->end - src > len) {
2348 				src	+= len;
2349 
2350 				break;
2351 			} else
2352 				goto invalid;
2353 
2354 			/* NOT REACHED */
2355 		case 0x01:	/* RESERVED */
2356 			goto invalid;
2357 		case 0x02:	/* RESERVED */
2358 			goto invalid;
2359 		case 0x03:	/* POINTER */
2360 			if (P->end - src < 2)
2361 				goto invalid;
2362 
2363 			src	+= 2;
2364 
2365 /* success ==> */	return src;
2366 		} /* switch() */
2367 	} /* while() */
2368 
2369 invalid:
2370 	return P->end;
2371 } /* dns_d_skip() */
2372 
2373 
2374 #include <stdio.h>
2375 
dns_d_expand(void * dst,size_t lim,unsigned short src,struct dns_packet * P,int * error)2376 size_t dns_d_expand(void *dst, size_t lim, unsigned short src, struct dns_packet *P, int *error) {
2377 	size_t dstp	= 0;
2378 	unsigned nptrs	= 0;
2379 	unsigned char len;
2380 
2381 	while (src < P->end) {
2382 		switch ((0x03 & (P->data[src] >> 6))) {
2383 		case 0x00:	/* FOLLOWS */
2384 			len	= (0x3f & P->data[src]);
2385 
2386 			if (0 == len) {
2387 				if (dstp == 0) {
2388 					if (dstp < lim)
2389 						((unsigned char *)dst)[dstp]	= '.';
2390 
2391 					dstp++;
2392 				}
2393 
2394 				/* NUL terminate */
2395 				if (lim > 0)
2396 					((unsigned char *)dst)[DNS_PP_MIN(dstp, lim - 1)]	= '\0';
2397 
2398 /* success ==> */		return dstp;
2399 			}
2400 
2401 			src++;
2402 
2403 			if (P->end - src < len)
2404 				goto toolong;
2405 
2406 			if (dstp < lim)
2407 				memcpy(&((unsigned char *)dst)[dstp], &P->data[src], DNS_PP_MIN(len, lim - dstp));
2408 
2409 			src	+= len;
2410 			dstp	+= len;
2411 
2412 			if (dstp < lim)
2413 				((unsigned char *)dst)[dstp]	= '.';
2414 
2415 			dstp++;
2416 
2417 			nptrs	= 0;
2418 
2419 			continue;
2420 		case 0x01:	/* RESERVED */
2421 			goto reserved;
2422 		case 0x02:	/* RESERVED */
2423 			goto reserved;
2424 		case 0x03:	/* POINTER */
2425 			if (++nptrs > DNS_D_MAXPTRS)
2426 				goto toolong;
2427 
2428 			if (P->end - src < 2)
2429 				goto toolong;
2430 
2431 			src	= ((0x3f & P->data[src + 0]) << 8)
2432 				| ((0xff & P->data[src + 1]) << 0);
2433 
2434 			continue;
2435 		} /* switch() */
2436 	} /* while() */
2437 
2438 toolong:
2439 	*error	= DNS_EILLEGAL;
2440 
2441 	if (lim > 0)
2442 		((unsigned char *)dst)[DNS_PP_MIN(dstp, lim - 1)]	= '\0';
2443 
2444 	return 0;
2445 reserved:
2446 	*error	= DNS_EILLEGAL;
2447 
2448 	if (lim > 0)
2449 		((unsigned char *)dst)[DNS_PP_MIN(dstp, lim - 1)]	= '\0';
2450 
2451 	return 0;
2452 } /* dns_d_expand() */
2453 
2454 
dns_d_push(struct dns_packet * P,const void * dn,size_t len)2455 int dns_d_push(struct dns_packet *P, const void *dn, size_t len) {
2456 	size_t lim	= P->size - P->end;
2457 	unsigned dp	= P->end;
2458 	int error	= DNS_EILLEGAL; /* silence compiler */
2459 
2460 	len	= dns_d_comp(&P->data[dp], lim, dn, len, P, &error);
2461 
2462 	if (len == 0)
2463 		return error;
2464 	if (len > lim)
2465 		return DNS_ENOBUFS;
2466 
2467 	P->end	+= len;
2468 
2469 	dns_p_dictadd(P, dp);
2470 
2471 	return 0;
2472 } /* dns_d_push() */
2473 
2474 
dns_d_cname(void * dst,size_t lim,const void * dn,size_t len,struct dns_packet * P,int * error_)2475 size_t dns_d_cname(void *dst, size_t lim, const void *dn, size_t len, struct dns_packet *P, int *error_) {
2476 	char host[DNS_D_MAXNAME + 1];
2477 	struct dns_rr_i i;
2478 	struct dns_rr rr;
2479 	unsigned depth;
2480 	int error;
2481 
2482 	if (sizeof host <= dns_d_anchor(host, sizeof host, dn, len))
2483 		{ error = ENAMETOOLONG; goto error; }
2484 
2485 	for (depth = 0; depth < 7; depth++) {
2486 		dns_rr_i_init(memset(&i, 0, sizeof i), P);
2487 
2488 		i.section	= DNS_S_ALL & ~DNS_S_QD;
2489 		i.name		= host;
2490 		i.type		= DNS_T_CNAME;
2491 
2492 		if (!dns_rr_grep(&rr, 1, &i, P, &error))
2493 			break;
2494 
2495 		if ((error = dns_cname_parse((struct dns_cname *)host, &rr, P)))
2496 			goto error;
2497 	}
2498 
2499 	return dns_strlcpy(dst, host, lim);
2500 error:
2501 	*error_	= error;
2502 
2503 	return 0;
2504 } /* dns_d_cname() */
2505 
2506 
2507 /*
2508  * R E S O U R C E  R E C O R D  R O U T I N E S
2509  *
2510  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2511 
dns_rr_copy(struct dns_packet * P,struct dns_rr * rr,struct dns_packet * Q)2512 int dns_rr_copy(struct dns_packet *P, struct dns_rr *rr, struct dns_packet *Q) {
2513 	unsigned char dn[DNS_D_MAXNAME + 1];
2514 	union dns_any any;
2515 	size_t len;
2516 	int error;
2517 
2518 	if (!(len = dns_d_expand(dn, sizeof dn, rr->dn.p, Q, &error)))
2519 		return error;
2520 	else if (len >= sizeof dn)
2521 		return DNS_EILLEGAL;
2522 
2523 	if (rr->section != DNS_S_QD && (error = dns_any_parse(dns_any_init(&any, sizeof any), rr, Q)))
2524 		return error;
2525 
2526 	return dns_p_push(P, rr->section, dn, len, rr->type, rr->class, rr->ttl, &any);
2527 } /* dns_rr_copy() */
2528 
2529 
dns_rr_parse(struct dns_rr * rr,unsigned short src,struct dns_packet * P)2530 int dns_rr_parse(struct dns_rr *rr, unsigned short src, struct dns_packet *P) {
2531 	unsigned short p	= src;
2532 
2533 	if (src >= P->end)
2534 		goto invalid;
2535 
2536 	rr->dn.p   = p;
2537 	rr->dn.len = (p = dns_d_skip(p, P)) - rr->dn.p;
2538 
2539 	if (P->end - p < 4)
2540 		goto invalid;
2541 
2542 	rr->type = ((0xff & P->data[p + 0]) << 8)
2543 	         | ((0xff & P->data[p + 1]) << 0);
2544 
2545 	rr->class = ((0xff & P->data[p + 2]) << 8)
2546 	          | ((0xff & P->data[p + 3]) << 0);
2547 
2548 	p += 4;
2549 
2550 	if (src < dns_p_qend(P)) {
2551 		rr->section = DNS_S_QUESTION;
2552 
2553 		rr->ttl    = 0;
2554 		rr->rd.p   = 0;
2555 		rr->rd.len = 0;
2556 
2557 		return 0;
2558 	}
2559 
2560 	if (P->end - p < 4)
2561 		goto invalid;
2562 
2563 	rr->ttl = ((0xff & P->data[p + 0]) << 24)
2564 	        | ((0xff & P->data[p + 1]) << 16)
2565 	        | ((0xff & P->data[p + 2]) << 8)
2566 	        | ((0xff & P->data[p + 3]) << 0);
2567 	if (rr->type != DNS_T_OPT)
2568 		rr->ttl = DNS_PP_MIN(rr->ttl, 0x7fffffffU);
2569 
2570 	p += 4;
2571 
2572 	if (P->end - p < 2)
2573 		goto invalid;
2574 
2575 	rr->rd.len = ((0xff & P->data[p + 0]) << 8)
2576 	           | ((0xff & P->data[p + 1]) << 0);
2577 	rr->rd.p = p + 2;
2578 
2579 	p += 2;
2580 
2581 	if (P->end - p < rr->rd.len)
2582 		goto invalid;
2583 
2584 	return 0;
2585 invalid:
2586 	return DNS_EILLEGAL;
2587 } /* dns_rr_parse() */
2588 
2589 
dns_rr_len(const unsigned short src,struct dns_packet * P)2590 static unsigned short dns_rr_len(const unsigned short src, struct dns_packet *P) {
2591 	unsigned short rp, rdlen;
2592 
2593 	rp	= dns_d_skip(src, P);
2594 
2595 	if (P->end - rp < 4)
2596 		return P->end - src;
2597 
2598 	rp	+= 4;	/* TYPE, CLASS */
2599 
2600 	if (rp <= dns_p_qend(P))
2601 		return rp - src;
2602 
2603 	if (P->end - rp < 6)
2604 		return P->end - src;
2605 
2606 	rp	+= 6;	/* TTL, RDLEN */
2607 
2608 	rdlen	= ((0xff & P->data[rp - 2]) << 8)
2609 		| ((0xff & P->data[rp - 1]) << 0);
2610 
2611 	if (P->end - rp < rdlen)
2612 		return P->end - src;
2613 
2614 	rp	+= rdlen;
2615 
2616 	return rp - src;
2617 } /* dns_rr_len() */
2618 
2619 
dns_rr_skip(unsigned short src,struct dns_packet * P)2620 unsigned short dns_rr_skip(unsigned short src, struct dns_packet *P) {
2621 	return src + dns_rr_len(src, P);
2622 } /* dns_rr_skip() */
2623 
2624 
dns_rr_section(unsigned short src,struct dns_packet * P)2625 static enum dns_section dns_rr_section(unsigned short src, struct dns_packet *P) {
2626 	enum dns_section section;
2627 	unsigned count, index;
2628 	unsigned short rp;
2629 
2630 	if (src >= P->memo.qd.base && src < P->memo.qd.end)
2631 		return DNS_S_QD;
2632 	if (src >= P->memo.an.base && src < P->memo.an.end)
2633 		return DNS_S_AN;
2634 	if (src >= P->memo.ns.base && src < P->memo.ns.end)
2635 		return DNS_S_NS;
2636 	if (src >= P->memo.ar.base && src < P->memo.ar.end)
2637 		return DNS_S_AR;
2638 
2639 	/* NOTE: Possibly bad memoization. Try it the hard-way. */
2640 
2641 	for (rp = 12, index = 0; rp < src && rp < P->end; index++)
2642 		rp = dns_rr_skip(rp, P);
2643 
2644 	section = DNS_S_QD;
2645 	count   = dns_p_count(P, section);
2646 
2647 	while (index >= count && section <= DNS_S_AR) {
2648 		section <<= 1;
2649 		count += dns_p_count(P, section);
2650 	}
2651 
2652 	return DNS_S_ALL & section;
2653 } /* dns_rr_section() */
2654 
2655 
dns_rr_type(unsigned short src,struct dns_packet * P)2656 static enum dns_type dns_rr_type(unsigned short src, struct dns_packet *P) {
2657 	struct dns_rr rr;
2658 	int error;
2659 
2660 	if ((error = dns_rr_parse(&rr, src, P)))
2661 		return 0;
2662 
2663 	return rr.type;
2664 } /* dns_rr_type() */
2665 
2666 
dns_rr_cmp(struct dns_rr * r0,struct dns_packet * P0,struct dns_rr * r1,struct dns_packet * P1)2667 int dns_rr_cmp(struct dns_rr *r0, struct dns_packet *P0, struct dns_rr *r1, struct dns_packet *P1) {
2668 	char host0[DNS_D_MAXNAME + 1], host1[DNS_D_MAXNAME + 1];
2669 	union dns_any any0, any1;
2670 	int cmp, error;
2671 	size_t len;
2672 
2673 	if ((cmp = r0->type - r1->type))
2674 		return cmp;
2675 
2676 	if ((cmp = r0->class - r1->class))
2677 		return cmp;
2678 
2679 	/*
2680 	 * FIXME: Do label-by-label comparison to handle illegally long names?
2681 	 */
2682 
2683 	if (!(len = dns_d_expand(host0, sizeof host0, r0->dn.p, P0, &error))
2684 	||  len >= sizeof host0)
2685 		return -1;
2686 
2687 	if (!(len = dns_d_expand(host1, sizeof host1, r1->dn.p, P1, &error))
2688 	||  len >= sizeof host1)
2689 		return 1;
2690 
2691 	if ((cmp = strcasecmp(host0, host1)))
2692 		return cmp;
2693 
2694 	if (DNS_S_QD & (r0->section | r1->section)) {
2695 		if (r0->section == r1->section)
2696 			return 0;
2697 
2698 		return (r0->section == DNS_S_QD)? -1 : 1;
2699 	}
2700 
2701 	if ((error = dns_any_parse(&any0, r0, P0)))
2702 		return -1;
2703 
2704 	if ((error = dns_any_parse(&any1, r1, P1)))
2705 		return 1;
2706 
2707 	return dns_any_cmp(&any0, r0->type, &any1, r1->type);
2708 } /* dns_rr_cmp() */
2709 
2710 
dns_rr_exists(struct dns_rr * rr0,struct dns_packet * P0,struct dns_packet * P1)2711 static _Bool dns_rr_exists(struct dns_rr *rr0, struct dns_packet *P0, struct dns_packet *P1) {
2712 	struct dns_rr rr1;
2713 
2714 	dns_rr_foreach(&rr1, P1, .section = rr0->section, .type = rr0->type) {
2715 		if (0 == dns_rr_cmp(rr0, P0, &rr1, P1))
2716 			return 1;
2717 	}
2718 
2719 	return 0;
2720 } /* dns_rr_exists() */
2721 
2722 
dns_rr_offset(struct dns_rr * rr)2723 static unsigned short dns_rr_offset(struct dns_rr *rr) {
2724 	return rr->dn.p;
2725 } /* dns_rr_offset() */
2726 
2727 
dns_rr_i_match(struct dns_rr * rr,struct dns_rr_i * i,struct dns_packet * P)2728 static _Bool dns_rr_i_match(struct dns_rr *rr, struct dns_rr_i *i, struct dns_packet *P) {
2729 	if (i->section && !(rr->section & i->section))
2730 		return 0;
2731 
2732 	if (i->type && rr->type != i->type && i->type != DNS_T_ALL)
2733 		return 0;
2734 
2735 	if (i->class && rr->class != i->class && i->class != DNS_C_ANY)
2736 		return 0;
2737 
2738 	if (i->name) {
2739 		char dn[DNS_D_MAXNAME + 1];
2740 		size_t len;
2741 		int error;
2742 
2743 		if (!(len = dns_d_expand(dn, sizeof dn, rr->dn.p, P, &error))
2744 		||  len >= sizeof dn)
2745 			return 0;
2746 
2747 		if (0 != strcasecmp(dn, i->name))
2748 			return 0;
2749 	}
2750 
2751 	if (i->data && i->type && rr->section > DNS_S_QD) {
2752 		union dns_any rd;
2753 		int error;
2754 
2755 		if ((error = dns_any_parse(&rd, rr, P)))
2756 			return 0;
2757 
2758 		if (0 != dns_any_cmp(&rd, rr->type, i->data, i->type))
2759 			return 0;
2760 	}
2761 
2762 	return 1;
2763 } /* dns_rr_i_match() */
2764 
2765 
dns_rr_i_start(struct dns_rr_i * i,struct dns_packet * P)2766 static unsigned short dns_rr_i_start(struct dns_rr_i *i, struct dns_packet *P) {
2767 	unsigned short rp;
2768 	struct dns_rr r0, rr;
2769 	int error;
2770 
2771 	if ((i->section & DNS_S_QD) && P->memo.qd.base)
2772 		rp = P->memo.qd.base;
2773 	else if ((i->section & DNS_S_AN) && P->memo.an.base)
2774 		rp = P->memo.an.base;
2775 	else if ((i->section & DNS_S_NS) && P->memo.ns.base)
2776 		rp = P->memo.ns.base;
2777 	else if ((i->section & DNS_S_AR) && P->memo.ar.base)
2778 		rp = P->memo.ar.base;
2779 	else
2780 		rp = 12;
2781 
2782 	for (; rp < P->end; rp = dns_rr_skip(rp, P)) {
2783 		if ((error = dns_rr_parse(&rr, rp, P)))
2784 			continue;
2785 
2786 		rr.section = dns_rr_section(rp, P);
2787 
2788 		if (!dns_rr_i_match(&rr, i, P))
2789 			continue;
2790 
2791 		r0 = rr;
2792 
2793 		goto lower;
2794 	}
2795 
2796 	return P->end;
2797 lower:
2798 	if (i->sort == &dns_rr_i_packet)
2799 		return dns_rr_offset(&r0);
2800 
2801 	while ((rp = dns_rr_skip(rp, P)) < P->end) {
2802 		if ((error = dns_rr_parse(&rr, rp, P)))
2803 			continue;
2804 
2805 		rr.section = dns_rr_section(rp, P);
2806 
2807 		if (!dns_rr_i_match(&rr, i, P))
2808 			continue;
2809 
2810 		if (i->sort(&rr, &r0, i, P) < 0)
2811 			r0 = rr;
2812 	}
2813 
2814 	return dns_rr_offset(&r0);
2815 } /* dns_rr_i_start() */
2816 
2817 
dns_rr_i_skip(unsigned short rp,struct dns_rr_i * i,struct dns_packet * P)2818 static unsigned short dns_rr_i_skip(unsigned short rp, struct dns_rr_i *i, struct dns_packet *P) {
2819 	struct dns_rr r0, r1, rr;
2820 	int error;
2821 
2822 	if ((error = dns_rr_parse(&r0, rp, P)))
2823 		return P->end;
2824 
2825 	r0.section = dns_rr_section(rp, P);
2826 
2827 	rp = (i->sort == &dns_rr_i_packet)? dns_rr_skip(rp, P) : 12;
2828 
2829 	for (; rp < P->end; rp = dns_rr_skip(rp, P)) {
2830 		if ((error = dns_rr_parse(&rr, rp, P)))
2831 			continue;
2832 
2833 		rr.section = dns_rr_section(rp, P);
2834 
2835 		if (!dns_rr_i_match(&rr, i, P))
2836 			continue;
2837 
2838 		if (i->sort(&rr, &r0, i, P) <= 0)
2839 			continue;
2840 
2841 		r1 = rr;
2842 
2843 		goto lower;
2844 	}
2845 
2846 	return P->end;
2847 lower:
2848 	if (i->sort == &dns_rr_i_packet)
2849 		return dns_rr_offset(&r1);
2850 
2851 	while ((rp = dns_rr_skip(rp, P)) < P->end) {
2852 		if ((error = dns_rr_parse(&rr, rp, P)))
2853 			continue;
2854 
2855 		rr.section = dns_rr_section(rp, P);
2856 
2857 		if (!dns_rr_i_match(&rr, i, P))
2858 			continue;
2859 
2860 		if (i->sort(&rr, &r0, i, P) <= 0)
2861 			continue;
2862 
2863 		if (i->sort(&rr, &r1, i, P) >= 0)
2864 			continue;
2865 
2866 		r1 = rr;
2867 	}
2868 
2869 	return dns_rr_offset(&r1);
2870 } /* dns_rr_i_skip() */
2871 
2872 
dns_rr_i_packet(struct dns_rr * a,struct dns_rr * b,struct dns_rr_i * i,struct dns_packet * P)2873 int dns_rr_i_packet(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) {
2874 	(void)i;
2875 	(void)P;
2876 
2877 	return (int)a->dn.p - (int)b->dn.p;
2878 } /* dns_rr_i_packet() */
2879 
2880 
dns_rr_i_order(struct dns_rr * a,struct dns_rr * b,struct dns_rr_i * i,struct dns_packet * P)2881 int dns_rr_i_order(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) {
2882 	int cmp;
2883 
2884 	(void)i;
2885 
2886 	if ((cmp = a->section - b->section))
2887 		return cmp;
2888 
2889 	if (a->type != b->type)
2890 		return (int)a->dn.p - (int)b->dn.p;
2891 
2892 	return dns_rr_cmp(a, P, b, P);
2893 } /* dns_rr_i_order() */
2894 
2895 
dns_rr_i_shuffle(struct dns_rr * a,struct dns_rr * b,struct dns_rr_i * i,struct dns_packet * P)2896 int dns_rr_i_shuffle(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) {
2897 	int cmp;
2898 
2899 	(void)i;
2900 	(void)P;
2901 
2902 	while (!i->state.regs[0])
2903 		i->state.regs[0]	= dns_random();
2904 
2905 	if ((cmp = a->section - b->section))
2906 		return cmp;
2907 
2908 	return dns_k_shuffle16(a->dn.p, i->state.regs[0]) - dns_k_shuffle16(b->dn.p, i->state.regs[0]);
2909 } /* dns_rr_i_shuffle() */
2910 
2911 
dns_rr_i_init(struct dns_rr_i * i,struct dns_packet * P)2912 struct dns_rr_i *dns_rr_i_init(struct dns_rr_i *i, struct dns_packet *P) {
2913 	static const struct dns_rr_i i_initializer;
2914 
2915 	(void)P;
2916 
2917 	i->state	= i_initializer.state;
2918 	i->saved	= i->state;
2919 
2920 	return i;
2921 } /* dns_rr_i_init() */
2922 
2923 
dns_rr_grep(struct dns_rr * rr,unsigned lim,struct dns_rr_i * i,struct dns_packet * P,int * error_)2924 unsigned dns_rr_grep(struct dns_rr *rr, unsigned lim, struct dns_rr_i *i, struct dns_packet *P, int *error_) {
2925 	unsigned count	= 0;
2926 	int error;
2927 
2928 	switch (i->state.exec) {
2929 	case 0:
2930 		if (!i->sort)
2931 			i->sort	= &dns_rr_i_packet;
2932 
2933 		i->state.next	= dns_rr_i_start(i, P);
2934 		i->state.exec++;
2935 
2936 		/* FALL THROUGH */
2937 	case 1:
2938 		while (count < lim && i->state.next < P->end) {
2939 			if ((error = dns_rr_parse(rr, i->state.next, P)))
2940 				goto error;
2941 
2942 			rr->section	= dns_rr_section(i->state.next, P);
2943 
2944 			rr++;
2945 			count++;
2946 			i->state.count++;
2947 
2948 			i->state.next	= dns_rr_i_skip(i->state.next, i, P);
2949 		} /* while() */
2950 
2951 		break;
2952 	} /* switch() */
2953 
2954 	return count;
2955 error:
2956 	*error_	= error;
2957 
2958 	return count;
2959 } /* dns_rr_grep() */
2960 
2961 
dns_rr_print(void * _dst,size_t lim,struct dns_rr * rr,struct dns_packet * P,int * _error)2962 size_t dns_rr_print(void *_dst, size_t lim, struct dns_rr *rr, struct dns_packet *P, int *_error) {
2963 	struct dns_buf dst = DNS_B_INTO(_dst, lim);
2964 	union dns_any any;
2965 	size_t n;
2966 	int error;
2967 
2968 	if (rr->section == DNS_S_QD)
2969 		dns_b_putc(&dst, ';');
2970 
2971 	if (!(n = dns_d_expand(any.ns.host, sizeof any.ns.host, rr->dn.p, P, &error)))
2972 		goto error;
2973 	dns_b_put(&dst, any.ns.host, DNS_PP_MIN(n, sizeof any.ns.host - 1));
2974 
2975 	if (rr->section != DNS_S_QD) {
2976 		dns_b_putc(&dst, ' ');
2977 		dns_b_fmtju(&dst, rr->ttl, 0);
2978 	}
2979 
2980 	dns_b_putc(&dst, ' ');
2981 	dns_b_puts(&dst, dns_strclass(rr->class));
2982 	dns_b_putc(&dst, ' ');
2983 	dns_b_puts(&dst, dns_strtype(rr->type));
2984 
2985 	if (rr->section == DNS_S_QD)
2986 		goto epilog;
2987 
2988 	dns_b_putc(&dst, ' ');
2989 
2990 	if ((error = dns_any_parse(dns_any_init(&any, sizeof any), rr, P)))
2991 		goto error;
2992 
2993 	n = dns_any_print(dst.p, dst.pe - dst.p, &any, rr->type);
2994 	dst.p += DNS_PP_MIN(n, (size_t)(dst.pe - dst.p));
2995 epilog:
2996 	return dns_b_strllen(&dst);
2997 error:
2998 	*_error = error;
2999 
3000 	return 0;
3001 } /* dns_rr_print() */
3002 
3003 
dns_a_parse(struct dns_a * a,struct dns_rr * rr,struct dns_packet * P)3004 int dns_a_parse(struct dns_a *a, struct dns_rr *rr, struct dns_packet *P) {
3005 	unsigned long addr;
3006 
3007 	if (rr->rd.len != 4)
3008 		return DNS_EILLEGAL;
3009 
3010 	addr	= ((0xffU & P->data[rr->rd.p + 0]) << 24)
3011 		| ((0xffU & P->data[rr->rd.p + 1]) << 16)
3012 		| ((0xffU & P->data[rr->rd.p + 2]) << 8)
3013 		| ((0xffU & P->data[rr->rd.p + 3]) << 0);
3014 
3015 	a->addr.s_addr	= htonl(addr);
3016 
3017 	return 0;
3018 } /* dns_a_parse() */
3019 
3020 
dns_a_push(struct dns_packet * P,struct dns_a * a)3021 int dns_a_push(struct dns_packet *P, struct dns_a *a) {
3022 	unsigned long addr;
3023 
3024 	if (P->size - P->end < 6)
3025 		return DNS_ENOBUFS;
3026 
3027 	P->data[P->end++]	= 0x00;
3028 	P->data[P->end++]	= 0x04;
3029 
3030 	addr	= ntohl(a->addr.s_addr);
3031 
3032 	P->data[P->end++]	= 0xffU & (addr >> 24);
3033 	P->data[P->end++]	= 0xffU & (addr >> 16);
3034 	P->data[P->end++]	= 0xffU & (addr >> 8);
3035 	P->data[P->end++]	= 0xffU & (addr >> 0);
3036 
3037 	return 0;
3038 } /* dns_a_push() */
3039 
3040 
dns_a_arpa(void * _dst,size_t lim,const struct dns_a * a)3041 size_t dns_a_arpa(void *_dst, size_t lim, const struct dns_a *a) {
3042 	struct dns_buf dst = DNS_B_INTO(_dst, lim);
3043 	unsigned long octets = ntohl(a->addr.s_addr);
3044 	unsigned i;
3045 
3046 	for (i = 0; i < 4; i++) {
3047 		dns_b_fmtju(&dst, 0xff & octets, 0);
3048 		dns_b_putc(&dst, '.');
3049 		octets >>= 8;
3050 	}
3051 
3052 	dns_b_puts(&dst, "in-addr.arpa.");
3053 
3054 	return dns_b_strllen(&dst);
3055 } /* dns_a_arpa() */
3056 
3057 
dns_a_cmp(const struct dns_a * a,const struct dns_a * b)3058 int dns_a_cmp(const struct dns_a *a, const struct dns_a *b) {
3059 	if (ntohl(a->addr.s_addr) < ntohl(b->addr.s_addr))
3060 		return -1;
3061 	if (ntohl(a->addr.s_addr) > ntohl(b->addr.s_addr))
3062 		return 1;
3063 
3064 	return 0;
3065 } /* dns_a_cmp() */
3066 
3067 
dns_a_print(void * dst,size_t lim,struct dns_a * a)3068 size_t dns_a_print(void *dst, size_t lim, struct dns_a *a) {
3069 	char addr[INET_ADDRSTRLEN + 1]	= "0.0.0.0";
3070 
3071 	dns_inet_ntop(AF_INET, &a->addr, addr, sizeof addr);
3072 
3073 	return dns_strlcpy(dst, addr, lim);
3074 } /* dns_a_print() */
3075 
3076 
dns_aaaa_parse(struct dns_aaaa * aaaa,struct dns_rr * rr,struct dns_packet * P)3077 int dns_aaaa_parse(struct dns_aaaa *aaaa, struct dns_rr *rr, struct dns_packet *P) {
3078 	if (rr->rd.len != sizeof aaaa->addr.s6_addr)
3079 		return DNS_EILLEGAL;
3080 
3081 	memcpy(aaaa->addr.s6_addr, &P->data[rr->rd.p], sizeof aaaa->addr.s6_addr);
3082 
3083 	return 0;
3084 } /* dns_aaaa_parse() */
3085 
3086 
dns_aaaa_push(struct dns_packet * P,struct dns_aaaa * aaaa)3087 int dns_aaaa_push(struct dns_packet *P, struct dns_aaaa *aaaa) {
3088 	if (P->size - P->end < 2 + sizeof aaaa->addr.s6_addr)
3089 		return DNS_ENOBUFS;
3090 
3091 	P->data[P->end++]	= 0x00;
3092 	P->data[P->end++]	= 0x10;
3093 
3094 	memcpy(&P->data[P->end], aaaa->addr.s6_addr, sizeof aaaa->addr.s6_addr);
3095 
3096 	P->end	+= sizeof aaaa->addr.s6_addr;
3097 
3098 	return 0;
3099 } /* dns_aaaa_push() */
3100 
3101 
dns_aaaa_cmp(const struct dns_aaaa * a,const struct dns_aaaa * b)3102 int dns_aaaa_cmp(const struct dns_aaaa *a, const struct dns_aaaa *b) {
3103 	unsigned i;
3104 	int cmp;
3105 
3106 	for (i = 0; i < lengthof(a->addr.s6_addr); i++) {
3107 		if ((cmp = (a->addr.s6_addr[i] - b->addr.s6_addr[i])))
3108 			return cmp;
3109 	}
3110 
3111 	return 0;
3112 } /* dns_aaaa_cmp() */
3113 
3114 
dns_aaaa_arpa(void * _dst,size_t lim,const struct dns_aaaa * aaaa)3115 size_t dns_aaaa_arpa(void *_dst, size_t lim, const struct dns_aaaa *aaaa) {
3116 	static const unsigned char hex[16] = "0123456789abcdef";
3117 	struct dns_buf dst = DNS_B_INTO(_dst, lim);
3118 	unsigned nyble;
3119 	int i, j;
3120 
3121 	for (i = sizeof aaaa->addr.s6_addr - 1; i >= 0; i--) {
3122 		nyble = aaaa->addr.s6_addr[i];
3123 
3124 		for (j = 0; j < 2; j++) {
3125 			dns_b_putc(&dst, hex[0x0f & nyble]);
3126 			dns_b_putc(&dst, '.');
3127 			nyble >>= 4;
3128 		}
3129 	}
3130 
3131 	dns_b_puts(&dst, "ip6.arpa.");
3132 
3133 	return dns_b_strllen(&dst);
3134 } /* dns_aaaa_arpa() */
3135 
3136 
dns_aaaa_print(void * dst,size_t lim,struct dns_aaaa * aaaa)3137 size_t dns_aaaa_print(void *dst, size_t lim, struct dns_aaaa *aaaa) {
3138 	char addr[INET6_ADDRSTRLEN + 1]	= "::";
3139 
3140 	dns_inet_ntop(AF_INET6, &aaaa->addr, addr, sizeof addr);
3141 
3142 	return dns_strlcpy(dst, addr, lim);
3143 } /* dns_aaaa_print() */
3144 
3145 
dns_mx_parse(struct dns_mx * mx,struct dns_rr * rr,struct dns_packet * P)3146 int dns_mx_parse(struct dns_mx *mx, struct dns_rr *rr, struct dns_packet *P) {
3147 	size_t len;
3148 	int error;
3149 
3150 	if (rr->rd.len < 3)
3151 		return DNS_EILLEGAL;
3152 
3153 	mx->preference	= (0xff00 & (P->data[rr->rd.p + 0] << 8))
3154 			| (0x00ff & (P->data[rr->rd.p + 1] << 0));
3155 
3156 	if (!(len = dns_d_expand(mx->host, sizeof mx->host, rr->rd.p + 2, P, &error)))
3157 		return error;
3158 	else if (len >= sizeof mx->host)
3159 		return DNS_EILLEGAL;
3160 
3161 	return 0;
3162 } /* dns_mx_parse() */
3163 
3164 
dns_mx_push(struct dns_packet * P,struct dns_mx * mx)3165 int dns_mx_push(struct dns_packet *P, struct dns_mx *mx) {
3166 	size_t end, len;
3167 	int error;
3168 
3169 	if (P->size - P->end < 5)
3170 		return DNS_ENOBUFS;
3171 
3172 	end	= P->end;
3173 	P->end	+= 2;
3174 
3175 	P->data[P->end++]	= 0xff & (mx->preference >> 8);
3176 	P->data[P->end++]	= 0xff & (mx->preference >> 0);
3177 
3178 	if ((error = dns_d_push(P, mx->host, strlen(mx->host))))
3179 		goto error;
3180 
3181 	len	= P->end - end - 2;
3182 
3183 	P->data[end + 0]	= 0xff & (len >> 8);
3184 	P->data[end + 1]	= 0xff & (len >> 0);
3185 
3186 	return 0;
3187 error:
3188 	P->end	= end;
3189 
3190 	return error;
3191 } /* dns_mx_push() */
3192 
3193 
dns_mx_cmp(const struct dns_mx * a,const struct dns_mx * b)3194 int dns_mx_cmp(const struct dns_mx *a, const struct dns_mx *b) {
3195 	int cmp;
3196 
3197 	if ((cmp = a->preference - b->preference))
3198 		return cmp;
3199 
3200 	return strcasecmp(a->host, b->host);
3201 } /* dns_mx_cmp() */
3202 
3203 
dns_mx_print(void * _dst,size_t lim,struct dns_mx * mx)3204 size_t dns_mx_print(void *_dst, size_t lim, struct dns_mx *mx) {
3205 	struct dns_buf dst = DNS_B_INTO(_dst, lim);
3206 
3207 	dns_b_fmtju(&dst, mx->preference, 0);
3208 	dns_b_putc(&dst, ' ');
3209 	dns_b_puts(&dst, mx->host);
3210 
3211 	return dns_b_strllen(&dst);
3212 } /* dns_mx_print() */
3213 
3214 
dns_mx_cname(void * dst,size_t lim,struct dns_mx * mx)3215 size_t dns_mx_cname(void *dst, size_t lim, struct dns_mx *mx) {
3216 	return dns_strlcpy(dst, mx->host, lim);
3217 } /* dns_mx_cname() */
3218 
3219 
dns_ns_parse(struct dns_ns * ns,struct dns_rr * rr,struct dns_packet * P)3220 int dns_ns_parse(struct dns_ns *ns, struct dns_rr *rr, struct dns_packet *P) {
3221 	size_t len;
3222 	int error;
3223 
3224 	if (!(len = dns_d_expand(ns->host, sizeof ns->host, rr->rd.p, P, &error)))
3225 		return error;
3226 	else if (len >= sizeof ns->host)
3227 		return DNS_EILLEGAL;
3228 
3229 	return 0;
3230 } /* dns_ns_parse() */
3231 
3232 
dns_ns_push(struct dns_packet * P,struct dns_ns * ns)3233 int dns_ns_push(struct dns_packet *P, struct dns_ns *ns) {
3234 	size_t end, len;
3235 	int error;
3236 
3237 	if (P->size - P->end < 3)
3238 		return DNS_ENOBUFS;
3239 
3240 	end	= P->end;
3241 	P->end	+= 2;
3242 
3243 	if ((error = dns_d_push(P, ns->host, strlen(ns->host))))
3244 		goto error;
3245 
3246 	len	= P->end - end - 2;
3247 
3248 	P->data[end + 0]	= 0xff & (len >> 8);
3249 	P->data[end + 1]	= 0xff & (len >> 0);
3250 
3251 	return 0;
3252 error:
3253 	P->end	= end;
3254 
3255 	return error;
3256 } /* dns_ns_push() */
3257 
3258 
dns_ns_cmp(const struct dns_ns * a,const struct dns_ns * b)3259 int dns_ns_cmp(const struct dns_ns *a, const struct dns_ns *b) {
3260 	return strcasecmp(a->host, b->host);
3261 } /* dns_ns_cmp() */
3262 
3263 
dns_ns_print(void * dst,size_t lim,struct dns_ns * ns)3264 size_t dns_ns_print(void *dst, size_t lim, struct dns_ns *ns) {
3265 	return dns_strlcpy(dst, ns->host, lim);
3266 } /* dns_ns_print() */
3267 
3268 
dns_ns_cname(void * dst,size_t lim,struct dns_ns * ns)3269 size_t dns_ns_cname(void *dst, size_t lim, struct dns_ns *ns) {
3270 	return dns_strlcpy(dst, ns->host, lim);
3271 } /* dns_ns_cname() */
3272 
3273 
dns_cname_parse(struct dns_cname * cname,struct dns_rr * rr,struct dns_packet * P)3274 int dns_cname_parse(struct dns_cname *cname, struct dns_rr *rr, struct dns_packet *P) {
3275 	return dns_ns_parse((struct dns_ns *)cname, rr, P);
3276 } /* dns_cname_parse() */
3277 
3278 
dns_cname_push(struct dns_packet * P,struct dns_cname * cname)3279 int dns_cname_push(struct dns_packet *P, struct dns_cname *cname) {
3280 	return dns_ns_push(P, (struct dns_ns *)cname);
3281 } /* dns_cname_push() */
3282 
3283 
dns_cname_cmp(const struct dns_cname * a,const struct dns_cname * b)3284 int dns_cname_cmp(const struct dns_cname *a, const struct dns_cname *b) {
3285 	return strcasecmp(a->host, b->host);
3286 } /* dns_cname_cmp() */
3287 
3288 
dns_cname_print(void * dst,size_t lim,struct dns_cname * cname)3289 size_t dns_cname_print(void *dst, size_t lim, struct dns_cname *cname) {
3290 	return dns_ns_print(dst, lim, (struct dns_ns *)cname);
3291 } /* dns_cname_print() */
3292 
3293 
dns_cname_cname(void * dst,size_t lim,struct dns_cname * cname)3294 size_t dns_cname_cname(void *dst, size_t lim, struct dns_cname *cname) {
3295 	return dns_strlcpy(dst, cname->host, lim);
3296 } /* dns_cname_cname() */
3297 
3298 
dns_soa_parse(struct dns_soa * soa,struct dns_rr * rr,struct dns_packet * P)3299 int dns_soa_parse(struct dns_soa *soa, struct dns_rr *rr, struct dns_packet *P) {
3300 	struct { void *dst; size_t lim; } dn[] =
3301 		{ { soa->mname, sizeof soa->mname },
3302 		  { soa->rname, sizeof soa->rname } };
3303 	unsigned *ts[] =
3304 		{ &soa->serial, &soa->refresh, &soa->retry, &soa->expire, &soa->minimum };
3305 	unsigned short rp;
3306 	unsigned i, j, n;
3307 	int error;
3308 
3309 	/* MNAME / RNAME */
3310 	if ((rp = rr->rd.p) >= P->end)
3311 		return DNS_EILLEGAL;
3312 
3313 	for (i = 0; i < lengthof(dn); i++) {
3314 		if (!(n = dns_d_expand(dn[i].dst, dn[i].lim, rp, P, &error)))
3315 			return error;
3316 		else if (n >= dn[i].lim)
3317 			return DNS_EILLEGAL;
3318 
3319 		if ((rp = dns_d_skip(rp, P)) >= P->end)
3320 			return DNS_EILLEGAL;
3321 	}
3322 
3323 	/* SERIAL / REFRESH / RETRY / EXPIRE / MINIMUM */
3324 	for (i = 0; i < lengthof(ts); i++) {
3325 		for (j = 0; j < 4; j++, rp++) {
3326 			if (rp >= P->end)
3327 				return DNS_EILLEGAL;
3328 
3329 			*ts[i]	<<= 8;
3330 			*ts[i]	|= (0xff & P->data[rp]);
3331 		}
3332 	}
3333 
3334 	return 0;
3335 } /* dns_soa_parse() */
3336 
3337 
dns_soa_push(struct dns_packet * P,struct dns_soa * soa)3338 int dns_soa_push(struct dns_packet *P, struct dns_soa *soa) {
3339 	void *dn[]	= { soa->mname, soa->rname };
3340 	unsigned ts[]	= { (0xffffffff & soa->serial),
3341 			    (0x7fffffff & soa->refresh),
3342 			    (0x7fffffff & soa->retry),
3343 			    (0x7fffffff & soa->expire),
3344 			    (0xffffffff & soa->minimum) };
3345 	unsigned i, j;
3346 	size_t end, len;
3347 	int error;
3348 
3349 	end	= P->end;
3350 
3351 	if ((P->end += 2) >= P->size)
3352 		goto toolong;
3353 
3354 	/* MNAME / RNAME */
3355 	for (i = 0; i < lengthof(dn); i++) {
3356 		if ((error = dns_d_push(P, dn[i], strlen(dn[i]))))
3357 			goto error;
3358 	}
3359 
3360 	/* SERIAL / REFRESH / RETRY / EXPIRE / MINIMUM */
3361 	for (i = 0; i < lengthof(ts); i++) {
3362 		if ((P->end += 4) >= P->size)
3363 			goto toolong;
3364 
3365 		for (j = 1; j <= 4; j++) {
3366 			P->data[P->end - j]	= (0xff & ts[i]);
3367 			ts[i]			>>= 8;
3368 		}
3369 	}
3370 
3371 	len			= P->end - end - 2;
3372 	P->data[end + 0]	= (0xff & (len >> 8));
3373 	P->data[end + 1]	= (0xff & (len >> 0));
3374 
3375 	return 0;
3376 toolong:
3377 	error	= DNS_ENOBUFS;
3378 
3379 	/* FALL THROUGH */
3380 error:
3381 	P->end	= end;
3382 
3383 	return error;
3384 } /* dns_soa_push() */
3385 
3386 
dns_soa_cmp(const struct dns_soa * a,const struct dns_soa * b)3387 int dns_soa_cmp(const struct dns_soa *a, const struct dns_soa *b) {
3388 	int cmp;
3389 
3390 	if ((cmp = strcasecmp(a->mname, b->mname)))
3391 		return cmp;
3392 
3393 	if ((cmp = strcasecmp(a->rname, b->rname)))
3394 		return cmp;
3395 
3396 	if (a->serial > b->serial)
3397 		return -1;
3398 	else if (a->serial < b->serial)
3399 		return 1;
3400 
3401 	if (a->refresh > b->refresh)
3402 		return -1;
3403 	else if (a->refresh < b->refresh)
3404 		return 1;
3405 
3406 	if (a->retry > b->retry)
3407 		return -1;
3408 	else if (a->retry < b->retry)
3409 		return 1;
3410 
3411 	if (a->expire > b->expire)
3412 		return -1;
3413 	else if (a->expire < b->expire)
3414 		return 1;
3415 
3416 	if (a->minimum > b->minimum)
3417 		return -1;
3418 	else if (a->minimum < b->minimum)
3419 		return 1;
3420 
3421 	return 0;
3422 } /* dns_soa_cmp() */
3423 
3424 
dns_soa_print(void * _dst,size_t lim,struct dns_soa * soa)3425 size_t dns_soa_print(void *_dst, size_t lim, struct dns_soa *soa) {
3426 	struct dns_buf dst = DNS_B_INTO(_dst, lim);
3427 
3428 	dns_b_puts(&dst, soa->mname);
3429 	dns_b_putc(&dst, ' ');
3430 	dns_b_puts(&dst, soa->rname);
3431 	dns_b_putc(&dst, ' ');
3432 	dns_b_fmtju(&dst, soa->serial, 0);
3433 	dns_b_putc(&dst, ' ');
3434 	dns_b_fmtju(&dst, soa->refresh, 0);
3435 	dns_b_putc(&dst, ' ');
3436 	dns_b_fmtju(&dst, soa->retry, 0);
3437 	dns_b_putc(&dst, ' ');
3438 	dns_b_fmtju(&dst, soa->expire, 0);
3439 	dns_b_putc(&dst, ' ');
3440 	dns_b_fmtju(&dst, soa->minimum, 0);
3441 
3442 	return dns_b_strllen(&dst);
3443 } /* dns_soa_print() */
3444 
3445 
dns_srv_parse(struct dns_srv * srv,struct dns_rr * rr,struct dns_packet * P)3446 int dns_srv_parse(struct dns_srv *srv, struct dns_rr *rr, struct dns_packet *P) {
3447 	unsigned short rp;
3448 	unsigned i;
3449 	size_t n;
3450 	int error;
3451 
3452 	memset(srv, '\0', sizeof *srv);
3453 
3454 	rp	= rr->rd.p;
3455 
3456 	if (rr->rd.len < 7)
3457 		return DNS_EILLEGAL;
3458 
3459 	for (i = 0; i < 2; i++, rp++) {
3460 		srv->priority	<<= 8;
3461 		srv->priority	|= (0xff & P->data[rp]);
3462 	}
3463 
3464 	for (i = 0; i < 2; i++, rp++) {
3465 		srv->weight	<<= 8;
3466 		srv->weight	|= (0xff & P->data[rp]);
3467 	}
3468 
3469 	for (i = 0; i < 2; i++, rp++) {
3470 		srv->port	<<= 8;
3471 		srv->port	|= (0xff & P->data[rp]);
3472 	}
3473 
3474 	if (!(n = dns_d_expand(srv->target, sizeof srv->target, rp, P, &error)))
3475 		return error;
3476 	else if (n >= sizeof srv->target)
3477 		return DNS_EILLEGAL;
3478 
3479 	return 0;
3480 } /* dns_srv_parse() */
3481 
3482 
dns_srv_push(struct dns_packet * P,struct dns_srv * srv)3483 int dns_srv_push(struct dns_packet *P, struct dns_srv *srv) {
3484 	size_t end, len;
3485 	int error;
3486 
3487 	end	= P->end;
3488 
3489 	if (P->size - P->end < 2)
3490 		goto toolong;
3491 
3492 	P->end	+= 2;
3493 
3494 	if (P->size - P->end < 6)
3495 		goto toolong;
3496 
3497 	P->data[P->end++]	= 0xff & (srv->priority >> 8);
3498 	P->data[P->end++]	= 0xff & (srv->priority >> 0);
3499 
3500 	P->data[P->end++]	= 0xff & (srv->weight >> 8);
3501 	P->data[P->end++]	= 0xff & (srv->weight >> 0);
3502 
3503 	P->data[P->end++]	= 0xff & (srv->port >> 8);
3504 	P->data[P->end++]	= 0xff & (srv->port >> 0);
3505 
3506 	if (0 == (len = dns_d_comp(&P->data[P->end], P->size - P->end, srv->target, strlen(srv->target), P, &error)))
3507 		goto error;
3508 	else if (P->size - P->end < len)
3509 		goto toolong;
3510 
3511 	P->end	+= len;
3512 
3513 	if (P->end > 65535)
3514 		goto toolong;
3515 
3516 	len	= P->end - end - 2;
3517 
3518 	P->data[end + 0]	= 0xff & (len >> 8);
3519 	P->data[end + 1]	= 0xff & (len >> 0);
3520 
3521 	return 0;
3522 toolong:
3523 	error	= DNS_ENOBUFS;
3524 
3525 	/* FALL THROUGH */
3526 error:
3527 	P->end	= end;
3528 
3529 	return error;
3530 } /* dns_srv_push() */
3531 
3532 
dns_srv_cmp(const struct dns_srv * a,const struct dns_srv * b)3533 int dns_srv_cmp(const struct dns_srv *a, const struct dns_srv *b) {
3534 	int cmp;
3535 
3536 	if ((cmp = a->priority - b->priority))
3537 		return cmp;
3538 
3539 	/*
3540 	 * FIXME: We need some sort of random seed to implement the dynamic
3541 	 * weighting required by RFC 2782.
3542 	 */
3543 	if ((cmp = a->weight - b->weight))
3544 		return cmp;
3545 
3546 	if ((cmp = a->port - b->port))
3547 		return cmp;
3548 
3549 	return strcasecmp(a->target, b->target);
3550 } /* dns_srv_cmp() */
3551 
3552 
dns_srv_print(void * _dst,size_t lim,struct dns_srv * srv)3553 size_t dns_srv_print(void *_dst, size_t lim, struct dns_srv *srv) {
3554 	struct dns_buf dst = DNS_B_INTO(_dst, lim);
3555 
3556 	dns_b_fmtju(&dst, srv->priority, 0);
3557 	dns_b_putc(&dst, ' ');
3558 	dns_b_fmtju(&dst, srv->weight, 0);
3559 	dns_b_putc(&dst, ' ');
3560 	dns_b_fmtju(&dst, srv->port, 0);
3561 	dns_b_putc(&dst, ' ');
3562 	dns_b_puts(&dst, srv->target);
3563 
3564 	return dns_b_strllen(&dst);
3565 } /* dns_srv_print() */
3566 
3567 
dns_srv_cname(void * dst,size_t lim,struct dns_srv * srv)3568 size_t dns_srv_cname(void *dst, size_t lim, struct dns_srv *srv) {
3569 	return dns_strlcpy(dst, srv->target, lim);
3570 } /* dns_srv_cname() */
3571 
3572 
dns_opt_ttl(const struct dns_opt * opt)3573 unsigned int dns_opt_ttl(const struct dns_opt *opt) {
3574 	unsigned int ttl = 0;
3575 
3576 	ttl |= (0xffU & opt->rcode) << 24;
3577 	ttl |= (0xffU & opt->version) << 16;
3578 	ttl |= (0xffffU & opt->flags) << 0;
3579 
3580 	return ttl;
3581 } /* dns_opt_ttl() */
3582 
3583 
dns_opt_class(const struct dns_opt * opt)3584 unsigned short dns_opt_class(const struct dns_opt *opt) {
3585 	return opt->maxudp;
3586 } /* dns_opt_class() */
3587 
3588 
dns_opt_init(struct dns_opt * opt,size_t size)3589 struct dns_opt *dns_opt_init(struct dns_opt *opt, size_t size) {
3590 	assert(size >= offsetof(struct dns_opt, data));
3591 
3592 	opt->size = size - offsetof(struct dns_opt, data);
3593 	opt->len  = 0;
3594 
3595 	opt->rcode   = 0;
3596 	opt->version = 0;
3597 	opt->maxudp  = 0;
3598 
3599 	return opt;
3600 } /* dns_opt_init() */
3601 
3602 
dns_opt_initany(union dns_any * any,size_t size)3603 static union dns_any *dns_opt_initany(union dns_any *any, size_t size) {
3604 	return dns_opt_init(&any->opt, size), any;
3605 } /* dns_opt_initany() */
3606 
3607 
dns_opt_parse(struct dns_opt * opt,struct dns_rr * rr,struct dns_packet * P)3608 int dns_opt_parse(struct dns_opt *opt, struct dns_rr *rr, struct dns_packet *P) {
3609 	const struct dns_buf src = DNS_B_FROM(&P->data[rr->rd.p], rr->rd.len);
3610 	struct dns_buf dst = DNS_B_INTO(opt->data, opt->size);
3611 	int error;
3612 
3613 	opt->rcode = 0xfff & ((rr->ttl >> 20) | dns_header(P)->rcode);
3614 	opt->version = 0xff & (rr->ttl >> 16);
3615 	opt->flags = 0xffff & rr->ttl;
3616 	opt->maxudp = 0xffff & rr->class;
3617 
3618 	while (src.p < src.pe) {
3619 		int code, len;
3620 
3621 		if (-1 == (code = dns_b_get16(&src, -1)))
3622 			return src.error;
3623 		if (-1 == (len = dns_b_get16(&src, -1)))
3624 			return src.error;
3625 
3626 		switch (code) {
3627 		default:
3628 			dns_b_put16(&dst, code);
3629 			dns_b_put16(&dst, len);
3630 			if ((error = dns_b_move(&dst, &src, len)))
3631 				return error;
3632 			break;
3633 		}
3634 	}
3635 
3636 	return 0;
3637 } /* dns_opt_parse() */
3638 
3639 
dns_opt_push(struct dns_packet * P,struct dns_opt * opt)3640 int dns_opt_push(struct dns_packet *P, struct dns_opt *opt) {
3641 	const struct dns_buf src = DNS_B_FROM(opt->data, opt->len);
3642 	struct dns_buf dst = DNS_B_INTO(&P->data[P->end], (P->size - P->end));
3643 	int error;
3644 
3645 	/* rdata length (see below) */
3646 	if ((error = dns_b_put16(&dst, 0)))
3647 		goto error;
3648 
3649 	/* ... push known options here */
3650 
3651 	/* push opaque option data */
3652 	if ((error = dns_b_move(&dst, &src, (size_t)(src.pe - src.p))))
3653 		goto error;
3654 
3655 	/* rdata length */
3656 	if ((error = dns_b_pput16(&dst, dns_b_tell(&dst) - 2, 0)))
3657 		goto error;
3658 
3659 #if !DNS_DEBUG_OPT_FORMERR
3660 	P->end += dns_b_tell(&dst);
3661 #endif
3662 
3663 	return 0;
3664 error:
3665 	return error;
3666 } /* dns_opt_push() */
3667 
3668 
dns_opt_cmp(const struct dns_opt * a,const struct dns_opt * b)3669 int dns_opt_cmp(const struct dns_opt *a, const struct dns_opt *b) {
3670 	(void)a;
3671 	(void)b;
3672 
3673 	return -1;
3674 } /* dns_opt_cmp() */
3675 
3676 
dns_opt_print(void * _dst,size_t lim,struct dns_opt * opt)3677 size_t dns_opt_print(void *_dst, size_t lim, struct dns_opt *opt) {
3678 	struct dns_buf dst = DNS_B_INTO(_dst, lim);
3679 	size_t p;
3680 
3681 	dns_b_putc(&dst, '"');
3682 
3683 	for (p = 0; p < opt->len; p++) {
3684 		dns_b_putc(&dst, '\\');
3685 		dns_b_fmtju(&dst, opt->data[p], 3);
3686 	}
3687 
3688 	dns_b_putc(&dst, '"');
3689 
3690 	return dns_b_strllen(&dst);
3691 } /* dns_opt_print() */
3692 
3693 
dns_ptr_parse(struct dns_ptr * ptr,struct dns_rr * rr,struct dns_packet * P)3694 int dns_ptr_parse(struct dns_ptr *ptr, struct dns_rr *rr, struct dns_packet *P) {
3695 	return dns_ns_parse((struct dns_ns *)ptr, rr, P);
3696 } /* dns_ptr_parse() */
3697 
3698 
dns_ptr_push(struct dns_packet * P,struct dns_ptr * ptr)3699 int dns_ptr_push(struct dns_packet *P, struct dns_ptr *ptr) {
3700 	return dns_ns_push(P, (struct dns_ns *)ptr);
3701 } /* dns_ptr_push() */
3702 
3703 
dns_ptr_qname(void * dst,size_t lim,int af,void * addr)3704 size_t dns_ptr_qname(void *dst, size_t lim, int af, void *addr) {
3705 	switch (af) {
3706 	case AF_INET6:
3707 		return dns_aaaa_arpa(dst, lim, addr);
3708 	case AF_INET:
3709 		return dns_a_arpa(dst, lim, addr);
3710 	default: {
3711 		struct dns_a a;
3712 		a.addr.s_addr = INADDR_NONE;
3713 		return dns_a_arpa(dst, lim, &a);
3714 	}
3715 	}
3716 } /* dns_ptr_qname() */
3717 
3718 
dns_ptr_cmp(const struct dns_ptr * a,const struct dns_ptr * b)3719 int dns_ptr_cmp(const struct dns_ptr *a, const struct dns_ptr *b) {
3720 	return strcasecmp(a->host, b->host);
3721 } /* dns_ptr_cmp() */
3722 
3723 
dns_ptr_print(void * dst,size_t lim,struct dns_ptr * ptr)3724 size_t dns_ptr_print(void *dst, size_t lim, struct dns_ptr *ptr) {
3725 	return dns_ns_print(dst, lim, (struct dns_ns *)ptr);
3726 } /* dns_ptr_print() */
3727 
3728 
dns_ptr_cname(void * dst,size_t lim,struct dns_ptr * ptr)3729 size_t dns_ptr_cname(void *dst, size_t lim, struct dns_ptr *ptr) {
3730 	return dns_strlcpy(dst, ptr->host, lim);
3731 } /* dns_ptr_cname() */
3732 
3733 
dns_sshfp_parse(struct dns_sshfp * fp,struct dns_rr * rr,struct dns_packet * P)3734 int dns_sshfp_parse(struct dns_sshfp *fp, struct dns_rr *rr, struct dns_packet *P) {
3735 	unsigned p = rr->rd.p, pe = rr->rd.p + rr->rd.len;
3736 
3737 	if (pe - p < 2)
3738 		return DNS_EILLEGAL;
3739 
3740 	fp->algo = P->data[p++];
3741 	fp->type = P->data[p++];
3742 
3743 	switch (fp->type) {
3744 	case DNS_SSHFP_SHA1:
3745 		if (pe - p < sizeof fp->digest.sha1)
3746 			return DNS_EILLEGAL;
3747 
3748 		memcpy(fp->digest.sha1, &P->data[p], sizeof fp->digest.sha1);
3749 
3750 		break;
3751 	default:
3752 		break;
3753 	} /* switch() */
3754 
3755 	return 0;
3756 } /* dns_sshfp_parse() */
3757 
3758 
dns_sshfp_push(struct dns_packet * P,struct dns_sshfp * fp)3759 int dns_sshfp_push(struct dns_packet *P, struct dns_sshfp *fp) {
3760 	unsigned p = P->end, pe = P->size, n;
3761 
3762 	if (pe - p < 4)
3763 		return DNS_ENOBUFS;
3764 
3765 	p += 2;
3766 	P->data[p++] = 0xff & fp->algo;
3767 	P->data[p++] = 0xff & fp->type;
3768 
3769 	switch (fp->type) {
3770 	case DNS_SSHFP_SHA1:
3771 		if (pe - p < sizeof fp->digest.sha1)
3772 			return DNS_ENOBUFS;
3773 
3774 		memcpy(&P->data[p], fp->digest.sha1, sizeof fp->digest.sha1);
3775 		p += sizeof fp->digest.sha1;
3776 
3777 		break;
3778 	default:
3779 		return DNS_EILLEGAL;
3780 	} /* switch() */
3781 
3782 	n = p - P->end - 2;
3783 	P->data[P->end++] = 0xff & (n >> 8);
3784 	P->data[P->end++] = 0xff & (n >> 0);
3785 	P->end = p;
3786 
3787 	return 0;
3788 } /* dns_sshfp_push() */
3789 
3790 
dns_sshfp_cmp(const struct dns_sshfp * a,const struct dns_sshfp * b)3791 int dns_sshfp_cmp(const struct dns_sshfp *a, const struct dns_sshfp *b) {
3792 	int cmp;
3793 
3794 	if ((cmp = a->algo - b->algo) || (cmp = a->type - b->type))
3795 		return cmp;
3796 
3797 	switch (a->type) {
3798 	case DNS_SSHFP_SHA1:
3799 		return memcmp(a->digest.sha1, b->digest.sha1, sizeof a->digest.sha1);
3800 	default:
3801 		return 0;
3802 	} /* switch() */
3803 
3804 	/* NOT REACHED */
3805 } /* dns_sshfp_cmp() */
3806 
3807 
dns_sshfp_print(void * _dst,size_t lim,struct dns_sshfp * fp)3808 size_t dns_sshfp_print(void *_dst, size_t lim, struct dns_sshfp *fp) {
3809 	static const unsigned char hex[16] = "0123456789abcdef";
3810 	struct dns_buf dst = DNS_B_INTO(_dst, lim);
3811 	size_t i;
3812 
3813 	dns_b_fmtju(&dst, fp->algo, 0);
3814 	dns_b_putc(&dst, ' ');
3815 	dns_b_fmtju(&dst, fp->type, 0);
3816 	dns_b_putc(&dst, ' ');
3817 
3818 	switch (fp->type) {
3819 	case DNS_SSHFP_SHA1:
3820 		for (i = 0; i < sizeof fp->digest.sha1; i++) {
3821 			dns_b_putc(&dst, hex[0x0f & (fp->digest.sha1[i] >> 4)]);
3822 			dns_b_putc(&dst, hex[0x0f & (fp->digest.sha1[i] >> 0)]);
3823 		}
3824 
3825 		break;
3826 	default:
3827 		dns_b_putc(&dst, '0');
3828 
3829 		break;
3830 	} /* switch() */
3831 
3832 	return dns_b_strllen(&dst);
3833 } /* dns_sshfp_print() */
3834 
3835 
dns_txt_init(struct dns_txt * txt,size_t size)3836 struct dns_txt *dns_txt_init(struct dns_txt *txt, size_t size) {
3837 	assert(size > offsetof(struct dns_txt, data));
3838 
3839 	txt->size	= size - offsetof(struct dns_txt, data);
3840 	txt->len	= 0;
3841 
3842 	return txt;
3843 } /* dns_txt_init() */
3844 
3845 
dns_txt_initany(union dns_any * any,size_t size)3846 static union dns_any *dns_txt_initany(union dns_any *any, size_t size) {
3847 	/* NB: union dns_any is already initialized as struct dns_txt */
3848 	(void)size;
3849 	return any;
3850 } /* dns_txt_initany() */
3851 
3852 
dns_txt_parse(struct dns_txt * txt,struct dns_rr * rr,struct dns_packet * P)3853 int dns_txt_parse(struct dns_txt *txt, struct dns_rr *rr, struct dns_packet *P) {
3854 	struct { unsigned char *b; size_t p, end; } dst, src;
3855 	unsigned n;
3856 
3857 	dst.b	= txt->data;
3858 	dst.p	= 0;
3859 	dst.end	= txt->size;
3860 
3861 	src.b	= P->data;
3862 	src.p	= rr->rd.p;
3863 	src.end	= src.p + rr->rd.len;
3864 
3865 	while (src.p < src.end) {
3866 		n	= 0xff & P->data[src.p++];
3867 
3868 		if (src.end - src.p < n || dst.end - dst.p < n)
3869 			return DNS_EILLEGAL;
3870 
3871 		memcpy(&dst.b[dst.p], &src.b[src.p], n);
3872 
3873 		dst.p	+= n;
3874 		src.p	+= n;
3875 	}
3876 
3877 	txt->len	= dst.p;
3878 
3879 	return 0;
3880 } /* dns_txt_parse() */
3881 
3882 
dns_txt_push(struct dns_packet * P,struct dns_txt * txt)3883 int dns_txt_push(struct dns_packet *P, struct dns_txt *txt) {
3884 	struct { unsigned char *b; size_t p, end; } dst, src;
3885 	unsigned n;
3886 
3887 	dst.b	= P->data;
3888 	dst.p	= P->end;
3889 	dst.end	= P->size;
3890 
3891 	src.b	= txt->data;
3892 	src.p	= 0;
3893 	src.end	= txt->len;
3894 
3895 	if (dst.end - dst.p < 2)
3896 		return DNS_ENOBUFS;
3897 
3898 	n	= txt->len + ((txt->len + 254) / 255);
3899 
3900 	dst.b[dst.p++]	= 0xff & (n >> 8);
3901 	dst.b[dst.p++]	= 0xff & (n >> 0);
3902 
3903 	while (src.p < src.end) {
3904 		n	= DNS_PP_MIN(255, src.end - src.p);
3905 
3906 		if (dst.p >= dst.end)
3907 			return DNS_ENOBUFS;
3908 
3909 		dst.b[dst.p++]	= n;
3910 
3911 		if (dst.end - dst.p < n)
3912 			return DNS_ENOBUFS;
3913 
3914 		memcpy(&dst.b[dst.p], &src.b[src.p], n);
3915 
3916 		dst.p	+= n;
3917 		src.p	+= n;
3918 	}
3919 
3920 	P->end	= dst.p;
3921 
3922 	return 0;
3923 } /* dns_txt_push() */
3924 
3925 
dns_txt_cmp(const struct dns_txt * a,const struct dns_txt * b)3926 int dns_txt_cmp(const struct dns_txt *a, const struct dns_txt *b) {
3927 	(void)a;
3928 	(void)b;
3929 
3930 	return -1;
3931 } /* dns_txt_cmp() */
3932 
3933 
dns_txt_print(void * _dst,size_t lim,struct dns_txt * txt)3934 size_t dns_txt_print(void *_dst, size_t lim, struct dns_txt *txt) {
3935 	struct dns_buf src = DNS_B_FROM(txt->data, txt->len);
3936 	struct dns_buf dst = DNS_B_INTO(_dst, lim);
3937 	unsigned i;
3938 
3939 	if (src.p < src.pe) {
3940 		do {
3941 			dns_b_putc(&dst, '"');
3942 
3943 			for (i = 0; i < 256 && src.p < src.pe; i++, src.p++) {
3944 				if (*src.p < 32 || *src.p > 126 || *src.p == '"' || *src.p == '\\') {
3945 					dns_b_putc(&dst, '\\');
3946 					dns_b_fmtju(&dst, *src.p, 3);
3947 				} else {
3948 					dns_b_putc(&dst, *src.p);
3949 				}
3950 			}
3951 
3952 			dns_b_putc(&dst, '"');
3953 			dns_b_putc(&dst, ' ');
3954 		} while (src.p < src.pe);
3955 
3956 		dns_b_popc(&dst);
3957 	} else {
3958 		dns_b_putc(&dst, '"');
3959 		dns_b_putc(&dst, '"');
3960 	}
3961 
3962 	return dns_b_strllen(&dst);
3963 } /* dns_txt_print() */
3964 
3965 
3966 static const struct dns_rrtype {
3967 	enum dns_type type;
3968 	const char *name;
3969 	union dns_any *(*init)(union dns_any *, size_t);
3970 	int (*parse)();
3971 	int (*push)();
3972 	int (*cmp)();
3973 	size_t (*print)();
3974 	size_t (*cname)();
3975 } dns_rrtypes[]	= {
3976 	{ DNS_T_A,      "A",      0,                 &dns_a_parse,      &dns_a_push,      &dns_a_cmp,      &dns_a_print,      0,                },
3977 	{ DNS_T_AAAA,   "AAAA",   0,                 &dns_aaaa_parse,   &dns_aaaa_push,   &dns_aaaa_cmp,   &dns_aaaa_print,   0,                },
3978 	{ DNS_T_MX,     "MX",     0,                 &dns_mx_parse,     &dns_mx_push,     &dns_mx_cmp,     &dns_mx_print,     &dns_mx_cname,    },
3979 	{ DNS_T_NS,     "NS",     0,                 &dns_ns_parse,     &dns_ns_push,     &dns_ns_cmp,     &dns_ns_print,     &dns_ns_cname,    },
3980 	{ DNS_T_CNAME,  "CNAME",  0,                 &dns_cname_parse,  &dns_cname_push,  &dns_cname_cmp,  &dns_cname_print,  &dns_cname_cname, },
3981 	{ DNS_T_SOA,    "SOA",    0,                 &dns_soa_parse,    &dns_soa_push,    &dns_soa_cmp,    &dns_soa_print,    0,                },
3982 	{ DNS_T_SRV,    "SRV",    0,                 &dns_srv_parse,    &dns_srv_push,    &dns_srv_cmp,    &dns_srv_print,    &dns_srv_cname,   },
3983 	{ DNS_T_OPT,    "OPT",    &dns_opt_initany,  &dns_opt_parse,    &dns_opt_push,    &dns_opt_cmp,    &dns_opt_print,    0,                },
3984 	{ DNS_T_PTR,    "PTR",    0,                 &dns_ptr_parse,    &dns_ptr_push,    &dns_ptr_cmp,    &dns_ptr_print,    &dns_ptr_cname,   },
3985 	{ DNS_T_TXT,    "TXT",    &dns_txt_initany,  &dns_txt_parse,    &dns_txt_push,    &dns_txt_cmp,    &dns_txt_print,    0,                },
3986 	{ DNS_T_SPF,    "SPF",    &dns_txt_initany,  &dns_txt_parse,    &dns_txt_push,    &dns_txt_cmp,    &dns_txt_print,    0,                },
3987 	{ DNS_T_SSHFP,  "SSHFP",  0,                 &dns_sshfp_parse,  &dns_sshfp_push,  &dns_sshfp_cmp,  &dns_sshfp_print,  0,                },
3988 	{ DNS_T_AXFR,   "AXFR",   0,                 0,                 0,                0,               0,                 0,                },
3989 }; /* dns_rrtypes[] */
3990 
dns_rrtype(enum dns_type type)3991 static const struct dns_rrtype *dns_rrtype(enum dns_type type) {
3992 	const struct dns_rrtype *t;
3993 
3994 	for (t = dns_rrtypes; t < endof(dns_rrtypes); t++) {
3995 		if (t->type == type && t->parse) {
3996 			return t;
3997 		}
3998 	}
3999 
4000 	return NULL;
4001 } /* dns_rrtype() */
4002 
4003 
dns_any_init(union dns_any * any,size_t size)4004 union dns_any *dns_any_init(union dns_any *any, size_t size) {
4005 	dns_static_assert(dns_same_type(any->txt, any->rdata, 1), "unexpected rdata type");
4006 	return (union dns_any *)dns_txt_init(&any->rdata, size);
4007 } /* dns_any_init() */
4008 
4009 
dns_any_sizeof(union dns_any * any)4010 static size_t dns_any_sizeof(union dns_any *any) {
4011 	dns_static_assert(dns_same_type(any->txt, any->rdata, 1), "unexpected rdata type");
4012 	return offsetof(struct dns_txt, data) + any->rdata.size;
4013 } /* dns_any_sizeof() */
4014 
dns_any_reinit(union dns_any * any,const struct dns_rrtype * t)4015 static union dns_any *dns_any_reinit(union dns_any *any, const struct dns_rrtype *t) {
4016 	return (t->init)? t->init(any, dns_any_sizeof(any)) : any;
4017 } /* dns_any_reinit() */
4018 
dns_any_parse(union dns_any * any,struct dns_rr * rr,struct dns_packet * P)4019 int dns_any_parse(union dns_any *any, struct dns_rr *rr, struct dns_packet *P) {
4020 	const struct dns_rrtype *t;
4021 
4022 	if ((t = dns_rrtype(rr->type)))
4023 		return t->parse(dns_any_reinit(any, t), rr, P);
4024 
4025 	if (rr->rd.len > any->rdata.size)
4026 		return DNS_EILLEGAL;
4027 
4028 	memcpy(any->rdata.data, &P->data[rr->rd.p], rr->rd.len);
4029 	any->rdata.len	= rr->rd.len;
4030 
4031 	return 0;
4032 } /* dns_any_parse() */
4033 
4034 
dns_any_push(struct dns_packet * P,union dns_any * any,enum dns_type type)4035 int dns_any_push(struct dns_packet *P, union dns_any *any, enum dns_type type) {
4036 	const struct dns_rrtype *t;
4037 
4038 	if ((t = dns_rrtype(type)))
4039 		return t->push(P, any);
4040 
4041 	if (P->size - P->end < any->rdata.len + 2)
4042 		return DNS_ENOBUFS;
4043 
4044 	P->data[P->end++]	= 0xff & (any->rdata.len >> 8);
4045 	P->data[P->end++]	= 0xff & (any->rdata.len >> 0);
4046 
4047 	memcpy(&P->data[P->end], any->rdata.data, any->rdata.len);
4048 	P->end	+= any->rdata.len;
4049 
4050 	return 0;
4051 } /* dns_any_push() */
4052 
4053 
dns_any_cmp(const union dns_any * a,enum dns_type x,const union dns_any * b,enum dns_type y)4054 int dns_any_cmp(const union dns_any *a, enum dns_type x, const union dns_any *b, enum dns_type y) {
4055 	const struct dns_rrtype *t;
4056 	int cmp;
4057 
4058 	if ((cmp = x - y))
4059 		return cmp;
4060 
4061 	if ((t = dns_rrtype(x)))
4062 		return t->cmp(a, b);
4063 
4064 	return -1;
4065 } /* dns_any_cmp() */
4066 
4067 
dns_any_print(void * _dst,size_t lim,union dns_any * any,enum dns_type type)4068 size_t dns_any_print(void *_dst, size_t lim, union dns_any *any, enum dns_type type) {
4069 	const struct dns_rrtype *t;
4070 	struct dns_buf src, dst;
4071 
4072 	if ((t = dns_rrtype(type)))
4073 		return t->print(_dst, lim, any);
4074 
4075 	dns_b_from(&src, any->rdata.data, any->rdata.len);
4076 	dns_b_into(&dst, _dst, lim);
4077 
4078 	dns_b_putc(&dst, '"');
4079 
4080 	while (src.p < src.pe) {
4081 		dns_b_putc(&dst, '\\');
4082 		dns_b_fmtju(&dst, *src.p++, 3);
4083 	}
4084 
4085 	dns_b_putc(&dst, '"');
4086 
4087 	return dns_b_strllen(&dst);
4088 } /* dns_any_print() */
4089 
4090 
dns_any_cname(void * dst,size_t lim,union dns_any * any,enum dns_type type)4091 size_t dns_any_cname(void *dst, size_t lim, union dns_any *any, enum dns_type type) {
4092 	const struct dns_rrtype *t;
4093 
4094 	if ((t = dns_rrtype(type)) && t->cname)
4095 		return t->cname(dst, lim, any);
4096 
4097 	return 0;
4098 } /* dns_any_cname() */
4099 
4100 
4101 /*
4102  * H O S T S  R O U T I N E S
4103  *
4104  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4105 
4106 struct dns_hosts {
4107 	struct dns_hosts_entry {
4108 		char host[DNS_D_MAXNAME + 1];
4109 		char arpa[73 + 1];
4110 
4111 		int af;
4112 
4113 		union {
4114 			struct in_addr a4;
4115 			struct in6_addr a6;
4116 		} addr;
4117 
4118 		_Bool alias;
4119 
4120 		struct dns_hosts_entry *next;
4121 	} *head, **tail;
4122 
4123 	dns_atomic_t refcount;
4124 }; /* struct dns_hosts */
4125 
4126 
dns_hosts_open(int * error)4127 struct dns_hosts *dns_hosts_open(int *error) {
4128 	static const struct dns_hosts hosts_initializer	= { .refcount = 1 };
4129 	struct dns_hosts *hosts;
4130 
4131 	if (!(hosts = malloc(sizeof *hosts)))
4132 		goto syerr;
4133 
4134 	*hosts	= hosts_initializer;
4135 
4136 	hosts->tail	= &hosts->head;
4137 
4138 	return hosts;
4139 syerr:
4140 	*error	= dns_syerr();
4141 
4142 	free(hosts);
4143 
4144 	return 0;
4145 } /* dns_hosts_open() */
4146 
4147 
dns_hosts_close(struct dns_hosts * hosts)4148 void dns_hosts_close(struct dns_hosts *hosts) {
4149 	struct dns_hosts_entry *ent, *xnt;
4150 
4151 	if (!hosts || 1 != dns_hosts_release(hosts))
4152 		return;
4153 
4154 	for (ent = hosts->head; ent; ent = xnt) {
4155 		xnt	= ent->next;
4156 
4157 		free(ent);
4158 	}
4159 
4160 	free(hosts);
4161 
4162 	return;
4163 } /* dns_hosts_close() */
4164 
4165 
dns_hosts_acquire(struct dns_hosts * hosts)4166 dns_refcount_t dns_hosts_acquire(struct dns_hosts *hosts) {
4167 	return dns_atomic_fetch_add(&hosts->refcount);
4168 } /* dns_hosts_acquire() */
4169 
4170 
dns_hosts_release(struct dns_hosts * hosts)4171 dns_refcount_t dns_hosts_release(struct dns_hosts *hosts) {
4172 	return dns_atomic_fetch_sub(&hosts->refcount);
4173 } /* dns_hosts_release() */
4174 
4175 
dns_hosts_mortal(struct dns_hosts * hosts)4176 struct dns_hosts *dns_hosts_mortal(struct dns_hosts *hosts) {
4177 	if (hosts)
4178 		dns_hosts_release(hosts);
4179 
4180 	return hosts;
4181 } /* dns_hosts_mortal() */
4182 
4183 
dns_hosts_local(int * error_)4184 struct dns_hosts *dns_hosts_local(int *error_) {
4185 	struct dns_hosts *hosts;
4186 	int error;
4187 
4188 	if (!(hosts = dns_hosts_open(&error)))
4189 		goto error;
4190 
4191 	if ((error = dns_hosts_loadpath(hosts, "/etc/hosts")))
4192 		goto error;
4193 
4194 	return hosts;
4195 error:
4196 	*error_	= error;
4197 
4198 	dns_hosts_close(hosts);
4199 
4200 	return 0;
4201 } /* dns_hosts_local() */
4202 
4203 
4204 #define dns_hosts_issep(ch)	(dns_isspace(ch))
4205 #define dns_hosts_iscom(ch)	((ch) == '#' || (ch) == ';')
4206 
dns_hosts_loadfile(struct dns_hosts * hosts,FILE * fp)4207 int dns_hosts_loadfile(struct dns_hosts *hosts, FILE *fp) {
4208 	struct dns_hosts_entry ent;
4209 	char word[DNS_PP_MAX(INET6_ADDRSTRLEN, DNS_D_MAXNAME) + 1];
4210 	unsigned wp, wc, skip;
4211 	int ch, error;
4212 
4213 	rewind(fp);
4214 
4215 	do {
4216 		memset(&ent, '\0', sizeof ent);
4217 		wc	= 0;
4218 		skip	= 0;
4219 
4220 		do {
4221 			memset(word, '\0', sizeof word);
4222 			wp	= 0;
4223 
4224 			while (EOF != (ch = fgetc(fp)) && ch != '\n') {
4225 				skip	|= !!dns_hosts_iscom(ch);
4226 
4227 				if (skip)
4228 					continue;
4229 
4230 				if (dns_hosts_issep(ch))
4231 					break;
4232 
4233 				if (wp < sizeof word - 1)
4234 					word[wp]	= ch;
4235 				wp++;
4236 			}
4237 
4238 			if (!wp)
4239 				continue;
4240 
4241 			wc++;
4242 
4243 			switch (wc) {
4244 			case 0:
4245 				break;
4246 			case 1:
4247 				ent.af	= (strchr(word, ':'))? AF_INET6 : AF_INET;
4248 				skip	= (1 != dns_inet_pton(ent.af, word, &ent.addr));
4249 
4250 				break;
4251 			default:
4252 				if (!wp)
4253 					break;
4254 
4255 				dns_d_anchor(ent.host, sizeof ent.host, word, wp);
4256 
4257 				if ((error = dns_hosts_insert(hosts, ent.af, &ent.addr, ent.host, (wc > 2))))
4258 					return error;
4259 
4260 				break;
4261 			} /* switch() */
4262 		} while (ch != EOF && ch != '\n');
4263 	} while (ch != EOF);
4264 
4265 	return 0;
4266 } /* dns_hosts_loadfile() */
4267 
4268 
dns_hosts_loadpath(struct dns_hosts * hosts,const char * path)4269 int dns_hosts_loadpath(struct dns_hosts *hosts, const char *path) {
4270 	FILE *fp;
4271 	int error;
4272 
4273 	if (!(fp = dns_fopen(path, "rt", &error)))
4274 		return error;
4275 
4276 	error = dns_hosts_loadfile(hosts, fp);
4277 
4278 	fclose(fp);
4279 
4280 	return error;
4281 } /* dns_hosts_loadpath() */
4282 
4283 
dns_hosts_dump(struct dns_hosts * hosts,FILE * fp)4284 int dns_hosts_dump(struct dns_hosts *hosts, FILE *fp) {
4285 	struct dns_hosts_entry *ent, *xnt;
4286 	char addr[INET6_ADDRSTRLEN + 1];
4287 	unsigned i;
4288 
4289 	for (ent = hosts->head; ent; ent = xnt) {
4290 		xnt	= ent->next;
4291 
4292 		dns_inet_ntop(ent->af, &ent->addr, addr, sizeof addr);
4293 
4294 		fputs(addr, fp);
4295 
4296 		for (i = strlen(addr); i < INET_ADDRSTRLEN; i++)
4297 			fputc(' ', fp);
4298 
4299 		fputc(' ', fp);
4300 
4301 		fputs(ent->host, fp);
4302 		fputc('\n', fp);
4303 	}
4304 
4305 	return 0;
4306 } /* dns_hosts_dump() */
4307 
4308 
dns_hosts_insert(struct dns_hosts * hosts,int af,const void * addr,const void * host,_Bool alias)4309 int dns_hosts_insert(struct dns_hosts *hosts, int af, const void *addr, const void *host, _Bool alias) {
4310 	struct dns_hosts_entry *ent;
4311 	int error;
4312 
4313 	if (!(ent = malloc(sizeof *ent)))
4314 		goto syerr;
4315 
4316 	dns_d_anchor(ent->host, sizeof ent->host, host, strlen(host));
4317 
4318 	switch ((ent->af = af)) {
4319 	case AF_INET6:
4320 		memcpy(&ent->addr.a6, addr, sizeof ent->addr.a6);
4321 
4322 		dns_aaaa_arpa(ent->arpa, sizeof ent->arpa, addr);
4323 
4324 		break;
4325 	case AF_INET:
4326 		memcpy(&ent->addr.a4, addr, sizeof ent->addr.a4);
4327 
4328 		dns_a_arpa(ent->arpa, sizeof ent->arpa, addr);
4329 
4330 		break;
4331 	default:
4332 		error	= EINVAL;
4333 
4334 		goto error;
4335 	} /* switch() */
4336 
4337 	ent->alias	= alias;
4338 
4339 	ent->next	= 0;
4340 	*hosts->tail	= ent;
4341 	hosts->tail	= &ent->next;
4342 
4343 	return 0;
4344 syerr:
4345 	error	= dns_syerr();
4346 error:
4347 	free(ent);
4348 
4349 	return error;
4350 } /* dns_hosts_insert() */
4351 
4352 
dns_hosts_query(struct dns_hosts * hosts,struct dns_packet * Q,int * error_)4353 struct dns_packet *dns_hosts_query(struct dns_hosts *hosts, struct dns_packet *Q, int *error_) {
4354 	struct dns_packet *P	= dns_p_new(512);
4355 	struct dns_packet *A	= 0;
4356 	struct dns_rr rr;
4357 	struct dns_hosts_entry *ent;
4358 	int error, af;
4359 	char qname[DNS_D_MAXNAME + 1];
4360 	size_t qlen;
4361 
4362 	if ((error = dns_rr_parse(&rr, 12, Q)))
4363 		goto error;
4364 
4365 	if (!(qlen = dns_d_expand(qname, sizeof qname, rr.dn.p, Q, &error)))
4366 		goto error;
4367 	else if (qlen >= sizeof qname)
4368 		goto toolong;
4369 
4370 	if ((error = dns_p_push(P, DNS_S_QD, qname, qlen, rr.type, rr.class, 0, 0)))
4371 		goto error;
4372 
4373 	switch (rr.type) {
4374 	case DNS_T_PTR:
4375 		for (ent = hosts->head; ent; ent = ent->next) {
4376 			if (ent->alias || 0 != strcasecmp(qname, ent->arpa))
4377 				continue;
4378 
4379 			if ((error = dns_p_push(P, DNS_S_AN, qname, qlen, rr.type, rr.class, 0, ent->host)))
4380 				goto error;
4381 		}
4382 
4383 		break;
4384 	case DNS_T_AAAA:
4385 		af	= AF_INET6;
4386 
4387 		goto loop;
4388 	case DNS_T_A:
4389 		af	= AF_INET;
4390 
4391 loop:		for (ent = hosts->head; ent; ent = ent->next) {
4392 			if (ent->af != af || 0 != strcasecmp(qname, ent->host))
4393 				continue;
4394 
4395 			if ((error = dns_p_push(P, DNS_S_AN, qname, qlen, rr.type, rr.class, 0, &ent->addr)))
4396 				goto error;
4397 		}
4398 
4399 		break;
4400 	default:
4401 		break;
4402 	} /* switch() */
4403 
4404 
4405 	if (!(A = dns_p_copy(dns_p_make(P->end, &error), P)))
4406 		goto error;
4407 
4408 	return A;
4409 toolong:
4410 	error = DNS_EILLEGAL;
4411 error:
4412 	*error_	= error;
4413 
4414 	dns_p_free(A);
4415 
4416 	return 0;
4417 } /* dns_hosts_query() */
4418 
4419 
4420 /*
4421  * R E S O L V . C O N F  R O U T I N E S
4422  *
4423  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4424 
dns_resconf_open(int * error)4425 struct dns_resolv_conf *dns_resconf_open(int *error) {
4426 	static const struct dns_resolv_conf resconf_initializer = {
4427 		.lookup = "bf",
4428 		.family = { AF_INET, AF_INET6 },
4429 		.options = { .ndots = 1, .timeout = 5, .attempts = 2, .tcp = DNS_RESCONF_TCP_ENABLE, },
4430 		.iface = { .ss_family = AF_INET },
4431 	};
4432 	struct dns_resolv_conf *resconf;
4433 	struct sockaddr_in *sin;
4434 	size_t len;
4435 
4436 	if (!(resconf = malloc(sizeof *resconf)))
4437 		goto syerr;
4438 
4439 	*resconf = resconf_initializer;
4440 
4441 	sin = (struct sockaddr_in *)&resconf->nameserver[0];
4442 	sin->sin_family      = AF_INET;
4443 	sin->sin_addr.s_addr = INADDR_ANY;
4444 	sin->sin_port        = htons(53);
4445 #if defined(SA_LEN)
4446 	sin->sin_len         = sizeof *sin;
4447 #endif
4448 
4449 	if (0 != gethostname(resconf->search[0], sizeof resconf->search[0]))
4450 		goto syerr;
4451 
4452 	len = strlen(resconf->search[0]);
4453 	len = dns_d_anchor(resconf->search[0], sizeof resconf->search[0], resconf->search[0], len);
4454 	len = dns_d_cleave(resconf->search[0], sizeof resconf->search[0], resconf->search[0], len);
4455 	if (1 == len) /* gethostname() returned a string without any label */
4456 		resconf->search[0][0] = '\0';
4457 
4458 	dns_resconf_acquire(resconf);
4459 
4460 	return resconf;
4461 syerr:
4462 	*error	= dns_syerr();
4463 
4464 	free(resconf);
4465 
4466 	return 0;
4467 } /* dns_resconf_open() */
4468 
4469 
dns_resconf_close(struct dns_resolv_conf * resconf)4470 void dns_resconf_close(struct dns_resolv_conf *resconf) {
4471 	if (!resconf || 1 != dns_resconf_release(resconf))
4472 		return /* void */;
4473 
4474 	free(resconf);
4475 } /* dns_resconf_close() */
4476 
4477 
dns_resconf_acquire(struct dns_resolv_conf * resconf)4478 dns_refcount_t dns_resconf_acquire(struct dns_resolv_conf *resconf) {
4479 	return dns_atomic_fetch_add(&resconf->_.refcount);
4480 } /* dns_resconf_acquire() */
4481 
4482 
dns_resconf_release(struct dns_resolv_conf * resconf)4483 dns_refcount_t dns_resconf_release(struct dns_resolv_conf *resconf) {
4484 	return dns_atomic_fetch_sub(&resconf->_.refcount);
4485 } /* dns_resconf_release() */
4486 
4487 
dns_resconf_mortal(struct dns_resolv_conf * resconf)4488 struct dns_resolv_conf *dns_resconf_mortal(struct dns_resolv_conf *resconf) {
4489 	if (resconf)
4490 		dns_resconf_release(resconf);
4491 
4492 	return resconf;
4493 } /* dns_resconf_mortal() */
4494 
4495 
dns_resconf_local(int * error_)4496 struct dns_resolv_conf *dns_resconf_local(int *error_) {
4497 	struct dns_resolv_conf *resconf;
4498 	int error;
4499 
4500 	if (!(resconf = dns_resconf_open(&error)))
4501 		goto error;
4502 
4503 	if ((error = dns_resconf_loadpath(resconf, "/etc/resolv.conf"))) {
4504 		/*
4505 		 * NOTE: Both the glibc and BIND9 resolvers ignore a missing
4506 		 * /etc/resolv.conf, defaulting to a nameserver of
4507 		 * 127.0.0.1. See also dns_hints_insert_resconf, and the
4508 		 * default initialization of nameserver[0] in
4509 		 * dns_resconf_open.
4510 		 */
4511 		if (error != ENOENT)
4512 			goto error;
4513 	}
4514 
4515 	if ((error = dns_nssconf_loadpath(resconf, "/etc/nsswitch.conf"))) {
4516 		if (error != ENOENT)
4517 			goto error;
4518 	}
4519 
4520 	return resconf;
4521 error:
4522 	*error_	= error;
4523 
4524 	dns_resconf_close(resconf);
4525 
4526 	return 0;
4527 } /* dns_resconf_local() */
4528 
4529 
dns_resconf_root(int * error)4530 struct dns_resolv_conf *dns_resconf_root(int *error) {
4531 	struct dns_resolv_conf *resconf;
4532 
4533 	if ((resconf = dns_resconf_local(error)))
4534 		resconf->options.recurse = 1;
4535 
4536 	return resconf;
4537 } /* dns_resconf_root() */
4538 
4539 
dns_resconf_timeout(const struct dns_resolv_conf * resconf)4540 static time_t dns_resconf_timeout(const struct dns_resolv_conf *resconf) {
4541 	return (time_t)DNS_PP_MIN(INT_MAX, resconf->options.timeout);
4542 } /* dns_resconf_timeout() */
4543 
4544 
4545 enum dns_resconf_keyword {
4546 	DNS_RESCONF_NAMESERVER,
4547 	DNS_RESCONF_DOMAIN,
4548 	DNS_RESCONF_SEARCH,
4549 	DNS_RESCONF_LOOKUP,
4550 	DNS_RESCONF_FILE,
4551 	DNS_RESCONF_BIND,
4552 	DNS_RESCONF_CACHE,
4553 	DNS_RESCONF_FAMILY,
4554 	DNS_RESCONF_INET4,
4555 	DNS_RESCONF_INET6,
4556 	DNS_RESCONF_OPTIONS,
4557 	DNS_RESCONF_EDNS0,
4558 	DNS_RESCONF_NDOTS,
4559 	DNS_RESCONF_TIMEOUT,
4560 	DNS_RESCONF_ATTEMPTS,
4561 	DNS_RESCONF_ROTATE,
4562 	DNS_RESCONF_RECURSE,
4563 	DNS_RESCONF_SMART,
4564 	DNS_RESCONF_TCP,
4565 	DNS_RESCONF_TCPx,
4566 	DNS_RESCONF_INTERFACE,
4567 	DNS_RESCONF_ZERO,
4568 	DNS_RESCONF_ONE,
4569 	DNS_RESCONF_ENABLE,
4570 	DNS_RESCONF_ONLY,
4571 	DNS_RESCONF_DISABLE,
4572 }; /* enum dns_resconf_keyword */
4573 
dns_resconf_keyword(const char * word)4574 static enum dns_resconf_keyword dns_resconf_keyword(const char *word) {
4575 	static const char *words[]	= {
4576 		[DNS_RESCONF_NAMESERVER]	= "nameserver",
4577 		[DNS_RESCONF_DOMAIN]		= "domain",
4578 		[DNS_RESCONF_SEARCH]		= "search",
4579 		[DNS_RESCONF_LOOKUP]		= "lookup",
4580 		[DNS_RESCONF_FILE]		= "file",
4581 		[DNS_RESCONF_BIND]		= "bind",
4582 		[DNS_RESCONF_CACHE]		= "cache",
4583 		[DNS_RESCONF_FAMILY]		= "family",
4584 		[DNS_RESCONF_INET4]		= "inet4",
4585 		[DNS_RESCONF_INET6]		= "inet6",
4586 		[DNS_RESCONF_OPTIONS]		= "options",
4587 		[DNS_RESCONF_EDNS0]		= "edns0",
4588 		[DNS_RESCONF_ROTATE]		= "rotate",
4589 		[DNS_RESCONF_RECURSE]		= "recurse",
4590 		[DNS_RESCONF_SMART]		= "smart",
4591 		[DNS_RESCONF_TCP]		= "tcp",
4592 		[DNS_RESCONF_INTERFACE]		= "interface",
4593 		[DNS_RESCONF_ZERO]		= "0",
4594 		[DNS_RESCONF_ONE]		= "1",
4595 		[DNS_RESCONF_ENABLE]		= "enable",
4596 		[DNS_RESCONF_ONLY]		= "only",
4597 		[DNS_RESCONF_DISABLE]		= "disable",
4598 	};
4599 	unsigned i;
4600 
4601 	for (i = 0; i < lengthof(words); i++) {
4602 		if (words[i] && 0 == strcasecmp(words[i], word))
4603 			return i;
4604 	}
4605 
4606 	if (0 == strncasecmp(word, "ndots:", sizeof "ndots:" - 1))
4607 		return DNS_RESCONF_NDOTS;
4608 
4609 	if (0 == strncasecmp(word, "timeout:", sizeof "timeout:" - 1))
4610 		return DNS_RESCONF_TIMEOUT;
4611 
4612 	if (0 == strncasecmp(word, "attempts:", sizeof "attempts:" - 1))
4613 		return DNS_RESCONF_ATTEMPTS;
4614 
4615 	if (0 == strncasecmp(word, "tcp:", sizeof "tcp:" - 1))
4616 		return DNS_RESCONF_TCPx;
4617 
4618 	return -1;
4619 } /* dns_resconf_keyword() */
4620 
4621 
4622 /** OpenBSD-style "[1.2.3.4]:53" nameserver syntax */
dns_resconf_pton(struct sockaddr_storage * ss,const char * src)4623 int dns_resconf_pton(struct sockaddr_storage *ss, const char *src) {
4624 	struct { char buf[128], *p; } addr = { "", addr.buf };
4625 	unsigned short port = 0;
4626 	int ch, af = AF_INET, error;
4627 
4628 	while ((ch = *src++)) {
4629 		switch (ch) {
4630 		case ' ':
4631 			/* FALL THROUGH */
4632 		case '\t':
4633 			break;
4634 		case '[':
4635 			break;
4636 		case ']':
4637 			while ((ch = *src++)) {
4638 				if (dns_isdigit(ch)) {
4639 					port *= 10;
4640 					port += ch - '0';
4641 				}
4642 			}
4643 
4644 			goto inet;
4645 		case ':':
4646 			af = AF_INET6;
4647 
4648 			/* FALL THROUGH */
4649 		default:
4650 			if (addr.p < endof(addr.buf) - 1)
4651 				*addr.p++ = ch;
4652 
4653 			break;
4654 		} /* switch() */
4655 	} /* while() */
4656 inet:
4657 
4658 	if ((error = dns_pton(af, addr.buf, dns_sa_addr(af, ss, NULL))))
4659 		return error;
4660 
4661 	port = (!port)? 53 : port;
4662 	*dns_sa_port(af, ss) = htons(port);
4663 	dns_sa_family(ss) = af;
4664 
4665 	return 0;
4666 } /* dns_resconf_pton() */
4667 
4668 #define dns_resconf_issep(ch)	(dns_isspace(ch) || (ch) == ',')
4669 #define dns_resconf_iscom(ch)	((ch) == '#' || (ch) == ';')
4670 
dns_resconf_loadfile(struct dns_resolv_conf * resconf,FILE * fp)4671 int dns_resconf_loadfile(struct dns_resolv_conf *resconf, FILE *fp) {
4672 	unsigned sa_count	= 0;
4673 	char words[6][DNS_D_MAXNAME + 1];
4674 	unsigned wp, wc, i, j, n;
4675 	int ch, error;
4676 
4677 	rewind(fp);
4678 
4679 	do {
4680 		memset(words, '\0', sizeof words);
4681 		wp	= 0;
4682 		wc	= 0;
4683 
4684 		while (EOF != (ch = getc(fp)) && ch != '\n') {
4685 			if (dns_resconf_issep(ch)) {
4686 				if (wp > 0) {
4687 					wp	= 0;
4688 
4689 					if (++wc >= lengthof(words))
4690 						goto skip;
4691 				}
4692 			} else if (dns_resconf_iscom(ch)) {
4693 skip:
4694 				do {
4695 					ch	= getc(fp);
4696 				} while (ch != EOF && ch != '\n');
4697 
4698 				break;
4699 			} else if (wp < sizeof words[wc] - 1) {
4700 				words[wc][wp++] = ch;
4701 			} else {
4702 				wp = 0; /* drop word */
4703 				goto skip;
4704 			}
4705 		}
4706 
4707 		if (wp > 0)
4708 			wc++;
4709 
4710 		if (wc < 2)
4711 			continue;
4712 
4713 		switch (dns_resconf_keyword(words[0])) {
4714 		case DNS_RESCONF_NAMESERVER:
4715 			if (sa_count >= lengthof(resconf->nameserver))
4716 				continue;
4717 
4718 			if ((error = dns_resconf_pton(&resconf->nameserver[sa_count], words[1])))
4719 				continue;
4720 
4721 			sa_count++;
4722 
4723 			break;
4724 		case DNS_RESCONF_DOMAIN:
4725 		case DNS_RESCONF_SEARCH:
4726 			memset(resconf->search, '\0', sizeof resconf->search);
4727 
4728 			for (i = 1, j = 0; i < wc && j < lengthof(resconf->search); i++, j++)
4729 				dns_d_anchor(resconf->search[j], sizeof resconf->search[j], words[i], strlen(words[i]));
4730 
4731 			break;
4732 		case DNS_RESCONF_LOOKUP:
4733 			for (i = 1, j = 0; i < wc && j < lengthof(resconf->lookup); i++) {
4734 				switch (dns_resconf_keyword(words[i])) {
4735 				case DNS_RESCONF_FILE:
4736 					resconf->lookup[j++]	= 'f';
4737 
4738 					break;
4739 				case DNS_RESCONF_BIND:
4740 					resconf->lookup[j++]	= 'b';
4741 
4742 					break;
4743 				case DNS_RESCONF_CACHE:
4744 					resconf->lookup[j++]	= 'c';
4745 
4746 					break;
4747 				default:
4748 					break;
4749 				} /* switch() */
4750 			} /* for() */
4751 
4752 			break;
4753 		case DNS_RESCONF_FAMILY:
4754 			for (i = 1, j = 0; i < wc && j < lengthof(resconf->family); i++) {
4755 				switch (dns_resconf_keyword(words[i])) {
4756 				case DNS_RESCONF_INET4:
4757 					resconf->family[j++]	= AF_INET;
4758 
4759 					break;
4760 				case DNS_RESCONF_INET6:
4761 					resconf->family[j++]	= AF_INET6;
4762 
4763 					break;
4764 				default:
4765 					break;
4766 				}
4767 			}
4768 
4769 			break;
4770 		case DNS_RESCONF_OPTIONS:
4771 			for (i = 1; i < wc; i++) {
4772 				switch (dns_resconf_keyword(words[i])) {
4773 				case DNS_RESCONF_EDNS0:
4774 					resconf->options.edns0	= 1;
4775 
4776 					break;
4777 				case DNS_RESCONF_NDOTS:
4778 					for (j = sizeof "ndots:" - 1, n = 0; dns_isdigit(words[i][j]); j++) {
4779 						n	*= 10;
4780 						n	+= words[i][j] - '0';
4781 					} /* for() */
4782 
4783 					resconf->options.ndots	= n;
4784 
4785 					break;
4786 				case DNS_RESCONF_TIMEOUT:
4787 					for (j = sizeof "timeout:" - 1, n = 0; dns_isdigit(words[i][j]); j++) {
4788 						n	*= 10;
4789 						n	+= words[i][j] - '0';
4790 					} /* for() */
4791 
4792 					resconf->options.timeout	= n;
4793 
4794 					break;
4795 				case DNS_RESCONF_ATTEMPTS:
4796 					for (j = sizeof "attempts:" - 1, n = 0; dns_isdigit(words[i][j]); j++) {
4797 						n	*= 10;
4798 						n	+= words[i][j] - '0';
4799 					} /* for() */
4800 
4801 					resconf->options.attempts	= n;
4802 
4803 					break;
4804 				case DNS_RESCONF_ROTATE:
4805 					resconf->options.rotate		= 1;
4806 
4807 					break;
4808 				case DNS_RESCONF_RECURSE:
4809 					resconf->options.recurse	= 1;
4810 
4811 					break;
4812 				case DNS_RESCONF_SMART:
4813 					resconf->options.smart		= 1;
4814 
4815 					break;
4816 				case DNS_RESCONF_TCP:
4817 					resconf->options.tcp		= DNS_RESCONF_TCP_ONLY;
4818 
4819 					break;
4820 				case DNS_RESCONF_TCPx:
4821 					switch (dns_resconf_keyword(&words[i][sizeof "tcp:" - 1])) {
4822 					case DNS_RESCONF_ENABLE:
4823 						resconf->options.tcp	= DNS_RESCONF_TCP_ENABLE;
4824 
4825 						break;
4826 					case DNS_RESCONF_ONE:
4827 					case DNS_RESCONF_ONLY:
4828 						resconf->options.tcp	= DNS_RESCONF_TCP_ONLY;
4829 
4830 						break;
4831 					case DNS_RESCONF_ZERO:
4832 					case DNS_RESCONF_DISABLE:
4833 						resconf->options.tcp	= DNS_RESCONF_TCP_DISABLE;
4834 
4835 						break;
4836 					default:
4837 						break;
4838 					} /* switch() */
4839 
4840 					break;
4841 				default:
4842 					break;
4843 				} /* switch() */
4844 			} /* for() */
4845 
4846 			break;
4847 		case DNS_RESCONF_INTERFACE:
4848 			for (i = 0, n = 0; dns_isdigit(words[2][i]); i++) {
4849 				n	*= 10;
4850 				n	+= words[2][i] - '0';
4851 			}
4852 
4853 			dns_resconf_setiface(resconf, words[1], n);
4854 
4855 			break;
4856 		default:
4857 			break;
4858 		} /* switch() */
4859 	} while (ch != EOF);
4860 
4861 	return 0;
4862 } /* dns_resconf_loadfile() */
4863 
4864 
dns_resconf_loadpath(struct dns_resolv_conf * resconf,const char * path)4865 int dns_resconf_loadpath(struct dns_resolv_conf *resconf, const char *path) {
4866 	FILE *fp;
4867 	int error;
4868 
4869 	if (!(fp = dns_fopen(path, "rt", &error)))
4870 		return error;
4871 
4872 	error = dns_resconf_loadfile(resconf, fp);
4873 
4874 	fclose(fp);
4875 
4876 	return error;
4877 } /* dns_resconf_loadpath() */
4878 
4879 
4880 struct dns_anyconf {
4881 	char *token[16];
4882 	unsigned count;
4883 	char buffer[1024], *tp, *cp;
4884 }; /* struct dns_anyconf */
4885 
4886 
dns_anyconf_reset(struct dns_anyconf * cf)4887 static void dns_anyconf_reset(struct dns_anyconf *cf) {
4888 	cf->count = 0;
4889 	cf->tp = cf->cp = cf->buffer;
4890 } /* dns_anyconf_reset() */
4891 
4892 
dns_anyconf_push(struct dns_anyconf * cf)4893 static int dns_anyconf_push(struct dns_anyconf *cf) {
4894 	if (!(cf->cp < endof(cf->buffer) && cf->count < lengthof(cf->token)))
4895 		return ENOMEM;
4896 
4897 	*cf->cp++ = '\0';
4898 	cf->token[cf->count++] = cf->tp;
4899 	cf->tp = cf->cp;
4900 
4901 	return 0;
4902 } /* dns_anyconf_push() */
4903 
4904 
dns_anyconf_pop(struct dns_anyconf * cf)4905 static void dns_anyconf_pop(struct dns_anyconf *cf) {
4906 	if (cf->count > 0) {
4907 		--cf->count;
4908 		cf->tp = cf->cp = cf->token[cf->count];
4909 		cf->token[cf->count] = 0;
4910 	}
4911 } /* dns_anyconf_pop() */
4912 
4913 
dns_anyconf_addc(struct dns_anyconf * cf,int ch)4914 static int dns_anyconf_addc(struct dns_anyconf *cf, int ch) {
4915 	if (!(cf->cp < endof(cf->buffer)))
4916 		return ENOMEM;
4917 
4918 	*cf->cp++ = ch;
4919 
4920 	return 0;
4921 } /* dns_anyconf_addc() */
4922 
4923 
dns_anyconf_match(const char * pat,int mc)4924 static _Bool dns_anyconf_match(const char *pat, int mc) {
4925 	_Bool match;
4926 	int pc;
4927 
4928 	if (*pat == '^') {
4929 		match = 0;
4930 		++pat;
4931 	} else {
4932 		match = 1;
4933 	}
4934 
4935 	while ((pc = *(const unsigned char *)pat++)) {
4936 		switch (pc) {
4937 		case '%':
4938 			if (!(pc = *(const unsigned char *)pat++))
4939 				return !match;
4940 
4941 			switch (pc) {
4942 			case 'a':
4943 				if (dns_isalpha(mc))
4944 					return match;
4945 				break;
4946 			case 'd':
4947 				if (dns_isdigit(mc))
4948 					return match;
4949 				break;
4950 			case 'w':
4951 				if (dns_isalnum(mc))
4952 					return match;
4953 				break;
4954 			case 's':
4955 				if (dns_isspace(mc))
4956 					return match;
4957 				break;
4958 			default:
4959 				if (mc == pc)
4960 					return match;
4961 				break;
4962 			} /* switch() */
4963 
4964 			break;
4965 		default:
4966 			if (mc == pc)
4967 				return match;
4968 			break;
4969 		} /* switch() */
4970 	} /* while() */
4971 
4972 	return !match;
4973 } /* dns_anyconf_match() */
4974 
4975 
dns_anyconf_peek(FILE * fp)4976 static int dns_anyconf_peek(FILE *fp) {
4977 	int ch;
4978 	ch = getc(fp);
4979 	ungetc(ch, fp);
4980 	return ch;
4981 } /* dns_anyconf_peek() */
4982 
4983 
dns_anyconf_skip(const char * pat,FILE * fp)4984 static size_t dns_anyconf_skip(const char *pat, FILE *fp) {
4985 	size_t count = 0;
4986 	int ch;
4987 
4988 	while (EOF != (ch = getc(fp))) {
4989 		if (dns_anyconf_match(pat, ch)) {
4990 			count++;
4991 			continue;
4992 		}
4993 
4994 		ungetc(ch, fp);
4995 
4996 		break;
4997 	}
4998 
4999 	return count;
5000 } /* dns_anyconf_skip() */
5001 
5002 
dns_anyconf_scan(struct dns_anyconf * cf,const char * pat,FILE * fp,int * error)5003 static size_t dns_anyconf_scan(struct dns_anyconf *cf, const char *pat, FILE *fp, int *error) {
5004 	size_t len;
5005 	int ch;
5006 
5007 	while (EOF != (ch = getc(fp))) {
5008 		if (dns_anyconf_match(pat, ch)) {
5009 			if ((*error = dns_anyconf_addc(cf, ch)))
5010 				return 0;
5011 
5012 			continue;
5013 		} else {
5014 			ungetc(ch, fp);
5015 
5016 			break;
5017 		}
5018 	}
5019 
5020 	if ((len = cf->cp - cf->tp)) {
5021 		if ((*error = dns_anyconf_push(cf)))
5022 			return 0;
5023 
5024 		return len;
5025 	} else {
5026 		*error = 0;
5027 
5028 		return 0;
5029 	}
5030 } /* dns_anyconf_scan() */
5031 
5032 
dns_anyconf_dump(struct dns_anyconf * cf,FILE * fp)5033 DNS_NOTUSED static void dns_anyconf_dump(struct dns_anyconf *cf, FILE *fp) {
5034 	unsigned i;
5035 
5036 	fprintf(fp, "tokens:");
5037 
5038 	for (i = 0; i < cf->count; i++) {
5039 		fprintf(fp, " %s", cf->token[i]);
5040 	}
5041 
5042 	fputc('\n', fp);
5043 } /* dns_anyconf_dump() */
5044 
5045 
5046 enum dns_nssconf_keyword {
5047 	DNS_NSSCONF_INVALID = 0,
5048 	DNS_NSSCONF_HOSTS   = 1,
5049 	DNS_NSSCONF_SUCCESS,
5050 	DNS_NSSCONF_NOTFOUND,
5051 	DNS_NSSCONF_UNAVAIL,
5052 	DNS_NSSCONF_TRYAGAIN,
5053 	DNS_NSSCONF_CONTINUE,
5054 	DNS_NSSCONF_RETURN,
5055 	DNS_NSSCONF_FILES,
5056 	DNS_NSSCONF_DNS,
5057 	DNS_NSSCONF_MDNS,
5058 
5059 	DNS_NSSCONF_LAST,
5060 }; /* enum dns_nssconf_keyword */
5061 
dns_nssconf_keyword(const char * word)5062 static enum dns_nssconf_keyword dns_nssconf_keyword(const char *word) {
5063 	static const char *list[] = {
5064 		[DNS_NSSCONF_HOSTS]    = "hosts",
5065 		[DNS_NSSCONF_SUCCESS]  = "success",
5066 		[DNS_NSSCONF_NOTFOUND] = "notfound",
5067 		[DNS_NSSCONF_UNAVAIL]  = "unavail",
5068 		[DNS_NSSCONF_TRYAGAIN] = "tryagain",
5069 		[DNS_NSSCONF_CONTINUE] = "continue",
5070 		[DNS_NSSCONF_RETURN]   = "return",
5071 		[DNS_NSSCONF_FILES]    = "files",
5072 		[DNS_NSSCONF_DNS]      = "dns",
5073 		[DNS_NSSCONF_MDNS]     = "mdns",
5074 	};
5075 	unsigned i;
5076 
5077 	for (i = 1; i < lengthof(list); i++) {
5078 		if (list[i] && 0 == strcasecmp(list[i], word))
5079 			return i;
5080 	}
5081 
5082 	return DNS_NSSCONF_INVALID;
5083 } /* dns_nssconf_keyword() */
5084 
5085 
dns_nssconf_c2k(int ch)5086 static enum dns_nssconf_keyword dns_nssconf_c2k(int ch) {
5087 	static const char map[] = {
5088 		['S'] = DNS_NSSCONF_SUCCESS,
5089 		['N'] = DNS_NSSCONF_NOTFOUND,
5090 		['U'] = DNS_NSSCONF_UNAVAIL,
5091 		['T'] = DNS_NSSCONF_TRYAGAIN,
5092 		['C'] = DNS_NSSCONF_CONTINUE,
5093 		['R'] = DNS_NSSCONF_RETURN,
5094 		['f'] = DNS_NSSCONF_FILES,
5095 		['F'] = DNS_NSSCONF_FILES,
5096 		['d'] = DNS_NSSCONF_DNS,
5097 		['D'] = DNS_NSSCONF_DNS,
5098 		['b'] = DNS_NSSCONF_DNS,
5099 		['B'] = DNS_NSSCONF_DNS,
5100 		['m'] = DNS_NSSCONF_MDNS,
5101 		['M'] = DNS_NSSCONF_MDNS,
5102 	};
5103 
5104 	return (ch >= 0 && ch < (int)lengthof(map))? map[ch] : DNS_NSSCONF_INVALID;
5105 } /* dns_nssconf_c2k() */
5106 
5107 
5108 DNS_PRAGMA_PUSH
5109 DNS_PRAGMA_QUIET
5110 
dns_nssconf_k2c(int k)5111 static int dns_nssconf_k2c(int k) {
5112 	static const char map[DNS_NSSCONF_LAST] = {
5113 		[DNS_NSSCONF_SUCCESS]  = 'S',
5114 		[DNS_NSSCONF_NOTFOUND] = 'N',
5115 		[DNS_NSSCONF_UNAVAIL]  = 'U',
5116 		[DNS_NSSCONF_TRYAGAIN] = 'T',
5117 		[DNS_NSSCONF_CONTINUE] = 'C',
5118 		[DNS_NSSCONF_RETURN]   = 'R',
5119 		[DNS_NSSCONF_FILES]    = 'f',
5120 		[DNS_NSSCONF_DNS]      = 'b',
5121 		[DNS_NSSCONF_MDNS]     = 'm',
5122 	};
5123 
5124 	return (k >= 0 && k < (int)lengthof(map))? (map[k]? map[k] : '?') : '?';
5125 } /* dns_nssconf_k2c() */
5126 
dns_nssconf_k2s(int k)5127 static const char *dns_nssconf_k2s(int k) {
5128 	static const char *const map[DNS_NSSCONF_LAST] = {
5129 		[DNS_NSSCONF_SUCCESS]  = "SUCCESS",
5130 		[DNS_NSSCONF_NOTFOUND] = "NOTFOUND",
5131 		[DNS_NSSCONF_UNAVAIL]  = "UNAVAIL",
5132 		[DNS_NSSCONF_TRYAGAIN] = "TRYAGAIN",
5133 		[DNS_NSSCONF_CONTINUE] = "continue",
5134 		[DNS_NSSCONF_RETURN]   = "return",
5135 		[DNS_NSSCONF_FILES]    = "files",
5136 		[DNS_NSSCONF_DNS]      = "dns",
5137 		[DNS_NSSCONF_MDNS]     = "mdns",
5138 	};
5139 
5140 	return (k >= 0 && k < (int)lengthof(map))? (map[k]? map[k] : "") : "";
5141 } /* dns_nssconf_k2s() */
5142 
5143 DNS_PRAGMA_POP
5144 
5145 
dns_nssconf_loadfile(struct dns_resolv_conf * resconf,FILE * fp)5146 int dns_nssconf_loadfile(struct dns_resolv_conf *resconf, FILE *fp) {
5147 	enum dns_nssconf_keyword source, status, action;
5148 	char lookup[sizeof resconf->lookup] = "", *lp;
5149 	struct dns_anyconf cf;
5150 	size_t i;
5151 	int error;
5152 
5153 	while (!feof(fp) && !ferror(fp)) {
5154 		dns_anyconf_reset(&cf);
5155 
5156 		dns_anyconf_skip("%s", fp);
5157 
5158 		if (!dns_anyconf_scan(&cf, "%w_", fp, &error))
5159 			goto nextent;
5160 
5161 		if (DNS_NSSCONF_HOSTS != dns_nssconf_keyword(cf.token[0]))
5162 			goto nextent;
5163 
5164 		dns_anyconf_pop(&cf);
5165 
5166 		if (!dns_anyconf_skip(": \t", fp))
5167 			goto nextent;
5168 
5169 		*(lp = lookup) = '\0';
5170 
5171 		while (dns_anyconf_scan(&cf, "%w_", fp, &error)) {
5172 			dns_anyconf_skip(" \t", fp);
5173 
5174 			if ('[' == dns_anyconf_peek(fp)) {
5175 				dns_anyconf_skip("[! \t", fp);
5176 
5177 				while (dns_anyconf_scan(&cf, "%w_", fp, &error)) {
5178 					dns_anyconf_skip("= \t", fp);
5179 					if (!dns_anyconf_scan(&cf, "%w_", fp, &error)) {
5180 						dns_anyconf_pop(&cf); /* discard status */
5181 						dns_anyconf_skip("^#;]\n", fp); /* skip to end of criteria */
5182 						break;
5183 					}
5184 					dns_anyconf_skip(" \t", fp);
5185 				}
5186 
5187 				dns_anyconf_skip("] \t", fp);
5188 			}
5189 
5190 			if ((size_t)(endof(lookup) - lp) < cf.count + 1) /* +1 for '\0' */
5191 				goto nextsrc;
5192 
5193 			source = dns_nssconf_keyword(cf.token[0]);
5194 
5195 			switch (source) {
5196 			case DNS_NSSCONF_DNS:
5197 			case DNS_NSSCONF_MDNS:
5198 			case DNS_NSSCONF_FILES:
5199 				*lp++ = dns_nssconf_k2c(source);
5200 				break;
5201 			default:
5202 				goto nextsrc;
5203 			}
5204 
5205 			for (i = 1; i + 1 < cf.count; i += 2) {
5206 				status = dns_nssconf_keyword(cf.token[i]);
5207 				action = dns_nssconf_keyword(cf.token[i + 1]);
5208 
5209 				switch (status) {
5210 				case DNS_NSSCONF_SUCCESS:
5211 				case DNS_NSSCONF_NOTFOUND:
5212 				case DNS_NSSCONF_UNAVAIL:
5213 				case DNS_NSSCONF_TRYAGAIN:
5214 					*lp++ = dns_nssconf_k2c(status);
5215 					break;
5216 				default:
5217 					continue;
5218 				}
5219 
5220 				switch (action) {
5221 				case DNS_NSSCONF_CONTINUE:
5222 				case DNS_NSSCONF_RETURN:
5223 					break;
5224 				default:
5225 					action = (status == DNS_NSSCONF_SUCCESS)
5226 					       ? DNS_NSSCONF_RETURN
5227 					       : DNS_NSSCONF_CONTINUE;
5228 					break;
5229 				}
5230 
5231 				*lp++ = dns_nssconf_k2c(action);
5232 			}
5233 nextsrc:
5234 			*lp = '\0';
5235 			dns_anyconf_reset(&cf);
5236 		}
5237 nextent:
5238 		dns_anyconf_skip("^\n", fp);
5239 	}
5240 
5241 	if (*lookup)
5242 		strncpy(resconf->lookup, lookup, sizeof resconf->lookup);
5243 
5244 	return 0;
5245 } /* dns_nssconf_loadfile() */
5246 
5247 
dns_nssconf_loadpath(struct dns_resolv_conf * resconf,const char * path)5248 int dns_nssconf_loadpath(struct dns_resolv_conf *resconf, const char *path) {
5249 	FILE *fp;
5250 	int error;
5251 
5252 	if (!(fp = dns_fopen(path, "rt", &error)))
5253 		return error;
5254 
5255 	error = dns_nssconf_loadfile(resconf, fp);
5256 
5257 	fclose(fp);
5258 
5259 	return error;
5260 } /* dns_nssconf_loadpath() */
5261 
5262 
5263 struct dns_nssconf_source {
5264 	enum dns_nssconf_keyword source, success, notfound, unavail, tryagain;
5265 }; /* struct dns_nssconf_source */
5266 
5267 typedef unsigned dns_nssconf_i;
5268 
dns_nssconf_peek(const struct dns_resolv_conf * resconf,dns_nssconf_i state)5269 static inline int dns_nssconf_peek(const struct dns_resolv_conf *resconf, dns_nssconf_i state) {
5270 	return (state < lengthof(resconf->lookup) && resconf->lookup[state])? resconf->lookup[state] : 0;
5271 } /* dns_nssconf_peek() */
5272 
dns_nssconf_next(struct dns_nssconf_source * src,const struct dns_resolv_conf * resconf,dns_nssconf_i * state)5273 static _Bool dns_nssconf_next(struct dns_nssconf_source *src, const struct dns_resolv_conf *resconf, dns_nssconf_i *state) {
5274 	int source, status, action;
5275 
5276 	src->source = DNS_NSSCONF_INVALID;
5277 	src->success = DNS_NSSCONF_RETURN;
5278 	src->notfound = DNS_NSSCONF_CONTINUE;
5279 	src->unavail = DNS_NSSCONF_CONTINUE;
5280 	src->tryagain = DNS_NSSCONF_CONTINUE;
5281 
5282 	while ((source = dns_nssconf_peek(resconf, *state))) {
5283 		source = dns_nssconf_c2k(source);
5284 		++*state;
5285 
5286 		switch (source) {
5287 		case DNS_NSSCONF_FILES:
5288 		case DNS_NSSCONF_DNS:
5289 		case DNS_NSSCONF_MDNS:
5290 			src->source = source;
5291 			break;
5292 		default:
5293 			continue;
5294 		}
5295 
5296 		while ((status = dns_nssconf_peek(resconf, *state)) && (action = dns_nssconf_peek(resconf, *state + 1))) {
5297 			status = dns_nssconf_c2k(status);
5298 			action = dns_nssconf_c2k(action);
5299 
5300 			switch (action) {
5301 			case DNS_NSSCONF_RETURN:
5302 			case DNS_NSSCONF_CONTINUE:
5303 				break;
5304 			default:
5305 				goto done;
5306 			}
5307 
5308 			switch (status) {
5309 			case DNS_NSSCONF_SUCCESS:
5310 				src->success = action;
5311 				break;
5312 			case DNS_NSSCONF_NOTFOUND:
5313 				src->notfound = action;
5314 				break;
5315 			case DNS_NSSCONF_UNAVAIL:
5316 				src->unavail = action;
5317 				break;
5318 			case DNS_NSSCONF_TRYAGAIN:
5319 				src->tryagain = action;
5320 				break;
5321 			default:
5322 				goto done;
5323 			}
5324 
5325 			*state += 2;
5326 		}
5327 
5328 		break;
5329 	}
5330 done:
5331 	return src->source != DNS_NSSCONF_INVALID;
5332 } /* dns_nssconf_next() */
5333 
5334 
dns_nssconf_dump_status(int status,int action,unsigned * count,FILE * fp)5335 static int dns_nssconf_dump_status(int status, int action, unsigned *count, FILE *fp) {
5336 	switch (status) {
5337 	case DNS_NSSCONF_SUCCESS:
5338 		if (action == DNS_NSSCONF_RETURN)
5339 			return 0;
5340 		break;
5341 	default:
5342 		if (action == DNS_NSSCONF_CONTINUE)
5343 			return 0;
5344 		break;
5345 	}
5346 
5347 	fputc(' ', fp);
5348 
5349 	if (!*count)
5350 		fputc('[', fp);
5351 
5352 	fprintf(fp, "%s=%s", dns_nssconf_k2s(status), dns_nssconf_k2s(action));
5353 
5354 	++*count;
5355 
5356 	return 0;
5357 } /* dns_nssconf_dump_status() */
5358 
5359 
dns_nssconf_dump(struct dns_resolv_conf * resconf,FILE * fp)5360 int dns_nssconf_dump(struct dns_resolv_conf *resconf, FILE *fp) {
5361 	struct dns_nssconf_source src;
5362 	dns_nssconf_i i = 0;
5363 
5364 	fputs("hosts:", fp);
5365 
5366 	while (dns_nssconf_next(&src, resconf, &i)) {
5367 		unsigned n = 0;
5368 
5369 		fprintf(fp, " %s", dns_nssconf_k2s(src.source));
5370 
5371 		dns_nssconf_dump_status(DNS_NSSCONF_SUCCESS, src.success, &n, fp);
5372 		dns_nssconf_dump_status(DNS_NSSCONF_NOTFOUND, src.notfound, &n, fp);
5373 		dns_nssconf_dump_status(DNS_NSSCONF_UNAVAIL, src.unavail, &n, fp);
5374 		dns_nssconf_dump_status(DNS_NSSCONF_TRYAGAIN, src.tryagain, &n, fp);
5375 
5376 		if (n)
5377 			fputc(']', fp);
5378 	}
5379 
5380 	fputc('\n', fp);
5381 
5382 	return 0;
5383 } /* dns_nssconf_dump() */
5384 
5385 
dns_resconf_setiface(struct dns_resolv_conf * resconf,const char * addr,unsigned short port)5386 int dns_resconf_setiface(struct dns_resolv_conf *resconf, const char *addr, unsigned short port) {
5387 	int af = (strchr(addr, ':'))? AF_INET6 : AF_INET;
5388 	int error;
5389 
5390 	if ((error = dns_pton(af, addr, dns_sa_addr(af, &resconf->iface, NULL))))
5391 		return error;
5392 
5393 	*dns_sa_port(af, &resconf->iface)	= htons(port);
5394 	resconf->iface.ss_family		= af;
5395 
5396 	return 0;
5397 } /* dns_resconf_setiface() */
5398 
5399 
5400 #define DNS_SM_RESTORE \
5401 	do { \
5402 		pc = 0xff & (*state >> 0); \
5403 		srchi = 0xff & (*state >> 8); \
5404 		ndots = 0xff & (*state >> 16); \
5405 	} while (0)
5406 
5407 #define DNS_SM_SAVE \
5408 	do { \
5409 		*state = ((0xff & pc) << 0) \
5410 		       | ((0xff & srchi) << 8) \
5411 		       | ((0xff & ndots) << 16); \
5412 	} while (0)
5413 
dns_resconf_search(void * dst,size_t lim,const void * qname,size_t qlen,struct dns_resolv_conf * resconf,dns_resconf_i_t * state)5414 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) {
5415 	unsigned pc, srchi, ndots, len;
5416 
5417 	DNS_SM_ENTER;
5418 
5419 	/* if FQDN then return as-is and finish */
5420 	if (dns_d_isanchored(qname, qlen)) {
5421 		len = dns_d_anchor(dst, lim, qname, qlen);
5422 		DNS_SM_YIELD(len);
5423 		DNS_SM_EXIT;
5424 	}
5425 
5426 	ndots = dns_d_ndots(qname, qlen);
5427 
5428 	if (ndots >= resconf->options.ndots) {
5429 		len = dns_d_anchor(dst, lim, qname, qlen);
5430 		DNS_SM_YIELD(len);
5431 	}
5432 
5433 	while (srchi < lengthof(resconf->search) && resconf->search[srchi][0]) {
5434 		struct dns_buf buf = DNS_B_INTO(dst, lim);
5435 		const char *dn = resconf->search[srchi++];
5436 
5437 		dns_b_put(&buf, qname, qlen);
5438 		dns_b_putc(&buf, '.');
5439 		dns_b_puts(&buf, dn);
5440 		if (!dns_d_isanchored(dn, strlen(dn)))
5441 			dns_b_putc(&buf, '.');
5442 		len = dns_b_strllen(&buf);
5443 		DNS_SM_YIELD(len);
5444 	}
5445 
5446 	if (ndots < resconf->options.ndots) {
5447 		len = dns_d_anchor(dst, lim, qname, qlen);
5448 		DNS_SM_YIELD(len);
5449 	}
5450 
5451 	DNS_SM_LEAVE;
5452 
5453 	return dns_strlcpy(dst, "", lim);
5454 } /* dns_resconf_search() */
5455 
5456 #undef DNS_SM_SAVE
5457 #undef DNS_SM_RESTORE
5458 
5459 
dns_resconf_dump(struct dns_resolv_conf * resconf,FILE * fp)5460 int dns_resconf_dump(struct dns_resolv_conf *resconf, FILE *fp) {
5461 	unsigned i;
5462 	int af;
5463 
5464 	for (i = 0; i < lengthof(resconf->nameserver) && (af = resconf->nameserver[i].ss_family) != AF_UNSPEC; i++) {
5465 		char addr[INET6_ADDRSTRLEN + 1]	= "[INVALID]";
5466 		unsigned short port;
5467 
5468 		dns_inet_ntop(af, dns_sa_addr(af, &resconf->nameserver[i], NULL), addr, sizeof addr);
5469 		port = ntohs(*dns_sa_port(af, &resconf->nameserver[i]));
5470 
5471 		if (port == 53)
5472 			fprintf(fp, "nameserver %s\n", addr);
5473 		else
5474 			fprintf(fp, "nameserver [%s]:%hu\n", addr, port);
5475 	}
5476 
5477 
5478 	fprintf(fp, "search");
5479 
5480 	for (i = 0; i < lengthof(resconf->search) && resconf->search[i][0]; i++)
5481 		fprintf(fp, " %s", resconf->search[i]);
5482 
5483 	fputc('\n', fp);
5484 
5485 
5486 	fputs("; ", fp);
5487 	dns_nssconf_dump(resconf, fp);
5488 
5489 	fprintf(fp, "lookup");
5490 
5491 	for (i = 0; i < lengthof(resconf->lookup) && resconf->lookup[i]; i++) {
5492 		switch (resconf->lookup[i]) {
5493 		case 'b':
5494 			fprintf(fp, " bind"); break;
5495 		case 'f':
5496 			fprintf(fp, " file"); break;
5497 		case 'c':
5498 			fprintf(fp, " cache"); break;
5499 		}
5500 	}
5501 
5502 	fputc('\n', fp);
5503 
5504 
5505 	fprintf(fp, "options ndots:%u timeout:%u attempts:%u", resconf->options.ndots, resconf->options.timeout, resconf->options.attempts);
5506 
5507 	if (resconf->options.edns0)
5508 		fprintf(fp, " edns0");
5509 	if (resconf->options.rotate)
5510 		fprintf(fp, " rotate");
5511 	if (resconf->options.recurse)
5512 		fprintf(fp, " recurse");
5513 	if (resconf->options.smart)
5514 		fprintf(fp, " smart");
5515 
5516 	switch (resconf->options.tcp) {
5517 	case DNS_RESCONF_TCP_ENABLE:
5518 		break;
5519 	case DNS_RESCONF_TCP_ONLY:
5520 		fprintf(fp, " tcp");
5521 		break;
5522 	case DNS_RESCONF_TCP_DISABLE:
5523 		fprintf(fp, " tcp:disable");
5524 		break;
5525 	}
5526 
5527 	fputc('\n', fp);
5528 
5529 
5530 	if ((af = resconf->iface.ss_family) != AF_UNSPEC) {
5531 		char addr[INET6_ADDRSTRLEN + 1]	= "[INVALID]";
5532 
5533 		dns_inet_ntop(af, dns_sa_addr(af, &resconf->iface, NULL), addr, sizeof addr);
5534 
5535 		fprintf(fp, "interface %s %hu\n", addr, ntohs(*dns_sa_port(af, &resconf->iface)));
5536 	}
5537 
5538 	return 0;
5539 } /* dns_resconf_dump() */
5540 
5541 
5542 /*
5543  * H I N T  S E R V E R  R O U T I N E S
5544  *
5545  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5546 
5547 struct dns_hints_soa {
5548 	unsigned char zone[DNS_D_MAXNAME + 1];
5549 
5550 	struct {
5551 		struct sockaddr_storage ss;
5552 		unsigned priority;
5553 	} addrs[16];
5554 
5555 	unsigned count;
5556 
5557 	struct dns_hints_soa *next;
5558 }; /* struct dns_hints_soa */
5559 
5560 
5561 struct dns_hints {
5562 	dns_atomic_t refcount;
5563 
5564 	struct dns_hints_soa *head;
5565 }; /* struct dns_hints */
5566 
5567 
dns_hints_open(struct dns_resolv_conf * resconf,int * error)5568 struct dns_hints *dns_hints_open(struct dns_resolv_conf *resconf, int *error) {
5569 	static const struct dns_hints H_initializer;
5570 	struct dns_hints *H;
5571 
5572 	(void)resconf;
5573 
5574 	if (!(H = malloc(sizeof *H)))
5575 		goto syerr;
5576 
5577 	*H	= H_initializer;
5578 
5579 	dns_hints_acquire(H);
5580 
5581 	return H;
5582 syerr:
5583 	*error	= dns_syerr();
5584 
5585 	free(H);
5586 
5587 	return 0;
5588 } /* dns_hints_open() */
5589 
5590 
dns_hints_close(struct dns_hints * H)5591 void dns_hints_close(struct dns_hints *H) {
5592 	struct dns_hints_soa *soa, *nxt;
5593 
5594 	if (!H || 1 != dns_hints_release(H))
5595 		return /* void */;
5596 
5597 	for (soa = H->head; soa; soa = nxt) {
5598 		nxt	= soa->next;
5599 
5600 		free(soa);
5601 	}
5602 
5603 	free(H);
5604 
5605 	return /* void */;
5606 } /* dns_hints_close() */
5607 
5608 
dns_hints_acquire(struct dns_hints * H)5609 dns_refcount_t dns_hints_acquire(struct dns_hints *H) {
5610 	return dns_atomic_fetch_add(&H->refcount);
5611 } /* dns_hints_acquire() */
5612 
5613 
dns_hints_release(struct dns_hints * H)5614 dns_refcount_t dns_hints_release(struct dns_hints *H) {
5615 	return dns_atomic_fetch_sub(&H->refcount);
5616 } /* dns_hints_release() */
5617 
5618 
dns_hints_mortal(struct dns_hints * hints)5619 struct dns_hints *dns_hints_mortal(struct dns_hints *hints) {
5620 	if (hints)
5621 		dns_hints_release(hints);
5622 
5623 	return hints;
5624 } /* dns_hints_mortal() */
5625 
5626 
dns_hints_local(struct dns_resolv_conf * resconf,int * error_)5627 struct dns_hints *dns_hints_local(struct dns_resolv_conf *resconf, int *error_) {
5628 	struct dns_hints *hints		= 0;
5629 	int error;
5630 
5631 	if (resconf)
5632 		dns_resconf_acquire(resconf);
5633 	else if (!(resconf = dns_resconf_local(&error)))
5634 		goto error;
5635 
5636 	if (!(hints = dns_hints_open(resconf, &error)))
5637 		goto error;
5638 
5639 	error	= 0;
5640 
5641 	if (0 == dns_hints_insert_resconf(hints, ".", resconf, &error) && error)
5642 		goto error;
5643 
5644 	dns_resconf_close(resconf);
5645 
5646 	return hints;
5647 error:
5648 	*error_	= error;
5649 
5650 	dns_resconf_close(resconf);
5651 	dns_hints_close(hints);
5652 
5653 	return 0;
5654 } /* dns_hints_local() */
5655 
5656 
dns_hints_root(struct dns_resolv_conf * resconf,int * error_)5657 struct dns_hints *dns_hints_root(struct dns_resolv_conf *resconf, int *error_) {
5658 	static const struct {
5659 		int af;
5660 		char addr[INET6_ADDRSTRLEN];
5661 	} root_hints[] = {
5662 		{ AF_INET,	"198.41.0.4"		},	/* A.ROOT-SERVERS.NET. */
5663 		{ AF_INET6,	"2001:503:ba3e::2:30"	},	/* A.ROOT-SERVERS.NET. */
5664 		{ AF_INET,	"192.228.79.201"	},	/* B.ROOT-SERVERS.NET. */
5665 		{ AF_INET6,	"2001:500:84::b"	},	/* B.ROOT-SERVERS.NET. */
5666 		{ AF_INET,	"192.33.4.12"		},	/* C.ROOT-SERVERS.NET. */
5667 		{ AF_INET6,	"2001:500:2::c"		},	/* C.ROOT-SERVERS.NET. */
5668 		{ AF_INET,	"199.7.91.13"		},	/* D.ROOT-SERVERS.NET. */
5669 		{ AF_INET6,	"2001:500:2d::d"	},	/* D.ROOT-SERVERS.NET. */
5670 		{ AF_INET,	"192.203.230.10"	},	/* E.ROOT-SERVERS.NET. */
5671 		{ AF_INET,	"192.5.5.241"		},	/* F.ROOT-SERVERS.NET. */
5672 		{ AF_INET6,	"2001:500:2f::f"	},	/* F.ROOT-SERVERS.NET. */
5673 		{ AF_INET,	"192.112.36.4"		},	/* G.ROOT-SERVERS.NET. */
5674 		{ AF_INET,	"128.63.2.53"		},	/* H.ROOT-SERVERS.NET. */
5675 		{ AF_INET6,	"2001:500:1::803f:235"	},	/* H.ROOT-SERVERS.NET. */
5676 		{ AF_INET,	"192.36.148.17"		},	/* I.ROOT-SERVERS.NET. */
5677 		{ AF_INET6,	"2001:7FE::53"		},	/* I.ROOT-SERVERS.NET. */
5678 		{ AF_INET,	"192.58.128.30"		},	/* J.ROOT-SERVERS.NET. */
5679 		{ AF_INET6,	"2001:503:c27::2:30"	},	/* J.ROOT-SERVERS.NET. */
5680 		{ AF_INET,	"193.0.14.129"		},	/* K.ROOT-SERVERS.NET. */
5681 		{ AF_INET6,	"2001:7FD::1"		},	/* K.ROOT-SERVERS.NET. */
5682 		{ AF_INET,	"199.7.83.42"		},	/* L.ROOT-SERVERS.NET. */
5683 		{ AF_INET6,	"2001:500:3::42"	},	/* L.ROOT-SERVERS.NET. */
5684 		{ AF_INET,	"202.12.27.33"		},	/* M.ROOT-SERVERS.NET. */
5685 		{ AF_INET6,	"2001:DC3::35"		},	/* M.ROOT-SERVERS.NET. */
5686 	};
5687 	struct dns_hints *hints		= 0;
5688 	struct sockaddr_storage ss;
5689 	unsigned i;
5690 	int error, af;
5691 
5692 	if (!(hints = dns_hints_open(resconf, &error)))
5693 		goto error;
5694 
5695 	for (i = 0; i < lengthof(root_hints); i++) {
5696 		af	= root_hints[i].af;
5697 
5698 		if ((error = dns_pton(af, root_hints[i].addr, dns_sa_addr(af, &ss, NULL))))
5699 			goto error;
5700 
5701 		*dns_sa_port(af, &ss)	= htons(53);
5702 		ss.ss_family		= af;
5703 
5704 		if ((error = dns_hints_insert(hints, ".", (struct sockaddr *)&ss, 1)))
5705 			goto error;
5706 	}
5707 
5708 	return hints;
5709 error:
5710 	*error_	= error;
5711 
5712 	dns_hints_close(hints);
5713 
5714 	return 0;
5715 } /* dns_hints_root() */
5716 
5717 
dns_hints_fetch(struct dns_hints * H,const char * zone)5718 static struct dns_hints_soa *dns_hints_fetch(struct dns_hints *H, const char *zone) {
5719 	struct dns_hints_soa *soa;
5720 
5721 	for (soa = H->head; soa; soa = soa->next) {
5722 		if (0 == strcasecmp(zone, (char *)soa->zone))
5723 			return soa;
5724 	}
5725 
5726 	return 0;
5727 } /* dns_hints_fetch() */
5728 
5729 
dns_hints_insert(struct dns_hints * H,const char * zone,const struct sockaddr * sa,unsigned priority)5730 int dns_hints_insert(struct dns_hints *H, const char *zone, const struct sockaddr *sa, unsigned priority) {
5731 	static const struct dns_hints_soa soa_initializer;
5732 	struct dns_hints_soa *soa;
5733 	unsigned i;
5734 
5735 	if (!(soa = dns_hints_fetch(H, zone))) {
5736 		if (!(soa = malloc(sizeof *soa)))
5737 			return dns_syerr();
5738 		*soa = soa_initializer;
5739 		dns_strlcpy((char *)soa->zone, zone, sizeof soa->zone);
5740 
5741 		soa->next = H->head;
5742 		H->head = soa;
5743 	}
5744 
5745 	i = soa->count % lengthof(soa->addrs);
5746 
5747 	memcpy(&soa->addrs[i].ss, sa, dns_sa_len(sa));
5748 
5749 	soa->addrs[i].priority = DNS_PP_MAX(1, priority);
5750 
5751 	if (soa->count < lengthof(soa->addrs))
5752 		soa->count++;
5753 
5754 	return 0;
5755 } /* dns_hints_insert() */
5756 
5757 
dns_hints_isinaddr_any(const void * sa)5758 static _Bool dns_hints_isinaddr_any(const void *sa) {
5759 	struct in_addr *addr;
5760 
5761 	if (dns_sa_family(sa) != AF_INET)
5762 		return 0;
5763 
5764 	addr = dns_sa_addr(AF_INET, sa, NULL);
5765 	return addr->s_addr == htonl(INADDR_ANY);
5766 }
5767 
dns_hints_insert_resconf(struct dns_hints * H,const char * zone,const struct dns_resolv_conf * resconf,int * error_)5768 unsigned dns_hints_insert_resconf(struct dns_hints *H, const char *zone, const struct dns_resolv_conf *resconf, int *error_) {
5769 	unsigned i, n, p;
5770 	int error;
5771 
5772 	for (i = 0, n = 0, p = 1; i < lengthof(resconf->nameserver) && resconf->nameserver[i].ss_family != AF_UNSPEC; i++, n++) {
5773 		union { struct sockaddr_in sin; } tmp;
5774 		struct sockaddr *ns;
5775 
5776 		/*
5777 		 * dns_resconf_open initializes nameserver[0] to INADDR_ANY.
5778 		 *
5779 		 * Traditionally the semantics of 0.0.0.0 meant the default
5780 		 * interface, which evolved to mean the loopback interface.
5781 		 * See comment block preceding resolv/res_init.c:res_init in
5782 		 * glibc 2.23. As of 2.23, glibc no longer translates
5783 		 * 0.0.0.0 despite the code comment, but it does default to
5784 		 * 127.0.0.1 when no nameservers are present.
5785 		 *
5786 		 * BIND9 as of 9.10.3 still translates 0.0.0.0 to 127.0.0.1.
5787 		 * See lib/lwres/lwconfig.c:lwres_create_addr and the
5788 		 * convert_zero flag. 127.0.0.1 is also the default when no
5789 		 * nameservers are present.
5790 		 */
5791 		if (dns_hints_isinaddr_any(&resconf->nameserver[i])) {
5792 			memcpy(&tmp.sin, &resconf->nameserver[i], sizeof tmp.sin);
5793 			tmp.sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
5794 			ns = (struct sockaddr *)&tmp.sin;
5795 		} else {
5796 			ns = (struct sockaddr *)&resconf->nameserver[i];
5797 		}
5798 
5799 		if ((error = dns_hints_insert(H, zone, ns, p)))
5800 			goto error;
5801 
5802 		p += !resconf->options.rotate;
5803 	}
5804 
5805 	return n;
5806 error:
5807 	*error_ = error;
5808 
5809 	return n;
5810 } /* dns_hints_insert_resconf() */
5811 
5812 
dns_hints_i_cmp(unsigned a,unsigned b,struct dns_hints_i * i,struct dns_hints_soa * soa)5813 static int dns_hints_i_cmp(unsigned a, unsigned b, struct dns_hints_i *i, struct dns_hints_soa *soa) {
5814 	int cmp;
5815 
5816 	if ((cmp = soa->addrs[a].priority - soa->addrs[b].priority))
5817 		return cmp;
5818 
5819 	return dns_k_shuffle16(a, i->state.seed) - dns_k_shuffle16(b, i->state.seed);
5820 } /* dns_hints_i_cmp() */
5821 
5822 
dns_hints_i_start(struct dns_hints_i * i,struct dns_hints_soa * soa)5823 static unsigned dns_hints_i_start(struct dns_hints_i *i, struct dns_hints_soa *soa) {
5824 	unsigned p0, p;
5825 
5826 	p0	= 0;
5827 
5828 	for (p = 1; p < soa->count; p++) {
5829 		if (dns_hints_i_cmp(p, p0, i, soa) < 0)
5830 			p0	= p;
5831 	}
5832 
5833 	return p0;
5834 } /* dns_hints_i_start() */
5835 
5836 
dns_hints_i_skip(unsigned p0,struct dns_hints_i * i,struct dns_hints_soa * soa)5837 static unsigned dns_hints_i_skip(unsigned p0, struct dns_hints_i *i, struct dns_hints_soa *soa) {
5838 	unsigned pZ, p;
5839 
5840 	for (pZ = 0; pZ < soa->count; pZ++) {
5841 		if (dns_hints_i_cmp(pZ, p0, i, soa) > 0)
5842 			goto cont;
5843 	}
5844 
5845 	return soa->count;
5846 cont:
5847 	for (p = pZ + 1; p < soa->count; p++) {
5848 		if (dns_hints_i_cmp(p, p0, i, soa) <= 0)
5849 			continue;
5850 
5851 		if (dns_hints_i_cmp(p, pZ, i, soa) >= 0)
5852 			continue;
5853 
5854 		pZ	= p;
5855 	}
5856 
5857 
5858 	return pZ;
5859 } /* dns_hints_i_skip() */
5860 
5861 
dns_hints_i_init(struct dns_hints_i * i,struct dns_hints * hints)5862 static struct dns_hints_i *dns_hints_i_init(struct dns_hints_i *i, struct dns_hints *hints) {
5863 	static const struct dns_hints_i i_initializer;
5864 	struct dns_hints_soa *soa;
5865 
5866 	i->state	= i_initializer.state;
5867 
5868 	do {
5869 		i->state.seed	= dns_random();
5870 	} while (0 == i->state.seed);
5871 
5872 	if ((soa = dns_hints_fetch(hints, i->zone))) {
5873 		i->state.next	= dns_hints_i_start(i, soa);
5874 	}
5875 
5876 	return i;
5877 } /* dns_hints_i_init() */
5878 
5879 
dns_hints_grep(struct sockaddr ** sa,socklen_t * sa_len,unsigned lim,struct dns_hints_i * i,struct dns_hints * H)5880 unsigned dns_hints_grep(struct sockaddr **sa, socklen_t *sa_len, unsigned lim, struct dns_hints_i *i, struct dns_hints *H) {
5881 	struct dns_hints_soa *soa;
5882 	unsigned n;
5883 
5884 	if (!(soa = dns_hints_fetch(H, i->zone)))
5885 		return 0;
5886 
5887 	n	= 0;
5888 
5889 	while (i->state.next < soa->count && n < lim) {
5890 		*sa	= (struct sockaddr *)&soa->addrs[i->state.next].ss;
5891 		*sa_len	= dns_sa_len(*sa);
5892 
5893 		sa++;
5894 		sa_len++;
5895 		n++;
5896 
5897 		i->state.next	= dns_hints_i_skip(i->state.next, i, soa);
5898 	}
5899 
5900 	return n;
5901 } /* dns_hints_grep() */
5902 
5903 
dns_hints_query(struct dns_hints * hints,struct dns_packet * Q,int * error_)5904 struct dns_packet *dns_hints_query(struct dns_hints *hints, struct dns_packet *Q, int *error_) {
5905 	struct dns_packet *A, *P;
5906 	struct dns_rr rr;
5907 	char zone[DNS_D_MAXNAME + 1];
5908 	size_t zlen;
5909 	struct dns_hints_i i;
5910 	struct sockaddr *sa;
5911 	socklen_t slen;
5912 	int error;
5913 
5914 	if (!dns_rr_grep(&rr, 1, dns_rr_i_new(Q, .section = DNS_S_QUESTION), Q, &error))
5915 		goto error;
5916 
5917 	if (!(zlen = dns_d_expand(zone, sizeof zone, rr.dn.p, Q, &error)))
5918 		goto error;
5919 	else if (zlen >= sizeof zone)
5920 		goto toolong;
5921 
5922 	P			= dns_p_new(512);
5923 	dns_header(P)->qr	= 1;
5924 
5925 	if ((error = dns_rr_copy(P, &rr, Q)))
5926 		goto error;
5927 
5928 	if ((error = dns_p_push(P, DNS_S_AUTHORITY, ".", strlen("."), DNS_T_NS, DNS_C_IN, 0, "hints.local.")))
5929 		goto error;
5930 
5931 	do {
5932 		i.zone	= zone;
5933 
5934 		dns_hints_i_init(&i, hints);
5935 
5936 		while (dns_hints_grep(&sa, &slen, 1, &i, hints)) {
5937 			int af		= sa->sa_family;
5938 			int rtype	= (af == AF_INET6)? DNS_T_AAAA : DNS_T_A;
5939 
5940 			if ((error = dns_p_push(P, DNS_S_ADDITIONAL, "hints.local.", strlen("hints.local."), rtype, DNS_C_IN, 0, dns_sa_addr(af, sa, NULL))))
5941 				goto error;
5942 		}
5943 	} while ((zlen = dns_d_cleave(zone, sizeof zone, zone, zlen)));
5944 
5945 	if (!(A = dns_p_copy(dns_p_make(P->end, &error), P)))
5946 		goto error;
5947 
5948 	return A;
5949 toolong:
5950 	error = DNS_EILLEGAL;
5951 error:
5952 	*error_	= error;
5953 
5954 	return 0;
5955 } /* dns_hints_query() */
5956 
5957 
5958 /** ugly hack to support specifying ports other than 53 in resolv.conf. */
dns_hints_port(struct dns_hints * hints,int af,void * addr)5959 static unsigned short dns_hints_port(struct dns_hints *hints, int af, void *addr) {
5960 	struct dns_hints_soa *soa;
5961 	void *addrsoa;
5962 	socklen_t addrlen;
5963 	unsigned short port;
5964 	unsigned i;
5965 
5966 	for (soa = hints->head; soa; soa = soa->next) {
5967 		for (i = 0; i < soa->count; i++) {
5968 			if (af != soa->addrs[i].ss.ss_family)
5969 				continue;
5970 
5971 			if (!(addrsoa = dns_sa_addr(af, &soa->addrs[i].ss, &addrlen)))
5972 				continue;
5973 
5974 			if (memcmp(addr, addrsoa, addrlen))
5975 				continue;
5976 
5977 			port = *dns_sa_port(af, &soa->addrs[i].ss);
5978 
5979 			return (port)? port : htons(53);
5980 		}
5981 	}
5982 
5983 	return htons(53);
5984 } /* dns_hints_port() */
5985 
5986 
dns_hints_dump(struct dns_hints * hints,FILE * fp)5987 int dns_hints_dump(struct dns_hints *hints, FILE *fp) {
5988 	struct dns_hints_soa *soa;
5989 	char addr[INET6_ADDRSTRLEN];
5990 	unsigned i;
5991 	int af, error;
5992 
5993 	for (soa = hints->head; soa; soa = soa->next) {
5994 		fprintf(fp, "ZONE \"%s\"\n", soa->zone);
5995 
5996 		for (i = 0; i < soa->count; i++) {
5997 			af = soa->addrs[i].ss.ss_family;
5998 
5999 			if ((error = dns_ntop(af, dns_sa_addr(af, &soa->addrs[i].ss, NULL), addr, sizeof addr)))
6000 				return error;
6001 
6002 			fprintf(fp, "\t(%d) [%s]:%hu\n", (int)soa->addrs[i].priority, addr, ntohs(*dns_sa_port(af, &soa->addrs[i].ss)));
6003 		}
6004 	}
6005 
6006 	return 0;
6007 } /* dns_hints_dump() */
6008 
6009 
6010 /*
6011  * C A C H E  R O U T I N E S
6012  *
6013  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6014 
dns_cache_acquire(struct dns_cache * cache)6015 static dns_refcount_t dns_cache_acquire(struct dns_cache *cache) {
6016 	return dns_atomic_fetch_add(&cache->_.refcount);
6017 } /* dns_cache_acquire() */
6018 
6019 
dns_cache_release(struct dns_cache * cache)6020 static dns_refcount_t dns_cache_release(struct dns_cache *cache) {
6021 	return dns_atomic_fetch_sub(&cache->_.refcount);
6022 } /* dns_cache_release() */
6023 
6024 
dns_cache_query(struct dns_packet * query,struct dns_cache * cache,int * error)6025 static struct dns_packet *dns_cache_query(struct dns_packet *query, struct dns_cache *cache, int *error) {
6026 	(void)query;
6027 	(void)cache;
6028 	(void)error;
6029 
6030 	return NULL;
6031 } /* dns_cache_query() */
6032 
6033 
dns_cache_submit(struct dns_packet * query,struct dns_cache * cache)6034 static int dns_cache_submit(struct dns_packet *query, struct dns_cache *cache) {
6035 	(void)query;
6036 	(void)cache;
6037 
6038 	return 0;
6039 } /* dns_cache_submit() */
6040 
6041 
dns_cache_check(struct dns_cache * cache)6042 static int dns_cache_check(struct dns_cache *cache) {
6043 	(void)cache;
6044 
6045 	return 0;
6046 } /* dns_cache_check() */
6047 
6048 
dns_cache_fetch(struct dns_cache * cache,int * error)6049 static struct dns_packet *dns_cache_fetch(struct dns_cache *cache, int *error) {
6050 	(void)cache;
6051 	(void)error;
6052 
6053 	return NULL;
6054 } /* dns_cache_fetch() */
6055 
6056 
dns_cache_pollfd(struct dns_cache * cache)6057 static int dns_cache_pollfd(struct dns_cache *cache) {
6058 	(void)cache;
6059 
6060 	return -1;
6061 } /* dns_cache_pollfd() */
6062 
6063 
dns_cache_events(struct dns_cache * cache)6064 static short dns_cache_events(struct dns_cache *cache) {
6065 	(void)cache;
6066 
6067 	return 0;
6068 } /* dns_cache_events() */
6069 
6070 
dns_cache_clear(struct dns_cache * cache)6071 static void dns_cache_clear(struct dns_cache *cache) {
6072 	(void)cache;
6073 
6074 	return;
6075 } /* dns_cache_clear() */
6076 
6077 
dns_cache_init(struct dns_cache * cache)6078 struct dns_cache *dns_cache_init(struct dns_cache *cache) {
6079 	static const struct dns_cache c_init = {
6080 		.acquire = &dns_cache_acquire,
6081 		.release = &dns_cache_release,
6082 		.query   = &dns_cache_query,
6083 		.submit  = &dns_cache_submit,
6084 		.check   = &dns_cache_check,
6085 		.fetch   = &dns_cache_fetch,
6086 		.pollfd  = &dns_cache_pollfd,
6087 		.events  = &dns_cache_events,
6088 		.clear   = &dns_cache_clear,
6089 		._ = { .refcount = 1, },
6090 	};
6091 
6092 	*cache = c_init;
6093 
6094 	return cache;
6095 } /* dns_cache_init() */
6096 
6097 
dns_cache_close(struct dns_cache * cache)6098 void dns_cache_close(struct dns_cache *cache) {
6099 	if (cache)
6100 		cache->release(cache);
6101 } /* dns_cache_close() */
6102 
6103 
6104 /*
6105  * S O C K E T  R O U T I N E S
6106  *
6107  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6108 
dns_socketclose(int * fd,const struct dns_options * opts)6109 static void dns_socketclose(int *fd, const struct dns_options *opts) {
6110 	if (opts && opts->closefd.cb)
6111 		opts->closefd.cb(fd, opts->closefd.arg);
6112 
6113 	if (*fd != -1) {
6114 #if _WIN32
6115 		closesocket(*fd);
6116 #else
6117 		close(*fd);
6118 #endif
6119 		*fd	= -1;
6120 	}
6121 } /* dns_socketclose() */
6122 
6123 
6124 #ifndef HAVE_IOCTLSOCKET
6125 #define HAVE_IOCTLSOCKET (_WIN32 || _WIN64)
6126 #endif
6127 
6128 #ifndef HAVE_SOCK_CLOEXEC
6129 #ifdef SOCK_CLOEXEC
6130 #define HAVE_SOCK_CLOEXEC 1
6131 #else
6132 #define HAVE_SOCK_CLOEXEC 0
6133 #endif
6134 #endif
6135 
6136 #ifndef HAVE_SOCK_NONBLOCK
6137 #ifdef SOCK_NONBLOCK
6138 #define HAVE_SOCK_NONBLOCK 1
6139 #else
6140 #define HAVE_SOCK_NONBLOCK 0
6141 #endif
6142 #endif
6143 
6144 #define DNS_SO_MAXTRY	7
6145 
dns_socket(struct sockaddr * local,int type,int * error_)6146 static int dns_socket(struct sockaddr *local, int type, int *error_) {
6147 	int fd = -1, flags, error;
6148 #if defined FIONBIO
6149 	unsigned long opt;
6150 #endif
6151 
6152 	flags = 0;
6153 #if HAVE_SOCK_CLOEXEC
6154 	flags |= SOCK_CLOEXEC;
6155 #endif
6156 #if HAVE_SOCK_NONBLOCK
6157 	flags |= SOCK_NONBLOCK;
6158 #endif
6159 	if (-1 == (fd = socket(local->sa_family, type|flags, 0)))
6160 		goto soerr;
6161 
6162 #if defined F_SETFD && !HAVE_SOCK_CLOEXEC
6163 	if (-1 == fcntl(fd, F_SETFD, 1))
6164 		goto syerr;
6165 #endif
6166 
6167 #if defined O_NONBLOCK && !HAVE_SOCK_NONBLOCK
6168 	if (-1 == (flags = fcntl(fd, F_GETFL)))
6169 		goto syerr;
6170 	if (-1 == fcntl(fd, F_SETFL, flags | O_NONBLOCK))
6171 		goto syerr;
6172 #elif defined FIONBIO && HAVE_IOCTLSOCKET
6173 	opt = 1;
6174 	if (0 != ioctlsocket(fd, FIONBIO, &opt))
6175 		goto soerr;
6176 #endif
6177 
6178 #if defined SO_NOSIGPIPE
6179 	if (type != SOCK_DGRAM) {
6180 		if (0 != setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &(int){ 1 }, sizeof (int)))
6181 			goto soerr;
6182 	}
6183 #endif
6184 
6185 	if (local->sa_family != AF_INET && local->sa_family != AF_INET6)
6186 		return fd;
6187 
6188 	if (type != SOCK_DGRAM)
6189 		return fd;
6190 
6191 	/*
6192 	 * FreeBSD, Linux, OpenBSD, OS X, and Solaris use random ports by
6193 	 * default. Though the ephemeral range is quite small on OS X
6194 	 * (49152-65535 on 10.10) and Linux (32768-60999 on 4.4.0, Ubuntu
6195 	 * Xenial). See also RFC 6056.
6196 	 *
6197 	 * TODO: Optionally rely on the kernel to select a random port.
6198 	 */
6199 	if (*dns_sa_port(local->sa_family, local) == 0) {
6200 		struct sockaddr_storage tmp;
6201 		unsigned i, port;
6202 
6203 		memcpy(&tmp, local, dns_sa_len(local));
6204 
6205 		for (i = 0; i < DNS_SO_MAXTRY; i++) {
6206 			port = 1025 + (dns_random() % 64510);
6207 
6208 			*dns_sa_port(tmp.ss_family, &tmp) = htons(port);
6209 
6210 			if (0 == bind(fd, (struct sockaddr *)&tmp, dns_sa_len(&tmp)))
6211 				return fd;
6212 		}
6213 
6214 		/* NB: continue to next bind statement */
6215 	}
6216 
6217 	if (0 == bind(fd, local, dns_sa_len(local)))
6218 		return fd;
6219 
6220 	/* FALL THROUGH */
6221 soerr:
6222 	error = dns_soerr();
6223 
6224 	goto error;
6225 #if (defined F_SETFD && !HAVE_SOCK_CLOEXEC) || (defined O_NONBLOCK && !HAVE_SOCK_NONBLOCK)
6226 syerr:
6227 	error = dns_syerr();
6228 
6229 	goto error;
6230 #endif
6231 error:
6232 	*error_ = error;
6233 
6234 	dns_socketclose(&fd, NULL);
6235 
6236 	return -1;
6237 } /* dns_socket() */
6238 
6239 
6240 enum {
6241 	DNS_SO_UDP_INIT	= 1,
6242 	DNS_SO_UDP_CONN,
6243 	DNS_SO_UDP_SEND,
6244 	DNS_SO_UDP_RECV,
6245 	DNS_SO_UDP_DONE,
6246 
6247 	DNS_SO_TCP_INIT,
6248 	DNS_SO_TCP_CONN,
6249 	DNS_SO_TCP_SEND,
6250 	DNS_SO_TCP_RECV,
6251 	DNS_SO_TCP_DONE,
6252 };
6253 
6254 struct dns_socket {
6255 	struct dns_options opts;
6256 
6257 	int udp;
6258 	int tcp;
6259 
6260 	int *old;
6261 	unsigned onum, olim;
6262 
6263 	int type;
6264 
6265 	struct sockaddr_storage local, remote;
6266 
6267 	struct dns_k_permutor qids;
6268 
6269 	struct dns_stat stat;
6270 
6271 	/*
6272 	 * NOTE: dns_so_reset() zeroes everything from here down.
6273 	 */
6274 	int state;
6275 
6276 	unsigned short qid;
6277 	char qname[DNS_D_MAXNAME + 1];
6278 	size_t qlen;
6279 	enum dns_type qtype;
6280 	enum dns_class qclass;
6281 
6282 	struct dns_packet *query;
6283 	size_t qout;
6284 
6285 	struct dns_clock elapsed;
6286 
6287 	struct dns_packet *answer;
6288 	size_t alen, apos;
6289 }; /* struct dns_socket */
6290 
6291 
6292 /*
6293  * NOTE: Actual closure delayed so that kqueue(2) and epoll(2) callers have
6294  * a chance to recognize a state change after installing a persistent event
6295  * and where sequential descriptors with the same integer value returned
6296  * from _pollfd() would be ambiguous. See dns_so_closefds().
6297  */
dns_so_closefd(struct dns_socket * so,int * fd)6298 static int dns_so_closefd(struct dns_socket *so, int *fd) {
6299 	int error;
6300 
6301 	if (*fd == -1)
6302 		return 0;
6303 
6304 	if (so->opts.closefd.cb) {
6305 		if ((error = so->opts.closefd.cb(fd, so->opts.closefd.arg))) {
6306 			return error;
6307 		} else if (*fd == -1)
6308 			return 0;
6309 	}
6310 
6311 	if (!(so->onum < so->olim)) {
6312 		unsigned olim = DNS_PP_MAX(4, so->olim * 2);
6313 		void *old;
6314 
6315 		if (!(old = realloc(so->old, sizeof so->old[0] * olim)))
6316 			return dns_syerr();
6317 
6318 		so->old  = old;
6319 		so->olim = olim;
6320 	}
6321 
6322 	so->old[so->onum++] = *fd;
6323 	*fd = -1;
6324 
6325 	return 0;
6326 } /* dns_so_closefd() */
6327 
6328 
6329 #define DNS_SO_CLOSE_UDP 0x01
6330 #define DNS_SO_CLOSE_TCP 0x02
6331 #define DNS_SO_CLOSE_OLD 0x04
6332 #define DNS_SO_CLOSE_ALL (DNS_SO_CLOSE_UDP|DNS_SO_CLOSE_TCP|DNS_SO_CLOSE_OLD)
6333 
dns_so_closefds(struct dns_socket * so,int which)6334 static void dns_so_closefds(struct dns_socket *so, int which) {
6335 	if (DNS_SO_CLOSE_UDP & which)
6336 		dns_socketclose(&so->udp, &so->opts);
6337 	if (DNS_SO_CLOSE_TCP & which)
6338 		dns_socketclose(&so->tcp, &so->opts);
6339 	if (DNS_SO_CLOSE_OLD & which) {
6340 		unsigned i;
6341 		for (i = 0; i < so->onum; i++)
6342 			dns_socketclose(&so->old[i], &so->opts);
6343 		so->onum = 0;
6344 		free(so->old);
6345 		so->old  = 0;
6346 		so->olim = 0;
6347 	}
6348 } /* dns_so_closefds() */
6349 
6350 
6351 static void dns_so_destroy(struct dns_socket *);
6352 
dns_so_init(struct dns_socket * so,const struct sockaddr * local,int type,const struct dns_options * opts,int * error)6353 static struct dns_socket *dns_so_init(struct dns_socket *so, const struct sockaddr *local, int type, const struct dns_options *opts, int *error) {
6354 	static const struct dns_socket so_initializer = { .opts = DNS_OPTS_INITIALIZER, .udp = -1, .tcp = -1, };
6355 
6356 	*so		= so_initializer;
6357 	so->type	= type;
6358 
6359 	if (opts)
6360 		so->opts = *opts;
6361 
6362 	if (local)
6363 		memcpy(&so->local, local, dns_sa_len(local));
6364 
6365 	if (-1 == (so->udp = dns_socket((struct sockaddr *)&so->local, SOCK_DGRAM, error)))
6366 		goto error;
6367 
6368 	dns_k_permutor_init(&so->qids, 1, 65535);
6369 
6370 	return so;
6371 error:
6372 	dns_so_destroy(so);
6373 
6374 	return 0;
6375 } /* dns_so_init() */
6376 
6377 
dns_so_open(const struct sockaddr * local,int type,const struct dns_options * opts,int * error)6378 struct dns_socket *dns_so_open(const struct sockaddr *local, int type, const struct dns_options *opts, int *error) {
6379 	struct dns_socket *so;
6380 
6381 	if (!(so = malloc(sizeof *so)))
6382 		goto syerr;
6383 
6384 	if (!dns_so_init(so, local, type, opts, error))
6385 		goto error;
6386 
6387 	return so;
6388 syerr:
6389 	*error	= dns_syerr();
6390 error:
6391 	dns_so_close(so);
6392 
6393 	return 0;
6394 } /* dns_so_open() */
6395 
6396 
dns_so_destroy(struct dns_socket * so)6397 static void dns_so_destroy(struct dns_socket *so) {
6398 	dns_so_reset(so);
6399 	dns_so_closefds(so, DNS_SO_CLOSE_ALL);
6400 } /* dns_so_destroy() */
6401 
6402 
dns_so_close(struct dns_socket * so)6403 void dns_so_close(struct dns_socket *so) {
6404 	if (!so)
6405 		return;
6406 
6407 	dns_so_destroy(so);
6408 
6409 	free(so);
6410 } /* dns_so_close() */
6411 
6412 
dns_so_reset(struct dns_socket * so)6413 void dns_so_reset(struct dns_socket *so) {
6414 	dns_p_setptr(&so->answer, NULL);
6415 
6416 	memset(&so->state, '\0', sizeof *so - offsetof(struct dns_socket, state));
6417 } /* dns_so_reset() */
6418 
6419 
dns_so_mkqid(struct dns_socket * so)6420 unsigned short dns_so_mkqid(struct dns_socket *so) {
6421 	return dns_k_permutor_step(&so->qids);
6422 } /* dns_so_mkqid() */
6423 
6424 
6425 #define DNS_SO_MINBUF	768
6426 
dns_so_newanswer(struct dns_socket * so,size_t len)6427 static int dns_so_newanswer(struct dns_socket *so, size_t len) {
6428 	size_t size	= offsetof(struct dns_packet, data) + DNS_PP_MAX(len, DNS_SO_MINBUF);
6429 	void *p;
6430 
6431 	if (!(p = realloc(so->answer, size)))
6432 		return dns_syerr();
6433 
6434 	so->answer	= dns_p_init(p, size);
6435 
6436 	return 0;
6437 } /* dns_so_newanswer() */
6438 
6439 
dns_so_submit(struct dns_socket * so,struct dns_packet * Q,struct sockaddr * host)6440 int dns_so_submit(struct dns_socket *so, struct dns_packet *Q, struct sockaddr *host) {
6441 	struct dns_rr rr;
6442 	int error = DNS_EUNKNOWN;
6443 
6444 	dns_so_reset(so);
6445 
6446 	if ((error = dns_rr_parse(&rr, 12, Q)))
6447 		goto error;
6448 
6449 	if (!(so->qlen = dns_d_expand(so->qname, sizeof so->qname, rr.dn.p, Q, &error)))
6450 		goto error;
6451 	/*
6452 	 * NOTE: Don't bail if expansion is too long; caller may be
6453 	 * intentionally sending long names. However, we won't be able to
6454 	 * verify it on return.
6455 	 */
6456 
6457 	so->qtype	= rr.type;
6458 	so->qclass	= rr.class;
6459 
6460 	if ((error = dns_so_newanswer(so, (Q->memo.opt.maxudp)? Q->memo.opt.maxudp : DNS_SO_MINBUF)))
6461 		goto syerr;
6462 
6463 	memcpy(&so->remote, host, dns_sa_len(host));
6464 
6465 	so->query	= Q;
6466 	so->qout	= 0;
6467 
6468 	dns_begin(&so->elapsed);
6469 
6470 	if (dns_header(so->query)->qid == 0)
6471 		dns_header(so->query)->qid	= dns_so_mkqid(so);
6472 
6473 	so->qid		= dns_header(so->query)->qid;
6474 	so->state	= (so->type == SOCK_STREAM)? DNS_SO_TCP_INIT : DNS_SO_UDP_INIT;
6475 
6476 	so->stat.queries++;
6477 
6478 	return 0;
6479 syerr:
6480 	error	= dns_syerr();
6481 error:
6482 	dns_so_reset(so);
6483 
6484 	return error;
6485 } /* dns_so_submit() */
6486 
6487 
dns_so_verify(struct dns_socket * so,struct dns_packet * P)6488 static int dns_so_verify(struct dns_socket *so, struct dns_packet *P) {
6489 	char qname[DNS_D_MAXNAME + 1];
6490 	size_t qlen;
6491 	struct dns_rr rr;
6492 	int error = -1;
6493 
6494 	if (so->qid != dns_header(so->answer)->qid)
6495 		goto reject;
6496 
6497 	if (!dns_p_count(so->answer, DNS_S_QD))
6498 		goto reject;
6499 
6500 	if (0 != dns_rr_parse(&rr, 12, so->answer))
6501 		goto reject;
6502 
6503 	if (rr.type != so->qtype || rr.class != so->qclass)
6504 		goto reject;
6505 
6506 	if (!(qlen = dns_d_expand(qname, sizeof qname, rr.dn.p, P, &error)))
6507 		goto error;
6508 	else if (qlen >= sizeof qname || qlen != so->qlen)
6509 		goto reject;
6510 
6511 	if (0 != strcasecmp(so->qname, qname))
6512 		goto reject;
6513 
6514 	return 0;
6515 reject:
6516 	error = DNS_EUNKNOWN;
6517 error:
6518 	DNS_SHOW(P, "rejecting packet (%s)", dns_strerror(error));
6519 
6520 	return error;
6521 } /* dns_so_verify() */
6522 
6523 
dns_so_tcp_keep(struct dns_socket * so)6524 static _Bool dns_so_tcp_keep(struct dns_socket *so) {
6525 	struct sockaddr_storage remote;
6526 
6527 	if (so->tcp == -1)
6528 		return 0;
6529 
6530 	if (0 != getpeername(so->tcp, (struct sockaddr *)&remote, &(socklen_t){ sizeof remote }))
6531 		return 0;
6532 
6533 	return 0 == dns_sa_cmp(&remote, &so->remote);
6534 } /* dns_so_tcp_keep() */
6535 
6536 
6537 #if defined __clang__
6538 #pragma clang diagnostic push
6539 #pragma clang diagnostic ignored "-Warray-bounds"
6540 #endif
6541 
dns_so_tcp_send(struct dns_socket * so)6542 static int dns_so_tcp_send(struct dns_socket *so) {
6543 	unsigned char *qsrc;
6544 	size_t qend;
6545 	long n;
6546 
6547 	so->query->data[-2] = 0xff & (so->query->end >> 8);
6548 	so->query->data[-1] = 0xff & (so->query->end >> 0);
6549 
6550 	qsrc = &so->query->data[-2] + so->qout;
6551 	qend = so->query->end + 2;
6552 
6553 	while (so->qout < qend) {
6554 		if (0 > (n = dns_send(so->tcp, (void *)&qsrc[so->qout], qend - so->qout, 0)))
6555 			return dns_soerr();
6556 
6557 		so->qout += n;
6558 		so->stat.tcp.sent.bytes += n;
6559 	}
6560 
6561 	so->stat.tcp.sent.count++;
6562 
6563 	return 0;
6564 } /* dns_so_tcp_send() */
6565 
6566 
dns_so_tcp_recv(struct dns_socket * so)6567 static int dns_so_tcp_recv(struct dns_socket *so) {
6568 	unsigned char *asrc;
6569 	size_t aend, alen;
6570 	int error;
6571 	long n;
6572 
6573 	aend = so->alen + 2;
6574 
6575 	while (so->apos < aend) {
6576 		asrc = &so->answer->data[-2];
6577 
6578 		if (0 > (n = recv(so->tcp, (void *)&asrc[so->apos], aend - so->apos, 0)))
6579 			return dns_soerr();
6580 		else if (n == 0)
6581 			return DNS_EUNKNOWN;	/* FIXME */
6582 
6583 		so->apos += n;
6584 		so->stat.tcp.rcvd.bytes += n;
6585 
6586 		if (so->alen == 0 && so->apos >= 2) {
6587 			alen = ((0xff & so->answer->data[-2]) << 8)
6588 			     | ((0xff & so->answer->data[-1]) << 0);
6589 
6590 			if ((error = dns_so_newanswer(so, alen)))
6591 				return error;
6592 
6593 			so->alen = alen;
6594 			aend = alen + 2;
6595 		}
6596 	}
6597 
6598 	so->answer->end	= so->alen;
6599 	so->stat.tcp.rcvd.count++;
6600 
6601 	return 0;
6602 } /* dns_so_tcp_recv() */
6603 
6604 #if __clang__
6605 #pragma clang diagnostic pop
6606 #endif
6607 
6608 
dns_so_check(struct dns_socket * so)6609 int dns_so_check(struct dns_socket *so) {
6610 	int error;
6611 	long n;
6612 
6613 retry:
6614 	switch (so->state) {
6615 	case DNS_SO_UDP_INIT:
6616 		so->state++;
6617 		/* FALL THROUGH */
6618 	case DNS_SO_UDP_CONN:
6619 		if (0 != connect(so->udp, (struct sockaddr *)&so->remote, dns_sa_len(&so->remote)))
6620 			goto soerr;
6621 
6622 		so->state++;
6623 		/* FALL THROUGH */
6624 	case DNS_SO_UDP_SEND:
6625 		if (0 > (n = send(so->udp, (void *)so->query->data, so->query->end, 0)))
6626 			goto soerr;
6627 
6628 		so->stat.udp.sent.bytes += n;
6629 		so->stat.udp.sent.count++;
6630 
6631 		so->state++;
6632 		/* FALL THROUGH */
6633 	case DNS_SO_UDP_RECV:
6634 		if (0 > (n = recv(so->udp, (void *)so->answer->data, so->answer->size, 0)))
6635 			goto soerr;
6636 
6637 		so->stat.udp.rcvd.bytes += n;
6638 		so->stat.udp.rcvd.count++;
6639 
6640 		if ((so->answer->end = n) < 12)
6641 			goto trash;
6642 
6643 		if ((error = dns_so_verify(so, so->answer)))
6644 			goto trash;
6645 
6646 		so->state++;
6647 		/* FALL THROUGH */
6648 	case DNS_SO_UDP_DONE:
6649 		if (!dns_header(so->answer)->tc || so->type == SOCK_DGRAM)
6650 			return 0;
6651 
6652 		so->state++;
6653 		/* FALL THROUGH */
6654 	case DNS_SO_TCP_INIT:
6655 		if (dns_so_tcp_keep(so)) {
6656 			so->state = DNS_SO_TCP_SEND;
6657 
6658 			goto retry;
6659 		}
6660 
6661 		if ((error = dns_so_closefd(so, &so->tcp)))
6662 			goto error;
6663 
6664 		if (-1 == (so->tcp = dns_socket((struct sockaddr *)&so->local, SOCK_STREAM, &error)))
6665 			goto error;
6666 
6667 		so->state++;
6668 		/* FALL THROUGH */
6669 	case DNS_SO_TCP_CONN:
6670 		if (0 != connect(so->tcp, (struct sockaddr *)&so->remote, dns_sa_len(&so->remote))) {
6671 			if (dns_soerr() != DNS_EISCONN)
6672 				goto soerr;
6673 		}
6674 
6675 		so->state++;
6676 		/* FALL THROUGH */
6677 	case DNS_SO_TCP_SEND:
6678 		if ((error = dns_so_tcp_send(so)))
6679 			goto error;
6680 
6681 		so->state++;
6682 		/* FALL THROUGH */
6683 	case DNS_SO_TCP_RECV:
6684 		if ((error = dns_so_tcp_recv(so)))
6685 			goto error;
6686 
6687 		so->state++;
6688 		/* FALL THROUGH */
6689 	case DNS_SO_TCP_DONE:
6690 		/* close unless DNS_RESCONF_TCP_ONLY (see dns_res_tcp2type) */
6691 		if (so->type != SOCK_STREAM) {
6692 			if ((error = dns_so_closefd(so, &so->tcp)))
6693 				goto error;
6694 		}
6695 
6696 		if (so->answer->end < 12)
6697 			return DNS_EILLEGAL;
6698 
6699 		if ((error = dns_so_verify(so, so->answer)))
6700 			goto error;
6701 
6702 		return 0;
6703 	default:
6704 		error	= DNS_EUNKNOWN;
6705 
6706 		goto error;
6707 	} /* switch() */
6708 
6709 trash:
6710 	DNS_CARP("discarding packet");
6711 	goto retry;
6712 soerr:
6713 	error	= dns_soerr();
6714 
6715 	goto error;
6716 error:
6717 	switch (error) {
6718 	case DNS_EINTR:
6719 		goto retry;
6720 	case DNS_EINPROGRESS:
6721 		/* FALL THROUGH */
6722 	case DNS_EALREADY:
6723 		/* FALL THROUGH */
6724 #if DNS_EWOULDBLOCK != DNS_EAGAIN
6725 	case DNS_EWOULDBLOCK:
6726 		/* FALL THROUGH */
6727 #endif
6728 		error	= DNS_EAGAIN;
6729 
6730 		break;
6731 	} /* switch() */
6732 
6733 	return error;
6734 } /* dns_so_check() */
6735 
6736 
dns_so_fetch(struct dns_socket * so,int * error)6737 struct dns_packet *dns_so_fetch(struct dns_socket *so, int *error) {
6738 	struct dns_packet *answer;
6739 
6740 	switch (so->state) {
6741 	case DNS_SO_UDP_DONE:
6742 	case DNS_SO_TCP_DONE:
6743 		answer		= so->answer;
6744 		so->answer	= 0;
6745 
6746 		return answer;
6747 	default:
6748 		*error	= DNS_EUNKNOWN;
6749 
6750 		return 0;
6751 	}
6752 } /* dns_so_fetch() */
6753 
6754 
dns_so_query(struct dns_socket * so,struct dns_packet * Q,struct sockaddr * host,int * error_)6755 struct dns_packet *dns_so_query(struct dns_socket *so, struct dns_packet *Q, struct sockaddr *host, int *error_) {
6756 	struct dns_packet *A;
6757 	int error;
6758 
6759 	if (!so->state) {
6760 		if ((error = dns_so_submit(so, Q, host)))
6761 			goto error;
6762 	}
6763 
6764 	if ((error = dns_so_check(so)))
6765 		goto error;
6766 
6767 	if (!(A = dns_so_fetch(so, &error)))
6768 		goto error;
6769 
6770 	dns_so_reset(so);
6771 
6772 	return A;
6773 error:
6774 	*error_	= error;
6775 
6776 	return 0;
6777 } /* dns_so_query() */
6778 
6779 
dns_so_elapsed(struct dns_socket * so)6780 time_t dns_so_elapsed(struct dns_socket *so) {
6781 	return dns_elapsed(&so->elapsed);
6782 } /* dns_so_elapsed() */
6783 
6784 
dns_so_clear(struct dns_socket * so)6785 void dns_so_clear(struct dns_socket *so) {
6786 	dns_so_closefds(so, DNS_SO_CLOSE_OLD);
6787 } /* dns_so_clear() */
6788 
6789 
dns_so_events2(struct dns_socket * so,enum dns_events type)6790 static int dns_so_events2(struct dns_socket *so, enum dns_events type) {
6791 	int events = 0;
6792 
6793 	switch (so->state) {
6794 	case DNS_SO_UDP_CONN:
6795 	case DNS_SO_UDP_SEND:
6796 		events |= DNS_POLLOUT;
6797 
6798 		break;
6799 	case DNS_SO_UDP_RECV:
6800 		events |= DNS_POLLIN;
6801 
6802 		break;
6803 	case DNS_SO_TCP_CONN:
6804 	case DNS_SO_TCP_SEND:
6805 		events |= DNS_POLLOUT;
6806 
6807 		break;
6808 	case DNS_SO_TCP_RECV:
6809 		events |= DNS_POLLIN;
6810 
6811 		break;
6812 	} /* switch() */
6813 
6814 	switch (type) {
6815 	case DNS_LIBEVENT:
6816 		return DNS_POLL2EV(events);
6817 	default:
6818 		return events;
6819 	} /* switch() */
6820 } /* dns_so_events2() */
6821 
6822 
dns_so_events(struct dns_socket * so)6823 int dns_so_events(struct dns_socket *so) {
6824 	return dns_so_events2(so, so->opts.events);
6825 } /* dns_so_events() */
6826 
6827 
dns_so_pollfd(struct dns_socket * so)6828 int dns_so_pollfd(struct dns_socket *so) {
6829 	switch (so->state) {
6830 	case DNS_SO_UDP_CONN:
6831 	case DNS_SO_UDP_SEND:
6832 	case DNS_SO_UDP_RECV:
6833 		return so->udp;
6834 	case DNS_SO_TCP_CONN:
6835 	case DNS_SO_TCP_SEND:
6836 	case DNS_SO_TCP_RECV:
6837 		return so->tcp;
6838 	} /* switch() */
6839 
6840 	return -1;
6841 } /* dns_so_pollfd() */
6842 
6843 
dns_so_poll(struct dns_socket * so,int timeout)6844 int dns_so_poll(struct dns_socket *so, int timeout) {
6845 	return dns_poll(dns_so_pollfd(so), dns_so_events2(so, DNS_SYSPOLL), timeout);
6846 } /* dns_so_poll() */
6847 
6848 
dns_so_stat(struct dns_socket * so)6849 const struct dns_stat *dns_so_stat(struct dns_socket *so) {
6850 	return &so->stat;
6851 } /* dns_so_stat() */
6852 
6853 
6854 /*
6855  * R E S O L V E R  R O U T I N E S
6856  *
6857  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6858 
6859 enum dns_res_state {
6860 	DNS_R_INIT,
6861 	DNS_R_GLUE,
6862 	DNS_R_SWITCH,		/* (B)IND, (F)ILE, (C)ACHE */
6863 
6864 	DNS_R_FILE,		/* Lookup in local hosts database */
6865 
6866 	DNS_R_CACHE,		/* Lookup in application cache */
6867 	DNS_R_SUBMIT,
6868 	DNS_R_CHECK,
6869 	DNS_R_FETCH,
6870 
6871 	DNS_R_BIND,		/* Lookup in the network */
6872 	DNS_R_SEARCH,
6873 	DNS_R_HINTS,
6874 	DNS_R_ITERATE,
6875 	DNS_R_FOREACH_NS,
6876 	DNS_R_RESOLV0_NS,	/* Prologue: Setup next frame and recurse */
6877 	DNS_R_RESOLV1_NS,	/* Epilog: Inspect answer */
6878 	DNS_R_FOREACH_A,
6879 	DNS_R_QUERY_A,
6880 	DNS_R_CNAME0_A,
6881 	DNS_R_CNAME1_A,
6882 
6883 	DNS_R_FINISH,
6884 	DNS_R_SMART0_A,
6885 	DNS_R_SMART1_A,
6886 	DNS_R_DONE,
6887 	DNS_R_SERVFAIL,
6888 }; /* enum dns_res_state */
6889 
6890 
6891 #define DNS_R_MAXDEPTH	8
6892 #define DNS_R_ENDFRAME	(DNS_R_MAXDEPTH - 1)
6893 
6894 struct dns_resolver {
6895 	struct dns_socket so;
6896 
6897 	struct dns_resolv_conf *resconf;
6898 	struct dns_hosts *hosts;
6899 	struct dns_hints *hints;
6900 	struct dns_cache *cache;
6901 
6902 	dns_atomic_t refcount;
6903 
6904 	/* Reset zeroes everything below here. */
6905 
6906 	char qname[DNS_D_MAXNAME + 1];
6907 	size_t qlen;
6908 
6909 	enum dns_type qtype;
6910 	enum dns_class qclass;
6911 
6912 	struct dns_clock elapsed;
6913 
6914 	dns_resconf_i_t search;
6915 
6916 	struct dns_rr_i smart;
6917 
6918 	struct dns_packet *nodata; /* answer if nothing better */
6919 
6920 	unsigned sp;
6921 
6922 	struct dns_res_frame {
6923 		enum dns_res_state state;
6924 
6925 		int error;
6926 		int which;	/* (B)IND, (F)ILE; index into resconf->lookup */
6927 		int qflags;
6928 
6929 		unsigned attempts;
6930 
6931 		struct dns_packet *query, *answer, *hints;
6932 
6933 		struct dns_rr_i hints_i, hints_j;
6934 		struct dns_rr hints_ns, ans_cname;
6935 	} stack[DNS_R_MAXDEPTH];
6936 }; /* struct dns_resolver */
6937 
6938 
dns_res_tcp2type(int tcp)6939 static int dns_res_tcp2type(int tcp) {
6940 	switch (tcp) {
6941 	case DNS_RESCONF_TCP_ONLY:
6942 		return SOCK_STREAM;
6943 	case DNS_RESCONF_TCP_DISABLE:
6944 		return SOCK_DGRAM;
6945 	default:
6946 		return 0;
6947 	}
6948 } /* dns_res_tcp2type() */
6949 
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)6950 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) {
6951 	static const struct dns_resolver R_initializer
6952 		= { .refcount = 1, };
6953 	struct dns_resolver *R	= 0;
6954 	int type, error;
6955 
6956 	/*
6957 	 * Grab ref count early because the caller may have passed us a mortal
6958 	 * reference, and we want to do the right thing if we return early
6959 	 * from an error.
6960 	 */
6961 	if (resconf)
6962 		dns_resconf_acquire(resconf);
6963 	if (hosts)
6964 		dns_hosts_acquire(hosts);
6965 	if (hints)
6966 		dns_hints_acquire(hints);
6967 	if (cache)
6968 		dns_cache_acquire(cache);
6969 
6970 	/*
6971 	 * Don't try to load it ourselves because a NULL object might be an
6972 	 * error from, say, dns_resconf_root(), and loading
6973 	 * dns_resconf_local() by default would create undesirable surpises.
6974 	 */
6975 	if (!resconf || !hosts || !hints) {
6976 		if (!*_error)
6977 			*_error = EINVAL;
6978 		goto _error;
6979 	}
6980 
6981 	if (!(R = malloc(sizeof *R)))
6982 		goto syerr;
6983 
6984 	*R	= R_initializer;
6985 	type	= dns_res_tcp2type(resconf->options.tcp);
6986 
6987 	if (!dns_so_init(&R->so, (struct sockaddr *)&resconf->iface, type, opts, &error))
6988 		goto error;
6989 
6990 	R->resconf	= resconf;
6991 	R->hosts	= hosts;
6992 	R->hints	= hints;
6993 	R->cache	= cache;
6994 
6995 	return R;
6996 syerr:
6997 	error	= dns_syerr();
6998 error:
6999 	*_error	= error;
7000 _error:
7001 	dns_res_close(R);
7002 
7003 	dns_resconf_close(resconf);
7004 	dns_hosts_close(hosts);
7005 	dns_hints_close(hints);
7006 	dns_cache_close(cache);
7007 
7008 	return 0;
7009 } /* dns_res_open() */
7010 
7011 
dns_res_stub(const struct dns_options * opts,int * error)7012 struct dns_resolver *dns_res_stub(const struct dns_options *opts, int *error) {
7013 	struct dns_resolv_conf *resconf	= 0;
7014 	struct dns_hosts *hosts		= 0;
7015 	struct dns_hints *hints		= 0;
7016 	struct dns_resolver *res	= 0;
7017 
7018 	if (!(resconf = dns_resconf_local(error)))
7019 		goto epilog;
7020 
7021 	if (!(hosts = dns_hosts_local(error)))
7022 		goto epilog;
7023 
7024 	if (!(hints = dns_hints_local(resconf, error)))
7025 		goto epilog;
7026 
7027 	if (!(res = dns_res_open(resconf, hosts, hints, NULL, opts, error)))
7028 		goto epilog;
7029 
7030 epilog:
7031 	dns_resconf_close(resconf);
7032 	dns_hosts_close(hosts);
7033 	dns_hints_close(hints);
7034 
7035 	return res;
7036 } /* dns_res_stub() */
7037 
7038 
dns_res_frame_destroy(struct dns_resolver * R,struct dns_res_frame * frame)7039 static void dns_res_frame_destroy(struct dns_resolver *R, struct dns_res_frame *frame) {
7040 	(void)R;
7041 
7042 	dns_p_setptr(&frame->query, NULL);
7043 	dns_p_setptr(&frame->answer, NULL);
7044 	dns_p_setptr(&frame->hints, NULL);
7045 } /* dns_res_frame_destroy() */
7046 
7047 
dns_res_frame_init(struct dns_resolver * R,struct dns_res_frame * frame)7048 static void dns_res_frame_init(struct dns_resolver *R, struct dns_res_frame *frame) {
7049 	memset(frame, '\0', sizeof *frame);
7050 
7051 	/*
7052 	 * NB: Can be invoked from dns_res_open, before R->resconf has been
7053 	 * initialized.
7054 	 */
7055 	if (R->resconf) {
7056 		if (!R->resconf->options.recurse)
7057 			frame->qflags |= DNS_Q_RD;
7058 		if (R->resconf->options.edns0)
7059 			frame->qflags |= DNS_Q_EDNS0;
7060 	}
7061 } /* dns_res_frame_init() */
7062 
7063 
dns_res_frame_reset(struct dns_resolver * R,struct dns_res_frame * frame)7064 static void dns_res_frame_reset(struct dns_resolver *R, struct dns_res_frame *frame) {
7065 	dns_res_frame_destroy(R, frame);
7066 	dns_res_frame_init(R, frame);
7067 } /* dns_res_frame_reset() */
7068 
7069 
dns_res_frame_prepare(struct dns_resolver * R,struct dns_res_frame * F,const char * qname,enum dns_type qtype,enum dns_class qclass)7070 static dns_error_t dns_res_frame_prepare(struct dns_resolver *R, struct dns_res_frame *F, const char *qname, enum dns_type qtype, enum dns_class qclass) {
7071 	struct dns_packet *P = NULL;
7072 
7073 	if (!(F < endof(R->stack)))
7074 		return DNS_EUNKNOWN;
7075 
7076 	dns_p_movptr(&P, &F->query);
7077 	dns_res_frame_reset(R, F);
7078 	dns_p_movptr(&F->query, &P);
7079 
7080 	return dns_q_make(&F->query, qname, qtype, qclass, F->qflags);
7081 } /* dns_res_frame_prepare() */
7082 
7083 
dns_res_reset(struct dns_resolver * R)7084 void dns_res_reset(struct dns_resolver *R) {
7085 	unsigned i;
7086 
7087 	dns_so_reset(&R->so);
7088 	dns_p_setptr(&R->nodata, NULL);
7089 
7090 	for (i = 0; i < lengthof(R->stack); i++)
7091 		dns_res_frame_destroy(R, &R->stack[i]);
7092 
7093 	memset(&R->qname, '\0', sizeof *R - offsetof(struct dns_resolver, qname));
7094 
7095 	for (i = 0; i < lengthof(R->stack); i++)
7096 		dns_res_frame_init(R, &R->stack[i]);
7097 } /* dns_res_reset() */
7098 
7099 
dns_res_close(struct dns_resolver * R)7100 void dns_res_close(struct dns_resolver *R) {
7101 	if (!R || 1 < dns_res_release(R))
7102 		return;
7103 
7104 	dns_res_reset(R);
7105 
7106 	dns_so_destroy(&R->so);
7107 
7108 	dns_hints_close(R->hints);
7109 	dns_hosts_close(R->hosts);
7110 	dns_resconf_close(R->resconf);
7111 	dns_cache_close(R->cache);
7112 
7113 	free(R);
7114 } /* dns_res_close() */
7115 
7116 
dns_res_acquire(struct dns_resolver * R)7117 dns_refcount_t dns_res_acquire(struct dns_resolver *R) {
7118 	return dns_atomic_fetch_add(&R->refcount);
7119 } /* dns_res_acquire() */
7120 
7121 
dns_res_release(struct dns_resolver * R)7122 dns_refcount_t dns_res_release(struct dns_resolver *R) {
7123 	return dns_atomic_fetch_sub(&R->refcount);
7124 } /* dns_res_release() */
7125 
7126 
dns_res_mortal(struct dns_resolver * res)7127 struct dns_resolver *dns_res_mortal(struct dns_resolver *res) {
7128 	if (res)
7129 		dns_res_release(res);
7130 	return res;
7131 } /* dns_res_mortal() */
7132 
7133 
dns_res_merge(struct dns_packet * P0,struct dns_packet * P1,int * error_)7134 static struct dns_packet *dns_res_merge(struct dns_packet *P0, struct dns_packet *P1, int *error_) {
7135 	size_t bufsiz	= P0->end + P1->end;
7136 	struct dns_packet *P[3]	= { P0, P1, 0 };
7137 	struct dns_rr rr[3];
7138 	int error, copy, i;
7139 	enum dns_section section;
7140 
7141 retry:
7142 	if (!(P[2] = dns_p_make(bufsiz, &error)))
7143 		goto error;
7144 
7145 	dns_rr_foreach(&rr[0], P[0], .section = DNS_S_QD) {
7146 		if ((error = dns_rr_copy(P[2], &rr[0], P[0])))
7147 			goto error;
7148 	}
7149 
7150 	for (section = DNS_S_AN; (DNS_S_ALL & section); section <<= 1) {
7151 		for (i = 0; i < 2; i++) {
7152 			dns_rr_foreach(&rr[i], P[i], .section = section) {
7153 				copy	= 1;
7154 
7155 				dns_rr_foreach(&rr[2], P[2], .type = rr[i].type, .section = (DNS_S_ALL & ~DNS_S_QD)) {
7156 					if (0 == dns_rr_cmp(&rr[i], P[i], &rr[2], P[2])) {
7157 						copy	= 0;
7158 
7159 						break;
7160 					}
7161 				}
7162 
7163 				if (copy && (error = dns_rr_copy(P[2], &rr[i], P[i]))) {
7164 					if (error == DNS_ENOBUFS && bufsiz < 65535) {
7165 						dns_p_setptr(&P[2], NULL);
7166 
7167 						bufsiz	= DNS_PP_MAX(65535, bufsiz * 2);
7168 
7169 						goto retry;
7170 					}
7171 
7172 					goto error;
7173 				}
7174 			} /* foreach(rr) */
7175 		} /* foreach(packet) */
7176 	} /* foreach(section) */
7177 
7178 	return P[2];
7179 error:
7180 	*error_	= error;
7181 
7182 	dns_p_free(P[2]);
7183 
7184 	return 0;
7185 } /* dns_res_merge() */
7186 
7187 
dns_res_glue(struct dns_resolver * R,struct dns_packet * Q)7188 static struct dns_packet *dns_res_glue(struct dns_resolver *R, struct dns_packet *Q) {
7189 	struct dns_packet *P	= dns_p_new(512);
7190 	char qname[DNS_D_MAXNAME + 1];
7191 	size_t qlen;
7192 	enum dns_type qtype;
7193 	struct dns_rr rr;
7194 	unsigned sp;
7195 	int error;
7196 
7197 	if (!(qlen = dns_d_expand(qname, sizeof qname, 12, Q, &error))
7198 	||  qlen >= sizeof qname)
7199 		return 0;
7200 
7201 	if (!(qtype = dns_rr_type(12, Q)))
7202 		return 0;
7203 
7204 	if ((error = dns_p_push(P, DNS_S_QD, qname, strlen(qname), qtype, DNS_C_IN, 0, 0)))
7205 		return 0;
7206 
7207 	for (sp = 0; sp <= R->sp; sp++) {
7208 		if (!R->stack[sp].answer)
7209 			continue;
7210 
7211 		dns_rr_foreach(&rr, R->stack[sp].answer, .name = qname, .type = qtype, .section = (DNS_S_ALL & ~DNS_S_QD)) {
7212 			rr.section	= DNS_S_AN;
7213 
7214 			if ((error = dns_rr_copy(P, &rr, R->stack[sp].answer)))
7215 				return 0;
7216 		}
7217 	}
7218 
7219 	if (dns_p_count(P, DNS_S_AN) > 0)
7220 		goto copy;
7221 
7222 	/* Otherwise, look for a CNAME */
7223 	for (sp = 0; sp <= R->sp; sp++) {
7224 		if (!R->stack[sp].answer)
7225 			continue;
7226 
7227 		dns_rr_foreach(&rr, R->stack[sp].answer, .name = qname, .type = DNS_T_CNAME, .section = (DNS_S_ALL & ~DNS_S_QD)) {
7228 			rr.section	= DNS_S_AN;
7229 
7230 			if ((error = dns_rr_copy(P, &rr, R->stack[sp].answer)))
7231 				return 0;
7232 		}
7233 	}
7234 
7235 	if (!dns_p_count(P, DNS_S_AN))
7236 		return 0;
7237 
7238 copy:
7239 	return dns_p_copy(dns_p_make(P->end, &error), P);
7240 } /* dns_res_glue() */
7241 
7242 
7243 /*
7244  * Sort NS records by three criteria:
7245  *
7246  * 	1) Whether glue is present.
7247  * 	2) Whether glue record is original or of recursive lookup.
7248  * 	3) Randomly shuffle records which share the above criteria.
7249  *
7250  * NOTE: Assumes only NS records passed, AND ASSUMES no new NS records will
7251  *       be added during an iteration.
7252  *
7253  * FIXME: Only groks A glue, not AAAA glue.
7254  */
dns_res_nameserv_cmp(struct dns_rr * a,struct dns_rr * b,struct dns_rr_i * i,struct dns_packet * P)7255 static int dns_res_nameserv_cmp(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) {
7256 	_Bool glued[2] = { 0 };
7257 	struct dns_rr x = { 0 }, y = { 0 };
7258 	struct dns_ns ns;
7259 	int cmp, error;
7260 
7261 	if (!(error = dns_ns_parse(&ns, a, P)))
7262 		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);
7263 
7264 	if (!(error = dns_ns_parse(&ns, b, P)))
7265 		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);
7266 
7267 	if ((cmp = glued[1] - glued[0])) {
7268 		return cmp;
7269 	} else if ((cmp = (dns_rr_offset(&y) < i->args[0]) - (dns_rr_offset(&x) < i->args[0]))) {
7270 		return cmp;
7271 	} else {
7272 		return dns_rr_i_shuffle(a, b, i, P);
7273 	}
7274 } /* dns_res_nameserv_cmp() */
7275 
7276 
7277 #define dgoto(sp, i)	\
7278 	do { R->stack[(sp)].state = (i); goto exec; } while (0)
7279 
dns_res_exec(struct dns_resolver * R)7280 static int dns_res_exec(struct dns_resolver *R) {
7281 	struct dns_res_frame *F;
7282 	struct dns_packet *P;
7283 	union {
7284 		char host[DNS_D_MAXNAME + 1];
7285 		char name[DNS_D_MAXNAME + 1];
7286 		struct dns_ns ns;
7287 		struct dns_cname cname;
7288 	} u;
7289 	size_t len;
7290 	struct dns_rr rr;
7291 	int error;
7292 
7293 exec:
7294 
7295 	F	= &R->stack[R->sp];
7296 
7297 	switch (F->state) {
7298 	case DNS_R_INIT:
7299 		F->state++;
7300 		/* FALL THROUGH */
7301 	case DNS_R_GLUE:
7302 		if (R->sp == 0)
7303 			dgoto(R->sp, DNS_R_SWITCH);
7304 
7305 		if (!F->query)
7306 			goto noquery;
7307 
7308 		if (!(F->answer = dns_res_glue(R, F->query)))
7309 			dgoto(R->sp, DNS_R_SWITCH);
7310 
7311 		if (!(len = dns_d_expand(u.name, sizeof u.name, 12, F->query, &error)))
7312 			goto error;
7313 		else if (len >= sizeof u.name)
7314 			goto toolong;
7315 
7316 		dns_rr_foreach(&rr, F->answer, .name = u.name, .type = dns_rr_type(12, F->query), .section = DNS_S_AN) {
7317 			dgoto(R->sp, DNS_R_FINISH);
7318 		}
7319 
7320 		dns_rr_foreach(&rr, F->answer, .name = u.name, .type = DNS_T_CNAME, .section = DNS_S_AN) {
7321 			F->ans_cname	= rr;
7322 
7323 			dgoto(R->sp, DNS_R_CNAME0_A);
7324 		}
7325 
7326 		F->state++;
7327 		/* FALL THROUGH */
7328 	case DNS_R_SWITCH:
7329 		while (F->which < (int)sizeof R->resconf->lookup && R->resconf->lookup[F->which]) {
7330 			switch (R->resconf->lookup[F->which++]) {
7331 			case 'b': case 'B':
7332 				dgoto(R->sp, DNS_R_BIND);
7333 			case 'f': case 'F':
7334 				dgoto(R->sp, DNS_R_FILE);
7335 			case 'c': case 'C':
7336 				if (R->cache)
7337 					dgoto(R->sp, DNS_R_CACHE);
7338 
7339 				break;
7340 			default:
7341 				break;
7342 			}
7343 		}
7344 
7345 		/*
7346 		 * FIXME: Examine more closely whether our logic is correct
7347 		 * and DNS_R_SERVFAIL is the correct default response.
7348 		 *
7349 		 * Case 1: We got here because we never got an answer on the
7350 		 *   wire. All queries timed-out and we reached maximum
7351 		 *   attempts count. See DNS_R_FOREACH_NS. In that case
7352 		 *   DNS_R_SERVFAIL is the correct state, unless we want to
7353 		 *   return DNS_ETIMEDOUT.
7354 		 *
7355 		 * Case 2: We were a stub resolver and got an unsatisfactory
7356 		 *   answer (empty ANSWER section) which caused us to jump
7357 		 *   back to DNS_R_SEARCH and ultimately to DNS_R_SWITCH. We
7358 		 *   return the answer returned from the wire, which we
7359 		 *   stashed in R->nodata.
7360 		 *
7361 		 * Case 3: We reached maximum attempts count as in case #1,
7362 		 *   but never got an authoritative response which caused us
7363 		 *   to short-circuit. See end of DNS_R_QUERY_A case. We
7364 		 *   should probably prepare R->nodata as in case #2.
7365 		 */
7366 		if (R->sp == 0 && R->nodata) { /* XXX: can we just return nodata regardless? */
7367 			dns_p_movptr(&F->answer, &R->nodata);
7368 			dgoto(R->sp, DNS_R_FINISH);
7369 		}
7370 
7371 		dgoto(R->sp, DNS_R_SERVFAIL);
7372 	case DNS_R_FILE:
7373 		if (R->sp > 0) {
7374 			if (!dns_p_setptr(&F->answer, dns_hosts_query(R->hosts, F->query, &error)))
7375 				goto error;
7376 
7377 			if (dns_p_count(F->answer, DNS_S_AN) > 0)
7378 				dgoto(R->sp, DNS_R_FINISH);
7379 
7380 			dns_p_setptr(&F->answer, NULL);
7381 		} else {
7382 			R->search = 0;
7383 
7384 			while ((len = dns_resconf_search(u.name, sizeof u.name, R->qname, R->qlen, R->resconf, &R->search))) {
7385 				if ((error = dns_q_make2(&F->query, u.name, len, R->qtype, R->qclass, F->qflags)))
7386 					goto error;
7387 
7388 				if (!dns_p_setptr(&F->answer, dns_hosts_query(R->hosts, F->query, &error)))
7389 					goto error;
7390 
7391 				if (dns_p_count(F->answer, DNS_S_AN) > 0)
7392 					dgoto(R->sp, DNS_R_FINISH);
7393 
7394 				dns_p_setptr(&F->answer, NULL);
7395 			}
7396 		}
7397 
7398 		dgoto(R->sp, DNS_R_SWITCH);
7399 	case DNS_R_CACHE:
7400 		error = 0;
7401 
7402 		if (!F->query && (error = dns_q_make(&F->query, R->qname, R->qtype, R->qclass, F->qflags)))
7403 			goto error;
7404 
7405 		if (dns_p_setptr(&F->answer, R->cache->query(F->query, R->cache, &error))) {
7406 			if (dns_p_count(F->answer, DNS_S_AN) > 0)
7407 				dgoto(R->sp, DNS_R_FINISH);
7408 
7409 			dns_p_setptr(&F->answer, NULL);
7410 
7411 			dgoto(R->sp, DNS_R_SWITCH);
7412 		} else if (error)
7413 			goto error;
7414 
7415 		F->state++;
7416 		/* FALL THROUGH */
7417 	case DNS_R_SUBMIT:
7418 		if ((error = R->cache->submit(F->query, R->cache)))
7419 			goto error;
7420 
7421 		F->state++;
7422 		/* FALL THROUGH */
7423 	case DNS_R_CHECK:
7424 		if ((error = R->cache->check(R->cache)))
7425 			goto error;
7426 
7427 		F->state++;
7428 		/* FALL THROUGH */
7429 	case DNS_R_FETCH:
7430 		error = 0;
7431 
7432 		if (dns_p_setptr(&F->answer, R->cache->fetch(R->cache, &error))) {
7433 			if (dns_p_count(F->answer, DNS_S_AN) > 0)
7434 				dgoto(R->sp, DNS_R_FINISH);
7435 
7436 			dns_p_setptr(&F->answer, NULL);
7437 
7438 			dgoto(R->sp, DNS_R_SWITCH);
7439 		} else if (error)
7440 			goto error;
7441 
7442 		dgoto(R->sp, DNS_R_SWITCH);
7443 	case DNS_R_BIND:
7444 		if (R->sp > 0) {
7445 			if (!F->query)
7446 				goto noquery;
7447 
7448 			dgoto(R->sp, DNS_R_HINTS);
7449 		}
7450 
7451 		R->search = 0;
7452 
7453 		F->state++;
7454 		/* FALL THROUGH */
7455 	case DNS_R_SEARCH:
7456 		/*
7457 		 * XXX: We probably should only apply the domain search
7458 		 * algorithm if R->sp == 0.
7459 		 */
7460 		if (!(len = dns_resconf_search(u.name, sizeof u.name, R->qname, R->qlen, R->resconf, &R->search)))
7461 			dgoto(R->sp, DNS_R_SWITCH);
7462 
7463 		if ((error = dns_q_make2(&F->query, u.name, len, R->qtype, R->qclass, F->qflags)))
7464 			goto error;
7465 
7466 		F->state++;
7467 		/* FALL THROUGH */
7468 	case DNS_R_HINTS:
7469 		if (!dns_p_setptr(&F->hints, dns_hints_query(R->hints, F->query, &error)))
7470 			goto error;
7471 
7472 		F->state++;
7473 		/* FALL THROUGH */
7474 	case DNS_R_ITERATE:
7475 		dns_rr_i_init(&F->hints_i, F->hints);
7476 
7477 		F->hints_i.section	= DNS_S_AUTHORITY;
7478 		F->hints_i.type		= DNS_T_NS;
7479 		F->hints_i.sort		= &dns_res_nameserv_cmp;
7480 		F->hints_i.args[0]	= F->hints->end;
7481 
7482 		F->state++;
7483 		/* FALL THROUGH */
7484 	case DNS_R_FOREACH_NS:
7485 		dns_rr_i_save(&F->hints_i);
7486 
7487 		/* Load our next nameserver host. */
7488 		if (!dns_rr_grep(&F->hints_ns, 1, &F->hints_i, F->hints, &error)) {
7489 			if (++F->attempts < R->resconf->options.attempts)
7490 				dgoto(R->sp, DNS_R_ITERATE);
7491 
7492 			dgoto(R->sp, DNS_R_SWITCH);
7493 		}
7494 
7495 		dns_rr_i_init(&F->hints_j, F->hints);
7496 
7497 		/* Assume there are glue records */
7498 		dgoto(R->sp, DNS_R_FOREACH_A);
7499 	case DNS_R_RESOLV0_NS:
7500 		/* Have we reached our max depth? */
7501 		if (&F[1] >= endof(R->stack))
7502 			dgoto(R->sp, DNS_R_FOREACH_NS);
7503 
7504 		if ((error = dns_ns_parse(&u.ns, &F->hints_ns, F->hints)))
7505 			goto error;
7506 		if ((error = dns_res_frame_prepare(R, &F[1], u.ns.host, DNS_T_A, DNS_C_IN)))
7507 			goto error;
7508 
7509 		F->state++;
7510 
7511 		dgoto(++R->sp, DNS_R_INIT);
7512 	case DNS_R_RESOLV1_NS:
7513 		if (!(len = dns_d_expand(u.host, sizeof u.host, 12, F[1].query, &error)))
7514 			goto error;
7515 		else if (len >= sizeof u.host)
7516 			goto toolong;
7517 
7518 		dns_rr_foreach(&rr, F[1].answer, .name = u.host, .type = DNS_T_A, .section = (DNS_S_ALL & ~DNS_S_QD)) {
7519 			rr.section	= DNS_S_AR;
7520 
7521 			if ((error = dns_rr_copy(F->hints, &rr, F[1].answer)))
7522 				goto error;
7523 
7524 			dns_rr_i_rewind(&F->hints_i);	/* Now there's glue. */
7525 		}
7526 
7527 		dgoto(R->sp, DNS_R_FOREACH_NS);
7528 	case DNS_R_FOREACH_A: {
7529 		struct dns_a a;
7530 		struct sockaddr_in sin;
7531 
7532 		/*
7533 		 * NOTE: Iterator initialized in DNS_R_FOREACH_NS because
7534 		 * this state is re-entrant, but we need to reset
7535 		 * .name to a valid pointer each time.
7536 		 */
7537 		if ((error = dns_ns_parse(&u.ns, &F->hints_ns, F->hints)))
7538 			goto error;
7539 
7540 		F->hints_j.name		= u.ns.host;
7541 		F->hints_j.type		= DNS_T_A;
7542 		F->hints_j.section	= DNS_S_ALL & ~DNS_S_QD;
7543 
7544 		if (!dns_rr_grep(&rr, 1, &F->hints_j, F->hints, &error)) {
7545 			if (!dns_rr_i_count(&F->hints_j))
7546 				dgoto(R->sp, DNS_R_RESOLV0_NS);
7547 
7548 			dgoto(R->sp, DNS_R_FOREACH_NS);
7549 		}
7550 
7551 		if ((error = dns_a_parse(&a, &rr, F->hints)))
7552 			goto error;
7553 
7554 		sin.sin_family	= AF_INET;
7555 		sin.sin_addr	= a.addr;
7556 		if (R->sp == 0)
7557 			sin.sin_port = dns_hints_port(R->hints, AF_INET, &sin.sin_addr);
7558 		else
7559 			sin.sin_port = htons(53);
7560 
7561 		if (DNS_DEBUG) {
7562 			char addr[INET_ADDRSTRLEN + 1];
7563 			dns_a_print(addr, sizeof addr, &a);
7564 			dns_header(F->query)->qid = dns_so_mkqid(&R->so);
7565 			DNS_SHOW(F->query, "ASKING: %s/%s @ DEPTH: %u)", u.ns.host, addr, R->sp);
7566 		}
7567 
7568 		if ((error = dns_so_submit(&R->so, F->query, (struct sockaddr *)&sin)))
7569 			goto error;
7570 
7571 		F->state++;
7572 	}
7573 	/* FALL THROUGH */
7574 	case DNS_R_QUERY_A:
7575 		if (dns_so_elapsed(&R->so) >= dns_resconf_timeout(R->resconf))
7576 			dgoto(R->sp, DNS_R_FOREACH_A);
7577 
7578 		if ((error = dns_so_check(&R->so)))
7579 			goto error;
7580 
7581 		if (!dns_p_setptr(&F->answer, dns_so_fetch(&R->so, &error)))
7582 			goto error;
7583 
7584 		if (DNS_DEBUG) {
7585 			DNS_SHOW(F->answer, "ANSWER @ DEPTH: %u)", R->sp);
7586 		}
7587 
7588 		if (dns_p_rcode(F->answer) == DNS_RC_FORMERR ||
7589 		    dns_p_rcode(F->answer) == DNS_RC_NOTIMP ||
7590 		    dns_p_rcode(F->answer) == DNS_RC_BADVERS) {
7591 			/* Temporarily disable EDNS0 and try again. */
7592 			if (F->qflags & DNS_Q_EDNS0) {
7593 				F->qflags &= ~DNS_Q_EDNS0;
7594 				if ((error = dns_q_remake(&F->query, F->qflags)))
7595 					goto error;
7596 
7597 				dgoto(R->sp, DNS_R_FOREACH_A);
7598 			}
7599 		}
7600 
7601 		if ((error = dns_rr_parse(&rr, 12, F->query)))
7602 			goto error;
7603 
7604 		if (!(len = dns_d_expand(u.name, sizeof u.name, rr.dn.p, F->query, &error)))
7605 			goto error;
7606 		else if (len >= sizeof u.name)
7607 			goto toolong;
7608 
7609 		dns_rr_foreach(&rr, F->answer, .section = DNS_S_AN, .name = u.name, .type = rr.type) {
7610 			dgoto(R->sp, DNS_R_FINISH);	/* Found */
7611 		}
7612 
7613 		dns_rr_foreach(&rr, F->answer, .section = DNS_S_AN, .name = u.name, .type = DNS_T_CNAME) {
7614 			F->ans_cname	= rr;
7615 
7616 			dgoto(R->sp, DNS_R_CNAME0_A);
7617 		}
7618 
7619 		/*
7620 		 * XXX: The condition here should probably check whether
7621 		 * R->sp == 0, because DNS_R_SEARCH runs regardless of
7622 		 * options.recurse. See DNS_R_BIND.
7623 		 */
7624 		if (!R->resconf->options.recurse) {
7625 			/* Make first answer our tentative answer */
7626 			if (!R->nodata)
7627 				dns_p_movptr(&R->nodata, &F->answer);
7628 
7629 			dgoto(R->sp, DNS_R_SEARCH);
7630 		}
7631 
7632 		dns_rr_foreach(&rr, F->answer, .section = DNS_S_NS, .type = DNS_T_NS) {
7633 			dns_p_movptr(&F->hints, &F->answer);
7634 
7635 			dgoto(R->sp, DNS_R_ITERATE);
7636 		}
7637 
7638 		/* XXX: Should this go further up? */
7639 		if (dns_header(F->answer)->aa)
7640 			dgoto(R->sp, DNS_R_FINISH);
7641 
7642 		/* XXX: Should we copy F->answer to R->nodata? */
7643 
7644 		dgoto(R->sp, DNS_R_FOREACH_A);
7645 	case DNS_R_CNAME0_A:
7646 		if (&F[1] >= endof(R->stack))
7647 			dgoto(R->sp, DNS_R_FINISH);
7648 
7649 		if ((error = dns_cname_parse(&u.cname, &F->ans_cname, F->answer)))
7650 			goto error;
7651 		if ((error = dns_res_frame_prepare(R, &F[1], u.cname.host, dns_rr_type(12, F->query), DNS_C_IN)))
7652 			goto error;
7653 
7654 		F->state++;
7655 
7656 		dgoto(++R->sp, DNS_R_INIT);
7657 	case DNS_R_CNAME1_A:
7658 		if (!(P = dns_res_merge(F->answer, F[1].answer, &error)))
7659 			goto error;
7660 
7661 		dns_p_setptr(&F->answer, P);
7662 
7663 		dgoto(R->sp, DNS_R_FINISH);
7664 	case DNS_R_FINISH:
7665 		if (!F->answer)
7666 			goto noanswer;
7667 
7668 		if (!R->resconf->options.smart || R->sp > 0)
7669 			dgoto(R->sp, DNS_R_DONE);
7670 
7671 		R->smart.section	= DNS_S_AN;
7672 		R->smart.type		= R->qtype;
7673 
7674 		dns_rr_i_init(&R->smart, F->answer);
7675 
7676 		F->state++;
7677 		/* FALL THROUGH */
7678 	case DNS_R_SMART0_A:
7679 		if (&F[1] >= endof(R->stack))
7680 			dgoto(R->sp, DNS_R_DONE);
7681 
7682 		while (dns_rr_grep(&rr, 1, &R->smart, F->answer, &error)) {
7683 			union {
7684 				struct dns_ns ns;
7685 				struct dns_mx mx;
7686 				struct dns_srv srv;
7687 			} rd;
7688 			const char *qname;
7689 			enum dns_type qtype;
7690 			enum dns_class qclass;
7691 
7692 			switch (rr.type) {
7693 			case DNS_T_NS:
7694 				if ((error = dns_ns_parse(&rd.ns, &rr, F->answer)))
7695 					goto error;
7696 
7697 				qname	= rd.ns.host;
7698 				qtype	= DNS_T_A;
7699 				qclass	= DNS_C_IN;
7700 
7701 				break;
7702 			case DNS_T_MX:
7703 				if ((error = dns_mx_parse(&rd.mx, &rr, F->answer)))
7704 					goto error;
7705 
7706 				qname	= rd.mx.host;
7707 				qtype	= DNS_T_A;
7708 				qclass	= DNS_C_IN;
7709 
7710 				break;
7711 			case DNS_T_SRV:
7712 				if ((error = dns_srv_parse(&rd.srv, &rr, F->answer)))
7713 					goto error;
7714 
7715 				qname	= rd.srv.target;
7716 				qtype	= DNS_T_A;
7717 				qclass	= DNS_C_IN;
7718 
7719 				break;
7720 			default:
7721 				continue;
7722 			} /* switch() */
7723 
7724 			if ((error = dns_res_frame_prepare(R, &F[1], qname, qtype, qclass)))
7725 				goto error;
7726 
7727 			F->state++;
7728 
7729 			dgoto(++R->sp, DNS_R_INIT);
7730 		} /* while() */
7731 
7732 		/*
7733 		 * NOTE: SMTP specification says to fallback to A record.
7734 		 *
7735 		 * XXX: Should we add a mock MX answer?
7736 		 */
7737 		if (R->qtype == DNS_T_MX && R->smart.state.count == 0) {
7738 			if ((error = dns_res_frame_prepare(R, &F[1], R->qname, DNS_T_A, DNS_C_IN)))
7739 				goto error;
7740 
7741 			R->smart.state.count++;
7742 			F->state++;
7743 
7744 			dgoto(++R->sp, DNS_R_INIT);
7745 		}
7746 
7747 		dgoto(R->sp, DNS_R_DONE);
7748 	case DNS_R_SMART1_A:
7749 		if (!F[1].answer)
7750 			goto noanswer;
7751 
7752 		/*
7753 		 * FIXME: For CNAME chains (which are typically illegal in
7754 		 * this context), we should rewrite the record host name
7755 		 * to the original smart qname. All the user cares about
7756 		 * is locating that A/AAAA record.
7757 		 */
7758 		dns_rr_foreach(&rr, F[1].answer, .section = DNS_S_AN, .type = DNS_T_A) {
7759 			rr.section	= DNS_S_AR;
7760 
7761 			if (dns_rr_exists(&rr, F[1].answer, F->answer))
7762 				continue;
7763 
7764 			while ((error = dns_rr_copy(F->answer, &rr, F[1].answer))) {
7765 				if (error != DNS_ENOBUFS)
7766 					goto error;
7767 				if ((error = dns_p_grow(&F->answer)))
7768 					goto error;
7769 			}
7770 		}
7771 
7772 		dgoto(R->sp, DNS_R_SMART0_A);
7773 	case DNS_R_DONE:
7774 		if (!F->answer)
7775 			goto noanswer;
7776 
7777 		if (R->sp > 0)
7778 			dgoto(--R->sp, F[-1].state);
7779 
7780 		break;
7781 	case DNS_R_SERVFAIL:
7782 		if (!dns_p_setptr(&F->answer, dns_p_make(DNS_P_QBUFSIZ, &error)))
7783 			goto error;
7784 
7785 		dns_header(F->answer)->qr	= 1;
7786 		dns_header(F->answer)->rcode	= DNS_RC_SERVFAIL;
7787 
7788 		if ((error = dns_p_push(F->answer, DNS_S_QD, R->qname, strlen(R->qname), R->qtype, R->qclass, 0, 0)))
7789 			goto error;
7790 
7791 		dgoto(R->sp, DNS_R_DONE);
7792 	default:
7793 		error	= EINVAL;
7794 
7795 		goto error;
7796 	} /* switch () */
7797 
7798 	return 0;
7799 noquery:
7800 	error = DNS_ENOQUERY;
7801 
7802 	goto error;
7803 noanswer:
7804 	error = DNS_ENOANSWER;
7805 
7806 	goto error;
7807 toolong:
7808 	error = DNS_EILLEGAL;
7809 
7810 	/* FALL THROUGH */
7811 error:
7812 	return error;
7813 } /* dns_res_exec() */
7814 
7815 #undef goto
7816 
7817 
dns_res_clear(struct dns_resolver * R)7818 void dns_res_clear(struct dns_resolver *R) {
7819 	switch (R->stack[R->sp].state) {
7820 	case DNS_R_CHECK:
7821 		R->cache->clear(R->cache);
7822 		break;
7823 	default:
7824 		dns_so_clear(&R->so);
7825 		break;
7826 	}
7827 } /* dns_res_clear() */
7828 
7829 
dns_res_events2(struct dns_resolver * R,enum dns_events type)7830 static int dns_res_events2(struct dns_resolver *R, enum dns_events type) {
7831 	int events;
7832 
7833 	switch (R->stack[R->sp].state) {
7834 	case DNS_R_CHECK:
7835 		events = R->cache->events(R->cache);
7836 
7837 		return (type == DNS_LIBEVENT)? DNS_POLL2EV(events) : events;
7838 	default:
7839 		return dns_so_events2(&R->so, type);
7840 	}
7841 } /* dns_res_events2() */
7842 
7843 
dns_res_events(struct dns_resolver * R)7844 int dns_res_events(struct dns_resolver *R) {
7845 	return dns_res_events2(R, R->so.opts.events);
7846 } /* dns_res_events() */
7847 
7848 
dns_res_pollfd(struct dns_resolver * R)7849 int dns_res_pollfd(struct dns_resolver *R) {
7850 	switch (R->stack[R->sp].state) {
7851 	case DNS_R_CHECK:
7852 		return R->cache->pollfd(R->cache);
7853 	default:
7854 		return dns_so_pollfd(&R->so);
7855 	}
7856 } /* dns_res_pollfd() */
7857 
7858 
dns_res_timeout(struct dns_resolver * R)7859 time_t dns_res_timeout(struct dns_resolver *R) {
7860 	time_t elapsed;
7861 
7862 	switch (R->stack[R->sp].state) {
7863 #if 0
7864 	case DNS_R_QUERY_AAAA:
7865 #endif
7866 	case DNS_R_QUERY_A:
7867 		elapsed = dns_so_elapsed(&R->so);
7868 
7869 		if (elapsed <= dns_resconf_timeout(R->resconf))
7870 			return R->resconf->options.timeout - elapsed;
7871 
7872 		break;
7873 	default:
7874 		break;
7875 	} /* switch() */
7876 
7877 	/*
7878 	 * NOTE: We're not in a pollable state, or the user code hasn't
7879 	 * called dns_res_check properly. The calling code is probably
7880 	 * broken. Put them into a slow-burn pattern.
7881 	 */
7882 	return 1;
7883 } /* dns_res_timeout() */
7884 
7885 
dns_res_elapsed(struct dns_resolver * R)7886 time_t dns_res_elapsed(struct dns_resolver *R) {
7887 	return dns_elapsed(&R->elapsed);
7888 } /* dns_res_elapsed() */
7889 
7890 
dns_res_poll(struct dns_resolver * R,int timeout)7891 int dns_res_poll(struct dns_resolver *R, int timeout) {
7892 	return dns_poll(dns_res_pollfd(R), dns_res_events2(R, DNS_SYSPOLL), timeout);
7893 } /* dns_res_poll() */
7894 
7895 
dns_res_submit2(struct dns_resolver * R,const char * qname,size_t qlen,enum dns_type qtype,enum dns_class qclass)7896 int dns_res_submit2(struct dns_resolver *R, const char *qname, size_t qlen, enum dns_type qtype, enum dns_class qclass) {
7897 	dns_res_reset(R);
7898 
7899 	/* Don't anchor; that can conflict with searchlist generation. */
7900 	dns_d_init(R->qname, sizeof R->qname, qname, (R->qlen = qlen), 0);
7901 
7902 	R->qtype	= qtype;
7903 	R->qclass	= qclass;
7904 
7905 	dns_begin(&R->elapsed);
7906 
7907 	return 0;
7908 } /* dns_res_submit2() */
7909 
7910 
dns_res_submit(struct dns_resolver * R,const char * qname,enum dns_type qtype,enum dns_class qclass)7911 int dns_res_submit(struct dns_resolver *R, const char *qname, enum dns_type qtype, enum dns_class qclass) {
7912 	return dns_res_submit2(R, qname, strlen(qname), qtype, qclass);
7913 } /* dns_res_submit() */
7914 
7915 
dns_res_check(struct dns_resolver * R)7916 int dns_res_check(struct dns_resolver *R) {
7917 	int error;
7918 
7919 	if (R->stack[0].state != DNS_R_DONE) {
7920 		if ((error = dns_res_exec(R)))
7921 			return error;
7922 	}
7923 
7924 	return 0;
7925 } /* dns_res_check() */
7926 
7927 
dns_res_fetch(struct dns_resolver * R,int * error)7928 struct dns_packet *dns_res_fetch(struct dns_resolver *R, int *error) {
7929 	struct dns_packet *P = NULL;
7930 
7931 	if (R->stack[0].state != DNS_R_DONE)
7932 		return *error = DNS_EUNKNOWN, (void *)0;
7933 
7934 	if (!dns_p_movptr(&P, &R->stack[0].answer))
7935 		return *error = DNS_EFETCHED, (void *)0;
7936 
7937 	return P;
7938 } /* dns_res_fetch() */
7939 
7940 
dns_res_fetch_and_study(struct dns_resolver * R,int * _error)7941 static struct dns_packet *dns_res_fetch_and_study(struct dns_resolver *R, int *_error) {
7942 	struct dns_packet *P = NULL;
7943 	int error;
7944 
7945 	if (!(P = dns_res_fetch(R, &error)))
7946 		goto error;
7947 	if ((error = dns_p_study(P)))
7948 		goto error;
7949 
7950 	return P;
7951 error:
7952 	*_error = error;
7953 
7954 	dns_p_free(P);
7955 
7956 	return NULL;
7957 } /* dns_res_fetch_and_study() */
7958 
7959 
dns_res_query(struct dns_resolver * res,const char * qname,enum dns_type qtype,enum dns_class qclass,int timeout,int * error_)7960 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_) {
7961 	int error;
7962 
7963 	if ((error = dns_res_submit(res, qname, qtype, qclass)))
7964 		goto error;
7965 
7966 	while ((error = dns_res_check(res))) {
7967 		if (dns_res_elapsed(res) > timeout)
7968 			error = DNS_ETIMEDOUT;
7969 
7970 		if (error != DNS_EAGAIN)
7971 			goto error;
7972 
7973 		if ((error = dns_res_poll(res, 1)))
7974 			goto error;
7975 	}
7976 
7977 	return dns_res_fetch(res, error_);
7978 error:
7979 	*error_ = error;
7980 
7981 	return 0;
7982 } /* dns_res_query() */
7983 
7984 
dns_res_stat(struct dns_resolver * res)7985 const struct dns_stat *dns_res_stat(struct dns_resolver *res) {
7986 	return dns_so_stat(&res->so);
7987 } /* dns_res_stat() */
7988 
7989 
dns_res_sethints(struct dns_resolver * res,struct dns_hints * hints)7990 void dns_res_sethints(struct dns_resolver *res, struct dns_hints *hints) {
7991 	dns_hints_acquire(hints); /* acquire first in case same hints object */
7992 	dns_hints_close(res->hints);
7993 	res->hints = hints;
7994 } /* dns_res_sethints() */
7995 
7996 
7997 /*
7998  * A D D R I N F O  R O U T I N E S
7999  *
8000  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8001 
8002 struct dns_addrinfo {
8003 	struct addrinfo hints;
8004 	struct dns_resolver *res;
8005 
8006 	char qname[DNS_D_MAXNAME + 1];
8007 	enum dns_type qtype;
8008 	unsigned short qport, port;
8009 
8010 	struct {
8011 		unsigned long todo;
8012 		int state;
8013 		int atype;
8014 		enum dns_type qtype;
8015 	} af;
8016 
8017 	struct dns_packet *answer;
8018 	struct dns_packet *glue;
8019 
8020 	struct dns_rr_i i, g;
8021 	struct dns_rr rr;
8022 
8023 	char cname[DNS_D_MAXNAME + 1];
8024 	char i_cname[DNS_D_MAXNAME + 1], g_cname[DNS_D_MAXNAME + 1];
8025 
8026 	int g_depth;
8027 
8028 	int state;
8029 	int found;
8030 
8031 	struct dns_stat st;
8032 }; /* struct dns_addrinfo */
8033 
8034 
8035 #define DNS_AI_AFMAX 32
8036 #define DNS_AI_AF2INDEX(af) (1UL << ((af) - 1))
8037 
dns_ai_af2index(int af)8038 static inline unsigned long dns_ai_af2index(int af) {
8039 	dns_static_assert(dns_same_type(unsigned long, DNS_AI_AF2INDEX(1), 1), "internal type mismatch");
8040 	dns_static_assert(dns_same_type(unsigned long, ((struct dns_addrinfo *)0)->af.todo, 1), "internal type mismatch");
8041 
8042 	return (af > 0 && af <= DNS_AI_AFMAX)? DNS_AI_AF2INDEX(af) : 0;
8043 }
8044 
dns_ai_setaf(struct dns_addrinfo * ai,int af,int qtype)8045 static int dns_ai_setaf(struct dns_addrinfo *ai, int af, int qtype) {
8046 	ai->af.atype = af;
8047 	ai->af.qtype = qtype;
8048 
8049 	ai->af.todo &= ~dns_ai_af2index(af);
8050 
8051 	return af;
8052 } /* dns_ai_setaf() */
8053 
8054 #define DNS_SM_RESTORE \
8055 	do { pc = 0xff & (ai->af.state >> 0); i = 0xff & (ai->af.state >> 8); } while (0)
8056 #define DNS_SM_SAVE \
8057 	do { ai->af.state = ((0xff & pc) << 0) | ((0xff & i) << 8); } while (0)
8058 
dns_ai_nextaf(struct dns_addrinfo * ai)8059 static int dns_ai_nextaf(struct dns_addrinfo *ai) {
8060 	int i, pc;
8061 
8062 	dns_static_assert(AF_UNSPEC == 0, "AF_UNSPEC constant not 0");
8063 	dns_static_assert(AF_INET <= DNS_AI_AFMAX, "AF_INET constant too large");
8064 	dns_static_assert(AF_INET6 <= DNS_AI_AFMAX, "AF_INET6 constant too large");
8065 
8066 	DNS_SM_ENTER;
8067 
8068 	if (ai->res) {
8069 		/*
8070 		 * NB: On OpenBSD, at least, the types of entries resolved
8071 		 * is the intersection of the /etc/resolv.conf families and
8072 		 * the families permitted by the .ai_type hint. So if
8073 		 * /etc/resolv.conf has "family inet4" and .ai_type
8074 		 * is AF_INET6, then the address ::1 will return 0 entries
8075 		 * even if AI_NUMERICHOST is specified in .ai_flags.
8076 		 */
8077 		while (i < (int)lengthof(ai->res->resconf->family)) {
8078 			int af = ai->res->resconf->family[i++];
8079 
8080 			if (af == AF_UNSPEC) {
8081 				DNS_SM_EXIT;
8082 			} else if (af < 0 || af > DNS_AI_AFMAX) {
8083 				continue;
8084 			} else if (!(DNS_AI_AF2INDEX(af) & ai->af.todo)) {
8085 				continue;
8086 			} else if (af == AF_INET) {
8087 				DNS_SM_YIELD(dns_ai_setaf(ai, AF_INET, DNS_T_A));
8088 			} else if (af == AF_INET6) {
8089 				DNS_SM_YIELD(dns_ai_setaf(ai, AF_INET6, DNS_T_AAAA));
8090 			}
8091 		}
8092 	} else {
8093 		/*
8094 		 * NB: If we get here than AI_NUMERICFLAGS should be set and
8095 		 * order shouldn't matter.
8096 		 */
8097 		if (DNS_AI_AF2INDEX(AF_INET) & ai->af.todo)
8098 			DNS_SM_YIELD(dns_ai_setaf(ai, AF_INET, DNS_T_A));
8099 		if (DNS_AI_AF2INDEX(AF_INET6) & ai->af.todo)
8100 			DNS_SM_YIELD(dns_ai_setaf(ai, AF_INET6, DNS_T_AAAA));
8101 	}
8102 
8103 	DNS_SM_LEAVE;
8104 
8105 	return dns_ai_setaf(ai, AF_UNSPEC, 0);
8106 } /* dns_ai_nextaf() */
8107 
8108 #undef DNS_SM_RESTORE
8109 #undef DNS_SM_SAVE
8110 
dns_ai_qtype(struct dns_addrinfo * ai)8111 static enum dns_type dns_ai_qtype(struct dns_addrinfo *ai) {
8112 	return (ai->qtype)? ai->qtype : ai->af.qtype;
8113 } /* dns_ai_qtype() */
8114 
8115 
dns_ai_parseport(unsigned short * port,const char * serv,const struct addrinfo * hints)8116 static dns_error_t dns_ai_parseport(unsigned short *port, const char *serv, const struct addrinfo *hints) {
8117 	const char *cp = serv;
8118 	unsigned long n = 0;
8119 
8120 	while (*cp >= '0' && *cp <= '9' && n < 65536) {
8121 		n *= 10;
8122 		n += *cp++ - '0';
8123 	}
8124 
8125 	if (*cp == '\0') {
8126 		if (cp == serv || n >= 65536)
8127 			return DNS_ESERVICE;
8128 
8129 		*port = n;
8130 
8131 		return 0;
8132 	}
8133 
8134 	if (hints->ai_flags & AI_NUMERICSERV)
8135 		return DNS_ESERVICE;
8136 
8137 	/* TODO: try getaddrinfo(NULL, serv, { .ai_flags = AI_NUMERICSERV }) */
8138 
8139 	return DNS_ESERVICE;
8140 } /* dns_ai_parseport() */
8141 
8142 
dns_ai_open(const char * host,const char * serv,enum dns_type qtype,const struct addrinfo * hints,struct dns_resolver * res,int * _error)8143 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) {
8144 	static const struct dns_addrinfo ai_initializer;
8145 	struct dns_addrinfo *ai;
8146 	int error;
8147 
8148 	if (res) {
8149 		dns_res_acquire(res);
8150 	} else if (!(hints->ai_flags & AI_NUMERICHOST)) {
8151 		/*
8152 		 * NOTE: it's assumed that *_error is set from a previous
8153 		 * API function call, such as dns_res_stub(). Should change
8154 		 * this semantic, but it's applied elsewhere, too.
8155 		 */
8156 		if (!*_error)
8157 			*_error = EINVAL;
8158 		return NULL;
8159 	}
8160 
8161 	if (!(ai = malloc(sizeof *ai)))
8162 		goto syerr;
8163 
8164 	*ai = ai_initializer;
8165 	ai->hints = *hints;
8166 
8167 	ai->res = res;
8168 	res = NULL;
8169 
8170 	if (sizeof ai->qname <= dns_strlcpy(ai->qname, host, sizeof ai->qname))
8171 		{ error = ENAMETOOLONG; goto error; }
8172 
8173 	ai->qtype = qtype;
8174 	ai->qport = 0;
8175 
8176 	if (serv && (error = dns_ai_parseport(&ai->qport, serv, hints)))
8177 		goto error;
8178 	ai->port = ai->qport;
8179 
8180 	/*
8181 	 * FIXME: If an explicit A or AAAA record type conflicts with
8182 	 * .ai_family or with resconf.family (i.e. AAAA specified but
8183 	 * AF_INET6 not in interection of .ai_family and resconf.family),
8184 	 * then what?
8185 	 */
8186 	switch (ai->qtype) {
8187 	case DNS_T_A:
8188 		ai->af.todo = DNS_AI_AF2INDEX(AF_INET);
8189 		break;
8190 	case DNS_T_AAAA:
8191 		ai->af.todo = DNS_AI_AF2INDEX(AF_INET6);
8192 		break;
8193 	default: /* 0, MX, SRV, etc */
8194 		switch (ai->hints.ai_family) {
8195 		case AF_UNSPEC:
8196 			ai->af.todo = DNS_AI_AF2INDEX(AF_INET) | DNS_AI_AF2INDEX(AF_INET6);
8197 			break;
8198 		case AF_INET:
8199 			ai->af.todo = DNS_AI_AF2INDEX(AF_INET);
8200 			break;
8201 		case AF_INET6:
8202 			ai->af.todo = DNS_AI_AF2INDEX(AF_INET6);
8203 			break;
8204 		default:
8205 			break;
8206 		}
8207 	}
8208 
8209 	return ai;
8210 syerr:
8211 	error = dns_syerr();
8212 error:
8213 	*_error = error;
8214 
8215 	dns_ai_close(ai);
8216 	dns_res_close(res);
8217 
8218 	return NULL;
8219 } /* dns_ai_open() */
8220 
8221 
dns_ai_close(struct dns_addrinfo * ai)8222 void dns_ai_close(struct dns_addrinfo *ai) {
8223 	if (!ai)
8224 		return;
8225 
8226 	dns_res_close(ai->res);
8227 
8228 	if (ai->answer != ai->glue)
8229 		dns_p_free(ai->glue);
8230 
8231 	dns_p_free(ai->answer);
8232 	free(ai);
8233 } /* dns_ai_close() */
8234 
8235 
dns_ai_setent(struct addrinfo ** ent,union dns_any * any,enum dns_type type,struct dns_addrinfo * ai)8236 static int dns_ai_setent(struct addrinfo **ent, union dns_any *any, enum dns_type type, struct dns_addrinfo *ai) {
8237 	union { struct sockaddr saddr; struct sockaddr_in sin; struct sockaddr_in6 sin6; } saddr = {0};
8238 	const char *cname;
8239 	size_t clen;
8240 
8241 	switch (type) {
8242 	case DNS_T_A:
8243 		saddr.sin.sin_family = AF_INET;
8244 		saddr.sin.sin_port = htons(ai->port);
8245 
8246 		memcpy(&saddr.sin.sin_addr, any, sizeof saddr.sin.sin_addr);
8247 
8248 		break;
8249 	case DNS_T_AAAA:
8250 		saddr.sin6.sin6_family = AF_INET6;
8251 		saddr.sin6.sin6_port = htons(ai->port);
8252 
8253 		memcpy(&saddr.sin6.sin6_addr, any, sizeof saddr.sin6.sin6_addr);
8254 
8255 		break;
8256 	default:
8257 		return EINVAL;
8258 	} /* switch() */
8259 
8260 	if (ai->hints.ai_flags & AI_CANONNAME) {
8261 		cname	= (*ai->cname)? ai->cname : ai->qname;
8262 		clen	= strlen(cname);
8263 	} else {
8264 		cname	= NULL;
8265 		clen	= 0;
8266 	}
8267 
8268 	if (!(*ent = malloc(sizeof **ent + dns_sa_len(&saddr) + ((ai->hints.ai_flags & AI_CANONNAME)? clen + 1 : 0))))
8269 		return dns_syerr();
8270 
8271 	memset(*ent, '\0', sizeof **ent);
8272 
8273 	(*ent)->ai_family	= saddr.saddr.sa_family;
8274 	(*ent)->ai_socktype	= ai->hints.ai_socktype;
8275 	(*ent)->ai_protocol	= ai->hints.ai_protocol;
8276 
8277 	(*ent)->ai_addr		= memcpy((unsigned char *)*ent + sizeof **ent, &saddr, dns_sa_len(&saddr));
8278 	(*ent)->ai_addrlen	= dns_sa_len(&saddr);
8279 
8280 	if (ai->hints.ai_flags & AI_CANONNAME)
8281 		(*ent)->ai_canonname	= memcpy((unsigned char *)*ent + sizeof **ent + dns_sa_len(&saddr), cname, clen + 1);
8282 
8283 	ai->found++;
8284 
8285 	return 0;
8286 } /* dns_ai_setent() */
8287 
8288 
8289 enum dns_ai_state {
8290 	DNS_AI_S_INIT,
8291 	DNS_AI_S_NEXTAF,
8292 	DNS_AI_S_NUMERIC,
8293 	DNS_AI_S_SUBMIT,
8294 	DNS_AI_S_CHECK,
8295 	DNS_AI_S_FETCH,
8296 	DNS_AI_S_FOREACH_I,
8297 	DNS_AI_S_INIT_G,
8298 	DNS_AI_S_ITERATE_G,
8299 	DNS_AI_S_FOREACH_G,
8300 	DNS_AI_S_SUBMIT_G,
8301 	DNS_AI_S_CHECK_G,
8302 	DNS_AI_S_FETCH_G,
8303 	DNS_AI_S_DONE,
8304 }; /* enum dns_ai_state */
8305 
8306 #define dns_ai_goto(which)	do { ai->state = (which); goto exec; } while (0)
8307 
dns_ai_nextent(struct addrinfo ** ent,struct dns_addrinfo * ai)8308 int dns_ai_nextent(struct addrinfo **ent, struct dns_addrinfo *ai) {
8309 	struct dns_packet *ans, *glue;
8310 	struct dns_rr rr;
8311 	char qname[DNS_D_MAXNAME + 1];
8312 	union dns_any any;
8313 	size_t qlen, clen;
8314 	int error;
8315 
8316 	*ent = 0;
8317 
8318 exec:
8319 
8320 	switch (ai->state) {
8321 	case DNS_AI_S_INIT:
8322 		ai->state++;
8323 		/* FALL THROUGH */
8324 	case DNS_AI_S_NEXTAF:
8325 		if (!dns_ai_nextaf(ai))
8326 			dns_ai_goto(DNS_AI_S_DONE);
8327 
8328 		ai->state++;
8329 		/* FALL THROUGH */
8330 	case DNS_AI_S_NUMERIC:
8331 		if (1 == dns_inet_pton(AF_INET, ai->qname, &any.a)) {
8332 			if (ai->af.atype == AF_INET) {
8333 				ai->state = DNS_AI_S_NEXTAF;
8334 				return dns_ai_setent(ent, &any, DNS_T_A, ai);
8335 			} else {
8336 				dns_ai_goto(DNS_AI_S_NEXTAF);
8337 			}
8338 		}
8339 
8340 		if (1 == dns_inet_pton(AF_INET6, ai->qname, &any.aaaa)) {
8341 			if (ai->af.atype == AF_INET6) {
8342 				ai->state = DNS_AI_S_NEXTAF;
8343 				return dns_ai_setent(ent, &any, DNS_T_AAAA, ai);
8344 			} else {
8345 				dns_ai_goto(DNS_AI_S_NEXTAF);
8346 			}
8347 		}
8348 
8349 		if (ai->hints.ai_flags & AI_NUMERICHOST)
8350 			dns_ai_goto(DNS_AI_S_NEXTAF);
8351 
8352 		ai->state++;
8353 		/* FALL THROUGH */
8354 	case DNS_AI_S_SUBMIT:
8355 		assert(ai->res);
8356 
8357 		if ((error = dns_res_submit(ai->res, ai->qname, dns_ai_qtype(ai), DNS_C_IN)))
8358 			return error;
8359 
8360 		ai->state++;
8361 		/* FALL THROUGH */
8362 	case DNS_AI_S_CHECK:
8363 		if ((error = dns_res_check(ai->res)))
8364 			return error;
8365 
8366 		ai->state++;
8367 		/* FALL THROUGH */
8368 	case DNS_AI_S_FETCH:
8369 		if (!(ans = dns_res_fetch_and_study(ai->res, &error)))
8370 			return error;
8371 		if (ai->glue != ai->answer)
8372 			dns_p_free(ai->glue);
8373 		ai->glue = dns_p_movptr(&ai->answer, &ans);
8374 
8375 		/* Search generator may have changed the qname. */
8376 		if (!(qlen = dns_d_expand(qname, sizeof qname, 12, ai->answer, &error)))
8377 			return error;
8378 		else if (qlen >= sizeof qname)
8379 			return DNS_EILLEGAL;
8380 		if (!dns_d_cname(ai->cname, sizeof ai->cname, qname, qlen, ai->answer, &error))
8381 			return error;
8382 
8383 		dns_strlcpy(ai->i_cname, ai->cname, sizeof ai->i_cname);
8384 		dns_rr_i_init(&ai->i, ai->answer);
8385 		ai->i.section = DNS_S_AN;
8386 		ai->i.name    = ai->i_cname;
8387 		ai->i.type    = dns_ai_qtype(ai);
8388 		ai->i.sort    = &dns_rr_i_order;
8389 
8390 		ai->state++;
8391 		/* FALL THROUGH */
8392 	case DNS_AI_S_FOREACH_I:
8393 		if (!dns_rr_grep(&rr, 1, &ai->i, ai->answer, &error))
8394 			dns_ai_goto(DNS_AI_S_NEXTAF);
8395 
8396 		if ((error = dns_any_parse(&any, &rr, ai->answer)))
8397 			return error;
8398 
8399 		ai->port = ai->qport;
8400 
8401 		switch (rr.type) {
8402 		case DNS_T_A:
8403 		case DNS_T_AAAA:
8404 			return dns_ai_setent(ent, &any, rr.type, ai);
8405 		default:
8406 			if (!(clen = dns_any_cname(ai->cname, sizeof ai->cname, &any, rr.type)))
8407 				dns_ai_goto(DNS_AI_S_FOREACH_I);
8408 
8409 			/*
8410 			 * Find the "real" canonical name. Some authorities
8411 			 * publish aliases where an RFC defines a canonical
8412 			 * name. We trust that the resolver followed any
8413 			 * CNAME chains on it's own, regardless of whether
8414 			 * the "smart" option is enabled.
8415 			 */
8416 			if (!dns_d_cname(ai->cname, sizeof ai->cname, ai->cname, clen, ai->answer, &error))
8417 				return error;
8418 
8419 			if (rr.type == DNS_T_SRV)
8420 				ai->port = any.srv.port;
8421 
8422 			break;
8423 		} /* switch() */
8424 
8425 		ai->state++;
8426 		/* FALL THROUGH */
8427 	case DNS_AI_S_INIT_G:
8428 		ai->g_depth = 0;
8429 
8430 		ai->state++;
8431 		/* FALL THROUGH */
8432 	case DNS_AI_S_ITERATE_G:
8433 		dns_strlcpy(ai->g_cname, ai->cname, sizeof ai->g_cname);
8434 		dns_rr_i_init(&ai->g, ai->glue);
8435 		ai->g.section = DNS_S_ALL & ~DNS_S_QD;
8436 		ai->g.name    = ai->g_cname;
8437 		ai->g.type    = ai->af.qtype;
8438 
8439 		ai->state++;
8440 		/* FALL THROUGH */
8441 	case DNS_AI_S_FOREACH_G:
8442 		if (!dns_rr_grep(&rr, 1, &ai->g, ai->glue, &error)) {
8443 			if (dns_rr_i_count(&ai->g) > 0)
8444 				dns_ai_goto(DNS_AI_S_FOREACH_I);
8445 			else
8446 				dns_ai_goto(DNS_AI_S_SUBMIT_G);
8447 		}
8448 
8449 		if ((error = dns_any_parse(&any, &rr, ai->glue)))
8450 			return error;
8451 
8452 		return dns_ai_setent(ent, &any, rr.type, ai);
8453 	case DNS_AI_S_SUBMIT_G:
8454 		/* skip if already queried */
8455 		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))
8456 			dns_ai_goto(DNS_AI_S_FOREACH_I);
8457 		/* skip if we recursed (CNAME chains should have been handled in the resolver) */
8458 		if (++ai->g_depth > 1)
8459 			dns_ai_goto(DNS_AI_S_FOREACH_I);
8460 
8461 		if ((error = dns_res_submit(ai->res, ai->g.name, ai->g.type, DNS_C_IN)))
8462 			return error;
8463 
8464 		ai->state++;
8465 		/* FALL THROUGH */
8466 	case DNS_AI_S_CHECK_G:
8467 		if ((error = dns_res_check(ai->res)))
8468 			return error;
8469 
8470 		ai->state++;
8471 		/* FALL THROUGH */
8472 	case DNS_AI_S_FETCH_G:
8473 		if (!(ans = dns_res_fetch_and_study(ai->res, &error)))
8474 			return error;
8475 
8476 		glue = dns_p_merge(ai->glue, DNS_S_ALL, ans, DNS_S_ALL, &error);
8477 		dns_p_setptr(&ans, NULL);
8478 		if (!glue)
8479 			return error;
8480 
8481 		if (ai->glue != ai->answer)
8482 			dns_p_free(ai->glue);
8483 		ai->glue = glue;
8484 
8485 		if (!dns_d_cname(ai->cname, sizeof ai->cname, ai->g.name, strlen(ai->g.name), ai->glue, &error))
8486 			dns_ai_goto(DNS_AI_S_FOREACH_I);
8487 
8488 		dns_ai_goto(DNS_AI_S_ITERATE_G);
8489 	case DNS_AI_S_DONE:
8490 		if (ai->found) {
8491 			return ENOENT; /* TODO: Just return 0 */
8492 		} else if (ai->answer) {
8493 			switch (dns_p_rcode(ai->answer)) {
8494 			case DNS_RC_NOERROR:
8495 				/* FALL THROUGH */
8496 			case DNS_RC_NXDOMAIN:
8497 				return DNS_ENONAME;
8498 			default:
8499 				return DNS_EFAIL;
8500 			}
8501 		} else {
8502 			return DNS_EFAIL;
8503 		}
8504 	default:
8505 		return EINVAL;
8506 	} /* switch() */
8507 } /* dns_ai_nextent() */
8508 
8509 
dns_ai_elapsed(struct dns_addrinfo * ai)8510 time_t dns_ai_elapsed(struct dns_addrinfo *ai) {
8511 	return (ai->res)? dns_res_elapsed(ai->res) : 0;
8512 } /* dns_ai_elapsed() */
8513 
8514 
dns_ai_clear(struct dns_addrinfo * ai)8515 void dns_ai_clear(struct dns_addrinfo *ai) {
8516 	if (ai->res)
8517 		dns_res_clear(ai->res);
8518 } /* dns_ai_clear() */
8519 
8520 
dns_ai_events(struct dns_addrinfo * ai)8521 int dns_ai_events(struct dns_addrinfo *ai) {
8522 	return (ai->res)? dns_res_events(ai->res) : 0;
8523 } /* dns_ai_events() */
8524 
8525 
dns_ai_pollfd(struct dns_addrinfo * ai)8526 int dns_ai_pollfd(struct dns_addrinfo *ai) {
8527 	return (ai->res)? dns_res_pollfd(ai->res) : -1;
8528 } /* dns_ai_pollfd() */
8529 
8530 
dns_ai_timeout(struct dns_addrinfo * ai)8531 time_t dns_ai_timeout(struct dns_addrinfo *ai) {
8532 	return (ai->res)? dns_res_timeout(ai->res) : 0;
8533 } /* dns_ai_timeout() */
8534 
8535 
dns_ai_poll(struct dns_addrinfo * ai,int timeout)8536 int dns_ai_poll(struct dns_addrinfo *ai, int timeout) {
8537 	return (ai->res)? dns_res_poll(ai->res, timeout) : 0;
8538 } /* dns_ai_poll() */
8539 
8540 
dns_ai_print(void * _dst,size_t lim,struct addrinfo * ent,struct dns_addrinfo * ai)8541 size_t dns_ai_print(void *_dst, size_t lim, struct addrinfo *ent, struct dns_addrinfo *ai) {
8542 	struct dns_buf dst = DNS_B_INTO(_dst, lim);
8543 	char addr[DNS_PP_MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) + 1];
8544 
8545 	dns_b_puts(&dst, "[ ");
8546 	dns_b_puts(&dst, ai->qname);
8547 	dns_b_puts(&dst, " IN ");
8548 	if (ai->qtype) {
8549 		dns_b_puts(&dst, dns_strtype(ai->qtype));
8550 	} else if (ent->ai_family == AF_INET) {
8551 		dns_b_puts(&dst, dns_strtype(DNS_T_A));
8552 	} else if (ent->ai_family == AF_INET6) {
8553 		dns_b_puts(&dst, dns_strtype(DNS_T_AAAA));
8554 	} else {
8555 		dns_b_puts(&dst, "0");
8556 	}
8557 	dns_b_puts(&dst, " ]\n");
8558 
8559 	dns_b_puts(&dst, ".ai_family    = ");
8560 	switch (ent->ai_family) {
8561 	case AF_INET:
8562 		dns_b_puts(&dst, "AF_INET");
8563 		break;
8564 	case AF_INET6:
8565 		dns_b_puts(&dst, "AF_INET6");
8566 		break;
8567 	default:
8568 		dns_b_fmtju(&dst, ent->ai_family, 0);
8569 		break;
8570 	}
8571 	dns_b_putc(&dst, '\n');
8572 
8573 	dns_b_puts(&dst, ".ai_socktype  = ");
8574 	switch (ent->ai_socktype) {
8575 	case SOCK_STREAM:
8576 		dns_b_puts(&dst, "SOCK_STREAM");
8577 		break;
8578 	case SOCK_DGRAM:
8579 		dns_b_puts(&dst, "SOCK_DGRAM");
8580 		break;
8581 	default:
8582 		dns_b_fmtju(&dst, ent->ai_socktype, 0);
8583 		break;
8584 	}
8585 	dns_b_putc(&dst, '\n');
8586 
8587 	dns_inet_ntop(dns_sa_family(ent->ai_addr), dns_sa_addr(dns_sa_family(ent->ai_addr), ent->ai_addr, NULL), addr, sizeof addr);
8588 	dns_b_puts(&dst, ".ai_addr      = [");
8589 	dns_b_puts(&dst, addr);
8590 	dns_b_puts(&dst, "]:");
8591 	dns_b_fmtju(&dst, ntohs(*dns_sa_port(dns_sa_family(ent->ai_addr), ent->ai_addr)), 0);
8592 	dns_b_putc(&dst, '\n');
8593 
8594 	dns_b_puts(&dst, ".ai_canonname = ");
8595 	dns_b_puts(&dst, (ent->ai_canonname)? ent->ai_canonname : "[NULL]");
8596 	dns_b_putc(&dst, '\n');
8597 
8598 	return dns_b_strllen(&dst);
8599 } /* dns_ai_print() */
8600 
8601 
dns_ai_stat(struct dns_addrinfo * ai)8602 const struct dns_stat *dns_ai_stat(struct dns_addrinfo *ai) {
8603 	return (ai->res)? dns_res_stat(ai->res) : &ai->st;
8604 } /* dns_ai_stat() */
8605 
8606 
8607 /*
8608  * M I S C E L L A N E O U S  R O U T I N E S
8609  *
8610  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8611 
8612 static const struct {
8613 	char name[16];
8614 	enum dns_section type;
8615 } dns_sections[] = {
8616 	{ "QUESTION",   DNS_S_QUESTION },
8617 	{ "QD",         DNS_S_QUESTION },
8618 	{ "ANSWER",     DNS_S_ANSWER },
8619 	{ "AN",         DNS_S_ANSWER },
8620 	{ "AUTHORITY",  DNS_S_AUTHORITY },
8621 	{ "NS",         DNS_S_AUTHORITY },
8622 	{ "ADDITIONAL", DNS_S_ADDITIONAL },
8623 	{ "AR",         DNS_S_ADDITIONAL },
8624 };
8625 
8626 const char *(dns_strsection)(enum dns_section section, void *_dst, size_t lim) {
8627 	struct dns_buf dst = DNS_B_INTO(_dst, lim);
8628 	unsigned i;
8629 
8630 	for (i = 0; i < lengthof(dns_sections); i++) {
8631 		if (dns_sections[i].type & section) {
8632 			dns_b_puts(&dst, dns_sections[i].name);
8633 			section &= ~dns_sections[i].type;
8634 			if (section)
8635 				dns_b_putc(&dst, '|');
8636 		}
8637 	}
8638 
8639 	if (section || dst.p == dst.base)
8640 		dns_b_fmtju(&dst, (0xffff & section), 0);
8641 
8642 	return dns_b_tostring(&dst);
8643 } /* dns_strsection() */
8644 
8645 
dns_isection(const char * src)8646 enum dns_section dns_isection(const char *src) {
8647 	enum dns_section section = 0;
8648 	char sbuf[128];
8649 	char *name, *next;
8650 	unsigned i;
8651 
8652 	dns_strlcpy(sbuf, src, sizeof sbuf);
8653 	next = sbuf;
8654 
8655 	while ((name = dns_strsep(&next, "|+, \t"))) {
8656 		for (i = 0; i < lengthof(dns_sections); i++) {
8657 			if (!strcasecmp(dns_sections[i].name, name)) {
8658 				section |= dns_sections[i].type;
8659 				break;
8660 			}
8661 		}
8662 	}
8663 
8664 	return section;
8665 } /* dns_isection() */
8666 
8667 
8668 static const struct {
8669 	char name[8];
8670 	enum dns_class type;
8671 } dns_classes[] = {
8672 	{ "IN", DNS_C_IN },
8673 };
8674 
8675 const char *(dns_strclass)(enum dns_class type, void *_dst, size_t lim) {
8676 	struct dns_buf dst = DNS_B_INTO(_dst, lim);
8677 	unsigned i;
8678 
8679 	for (i = 0; i < lengthof(dns_classes); i++) {
8680 		if (dns_classes[i].type == type) {
8681 			dns_b_puts(&dst, dns_classes[i].name);
8682 			break;
8683 		}
8684 	}
8685 
8686 	if (dst.p == dst.base)
8687 		dns_b_fmtju(&dst, (0xffff & type), 0);
8688 
8689 	return dns_b_tostring(&dst);
8690 } /* dns_strclass() */
8691 
8692 
dns_iclass(const char * name)8693 enum dns_class dns_iclass(const char *name) {
8694 	unsigned i, class;
8695 
8696 	for (i = 0; i < lengthof(dns_classes); i++) {
8697 		if (!strcasecmp(dns_classes[i].name, name))
8698 			return dns_classes[i].type;
8699 	}
8700 
8701 	class = 0;
8702 	while (dns_isdigit(*name)) {
8703 		class *= 10;
8704 		class += *name++ - '0';
8705 	}
8706 
8707 	return DNS_PP_MIN(class, 0xffff);
8708 } /* dns_iclass() */
8709 
8710 
8711 const char *(dns_strtype)(enum dns_type type, void *_dst, size_t lim) {
8712 	struct dns_buf dst = DNS_B_INTO(_dst, lim);
8713 	unsigned i;
8714 
8715 	for (i = 0; i < lengthof(dns_rrtypes); i++) {
8716 		if (dns_rrtypes[i].type == type) {
8717 			dns_b_puts(&dst, dns_rrtypes[i].name);
8718 			break;
8719 		}
8720 	}
8721 
8722 	if (dst.p == dst.base)
8723 		dns_b_fmtju(&dst, (0xffff & type), 0);
8724 
8725 	return dns_b_tostring(&dst);
8726 } /* dns_strtype() */
8727 
8728 
dns_itype(const char * name)8729 enum dns_type dns_itype(const char *name) {
8730 	unsigned i, type;
8731 
8732 	for (i = 0; i < lengthof(dns_rrtypes); i++) {
8733 		if (!strcasecmp(dns_rrtypes[i].name, name))
8734 			return dns_rrtypes[i].type;
8735 	}
8736 
8737 	type = 0;
8738 	while (dns_isdigit(*name)) {
8739 		type *= 10;
8740 		type += *name++ - '0';
8741 	}
8742 
8743 	return DNS_PP_MIN(type, 0xffff);
8744 } /* dns_itype() */
8745 
8746 
8747 static char dns_opcodes[16][16] = {
8748 	[DNS_OP_QUERY]  = "QUERY",
8749 	[DNS_OP_IQUERY] = "IQUERY",
8750 	[DNS_OP_STATUS] = "STATUS",
8751 	[DNS_OP_NOTIFY] = "NOTIFY",
8752 	[DNS_OP_UPDATE] = "UPDATE",
8753 };
8754 
dns__strcode(int code,volatile char * dst,size_t lim)8755 static const char *dns__strcode(int code, volatile char *dst, size_t lim) {
8756 	char _tmp[48] = "";
8757 	struct dns_buf tmp;
8758 	size_t p;
8759 
8760 	assert(lim > 0);
8761 	dns_b_fmtju(dns_b_into(&tmp, _tmp, DNS_PP_MIN(sizeof _tmp, lim - 1)), code, 0);
8762 
8763 	/* copy downwards so first byte is copied last (see below) */
8764 	p = (size_t)(tmp.p - tmp.base);
8765 	dst[p] = '\0';
8766 	while (p--)
8767 		dst[p] = _tmp[p];
8768 
8769 	return (const char *)dst;
8770 }
8771 
dns_stropcode(enum dns_opcode opcode)8772 const char *dns_stropcode(enum dns_opcode opcode) {
8773 	opcode = (unsigned)opcode % lengthof(dns_opcodes);
8774 
8775 	if ('\0' == dns_opcodes[opcode][0])
8776 		return dns__strcode(opcode, dns_opcodes[opcode], sizeof dns_opcodes[opcode]);
8777 
8778 	return dns_opcodes[opcode];
8779 } /* dns_stropcode() */
8780 
8781 
dns_iopcode(const char * name)8782 enum dns_opcode dns_iopcode(const char *name) {
8783 	unsigned opcode;
8784 
8785 	for (opcode = 0; opcode < lengthof(dns_opcodes); opcode++) {
8786 		if (!strcasecmp(name, dns_opcodes[opcode]))
8787 			return opcode;
8788 	}
8789 
8790 	opcode = 0;
8791 	while (dns_isdigit(*name)) {
8792 		opcode *= 10;
8793 		opcode += *name++ - '0';
8794 	}
8795 
8796 	return DNS_PP_MIN(opcode, 0x0f);
8797 } /* dns_iopcode() */
8798 
8799 
8800 static char dns_rcodes[32][16] = {
8801 	[DNS_RC_NOERROR]  = "NOERROR",
8802 	[DNS_RC_FORMERR]  = "FORMERR",
8803 	[DNS_RC_SERVFAIL] = "SERVFAIL",
8804 	[DNS_RC_NXDOMAIN] = "NXDOMAIN",
8805 	[DNS_RC_NOTIMP]   = "NOTIMP",
8806 	[DNS_RC_REFUSED]  = "REFUSED",
8807 	[DNS_RC_YXDOMAIN] = "YXDOMAIN",
8808 	[DNS_RC_YXRRSET]  = "YXRRSET",
8809 	[DNS_RC_NXRRSET]  = "NXRRSET",
8810 	[DNS_RC_NOTAUTH]  = "NOTAUTH",
8811 	[DNS_RC_NOTZONE]  = "NOTZONE",
8812 	/* EDNS(0) extended RCODEs ... */
8813 	[DNS_RC_BADVERS]  = "BADVERS",
8814 };
8815 
dns_strrcode(enum dns_rcode rcode)8816 const char *dns_strrcode(enum dns_rcode rcode) {
8817 	rcode = (unsigned)rcode % lengthof(dns_rcodes);
8818 
8819 	if ('\0' == dns_rcodes[rcode][0])
8820 		return dns__strcode(rcode, dns_rcodes[rcode], sizeof dns_rcodes[rcode]);
8821 
8822 	return dns_rcodes[rcode];
8823 } /* dns_strrcode() */
8824 
8825 
dns_ircode(const char * name)8826 enum dns_rcode dns_ircode(const char *name) {
8827 	unsigned rcode;
8828 
8829 	for (rcode = 0; rcode < lengthof(dns_rcodes); rcode++) {
8830 		if (!strcasecmp(name, dns_rcodes[rcode]))
8831 			return rcode;
8832 	}
8833 
8834 	rcode = 0;
8835 	while (dns_isdigit(*name)) {
8836 		rcode *= 10;
8837 		rcode += *name++ - '0';
8838 	}
8839 
8840 	return DNS_PP_MIN(rcode, 0xfff);
8841 } /* dns_ircode() */
8842 
8843 
8844 
8845 /*
8846  * 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
8847  *
8848  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8849 #if DNS_MAIN
8850 
8851 #include <stdarg.h>
8852 #include <stdlib.h>
8853 #include <stdio.h>
8854 
8855 #include <ctype.h>
8856 
8857 #if _WIN32
8858 #include <getopt.h>
8859 #endif
8860 
8861 #if !_WIN32
8862 #include <err.h>
8863 #endif
8864 
8865 
8866 struct {
8867 	struct {
8868 		const char *path[8];
8869 		unsigned count;
8870 	} resconf, nssconf, hosts, cache;
8871 
8872 	const char *qname;
8873 	enum dns_type qtype;
8874 
8875 	int (*sort)();
8876 
8877 	int verbose;
8878 } MAIN = {
8879 	.sort	= &dns_rr_i_packet,
8880 };
8881 
8882 
hexdump(const unsigned char * src,size_t len,FILE * fp)8883 static void hexdump(const unsigned char *src, size_t len, FILE *fp) {
8884 	static const unsigned char hex[]	= "0123456789abcdef";
8885 	static const unsigned char tmpl[]	= "                                                    |                |\n";
8886 	unsigned char ln[sizeof tmpl];
8887 	const unsigned char *sp, *se;
8888 	unsigned char *h, *g;
8889 	unsigned i, n;
8890 
8891 	sp	= src;
8892 	se	= sp + len;
8893 
8894 	while (sp < se) {
8895 		memcpy(ln, tmpl, sizeof ln);
8896 
8897 		h	= &ln[2];
8898 		g	= &ln[53];
8899 
8900 		for (n = 0; n < 2; n++) {
8901 			for (i = 0; i < 8 && se - sp > 0; i++, sp++) {
8902 				h[0]	= hex[0x0f & (*sp >> 4)];
8903 				h[1]	= hex[0x0f & (*sp >> 0)];
8904 				h	+= 3;
8905 
8906 				*g++	= (isgraph(*sp))? *sp : '.';
8907 			}
8908 
8909 			h++;
8910 		}
8911 
8912 		fputs((char *)ln, fp);
8913 	}
8914 
8915 	return /* void */;
8916 } /* hexdump() */
8917 
8918 
panic(const char * fmt,...)8919 DNS_NORETURN static void panic(const char *fmt, ...) {
8920 	va_list ap;
8921 
8922 	va_start(ap, fmt);
8923 
8924 #if _WIN32
8925 	vfprintf(stderr, fmt, ap);
8926 
8927 	exit(EXIT_FAILURE);
8928 #else
8929 	verrx(EXIT_FAILURE, fmt, ap);
8930 #endif
8931 } /* panic() */
8932 
8933 #define panic_(fn, ln, fmt, ...)	\
8934 	panic(fmt "%0s", (fn), (ln), __VA_ARGS__)
8935 #define panic(...)			\
8936 	panic_(__func__, __LINE__, "(%s:%d) " __VA_ARGS__, "")
8937 
8938 
grow(unsigned char * p,size_t size)8939 static void *grow(unsigned char *p, size_t size) {
8940 	void *tmp;
8941 
8942 	if (!(tmp = realloc(p, size)))
8943 		panic("realloc(%"PRIuZ"): %s", size, dns_strerror(errno));
8944 
8945 	return tmp;
8946 } /* grow() */
8947 
8948 
add(size_t a,size_t b)8949 static size_t add(size_t a, size_t b) {
8950 	if (~a < b)
8951 		panic("%"PRIuZ" + %"PRIuZ": integer overflow", a, b);
8952 
8953 	return a + b;
8954 } /* add() */
8955 
8956 
append(unsigned char ** dst,size_t osize,const void * src,size_t len)8957 static size_t append(unsigned char **dst, size_t osize, const void *src, size_t len) {
8958 	size_t size = add(osize, len);
8959 
8960 	*dst = grow(*dst, size);
8961 	memcpy(*dst + osize, src, len);
8962 
8963 	return size;
8964 } /* append() */
8965 
8966 
slurp(unsigned char ** dst,size_t osize,FILE * fp,const char * path)8967 static size_t slurp(unsigned char **dst, size_t osize, FILE *fp, const char *path) {
8968 	size_t size = osize;
8969 	unsigned char buf[1024];
8970 	size_t count;
8971 
8972 	while ((count = fread(buf, 1, sizeof buf, fp)))
8973 		size = append(dst, size, buf, count);
8974 
8975 	if (ferror(fp))
8976 		panic("%s: %s", path, dns_strerror(errno));
8977 
8978 	return size;
8979 } /* slurp() */
8980 
8981 
resconf(void)8982 static struct dns_resolv_conf *resconf(void) {
8983 	static struct dns_resolv_conf *resconf;
8984 	const char *path;
8985 	unsigned i;
8986 	int error;
8987 
8988 	if (resconf)
8989 		return resconf;
8990 
8991 	if (!(resconf = dns_resconf_open(&error)))
8992 		panic("dns_resconf_open: %s", dns_strerror(error));
8993 
8994 	if (!MAIN.resconf.count)
8995 		MAIN.resconf.path[MAIN.resconf.count++]	= "/etc/resolv.conf";
8996 
8997 	for (i = 0; i < MAIN.resconf.count; i++) {
8998 		path	= MAIN.resconf.path[i];
8999 
9000 		if (0 == strcmp(path, "-"))
9001 			error	= dns_resconf_loadfile(resconf, stdin);
9002 		else
9003 			error	= dns_resconf_loadpath(resconf, path);
9004 
9005 		if (error)
9006 			panic("%s: %s", path, dns_strerror(error));
9007 	}
9008 
9009 	for (i = 0; i < MAIN.nssconf.count; i++) {
9010 		path	= MAIN.nssconf.path[i];
9011 
9012 		if (0 == strcmp(path, "-"))
9013 			error	= dns_nssconf_loadfile(resconf, stdin);
9014 		else
9015 			error	= dns_nssconf_loadpath(resconf, path);
9016 
9017 		if (error)
9018 			panic("%s: %s", path, dns_strerror(error));
9019 	}
9020 
9021 	if (!MAIN.nssconf.count) {
9022 		path = "/etc/nsswitch.conf";
9023 
9024 		if (!(error = dns_nssconf_loadpath(resconf, path)))
9025 			MAIN.nssconf.path[MAIN.nssconf.count++] = path;
9026 		else if (error != ENOENT)
9027 			panic("%s: %s", path, dns_strerror(error));
9028 	}
9029 
9030 	return resconf;
9031 } /* resconf() */
9032 
9033 
hosts(void)9034 static struct dns_hosts *hosts(void) {
9035 	static struct dns_hosts *hosts;
9036 	const char *path;
9037 	unsigned i;
9038 	int error;
9039 
9040 	if (hosts)
9041 		return hosts;
9042 
9043 	if (!MAIN.hosts.count) {
9044 		MAIN.hosts.path[MAIN.hosts.count++]	= "/etc/hosts";
9045 
9046 		/* Explicitly test dns_hosts_local() */
9047 		if (!(hosts = dns_hosts_local(&error)))
9048 			panic("%s: %s", "/etc/hosts", dns_strerror(error));
9049 
9050 		return hosts;
9051 	}
9052 
9053 	if (!(hosts = dns_hosts_open(&error)))
9054 		panic("dns_hosts_open: %s", dns_strerror(error));
9055 
9056 	for (i = 0; i < MAIN.hosts.count; i++) {
9057 		path	= MAIN.hosts.path[i];
9058 
9059 		if (0 == strcmp(path, "-"))
9060 			error	= dns_hosts_loadfile(hosts, stdin);
9061 		else
9062 			error	= dns_hosts_loadpath(hosts, path);
9063 
9064 		if (error)
9065 			panic("%s: %s", path, dns_strerror(error));
9066 	}
9067 
9068 	return hosts;
9069 } /* hosts() */
9070 
9071 
9072 #if DNS_CACHE
9073 #include "cache.h"
9074 
cache(void)9075 static struct dns_cache *cache(void) {
9076 	static struct cache *cache;
9077 	const char *path;
9078 	unsigned i;
9079 	int error;
9080 
9081 	if (cache)
9082 		return cache_resi(cache);
9083 	if (!MAIN.cache.count)
9084 		return NULL;
9085 
9086 	if (!(cache = cache_open(&error)))
9087 		panic("%s: %s", MAIN.cache.path[0], dns_strerror(error));
9088 
9089 	for (i = 0; i < MAIN.cache.count; i++) {
9090 		path = MAIN.cache.path[i];
9091 
9092 		if (!strcmp(path, "-")) {
9093 			if ((error = cache_loadfile(cache, stdin, NULL, 0)))
9094 				panic("%s: %s", path, dns_strerror(error));
9095 		} else if ((error = cache_loadpath(cache, path, NULL, 0)))
9096 			panic("%s: %s", path, dns_strerror(error));
9097 	}
9098 
9099 	return cache_resi(cache);
9100 } /* cache() */
9101 #else
cache(void)9102 static struct dns_cache *cache(void) { return NULL; }
9103 #endif
9104 
9105 
print_packet(struct dns_packet * P,FILE * fp)9106 static void print_packet(struct dns_packet *P, FILE *fp) {
9107 	dns_p_dump3(P, dns_rr_i_new(P, .sort = MAIN.sort), fp);
9108 
9109 	if (MAIN.verbose > 2)
9110 		hexdump(P->data, P->end, fp);
9111 } /* print_packet() */
9112 
9113 
parse_packet(int argc DNS_NOTUSED,char * argv[]DNS_NOTUSED)9114 static int parse_packet(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
9115 	struct dns_packet *P	= dns_p_new(512);
9116 	struct dns_packet *Q	= dns_p_new(512);
9117 	enum dns_section section;
9118 	struct dns_rr rr;
9119 	int error;
9120 	union dns_any any;
9121 	char pretty[sizeof any * 2];
9122 	size_t len;
9123 
9124 	P->end	= fread(P->data, 1, P->size, stdin);
9125 
9126 	fputs(";; [HEADER]\n", stdout);
9127 	fprintf(stdout, ";;     qr : %s(%d)\n", (dns_header(P)->qr)? "RESPONSE" : "QUERY", dns_header(P)->qr);
9128 	fprintf(stdout, ";; opcode : %s(%d)\n", dns_stropcode(dns_header(P)->opcode), dns_header(P)->opcode);
9129 	fprintf(stdout, ";;     aa : %s(%d)\n", (dns_header(P)->aa)? "AUTHORITATIVE" : "NON-AUTHORITATIVE", dns_header(P)->aa);
9130 	fprintf(stdout, ";;     tc : %s(%d)\n", (dns_header(P)->tc)? "TRUNCATED" : "NOT-TRUNCATED", dns_header(P)->tc);
9131 	fprintf(stdout, ";;     rd : %s(%d)\n", (dns_header(P)->rd)? "RECURSION-DESIRED" : "RECURSION-NOT-DESIRED", dns_header(P)->rd);
9132 	fprintf(stdout, ";;     ra : %s(%d)\n", (dns_header(P)->ra)? "RECURSION-ALLOWED" : "RECURSION-NOT-ALLOWED", dns_header(P)->ra);
9133 	fprintf(stdout, ";;  rcode : %s(%d)\n", dns_strrcode(dns_p_rcode(P)), dns_p_rcode(P));
9134 
9135 	section	= 0;
9136 
9137 	dns_rr_foreach(&rr, P, .sort = MAIN.sort) {
9138 		if (section != rr.section)
9139 			fprintf(stdout, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(P, rr.section));
9140 
9141 		if ((len = dns_rr_print(pretty, sizeof pretty, &rr, P, &error)))
9142 			fprintf(stdout, "%s\n", pretty);
9143 
9144 		dns_rr_copy(Q, &rr, P);
9145 
9146 		section	= rr.section;
9147 	}
9148 
9149 	fputs("; ; ; ; ; ; ; ;\n\n", stdout);
9150 
9151 	section	= 0;
9152 
9153 #if 0
9154 	dns_rr_foreach(&rr, Q, .name = "ns8.yahoo.com.") {
9155 #else
9156 	struct dns_rr rrset[32];
9157 	struct dns_rr_i *rri	= dns_rr_i_new(Q, .name = dns_d_new("ns8.yahoo.com", DNS_D_ANCHOR), .sort = MAIN.sort);
9158 	unsigned rrcount	= dns_rr_grep(rrset, lengthof(rrset), rri, Q, &error);
9159 
9160 	for (unsigned i = 0; i < rrcount; i++) {
9161 		rr	= rrset[i];
9162 #endif
9163 		if (section != rr.section)
9164 			fprintf(stdout, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(Q, rr.section));
9165 
9166 		if ((len = dns_rr_print(pretty, sizeof pretty, &rr, Q, &error)))
9167 			fprintf(stdout, "%s\n", pretty);
9168 
9169 		section	= rr.section;
9170 	}
9171 
9172 	if (MAIN.verbose > 1) {
9173 		fprintf(stderr, "orig:%"PRIuZ"\n", P->end);
9174 		hexdump(P->data, P->end, stdout);
9175 
9176 		fprintf(stderr, "copy:%"PRIuZ"\n", Q->end);
9177 		hexdump(Q->data, Q->end, stdout);
9178 	}
9179 
9180 	return 0;
9181 } /* parse_packet() */
9182 
9183 
9184 static int parse_domain(int argc, char *argv[]) {
9185 	char *dn;
9186 
9187 	dn	= (argc > 1)? argv[1] : "f.l.google.com";
9188 
9189 	printf("[%s]\n", dn);
9190 
9191 	dn	= dns_d_new(dn);
9192 
9193 	do {
9194 		puts(dn);
9195 	} while (dns_d_cleave(dn, strlen(dn) + 1, dn, strlen(dn)));
9196 
9197 	return 0;
9198 } /* parse_domain() */
9199 
9200 
9201 static int trim_domain(int argc, char **argv) {
9202 	for (argc--, argv++; argc > 0; argc--, argv++) {
9203 		char name[DNS_D_MAXNAME + 1];
9204 
9205 		dns_d_trim(name, sizeof name, *argv, strlen(*argv), DNS_D_ANCHOR);
9206 
9207 		puts(name);
9208 	}
9209 
9210 	return 0;
9211 } /* trim_domain() */
9212 
9213 
9214 static int expand_domain(int argc, char *argv[]) {
9215 	unsigned short rp = 0;
9216 	unsigned char *src = NULL;
9217 	unsigned char *dst;
9218 	struct dns_packet *pkt;
9219 	size_t lim = 0, len;
9220 	int error;
9221 
9222 	if (argc > 1)
9223 		rp = atoi(argv[1]);
9224 
9225 	len = slurp(&src, 0, stdin, "-");
9226 
9227 	if (!(pkt = dns_p_make(len, &error)))
9228 		panic("malloc(%"PRIuZ"): %s", len, dns_strerror(error));
9229 
9230 	memcpy(pkt->data, src, len);
9231 	pkt->end = len;
9232 
9233 	lim = 1;
9234 	dst = grow(NULL, lim);
9235 
9236 	while (lim <= (len = dns_d_expand(dst, lim, rp, pkt, &error))) {
9237 		lim = add(len, 1);
9238 		dst = grow(dst, lim);
9239 	}
9240 
9241 	if (!len)
9242 		panic("expand: %s", dns_strerror(error));
9243 
9244 	fwrite(dst, 1, len, stdout);
9245 	fflush(stdout);
9246 
9247 	free(src);
9248 	free(dst);
9249 	free(pkt);
9250 
9251 	return 0;
9252 } /* expand_domain() */
9253 
9254 
9255 static int show_resconf(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
9256 	unsigned i;
9257 
9258 	resconf(); /* load it */
9259 
9260 	fputs("; SOURCES\n", stdout);
9261 
9262 	for (i = 0; i < MAIN.resconf.count; i++)
9263 		fprintf(stdout, ";   %s\n", MAIN.resconf.path[i]);
9264 
9265 	for (i = 0; i < MAIN.nssconf.count; i++)
9266 		fprintf(stdout, ";   %s\n", MAIN.nssconf.path[i]);
9267 
9268 	fputs(";\n", stdout);
9269 
9270 	dns_resconf_dump(resconf(), stdout);
9271 
9272 	return 0;
9273 } /* show_resconf() */
9274 
9275 
9276 static int show_nssconf(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
9277 	unsigned i;
9278 
9279 	resconf();
9280 
9281 	fputs("# SOURCES\n", stdout);
9282 
9283 	for (i = 0; i < MAIN.resconf.count; i++)
9284 		fprintf(stdout, "#   %s\n", MAIN.resconf.path[i]);
9285 
9286 	for (i = 0; i < MAIN.nssconf.count; i++)
9287 		fprintf(stdout, "#   %s\n", MAIN.nssconf.path[i]);
9288 
9289 	fputs("#\n", stdout);
9290 
9291 	dns_nssconf_dump(resconf(), stdout);
9292 
9293 	return 0;
9294 } /* show_nssconf() */
9295 
9296 
9297 static int show_hosts(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
9298 	unsigned i;
9299 
9300 	hosts();
9301 
9302 	fputs("# SOURCES\n", stdout);
9303 
9304 	for (i = 0; i < MAIN.hosts.count; i++)
9305 		fprintf(stdout, "#   %s\n", MAIN.hosts.path[i]);
9306 
9307 	fputs("#\n", stdout);
9308 
9309 	dns_hosts_dump(hosts(), stdout);
9310 
9311 	return 0;
9312 } /* show_hosts() */
9313 
9314 
9315 static int query_hosts(int argc, char *argv[]) {
9316 	struct dns_packet *Q	= dns_p_new(512);
9317 	struct dns_packet *A;
9318 	char qname[DNS_D_MAXNAME + 1];
9319 	size_t qlen;
9320 	int error;
9321 
9322 	if (!MAIN.qname)
9323 		MAIN.qname	= (argc > 1)? argv[1] : "localhost";
9324 	if (!MAIN.qtype)
9325 		MAIN.qtype	= DNS_T_A;
9326 
9327 	hosts();
9328 
9329 	if (MAIN.qtype == DNS_T_PTR && !strstr(MAIN.qname, "arpa")) {
9330 		union { struct in_addr a; struct in6_addr a6; } addr;
9331 		int af	= (strchr(MAIN.qname, ':'))? AF_INET6 : AF_INET;
9332 
9333 		if ((error = dns_pton(af, MAIN.qname, &addr)))
9334 			panic("%s: %s", MAIN.qname, dns_strerror(error));
9335 
9336 		qlen	= dns_ptr_qname(qname, sizeof qname, af, &addr);
9337 	} else
9338 		qlen	= dns_strlcpy(qname, MAIN.qname, sizeof qname);
9339 
9340 	if ((error = dns_p_push(Q, DNS_S_QD, qname, qlen, MAIN.qtype, DNS_C_IN, 0, 0)))
9341 		panic("%s: %s", qname, dns_strerror(error));
9342 
9343 	if (!(A = dns_hosts_query(hosts(), Q, &error)))
9344 		panic("%s: %s", qname, dns_strerror(error));
9345 
9346 	print_packet(A, stdout);
9347 
9348 	free(A);
9349 
9350 	return 0;
9351 } /* query_hosts() */
9352 
9353 
9354 static int search_list(int argc, char *argv[]) {
9355 	const char *qname	= (argc > 1)? argv[1] : "f.l.google.com";
9356 	unsigned long i		= 0;
9357 	char name[DNS_D_MAXNAME + 1];
9358 
9359 	printf("[%s]\n", qname);
9360 
9361 	while (dns_resconf_search(name, sizeof name, qname, strlen(qname), resconf(), &i))
9362 		puts(name);
9363 
9364 	return 0;
9365 } /* search_list() */
9366 
9367 
9368 static int permute_set(int argc, char *argv[]) {
9369 	unsigned lo, hi, i;
9370 	struct dns_k_permutor p;
9371 
9372 	hi	= (--argc > 0)? atoi(argv[argc]) : 8;
9373 	lo	= (--argc > 0)? atoi(argv[argc]) : 0;
9374 
9375 	fprintf(stderr, "[%u .. %u]\n", lo, hi);
9376 
9377 	dns_k_permutor_init(&p, lo, hi);
9378 
9379 	for (i = lo; i <= hi; i++)
9380 		fprintf(stdout, "%u\n", dns_k_permutor_step(&p));
9381 //		printf("%u -> %u -> %u\n", i, dns_k_permutor_E(&p, i), dns_k_permutor_D(&p, dns_k_permutor_E(&p, i)));
9382 
9383 	return 0;
9384 } /* permute_set() */
9385 
9386 
9387 static int shuffle_16(int argc, char *argv[]) {
9388 	unsigned n, r;
9389 
9390 	if (--argc > 0) {
9391 		n = 0xffff & atoi(argv[argc]);
9392 		r = (--argc > 0)? (unsigned)atoi(argv[argc]) : dns_random();
9393 
9394 		fprintf(stdout, "%hu\n", dns_k_shuffle16(n, r));
9395 	} else {
9396 		r = dns_random();
9397 
9398 		for (n = 0; n < 65536; n++)
9399 			fprintf(stdout, "%hu\n", dns_k_shuffle16(n, r));
9400 	}
9401 
9402 	return 0;
9403 } /* shuffle_16() */
9404 
9405 
9406 static int dump_random(int argc, char *argv[]) {
9407 	unsigned char b[32];
9408 	unsigned i, j, n, r;
9409 
9410 	n	= (argc > 1)? atoi(argv[1]) : 32;
9411 
9412 	while (n) {
9413 		i	= 0;
9414 
9415 		do {
9416 			r	= dns_random();
9417 
9418 			for (j = 0; j < sizeof r && i < n && i < sizeof b; i++, j++) {
9419 				b[i]	= 0xff & r;
9420 				r	>>= 8;
9421 			}
9422 		} while (i < n && i < sizeof b);
9423 
9424 		hexdump(b, i, stdout);
9425 
9426 		n	-= i;
9427 	}
9428 
9429 	return 0;
9430 } /* dump_random() */
9431 
9432 
9433 static int send_query(int argc, char *argv[]) {
9434 	struct dns_packet *A, *Q	= dns_p_new(512);
9435 	char host[INET6_ADDRSTRLEN + 1];
9436 	struct sockaddr_storage ss;
9437 	struct dns_socket *so;
9438 	int error, type;
9439 
9440 	if (argc > 1) {
9441 		ss.ss_family	= (strchr(argv[1], ':'))? AF_INET6 : AF_INET;
9442 
9443 		if ((error = dns_pton(ss.ss_family, argv[1], dns_sa_addr(ss.ss_family, &ss, NULL))))
9444 			panic("%s: %s", argv[1], dns_strerror(error));
9445 
9446 		*dns_sa_port(ss.ss_family, &ss)	= htons(53);
9447 	} else
9448 		memcpy(&ss, &resconf()->nameserver[0], dns_sa_len(&resconf()->nameserver[0]));
9449 
9450 	if (!dns_inet_ntop(ss.ss_family, dns_sa_addr(ss.ss_family, &ss, NULL), host, sizeof host))
9451 		panic("bad host address, or none provided");
9452 
9453 	if (!MAIN.qname)
9454 		MAIN.qname	= "ipv6.google.com";
9455 	if (!MAIN.qtype)
9456 		MAIN.qtype	= DNS_T_AAAA;
9457 
9458 	if ((error = dns_p_push(Q, DNS_S_QD, MAIN.qname, strlen(MAIN.qname), MAIN.qtype, DNS_C_IN, 0, 0)))
9459 		panic("dns_p_push: %s", dns_strerror(error));
9460 
9461 	dns_header(Q)->rd	= 1;
9462 
9463 	if (strstr(argv[0], "udp"))
9464 		type	= SOCK_DGRAM;
9465 	else if (strstr(argv[0], "tcp"))
9466 		type	= SOCK_STREAM;
9467 	else
9468 		type	= dns_res_tcp2type(resconf()->options.tcp);
9469 
9470 	fprintf(stderr, "querying %s for %s IN %s\n", host, MAIN.qname, dns_strtype(MAIN.qtype));
9471 
9472 	if (!(so = dns_so_open((struct sockaddr *)&resconf()->iface, type, dns_opts(), &error)))
9473 		panic("dns_so_open: %s", dns_strerror(error));
9474 
9475 	while (!(A = dns_so_query(so, Q, (struct sockaddr *)&ss, &error))) {
9476 		if (error != DNS_EAGAIN)
9477 			panic("dns_so_query: %s (%d)", dns_strerror(error), error);
9478 		if (dns_so_elapsed(so) > 10)
9479 			panic("query timed-out");
9480 
9481 		dns_so_poll(so, 1);
9482 	}
9483 
9484 	print_packet(A, stdout);
9485 
9486 	dns_so_close(so);
9487 
9488 	return 0;
9489 } /* send_query() */
9490 
9491 
9492 static int print_arpa(int argc, char *argv[]) {
9493 	const char *ip	= (argc > 1)? argv[1] : "::1";
9494 	int af		= (strchr(ip, ':'))? AF_INET6 : AF_INET;
9495 	union { struct in_addr a4; struct in6_addr a6; } addr;
9496 	char host[DNS_D_MAXNAME + 1];
9497 
9498 	if (1 != dns_inet_pton(af, ip, &addr) || 0 == dns_ptr_qname(host, sizeof host, af, &addr))
9499 		panic("%s: invalid address", ip);
9500 
9501 	fprintf(stdout, "%s\n", host);
9502 
9503 	return 0;
9504 } /* print_arpa() */
9505 
9506 
9507 static int show_hints(int argc, char *argv[]) {
9508 	struct dns_hints *(*load)(struct dns_resolv_conf *, int *);
9509 	const char *which, *how, *who;
9510 	struct dns_hints *hints;
9511 	int error;
9512 
9513 	which	= (argc > 1)? argv[1] : "local";
9514 	how	= (argc > 2)? argv[2] : "plain";
9515 	who	= (argc > 3)? argv[3] : "google.com";
9516 
9517 	load	= (0 == strcmp(which, "local"))
9518 		? &dns_hints_local
9519 		: &dns_hints_root;
9520 
9521 	if (!(hints = load(resconf(), &error)))
9522 		panic("%s: %s", argv[0], dns_strerror(error));
9523 
9524 	if (0 == strcmp(how, "plain")) {
9525 		dns_hints_dump(hints, stdout);
9526 	} else {
9527 		struct dns_packet *query, *answer;
9528 
9529 		query	= dns_p_new(512);
9530 
9531 		if ((error = dns_p_push(query, DNS_S_QUESTION, who, strlen(who), DNS_T_A, DNS_C_IN, 0, 0)))
9532 			panic("%s: %s", who, dns_strerror(error));
9533 
9534 		if (!(answer = dns_hints_query(hints, query, &error)))
9535 			panic("%s: %s", who, dns_strerror(error));
9536 
9537 		print_packet(answer, stdout);
9538 
9539 		free(answer);
9540 	}
9541 
9542 	dns_hints_close(hints);
9543 
9544 	return 0;
9545 } /* show_hints() */
9546 
9547 
9548 static int resolve_query(int argc DNS_NOTUSED, char *argv[]) {
9549 	_Bool recurse = !!strstr(argv[0], "recurse");
9550 	struct dns_hints *(*hints)() = (recurse)? &dns_hints_root : &dns_hints_local;
9551 	struct dns_resolver *R;
9552 	struct dns_packet *ans;
9553 	const struct dns_stat *st;
9554 	int error;
9555 
9556 	if (!MAIN.qname)
9557 		MAIN.qname = "www.google.com";
9558 	if (!MAIN.qtype)
9559 		MAIN.qtype = DNS_T_A;
9560 
9561 	resconf()->options.recurse = recurse;
9562 
9563 	if (!(R = dns_res_open(resconf(), hosts(), dns_hints_mortal(hints(resconf(), &error)), cache(), dns_opts(), &error)))
9564 		panic("%s: %s", MAIN.qname, dns_strerror(error));
9565 
9566 	if ((error = dns_res_submit(R, MAIN.qname, MAIN.qtype, DNS_C_IN)))
9567 		panic("%s: %s", MAIN.qname, dns_strerror(error));
9568 
9569 	while ((error = dns_res_check(R))) {
9570 		if (error != DNS_EAGAIN)
9571 			panic("dns_res_check: %s (%d)", dns_strerror(error), error);
9572 		if (dns_res_elapsed(R) > 30)
9573 			panic("query timed-out");
9574 
9575 		dns_res_poll(R, 1);
9576 	}
9577 
9578 	ans = dns_res_fetch(R, &error);
9579 	print_packet(ans, stdout);
9580 	free(ans);
9581 
9582 	st = dns_res_stat(R);
9583 	putchar('\n');
9584 	printf(";; queries:  %"PRIuZ"\n", st->queries);
9585 	printf(";; udp sent: %"PRIuZ" in %"PRIuZ" bytes\n", st->udp.sent.count, st->udp.sent.bytes);
9586 	printf(";; udp rcvd: %"PRIuZ" in %"PRIuZ" bytes\n", st->udp.rcvd.count, st->udp.rcvd.bytes);
9587 	printf(";; tcp sent: %"PRIuZ" in %"PRIuZ" bytes\n", st->tcp.sent.count, st->tcp.sent.bytes);
9588 	printf(";; tcp rcvd: %"PRIuZ" in %"PRIuZ" bytes\n", st->tcp.rcvd.count, st->tcp.rcvd.bytes);
9589 
9590 	dns_res_close(R);
9591 
9592 	return 0;
9593 } /* resolve_query() */
9594 
9595 
9596 static int resolve_addrinfo(int argc DNS_NOTUSED, char *argv[]) {
9597 	_Bool recurse = !!strstr(argv[0], "recurse");
9598 	struct dns_hints *(*hints)() = (recurse)? &dns_hints_root : &dns_hints_local;
9599 	struct dns_resolver *res = NULL;
9600 	struct dns_addrinfo *ai = NULL;
9601 	struct addrinfo ai_hints = { .ai_family = PF_UNSPEC, .ai_socktype = SOCK_STREAM, .ai_flags = AI_CANONNAME };
9602 	struct addrinfo *ent;
9603 	char pretty[512];
9604 	int error;
9605 
9606 	if (!MAIN.qname)
9607 		MAIN.qname = "www.google.com";
9608 	/* NB: MAIN.qtype of 0 means obey hints.ai_family */
9609 
9610 	resconf()->options.recurse = recurse;
9611 
9612 	if (!(res = dns_res_open(resconf(), hosts(), dns_hints_mortal(hints(resconf(), &error)), cache(), dns_opts(), &error)))
9613 		panic("%s: %s", MAIN.qname, dns_strerror(error));
9614 
9615 	if (!(ai = dns_ai_open(MAIN.qname, "80", MAIN.qtype, &ai_hints, res, &error)))
9616 		panic("%s: %s", MAIN.qname, dns_strerror(error));
9617 
9618 	do {
9619 		switch (error = dns_ai_nextent(&ent, ai)) {
9620 		case 0:
9621 			dns_ai_print(pretty, sizeof pretty, ent, ai);
9622 
9623 			fputs(pretty, stdout);
9624 
9625 			free(ent);
9626 
9627 			break;
9628 		case ENOENT:
9629 			break;
9630 		case DNS_EAGAIN:
9631 			if (dns_ai_elapsed(ai) > 30)
9632 				panic("query timed-out");
9633 
9634 			dns_ai_poll(ai, 1);
9635 
9636 			break;
9637 		default:
9638 			panic("dns_ai_nextent: %s (%d)", dns_strerror(error), error);
9639 		}
9640 	} while (error != ENOENT);
9641 
9642 	dns_res_close(res);
9643 	dns_ai_close(ai);
9644 
9645 	return 0;
9646 } /* resolve_addrinfo() */
9647 
9648 
9649 static int echo_port(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
9650 	union {
9651 		struct sockaddr sa;
9652 		struct sockaddr_in sin;
9653 	} port;
9654 	int fd;
9655 
9656 	memset(&port, 0, sizeof port);
9657 	port.sin.sin_family = AF_INET;
9658 	port.sin.sin_port = htons(5354);
9659 	port.sin.sin_addr.s_addr = inet_addr("127.0.0.1");
9660 
9661 	if (-1 == (fd = socket(PF_INET, SOCK_DGRAM, 0)))
9662 		panic("socket: %s", strerror(errno));
9663 
9664 	if (0 != bind(fd, &port.sa, sizeof port.sa))
9665 		panic("127.0.0.1:5353: %s", dns_strerror(errno));
9666 
9667 	for (;;) {
9668 		struct dns_packet *pkt = dns_p_new(512);
9669 		struct sockaddr_storage ss;
9670 		socklen_t slen = sizeof ss;
9671 		ssize_t count;
9672 #if defined(MSG_WAITALL) /* MinGW issue */
9673 		int rflags = MSG_WAITALL;
9674 #else
9675 		int rflags = 0;
9676 #endif
9677 
9678 		count = recvfrom(fd, (char *)pkt->data, pkt->size, rflags, (struct sockaddr *)&ss, &slen);
9679 
9680 		if (!count || count < 0)
9681 			panic("recvfrom: %s", strerror(errno));
9682 
9683 		pkt->end = count;
9684 
9685 		dns_p_dump(pkt, stdout);
9686 
9687 		(void)sendto(fd, (char *)pkt->data, pkt->end, 0, (struct sockaddr *)&ss, slen);
9688 	}
9689 
9690 	return 0;
9691 } /* echo_port() */
9692 
9693 
9694 static int isection(int argc, char *argv[]) {
9695 	const char *name = (argc > 1)? argv[1] : "";
9696 	int type;
9697 
9698 	type = dns_isection(name);
9699 	name = dns_strsection(type);
9700 
9701 	printf("%s (%d)\n", name, type);
9702 
9703 	return 0;
9704 } /* isection() */
9705 
9706 
9707 static int iclass(int argc, char *argv[]) {
9708 	const char *name = (argc > 1)? argv[1] : "";
9709 	int type;
9710 
9711 	type = dns_iclass(name);
9712 	name = dns_strclass(type);
9713 
9714 	printf("%s (%d)\n", name, type);
9715 
9716 	return 0;
9717 } /* iclass() */
9718 
9719 
9720 static int itype(int argc, char *argv[]) {
9721 	const char *name = (argc > 1)? argv[1] : "";
9722 	int type;
9723 
9724 	type = dns_itype(name);
9725 	name = dns_strtype(type);
9726 
9727 	printf("%s (%d)\n", name, type);
9728 
9729 	return 0;
9730 } /* itype() */
9731 
9732 
9733 static int iopcode(int argc, char *argv[]) {
9734 	const char *name = (argc > 1)? argv[1] : "";
9735 	int type;
9736 
9737 	type = dns_iopcode(name);
9738 	name = dns_stropcode(type);
9739 
9740 	printf("%s (%d)\n", name, type);
9741 
9742 	return 0;
9743 } /* iopcode() */
9744 
9745 
9746 static int ircode(int argc, char *argv[]) {
9747 	const char *name = (argc > 1)? argv[1] : "";
9748 	int type;
9749 
9750 	type = dns_ircode(name);
9751 	name = dns_strrcode(type);
9752 
9753 	printf("%s (%d)\n", name, type);
9754 
9755 	return 0;
9756 } /* ircode() */
9757 
9758 
9759 #define SIZE1(x) { DNS_PP_STRINGIFY(x), sizeof (x) }
9760 #define SIZE2(x, ...) SIZE1(x), SIZE1(__VA_ARGS__)
9761 #define SIZE3(x, ...) SIZE1(x), SIZE2(__VA_ARGS__)
9762 #define SIZE4(x, ...) SIZE1(x), SIZE3(__VA_ARGS__)
9763 #define SIZE(...) DNS_PP_CALL(DNS_PP_XPASTE(SIZE, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__)
9764 
9765 static int sizes(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
9766 	static const struct { const char *name; size_t size; } type[] = {
9767 		SIZE(struct dns_header, struct dns_packet, struct dns_rr, struct dns_rr_i),
9768 		SIZE(struct dns_a, struct dns_aaaa, struct dns_mx, struct dns_ns),
9769 		SIZE(struct dns_cname, struct dns_soa, struct dns_ptr, struct dns_srv),
9770 		SIZE(struct dns_sshfp, struct dns_txt, union dns_any),
9771 		SIZE(struct dns_resolv_conf, struct dns_hosts, struct dns_hints, struct dns_hints_i),
9772 		SIZE(struct dns_options, struct dns_socket, struct dns_resolver, struct dns_addrinfo),
9773 		SIZE(struct dns_cache), SIZE(size_t), SIZE(void *), SIZE(long)
9774 	};
9775 	unsigned i, max;
9776 
9777 	for (i = 0, max = 0; i < lengthof(type); i++)
9778 		max = DNS_PP_MAX(max, strlen(type[i].name));
9779 
9780 	for (i = 0; i < lengthof(type); i++)
9781 		printf("%*s : %"PRIuZ"\n", max, type[i].name, type[i].size);
9782 
9783 	return 0;
9784 } /* sizes() */
9785 
9786 
9787 static const struct { const char *cmd; int (*run)(); const char *help; } cmds[] = {
9788 	{ "parse-packet",	&parse_packet,		"parse binary packet from stdin" },
9789 	{ "parse-domain",	&parse_domain,		"anchor and iteratively cleave domain" },
9790 	{ "trim-domain",	&trim_domain,		"trim and anchor domain name" },
9791 	{ "expand-domain",	&expand_domain,		"expand domain at offset NN in packet from stdin" },
9792 	{ "show-resconf",	&show_resconf,		"show resolv.conf data" },
9793 	{ "show-hosts",		&show_hosts,		"show hosts data" },
9794 	{ "show-nssconf",	&show_nssconf,		"show nsswitch.conf data" },
9795 	{ "query-hosts",	&query_hosts,		"query A, AAAA or PTR in hosts data" },
9796 	{ "search-list",	&search_list,		"generate query search list from domain" },
9797 	{ "permute-set",	&permute_set,		"generate random permutation -> (0 .. N or N .. M)" },
9798 	{ "shuffle-16",		&shuffle_16,		"simple 16-bit permutation" },
9799 	{ "dump-random",	&dump_random,		"generate random bytes" },
9800 	{ "send-query",		&send_query,		"send query to host" },
9801 	{ "send-query-udp",	&send_query,		"send udp query to host" },
9802 	{ "send-query-tcp",	&send_query,		"send tcp query to host" },
9803 	{ "print-arpa",		&print_arpa,		"print arpa. zone name of address" },
9804 	{ "show-hints",		&show_hints,		"print hints: show-hints [local|root] [plain|packet]" },
9805 	{ "resolve-stub",	&resolve_query,		"resolve as stub resolver" },
9806 	{ "resolve-recurse",	&resolve_query,		"resolve as recursive resolver" },
9807 	{ "addrinfo-stub",	&resolve_addrinfo,	"resolve through getaddrinfo clone" },
9808 	{ "addrinfo-recurse",	&resolve_addrinfo,	"resolve through getaddrinfo clone" },
9809 /*	{ "resolve-nameinfo",	&resolve_query,		"resolve as recursive resolver" }, */
9810 	{ "echo",		&echo_port,		"server echo mode, for nmap fuzzing" },
9811 	{ "isection",		&isection,		"parse section string" },
9812 	{ "iclass",		&iclass,		"parse class string" },
9813 	{ "itype",		&itype,			"parse type string" },
9814 	{ "iopcode",		&iopcode,		"parse opcode string" },
9815 	{ "ircode",		&ircode,		"parse rcode string" },
9816 	{ "sizes",		&sizes,			"print data structure sizes" },
9817 };
9818 
9819 
9820 static void print_usage(const char *progname, FILE *fp) {
9821 	static const char *usage	=
9822 		" [OPTIONS] COMMAND [ARGS]\n"
9823 		"  -c PATH   Path to resolv.conf\n"
9824 		"  -n PATH   Path to nsswitch.conf\n"
9825 		"  -l PATH   Path to local hosts\n"
9826 		"  -z PATH   Path to zone cache\n"
9827 		"  -q QNAME  Query name\n"
9828 		"  -t QTYPE  Query type\n"
9829 		"  -s HOW    Sort records\n"
9830 		"  -v        Be more verbose (-vv show packets; -vvv hexdump packets)\n"
9831 		"  -V        Print version info\n"
9832 		"  -h        Print this usage message\n"
9833 		"\n";
9834 	unsigned i, n, m;
9835 
9836 	fputs(progname, fp);
9837 	fputs(usage, fp);
9838 
9839 	for (i = 0, m = 0; i < lengthof(cmds); i++) {
9840 		if (strlen(cmds[i].cmd) > m)
9841 			m	= strlen(cmds[i].cmd);
9842 	}
9843 
9844 	for (i = 0; i < lengthof(cmds); i++) {
9845 		fprintf(fp, "  %s  ", cmds[i].cmd);
9846 
9847 		for (n = strlen(cmds[i].cmd); n < m; n++)
9848 			putc(' ', fp);
9849 
9850 		fputs(cmds[i].help, fp);
9851 		putc('\n', fp);
9852 	}
9853 
9854 	fputs("\nReport bugs to William Ahern <william@25thandClement.com>\n", fp);
9855 } /* print_usage() */
9856 
9857 
9858 static void print_version(const char *progname, FILE *fp) {
9859 	fprintf(fp, "%s (dns.c) %.8X\n", progname, dns_v_rel());
9860 	fprintf(fp, "vendor  %s\n", dns_vendor());
9861 	fprintf(fp, "release %.8X\n", dns_v_rel());
9862 	fprintf(fp, "abi     %.8X\n", dns_v_abi());
9863 	fprintf(fp, "api     %.8X\n", dns_v_api());
9864 } /* print_version() */
9865 
9866 
9867 int main(int argc, char **argv) {
9868 	extern int optind;
9869 	extern char *optarg;
9870 	const char *progname	= argv[0];
9871 	unsigned i;
9872 	int ch;
9873 
9874 	while (-1 != (ch = getopt(argc, argv, "q:t:c:n:l:z:s:vVh"))) {
9875 		switch (ch) {
9876 		case 'c':
9877 			assert(MAIN.resconf.count < lengthof(MAIN.resconf.path));
9878 
9879 			MAIN.resconf.path[MAIN.resconf.count++]	= optarg;
9880 
9881 			break;
9882 		case 'n':
9883 			assert(MAIN.nssconf.count < lengthof(MAIN.nssconf.path));
9884 
9885 			MAIN.nssconf.path[MAIN.nssconf.count++]	= optarg;
9886 
9887 			break;
9888 		case 'l':
9889 			assert(MAIN.hosts.count < lengthof(MAIN.hosts.path));
9890 
9891 			MAIN.hosts.path[MAIN.hosts.count++]	= optarg;
9892 
9893 			break;
9894 		case 'z':
9895 			assert(MAIN.cache.count < lengthof(MAIN.cache.path));
9896 
9897 			MAIN.cache.path[MAIN.cache.count++]	= optarg;
9898 
9899 			break;
9900 		case 'q':
9901 			MAIN.qname	= optarg;
9902 
9903 			break;
9904 		case 't':
9905 			for (i = 0; i < lengthof(dns_rrtypes); i++) {
9906 				if (0 == strcasecmp(dns_rrtypes[i].name, optarg))
9907 					{ MAIN.qtype = dns_rrtypes[i].type; break; }
9908 			}
9909 
9910 			if (MAIN.qtype)
9911 				break;
9912 
9913 			for (i = 0; dns_isdigit(optarg[i]); i++) {
9914 				MAIN.qtype	*= 10;
9915 				MAIN.qtype	+= optarg[i] - '0';
9916 			}
9917 
9918 			if (!MAIN.qtype)
9919 				panic("%s: invalid query type", optarg);
9920 
9921 			break;
9922 		case 's':
9923 			if (0 == strcasecmp(optarg, "packet"))
9924 				MAIN.sort	= &dns_rr_i_packet;
9925 			else if (0 == strcasecmp(optarg, "shuffle"))
9926 				MAIN.sort	= &dns_rr_i_shuffle;
9927 			else if (0 == strcasecmp(optarg, "order"))
9928 				MAIN.sort	= &dns_rr_i_order;
9929 			else
9930 				panic("%s: invalid sort method", optarg);
9931 
9932 			break;
9933 		case 'v':
9934 			dns_debug = ++MAIN.verbose;
9935 
9936 			break;
9937 		case 'V':
9938 			print_version(progname, stdout);
9939 
9940 			return 0;
9941 		case 'h':
9942 			print_usage(progname, stdout);
9943 
9944 			return 0;
9945 		default:
9946 			print_usage(progname, stderr);
9947 
9948 			return EXIT_FAILURE;
9949 		} /* switch() */
9950 	} /* while() */
9951 
9952 	argc	-= optind;
9953 	argv	+= optind;
9954 
9955 	for (i = 0; i < lengthof(cmds) && argv[0]; i++) {
9956 		if (0 == strcmp(cmds[i].cmd, argv[0]))
9957 			return cmds[i].run(argc, argv);
9958 	}
9959 
9960 	print_usage(progname, stderr);
9961 
9962 	return EXIT_FAILURE;
9963 } /* main() */
9964 
9965 
9966 #endif /* DNS_MAIN */
9967 
9968 
9969 /*
9970  * pop file-scoped compiler annotations
9971  */
9972 #if __clang__
9973 #pragma clang diagnostic pop
9974 #elif DNS_GNUC_PREREQ(4,6,0)
9975 #pragma GCC diagnostic pop
9976 #endif
9977 
9978