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