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