1/* DNS test framework and libresolv redirection.
2 Copyright (C) 2016-2020 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
18
19#include <support/resolv_test.h>
20
21#include <arpa/inet.h>
22#include <errno.h>
23#include <fcntl.h>
24#include <nss.h>
25#include <resolv.h>
26#include <search.h>
27#include <stdlib.h>
28#include <string.h>
29#include <support/check.h>
30#include <support/namespace.h>
31#include <support/support.h>
32#include <support/test-driver.h>
33#include <support/xsocket.h>
34#include <support/xthread.h>
35#include <support/xunistd.h>
36#include <sys/uio.h>
37#include <unistd.h>
38
39/* Response builder. */
40
41enum
42 {
43 max_response_length = 65536
44 };
45
46/* Used for locating domain names containing for the purpose of
47 forming compression references. */
48struct compressed_name
49{
50 uint16_t offset;
51 unsigned char length;
52 unsigned char name[]; /* Without terminating NUL. */
53};
54
55static struct compressed_name *
56allocate_compressed_name (const unsigned char *encoded, unsigned int offset)
57{
58 /* Compute the length of the domain name. */
59 size_t length;
60 {
61 const unsigned char *p;
62 for (p = encoded; *p != '\0';)
63 {
64 /* No compression references are allowed. */
65 TEST_VERIFY (*p <= 63);
66 /* Skip over the label. */
67 p += 1 + *p;
68 }
69 length = p - encoded;
70 ++length; /* For the terminating NUL byte. */
71 }
72 TEST_VERIFY_EXIT (length <= 255);
73
74 struct compressed_name *result
75 = xmalloc (offsetof (struct compressed_name, name) + length);
76 result->offset = offset;
77 result->length = length;
78 memcpy (result->name, encoded, length);
79 return result;
80}
81
82/* Convert CH to lower case. Only change letters in the ASCII
83 range. */
84static inline unsigned char
85ascii_tolower (unsigned char ch)
86{
87 if ('A' <= ch && ch <= 'Z')
88 return ch - 'A' + 'a';
89 else
90 return ch;
91}
92
93/* Compare both names, for use with tsearch. The order is arbitrary,
94 but the comparison is case-insenstive. */
95static int
96compare_compressed_name (const void *left, const void *right)
97{
98 const struct compressed_name *crleft = left;
99 const struct compressed_name *crright = right;
100
101 if (crleft->length != crright->length)
102 /* The operands are converted to int before the subtraction. */
103 return crleft->length - crright->length;
104
105 const unsigned char *nameleft = crleft->name;
106 const unsigned char *nameright = crright->name;
107
108 while (true)
109 {
110 int lenleft = *nameleft++;
111 int lenright = *nameright++;
112
113 /* Labels must not e compression references. */
114 TEST_VERIFY (lenleft <= 63);
115 TEST_VERIFY (lenright <= 63);
116
117 if (lenleft != lenright)
118 return left - right;
119 if (lenleft == 0)
120 /* End of name reached without spotting a difference. */
121 return 0;
122 /* Compare the label in a case-insenstive manner. */
123 const unsigned char *endnameleft = nameleft + lenleft;
124 while (nameleft < endnameleft)
125 {
126 int l = *nameleft++;
127 int r = *nameright++;
128 if (l != r)
129 {
130 l = ascii_tolower (l);
131 r = ascii_tolower (r);
132 if (l != r)
133 return l - r;
134 }
135 }
136 }
137}
138
139struct resolv_response_builder
140{
141 const unsigned char *query_buffer;
142 size_t query_length;
143
144 size_t offset; /* Bytes written so far in buffer. */
145 ns_sect section; /* Current section in the DNS packet. */
146 unsigned int truncate_bytes; /* Bytes to remove at end of response. */
147 bool drop; /* Discard generated response. */
148 bool close; /* Close TCP client connection. */
149
150 /* Offset of the two-byte RDATA length field in the currently
151 written RDATA sub-structure. 0 if no RDATA is being written. */
152 size_t current_rdata_offset;
153
154 /* tsearch tree for locating targets for label compression. */
155 void *compression_offsets;
156
157 /* Must be last. Not zeroed for performance reasons. */
158 unsigned char buffer[max_response_length];
159};
160
161/* Response builder. */
162
163void
164resolv_response_init (struct resolv_response_builder *b,
165 struct resolv_response_flags flags)
166{
167 if (b->offset > 0)
168 FAIL_EXIT1 ("response_init: called at offset %zu", b->offset);
169 if (b->query_length < 12)
170 FAIL_EXIT1 ("response_init called for a query of size %zu",
171 b->query_length);
172 if (flags.rcode > 15)
173 FAIL_EXIT1 ("response_init: invalid RCODE %u", flags.rcode);
174
175 /* Copy the transaction ID. */
176 b->buffer[0] = b->query_buffer[0];
177 b->buffer[1] = b->query_buffer[1];
178
179 /* Initialize the flags. */
180 b->buffer[2] = 0x80; /* Mark as response. */
181 b->buffer[2] |= b->query_buffer[2] & 0x01; /* Copy the RD bit. */
182 if (flags.tc)
183 b->buffer[2] |= 0x02;
184 b->buffer[3] = 0x80 | flags.rcode; /* Always set RA. */
185 if (flags.ad)
186 b->buffer[3] |= 0x20;
187
188 /* Fill in the initial section count values. */
189 b->buffer[4] = flags.qdcount >> 8;
190 b->buffer[5] = flags.qdcount;
191 b->buffer[6] = flags.ancount >> 8;
192 b->buffer[7] = flags.ancount;
193 b->buffer[8] = flags.nscount >> 8;
194 b->buffer[9] = flags.nscount;
195 b->buffer[10] = flags.adcount >> 8;
196 b->buffer[11] = flags.adcount;
197
198 b->offset = 12;
199}
200
201void
202resolv_response_section (struct resolv_response_builder *b, ns_sect section)
203{
204 if (b->offset == 0)
205 FAIL_EXIT1 ("resolv_response_section: response_init not called before");
206 if (section < b->section)
207 FAIL_EXIT1 ("resolv_response_section: cannot go back to previous section");
208 b->section = section;
209}
210
211/* Add a single byte to B. */
212static inline void
213response_add_byte (struct resolv_response_builder *b, unsigned char ch)
214{
215 if (b->offset == max_response_length)
216 FAIL_EXIT1 ("DNS response exceeds 64 KiB limit");
217 b->buffer[b->offset] = ch;
218 ++b->offset;
219}
220
221/* Add a 16-bit word VAL to B, in big-endian format. */
222static void
223response_add_16 (struct resolv_response_builder *b, uint16_t val)
224{
225 response_add_byte (b, val >> 8);
226 response_add_byte (b, val);
227}
228
229/* Increment the pers-section record counter in the packet header. */
230static void
231response_count_increment (struct resolv_response_builder *b)
232{
233 unsigned int offset = b->section;
234 offset = 4 + 2 * offset;
235 ++b->buffer[offset + 1];
236 if (b->buffer[offset + 1] == 0)
237 {
238 /* Carry. */
239 ++b->buffer[offset];
240 if (b->buffer[offset] == 0)
241 /* Overflow. */
242 FAIL_EXIT1 ("too many records in section");
243 }
244}
245
246void
247resolv_response_add_question (struct resolv_response_builder *b,
248 const char *name, uint16_t class, uint16_t type)
249{
250 if (b->offset == 0)
251 FAIL_EXIT1 ("resolv_response_add_question: "
252 "resolv_response_init not called");
253 if (b->section != ns_s_qd)
254 FAIL_EXIT1 ("resolv_response_add_question: "
255 "must be called in the question section");
256
257 resolv_response_add_name (b, name);
258 response_add_16 (b, type);
259 response_add_16 (b, class);
260
261 response_count_increment (b);
262}
263
264void
265resolv_response_add_name (struct resolv_response_builder *b,
266 const char *const origname)
267{
268 unsigned char encoded_name[NS_MAXDNAME];
269 if (ns_name_pton (origname, encoded_name, sizeof (encoded_name)) < 0)
270 FAIL_EXIT1 ("ns_name_pton (\"%s\"): %m", origname);
271
272 /* Copy the encoded name into the output buffer, apply compression
273 where possible. */
274 for (const unsigned char *name = encoded_name; ;)
275 {
276 if (*name == '\0')
277 {
278 /* We have reached the end of the name. Add the terminating
279 NUL byte. */
280 response_add_byte (b, '\0');
281 break;
282 }
283
284 /* Set to the compression target if compression is possible. */
285 struct compressed_name *crname_target;
286
287 /* Compression references can only reach the beginning of the
288 packet. */
289 enum { compression_limit = 1 << 12 };
290
291 {
292 /* The trailing part of the name to be looked up in the tree
293 with the compression targets. */
294 struct compressed_name *crname
295 = allocate_compressed_name (name, b->offset);
296
297 if (b->offset < compression_limit)
298 {
299 /* Add the name to the tree, for future compression
300 references. */
301 void **ptr = tsearch (crname, &b->compression_offsets,
302 compare_compressed_name);
303 if (ptr == NULL)
304 FAIL_EXIT1 ("tsearch out of memory");
305 crname_target = *ptr;
306
307 if (crname_target != crname)
308 /* The new name was not actually added to the tree.
309 Deallocate it. */
310 free (crname);
311 else
312 /* Signal that the tree did not yet contain the name,
313 but keep the allocation because it is now part of the
314 tree. */
315 crname_target = NULL;
316 }
317 else
318 {
319 /* This name cannot be reached by a compression reference.
320 No need to add it to the tree for future reference. */
321 void **ptr = tfind (crname, &b->compression_offsets,
322 compare_compressed_name);
323 if (ptr != NULL)
324 crname_target = *ptr;
325 else
326 crname_target = NULL;
327 TEST_VERIFY (crname_target != crname);
328 /* Not added to the tree. */
329 free (crname);
330 }
331 }
332
333 if (crname_target != NULL)
334 {
335 /* The name is known. Reference the previous location. */
336 unsigned int old_offset = crname_target->offset;
337 TEST_VERIFY_EXIT (old_offset < compression_limit);
338 response_add_byte (b, 0xC0 | (old_offset >> 8));
339 response_add_byte (b, old_offset);
340 break;
341 }
342 else
343 {
344 /* The name is new. Add this label. */
345 unsigned int len = 1 + *name;
346 resolv_response_add_data (b, name, len);
347 name += len;
348 }
349 }
350}
351
352void
353resolv_response_open_record (struct resolv_response_builder *b,
354 const char *name,
355 uint16_t class, uint16_t type, uint32_t ttl)
356{
357 if (b->section == ns_s_qd)
358 FAIL_EXIT1 ("resolv_response_open_record called in question section");
359 if (b->current_rdata_offset != 0)
360 FAIL_EXIT1 ("resolv_response_open_record called with open record");
361
362 resolv_response_add_name (b, name);
363 response_add_16 (b, type);
364 response_add_16 (b, class);
365 response_add_16 (b, ttl >> 16);
366 response_add_16 (b, ttl);
367
368 b->current_rdata_offset = b->offset;
369 /* Add room for the RDATA length. */
370 response_add_16 (b, 0);
371}
372
373
374void
375resolv_response_close_record (struct resolv_response_builder *b)
376{
377 size_t rdata_offset = b->current_rdata_offset;
378 if (rdata_offset == 0)
379 FAIL_EXIT1 ("response_close_record called without open record");
380 size_t rdata_length = b->offset - rdata_offset - 2;
381 if (rdata_length > 65535)
382 FAIL_EXIT1 ("RDATA length %zu exceeds limit", rdata_length);
383 b->buffer[rdata_offset] = rdata_length >> 8;
384 b->buffer[rdata_offset + 1] = rdata_length;
385 response_count_increment (b);
386 b->current_rdata_offset = 0;
387}
388
389void
390resolv_response_add_data (struct resolv_response_builder *b,
391 const void *data, size_t length)
392{
393 size_t remaining = max_response_length - b->offset;
394 if (remaining < length)
395 FAIL_EXIT1 ("resolv_response_add_data: not enough room for %zu bytes",
396 length);
397 memcpy (b->buffer + b->offset, data, length);
398 b->offset += length;
399}
400
401void
402resolv_response_drop (struct resolv_response_builder *b)
403{
404 b->drop = true;
405}
406
407void
408resolv_response_close (struct resolv_response_builder *b)
409{
410 b->close = true;
411}
412
413void
414resolv_response_truncate_data (struct resolv_response_builder *b, size_t count)
415{
416 if (count > 65535)
417 FAIL_EXIT1 ("resolv_response_truncate_data: argument too large: %zu",
418 count);
419 b->truncate_bytes = count;
420}
421
422
423size_t
424resolv_response_length (const struct resolv_response_builder *b)
425{
426 return b->offset;
427}
428
429unsigned char *
430resolv_response_buffer (const struct resolv_response_builder *b)
431{
432 unsigned char *result = xmalloc (b->offset);
433 memcpy (result, b->buffer, b->offset);
434 return result;
435}
436
437static struct resolv_response_builder *
438response_builder_allocate
439 (const unsigned char *query_buffer, size_t query_length)
440{
441 struct resolv_response_builder *b = xmalloc (sizeof (*b));
442 memset (b, 0, offsetof (struct resolv_response_builder, buffer));
443 b->query_buffer = query_buffer;
444 b->query_length = query_length;
445 return b;
446}
447
448static void
449response_builder_free (struct resolv_response_builder *b)
450{
451 tdestroy (b->compression_offsets, free);
452 free (b);
453}
454
455/* DNS query processing. */
456
457/* Data extracted from the question section of a DNS packet. */
458struct query_info
459{
460 char qname[MAXDNAME];
461 uint16_t qclass;
462 uint16_t qtype;
463 struct resolv_edns_info edns;
464};
465
466/* Update *INFO from the specified DNS packet. */
467static void
468parse_query (struct query_info *info,
469 const unsigned char *buffer, size_t length)
470{
471 HEADER hd;
472 _Static_assert (sizeof (hd) == 12, "DNS header size");
473 if (length < sizeof (hd))
474 FAIL_EXIT1 ("malformed DNS query: too short: %zu bytes", length);
475 memcpy (&hd, buffer, sizeof (hd));
476
477 if (ntohs (hd.qdcount) != 1)
478 FAIL_EXIT1 ("malformed DNS query: wrong question count: %d",
479 (int) ntohs (hd.qdcount));
480 if (ntohs (hd.ancount) != 0)
481 FAIL_EXIT1 ("malformed DNS query: wrong answer count: %d",
482 (int) ntohs (hd.ancount));
483 if (ntohs (hd.nscount) != 0)
484 FAIL_EXIT1 ("malformed DNS query: wrong authority count: %d",
485 (int) ntohs (hd.nscount));
486 if (ntohs (hd.arcount) > 1)
487 FAIL_EXIT1 ("malformed DNS query: wrong additional count: %d",
488 (int) ntohs (hd.arcount));
489
490 int ret = dn_expand (buffer, buffer + length, buffer + sizeof (hd),
491 info->qname, sizeof (info->qname));
492 if (ret < 0)
493 FAIL_EXIT1 ("malformed DNS query: cannot uncompress QNAME");
494
495 /* Obtain QTYPE and QCLASS. */
496 size_t remaining = length - (12 + ret);
497 struct
498 {
499 uint16_t qtype;
500 uint16_t qclass;
501 } qtype_qclass;
502 if (remaining < sizeof (qtype_qclass))
503 FAIL_EXIT1 ("malformed DNS query: "
504 "query lacks QCLASS/QTYPE, QNAME: %s", info->qname);
505 memcpy (&qtype_qclass, buffer + 12 + ret, sizeof (qtype_qclass));
506 info->qclass = ntohs (qtype_qclass.qclass);
507 info->qtype = ntohs (qtype_qclass.qtype);
508
509 memset (&info->edns, 0, sizeof (info->edns));
510 if (ntohs (hd.arcount) > 0)
511 {
512 /* Parse EDNS record. */
513 struct __attribute__ ((packed, aligned (1)))
514 {
515 uint8_t root;
516 uint16_t rtype;
517 uint16_t payload;
518 uint8_t edns_extended_rcode;
519 uint8_t edns_version;
520 uint16_t flags;
521 uint16_t rdatalen;
522 } rr;
523 _Static_assert (sizeof (rr) == 11, "EDNS record size");
524
525 if (remaining < 4 + sizeof (rr))
526 FAIL_EXIT1 ("mailformed DNS query: no room for EDNS record");
527 memcpy (&rr, buffer + 12 + ret + 4, sizeof (rr));
528 if (rr.root != 0)
529 FAIL_EXIT1 ("malformed DNS query: invalid OPT RNAME: %d\n", rr.root);
530 if (rr.rtype != htons (41))
531 FAIL_EXIT1 ("malformed DNS query: invalid OPT type: %d\n",
532 ntohs (rr.rtype));
533 info->edns.active = true;
534 info->edns.extended_rcode = rr.edns_extended_rcode;
535 info->edns.version = rr.edns_version;
536 info->edns.flags = ntohs (rr.flags);
537 info->edns.payload_size = ntohs (rr.payload);
538 }
539}
540
541
542/* Main testing framework. */
543
544/* Per-server information. One struct is allocated for each test
545 server. */
546struct resolv_test_server
547{
548 /* Local address of the server. UDP and TCP use the same port. */
549 struct sockaddr_in address;
550
551 /* File descriptor of the UDP server, or -1 if this server is
552 disabled. */
553 int socket_udp;
554
555 /* File descriptor of the TCP server, or -1 if this server is
556 disabled. */
557 int socket_tcp;
558
559 /* Counter of the number of responses processed so far. */
560 size_t response_number;
561
562 /* Thread handles for the server threads (if not disabled in the
563 configuration). */
564 pthread_t thread_udp;
565 pthread_t thread_tcp;
566};
567
568/* Main struct for keeping track of libresolv redirection and
569 testing. */
570struct resolv_test
571{
572 /* After initialization, any access to the struct must be performed
573 while this lock is acquired. */
574 pthread_mutex_t lock;
575
576 /* Data for each test server. */
577 struct resolv_test_server servers[resolv_max_test_servers];
578
579 /* Used if config.single_thread_udp is true. */
580 pthread_t thread_udp_single;
581
582 struct resolv_redirect_config config;
583 bool termination_requested;
584};
585
586/* Function implementing a server thread. */
587typedef void (*thread_callback) (struct resolv_test *, int server_index);
588
589/* Storage for thread-specific data, for passing to the
590 thread_callback function. */
591struct thread_closure
592{
593 struct resolv_test *obj; /* Current test object. */
594 thread_callback callback; /* Function to call. */
595 int server_index; /* Index of the implemented server. */
596};
597
598/* Wrap response_callback as a function which can be passed to
599 pthread_create. */
600static void *
601thread_callback_wrapper (void *arg)
602{
603 struct thread_closure *closure = arg;
604 closure->callback (closure->obj, closure->server_index);
605 free (closure);
606 return NULL;
607}
608
609/* Start a server thread for the specified SERVER_INDEX, implemented
610 by CALLBACK. */
611static pthread_t
612start_server_thread (struct resolv_test *obj, int server_index,
613 thread_callback callback)
614{
615 struct thread_closure *closure = xmalloc (sizeof (*closure));
616 *closure = (struct thread_closure)
617 {
618 .obj = obj,
619 .callback = callback,
620 .server_index = server_index,
621 };
622 return xpthread_create (NULL, thread_callback_wrapper, closure);
623}
624
625/* Process one UDP query. Return false if a termination requested has
626 been detected. */
627static bool
628server_thread_udp_process_one (struct resolv_test *obj, int server_index)
629{
630 unsigned char query[512];
631 struct sockaddr_storage peer;
632 socklen_t peerlen = sizeof (peer);
633 size_t length = xrecvfrom (obj->servers[server_index].socket_udp,
634 query, sizeof (query), 0,
635 (struct sockaddr *) &peer, &peerlen);
636 /* Check for termination. */
637 {
638 bool termination_requested;
639 xpthread_mutex_lock (&obj->lock);
640 termination_requested = obj->termination_requested;
641 xpthread_mutex_unlock (&obj->lock);
642 if (termination_requested)
643 return false;
644 }
645
646
647 struct query_info qinfo;
648 parse_query (&qinfo, query, length);
649 if (test_verbose > 0)
650 {
651 if (test_verbose > 1)
652 printf ("info: UDP server %d: incoming query:"
653 " %zd bytes, %s/%u/%u, tnxid=0x%02x%02x\n",
654 server_index, length, qinfo.qname, qinfo.qclass, qinfo.qtype,
655 query[0], query[1]);
656 else
657 printf ("info: UDP server %d: incoming query:"
658 " %zd bytes, %s/%u/%u\n",
659 server_index, length, qinfo.qname, qinfo.qclass, qinfo.qtype);
660 }
661
662 struct resolv_response_context ctx =
663 {
664 .query_buffer = query,
665 .query_length = length,
666 .server_index = server_index,
667 .tcp = false,
668 .edns = qinfo.edns,
669 };
670 struct resolv_response_builder *b = response_builder_allocate (query, length);
671 obj->config.response_callback
672 (&ctx, b, qinfo.qname, qinfo.qclass, qinfo.qtype);
673
674 if (b->drop)
675 {
676 if (test_verbose)
677 printf ("info: UDP server %d: dropping response to %s/%u/%u\n",
678 server_index, qinfo.qname, qinfo.qclass, qinfo.qtype);
679 }
680 else
681 {
682 if (test_verbose)
683 {
684 if (b->offset >= 12)
685 printf ("info: UDP server %d: sending response:"
686 " %zu bytes, RCODE %d (for %s/%u/%u)\n",
687 server_index, b->offset, b->buffer[3] & 0x0f,
688 qinfo.qname, qinfo.qclass, qinfo.qtype);
689 else
690 printf ("info: UDP server %d: sending response: %zu bytes"
691 " (for %s/%u/%u)\n",
692 server_index, b->offset,
693 qinfo.qname, qinfo.qclass, qinfo.qtype);
694 if (b->truncate_bytes > 0)
695 printf ("info: truncated by %u bytes\n", b->truncate_bytes);
696 }
697 size_t to_send = b->offset;
698 if (to_send < b->truncate_bytes)
699 to_send = 0;
700 else
701 to_send -= b->truncate_bytes;
702
703 /* Ignore most errors here because the other end may have closed
704 the socket. */
705 if (sendto (obj->servers[server_index].socket_udp,
706 b->buffer, to_send, 0,
707 (struct sockaddr *) &peer, peerlen) < 0)
708 TEST_VERIFY_EXIT (errno != EBADF);
709 }
710 response_builder_free (b);
711 return true;
712}
713
714/* UDP thread_callback function. Variant for one thread per
715 server. */
716static void
717server_thread_udp (struct resolv_test *obj, int server_index)
718{
719 while (server_thread_udp_process_one (obj, server_index))
720 ;
721}
722
723/* Single-threaded UDP processing function, for the single_thread_udp
724 case. */
725static void *
726server_thread_udp_single (void *closure)
727{
728 struct resolv_test *obj = closure;
729
730 struct pollfd fds[resolv_max_test_servers];
731 for (int server_index = 0; server_index < resolv_max_test_servers;
732 ++server_index)
733 if (obj->config.servers[server_index].disable_udp)
734 fds[server_index] = (struct pollfd) {.fd = -1};
735 else
736 {
737 fds[server_index] = (struct pollfd)
738 {
739 .fd = obj->servers[server_index].socket_udp,
740 .events = POLLIN
741 };
742
743 /* Make the socket non-blocking. */
744 int flags = fcntl (obj->servers[server_index].socket_udp, F_GETFL, 0);
745 if (flags < 0)
746 FAIL_EXIT1 ("fcntl (F_GETFL): %m");
747 flags |= O_NONBLOCK;
748 if (fcntl (obj->servers[server_index].socket_udp, F_SETFL, flags) < 0)
749 FAIL_EXIT1 ("fcntl (F_SETFL): %m");
750 }
751
752 while (true)
753 {
754 xpoll (fds, resolv_max_test_servers, -1);
755 for (int server_index = 0; server_index < resolv_max_test_servers;
756 ++server_index)
757 if (fds[server_index].revents != 0)
758 {
759 if (!server_thread_udp_process_one (obj, server_index))
760 goto out;
761 fds[server_index].revents = 0;
762 }
763 }
764
765 out:
766 return NULL;
767}
768
769/* Start the single UDP handler thread (for the single_thread_udp
770 case). */
771static void
772start_server_thread_udp_single (struct resolv_test *obj)
773{
774 obj->thread_udp_single
775 = xpthread_create (NULL, server_thread_udp_single, obj);
776}
777
778/* Data describing a TCP client connect. */
779struct tcp_thread_closure
780{
781 struct resolv_test *obj;
782 int server_index;
783 int client_socket;
784};
785
786/* Read a complete DNS query packet. If EOF_OK, an immediate
787 end-of-file condition is acceptable. */
788static bool
789read_fully (int fd, void *buf, size_t len, bool eof_ok)
790{
791 const void *const end = buf + len;
792 while (buf < end)
793 {
794 ssize_t ret = read (fd, buf, end - buf);
795 if (ret == 0)
796 {
797 if (!eof_ok)
798 {
799 support_record_failure ();
800 printf ("error: unexpected EOF on TCP connection\n");
801 }
802 return false;
803 }
804 else if (ret < 0)
805 {
806 if (!eof_ok || errno != ECONNRESET)
807 {
808 support_record_failure ();
809 printf ("error: TCP read: %m\n");
810 }
811 return false;
812 }
813 buf += ret;
814 eof_ok = false;
815 }
816 return true;
817}
818
819/* Write an array of iovecs. Terminate the process on failure. */
820static void
821writev_fully (int fd, struct iovec *buffers, size_t count)
822{
823 while (count > 0)
824 {
825 /* Skip zero-length write requests. */
826 if (buffers->iov_len == 0)
827 {
828 ++buffers;
829 --count;
830 continue;
831 }
832 /* Try to rewrite the remaing buffers. */
833 ssize_t ret = writev (fd, buffers, count);
834 if (ret < 0)
835 FAIL_EXIT1 ("writev: %m");
836 if (ret == 0)
837 FAIL_EXIT1 ("writev: invalid return value zero");
838 /* Find the buffers that were successfully written. */
839 while (ret > 0)
840 {
841 if (count == 0)
842 FAIL_EXIT1 ("internal writev consistency failure");
843 /* Current buffer was partially written. */
844 if (buffers->iov_len > (size_t) ret)
845 {
846 buffers->iov_base += ret;
847 buffers->iov_len -= ret;
848 ret = 0;
849 }
850 else
851 {
852 ret -= buffers->iov_len;
853 buffers->iov_len = 0;
854 ++buffers;
855 --count;
856 }
857 }
858 }
859}
860
861/* Thread callback for handling a single established TCP connection to
862 a client. */
863static void *
864server_thread_tcp_client (void *arg)
865{
866 struct tcp_thread_closure *closure = arg;
867
868 while (true)
869 {
870 /* Read packet length. */
871 uint16_t query_length;
872 if (!read_fully (closure->client_socket,
873 &query_length, sizeof (query_length), true))
874 break;
875 query_length = ntohs (query_length);
876
877 /* Read the packet. */
878 unsigned char *query_buffer = xmalloc (query_length);
879 read_fully (closure->client_socket, query_buffer, query_length, false);
880
881 struct query_info qinfo;
882 parse_query (&qinfo, query_buffer, query_length);
883 if (test_verbose > 0)
884 {
885 if (test_verbose > 1)
886 printf ("info: UDP server %d: incoming query:"
887 " %d bytes, %s/%u/%u, tnxid=0x%02x%02x\n",
888 closure->server_index, query_length,
889 qinfo.qname, qinfo.qclass, qinfo.qtype,
890 query_buffer[0], query_buffer[1]);
891 else
892 printf ("info: TCP server %d: incoming query:"
893 " %u bytes, %s/%u/%u\n",
894 closure->server_index, query_length,
895 qinfo.qname, qinfo.qclass, qinfo.qtype);
896 }
897
898 struct resolv_response_context ctx =
899 {
900 .query_buffer = query_buffer,
901 .query_length = query_length,
902 .server_index = closure->server_index,
903 .tcp = true,
904 .edns = qinfo.edns,
905 };
906 struct resolv_response_builder *b = response_builder_allocate
907 (query_buffer, query_length);
908 closure->obj->config.response_callback
909 (&ctx, b, qinfo.qname, qinfo.qclass, qinfo.qtype);
910
911 if (b->drop)
912 {
913 if (test_verbose)
914 printf ("info: TCP server %d: dropping response to %s/%u/%u\n",
915 closure->server_index,
916 qinfo.qname, qinfo.qclass, qinfo.qtype);
917 }
918 else
919 {
920 if (test_verbose)
921 printf ("info: TCP server %d: sending response: %zu bytes"
922 " (for %s/%u/%u)\n",
923 closure->server_index, b->offset,
924 qinfo.qname, qinfo.qclass, qinfo.qtype);
925 uint16_t length = htons (b->offset);
926 size_t to_send = b->offset;
927 if (to_send < b->truncate_bytes)
928 to_send = 0;
929 else
930 to_send -= b->truncate_bytes;
931 struct iovec buffers[2] =
932 {
933 {&length, sizeof (length)},
934 {b->buffer, to_send}
935 };
936 writev_fully (closure->client_socket, buffers, 2);
937 }
938 bool close_flag = b->close;
939 response_builder_free (b);
940 free (query_buffer);
941 if (close_flag)
942 break;
943 }
944
945 xclose (closure->client_socket);
946 free (closure);
947 return NULL;
948}
949
950/* thread_callback for the TCP case. Accept connections and create a
951 new thread for each client. */
952static void
953server_thread_tcp (struct resolv_test *obj, int server_index)
954{
955 while (true)
956 {
957 /* Get the client conenction. */
958 int client_socket = xaccept
959 (obj->servers[server_index].socket_tcp, NULL, NULL);
960
961 /* Check for termination. */
962 xpthread_mutex_lock (&obj->lock);
963 if (obj->termination_requested)
964 {
965 xpthread_mutex_unlock (&obj->lock);
966 xclose (client_socket);
967 break;
968 }
969 xpthread_mutex_unlock (&obj->lock);
970
971 /* Spawn a new thread for handling this connection. */
972 struct tcp_thread_closure *closure = xmalloc (sizeof (*closure));
973 *closure = (struct tcp_thread_closure)
974 {
975 .obj = obj,
976 .server_index = server_index,
977 .client_socket = client_socket,
978 };
979
980 pthread_t thr
981 = xpthread_create (NULL, server_thread_tcp_client, closure);
982 /* TODO: We should keep track of this thread so that we can
983 block in resolv_test_end until it has exited. */
984 xpthread_detach (thr);
985 }
986}
987
988/* Create UDP and TCP server sockets. */
989static void
990make_server_sockets (struct resolv_test_server *server)
991{
992 while (true)
993 {
994 server->socket_udp = xsocket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
995 server->socket_tcp = xsocket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
996
997 /* Pick the address for the UDP socket. */
998 server->address = (struct sockaddr_in)
999 {
1000 .sin_family = AF_INET,
1001 .sin_addr = {.s_addr = htonl (INADDR_LOOPBACK)}
1002 };
1003 xbind (server->socket_udp,
1004 (struct sockaddr *)&server->address, sizeof (server->address));
1005
1006 /* Retrieve the address. */
1007 socklen_t addrlen = sizeof (server->address);
1008 xgetsockname (server->socket_udp,
1009 (struct sockaddr *)&server->address, &addrlen);
1010
1011 /* Bind the TCP socket to the same address. */
1012 {
1013 int on = 1;
1014 xsetsockopt (server->socket_tcp, SOL_SOCKET, SO_REUSEADDR,
1015 &on, sizeof (on));
1016 }
1017 if (bind (server->socket_tcp,
1018 (struct sockaddr *)&server->address,
1019 sizeof (server->address)) != 0)
1020 {
1021 /* Port collision. The UDP bind succeeded, but the TCP BIND
1022 failed. We assume here that the kernel will pick the
1023 next local UDP address randomly. */
1024 if (errno == EADDRINUSE)
1025 {
1026 xclose (server->socket_udp);
1027 xclose (server->socket_tcp);
1028 continue;
1029 }
1030 FAIL_EXIT1 ("TCP bind: %m");
1031 }
1032 xlisten (server->socket_tcp, 5);
1033 break;
1034 }
1035}
1036
1037/* Like make_server_sockets, but the caller supplies the address to
1038 use. */
1039static void
1040make_server_sockets_for_address (struct resolv_test_server *server,
1041 const struct sockaddr *addr)
1042{
1043 server->socket_udp = xsocket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1044 server->socket_tcp = xsocket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
1045
1046 if (addr->sa_family == AF_INET)
1047 server->address = *(const struct sockaddr_in *) addr;
1048 else
1049 /* We cannot store the server address in the socket. This should
1050 not matter if disable_redirect is used. */
1051 server->address = (struct sockaddr_in) { .sin_family = 0, };
1052
1053 xbind (server->socket_udp,
1054 (struct sockaddr *)&server->address, sizeof (server->address));
1055 xbind (server->socket_tcp,
1056 (struct sockaddr *)&server->address, sizeof (server->address));
1057 xlisten (server->socket_tcp, 5);
1058}
1059
1060/* One-time initialization of NSS. */
1061static void
1062resolv_redirect_once (void)
1063{
1064 /* Only use nss_dns. */
1065 __nss_configure_lookup ("hosts", "dns");
1066 __nss_configure_lookup ("networks", "dns");
1067 /* Enter a network namespace for isolation and firewall state
1068 cleanup. The tests will still work if these steps fail, but they
1069 may be less reliable. */
1070 support_become_root ();
1071 support_enter_network_namespace ();
1072}
1073pthread_once_t resolv_redirect_once_var = PTHREAD_ONCE_INIT;
1074
1075void
1076resolv_test_init (void)
1077{
1078 /* Perform one-time initialization of NSS. */
1079 xpthread_once (&resolv_redirect_once_var, resolv_redirect_once);
1080}
1081
1082/* Copy the search path from CONFIG.search to the _res object. */
1083static void
1084set_search_path (struct resolv_redirect_config config)
1085{
1086 memset (_res.defdname, 0, sizeof (_res.defdname));
1087 memset (_res.dnsrch, 0, sizeof (_res.dnsrch));
1088
1089 char *current = _res.defdname;
1090 char *end = current + sizeof (_res.defdname);
1091
1092 for (unsigned int i = 0;
1093 i < sizeof (config.search) / sizeof (config.search[0]); ++i)
1094 {
1095 if (config.search[i] == NULL)
1096 continue;
1097
1098 size_t length = strlen (config.search[i]) + 1;
1099 size_t remaining = end - current;
1100 TEST_VERIFY_EXIT (length <= remaining);
1101 memcpy (current, config.search[i], length);
1102 _res.dnsrch[i] = current;
1103 current += length;
1104 }
1105}
1106
1107struct resolv_test *
1108resolv_test_start (struct resolv_redirect_config config)
1109{
1110 /* Apply configuration defaults. */
1111 if (config.nscount == 0)
1112 config.nscount = resolv_max_test_servers;
1113
1114 struct resolv_test *obj = xmalloc (sizeof (*obj));
1115 *obj = (struct resolv_test) {
1116 .config = config,
1117 .lock = PTHREAD_MUTEX_INITIALIZER,
1118 };
1119
1120 if (!config.disable_redirect)
1121 resolv_test_init ();
1122
1123 /* Create all the servers, to reserve the necessary ports. */
1124 for (int server_index = 0; server_index < config.nscount; ++server_index)
1125 if (config.disable_redirect && config.server_address_overrides != NULL)
1126 make_server_sockets_for_address
1127 (obj->servers + server_index,
1128 config.server_address_overrides[server_index]);
1129 else
1130 make_server_sockets (obj->servers + server_index);
1131
1132 /* Start server threads. Disable the server ports, as
1133 requested. */
1134 for (int server_index = 0; server_index < config.nscount; ++server_index)
1135 {
1136 struct resolv_test_server *server = obj->servers + server_index;
1137 if (config.servers[server_index].disable_udp)
1138 {
1139 xclose (server->socket_udp);
1140 server->socket_udp = -1;
1141 }
1142 else if (!config.single_thread_udp)
1143 server->thread_udp = start_server_thread (obj, server_index,
1144 server_thread_udp);
1145 if (config.servers[server_index].disable_tcp)
1146 {
1147 xclose (server->socket_tcp);
1148 server->socket_tcp = -1;
1149 }
1150 else
1151 server->thread_tcp = start_server_thread (obj, server_index,
1152 server_thread_tcp);
1153 }
1154 if (config.single_thread_udp)
1155 start_server_thread_udp_single (obj);
1156
1157 if (config.disable_redirect)
1158 return obj;
1159
1160 int timeout = 1;
1161
1162 /* Initialize libresolv. */
1163 TEST_VERIFY_EXIT (res_init () == 0);
1164
1165 /* Disable IPv6 name server addresses. The code below only
1166 overrides the IPv4 addresses. */
1167 __res_iclose (&_res, true);
1168 _res._u._ext.nscount = 0;
1169
1170 /* Redirect queries to the server socket. */
1171 if (test_verbose)
1172 {
1173 printf ("info: old timeout value: %d\n", _res.retrans);
1174 printf ("info: old retry attempt value: %d\n", _res.retry);
1175 printf ("info: old _res.options: 0x%lx\n", _res.options);
1176 printf ("info: old _res.nscount value: %d\n", _res.nscount);
1177 printf ("info: old _res.ndots value: %d\n", _res.ndots);
1178 }
1179 _res.retrans = timeout;
1180 _res.retry = 4;
1181 _res.nscount = config.nscount;
1182 _res.options = RES_INIT | RES_RECURSE | RES_DEFNAMES | RES_DNSRCH;
1183 _res.ndots = 1;
1184 if (test_verbose)
1185 {
1186 printf ("info: new timeout value: %d\n", _res.retrans);
1187 printf ("info: new retry attempt value: %d\n", _res.retry);
1188 printf ("info: new _res.options: 0x%lx\n", _res.options);
1189 printf ("info: new _res.nscount value: %d\n", _res.nscount);
1190 printf ("info: new _res.ndots value: %d\n", _res.ndots);
1191 }
1192 for (int server_index = 0; server_index < config.nscount; ++server_index)
1193 {
1194 TEST_VERIFY_EXIT (obj->servers[server_index].address.sin_port != 0);
1195 _res.nsaddr_list[server_index] = obj->servers[server_index].address;
1196 if (test_verbose)
1197 {
1198 char buf[256];
1199 TEST_VERIFY_EXIT
1200 (inet_ntop (AF_INET, &obj->servers[server_index].address.sin_addr,
1201 buf, sizeof (buf)) != NULL);
1202 printf ("info: server %d: %s/%u\n",
1203 server_index, buf,
1204 htons (obj->servers[server_index].address.sin_port));
1205 }
1206 }
1207
1208 set_search_path (config);
1209
1210 return obj;
1211}
1212
1213void
1214resolv_test_end (struct resolv_test *obj)
1215{
1216 res_close ();
1217
1218 xpthread_mutex_lock (&obj->lock);
1219 obj->termination_requested = true;
1220 xpthread_mutex_unlock (&obj->lock);
1221
1222 /* Send trigger packets to unblock the server threads. */
1223 for (int server_index = 0; server_index < obj->config.nscount;
1224 ++server_index)
1225 {
1226 if (!obj->config.servers[server_index].disable_udp)
1227 {
1228 int sock = xsocket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1229 xsendto (sock, "", 1, 0,
1230 (struct sockaddr *) &obj->servers[server_index].address,
1231 sizeof (obj->servers[server_index].address));
1232 xclose (sock);
1233 }
1234 if (!obj->config.servers[server_index].disable_tcp)
1235 {
1236 int sock = xsocket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
1237 xconnect (sock,
1238 (struct sockaddr *) &obj->servers[server_index].address,
1239 sizeof (obj->servers[server_index].address));
1240 xclose (sock);
1241 }
1242 }
1243
1244 if (obj->config.single_thread_udp)
1245 xpthread_join (obj->thread_udp_single);
1246
1247 /* Wait for the server threads to terminate. */
1248 for (int server_index = 0; server_index < obj->config.nscount;
1249 ++server_index)
1250 {
1251 if (!obj->config.servers[server_index].disable_udp)
1252 {
1253 if (!obj->config.single_thread_udp)
1254 xpthread_join (obj->servers[server_index].thread_udp);
1255 xclose (obj->servers[server_index].socket_udp);
1256 }
1257 if (!obj->config.servers[server_index].disable_tcp)
1258 {
1259 xpthread_join (obj->servers[server_index].thread_tcp);
1260 xclose (obj->servers[server_index].socket_tcp);
1261 }
1262 }
1263
1264 free (obj);
1265}
1266