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