summaryrefslogtreecommitdiff
path: root/src/static_libs
diff options
context:
space:
mode:
authorCarsten Haitzler (Rasterman) <raster@rasterman.com>2016-05-22 17:03:26 +0900
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>2016-05-24 09:20:49 +0900
commit1eba9d9de026d9ec28aa5b42457b144e437dbfe3 (patch)
treea081fc4b41fc3c79258425953fa4a5792924bc61 /src/static_libs
parent6e23780bb13fdc16a2034d01bf3fc06a2355fbee (diff)
ecore-con - simplify down to a single libc resolver
Summary: this removes the cares/ares based resolver and the compiled-in dns.c resolver, modified the getaddrinfo based resolver to use threads not forking (almost halving its size) and now makes that the only resolver we have. getaddrinfo handles ipv6 and ipv4 (according to docs). this simplifies code paths, drops code size of the efl tree by about 11k lines of code, makes it easier to test and more robust to future changes with ip resolving as it now just relies on libc. we won't have coverity complaints on dns.c imported code anymore to fix and don't have tokeep up with bugfixes/security from the upstream imported code. this means we use a single resolver on all platforms (windows, mac, linux) as opposed to before where cares was used for windows, and dns.c on linux/mac. oh and the forking original was broken since our move to eo too. so it couldnt even compile if enabled, letalone work. so fix bug with missing /etc/resolv.conf that dns.c couldn't cope with, fix testability, fix maintainability and reduce efl codebase size. this fixes T3668 @fix @improve Subscribers: cedric, seoz, jpeg Maniphest Tasks: T3668 Differential Revision: https://phab.enlightenment.org/D3971
Diffstat (limited to 'src/static_libs')
-rw-r--r--src/static_libs/dns/dns.c8701
-rw-r--r--src/static_libs/dns/dns.h1177
2 files changed, 0 insertions, 9878 deletions
diff --git a/src/static_libs/dns/dns.c b/src/static_libs/dns/dns.c
deleted file mode 100644
index a426a53..0000000
--- a/src/static_libs/dns/dns.c
+++ /dev/null
@@ -1,8701 +0,0 @@
1/* ==========================================================================
2 * dns.c - Recursive, Reentrant DNS Resolver.
3 * --------------------------------------------------------------------------
4 * Copyright (c) 2008, 2009, 2010, 2012, 2013 William Ahern
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to permit
11 * persons to whom the Software is furnished to do so, subject to the
12 * following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
20 * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
21 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
23 * USE OR OTHER DEALINGS IN THE SOFTWARE.
24 * ==========================================================================
25 */
26#if !defined(__FreeBSD__) && !defined(__sun)
27#ifndef _XOPEN_SOURCE
28#define _XOPEN_SOURCE 600
29#endif
30
31#undef _DEFAULT_SOURCE
32#define _DEFAULT_SOURCE
33
34#undef _BSD_SOURCE
35#define _BSD_SOURCE
36
37#undef _DARWIN_C_SOURCE
38#define _DARWIN_C_SOURCE
39
40#undef _NETBSD_SOURCE
41#define _NETBSD_SOURCE
42#endif
43
44#include <stddef.h> /* offsetof() */
45#ifdef _WIN32
46#define uint32_t unsigned int
47#else
48#include <stdint.h> /* uint32_t */
49#endif
50#include <stdlib.h> /* malloc(3) realloc(3) free(3) rand(3) random(3) arc4random(3) */
51#include <stdio.h> /* FILE fopen(3) fclose(3) getc(3) rewind(3) */
52
53#include <string.h> /* memcpy(3) strlen(3) memmove(3) memchr(3) memcmp(3) strchr(3) strsep(3) strcspn(3) */
54#include <strings.h> /* strcasecmp(3) strncasecmp(3) */
55
56#include <ctype.h> /* isspace(3) isdigit(3) */
57
58#include <time.h> /* time_t time(2) difftime(3) */
59
60#include <signal.h> /* SIGPIPE sigemptyset(3) sigaddset(3) sigpending(2) sigprocmask(2) pthread_sigmask(3) sigtimedwait(2) */
61
62#include <errno.h> /* errno EINVAL ENOENT */
63
64#undef NDEBUG
65#include <assert.h> /* assert(3) */
66
67#if _WIN32
68#ifndef FD_SETSIZE
69#define FD_SETSIZE 256
70#endif
71#include <winsock2.h>
72#include <ws2tcpip.h>
73#else
74#include <sys/types.h> /* FD_SETSIZE socklen_t */
75#include <sys/select.h> /* FD_ZERO FD_SET fd_set select(2) */
76#include <sys/socket.h> /* AF_INET AF_INET6 AF_UNIX struct sockaddr struct sockaddr_in struct sockaddr_in6 socket(2) */
77
78#if defined(AF_UNIX)
79#include <sys/un.h> /* struct sockaddr_un */
80#endif
81
82#include <fcntl.h> /* F_SETFD F_GETFL F_SETFL O_NONBLOCK fcntl(2) */
83
84#include <unistd.h> /* _POSIX_THREADS gethostname(3) close(2) */
85
86#include <poll.h> /* POLLIN POLLOUT */
87
88#include <netinet/in.h> /* struct sockaddr_in struct sockaddr_in6 */
89
90#include <arpa/inet.h> /* inet_pton(3) inet_ntop(3) htons(3) ntohs(3) */
91
92#include <netdb.h> /* struct addrinfo */
93#endif
94
95#include "dns.h"
96
97
98/*
99 * C O M P I L E R A N N O T A T I O N S
100 *
101 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
102
103#if __GNUC__
104#define DNS_NOTUSED __attribute__((unused))
105#else
106#define DNS_NOTUSED
107#endif
108
109#if __clang__
110#pragma clang diagnostic push
111#pragma clang diagnostic ignored "-Wunused-parameter"
112#elif (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4
113#pragma GCC diagnostic push
114#pragma GCC diagnostic ignored "-Wunused-parameter"
115#endif
116
117
118/*
119 * S T A N D A R D M A C R O S
120 *
121 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
122
123#ifndef MIN
124#define MIN(a, b) (((a) < (b))? (a) : (b))
125#endif
126
127
128#ifndef MAX
129#define MAX(a, b) (((a) > (b))? (a) : (b))
130#endif
131
132
133#ifndef lengthof
134#define lengthof(a) (sizeof (a) / sizeof (a)[0])
135#endif
136
137#ifndef endof
138#define endof(a) (&(a)[lengthof((a))])
139#endif
140
141
142/*
143 * M I S C E L L A N E O U S C O M P A T
144 *
145 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
146
147#if _WIN32 || _WIN64
148#define PRIuZ "Iu"
149#else
150#define PRIuZ "zu"
151#endif
152
153#ifndef DNS_THREAD_SAFE
154#if (defined _REENTRANT || defined _THREAD_SAFE) && _POSIX_THREADS > 0
155#define DNS_THREAD_SAFE 1
156#else
157#define DNS_THREAD_SAFE 0
158#endif
159#endif
160
161
162/*
163 * D E B U G M A C R O S
164 *
165 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
166
167int dns_debug = 0;
168
169#if DNS_DEBUG
170
171#undef DNS_DEBUG
172#define DNS_DEBUG dns_debug
173
174#define DNS_SAY_(fmt, ...) \
175 do { if (DNS_DEBUG > 0) fprintf(stderr, fmt "%.1s", __func__, __LINE__, __VA_ARGS__); } while (0)
176#define DNS_SAY(...) DNS_SAY_("@@ (%s:%d) " __VA_ARGS__, "\n")
177#define DNS_HAI DNS_SAY("HAI")
178
179#define DNS_SHOW_(P, fmt, ...) do { \
180 if (DNS_DEBUG > 1) { \
181 fprintf(stderr, "@@ BEGIN * * * * * * * * * * * *\n"); \
182 fprintf(stderr, "@@ " fmt "%.0s\n", __VA_ARGS__); \
183 dns_p_dump((P), stderr); \
184 fprintf(stderr, "@@ END * * * * * * * * * * * * *\n\n"); \
185 } \
186} while (0)
187
188#define DNS_SHOW(...) DNS_SHOW_(__VA_ARGS__, "")
189
190#else /* !DNS_DEBUG */
191
192#undef DNS_DEBUG
193#define DNS_DEBUG 0
194
195#define DNS_SAY(...)
196#define DNS_HAI
197#define DNS_SHOW(...)
198
199#endif /* DNS_DEBUG */
200
201
202/*
203 * V E R S I O N R O U T I N E S
204 *
205 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
206
207const char *dns_vendor(void) {
208 return DNS_VENDOR;
209} /* dns_vendor() */
210
211
212int dns_v_rel(void) {
213 return DNS_V_REL;
214} /* dns_v_rel() */
215
216
217int dns_v_abi(void) {
218 return DNS_V_ABI;
219} /* dns_v_abi() */
220
221
222int dns_v_api(void) {
223 return DNS_V_API;
224} /* dns_v_api() */
225
226
227/*
228 * E R R O R R O U T I N E S
229 *
230 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
231
232#if _WIN32
233
234#define DNS_EINTR WSAEINTR
235#define DNS_EINPROGRESS WSAEINPROGRESS
236#define DNS_EISCONN WSAEISCONN
237#define DNS_EWOULDBLOCK WSAEWOULDBLOCK
238#define DNS_EALREADY WSAEALREADY
239#define DNS_EAGAIN EAGAIN
240#define DNS_ETIMEDOUT WSAETIMEDOUT
241
242#define dns_syerr() ((int)GetLastError())
243#define dns_soerr() ((int)WSAGetLastError())
244
245#else
246
247#define DNS_EINTR EINTR
248#define DNS_EINPROGRESS EINPROGRESS
249#define DNS_EISCONN EISCONN
250#define DNS_EWOULDBLOCK EWOULDBLOCK
251#define DNS_EALREADY EALREADY
252#define DNS_EAGAIN EAGAIN
253#define DNS_ETIMEDOUT ETIMEDOUT
254
255#define dns_syerr() errno
256#define dns_soerr() errno
257
258#endif
259
260
261const char *dns_strerror(int error) {
262 switch (error) {
263 case DNS_ENOBUFS:
264 return "DNS packet buffer too small";
265 case DNS_EILLEGAL:
266 return "Illegal DNS RR name or data";
267 case DNS_EORDER:
268 return "Attempt to push RR out of section order";
269 case DNS_ESECTION:
270 return "Invalid section specified";
271 case DNS_EUNKNOWN:
272 return "Unknown DNS error";
273 case DNS_EADDRESS:
274 return "Invalid textual address form";
275 default:
276 return strerror(error);
277 } /* switch() */
278} /* dns_strerror() */
279
280
281/*
282 * A T O M I C R O U T I N E S
283 *
284 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
285
286DNS_NOTUSED static void dns_atomic_fence(void) {
287 return;
288} /* dns_atomic_fence() */
289
290
291static unsigned dns_atomic_inc(dns_atomic_t *i) {
292 return (*i)++;
293} /* dns_atomic_inc() */
294
295
296static unsigned dns_atomic_dec(dns_atomic_t *i) {
297 return (*i)--;
298} /* dns_atomic_dec() */
299
300
301static unsigned dns_atomic_load(dns_atomic_t *i) {
302 return *i;
303} /* dns_atomic_load() */
304
305
306DNS_NOTUSED static unsigned dns_atomic_store(dns_atomic_t *i, unsigned n) {
307 unsigned o;
308
309 o = dns_atomic_load(i);
310 *i = n;
311 return o;
312} /* dns_atomic_store() */
313
314
315/*
316 * C R Y P T O R O U T I N E S
317 *
318 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
319
320/*
321 * P R N G
322 */
323
324#ifndef DNS_RANDOM
325#if defined(HAVE_ARC4RANDOM) \
326 || defined(__OpenBSD__) \
327 || defined(__FreeBSD__) \
328 || defined(__NetBSD__) \
329 || defined(__APPLE__)
330#define DNS_RANDOM arc4random
331#elif __linux
332#define DNS_RANDOM random
333#else
334#define DNS_RANDOM rand
335#endif
336#endif
337
338#define DNS_RANDOM_arc4random 1
339#define DNS_RANDOM_random 2
340#define DNS_RANDOM_rand 3
341#define DNS_RANDOM_RAND_bytes 4
342
343#define DNS_RANDOM_OPENSSL (DNS_RANDOM_RAND_bytes == DNS_PP_XPASTE(DNS_RANDOM_, DNS_RANDOM))
344
345#if DNS_RANDOM_OPENSSL
346#include <openssl/rand.h>
347#endif
348
349static unsigned dns_random_(void) {
350#if DNS_RANDOM_OPENSSL
351 unsigned r;
352
353 assert(1 == RAND_bytes((unsigned char *)&r, sizeof r));
354
355 return r;
356#else
357 return DNS_RANDOM();
358#endif
359} /* dns_random_() */
360
361unsigned (*dns_random)(void) __attribute__((weak)) = &dns_random_;
362
363
364/*
365 * P E R M U T A T I O N G E N E R A T O R
366 */
367
368#define DNS_K_TEA_KEY_SIZE 16
369#define DNS_K_TEA_BLOCK_SIZE 8
370#define DNS_K_TEA_CYCLES 32
371#define DNS_K_TEA_MAGIC 0x9E3779B9U
372
373struct dns_k_tea {
374 uint32_t key[DNS_K_TEA_KEY_SIZE / sizeof (uint32_t)];
375 unsigned cycles;
376}; /* struct dns_k_tea */
377
378
379static void dns_k_tea_init(struct dns_k_tea *tea, uint32_t key[], unsigned cycles) {
380 memcpy(tea->key, key, sizeof tea->key);
381
382 tea->cycles = (cycles)? cycles : DNS_K_TEA_CYCLES;
383} /* dns_k_tea_init() */
384
385
386static void dns_k_tea_encrypt(struct dns_k_tea *tea, uint32_t v[], uint32_t *w) {
387 uint32_t y, z, sum, n;
388
389 y = v[0];
390 z = v[1];
391 sum = 0;
392
393 for (n = 0; n < tea->cycles; n++) {
394 sum += DNS_K_TEA_MAGIC;
395 y += ((z << 4) + tea->key[0]) ^ (z + sum) ^ ((z >> 5) + tea->key[1]);
396 z += ((y << 4) + tea->key[2]) ^ (y + sum) ^ ((y >> 5) + tea->key[3]);
397 }
398
399 w[0] = y;
400 w[1] = z;
401
402 return /* void */;
403} /* dns_k_tea_encrypt() */
404
405
406/*
407 * Permutation generator, based on a Luby-Rackoff Feistel construction.
408 *
409 * Specifically, this is a generic balanced Feistel block cipher using TEA
410 * (another block cipher) as the pseudo-random function, F. At best it's as
411 * strong as F (TEA), notwithstanding the seeding. F could be AES, SHA-1, or
412 * perhaps Bernstein's Salsa20 core; I am naively trying to keep things
413 * simple.
414 *
415 * The generator can create a permutation of any set of numbers, as long as
416 * the size of the set is an even power of 2. This limitation arises either
417 * out of an inherent property of balanced Feistel constructions, or by my
418 * own ignorance. I'll tackle an unbalanced construction after I wrap my
419 * head around Schneier and Kelsey's paper.
420 *
421 * CAVEAT EMPTOR. IANAC.
422 */
423#define DNS_K_PERMUTOR_ROUNDS 8
424
425struct dns_k_permutor {
426 unsigned stepi, length, limit;
427 unsigned shift, mask, rounds;
428
429 struct dns_k_tea tea;
430}; /* struct dns_k_permutor */
431
432
433static inline unsigned dns_k_permutor_powof(unsigned n) {
434 unsigned m, i = 0;
435
436 for (m = 1; m < n; m <<= 1, i++)
437 ;;
438
439 return i;
440} /* dns_k_permutor_powof() */
441
442static void dns_k_permutor_init(struct dns_k_permutor *p, unsigned low, unsigned high) {
443 uint32_t key[DNS_K_TEA_KEY_SIZE / sizeof (uint32_t)];
444 unsigned width, i;
445
446 p->stepi = 0;
447
448 p->length = (high - low) + 1;
449 p->limit = high;
450
451 width = dns_k_permutor_powof(p->length);
452 width += width % 2;
453
454 p->shift = width / 2;
455 p->mask = (1U << p->shift) - 1;
456 p->rounds = DNS_K_PERMUTOR_ROUNDS;
457
458 for (i = 0; i < lengthof(key); i++)
459 key[i] = dns_random();
460
461 dns_k_tea_init(&p->tea, key, 0);
462
463 return /* void */;
464} /* dns_k_permutor_init() */
465
466
467static unsigned dns_k_permutor_F(struct dns_k_permutor *p, unsigned k, unsigned x) {
468 uint32_t in[DNS_K_TEA_BLOCK_SIZE / sizeof (uint32_t)], out[DNS_K_TEA_BLOCK_SIZE / sizeof (uint32_t)];
469
470 memset(in, '\0', sizeof in);
471
472 in[0] = k;
473 in[1] = x;
474
475 dns_k_tea_encrypt(&p->tea, in, out);
476
477 return p->mask & out[0];
478} /* dns_k_permutor_F() */
479
480
481static unsigned dns_k_permutor_E(struct dns_k_permutor *p, unsigned n) {
482 unsigned l[2], r[2];
483 unsigned i;
484
485 i = 0;
486 l[i] = p->mask & (n >> p->shift);
487 r[i] = p->mask & (n >> 0);
488
489 do {
490 l[(i + 1) % 2] = r[i % 2];
491 r[(i + 1) % 2] = l[i % 2] ^ dns_k_permutor_F(p, i, r[i % 2]);
492
493 i++;
494 } while (i < p->rounds - 1);
495
496 return ((l[i % 2] & p->mask) << p->shift) | ((r[i % 2] & p->mask) << 0);
497} /* dns_k_permutor_E() */
498
499
500DNS_NOTUSED static unsigned dns_k_permutor_D(struct dns_k_permutor *p, unsigned n) {
501 unsigned l[2], r[2];
502 unsigned i;
503
504 i = p->rounds - 1;
505 l[i % 2] = p->mask & (n >> p->shift);
506 r[i % 2] = p->mask & (n >> 0);
507
508 do {
509 i--;
510
511 r[i % 2] = l[(i + 1) % 2];
512 l[i % 2] = r[(i + 1) % 2] ^ dns_k_permutor_F(p, i, l[(i + 1) % 2]);
513 } while (i > 0);
514
515 return ((l[i % 2] & p->mask) << p->shift) | ((r[i % 2] & p->mask) << 0);
516} /* dns_k_permutor_D() */
517
518
519static unsigned dns_k_permutor_step(struct dns_k_permutor *p) {
520 unsigned n;
521
522 do {
523 n = dns_k_permutor_E(p, p->stepi++);
524 } while (n >= p->length);
525
526 return n + (p->limit + 1 - p->length);
527} /* dns_k_permutor_step() */
528
529
530/*
531 * Simple permutation box. Useful for shuffling rrsets from an iterator.
532 * Uses AES s-box to provide good diffusion.
533 *
534 * Seems to pass muster under runs test.
535 *
536 * $ for i in 0 1 2 3 4 5 6 7 8 9; do ./dns shuffle-16 > /tmp/out; done
537 * $ R -q -f /dev/stdin 2>/dev/null <<-EOF | awk '/p-value/{ print $8 }'
538 * library(lawstat)
539 * runs.test(scan(file="/tmp/out"))
540 * EOF
541 */
542static unsigned short dns_k_shuffle16(unsigned short n, unsigned s) {
543 static const unsigned char sbox[256] =
544 { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
545 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
546 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
547 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
548 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
549 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
550 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
551 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
552 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
553 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
554 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
555 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
556 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
557 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
558 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
559 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
560 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
561 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
562 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
563 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
564 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
565 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
566 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
567 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
568 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
569 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
570 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
571 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
572 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
573 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
574 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
575 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };
576 unsigned char a, b;
577 unsigned i;
578
579 a = 0xff & (n >> 0);
580 b = 0xff & (n >> 8);
581
582 for (i = 0; i < 4; i++) {
583 a ^= 0xff & s;
584 a = sbox[a] ^ b;
585 b = sbox[b] ^ a;
586 s >>= 8;
587 }
588
589 return ((0xff00 & (a << 8)) | (0x00ff & (b << 0)));
590} /* dns_k_shuffle16() */
591
592
593/*
594 * U T I L I T Y R O U T I N E S
595 *
596 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
597
598#define DNS_MAXINTERVAL 300
599
600struct dns_clock {
601 time_t sample, elapsed;
602}; /* struct dns_clock */
603
604static void dns_begin(struct dns_clock *clk) {
605 clk->sample = time(0);
606 clk->elapsed = 0;
607} /* dns_begin() */
608
609static time_t dns_elapsed(struct dns_clock *clk) {
610 time_t curtime;
611
612 if ((time_t)-1 == time(&curtime))
613 return clk->elapsed;
614
615 if (curtime > clk->sample)
616 clk->elapsed += (time_t)MIN(difftime(curtime, clk->sample), DNS_MAXINTERVAL);
617
618 clk->sample = curtime;
619
620 return clk->elapsed;
621} /* dns_elapsed() */
622
623
624static size_t dns_af_len(int af) {
625 static const size_t table[AF_MAX] = {
626 [AF_INET6] = sizeof (struct sockaddr_in6),
627 [AF_INET] = sizeof (struct sockaddr_in),
628#if defined(AF_UNIX) && !defined(_WIN32)
629 [AF_UNIX] = sizeof (struct sockaddr_un),
630#endif
631 };
632
633 return table[af];
634} /* dns_af_len() */
635
636#define dns_sa_len(sa) dns_af_len(dns_sa_family(sa))
637
638
639#define DNS_SA_NOPORT &dns_sa_noport
640static unsigned short dns_sa_noport;
641
642unsigned short *dns_sa_port(int af, void *sa) {
643 switch (af) {
644 case AF_INET6:
645 return &((struct sockaddr_in6 *)sa)->sin6_port;
646 case AF_INET:
647 return &((struct sockaddr_in *)sa)->sin_port;
648 default:
649 return DNS_SA_NOPORT;
650 }
651} /* dns_sa_port() */
652
653
654void *dns_sa_addr(int af, void *sa) {
655 switch (af) {
656 case AF_INET6:
657 return &((struct sockaddr_in6 *)sa)->sin6_addr;
658 case AF_INET:
659 return &((struct sockaddr_in *)sa)->sin_addr;
660 default:
661 return 0;
662 }
663} /* dns_sa_addr() */
664
665
666#if _WIN32
667static int dns_inet_pton(int af, const void *src, void *dst) {
668 union { struct sockaddr_in sin; struct sockaddr_in6 sin6; } u;
669
670 u.sin.sin_family = af;
671
672 if (0 != WSAStringToAddressA((void *)src, af, (void *)0, (struct sockaddr *)&u, &(int){ sizeof u }))
673 return -1;
674
675 switch (af) {
676 case AF_INET6:
677 *(struct in6_addr *)dst = u.sin6.sin6_addr;
678
679 return 1;
680 case AF_INET:
681 *(struct in_addr *)dst = u.sin.sin_addr;
682
683 return 1;
684 default:
685 return 0;
686 }
687} /* dns_inet_pton() */
688
689const char *dns_inet_ntop(int af, const void *src, void *dst, unsigned long lim) {
690 union { struct sockaddr_in sin; struct sockaddr_in6 sin6; } u;
691
692 /* NOTE: WSAAddressToString will print .sin_port unless zeroed. */
693 memset(&u, 0, sizeof u);
694
695 u.sin.sin_family = af;
696
697 switch (af) {
698 case AF_INET6:
699 u.sin6.sin6_addr = *(struct in6_addr *)src;
700 break;
701 case AF_INET:
702 u.sin.sin_addr = *(struct in_addr *)src;
703
704 break;
705 default:
706 return 0;
707 }
708
709 if (0 != WSAAddressToStringA((struct sockaddr *)&u, dns_sa_len(&u), (void *)0, dst, &lim))
710 return 0;
711
712 return dst;
713} /* dns_inet_ntop() */
714#endif
715
716
717static dns_error_t dns_pton(int af, const void *src, void *dst) {
718 switch (dns_inet_pton(af, src, dst)) {
719 case 1:
720 return 0;
721 case -1:
722 return dns_soerr();
723 default:
724 return DNS_EADDRESS;
725 }
726} /* dns_pton() */
727
728
729static dns_error_t dns_ntop(int af, const void *src, void *dst, unsigned long lim) {
730 return (dns_inet_ntop(af, src, dst, lim))? 0 : dns_soerr();
731} /* dns_ntop() */
732
733
734size_t dns_strlcpy(char *dst, const char *src, size_t lim) {
735 char *d = dst;
736 char *e = &dst[lim];
737 const char *s = src;
738
739 if (d < e) {
740 do {
741 if ('\0' == (*d++ = *s++))
742 return s - src - 1;
743 } while (d < e);
744
745 d[-1] = '\0';
746 }
747
748 while (*s++ != '\0')
749 ;;
750
751 return s - src - 1;
752} /* dns_strlcpy() */
753
754
755size_t dns_strlcat(char *dst, const char *src, size_t lim) {
756 char *d = memchr(dst, '\0', lim);
757 char *e = &dst[lim];
758 const char *s = src;
759 const char *p;
760
761 if (d && d < e) {
762 do {
763 if ('\0' == (*d++ = *s++))
764 return d - dst - 1;
765 } while (d < e);
766
767 d[-1] = '\0';
768 }
769
770 p = s;
771
772 while (*s++ != '\0')
773 ;;
774
775 return lim + (s - p - 1);
776} /* dns_strlcat() */
777
778
779#if _WIN32
780
781static char *dns_strsep(char **sp, const char *delim) {
782 char *p;
783
784 if (!(p = *sp))
785 return 0;
786
787 *sp += strcspn(p, delim);
788
789 if (**sp != '\0') {
790 **sp = '\0';
791 ++*sp;
792 } else
793 *sp = NULL;
794
795 return p;
796} /* dns_strsep() */
797
798#else
799#define dns_strsep(...) strsep(__VA_ARGS__)
800#endif
801
802
803#if _WIN32
804#define strcasecmp(...) _stricmp(__VA_ARGS__)
805#define strncasecmp(...) _strnicmp(__VA_ARGS__)
806#endif
807
808
809static int dns_poll(int fd, short events, int timeout) {
810 fd_set rset, wset;
811
812 if (!events)
813 return 0;
814
815 assert(fd >= 0 && (unsigned)fd < FD_SETSIZE);
816
817 FD_ZERO(&rset);
818 FD_ZERO(&wset);
819
820 if (events & DNS_POLLIN)
821 FD_SET(fd, &rset);
822
823 if (events & DNS_POLLOUT)
824 FD_SET(fd, &wset);
825
826 select(fd + 1, &rset, &wset, 0, (timeout >= 0)? &(struct timeval){ timeout, 0 } : NULL);
827
828 return 0;
829} /* dns_poll() */
830
831
832#if !_WIN32
833DNS_NOTUSED static int dns_sigmask(int how, const sigset_t *set, sigset_t *oset) {
834#if DNS_THREAD_SAFE
835 return pthread_sigmask(how, set, oset);
836#else
837 return (0 == sigprocmask(how, set, oset))? 0 : errno;
838#endif
839} /* dns_sigmask() */
840#endif
841
842
843static long dns_send(int fd, const void *src, size_t lim, int flags) {
844#if _WIN32 || !defined SIGPIPE || defined SO_NOSIGPIPE
845 return send(fd, src, lim, flags);
846#elif defined MSG_NOSIGNAL
847 return send(fd, src, lim, flags|MSG_NOSIGNAL);
848#elif _POSIX_REALTIME_SIGNALS > 0 /* require sigtimedwait */
849 /*
850 * SIGPIPE handling similar to the approach described in
851 * http://krokisplace.blogspot.com/2010/02/suppressing-sigpipe-in-library.html
852 */
853 sigset_t pending, blocked, piped;
854 long count;
855 int saved, error;
856
857 sigemptyset(&pending);
858 sigpending(&pending);
859
860 if (!sigismember(&pending, SIGPIPE)) {
861 sigemptyset(&piped);
862 sigaddset(&piped, SIGPIPE);
863 sigemptyset(&blocked);
864
865 if ((error = dns_sigmask(SIG_BLOCK, &piped, &blocked)))
866 goto error;
867 }
868
869 count = send(fd, src, lim, flags);
870
871 if (!sigismember(&pending, SIGPIPE)) {
872 saved = errno;
873
874 if (count == -1 && errno == EPIPE) {
875 while (-1 == sigtimedwait(&piped, NULL, &(struct timespec){ 0, 0 }) && errno == EINTR)
876 ;;
877 }
878
879 if ((error = dns_sigmask(SIG_SETMASK, &blocked, NULL)))
880 goto error;
881
882 errno = saved;
883 }
884
885 return count;
886error:
887 errno = error;
888
889 return -1;
890#else
891#error "unable to suppress SIGPIPE"
892 return send(fd, src, lim, flags);
893#endif
894} /* dns_send() */
895
896
897/*
898 * P A C K E T R O U T I N E S
899 *
900 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
901
902unsigned dns_p_count(struct dns_packet *P, enum dns_section section) {
903 unsigned count;
904
905 switch (section) {
906 case DNS_S_QD:
907 return ntohs(dns_header(P)->qdcount);
908 case DNS_S_AN:
909 return ntohs(dns_header(P)->ancount);
910 case DNS_S_NS:
911 return ntohs(dns_header(P)->nscount);
912 case DNS_S_AR:
913 return ntohs(dns_header(P)->arcount);
914 default:
915 count = 0;
916
917 if (section & DNS_S_QD)
918 count += ntohs(dns_header(P)->qdcount);
919 if (section & DNS_S_AN)
920 count += ntohs(dns_header(P)->ancount);
921 if (section & DNS_S_NS)
922 count += ntohs(dns_header(P)->nscount);
923 if (section & DNS_S_AR)
924 count += ntohs(dns_header(P)->arcount);
925
926 return count;
927 }
928} /* dns_p_count() */
929
930
931struct dns_packet *dns_p_init(struct dns_packet *P, size_t size) {
932 if (!P)
933 return 0;
934
935 assert(size >= offsetof(struct dns_packet, data) + 12);
936
937 memset(P, 0, sizeof *P);
938 P->size = size - offsetof(struct dns_packet, data);
939 P->end = 12;
940
941 memset(P->data, '\0', 12);
942
943 return P;
944} /* dns_p_init() */
945
946
947static unsigned short dns_p_qend(struct dns_packet *P) {
948 unsigned short qend = 12;
949 unsigned i, count = dns_p_count(P, DNS_S_QD);
950
951 for (i = 0; i < count && qend < P->end; i++) {
952 if (P->end == (qend = dns_d_skip(qend, P)))
953 goto invalid;
954
955 if (P->end - qend < 4)
956 goto invalid;
957
958 qend += 4;
959 }
960
961 return MIN(qend, P->end);
962invalid:
963 return P->end;
964} /* dns_p_qend() */
965
966
967struct dns_packet *dns_p_make(size_t len, int *error) {
968 struct dns_packet *P;
969 size_t size = dns_p_calcsize(len);
970
971 if (!(P = dns_p_init(malloc(size), size)))
972 *error = dns_syerr();
973
974 return P;
975} /* dns_p_make() */
976
977
978int dns_p_grow(struct dns_packet **P) {
979 struct dns_packet *tmp;
980 size_t size;
981 int error;
982
983 if (!*P) {
984 if (!(*P = dns_p_make(DNS_P_QBUFSIZ, &error)))
985 return error;
986
987 return 0;
988 }
989
990 size = dns_p_sizeof(*P);
991 size |= size >> 1;
992 size |= size >> 2;
993 size |= size >> 4;
994 size |= size >> 8;
995 size++;
996
997 if (size > 65536)
998 return DNS_ENOBUFS;
999
1000 if (!(tmp = realloc(*P, dns_p_calcsize(size))))
1001 return dns_syerr();
1002
1003 tmp->size = size;
1004 *P = tmp;
1005
1006 return 0;
1007} /* dns_p_grow() */
1008
1009
1010struct dns_packet *dns_p_copy(struct dns_packet *P, const struct dns_packet *P0) {
1011 if (!P)
1012 return 0;
1013
1014 P->end = MIN(P->size, P0->end);
1015
1016 memcpy(P->data, P0->data, P->end);
1017
1018 return P;
1019} /* dns_p_copy() */
1020
1021
1022struct dns_packet *dns_p_merge(struct dns_packet *A, enum dns_section Amask, struct dns_packet *B, enum dns_section Bmask, int *error_) {
1023 size_t bufsiz = MIN(65535, ((A)? A->end : 0) + ((B)? B->end : 0));
1024 struct dns_packet *M;
1025 enum dns_section section;
1026 struct dns_rr rr, mr;
1027 int error, copy;
1028
1029 if (!A && B) {
1030 A = B;
1031 Amask = Bmask;
1032 B = 0;
1033 }
1034
1035merge:
1036 if (!(M = dns_p_make(bufsiz, &error)))
1037 goto error;
1038
1039 for (section = DNS_S_QD; (DNS_S_ALL & section); section <<= 1) {
1040 if (A && (section & Amask)) {
1041 dns_rr_foreach(&rr, A, .section = section) {
1042 if ((error = dns_rr_copy(M, &rr, A)))
1043 goto error;
1044 }
1045 }
1046
1047 if (B && (section & Bmask)) {
1048 dns_rr_foreach(&rr, B, .section = section) {
1049 copy = 1;
1050
1051 dns_rr_foreach(&mr, M, .type = rr.type, .section = DNS_S_ALL) {
1052 if (!(copy = dns_rr_cmp(&rr, B, &mr, M)))
1053 break;
1054 }
1055
1056 if (copy && (error = dns_rr_copy(M, &rr, B)))
1057 goto error;
1058 }
1059 }
1060 }
1061
1062 return M;
1063error:
1064 free(M); M = 0;
1065
1066 if (error == DNS_ENOBUFS && bufsiz < 65535) {
1067 bufsiz = MIN(65535, bufsiz * 2);
1068
1069 goto merge;
1070 }
1071
1072 *error_ = error;
1073
1074 return 0;
1075} /* dns_p_merge() */
1076
1077
1078static unsigned short dns_l_skip(unsigned short, const unsigned char *, size_t);
1079
1080void dns_p_dictadd(struct dns_packet *P, unsigned short dn) {
1081 unsigned short lp, lptr, i;
1082
1083 lp = dn;
1084
1085 while (lp < P->end) {
1086 if (0xc0 == (0xc0 & P->data[lp]) && P->end - lp >= 2 && lp != dn) {
1087 lptr = ((0x3f & P->data[lp + 0]) << 8)
1088 | ((0xff & P->data[lp + 1]) << 0);
1089
1090 for (i = 0; i < lengthof(P->dict) && P->dict[i]; i++) {
1091 if (P->dict[i] == lptr) {
1092 P->dict[i] = dn;
1093
1094 return;
1095 }
1096 }
1097 }
1098
1099 lp = dns_l_skip(lp, P->data, P->end);
1100 }
1101
1102 for (i = 0; i < lengthof(P->dict); i++) {
1103 if (!P->dict[i]) {
1104 P->dict[i] = dn;
1105
1106 break;
1107 }
1108 }
1109} /* dns_p_dictadd() */
1110
1111
1112int 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) {
1113 size_t end = P->end;
1114 int error;
1115
1116 if ((error = dns_d_push(P, dn, dnlen)))
1117 goto error;
1118
1119 if (P->size - P->end < 4)
1120 goto nobufs;
1121
1122 P->data[P->end++] = 0xff & (type >> 8);
1123 P->data[P->end++] = 0xff & (type >> 0);
1124
1125 P->data[P->end++] = 0xff & (class >> 8);
1126 P->data[P->end++] = 0xff & (class >> 0);
1127
1128 if (section == DNS_S_QD)
1129 goto update;
1130
1131 if (P->size - P->end < 6)
1132 goto nobufs;
1133
1134 P->data[P->end++] = 0x7f & (ttl >> 24);
1135 P->data[P->end++] = 0xff & (ttl >> 16);
1136 P->data[P->end++] = 0xff & (ttl >> 8);
1137 P->data[P->end++] = 0xff & (ttl >> 0);
1138
1139 if ((error = dns_any_push(P, (union dns_any *)any, type)))
1140 goto error;
1141
1142update:
1143 switch (section) {
1144 case DNS_S_QD:
1145 if (dns_p_count(P, DNS_S_AN|DNS_S_NS|DNS_S_AR))
1146 goto order;
1147
1148 if (!P->qd.base && (error = dns_p_study(P)))
1149 goto error;
1150
1151 dns_header(P)->qdcount = htons(ntohs(dns_header(P)->qdcount) + 1);
1152
1153 P->qd.end = P->end;
1154 P->an.base = P->end;
1155 P->an.end = P->end;
1156 P->ns.base = P->end;
1157 P->ns.end = P->end;
1158 P->ar.base = P->end;
1159 P->ar.end = P->end;
1160
1161 break;
1162 case DNS_S_AN:
1163 if (dns_p_count(P, DNS_S_NS|DNS_S_AR))
1164 goto order;
1165
1166 if (!P->an.base && (error = dns_p_study(P)))
1167 goto error;
1168
1169 dns_header(P)->ancount = htons(ntohs(dns_header(P)->ancount) + 1);
1170
1171 P->an.end = P->end;
1172 P->ns.base = P->end;
1173 P->ns.end = P->end;
1174 P->ar.base = P->end;
1175 P->ar.end = P->end;
1176
1177 break;
1178 case DNS_S_NS:
1179 if (dns_p_count(P, DNS_S_AR))
1180 goto order;
1181
1182 if (!P->ns.base && (error = dns_p_study(P)))
1183 goto error;
1184
1185 dns_header(P)->nscount = htons(ntohs(dns_header(P)->nscount) + 1);
1186
1187 P->ns.end = P->end;
1188 P->ar.base = P->end;
1189 P->ar.end = P->end;
1190
1191 break;
1192 case DNS_S_AR:
1193 if (!P->ar.base && (error = dns_p_study(P)))
1194 goto error;
1195
1196 dns_header(P)->arcount = htons(ntohs(dns_header(P)->arcount) + 1);
1197
1198 P->ar.end = P->end;
1199
1200 break;
1201 default:
1202 error = DNS_ESECTION;
1203
1204 goto error;
1205 } /* switch() */
1206
1207 return 0;
1208nobufs:
1209 error = DNS_ENOBUFS;
1210
1211 goto error;
1212order:
1213 error = DNS_EORDER;
1214
1215 goto error;
1216error:
1217 P->end = end;
1218
1219 return error;
1220} /* dns_p_push() */
1221
1222
1223static void dns_p_dump3(struct dns_packet *P, struct dns_rr_i *I, FILE *fp) {
1224 enum dns_section section;
1225 struct dns_rr rr;
1226 int error;
1227 union dns_any any;
1228 char pretty[sizeof any * 2];
1229 size_t len;
1230
1231 fputs(";; [HEADER]\n", fp);
1232 fprintf(fp, ";; qr : %s(%d)\n", (dns_header(P)->qr)? "RESPONSE" : "QUERY", dns_header(P)->qr);
1233 fprintf(fp, ";; opcode : %s(%d)\n", dns_stropcode(dns_header(P)->opcode), dns_header(P)->opcode);
1234 fprintf(fp, ";; aa : %s(%d)\n", (dns_header(P)->aa)? "AUTHORITATIVE" : "NON-AUTHORITATIVE", dns_header(P)->aa);
1235 fprintf(fp, ";; tc : %s(%d)\n", (dns_header(P)->tc)? "TRUNCATED" : "NOT-TRUNCATED", dns_header(P)->tc);
1236 fprintf(fp, ";; rd : %s(%d)\n", (dns_header(P)->rd)? "RECURSION-DESIRED" : "RECURSION-NOT-DESIRED", dns_header(P)->rd);
1237 fprintf(fp, ";; ra : %s(%d)\n", (dns_header(P)->ra)? "RECURSION-ALLOWED" : "RECURSION-NOT-ALLOWED", dns_header(P)->ra);
1238 fprintf(fp, ";; rcode : %s(%d)\n", dns_strrcode(dns_header(P)->rcode), dns_header(P)->rcode);
1239
1240 section = 0;
1241
1242 while (dns_rr_grep(&rr, 1, I, P, &error)) {
1243 if (section != rr.section)
1244 fprintf(fp, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(P, rr.section));
1245
1246 if ((len = dns_rr_print(pretty, sizeof pretty, &rr, P, &error)))
1247 fprintf(fp, "%s\n", pretty);
1248
1249 section = rr.section;
1250 }
1251} /* dns_p_dump3() */
1252
1253
1254void dns_p_dump(struct dns_packet *P, FILE *fp) {
1255 dns_p_dump3(P, dns_rr_i_new(P, .section = 0), fp);
1256} /* dns_p_dump() */
1257
1258
1259static void dns_s_unstudy(struct dns_s_memo *m)
1260 { m->base = 0; m->end = 0; }
1261
1262static void dns_p_unstudy(struct dns_packet *P) {
1263 dns_s_unstudy(&P->qd);
1264 dns_s_unstudy(&P->an);
1265 dns_s_unstudy(&P->ns);
1266 dns_s_unstudy(&P->ar);
1267} /* dns_p_unstudy() */
1268
1269static int dns_s_study(struct dns_s_memo *m, enum dns_section section, unsigned base, struct dns_packet *P) {
1270 unsigned short count, rp;
1271
1272 count = dns_p_count(P, section);
1273
1274 for (rp = base; count && rp < P->end; count--)
1275 rp = dns_rr_skip(rp, P);
1276
1277 m->base = base;
1278 m->end = rp;
1279
1280 return 0;
1281} /* dns_s_study() */
1282
1283int dns_p_study(struct dns_packet *P) {
1284 int error;
1285
1286 if ((error = dns_s_study(&P->qd, DNS_S_QD, 12, P)))
1287 goto error;
1288
1289 if ((error = dns_s_study(&P->an, DNS_S_AN, P->qd.end, P)))
1290 goto error;
1291
1292 if ((error = dns_s_study(&P->ns, DNS_S_NS, P->an.end, P)))
1293 goto error;
1294
1295 if ((error = dns_s_study(&P->ar, DNS_S_AR, P->ns.end, P)))
1296 goto error;
1297
1298 return 0;
1299error:
1300 dns_p_unstudy(P);
1301
1302 return error;
1303} /* dns_p_study() */
1304
1305
1306/*
1307 * D O M A I N N A M E R O U T I N E S
1308 *
1309 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1310
1311#ifndef DNS_D_MAXPTRS
1312#define DNS_D_MAXPTRS 127 /* Arbitrary; possible, valid depth is something like packet size / 2 + fudge. */
1313#endif
1314
1315static size_t dns_l_expand(unsigned char *dst, size_t lim, unsigned short src, unsigned short *nxt, const unsigned char *data, size_t end) {
1316 unsigned short len;
1317 unsigned nptrs = 0;
1318
1319retry:
1320 if (src >= end)
1321 goto invalid;
1322
1323 switch (0x03 & (data[src] >> 6)) {
1324 case 0x00:
1325 len = (0x3f & (data[src++]));
1326
1327 if (end - src < len)
1328 goto invalid;
1329
1330 if (lim > 0) {
1331 memcpy(dst, &data[src], MIN(lim, len));
1332
1333 dst[MIN(lim - 1, len)] = '\0';
1334 }
1335
1336 *nxt = src + len;
1337
1338 return len;
1339 case 0x01:
1340 goto invalid;
1341 case 0x02:
1342 goto invalid;
1343 case 0x03:
1344 if (++nptrs > DNS_D_MAXPTRS)
1345 goto invalid;
1346
1347 if (end - src < 2)
1348 goto invalid;
1349
1350 src = ((0x3f & data[src + 0]) << 8)
1351 | ((0xff & data[src + 1]) << 0);
1352
1353 goto retry;
1354 } /* switch() */
1355
1356 /* NOT REACHED */
1357invalid:
1358 *nxt = end;
1359
1360 return 0;
1361} /* dns_l_expand() */
1362
1363
1364static unsigned short dns_l_skip(unsigned short src, const unsigned char *data, size_t end) {
1365 unsigned short len;
1366
1367 if (src >= end)
1368 goto invalid;
1369
1370 switch (0x03 & (data[src] >> 6)) {
1371 case 0x00:
1372 len = (0x3f & (data[src++]));
1373
1374 if (end - src < len)
1375 goto invalid;
1376
1377 return (len)? src + len : end;
1378 case 0x01:
1379 goto invalid;
1380 case 0x02:
1381 goto invalid;
1382 case 0x03:
1383 return end;
1384 } /* switch() */
1385
1386 /* NOT REACHED */
1387invalid:
1388 return end;
1389} /* dns_l_skip() */
1390
1391
1392size_t dns_d_trim(void *dst_, size_t lim, const void *src_, size_t len, int flags) {
1393 unsigned char *dst = dst_;
1394 const unsigned char *src = src_;
1395 size_t dp = 0, sp = 0;
1396 int lc;
1397
1398 /* trim any leading dot(s) */
1399 while (sp < len && src[sp] == '.')
1400 sp++;
1401
1402 for (lc = 0; sp < len; lc = src[sp++]) {
1403 /* trim extra dot(s) */
1404 if (src[sp] == '.' && lc == '.')
1405 continue;
1406
1407 if (dp < lim)
1408 dst[dp] = src[sp];
1409
1410 dp++;
1411 }
1412
1413 if ((flags & DNS_D_ANCHOR) && lc != '.') {
1414 if (dp < lim)
1415 dst[dp] = '.';
1416
1417 dp++;
1418 }
1419
1420 if (lim > 0)
1421 dst[MIN(dp, lim - 1)] = '\0';
1422
1423 return dp;
1424} /* dns_d_trim() */
1425
1426
1427char *dns_d_init(void *dst, size_t lim, const void *src, size_t len, int flags) {
1428 if (flags & DNS_D_TRIM) {
1429 dns_d_trim(dst, lim, src, len, flags);
1430 } if (flags & DNS_D_ANCHOR) {
1431 dns_d_anchor(dst, lim, src, len);
1432 } else {
1433 memmove(dst, src, MIN(lim, len));
1434
1435 if (lim > 0)
1436 ((char *)dst)[MIN(len, lim - 1)] = '\0';
1437 }
1438
1439 return dst;
1440} /* dns_d_init() */
1441
1442
1443size_t dns_d_anchor(void *dst, size_t lim, const void *src, size_t len) {
1444 if (len == 0)
1445 return 0;
1446
1447 memmove(dst, src, MIN(lim, len));
1448
1449 if (((const char *)src)[len - 1] != '.') {
1450 if (len < lim)
1451 ((char *)dst)[len] = '.';
1452 len++;
1453 }
1454
1455 if (lim > 0)
1456 ((char *)dst)[MIN(lim - 1, len)] = '\0';
1457
1458 return len;
1459} /* dns_d_anchor() */
1460
1461
1462size_t dns_d_cleave(void *dst, size_t lim, const void *src, size_t len) {
1463 const char *dot;
1464
1465 /* XXX: Skip any leading dot. Handles cleaving root ".". */
1466 if (len == 0 || !(dot = memchr((const char *)src + 1, '.', len - 1)))
1467 return 0;
1468
1469 len -= dot - (const char *)src;
1470
1471 /* XXX: Unless root, skip the label's trailing dot. */
1472 if (len > 1) {
1473 src = ++dot;
1474 len--;
1475 } else
1476 src = dot;
1477
1478 memmove(dst, src, MIN(lim, len));
1479
1480 if (lim > 0)
1481 ((char *)dst)[MIN(lim - 1, len)] = '\0';
1482
1483 return len;
1484} /* dns_d_cleave() */
1485
1486
1487size_t dns_d_comp(void *dst_, size_t lim, const void *src_, size_t len, struct dns_packet *P, int *error DNS_NOTUSED) {
1488 struct { unsigned char *b; size_t p, x; } dst, src;
1489 unsigned char ch = '.';
1490
1491 dst.b = dst_;
1492 dst.p = 0;
1493 dst.x = 1;
1494
1495 src.b = (unsigned char *)src_;
1496 src.p = 0;
1497 src.x = 0;
1498
1499 while (src.x < len) {
1500 ch = src.b[src.x];
1501
1502 if (ch == '.') {
1503 if (dst.p < lim)
1504 dst.b[dst.p] = (0x3f & (src.x - src.p));
1505
1506 dst.p = dst.x++;
1507 src.p = ++src.x;
1508 } else {
1509 if (dst.x < lim)
1510 dst.b[dst.x] = ch;
1511
1512 dst.x++;
1513 src.x++;
1514 }
1515 } /* while() */
1516
1517 if (src.x > src.p) {
1518 if (dst.p < lim)
1519 dst.b[dst.p] = (0x3f & (src.x - src.p));
1520
1521 dst.p = dst.x;
1522 }
1523
1524 if (dst.p > 1) {
1525 if (dst.p < lim)
1526 dst.b[dst.p] = 0x00;
1527
1528 dst.p++;
1529 }
1530
1531#if 1
1532 if (dst.p < lim) {
1533 struct { unsigned char label[DNS_D_MAXLABEL + 1]; size_t len; unsigned short p, x, y; } a, b;
1534 unsigned i;
1535
1536 a.p = 0;
1537
1538 while ((a.len = dns_l_expand(a.label, sizeof a.label, a.p, &a.x, dst.b, lim))) {
1539 for (i = 0; i < lengthof(P->dict) && P->dict[i]; i++) {
1540 b.p = P->dict[i];
1541
1542 while ((b.len = dns_l_expand(b.label, sizeof b.label, b.p, &b.x, P->data, P->end))) {
1543 a.y = a.x;
1544 b.y = b.x;
1545
1546 while (a.len && b.len && 0 == strcasecmp((char *)a.label, (char *)b.label)) {
1547 a.len = dns_l_expand(a.label, sizeof a.label, a.y, &a.y, dst.b, lim);
1548 b.len = dns_l_expand(b.label, sizeof b.label, b.y, &b.y, P->data, P->end);
1549 }
1550
1551 if (a.len == 0 && b.len == 0 && b.p <= 0x3fff) {
1552 dst.b[a.p++] = 0xc0
1553 | (0x3f & (b.p >> 8));
1554 dst.b[a.p++] = (0xff & (b.p >> 0));
1555
1556 return a.p;
1557 }
1558
1559 b.p = b.x;
1560 } /* while() */
1561 } /* for() */
1562
1563 a.p = a.x;
1564 } /* while() */
1565 } /* if () */
1566#endif
1567
1568 return dst.p;
1569} /* dns_d_comp() */
1570
1571
1572unsigned short dns_d_skip(unsigned short src, struct dns_packet *P) {
1573 unsigned short len;
1574
1575 while (src < P->end) {
1576 switch (0x03 & (P->data[src] >> 6)) {
1577 case 0x00: /* FOLLOWS */
1578 len = (0x3f & P->data[src++]);
1579
1580 if (0 == len) {
1581/* success ==> */ return src;
1582 } else if (P->end - src > len) {
1583 src += len;
1584
1585 break;
1586 } else
1587 goto invalid;
1588
1589 /* NOT REACHED */
1590 case 0x01: /* RESERVED */
1591 goto invalid;
1592 case 0x02: /* RESERVED */
1593 goto invalid;
1594 case 0x03: /* POINTER */
1595 if (P->end - src < 2)
1596 goto invalid;
1597
1598 src += 2;
1599
1600/* success ==> */ return src;
1601 } /* switch() */
1602 } /* while() */
1603
1604invalid:
1605//assert(0);
1606 return P->end;
1607} /* dns_d_skip() */
1608
1609
1610#include <stdio.h>
1611
1612size_t dns_d_expand(void *dst, size_t lim, unsigned short src, struct dns_packet *P, int *error) {
1613 size_t dstp = 0;
1614 unsigned nptrs = 0;
1615 unsigned char len;
1616
1617 while (src < P->end) {
1618 switch ((0x03 & (P->data[src] >> 6))) {
1619 case 0x00: /* FOLLOWS */
1620 len = (0x3f & P->data[src]);
1621
1622 if (0 == len) {
1623 if (dstp == 0) {
1624 if (dstp < lim)
1625 ((unsigned char *)dst)[dstp] = '.';
1626
1627 dstp++;
1628 }
1629
1630 /* NUL terminate */
1631 if (lim > 0)
1632 ((unsigned char *)dst)[MIN(dstp, lim - 1)] = '\0';
1633
1634/* success ==> */ return dstp;
1635 }
1636
1637 src++;
1638
1639 if (P->end - src < len)
1640 goto toolong;
1641
1642 if (dstp < lim)
1643 memcpy(&((unsigned char *)dst)[dstp], &P->data[src], MIN(len, lim - dstp));
1644
1645 src += len;
1646 dstp += len;
1647
1648 if (dstp < lim)
1649 ((unsigned char *)dst)[dstp] = '.';
1650
1651 dstp++;
1652
1653 nptrs = 0;
1654
1655 continue;
1656 case 0x01: /* RESERVED */
1657 goto reserved;
1658 case 0x02: /* RESERVED */
1659 goto reserved;
1660 case 0x03: /* POINTER */
1661 if (++nptrs > DNS_D_MAXPTRS)
1662 goto toolong;
1663
1664 if (P->end - src < 2)
1665 goto toolong;
1666
1667 src = ((0x3f & P->data[src + 0]) << 8)
1668 | ((0xff & P->data[src + 1]) << 0);
1669
1670 continue;
1671 } /* switch() */
1672 } /* while() */
1673
1674toolong:
1675 *error = DNS_EILLEGAL;
1676
1677 if (lim > 0)
1678 ((unsigned char *)dst)[MIN(dstp, lim - 1)] = '\0';
1679
1680 return 0;
1681reserved:
1682 *error = DNS_EILLEGAL;
1683
1684 if (lim > 0)
1685 ((unsigned char *)dst)[MIN(dstp, lim - 1)] = '\0';
1686
1687 return 0;
1688} /* dns_d_expand() */
1689
1690
1691int dns_d_push(struct dns_packet *P, const void *dn, size_t len) {
1692 size_t lim = P->size - P->end;
1693 unsigned dp = P->end;
1694 int error;
1695
1696 len = dns_d_comp(&P->data[dp], lim, dn, len, P, &error);
1697
1698 if (len == 0)
1699 return error;
1700 if (len > lim)
1701 return DNS_ENOBUFS;
1702
1703 P->end += len;
1704
1705 dns_p_dictadd(P, dp);
1706
1707 return 0;
1708} /* dns_d_push() */
1709
1710
1711size_t dns_d_cname(void *dst, size_t lim, const void *dn, size_t len, struct dns_packet *P, int *error_) {
1712 char host[DNS_D_MAXNAME + 1];
1713 struct dns_rr_i i;
1714 struct dns_rr rr;
1715 unsigned depth;
1716 int error;
1717
1718 if (sizeof host <= dns_d_anchor(host, sizeof host, dn, len))
1719 { error = ENAMETOOLONG; goto error; }
1720
1721 for (depth = 0; depth < 7; depth++) {
1722 dns_rr_i_init(memset(&i, 0, sizeof i), P);
1723
1724 i.section = DNS_S_ALL & ~DNS_S_QD;
1725 i.name = host;
1726 i.type = DNS_T_CNAME;
1727
1728 if (!dns_rr_grep(&rr, 1, &i, P, &error))
1729 break;
1730
1731 if ((error = dns_cname_parse((struct dns_cname *)host, &rr, P)))
1732 goto error;
1733 }
1734
1735 return dns_strlcpy(dst, host, lim);
1736error:
1737 *error_ = error;
1738
1739 return 0;
1740} /* dns_d_cname() */
1741
1742
1743/*
1744 * R E S O U R C E R E C O R D R O U T I N E S
1745 *
1746 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1747
1748int dns_rr_copy(struct dns_packet *P, struct dns_rr *rr, struct dns_packet *Q) {
1749 unsigned char dn[DNS_D_MAXNAME + 1];
1750 union dns_any any;
1751 size_t len;
1752 int error;
1753
1754 if (!(len = dns_d_expand(dn, sizeof dn, rr->dn.p, Q, &error)))
1755 return error;
1756 else if (len >= sizeof dn)
1757 return DNS_EILLEGAL;
1758
1759 if (rr->section != DNS_S_QD && (error = dns_any_parse(dns_any_init(&any, sizeof any), rr, Q)))
1760 return error;
1761
1762 return dns_p_push(P, rr->section, dn, len, rr->type, rr->class, rr->ttl, &any);
1763} /* dns_rr_copy() */
1764
1765
1766int dns_rr_parse(struct dns_rr *rr, unsigned short src, struct dns_packet *P) {
1767 unsigned short p = src;
1768
1769 if (src >= P->end)
1770 goto invalid;
1771
1772 rr->dn.p = p;
1773 rr->dn.len = (p = dns_d_skip(p, P)) - rr->dn.p;
1774
1775 if (P->end - p < 4)
1776 goto invalid;
1777
1778 rr->type = ((0xff & P->data[p + 0]) << 8)
1779 | ((0xff & P->data[p + 1]) << 0);
1780
1781 rr->class = ((0xff & P->data[p + 2]) << 8)
1782 | ((0xff & P->data[p + 3]) << 0);
1783
1784 p += 4;
1785
1786 if (src < dns_p_qend(P)) {
1787 rr->section = DNS_S_QUESTION;
1788
1789 rr->ttl = 0;
1790 rr->rd.p = 0;
1791 rr->rd.len = 0;
1792
1793 return 0;
1794 }
1795
1796 if (P->end - p < 4)
1797 goto invalid;
1798
1799 rr->ttl = ((0x7f & P->data[p + 0]) << 24)
1800 | ((0xff & P->data[p + 1]) << 16)
1801 | ((0xff & P->data[p + 2]) << 8)
1802 | ((0xff & P->data[p + 3]) << 0);
1803
1804 p += 4;
1805
1806 if (P->end - p < 2)
1807 goto invalid;
1808
1809 rr->rd.len = ((0xff & P->data[p + 0]) << 8)
1810 | ((0xff & P->data[p + 1]) << 0);
1811 rr->rd.p = p + 2;
1812
1813 p += 2;
1814
1815 if (P->end - p < rr->rd.len)
1816 goto invalid;
1817
1818 return 0;
1819invalid:
1820//assert(0);
1821 return DNS_EILLEGAL;
1822} /* dns_rr_parse() */
1823
1824
1825static unsigned short dns_rr_len(const unsigned short src, struct dns_packet *P) {
1826 unsigned short rp, rdlen;
1827
1828 rp = dns_d_skip(src, P);
1829
1830 if (P->end - rp < 4)
1831 return P->end - src;
1832
1833 rp += 4; /* TYPE, CLASS */
1834
1835 if (rp <= dns_p_qend(P))
1836 return rp - src;
1837
1838 if (P->end - rp < 6)
1839 return P->end - src;
1840
1841 rp += 6; /* TTL, RDLEN */
1842
1843 rdlen = ((0xff & P->data[rp - 2]) << 8)
1844 | ((0xff & P->data[rp - 1]) << 0);
1845
1846 if (P->end - rp < rdlen)
1847 return P->end - src;
1848
1849 rp += rdlen;
1850
1851 return rp - src;
1852} /* dns_rr_len() */
1853
1854
1855unsigned short dns_rr_skip(unsigned short src, struct dns_packet *P) {
1856 return src + dns_rr_len(src, P);
1857} /* dns_rr_skip() */
1858
1859
1860static enum dns_section dns_rr_section(unsigned short src, struct dns_packet *P) {
1861 enum dns_section section;
1862 unsigned count, ind;
1863 unsigned short rp;
1864
1865 if (src >= P->qd.base && src < P->qd.end)
1866 return DNS_S_QD;
1867 if (src >= P->an.base && src < P->an.end)
1868 return DNS_S_AN;
1869 if (src >= P->ns.base && src < P->ns.end)
1870 return DNS_S_NS;
1871 if (src >= P->ar.base && src < P->ar.end)
1872 return DNS_S_AR;
1873
1874 /* NOTE: Possibly bad memoization. Try it the hard-way. */
1875
1876 for (rp = 12, ind = 0; rp < src && rp < P->end; ind++)
1877 rp = dns_rr_skip(rp, P);
1878
1879 section = DNS_S_QD;
1880 count = dns_p_count(P, section);
1881
1882 while (ind >= count && section <= DNS_S_AR) {
1883 section <<= 1;
1884 count += dns_p_count(P, section);
1885 }
1886
1887 return DNS_S_ALL & section;
1888} /* dns_rr_section() */
1889
1890
1891static enum dns_type dns_rr_type(unsigned short src, struct dns_packet *P) {
1892 struct dns_rr rr;
1893 int error;
1894
1895 if ((error = dns_rr_parse(&rr, src, P)))
1896 return 0;
1897
1898 return rr.type;
1899} /* dns_rr_type() */
1900
1901
1902int dns_rr_cmp(struct dns_rr *r0, struct dns_packet *P0, struct dns_rr *r1, struct dns_packet *P1) {
1903 char host0[DNS_D_MAXNAME + 1], host1[DNS_D_MAXNAME + 1];
1904 union dns_any any0, any1;
1905 int cmp, error;
1906 size_t len;
1907
1908 if ((cmp = r0->type - r1->type))
1909 return cmp;
1910
1911 if ((cmp = r0->class - r1->class))
1912 return cmp;
1913
1914 /*
1915 * FIXME: Do label-by-label comparison to handle illegally long names?
1916 */
1917
1918 if (!(len = dns_d_expand(host0, sizeof host0, r0->dn.p, P0, &error))
1919 || len >= sizeof host0)
1920 return -1;
1921
1922 if (!(len = dns_d_expand(host1, sizeof host1, r1->dn.p, P1, &error))
1923 || len >= sizeof host1)
1924 return 1;
1925
1926 if ((cmp = strcasecmp(host0, host1)))
1927 return cmp;
1928
1929 if (DNS_S_QD & (r0->section | r1->section)) {
1930 if (r0->section == r1->section)
1931 return 0;
1932
1933 return (r0->section == DNS_S_QD)? -1 : 1;
1934 }
1935
1936 if ((error = dns_any_parse(&any0, r0, P0)))
1937 return -1;
1938
1939 if ((error = dns_any_parse(&any1, r1, P1)))
1940 return 1;
1941
1942 return dns_any_cmp(&any0, r0->type, &any1, r1->type);
1943} /* dns_rr_cmp() */
1944
1945
1946static _Bool dns_rr_exists(struct dns_rr *rr0, struct dns_packet *P0, struct dns_packet *P1) {
1947 struct dns_rr rr1;
1948
1949 dns_rr_foreach(&rr1, P1, .section = rr0->section, .type = rr0->type) {
1950 if (0 == dns_rr_cmp(rr0, P0, &rr1, P1))
1951 return 1;
1952 }
1953
1954 return 0;
1955} /* dns_rr_exists() */
1956
1957
1958static unsigned short dns_rr_offset(struct dns_rr *rr) {
1959 return rr->dn.p;
1960} /* dns_rr_offset() */
1961
1962
1963static _Bool dns_rr_i_match(struct dns_rr *rr, struct dns_rr_i *i, struct dns_packet *P) {
1964 if (i->section && !(rr->section & i->section))
1965 return 0;
1966
1967 if (i->type && rr->type != i->type && i->type != DNS_T_ALL)
1968 return 0;
1969
1970 if (i->class && rr->class != i->class && i->class != DNS_C_ANY)
1971 return 0;
1972
1973 if (i->name) {
1974 char dn[DNS_D_MAXNAME + 1];
1975 size_t len;
1976 int error;
1977
1978 if (!(len = dns_d_expand(dn, sizeof dn, rr->dn.p, P, &error))
1979 || len >= sizeof dn)
1980 return 0;
1981
1982 if (0 != strcasecmp(dn, i->name))
1983 return 0;
1984 }
1985
1986 if (i->data && i->type && rr->section > DNS_S_QD) {
1987 union dns_any rd;
1988 int error;
1989
1990 if ((error = dns_any_parse(&rd, rr, P)))
1991 return 0;
1992
1993 if (0 != dns_any_cmp(&rd, rr->type, i->data, i->type))
1994 return 0;
1995 }
1996
1997 return 1;
1998} /* dns_rr_i_match() */
1999
2000
2001static unsigned short dns_rr_i_start(struct dns_rr_i *i, struct dns_packet *P) {
2002 unsigned short rp;
2003 struct dns_rr r0, rr;
2004 int error;
2005
2006 if ((i->section & DNS_S_QD) && P->qd.base)
2007 rp = P->qd.base;
2008 else if ((i->section & DNS_S_AN) && P->an.base)
2009 rp = P->an.base;
2010 else if ((i->section & DNS_S_NS) && P->ns.base)
2011 rp = P->ns.base;
2012 else if ((i->section & DNS_S_AR) && P->ar.base)
2013 rp = P->ar.base;
2014 else
2015 rp = 12;
2016
2017 for (; rp < P->end; rp = dns_rr_skip(rp, P)) {
2018 if ((error = dns_rr_parse(&rr, rp, P)))
2019 continue;
2020
2021 rr.section = dns_rr_section(rp, P);
2022
2023 if (!dns_rr_i_match(&rr, i, P))
2024 continue;
2025
2026 r0 = rr;
2027
2028 goto lower;
2029 }
2030
2031 return P->end;
2032lower:
2033 if (i->sort == &dns_rr_i_packet)
2034 return dns_rr_offset(&r0);
2035
2036 while ((rp = dns_rr_skip(rp, P)) < P->end) {
2037 if ((error = dns_rr_parse(&rr, rp, P)))
2038 continue;
2039
2040 rr.section = dns_rr_section(rp, P);
2041
2042 if (!dns_rr_i_match(&rr, i, P))
2043 continue;
2044
2045 if (i->sort(&rr, &r0, i, P) < 0)
2046 r0 = rr;
2047 }
2048
2049 return dns_rr_offset(&r0);
2050} /* dns_rr_i_start() */
2051
2052
2053static unsigned short dns_rr_i_skip(unsigned short rp, struct dns_rr_i *i, struct dns_packet *P) {
2054 struct dns_rr r0, r1, rr;
2055 int error;
2056
2057 if ((error = dns_rr_parse(&r0, rp, P)))
2058 return P->end;
2059
2060 r0.section = dns_rr_section(rp, P);
2061
2062 rp = (i->sort == &dns_rr_i_packet)? dns_rr_skip(rp, P) : 12;
2063
2064 for (; rp < P->end; rp = dns_rr_skip(rp, P)) {
2065 if ((error = dns_rr_parse(&rr, rp, P)))
2066 continue;
2067
2068 rr.section = dns_rr_section(rp, P);
2069
2070 if (!dns_rr_i_match(&rr, i, P))
2071 continue;
2072
2073 if (i->sort(&rr, &r0, i, P) <= 0)
2074 continue;
2075
2076 r1 = rr;
2077
2078 goto lower;
2079 }
2080
2081 return P->end;
2082lower:
2083 if (i->sort == &dns_rr_i_packet)
2084 return dns_rr_offset(&r1);
2085
2086 while ((rp = dns_rr_skip(rp, P)) < P->end) {
2087 if ((error = dns_rr_parse(&rr, rp, P)))
2088 continue;
2089
2090 rr.section = dns_rr_section(rp, P);
2091
2092 if (!dns_rr_i_match(&rr, i, P))
2093 continue;
2094
2095 if (i->sort(&rr, &r0, i, P) <= 0)
2096 continue;
2097
2098 if (i->sort(&rr, &r1, i, P) >= 0)
2099 continue;
2100
2101 r1 = rr;
2102 }
2103
2104 return dns_rr_offset(&r1);
2105} /* dns_rr_i_skip() */
2106
2107
2108int dns_rr_i_packet(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i DNS_NOTUSED, struct dns_packet *P DNS_NOTUSED) {
2109 return (int)a->dn.p - (int)b->dn.p;
2110} /* dns_rr_i_packet() */
2111
2112
2113int dns_rr_i_order(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i DNS_NOTUSED, struct dns_packet *P) {
2114 int cmp;
2115
2116 if ((cmp = a->section - b->section))
2117 return cmp;
2118
2119 if (a->type != b->type)
2120 return (int)a->dn.p - (int)b->dn.p;
2121
2122 return dns_rr_cmp(a, P, b, P);
2123} /* dns_rr_i_order() */
2124
2125
2126int dns_rr_i_shuffle(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P DNS_NOTUSED) {
2127 int cmp;
2128
2129 while (!i->state.regs[0])
2130 i->state.regs[0] = dns_random();
2131
2132 if ((cmp = a->section - b->section))
2133 return cmp;
2134
2135 return dns_k_shuffle16(a->dn.p, i->state.regs[0]) - dns_k_shuffle16(b->dn.p, i->state.regs[0]);
2136} /* dns_rr_i_shuffle() */
2137
2138
2139struct dns_rr_i *dns_rr_i_init(struct dns_rr_i *i, struct dns_packet *P DNS_NOTUSED) {
2140 static const struct dns_rr_i i_initializer;
2141
2142 i->state = i_initializer.state;
2143 i->saved = i->state;
2144
2145 return i;
2146} /* dns_rr_i_init() */
2147
2148
2149unsigned dns_rr_grep(struct dns_rr *rr, unsigned lim, struct dns_rr_i *i, struct dns_packet *P, int *error_) {
2150 unsigned count = 0;
2151 int error;
2152
2153 switch (i->state.exec) {
2154 case 0:
2155 if (!i->sort)
2156 i->sort = &dns_rr_i_packet;
2157
2158 i->state.next = dns_rr_i_start(i, P);
2159 i->state.exec++;
2160
2161 /* FALL THROUGH */
2162 case 1:
2163 while (count < lim && i->state.next < P->end) {
2164 if ((error = dns_rr_parse(rr, i->state.next, P)))
2165 goto error;
2166
2167 rr->section = dns_rr_section(i->state.next, P);
2168
2169 rr++;
2170 count++;
2171 i->state.count++;
2172
2173 i->state.next = dns_rr_i_skip(i->state.next, i, P);
2174 } /* while() */
2175
2176 break;
2177 } /* switch() */
2178
2179 return count;
2180error:
2181 *error_ = error;
2182
2183 return count;
2184} /* dns_rr_grep() */
2185
2186
2187static size_t dns__printchar(void *dst, size_t lim, size_t cp, unsigned char ch) {
2188 if (cp < lim)
2189 ((unsigned char *)dst)[cp] = ch;
2190
2191 return 1;
2192} /* dns__printchar() */
2193
2194
2195static size_t dns__printstring(void *dst, size_t lim, size_t cp, const void *src, size_t len) {
2196 if (cp < lim)
2197 memcpy(&((unsigned char *)dst)[cp], src, MIN(len, lim - cp));
2198
2199 return len;
2200} /* dns__printstring() */
2201
2202#define dns__printstring5(a, b, c, d, e) dns__printstring((a), (b), (c), (d), (e))
2203#define dns__printstring4(a, b, c, d) dns__printstring((a), (b), (c), (d), strlen((d)))
2204#define dns__printstring(...) DNS_PP_CALL(DNS_PP_XPASTE(dns__printstring, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__)
2205
2206
2207static void dns__printnul(void *dst, size_t lim, size_t off) {
2208 if (lim > 0)
2209 ((unsigned char *)dst)[MIN(off, lim - 1)] = '\0';
2210} /* dns__printnul() */
2211
2212
2213static size_t dns__print10(void *dst, size_t lim, size_t off, unsigned n, unsigned pad) {
2214 unsigned char tmp[32];
2215 unsigned dp = off;
2216 unsigned cp = 0;
2217 unsigned d = 1000000000;
2218 unsigned ch;
2219
2220 pad = MAX(1, pad);
2221
2222 while (d) {
2223 if ((ch = n / d) || cp > 0) {
2224 n -= ch * d;
2225
2226 tmp[cp] = '0' + ch;
2227
2228 cp++;
2229 }
2230
2231 d /= 10;
2232 }
2233
2234 while (cp < pad) {
2235 dp += dns__printchar(dst, lim, dp, '0');
2236 pad--;
2237 }
2238
2239 dp += dns__printstring(dst, lim, dp, tmp, cp);
2240
2241 return dp - off;
2242} /* dns__print10() */
2243
2244
2245size_t dns_rr_print(void *dst, size_t lim, struct dns_rr *rr, struct dns_packet *P, int *error_) {
2246 union dns_any any;
2247 size_t cp, n, rdlen;
2248 void *rd;
2249 int error;
2250
2251 cp = 0;
2252
2253 if (rr->section == DNS_S_QD)
2254 cp += dns__printchar(dst, lim, cp, ';');
2255
2256 if (!(n = dns_d_expand(&((unsigned char *)dst)[cp], (cp < lim)? lim - cp : 0, rr->dn.p, P, &error)))
2257 goto error;
2258
2259 cp += n;
2260
2261 if (rr->section != DNS_S_QD) {
2262 cp += dns__printchar(dst, lim, cp, ' ');
2263 cp += dns__print10(dst, lim, cp, rr->ttl, 0);
2264 }
2265
2266 cp += dns__printchar(dst, lim, cp, ' ');
2267 cp += dns__printstring(dst, lim, cp, dns_strclass(rr->class), strlen(dns_strclass(rr->class)));
2268 cp += dns__printchar(dst, lim, cp, ' ');
2269 cp += dns__printstring(dst, lim, cp, dns_strtype(rr->type), strlen(dns_strtype(rr->type)));
2270
2271 if (rr->section == DNS_S_QD)
2272 goto epilog;
2273
2274 cp += dns__printchar(dst, lim, cp, ' ');
2275
2276 if ((error = dns_any_parse(dns_any_init(&any, sizeof any), rr, P)))
2277 goto error;
2278
2279 if (cp < lim) {
2280 rd = &((unsigned char *)dst)[cp];
2281 rdlen = lim - cp;
2282 } else {
2283 rd = 0;
2284 rdlen = 0;
2285 }
2286
2287 cp += dns_any_print(rd, rdlen, &any, rr->type);
2288
2289epilog:
2290 dns__printnul(dst, lim, cp);
2291
2292 return cp;
2293error:
2294 *error_ = error;
2295
2296 return 0;
2297} /* dns_rr_print() */
2298
2299
2300int dns_a_parse(struct dns_a *a, struct dns_rr *rr, struct dns_packet *P) {
2301 unsigned long addr;
2302
2303 if (rr->rd.len != 4)
2304 return DNS_EILLEGAL;
2305
2306 addr = ((0xff & P->data[rr->rd.p + 0]) << 24)
2307 | ((0xff & P->data[rr->rd.p + 1]) << 16)
2308 | ((0xff & P->data[rr->rd.p + 2]) << 8)
2309 | ((0xff & P->data[rr->rd.p + 3]) << 0);
2310
2311 a->addr.s_addr = htonl(addr);
2312
2313 return 0;
2314} /* dns_a_parse() */
2315
2316
2317int dns_a_push(struct dns_packet *P, struct dns_a *a) {
2318 unsigned long addr;
2319
2320 if (P->size - P->end < 6)
2321 return DNS_ENOBUFS;
2322
2323 P->data[P->end++] = 0x00;
2324 P->data[P->end++] = 0x04;
2325
2326 addr = ntohl(a->addr.s_addr);
2327
2328 P->data[P->end++] = 0xff & (addr >> 24);
2329 P->data[P->end++] = 0xff & (addr >> 16);
2330 P->data[P->end++] = 0xff & (addr >> 8);
2331 P->data[P->end++] = 0xff & (addr >> 0);
2332
2333 return 0;
2334} /* dns_a_push() */
2335
2336
2337size_t dns_a_arpa(void *dst, size_t lim, const struct dns_a *a) {
2338 unsigned long a4 = ntohl(a->addr.s_addr);
2339 size_t cp = 0;
2340 unsigned i;
2341
2342 for (i = 4; i > 0; i--) {
2343 cp += dns__print10(dst, lim, cp, (0xff & a4), 0);
2344 cp += dns__printchar(dst, lim, cp, '.');
2345 a4 >>= 8;
2346 }
2347
2348 cp += dns__printstring(dst, lim, cp, "in-addr.arpa.");
2349
2350 dns__printnul(dst, lim, cp);
2351
2352 return cp;
2353} /* dns_a_arpa() */
2354
2355
2356int dns_a_cmp(const struct dns_a *a, const struct dns_a *b) {
2357 if (ntohl(a->addr.s_addr) < ntohl(b->addr.s_addr))
2358 return -1;
2359 if (ntohl(a->addr.s_addr) > ntohl(b->addr.s_addr))
2360 return 1;
2361
2362 return 0;
2363} /* dns_a_cmp() */
2364
2365
2366size_t dns_a_print(void *dst, size_t lim, struct dns_a *a) {
2367 char addr[INET_ADDRSTRLEN + 1] = "0.0.0.0";
2368 size_t len;
2369
2370 dns_inet_ntop(AF_INET, &a->addr, addr, sizeof addr);
2371
2372 dns__printnul(dst, lim, (len = dns__printstring(dst, lim, 0, addr)));
2373
2374 return len;
2375} /* dns_a_print() */
2376
2377
2378int dns_aaaa_parse(struct dns_aaaa *aaaa, struct dns_rr *rr, struct dns_packet *P) {
2379 if (rr->rd.len != sizeof aaaa->addr.s6_addr)
2380 return DNS_EILLEGAL;
2381
2382 memcpy(aaaa->addr.s6_addr, &P->data[rr->rd.p], sizeof aaaa->addr.s6_addr);
2383
2384 return 0;
2385} /* dns_aaaa_parse() */
2386
2387
2388int dns_aaaa_push(struct dns_packet *P, struct dns_aaaa *aaaa) {
2389 if (P->size - P->end < 2 + sizeof aaaa->addr.s6_addr)
2390 return DNS_ENOBUFS;
2391
2392 P->data[P->end++] = 0x00;
2393 P->data[P->end++] = 0x10;
2394
2395 memcpy(&P->data[P->end], aaaa->addr.s6_addr, sizeof aaaa->addr.s6_addr);
2396
2397 P->end += sizeof aaaa->addr.s6_addr;
2398
2399 return 0;
2400} /* dns_aaaa_push() */
2401
2402
2403int dns_aaaa_cmp(const struct dns_aaaa *a, const struct dns_aaaa *b) {
2404 unsigned i;
2405 int cmp;
2406
2407 for (i = 0; i < lengthof(a->addr.s6_addr); i++) {
2408 if ((cmp = (a->addr.s6_addr[i] - b->addr.s6_addr[i])))
2409 return cmp;
2410 }
2411
2412 return 0;
2413} /* dns_aaaa_cmp() */
2414
2415
2416size_t dns_aaaa_arpa(void *dst, size_t lim, const struct dns_aaaa *aaaa) {
2417 static const unsigned char hex[16] = "0123456789abcdef";
2418 size_t cp = 0;
2419 unsigned nyble;
2420 int i, j;
2421
2422 for (i = sizeof aaaa->addr.s6_addr - 1; i >= 0; i--) {
2423 nyble = aaaa->addr.s6_addr[i];
2424
2425 for (j = 0; j < 2; j++) {
2426 cp += dns__printchar(dst, lim, cp, hex[0x0f & nyble]);
2427 cp += dns__printchar(dst, lim, cp, '.');
2428 nyble >>= 4;
2429 }
2430 }
2431
2432 cp += dns__printstring(dst, lim, cp, "ip6.arpa.");
2433
2434 dns__printnul(dst, lim, cp);
2435
2436 return cp;
2437} /* dns_aaaa_arpa() */
2438
2439
2440size_t dns_aaaa_print(void *dst, size_t lim, struct dns_aaaa *aaaa) {
2441 char addr[INET6_ADDRSTRLEN + 1] = "::";
2442 size_t len;
2443
2444 dns_inet_ntop(AF_INET6, &aaaa->addr, addr, sizeof addr);
2445
2446 dns__printnul(dst, lim, (len = dns__printstring(dst, lim, 0, addr)));
2447
2448 return len;
2449} /* dns_aaaa_print() */
2450
2451
2452int dns_mx_parse(struct dns_mx *mx, struct dns_rr *rr, struct dns_packet *P) {
2453 size_t len;
2454 int error;
2455
2456 if (rr->rd.len < 3)
2457 return DNS_EILLEGAL;
2458
2459 mx->preference = (0xff00 & (P->data[rr->rd.p + 0] << 8))
2460 | (0x00ff & (P->data[rr->rd.p + 1] << 0));
2461
2462 if (!(len = dns_d_expand(mx->host, sizeof mx->host, rr->rd.p + 2, P, &error)))
2463 return error;
2464 else if (len >= sizeof mx->host)
2465 return DNS_EILLEGAL;
2466
2467 return 0;
2468} /* dns_mx_parse() */
2469
2470
2471int dns_mx_push(struct dns_packet *P, struct dns_mx *mx) {
2472 size_t end, len;
2473 int error;
2474
2475 if (P->size - P->end < 5)
2476 return DNS_ENOBUFS;
2477
2478 end = P->end;
2479 P->end += 2;
2480
2481 P->data[P->end++] = 0xff & (mx->preference >> 8);
2482 P->data[P->end++] = 0xff & (mx->preference >> 0);
2483
2484 if ((error = dns_d_push(P, mx->host, strlen(mx->host))))
2485 goto error;
2486
2487 len = P->end - end - 2;
2488
2489 P->data[end + 0] = 0xff & (len >> 8);
2490 P->data[end + 1] = 0xff & (len >> 0);
2491
2492 return 0;
2493error:
2494 P->end = end;
2495
2496 return error;
2497} /* dns_mx_push() */
2498
2499
2500int dns_mx_cmp(const struct dns_mx *a, const struct dns_mx *b) {
2501 int cmp;
2502
2503 if ((cmp = a->preference - b->preference))
2504 return cmp;
2505
2506 return strcasecmp(a->host, b->host);
2507} /* dns_mx_cmp() */
2508
2509
2510size_t dns_mx_print(void *dst, size_t lim, struct dns_mx *mx) {
2511 size_t cp = 0;
2512
2513 cp += dns__print10(dst, lim, cp, mx->preference, 0);
2514 cp += dns__printchar(dst, lim, cp, ' ');
2515 cp += dns__printstring(dst, lim, cp, mx->host, strlen(mx->host));
2516
2517 dns__printnul(dst, lim, cp);
2518
2519 return cp;
2520} /* dns_mx_print() */
2521
2522
2523size_t dns_mx_cname(void *dst, size_t lim, struct dns_mx *mx) {
2524 return dns_strlcpy(dst, mx->host, lim);
2525} /* dns_mx_cname() */
2526
2527
2528int dns_ns_parse(struct dns_ns *ns, struct dns_rr *rr, struct dns_packet *P) {
2529 size_t len;
2530 int error;
2531
2532 if (!(len = dns_d_expand(ns->host, sizeof ns->host, rr->rd.p, P, &error)))
2533 return error;
2534 else if (len >= sizeof ns->host)
2535 return DNS_EILLEGAL;
2536
2537 return 0;
2538} /* dns_ns_parse() */
2539
2540
2541int dns_ns_push(struct dns_packet *P, struct dns_ns *ns) {
2542 size_t end, len;
2543 int error;
2544
2545 if (P->size - P->end < 3)
2546 return DNS_ENOBUFS;
2547
2548 end = P->end;
2549 P->end += 2;
2550
2551 if ((error = dns_d_push(P, ns->host, strlen(ns->host))))
2552 goto error;
2553
2554 len = P->end - end - 2;
2555
2556 P->data[end + 0] = 0xff & (len >> 8);
2557 P->data[end + 1] = 0xff & (len >> 0);
2558
2559 return 0;
2560error:
2561 P->end = end;
2562
2563 return error;
2564} /* dns_ns_push() */
2565
2566
2567int dns_ns_cmp(const struct dns_ns *a, const struct dns_ns *b) {
2568 return strcasecmp(a->host, b->host);
2569} /* dns_ns_cmp() */
2570
2571
2572size_t dns_ns_print(void *dst, size_t lim, struct dns_ns *ns) {
2573 size_t cp;
2574
2575 cp = dns__printstring(dst, lim, 0, ns->host, strlen(ns->host));
2576
2577 dns__printnul(dst, lim, cp);
2578
2579 return cp;
2580} /* dns_ns_print() */
2581
2582
2583size_t dns_ns_cname(void *dst, size_t lim, struct dns_ns *ns) {
2584 return dns_strlcpy(dst, ns->host, lim);
2585} /* dns_ns_cname() */
2586
2587
2588int dns_cname_parse(struct dns_cname *cname, struct dns_rr *rr, struct dns_packet *P) {
2589 return dns_ns_parse((struct dns_ns *)cname, rr, P);
2590} /* dns_cname_parse() */
2591
2592
2593int dns_cname_push(struct dns_packet *P, struct dns_cname *cname) {
2594 return dns_ns_push(P, (struct dns_ns *)cname);
2595} /* dns_cname_push() */
2596
2597
2598int dns_cname_cmp(const struct dns_cname *a, const struct dns_cname *b) {
2599 return strcasecmp(a->host, b->host);
2600} /* dns_cname_cmp() */
2601
2602
2603size_t dns_cname_print(void *dst, size_t lim, struct dns_cname *cname) {
2604 return dns_ns_print(dst, lim, (struct dns_ns *)cname);
2605} /* dns_cname_print() */
2606
2607
2608size_t dns_cname_cname(void *dst, size_t lim, struct dns_cname *cname) {
2609 return dns_strlcpy(dst, cname->host, lim);
2610} /* dns_cname_cname() */
2611
2612
2613int dns_soa_parse(struct dns_soa *soa, struct dns_rr *rr, struct dns_packet *P) {
2614 struct { void *dst; size_t lim; } dn[] =
2615 { { soa->mname, sizeof soa->mname },
2616 { soa->rname, sizeof soa->rname } };
2617 unsigned *ts[] =
2618 { &soa->serial, &soa->refresh, &soa->retry, &soa->expire, &soa->minimum };
2619 unsigned short rp;
2620 unsigned i, j, n;
2621 int error;
2622
2623 /* MNAME / RNAME */
2624 if ((rp = rr->rd.p) >= P->end)
2625 return DNS_EILLEGAL;
2626
2627 for (i = 0; i < lengthof(dn); i++) {
2628 if (!(n = dns_d_expand(dn[i].dst, dn[i].lim, rp, P, &error)))
2629 return error;
2630 else if (n >= dn[i].lim)
2631 return DNS_EILLEGAL;
2632
2633 if ((rp = dns_d_skip(rp, P)) >= P->end)
2634 return DNS_EILLEGAL;
2635 }
2636
2637 /* SERIAL / REFRESH / RETRY / EXPIRE / MINIMUM */
2638 for (i = 0; i < lengthof(ts); i++) {
2639 for (j = 0; j < 4; j++, rp++) {
2640 if (rp >= P->end)
2641 return DNS_EILLEGAL;
2642
2643 *ts[i] <<= 8;
2644 *ts[i] |= (0xff & P->data[rp]);
2645 }
2646 }
2647
2648 return 0;
2649} /* dns_soa_parse() */
2650
2651
2652int dns_soa_push(struct dns_packet *P, struct dns_soa *soa) {
2653 void *dn[] = { soa->mname, soa->rname };
2654 unsigned ts[] = { (0xffffffff & soa->serial),
2655 (0x7fffffff & soa->refresh),
2656 (0x7fffffff & soa->retry),
2657 (0x7fffffff & soa->expire),
2658 (0xffffffff & soa->minimum) };
2659 unsigned i, j;
2660 size_t end, len;
2661 int error;
2662
2663 end = P->end;
2664
2665 if ((P->end += 2) >= P->size)
2666 goto toolong;
2667
2668 /* MNAME / RNAME */
2669 for (i = 0; i < lengthof(dn); i++) {
2670 if ((error = dns_d_push(P, dn[i], strlen(dn[i]))))
2671 goto error;
2672 }
2673
2674 /* SERIAL / REFRESH / RETRY / EXPIRE / MINIMUM */
2675 for (i = 0; i < lengthof(ts); i++) {
2676 if ((P->end += 4) >= P->size)
2677 goto toolong;
2678
2679 for (j = 1; j <= 4; j++) {
2680 P->data[P->end - j] = (0xff & ts[i]);
2681 ts[i] >>= 8;
2682 }
2683 }
2684
2685 len = P->end - end - 2;
2686 P->data[end + 0] = (0xff & (len >> 8));
2687 P->data[end + 1] = (0xff & (len >> 0));
2688
2689 return 0;
2690toolong:
2691 error = DNS_ENOBUFS;
2692
2693 /* FALL THROUGH */
2694error:
2695 P->end = end;
2696
2697 return error;
2698} /* dns_soa_push() */
2699
2700
2701int dns_soa_cmp(const struct dns_soa *a, const struct dns_soa *b) {
2702 int cmp;
2703
2704 if ((cmp = strcasecmp(a->mname, b->mname)))
2705 return cmp;
2706
2707 if ((cmp = strcasecmp(a->rname, b->rname)))
2708 return cmp;
2709
2710 if (a->serial > b->serial)
2711 return -1;
2712 else if (a->serial < b->serial)
2713 return 1;
2714
2715 if (a->refresh > b->refresh)
2716 return -1;
2717 else if (a->refresh < b->refresh)
2718 return 1;
2719
2720 if (a->retry > b->retry)
2721 return -1;
2722 else if (a->retry < b->retry)
2723 return 1;
2724
2725 if (a->expire > b->expire)
2726 return -1;
2727 else if (a->expire < b->expire)
2728 return 1;
2729
2730 if (a->minimum > b->minimum)
2731 return -1;
2732 else if (a->minimum < b->minimum)
2733 return 1;
2734
2735 return 0;
2736} /* dns_soa_cmp() */
2737
2738
2739size_t dns_soa_print(void *dst, size_t lim, struct dns_soa *soa) {
2740 size_t cp = 0;
2741
2742 cp += dns__printstring(dst, lim, cp, soa->mname, strlen(soa->mname));
2743 cp += dns__printchar(dst, lim, cp, ' ');
2744 cp += dns__printstring(dst, lim, cp, soa->rname, strlen(soa->rname));
2745 cp += dns__printchar(dst, lim, cp, ' ');
2746 cp += dns__print10(dst, lim, cp, soa->serial, 0);
2747 cp += dns__printchar(dst, lim, cp, ' ');
2748 cp += dns__print10(dst, lim, cp, soa->refresh, 0);
2749 cp += dns__printchar(dst, lim, cp, ' ');
2750 cp += dns__print10(dst, lim, cp, soa->retry, 0);
2751 cp += dns__printchar(dst, lim, cp, ' ');
2752 cp += dns__print10(dst, lim, cp, soa->expire, 0);
2753 cp += dns__printchar(dst, lim, cp, ' ');
2754 cp += dns__print10(dst, lim, cp, soa->minimum, 0);
2755
2756 dns__printnul(dst, lim, cp);
2757
2758 return cp;
2759} /* dns_soa_print() */
2760
2761
2762int dns_srv_parse(struct dns_srv *srv, struct dns_rr *rr, struct dns_packet *P) {
2763 unsigned short rp;
2764 unsigned i;
2765 size_t n;
2766 int error;
2767
2768 memset(srv, '\0', sizeof *srv);
2769
2770 rp = rr->rd.p;
2771
2772 if (P->size - P->end < 6)
2773 return DNS_EILLEGAL;
2774
2775 for (i = 0; i < 2; i++, rp++) {
2776 srv->priority <<= 8;
2777 srv->priority |= (0xff & P->data[rp]);
2778 }
2779
2780 for (i = 0; i < 2; i++, rp++) {
2781 srv->weight <<= 8;
2782 srv->weight |= (0xff & P->data[rp]);
2783 }
2784
2785 for (i = 0; i < 2; i++, rp++) {
2786 srv->port <<= 8;
2787 srv->port |= (0xff & P->data[rp]);
2788 }
2789
2790 if (!(n = dns_d_expand(srv->target, sizeof srv->target, rp, P, &error)))
2791 return error;
2792 else if (n >= sizeof srv->target)
2793 return DNS_EILLEGAL;
2794
2795 return 0;
2796} /* dns_srv_parse() */
2797
2798
2799int dns_srv_push(struct dns_packet *P, struct dns_srv *srv) {
2800 size_t end, len;
2801 int error;
2802
2803 end = P->end;
2804
2805 if (P->size - P->end < 2)
2806 goto toolong;
2807
2808 P->end += 2;
2809
2810 if (P->size - P->end < 6)
2811 goto toolong;
2812
2813 P->data[P->end++] = 0xff & (srv->priority >> 8);
2814 P->data[P->end++] = 0xff & (srv->priority >> 0);
2815
2816 P->data[P->end++] = 0xff & (srv->weight >> 8);
2817 P->data[P->end++] = 0xff & (srv->weight >> 0);
2818
2819 P->data[P->end++] = 0xff & (srv->port >> 8);
2820 P->data[P->end++] = 0xff & (srv->port >> 0);
2821
2822 if (0 == (len = dns_d_comp(&P->data[P->end], P->size - P->end, srv->target, strlen(srv->target), P, &error)))
2823 goto error;
2824 else if (P->size - P->end < len)
2825 goto toolong;
2826
2827 P->end += len;
2828
2829 if (P->end > 65535)
2830 goto toolong;
2831
2832 len = P->end - end - 2;
2833
2834 P->data[end + 0] = 0xff & (len >> 8);
2835 P->data[end + 1] = 0xff & (len >> 0);
2836
2837 return 0;
2838toolong:
2839 error = DNS_ENOBUFS;
2840
2841 /* FALL THROUGH */
2842error:
2843 P->end = end;
2844
2845 return error;
2846} /* dns_srv_push() */
2847
2848
2849int dns_srv_cmp(const struct dns_srv *a, const struct dns_srv *b) {
2850 int cmp;
2851
2852 if ((cmp = a->priority - b->priority))
2853 return cmp;
2854
2855 /*
2856 * FIXME: We need some sort of random seed to implement the dynamic
2857 * weighting required by RFC 2782.
2858 */
2859 if ((cmp = a->weight - b->weight))
2860 return cmp;
2861
2862 if ((cmp = a->port - b->port))
2863 return cmp;
2864
2865 return strcasecmp(a->target, b->target);
2866} /* dns_srv_cmp() */
2867
2868
2869size_t dns_srv_print(void *dst, size_t lim, struct dns_srv *srv) {
2870 size_t cp = 0;
2871
2872 cp += dns__print10(dst, lim, cp, srv->priority, 0);
2873 cp += dns__printchar(dst, lim, cp, ' ');
2874 cp += dns__print10(dst, lim, cp, srv->weight, 0);
2875 cp += dns__printchar(dst, lim, cp, ' ');
2876 cp += dns__print10(dst, lim, cp, srv->port, 0);
2877 cp += dns__printchar(dst, lim, cp, ' ');
2878 cp += dns__printstring(dst, lim, cp, srv->target, strlen(srv->target));
2879
2880 dns__printnul(dst, lim, cp);
2881
2882 return cp;
2883} /* dns_srv_print() */
2884
2885
2886size_t dns_srv_cname(void *dst, size_t lim, struct dns_srv *srv) {
2887 return dns_strlcpy(dst, srv->target, lim);
2888} /* dns_srv_cname() */
2889
2890
2891unsigned int dns_opt_ttl(const struct dns_opt *opt) {
2892 unsigned int ttl = 0;
2893
2894 ttl |= (0xffU & opt->rcode) << 24U;
2895 ttl |= (0xffU & opt->version) << 16U;
2896
2897 return ttl;
2898} /* dns_opt_ttl() */
2899
2900
2901unsigned short dns_opt_class(const struct dns_opt *opt) {
2902 return opt->maxsize;
2903} /* dns_opt_class() */
2904
2905
2906struct dns_opt *dns_opt_init(struct dns_opt *opt, size_t size) {
2907 assert(size >= offsetof(struct dns_opt, data));
2908
2909 opt->size = size - offsetof(struct dns_opt, data);
2910 opt->len = 0;
2911
2912 opt->rcode = 0;
2913 opt->version = 0;
2914 opt->maxsize = 512;
2915
2916 return opt;
2917} /* dns_opt_init() */
2918
2919
2920int dns_opt_parse(struct dns_opt *opt, struct dns_rr *rr, struct dns_packet *P) {
2921 opt->len = 0;
2922
2923 return 0;
2924} /* dns_opt_parse() */
2925
2926
2927int dns_opt_push(struct dns_packet *P, struct dns_opt *opt) {
2928 return 0;
2929} /* dns_opt_push() */
2930
2931
2932int dns_opt_cmp(const struct dns_opt *a, const struct dns_opt *b) {
2933 return 0;
2934} /* dns_opt_cmp() */
2935
2936
2937size_t dns_opt_print(void *dst, size_t lim, struct dns_opt *opt) {
2938 size_t p = 0, src;
2939
2940 p += dns__printchar(dst, lim, p, '"');
2941
2942 for (src = 0; src < opt->len; src++) {
2943 p += dns__printchar(dst, lim, p, '\\');
2944 p += dns__print10(dst, lim, p, opt->data[src], 3);
2945 }
2946
2947 p += dns__printchar(dst, lim, p, '"');
2948
2949 dns__printnul(dst, lim, p);
2950
2951 return p;
2952} /* dns_opt_print() */
2953
2954
2955int dns_ptr_parse(struct dns_ptr *ptr, struct dns_rr *rr, struct dns_packet *P) {
2956 return dns_ns_parse((struct dns_ns *)ptr, rr, P);
2957} /* dns_ptr_parse() */
2958
2959
2960int dns_ptr_push(struct dns_packet *P, struct dns_ptr *ptr) {
2961 return dns_ns_push(P, (struct dns_ns *)ptr);
2962} /* dns_ptr_push() */
2963
2964
2965size_t dns_ptr_qname(void *dst, size_t lim, int af, void *addr) {
2966 unsigned len = (af == AF_INET6)
2967 ? dns_aaaa_arpa(dst, lim, addr)
2968 : dns_a_arpa(dst, lim, addr);
2969
2970 dns__printnul(dst, lim, len);
2971
2972 return len;
2973} /* dns_ptr_qname() */
2974
2975
2976int dns_ptr_cmp(const struct dns_ptr *a, const struct dns_ptr *b) {
2977 return strcasecmp(a->host, b->host);
2978} /* dns_ptr_cmp() */
2979
2980
2981size_t dns_ptr_print(void *dst, size_t lim, struct dns_ptr *ptr) {
2982 return dns_ns_print(dst, lim, (struct dns_ns *)ptr);
2983} /* dns_ptr_print() */
2984
2985
2986size_t dns_ptr_cname(void *dst, size_t lim, struct dns_ptr *ptr) {
2987 return dns_strlcpy(dst, ptr->host, lim);
2988} /* dns_ptr_cname() */
2989
2990
2991int dns_sshfp_parse(struct dns_sshfp *fp, struct dns_rr *rr, struct dns_packet *P) {
2992 unsigned p = rr->rd.p, pe = rr->rd.p + rr->rd.len;
2993
2994 if (pe - p < 2)
2995 return DNS_EILLEGAL;
2996
2997 fp->algo = P->data[p++];
2998 fp->type = P->data[p++];
2999
3000 switch (fp->type) {
3001 case DNS_SSHFP_SHA1:
3002 if (pe - p < sizeof fp->digest.sha1)
3003 return DNS_EILLEGAL;
3004
3005 memcpy(fp->digest.sha1, &P->data[p], sizeof fp->digest.sha1);
3006
3007 break;
3008 default:
3009 break;
3010 } /* switch() */
3011
3012 return 0;
3013} /* dns_sshfp_parse() */
3014
3015
3016int dns_sshfp_push(struct dns_packet *P, struct dns_sshfp *fp) {
3017 unsigned p = P->end, pe = P->size, n;
3018
3019 if (pe - p < 4)
3020 return DNS_ENOBUFS;
3021
3022 p += 2;
3023 P->data[p++] = 0xff & fp->algo;
3024 P->data[p++] = 0xff & fp->type;
3025
3026 switch (fp->type) {
3027 case DNS_SSHFP_SHA1:
3028 if (pe - p < sizeof fp->digest.sha1)
3029 return DNS_ENOBUFS;
3030
3031 memcpy(&P->data[p], fp->digest.sha1, sizeof fp->digest.sha1);
3032 p += sizeof fp->digest.sha1;
3033
3034 break;
3035 default:
3036 return DNS_EILLEGAL;
3037 } /* switch() */
3038
3039 n = p - P->end - 2;
3040 P->data[P->end++] = 0xff & (n >> 8);
3041 P->data[P->end++] = 0xff & (n >> 0);
3042 P->end = p;
3043
3044 return 0;
3045} /* dns_sshfp_push() */
3046
3047
3048int dns_sshfp_cmp(const struct dns_sshfp *a, const struct dns_sshfp *b) {
3049 int cmp;
3050
3051 if ((cmp = a->algo - b->algo) || (cmp = a->type - b->type))
3052 return cmp;
3053
3054 switch (a->type) {
3055 case DNS_SSHFP_SHA1:
3056 return memcmp(a->digest.sha1, b->digest.sha1, sizeof a->digest.sha1);
3057 default:
3058 return 0;
3059 } /* switch() */
3060
3061 /* NOT REACHED */
3062} /* dns_sshfp_cmp() */
3063
3064
3065size_t dns_sshfp_print(void *dst, size_t lim, struct dns_sshfp *fp) {
3066 static const unsigned char hex[16] = "0123456789abcdef";
3067 size_t i, p = 0;
3068
3069 p += dns__print10(dst, lim, p, fp->algo, 0);
3070 p += dns__printchar(dst, lim, p, ' ');
3071 p += dns__print10(dst, lim, p, fp->type, 0);
3072 p += dns__printchar(dst, lim, p, ' ');
3073
3074 switch (fp->type) {
3075 case DNS_SSHFP_SHA1:
3076 for (i = 0; i < sizeof fp->digest.sha1; i++) {
3077 p += dns__printchar(dst, lim, p, hex[0x0f & (fp->digest.sha1[i] >> 4)]);
3078 p += dns__printchar(dst, lim, p, hex[0x0f & (fp->digest.sha1[i] >> 0)]);
3079 }
3080
3081 break;
3082 default:
3083 p += dns__printchar(dst, lim, p, '0');
3084
3085 break;
3086 } /* switch() */
3087
3088 dns__printnul(dst, lim, p);
3089
3090 return p;
3091} /* dns_sshfp_print() */
3092
3093
3094struct dns_txt *dns_txt_init(struct dns_txt *txt, size_t size) {
3095 assert(size > offsetof(struct dns_txt, data));
3096
3097 txt->size = size - offsetof(struct dns_txt, data);
3098 txt->len = 0;
3099
3100 return txt;
3101} /* dns_txt_init() */
3102
3103
3104int dns_txt_parse(struct dns_txt *txt, struct dns_rr *rr, struct dns_packet *P) {
3105 struct { unsigned char *b; size_t p, end; } dst, src;
3106 unsigned n;
3107
3108 dst.b = txt->data;
3109 dst.p = 0;
3110 dst.end = txt->size;
3111
3112 src.b = P->data;
3113 src.p = rr->rd.p;
3114 src.end = src.p + rr->rd.len;
3115
3116 while (src.p < src.end) {
3117 n = 0xff & P->data[src.p++];
3118
3119 if (src.end - src.p < n || dst.end - dst.p < n)
3120 return DNS_EILLEGAL;
3121
3122 memcpy(&dst.b[dst.p], &src.b[src.p], n);
3123
3124 dst.p += n;
3125 src.p += n;
3126 }
3127
3128 txt->len = dst.p;
3129
3130 return 0;
3131} /* dns_txt_parse() */
3132
3133
3134int dns_txt_push(struct dns_packet *P, struct dns_txt *txt) {
3135 struct { unsigned char *b; size_t p, end; } dst, src;
3136 unsigned n;
3137
3138 dst.b = P->data;
3139 dst.p = P->end;
3140 dst.end = P->size;
3141
3142 src.b = txt->data;
3143 src.p = 0;
3144 src.end = txt->len;
3145
3146 if (dst.end - dst.p < 2)
3147 return DNS_ENOBUFS;
3148
3149 n = txt->len + ((txt->len + 254) / 255);
3150
3151 dst.b[dst.p++] = 0xff & (n >> 8);
3152 dst.b[dst.p++] = 0xff & (n >> 0);
3153
3154 while (src.p < src.end) {
3155 n = MIN(255, src.end - src.p);
3156
3157 if (dst.p >= dst.end)
3158 return DNS_ENOBUFS;
3159
3160 dst.b[dst.p++] = n;
3161
3162 if (dst.end - dst.p < n)
3163 return DNS_ENOBUFS;
3164
3165 memcpy(&dst.b[dst.p], &src.b[src.p], n);
3166
3167 dst.p += n;
3168 src.p += n;
3169 }
3170
3171 P->end = dst.p;
3172
3173 return 0;
3174} /* dns_txt_push() */
3175
3176
3177int dns_txt_cmp(const struct dns_txt *a DNS_NOTUSED, const struct dns_txt *b DNS_NOTUSED) {
3178 return -1;
3179} /* dns_txt_cmp() */
3180
3181
3182size_t dns_txt_print(void *dst_, size_t lim, struct dns_txt *txt) {
3183 struct { unsigned char *b; size_t p, end; } dst, src;
3184 unsigned ch;
3185
3186 dst.b = dst_;
3187 dst.end = lim;
3188 dst.p = 0;
3189
3190 src.b = txt->data;
3191 src.end = txt->len;
3192 src.p = 0;
3193
3194 dst.p += dns__printchar(dst.b, dst.end, dst.p, '"');
3195
3196 while (src.p < src.end) {
3197 ch = src.b[src.p];
3198
3199 if (0 == (src.p++ % 255) && src.p != 1) {
3200 dst.p += dns__printchar(dst.b, dst.end, dst.p, '"');
3201 dst.p += dns__printchar(dst.b, dst.end, dst.p, ' ');
3202 dst.p += dns__printchar(dst.b, dst.end, dst.p, '"');
3203 }
3204
3205 if (ch < 32 || ch > 126 || ch == '"' || ch == '\\') {
3206 dst.p += dns__printchar(dst.b, dst.end, dst.p, '\\');
3207 dst.p += dns__print10(dst.b, dst.end, dst.p, ch, 3);
3208 } else {
3209 dst.p += dns__printchar(dst.b, dst.end, dst.p, ch);
3210 }
3211 }
3212
3213 dst.p += dns__printchar(dst.b, dst.end, dst.p, '"');
3214
3215 dns__printnul(dst.b, dst.end, dst.p);
3216
3217 return dst.p;
3218} /* dns_txt_print() */
3219
3220
3221static const struct {
3222 enum dns_type type;
3223 const char *name;
3224 int (*parse)();
3225 int (*push)();
3226 int (*cmp)();
3227 size_t (*print)();
3228 size_t (*cname)();
3229} dns_rrtypes[] = {
3230 { DNS_T_A, "A", &dns_a_parse, &dns_a_push, &dns_a_cmp, &dns_a_print, 0 },
3231 { DNS_T_AAAA, "AAAA", &dns_aaaa_parse, &dns_aaaa_push, &dns_aaaa_cmp, &dns_aaaa_print, 0 },
3232 { DNS_T_MX, "MX", &dns_mx_parse, &dns_mx_push, &dns_mx_cmp, &dns_mx_print, &dns_mx_cname },
3233 { DNS_T_NS, "NS", &dns_ns_parse, &dns_ns_push, &dns_ns_cmp, &dns_ns_print, &dns_ns_cname },
3234 { DNS_T_CNAME, "CNAME", &dns_cname_parse, &dns_cname_push, &dns_cname_cmp, &dns_cname_print, &dns_cname_cname },
3235 { DNS_T_SOA, "SOA", &dns_soa_parse, &dns_soa_push, &dns_soa_cmp, &dns_soa_print, 0 },
3236 { DNS_T_SRV, "SRV", &dns_srv_parse, &dns_srv_push, &dns_srv_cmp, &dns_srv_print, &dns_srv_cname },
3237 { DNS_T_OPT, "OPT", &dns_opt_parse, &dns_opt_push, &dns_opt_cmp, &dns_opt_print, 0 },
3238 { DNS_T_PTR, "PTR", &dns_ptr_parse, &dns_ptr_push, &dns_ptr_cmp, &dns_ptr_print, &dns_ptr_cname },
3239 { DNS_T_TXT, "TXT", &dns_txt_parse, &dns_txt_push, &dns_txt_cmp, &dns_txt_print, 0 },
3240 { DNS_T_SPF, "SPF", &dns_txt_parse, &dns_txt_push, &dns_txt_cmp, &dns_txt_print, 0 },
3241 { DNS_T_SSHFP, "SSHFP", &dns_sshfp_parse, &dns_sshfp_push, &dns_sshfp_cmp, &dns_sshfp_print, 0 },
3242}; /* dns_rrtypes[] */
3243
3244
3245union dns_any *dns_any_init(union dns_any *any, size_t size) {
3246 return (union dns_any *)dns_txt_init(&any->rdata, size);
3247} /* dns_any_init() */
3248
3249
3250int dns_any_parse(union dns_any *any, struct dns_rr *rr, struct dns_packet *P) {
3251 unsigned i;
3252
3253 for (i = 0; i < lengthof(dns_rrtypes); i++) {
3254 if (dns_rrtypes[i].type == rr->type)
3255 return dns_rrtypes[i].parse(any, rr, P);
3256 }
3257
3258 if (rr->rd.len > any->rdata.size)
3259 return DNS_EILLEGAL;
3260
3261 memcpy(any->rdata.data, &P->data[rr->rd.p], rr->rd.len);
3262 any->rdata.len = rr->rd.len;
3263
3264 return 0;
3265} /* dns_any_parse() */
3266
3267
3268int dns_any_push(struct dns_packet *P, union dns_any *any, enum dns_type type) {
3269 unsigned i;
3270
3271 for (i = 0; i < lengthof(dns_rrtypes); i++) {
3272 if (dns_rrtypes[i].type == type)
3273 return dns_rrtypes[i].push(P, any);
3274 }
3275
3276 if (P->size - P->end < any->rdata.len + 2)
3277 return DNS_ENOBUFS;
3278
3279 P->data[P->end++] = 0xff & (any->rdata.len >> 8);
3280 P->data[P->end++] = 0xff & (any->rdata.len >> 0);
3281
3282 memcpy(&P->data[P->end], any->rdata.data, any->rdata.len);
3283 P->end += any->rdata.len;
3284
3285 return 0;
3286} /* dns_any_push() */
3287
3288
3289int dns_any_cmp(const union dns_any *a, enum dns_type x, const union dns_any *b, enum dns_type y) {
3290 unsigned i;
3291 int cmp;
3292
3293 if ((cmp = x - y))
3294 return cmp;
3295
3296 for (i = 0; i < lengthof(dns_rrtypes); i++) {
3297 if (dns_rrtypes[i].type == x)
3298 return dns_rrtypes[i].cmp(a, b);
3299 }
3300
3301 return -1;
3302} /* dns_any_cmp() */
3303
3304
3305size_t dns_any_print(void *dst_, size_t lim, union dns_any *any, enum dns_type type) {
3306 struct { unsigned char *b; size_t p, end; } dst, src;
3307 unsigned i, ch;
3308
3309 for (i = 0; i < lengthof(dns_rrtypes); i++) {
3310 if (dns_rrtypes[i].type == type)
3311 return dns_rrtypes[i].print(dst_, lim, any);
3312 }
3313
3314 dst.b = dst_;
3315 dst.end = lim;
3316 dst.p = 0;
3317
3318 src.b = any->rdata.data;
3319 src.end = any->rdata.len;
3320 src.p = 0;
3321
3322 dst.p += dns__printchar(dst.b, dst.end, dst.p, '"');
3323
3324 while (src.p < src.end) {
3325 ch = src.b[src.p++];
3326
3327 dst.p += dns__printchar(dst.b, dst.end, dst.p, '\\');
3328 dst.p += dns__print10(dst.b, dst.end, dst.p, ch, 3);
3329 }
3330
3331 dst.p += dns__printchar(dst.b, dst.end, dst.p, '"');
3332
3333 dns__printnul(dst.b, dst.end, dst.p);
3334
3335 return dst.p;
3336} /* dns_any_print() */
3337
3338
3339size_t dns_any_cname(void *dst, size_t lim, union dns_any *any, enum dns_type type) {
3340 unsigned i;
3341
3342 for (i = 0; i < lengthof(dns_rrtypes); i++) {
3343 if (dns_rrtypes[i].type == type)
3344 return (dns_rrtypes[i].cname)? dns_rrtypes[i].cname(dst, lim, any) : 0;
3345 }
3346
3347 return 0;
3348} /* dns_any_cname() */
3349
3350
3351/*
3352 * H O S T S R O U T I N E S
3353 *
3354 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3355
3356struct dns_hosts {
3357 struct dns_hosts_entry {
3358 char host[DNS_D_MAXNAME + 1];
3359 char arpa[73 + 1];
3360
3361 int af;
3362
3363 union {
3364 struct in_addr a4;
3365 struct in6_addr a6;
3366 } addr;
3367
3368 _Bool alias;
3369
3370 struct dns_hosts_entry *next;
3371 } *head, **tail;
3372
3373 dns_atomic_t refcount;
3374}; /* struct dns_hosts */
3375
3376
3377struct dns_hosts *dns_hosts_open(int *error) {
3378 static const struct dns_hosts hosts_initializer = { .refcount = 1 };
3379 struct dns_hosts *hosts;
3380
3381 if (!(hosts = malloc(sizeof *hosts)))
3382 goto syerr;
3383
3384 *hosts = hosts_initializer;
3385
3386 hosts->tail = &hosts->head;
3387
3388 return hosts;
3389syerr:
3390 *error = dns_syerr();
3391
3392 free(hosts);
3393
3394 return 0;
3395} /* dns_hosts_open() */
3396
3397
3398void dns_hosts_close(struct dns_hosts *hosts) {
3399 struct dns_hosts_entry *ent, *xnt;
3400
3401 if (!hosts || 1 != dns_hosts_release(hosts))
3402 return;
3403
3404 for (ent = hosts->head; ent; ent = xnt) {
3405 xnt = ent->next;
3406
3407 free(ent);
3408 }
3409
3410 free(hosts);
3411
3412 return;
3413} /* dns_hosts_close() */
3414
3415
3416unsigned dns_hosts_acquire(struct dns_hosts *hosts) {
3417 return dns_atomic_inc(&hosts->refcount);
3418} /* dns_hosts_acquire() */
3419
3420
3421unsigned dns_hosts_release(struct dns_hosts *hosts) {
3422 return dns_atomic_dec(&hosts->refcount);
3423} /* dns_hosts_release() */
3424
3425
3426struct dns_hosts *dns_hosts_mortal(struct dns_hosts *hosts) {
3427 if (hosts)
3428 dns_hosts_release(hosts);
3429
3430 return hosts;
3431} /* dns_hosts_mortal() */
3432
3433
3434struct dns_hosts *dns_hosts_local(int *error_) {
3435 struct dns_hosts *hosts;
3436 int error;
3437
3438 if (!(hosts = dns_hosts_open(&error)))
3439 goto error;
3440
3441#ifndef _WIN32
3442 if ((error = dns_hosts_loadpath(hosts, "/etc/hosts")))
3443 goto error;
3444#endif
3445 return hosts;
3446error:
3447 *error_ = error;
3448
3449 dns_hosts_close(hosts);
3450
3451 return 0;
3452} /* dns_hosts_local() */
3453
3454
3455#define dns_hosts_issep(ch) (isspace(ch))
3456#define dns_hosts_iscom(ch) ((ch) == '#' || (ch) == ';')
3457
3458int dns_hosts_loadfile(struct dns_hosts *hosts, FILE *fp) {
3459 struct dns_hosts_entry ent;
3460 char word[MAX(INET6_ADDRSTRLEN, DNS_D_MAXNAME) + 1];
3461 unsigned wp, wc, skip;
3462 int ch, error;
3463
3464 rewind(fp);
3465
3466 do {
3467 memset(&ent, '\0', sizeof ent);
3468 wc = 0;
3469 skip = 0;
3470
3471 do {
3472 memset(word, '\0', sizeof word);
3473 wp = 0;
3474
3475 while (EOF != (ch = fgetc(fp)) && ch != '\n') {
3476 skip |= !!dns_hosts_iscom(ch);
3477
3478 if (skip)
3479 continue;
3480
3481 if (dns_hosts_issep(ch))
3482 break;
3483
3484 if (wp < sizeof word - 1)
3485 word[wp] = ch;
3486 wp++;
3487 }
3488
3489 if (!wp)
3490 continue;
3491
3492 wc++;
3493
3494 switch (wc) {
3495 case 1:
3496 ent.af = (strchr(word, ':'))? AF_INET6 : AF_INET;
3497 skip = (1 != dns_inet_pton(ent.af, word, &ent.addr));
3498
3499 break;
3500 default:
3501 dns_d_anchor(ent.host, sizeof ent.host, word, wp);
3502
3503 if ((error = dns_hosts_insert(hosts, ent.af, &ent.addr, ent.host, (wc > 2))))
3504 return error;
3505
3506 break;
3507 } /* switch() */
3508 } while (ch != EOF && ch != '\n');
3509 } while (ch != EOF);
3510
3511 return 0;
3512} /* dns_hosts_loadfile() */
3513
3514
3515int dns_hosts_loadpath(struct dns_hosts *hosts, const char *path) {
3516 FILE *fp;
3517 int error;
3518
3519 if (!(fp = fopen(path, "rb")))
3520 return dns_syerr();
3521
3522 error = dns_hosts_loadfile(hosts, fp);
3523
3524 fclose(fp);
3525
3526 return error;
3527} /* dns_hosts_loadpath() */
3528
3529
3530int dns_hosts_dump(struct dns_hosts *hosts, FILE *fp) {
3531 struct dns_hosts_entry *ent, *xnt;
3532 char addr[INET6_ADDRSTRLEN + 1];
3533 unsigned i;
3534
3535 for (ent = hosts->head; ent; ent = xnt) {
3536 xnt = ent->next;
3537
3538 dns_inet_ntop(ent->af, &ent->addr, addr, sizeof addr);
3539
3540 fputs(addr, fp);
3541
3542 for (i = strlen(addr); i < INET_ADDRSTRLEN; i++)
3543 fputc(' ', fp);
3544
3545 fputc(' ', fp);
3546
3547 fputs(ent->host, fp);
3548 fputc('\n', fp);
3549 }
3550
3551 return 0;
3552} /* dns_hosts_dump() */
3553
3554
3555int dns_hosts_insert(struct dns_hosts *hosts, int af, const void *addr, const void *host, _Bool alias) {
3556 struct dns_hosts_entry *ent;
3557 int error;
3558
3559 if (!(ent = malloc(sizeof *ent)))
3560 goto syerr;
3561
3562 dns_d_anchor(ent->host, sizeof ent->host, host, strlen(host));
3563
3564 switch ((ent->af = af)) {
3565 case AF_INET6:
3566 memcpy(&ent->addr.a6, addr, sizeof ent->addr.a6);
3567
3568 dns_aaaa_arpa(ent->arpa, sizeof ent->arpa, addr);
3569
3570 break;
3571 case AF_INET:
3572 memcpy(&ent->addr.a4, addr, sizeof ent->addr.a4);
3573
3574 dns_a_arpa(ent->arpa, sizeof ent->arpa, addr);
3575
3576 break;
3577 default:
3578 error = EINVAL;
3579
3580 goto error;
3581 } /* switch() */
3582
3583 ent->alias = alias;
3584
3585 ent->next = 0;
3586 *hosts->tail = ent;
3587 hosts->tail = &ent->next;
3588
3589 return 0;
3590syerr:
3591 error = dns_syerr();
3592error:
3593 free(ent);
3594
3595 return error;
3596} /* dns_hosts_insert() */
3597
3598
3599struct dns_packet *dns_hosts_query(struct dns_hosts *hosts, struct dns_packet *Q, int *error_) {
3600 struct dns_packet *P = dns_p_new(512);
3601 struct dns_packet *A = 0;
3602 struct dns_rr rr;
3603 struct dns_hosts_entry *ent;
3604 int error, af;
3605 char qname[DNS_D_MAXNAME + 1];
3606 size_t qlen;
3607
3608 if ((error = dns_rr_parse(&rr, 12, Q)))
3609 goto error;
3610
3611 if (!(qlen = dns_d_expand(qname, sizeof qname, rr.dn.p, Q, &error)))
3612 goto error;
3613 else if (qlen >= sizeof qname)
3614 goto toolong;
3615
3616 if ((error = dns_p_push(P, DNS_S_QD, qname, qlen, rr.type, rr.class, 0, 0)))
3617 goto error;
3618
3619 switch (rr.type) {
3620 case DNS_T_PTR:
3621 for (ent = hosts->head; ent; ent = ent->next) {
3622 if (ent->alias || 0 != strcasecmp(qname, ent->arpa))
3623 continue;
3624
3625 if ((error = dns_p_push(P, DNS_S_AN, qname, qlen, rr.type, rr.class, 0, ent->host)))
3626 goto error;
3627 }
3628
3629 break;
3630 case DNS_T_AAAA:
3631 af = AF_INET6;
3632
3633 goto loop;
3634 case DNS_T_A:
3635 af = AF_INET;
3636
3637loop: for (ent = hosts->head; ent; ent = ent->next) {
3638 if (ent->af != af || 0 != strcasecmp(qname, ent->host))
3639 continue;
3640
3641 if ((error = dns_p_push(P, DNS_S_AN, qname, qlen, rr.type, rr.class, 0, &ent->addr)))
3642 goto error;
3643 }
3644
3645 break;
3646 default:
3647 break;
3648 } /* switch() */
3649
3650
3651 if (!(A = dns_p_copy(dns_p_make(P->end, &error), P)))
3652 goto error;
3653
3654 return A;
3655toolong:
3656 error = DNS_EILLEGAL;
3657error:
3658 *error_ = error;
3659
3660 free(A);
3661
3662 return 0;
3663} /* dns_hosts_query() */
3664
3665
3666/*
3667 * R E S O L V . C O N F R O U T I N E S
3668 *
3669 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3670
3671struct dns_resolv_conf *dns_resconf_open(int *error) {
3672 static const struct dns_resolv_conf resconf_initializer
3673 = { .lookup = "bf", .options = { .ndots = 1, .timeout = 5, .attempts = 2, .tcp = DNS_RESCONF_TCP_ENABLE, },
3674 .iface = { .ss_family = AF_INET }, };
3675 struct dns_resolv_conf *resconf;
3676 struct sockaddr_in *sin;
3677
3678 if (!(resconf = malloc(sizeof *resconf)))
3679 goto syerr;
3680
3681 *resconf = resconf_initializer;
3682
3683 sin = (struct sockaddr_in *)&resconf->nameserver[0];
3684 sin->sin_family = AF_INET;
3685 sin->sin_addr.s_addr = INADDR_ANY;
3686 sin->sin_port = htons(53);
3687#if defined(SA_LEN)
3688 sin->sin_len = sizeof *sin;
3689#endif
3690
3691 if (0 != gethostname(resconf->search[0], sizeof resconf->search[0]))
3692 goto syerr;
3693
3694 dns_d_anchor(resconf->search[0], sizeof resconf->search[0], resconf->search[0], strlen(resconf->search[0]));
3695 dns_d_cleave(resconf->search[0], sizeof resconf->search[0], resconf->search[0], strlen(resconf->search[0]));
3696
3697 /*
3698 * XXX: If gethostname() returned a string without any label
3699 * separator, then search[0][0] should be NUL.
3700 */
3701
3702 dns_resconf_acquire(resconf);
3703
3704 return resconf;
3705syerr:
3706 *error = dns_syerr();
3707
3708 free(resconf);
3709
3710 return 0;
3711} /* dns_resconf_open() */
3712
3713
3714void dns_resconf_close(struct dns_resolv_conf *resconf) {
3715 if (!resconf || 1 != dns_resconf_release(resconf))
3716 return /* void */;
3717
3718 free(resconf);
3719} /* dns_resconf_close() */
3720
3721
3722unsigned dns_resconf_acquire(struct dns_resolv_conf *resconf) {
3723 return dns_atomic_inc(&resconf->_.refcount);
3724} /* dns_resconf_acquire() */
3725
3726
3727unsigned dns_resconf_release(struct dns_resolv_conf *resconf) {
3728 return dns_atomic_dec(&resconf->_.refcount);
3729} /* dns_resconf_release() */
3730
3731
3732struct dns_resolv_conf *dns_resconf_mortal(struct dns_resolv_conf *resconf) {
3733 if (resconf)
3734 dns_resconf_release(resconf);
3735
3736 return resconf;
3737} /* dns_resconf_mortal() */
3738
3739
3740struct dns_resolv_conf *dns_resconf_local(int *error_) {
3741 struct dns_resolv_conf *resconf;
3742 int error;
3743
3744 if (!(resconf = dns_resconf_open(&error)))
3745 goto error;
3746
3747#ifndef _WIN32
3748 if ((error = dns_resconf_loadpath(resconf, "/etc/resolv.conf")))
3749 goto error;
3750
3751 if ((error = dns_nssconf_loadpath(resconf, "/etc/nsswitch.conf"))) {
3752 if (error != ENOENT)
3753 goto error;
3754 }
3755#endif
3756
3757 return resconf;
3758error:
3759 *error_ = error;
3760
3761 dns_resconf_close(resconf);
3762
3763 return 0;
3764} /* dns_resconf_local() */
3765
3766
3767struct dns_resolv_conf *dns_resconf_root(int *error) {
3768 struct dns_resolv_conf *resconf;
3769
3770 if ((resconf = dns_resconf_local(error)))
3771 resconf->options.recurse = 1;
3772
3773 return resconf;
3774} /* dns_resconf_root() */
3775
3776
3777enum dns_resconf_keyword {
3778 DNS_RESCONF_NAMESERVER,
3779 DNS_RESCONF_DOMAIN,
3780 DNS_RESCONF_SEARCH,
3781 DNS_RESCONF_LOOKUP,
3782 DNS_RESCONF_FILE,
3783 DNS_RESCONF_BIND,
3784 DNS_RESCONF_CACHE,
3785 DNS_RESCONF_OPTIONS,
3786 DNS_RESCONF_EDNS0,
3787 DNS_RESCONF_NDOTS,
3788 DNS_RESCONF_TIMEOUT,
3789 DNS_RESCONF_ATTEMPTS,
3790 DNS_RESCONF_ROTATE,
3791 DNS_RESCONF_RECURSE,
3792 DNS_RESCONF_SMART,
3793 DNS_RESCONF_TCP,
3794 DNS_RESCONF_TCPx,
3795 DNS_RESCONF_INTERFACE,
3796 DNS_RESCONF_ZERO,
3797 DNS_RESCONF_ONE,
3798 DNS_RESCONF_ENABLE,
3799 DNS_RESCONF_ONLY,
3800 DNS_RESCONF_DISABLE,
3801}; /* enum dns_resconf_keyword */
3802
3803static enum dns_resconf_keyword dns_resconf_keyword(const char *word) {
3804 static const char *words[] = {
3805 [DNS_RESCONF_NAMESERVER] = "nameserver",
3806 [DNS_RESCONF_DOMAIN] = "domain",
3807 [DNS_RESCONF_SEARCH] = "search",
3808 [DNS_RESCONF_LOOKUP] = "lookup",
3809 [DNS_RESCONF_FILE] = "file",
3810 [DNS_RESCONF_BIND] = "bind",
3811 [DNS_RESCONF_CACHE] = "cache",
3812 [DNS_RESCONF_OPTIONS] = "options",
3813 [DNS_RESCONF_EDNS0] = "edns0",
3814 [DNS_RESCONF_ROTATE] = "rotate",
3815 [DNS_RESCONF_RECURSE] = "recurse",
3816 [DNS_RESCONF_SMART] = "smart",
3817 [DNS_RESCONF_TCP] = "tcp",
3818 [DNS_RESCONF_INTERFACE] = "interface",
3819 [DNS_RESCONF_ZERO] = "0",
3820 [DNS_RESCONF_ONE] = "1",
3821 [DNS_RESCONF_ENABLE] = "enable",
3822 [DNS_RESCONF_ONLY] = "only",
3823 [DNS_RESCONF_DISABLE] = "disable",
3824 };
3825 unsigned i;
3826
3827 for (i = 0; i < lengthof(words); i++) {
3828 if (words[i] && 0 == strcasecmp(words[i], word))
3829 return i;
3830 }
3831
3832 if (0 == strncasecmp(word, "ndots:", sizeof "ndots:" - 1))
3833 return DNS_RESCONF_NDOTS;
3834
3835 if (0 == strncasecmp(word, "timeout:", sizeof "timeout:" - 1))
3836 return DNS_RESCONF_TIMEOUT;
3837
3838 if (0 == strncasecmp(word, "attempts:", sizeof "attempts:" - 1))
3839 return DNS_RESCONF_ATTEMPTS;
3840
3841 if (0 == strncasecmp(word, "tcp:", sizeof "tcp:" - 1))
3842 return DNS_RESCONF_TCPx;
3843
3844 return -1;
3845} /* dns_resconf_keyword() */
3846
3847
3848/** OpenBSD-style "[1.2.3.4]:53" nameserver syntax */
3849static int dns_resconf_pton(struct sockaddr_storage *ss, const char *src) {
3850 struct { char buf[128], *p; } addr = { "", addr.buf };
3851 unsigned short port = 0;
3852 int ch, af = AF_INET, error;
3853
3854 while ((ch = *src++)) {
3855 switch (ch) {
3856 case ' ':
3857 /* FALL THROUGH */
3858 case '\t':
3859 break;
3860 case '[':
3861 break;
3862 case ']':
3863 while ((ch = *src++)) {
3864 if (isdigit((unsigned char)ch)) {
3865 port *= 10;
3866 port += ch - '0';
3867 }
3868 }
3869
3870 goto inet;
3871 case ':':
3872 af = AF_INET6;
3873
3874 /* FALL THROUGH */
3875 default:
3876 if (addr.p < endof(addr.buf) - 1)
3877 *addr.p++ = ch;
3878
3879 break;
3880 } /* switch() */
3881 } /* while() */
3882inet:
3883
3884 if ((error = dns_pton(af, addr.buf, dns_sa_addr(af, ss))))
3885 return error;
3886
3887 port = (!port)? 53 : port;
3888 *dns_sa_port(af, ss) = htons(port);
3889 dns_sa_family(ss) = af;
3890
3891 return 0;
3892} /* dns_resconf_pton() */
3893
3894#define dns_resconf_issep(ch) (isspace(ch) || (ch) == ',')
3895#define dns_resconf_iscom(ch) ((ch) == '#' || (ch) == ';')
3896
3897int dns_resconf_loadfile(struct dns_resolv_conf *resconf, FILE *fp) {
3898 unsigned sa_count = 0;
3899 char words[6][DNS_D_MAXNAME + 1];
3900 unsigned wp, wc, i, j, n;
3901 int ch, error;
3902
3903 rewind(fp);
3904
3905 do {
3906 memset(words, '\0', sizeof words);
3907 wp = 0;
3908 wc = 0;
3909
3910 while (EOF != (ch = getc(fp)) && ch != '\n') {
3911 if (dns_resconf_issep(ch)) {