Browse code

glibc: fix CVE-2017-12132

Change-Id: I9d07bfd1bfd0c6c431db00ab7c1ab25a4d3c495b
Reviewed-on: http://photon-jenkins.eng.vmware.com:8082/6614
Tested-by: gerrit-photon <photon-checkins@vmware.com>
Reviewed-by: Alexey Makhalov <amakhalov@vmware.com>

Keerthana K authored on 2019/01/29 16:40:20
Showing 2 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,2134 @@
0
+From e14a27723cc3a154d67f3f26e719d08c0ba9ad25 Mon Sep 17 00:00:00 2001
1
+From: Florian Weimer <fweimer@redhat.com>
2
+Date: Thu, 13 Apr 2017 13:09:38 +0200
3
+Subject: [PATCH 1/1] resolv: Reduce EDNS payload size to 1200 bytes [BZ
4
+ #21361]
5
+
6
+This hardens the stub resolver against fragmentation-based attacks.
7
+---
8
+ ChangeLog                |  21 ++
9
+ NEWS                     |   3 +-
10
+ include/resolv.h         |   3 -
11
+ resolv/Makefile          |   2 +
12
+ resolv/res_mkquery.c     |  28 ++-
13
+ resolv/res_query.c       |  23 ++-
14
+ resolv/resolv-internal.h |  18 ++
15
+ resolv/tst-resolv-edns.c | 501 +++++++++++++++++++++++++++++++++++++++++++++++
16
+ support/resolv_test.c    |  56 +++++-
17
+ support/resolv_test.h    |  11 ++
18
+ 10 files changed, 652 insertions(+), 14 deletions(-)
19
+ create mode 100644 resolv/tst-resolv-edns.c
20
+
21
+diff --git a/include/resolv.h b/include/resolv.h
22
+index 95dcd3c..e8f477c 100644
23
+--- a/include/resolv.h
24
+@@ -38,8 +38,6 @@
25
+ extern int res_ourserver_p (const res_state __statp,
26
+ 			    const struct sockaddr_in6 *__inp);
27
+ extern void __res_iclose (res_state statp, bool free_addr);
28
+-extern int __res_nopt(res_state statp, int n0, u_char *buf, int buflen,
29
+-		      int anslen);
30
+ libc_hidden_proto (__res_ninit)
31
+ libc_hidden_proto (__res_maybe_init)
32
+ libc_hidden_proto (__res_nclose)
33
+@@ -91,7 +89,6 @@ libresolv_hidden_proto (__res_nameinquery)
34
+ libresolv_hidden_proto (__res_queriesmatch)
35
+ libresolv_hidden_proto (__res_nsend)
36
+ libresolv_hidden_proto (__b64_ntop)
37
+-libresolv_hidden_proto (__res_nopt)
38
+ libresolv_hidden_proto (__dn_count_labels)
39
+ libresolv_hidden_proto (__p_secstodate)
40
+ 
41
+diff --git a/resolv/Makefile b/resolv/Makefile
42
+index c69b24b..d41fd46 100644
43
+--- a/resolv/Makefile
44
+@@ -39,7 +39,9 @@
45
+ ifeq ($(have-thread-library),yes)
46
+ extra-libs += libanl
47
+ routines += gai_sigqueue
48
+-tests += tst-res_hconf_reorder
49
++tests += \
50
++  tst-res_hconf_reorder \
51
++  tst-resolv-edns
52
+ 
53
+ # This test sends millions of packets and is rather slow.
54
+ xtests += tst-resolv-qtypes
55
+@@ -124,3 +126,4 @@
56
+ 	$(evaluate-test)
57
+ 
58
+ $(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library)
59
++$(objpfx)tst-resolv-edns: $(objpfx)libresolv.so $(shared-thread-library)
60
+diff --git a/resolv/res_mkquery.c b/resolv/res_mkquery.c
61
+index 4532b58..8279d15 100644
62
+--- a/resolv/res_mkquery.c
63
+@@ -69,7 +69,7 @@
64
+ #include <netinet/in.h>
65
+ #include <arpa/nameser.h>
66
+ #include <netdb.h>
67
+-#include <resolv.h>
68
++#include <resolv/resolv-internal.h>
69
+ #include <stdio.h>
70
+ #include <string.h>
71
+ #include <sys/time.h>
72
+@@ -225,7 +225,30 @@ __res_nopt(res_state statp,
73
+ 	*cp++ = 0;	/* "." */
74
+ 
75
+ 	NS_PUT16(T_OPT, cp);	/* TYPE */
76
+-	NS_PUT16(MIN(anslen, 0xffff), cp);	/* CLASS = UDP payload size */
77
++
78
++	/* Lowering the advertised buffer size based on the actual
79
++	   answer buffer size is desirable because the server will
80
++	   minimize the reply to fit into the UDP packet (and A
81
++	   non-minimal response might not fit the buffer).
82
++
83
++	   The RESOLV_EDNS_BUFFER_SIZE limit could still result in TCP
84
++	   fallback and a non-minimal response which has to be
85
++	   hard-truncated in the stub resolver, but this is price to
86
++	   pay for avoiding fragmentation.  (This issue does not
87
++	   affect the nss_dns functions because they use the stub
88
++	   resolver in such a way that it allocates a properly sized
89
++	   response buffer.)  */
90
++	{
91
++	  uint16_t buffer_size;
92
++	  if (anslen < 512)
93
++	    buffer_size = 512;
94
++	  else if (anslen > RESOLV_EDNS_BUFFER_SIZE)
95
++	    buffer_size = RESOLV_EDNS_BUFFER_SIZE;
96
++	  else
97
++	    buffer_size = anslen;
98
++	  NS_PUT16 (buffer_size, cp);
99
++	}
100
++
101
+ 	*cp++ = NOERROR;	/* extended RCODE */
102
+ 	*cp++ = 0;		/* EDNS version */
103
+ 
104
+@@ -243,4 +266,3 @@ __res_nopt(res_state statp,
105
+ 
106
+ 	return cp - buf;
107
+ }
108
+-libresolv_hidden_def (__res_nopt)
109
+diff --git a/resolv/res_query.c b/resolv/res_query.c
110
+index 6f3eada..c3ebcbf 100644
111
+--- a/resolv/res_query.c
112
+@@ -78,6 +78,7 @@
113
+ #include <stdio.h>
114
+ #include <stdlib.h>
115
+ #include <string.h>
116
++#include <resolv/resolv-internal.h>
117
+ 
118
+ /* Options.  Leave them on. */
119
+ /* #undef DEBUG */
120
+@@ -147,7 +148,10 @@ __libc_res_nquery(res_state statp,
121
+ 		if ((oflags & RES_F_EDNS0ERR) == 0
122
+ 		    && (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
123
+ 		  {
124
+-		    n = __res_nopt(statp, n, query1, bufsize, anslen / 2);
125
++		    /* Use RESOLV_EDNS_BUFFER_SIZE because the receive
126
++		       buffer can be reallocated.  */
127
++		    n = __res_nopt (statp, n, query1, bufsize,
128
++				    RESOLV_EDNS_BUFFER_SIZE);
129
+ 		    if (n < 0)
130
+ 		      goto unspec_nomem;
131
+ 		  }
132
+@@ -168,8 +172,10 @@ __libc_res_nquery(res_state statp,
133
+ 		if (n > 0
134
+ 		    && (oflags & RES_F_EDNS0ERR) == 0
135
+ 		    && (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
136
+-		  n = __res_nopt(statp, n, query2, bufsize - nused - n,
137
+-				 anslen / 2);
138
++		  /* Use RESOLV_EDNS_BUFFER_SIZE because the receive
139
++		     buffer can be reallocated.  */
140
++		  n = __res_nopt (statp, n, query2, bufsize,
141
++				  RESOLV_EDNS_BUFFER_SIZE);
142
+ 		nquery2 = n;
143
+ 	      }
144
+ 
145
+@@ -183,7 +189,16 @@ __libc_res_nquery(res_state statp,
146
+ 	    if (n > 0
147
+ 		&& (oflags & RES_F_EDNS0ERR) == 0
148
+ 		&& (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
149
+-	      n = __res_nopt(statp, n, query1, bufsize, anslen);
150
++	      {
151
++		/* Use RESOLV_EDNS_BUFFER_SIZE if the receive buffer
152
++		   can be reallocated.  */
153
++		size_t advertise;
154
++		if (answerp == NULL)
155
++		  advertise = anslen;
156
++		else
157
++		  advertise = RESOLV_EDNS_BUFFER_SIZE;
158
++		n = __res_nopt (statp, n, query1, bufsize, advertise);
159
++	      }
160
+ 
161
+ 	    nquery1 = n;
162
+ 	  }
163
+diff --git a/resolv/resolv-internal.h b/resolv/resolv-internal.h
164
+new file mode 100644
165
+index d35df1c..0d69ce1
166
+--- /dev/null
167
+@@ -0,0 +1,59 @@
168
++/* libresolv interfaces for internal use across glibc.
169
++   Copyright (C) 2016-2017 Free Software Foundation, Inc.
170
++   This file is part of the GNU C Library.
171
++
172
++   The GNU C Library is free software; you can redistribute it and/or
173
++   modify it under the terms of the GNU Lesser General Public
174
++   License as published by the Free Software Foundation; either
175
++   version 2.1 of the License, or (at your option) any later version.
176
++
177
++   The GNU C Library is distributed in the hope that it will be useful,
178
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
179
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
180
++   Lesser General Public License for more details.
181
++
182
++   You should have received a copy of the GNU Lesser General Public
183
++   License along with the GNU C Library; if not, see
184
++   <http://www.gnu.org/licenses/>.  */
185
++
186
++#ifndef _RESOLV_INTERNAL_H
187
++#define _RESOLV_INTERNAL_H 1
188
++
189
++#include <resolv.h>
190
++#include <stdbool.h>
191
++
192
++/* Resolver flags.  Used for _flags in struct __res_state.  */
193
++#define RES_F_VC        0x00000001 /* Socket is TCP.  */
194
++#define RES_F_CONN      0x00000002 /* Socket is connected.  */
195
++#define RES_F_EDNS0ERR  0x00000004 /* EDNS0 caused errors.  */
196
++
197
++
198
++/* Internal version of RES_USE_INET6 which does not trigger a
199
++   deprecation warning.  */
200
++#define DEPRECATED_RES_USE_INET6 0x00002000
201
++
202
++static inline bool
203
++res_use_inet6 (void)
204
++{
205
++  return _res.options & DEPRECATED_RES_USE_INET6;
206
++}
207
++
208
++enum
209
++  {
210
++    /* The advertized EDNS buffer size.  The value 1200 is derived
211
++       from the IPv6 minimum MTU (1280 bytes) minus some arbitrary
212
++       space for tunneling overhead.  If the DNS server does not react
213
++       to ICMP Fragmentation Needed But DF Set messages, this should
214
++       avoid all UDP fragments on current networks.  Avoiding UDP
215
++       fragments is desirable because it prevents fragmentation-based
216
++       spoofing attacks because the randomness in a DNS packet is
217
++       concentrated in the first fragment (with the headers) and does
218
++       not protect subsequent fragments.  */
219
++    RESOLV_EDNS_BUFFER_SIZE = 1200,
220
++  };
221
++
222
++/* Add an OPT record to a DNS query.  */
223
++int __res_nopt (res_state, int n0, unsigned char *buf, int buflen,
224
++                int anslen) attribute_hidden;
225
++
226
++#endif  /* _RESOLV_INTERNAL_H */
227
+diff --git a/resolv/tst-resolv-edns.c b/resolv/tst-resolv-edns.c
228
+new file mode 100644
229
+index 0000000..f17dbc3
230
+--- /dev/null
231
+@@ -0,0 +1,501 @@
232
++/* Test EDNS handling in the stub resolver.
233
++   Copyright (C) 2016-2017 Free Software Foundation, Inc.
234
++   This file is part of the GNU C Library.
235
++
236
++   The GNU C Library is free software; you can redistribute it and/or
237
++   modify it under the terms of the GNU Lesser General Public
238
++   License as published by the Free Software Foundation; either
239
++   version 2.1 of the License, or (at your option) any later version.
240
++
241
++   The GNU C Library is distributed in the hope that it will be useful,
242
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
243
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
244
++   Lesser General Public License for more details.
245
++
246
++   You should have received a copy of the GNU Lesser General Public
247
++   License along with the GNU C Library; if not, see
248
++   <http://www.gnu.org/licenses/>.  */
249
++
250
++#include <errno.h>
251
++#include <netdb.h>
252
++#include <stdio.h>
253
++#include <stdlib.h>
254
++#include <string.h>
255
++#include <support/check.h>
256
++#include <support/resolv_test.h>
257
++#include <support/support.h>
258
++#include <support/test-driver.h>
259
++#include <support/xthread.h>
260
++
261
++/* Data produced by a test query.  */
262
++struct response_data
263
++{
264
++  char *qname;
265
++  uint16_t qtype;
266
++  struct resolv_edns_info edns;
267
++};
268
++
269
++/* Global array used by put_response and get_response to record
270
++   response data.  The test DNS server returns the index of the array
271
++   element which contains the actual response data.  This enables the
272
++   test case to return arbitrary amounts of data with the limited
273
++   number of bits which fit into an IP addres.
274
++
275
++   The volatile specifier is needed because the test case accesses
276
++   these variables from a callback function called from a function
277
++   which is marked as __THROW (i.e., a leaf function which actually is
278
++   not).  */
279
++static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
280
++static struct response_data ** volatile response_data_array;
281
++volatile static size_t response_data_count;
282
++
283
++/* Extract information from the query, store it in a struct
284
++   response_data object, and return its index in the
285
++   response_data_array.  */
286
++static unsigned int
287
++put_response (const struct resolv_response_context *ctx,
288
++                 const char *qname, uint16_t qtype)
289
++{
290
++  xpthread_mutex_lock (&mutex);
291
++  ++response_data_count;
292
++  /* We only can represent 2**24 indexes in 10.0.0.0/8.  */
293
++  TEST_VERIFY (response_data_count < (1 << 24));
294
++  response_data_array = xrealloc
295
++    (response_data_array, sizeof (*response_data_array) * response_data_count);
296
++  unsigned int index = response_data_count - 1;
297
++  struct response_data *data = xmalloc (sizeof (*data));
298
++  *data = (struct response_data)
299
++    {
300
++      .qname = xstrdup (qname),
301
++      .qtype = qtype,
302
++      .edns = ctx->edns,
303
++    };
304
++  response_data_array[index] = data;
305
++  xpthread_mutex_unlock (&mutex);
306
++  return index;
307
++}
308
++
309
++/* Verify the index into the response_data array and return the data
310
++   at it.  */
311
++static struct response_data *
312
++get_response (unsigned int index)
313
++{
314
++  xpthread_mutex_lock (&mutex);
315
++  TEST_VERIFY_EXIT (index < response_data_count);
316
++  struct response_data *result = response_data_array[index];
317
++  xpthread_mutex_unlock (&mutex);
318
++  return result;
319
++}
320
++
321
++/* Deallocate all response data.  */
322
++static void
323
++free_response_data (void)
324
++{
325
++  xpthread_mutex_lock (&mutex);
326
++  size_t count = response_data_count;
327
++  struct response_data **array = response_data_array;
328
++  for (unsigned int i = 0; i < count; ++i)
329
++    {
330
++      struct response_data *data = array[i];
331
++      free (data->qname);
332
++      free (data);
333
++    }
334
++  free (array);
335
++  response_data_array = NULL;
336
++  response_data_count = 0;
337
++  xpthread_mutex_unlock (&mutex);
338
++}
339
++
340
++#define EDNS_PROBE_EXAMPLE "edns-probe.example"
341
++
342
++static void
343
++response (const struct resolv_response_context *ctx,
344
++          struct resolv_response_builder *b,
345
++          const char *qname, uint16_t qclass, uint16_t qtype)
346
++{
347
++  TEST_VERIFY_EXIT (qname != NULL);
348
++
349
++  /* The "tcp." prefix can be used to request TCP fallback.  */
350
++  const char *qname_compare = qname;
351
++  bool force_tcp;
352
++  if (strncmp ("tcp.", qname_compare, strlen ("tcp.")) == 0)
353
++    {
354
++      force_tcp = true;
355
++      qname_compare += strlen ("tcp.");
356
++    }
357
++  else
358
++    force_tcp = false;
359
++
360
++  enum {edns_probe} requested_qname;
361
++  if (strcmp (qname_compare, EDNS_PROBE_EXAMPLE) == 0)
362
++    requested_qname = edns_probe;
363
++  else
364
++    {
365
++      support_record_failure ();
366
++      printf ("error: unexpected QNAME: %s\n", qname);
367
++      return;
368
++    }
369
++  TEST_VERIFY_EXIT (qclass == C_IN);
370
++  struct resolv_response_flags flags = {.tc = force_tcp && !ctx->tcp};
371
++  resolv_response_init (b, flags);
372
++  resolv_response_add_question (b, qname, qclass, qtype);
373
++  if (flags.tc)
374
++    return;
375
++
376
++  if (test_verbose)
377
++    printf ("info: edns=%d payload_size=%d\n",
378
++            ctx->edns.active, ctx->edns.payload_size);
379
++
380
++  /* Encode the response_data object in multiple address records.
381
++     Each record carries two bytes of payload data, and an index.  */
382
++  resolv_response_section (b, ns_s_an);
383
++  switch (requested_qname)
384
++    {
385
++    case edns_probe:
386
++      {
387
++        unsigned int index = put_response (ctx, qname, qtype);
388
++        switch (qtype)
389
++          {
390
++          case T_A:
391
++            {
392
++              uint32_t addr = htonl (0x0a000000 | index);
393
++              resolv_response_open_record (b, qname, qclass, qtype, 0);
394
++              resolv_response_add_data (b, &addr, sizeof (addr));
395
++              resolv_response_close_record (b);
396
++            }
397
++            break;
398
++          case T_AAAA:
399
++            {
400
++              char addr[16]
401
++                = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0,
402
++                   index >> 16, index >> 8, index};
403
++              resolv_response_open_record (b, qname, qclass, qtype, 0);
404
++              resolv_response_add_data (b, &addr, sizeof (addr));
405
++              resolv_response_close_record (b);
406
++            }
407
++          }
408
++      }
409
++      break;
410
++    }
411
++}
412
++
413
++/* Update *DATA with data from ADDRESS of SIZE.  Set the corresponding
414
++   flag in SHADOW for each byte written.  */
415
++static struct response_data *
416
++decode_address (const void *address, size_t size)
417
++{
418
++  switch (size)
419
++    {
420
++    case 4:
421
++      TEST_VERIFY (memcmp (address, "\x0a", 1) == 0);
422
++      break;
423
++    case 16:
424
++      TEST_VERIFY (memcmp (address, "\x20\x01\x0d\xb8", 4) == 0);
425
++      break;
426
++    default:
427
++      FAIL_EXIT1 ("unexpected address size %zu", size);
428
++    }
429
++  const unsigned char *addr = address;
430
++  unsigned int index = addr[size - 3] * 256 * 256
431
++    + addr[size - 2] * 256
432
++    + addr[size - 1];
433
++  return get_response (index);
434
++}
435
++
436
++static struct response_data *
437
++decode_hostent (struct hostent *e)
438
++{
439
++  TEST_VERIFY_EXIT (e != NULL);
440
++  TEST_VERIFY_EXIT (e->h_addr_list[0] != NULL);
441
++  TEST_VERIFY (e->h_addr_list[1] == NULL);
442
++  return decode_address (e->h_addr_list[0], e->h_length);
443
++}
444
++
445
++static struct response_data *
446
++decode_addrinfo (struct addrinfo *ai, int family)
447
++{
448
++  struct response_data *data = NULL;
449
++  while (ai != NULL)
450
++    {
451
++      if (ai->ai_family == family)
452
++        {
453
++          struct response_data *new_data;
454
++          switch (family)
455
++            {
456
++            case AF_INET:
457
++              {
458
++                struct sockaddr_in *pin = (struct sockaddr_in *) ai->ai_addr;
459
++                new_data = decode_address (&pin->sin_addr.s_addr, 4);
460
++              }
461
++              break;
462
++            case AF_INET6:
463
++              {
464
++                struct sockaddr_in6 *pin = (struct sockaddr_in6 *) ai->ai_addr;
465
++                new_data = decode_address (&pin->sin6_addr.s6_addr, 16);
466
++              }
467
++              break;
468
++            default:
469
++              FAIL_EXIT1 ("invalid address family %d", ai->ai_family);
470
++            }
471
++          if (data == NULL)
472
++            data = new_data;
473
++          else
474
++            /* Check pointer equality because this should be the same
475
++               response (same index).  */
476
++            TEST_VERIFY (data == new_data);
477
++        }
478
++      ai = ai->ai_next;
479
++    }
480
++  TEST_VERIFY_EXIT (data != NULL);
481
++  return data;
482
++}
483
++
484
++/* Updated by the main test loop in accordance with what is set in
485
++   _res.options.  */
486
++static bool use_edns;
487
++static bool use_dnssec;
488
++
489
++/* Verify the decoded response data against the flags above.  */
490
++static void
491
++verify_response_data_payload (struct response_data *data,
492
++                              size_t expected_payload)
493
++{
494
++  bool edns = use_edns || use_dnssec;
495
++  TEST_VERIFY (data->edns.active == edns);
496
++  if (!edns)
497
++    expected_payload = 0;
498
++  if (data->edns.payload_size != expected_payload)
499
++    {
500
++      support_record_failure ();
501
++      printf ("error: unexpected payload size %d (edns=%d)\n",
502
++              (int) data->edns.payload_size, edns);
503
++    }
504
++  uint16_t expected_flags = 0;
505
++  if (use_dnssec)
506
++    expected_flags |= 0x8000;   /* DO flag.  */
507
++  if (data->edns.flags != expected_flags)
508
++    {
509
++      support_record_failure ();
510
++      printf ("error: unexpected EDNS flags 0x%04x (edns=%d)\n",
511
++              (int) data->edns.flags, edns);
512
++    }
513
++}
514
++
515
++/* Same as verify_response_data_payload, but use the default
516
++   payload.  */
517
++static void
518
++verify_response_data (struct response_data *data)
519
++{
520
++  verify_response_data_payload (data, 1200);
521
++}
522
++
523
++static void
524
++check_hostent (struct hostent *e)
525
++{
526
++  TEST_VERIFY_EXIT (e != NULL);
527
++  verify_response_data (decode_hostent (e));
528
++}
529
++
530
++static void
531
++do_ai (int family)
532
++{
533
++  struct addrinfo hints = { .ai_family = family };
534
++  struct addrinfo *ai;
535
++  int ret = getaddrinfo (EDNS_PROBE_EXAMPLE, "80", &hints, &ai);
536
++  TEST_VERIFY_EXIT (ret == 0);
537
++  switch (family)
538
++    {
539
++    case AF_INET:
540
++    case AF_INET6:
541
++      verify_response_data (decode_addrinfo (ai, family));
542
++      break;
543
++    case AF_UNSPEC:
544
++      verify_response_data (decode_addrinfo (ai, AF_INET));
545
++      verify_response_data (decode_addrinfo (ai, AF_INET6));
546
++      break;
547
++    default:
548
++      FAIL_EXIT1 ("invalid address family %d", family);
549
++    }
550
++  freeaddrinfo (ai);
551
++}
552
++
553
++enum res_op
554
++{
555
++  res_op_search,
556
++  res_op_query,
557
++  res_op_querydomain,
558
++  res_op_nsearch,
559
++  res_op_nquery,
560
++  res_op_nquerydomain,
561
++
562
++  res_op_last = res_op_nquerydomain,
563
++};
564
++
565
++static const char *
566
++res_op_string (enum res_op op)
567
++{
568
++  switch (op)
569
++    {
570
++      case res_op_search:
571
++        return "res_search";
572
++      case res_op_query:
573
++        return "res_query";
574
++      case res_op_querydomain:
575
++        return "res_querydomain";
576
++      case res_op_nsearch:
577
++        return "res_nsearch";
578
++      case res_op_nquery:
579
++        return "res_nquery";
580
++      case res_op_nquerydomain:
581
++        return "res_nquerydomain";
582
++    }
583
++  FAIL_EXIT1 ("invalid res_op value %d", (int) op);
584
++}
585
++
586
++/* Call libresolv function OP to look up PROBE_NAME, with an answer
587
++   buffer of SIZE bytes.  Check that the advertised UDP buffer size is
588
++   in fact EXPECTED_BUFFER_SIZE.  */
589
++static void
590
++do_res_search (const char *probe_name, enum res_op op, size_t size,
591
++               size_t expected_buffer_size)
592
++{
593
++  if (test_verbose)
594
++    printf ("info: testing %s with buffer size %zu\n",
595
++            res_op_string (op), size);
596
++  unsigned char *buffer = xmalloc (size);
597
++  int ret = -1;
598
++  switch (op)
599
++    {
600
++    case res_op_search:
601
++      ret = res_search (probe_name, C_IN, T_A, buffer, size);
602
++      break;
603
++    case res_op_query:
604
++      ret = res_query (probe_name, C_IN, T_A, buffer, size);
605
++      break;
606
++    case res_op_nsearch:
607
++      ret = res_nsearch (&_res, probe_name, C_IN, T_A, buffer, size);
608
++      break;
609
++    case res_op_nquery:
610
++      ret = res_nquery (&_res, probe_name, C_IN, T_A, buffer, size);
611
++      break;
612
++    case res_op_querydomain:
613
++    case res_op_nquerydomain:
614
++      {
615
++        char *example_stripped = xstrdup (probe_name);
616
++        char *dot_example = strstr (example_stripped, ".example");
617
++        if (dot_example != NULL && strcmp (dot_example, ".example") == 0)
618
++          {
619
++            /* Truncate the domain name.  */
620
++            *dot_example = '\0';
621
++            if (op == res_op_querydomain)
622
++              ret = res_querydomain
623
++              (example_stripped, "example", C_IN, T_A, buffer, size);
624
++            else
625
++              ret = res_nquerydomain
626
++                (&_res, example_stripped, "example", C_IN, T_A, buffer, size);
627
++          }
628
++        else
629
++          FAIL_EXIT1 ("invalid probe name: %s", probe_name);
630
++        free (example_stripped);
631
++      }
632
++      break;
633
++    }
634
++  TEST_VERIFY_EXIT (ret > 12);
635
++  unsigned char *end = buffer + ret;
636
++
637
++  HEADER *hd = (HEADER *) buffer;
638
++  TEST_VERIFY (ntohs (hd->qdcount) == 1);
639
++  TEST_VERIFY (ntohs (hd->ancount) == 1);
640
++  /* Skip over the header.  */
641
++  unsigned char *p = buffer + sizeof (*hd);
642
++  /* Skip over the question.  */
643
++  ret = dn_skipname (p, end);
644
++  TEST_VERIFY_EXIT (ret > 0);
645
++  p += ret;
646
++  TEST_VERIFY_EXIT (end - p >= 4);
647
++  p += 4;
648
++  /* Skip over the RNAME and the RR header, but stop at the RDATA
649
++     length.  */
650
++  ret = dn_skipname (p, end);
651
++  TEST_VERIFY_EXIT (ret > 0);
652
++  p += ret;
653
++  TEST_VERIFY_EXIT (end - p >= 2 + 2 + 4 + 2 + 4);
654
++  p += 2 + 2 + 4;
655
++  /* The IP address should be 4 bytes long.  */
656
++  TEST_VERIFY_EXIT (p[0] == 0);
657
++  TEST_VERIFY_EXIT (p[1] == 4);
658
++  /* Extract the address information.   */
659
++  p += 2;
660
++  struct response_data *data = decode_address (p, 4);
661
++
662
++  verify_response_data_payload (data, expected_buffer_size);
663
++
664
++  free (buffer);
665
++}
666
++
667
++static void
668
++run_test (const char *probe_name)
669
++{
670
++  if (test_verbose)
671
++    printf ("\ninfo: * use_edns=%d use_dnssec=%d\n",
672
++            use_edns, use_dnssec);
673
++  check_hostent (gethostbyname (probe_name));
674
++  check_hostent (gethostbyname2 (probe_name, AF_INET));
675
++  check_hostent (gethostbyname2 (probe_name, AF_INET6));
676
++  do_ai (AF_UNSPEC);
677
++  do_ai (AF_INET);
678
++  do_ai (AF_INET6);
679
++
680
++  for (int op = 0; op <= res_op_last; ++op)
681
++    {
682
++      do_res_search (probe_name, op, 301, 512);
683
++      do_res_search (probe_name, op, 511, 512);
684
++      do_res_search (probe_name, op, 512, 512);
685
++      do_res_search (probe_name, op, 513, 513);
686
++      do_res_search (probe_name, op, 657, 657);
687
++      do_res_search (probe_name, op, 1199, 1199);
688
++      do_res_search (probe_name, op, 1200, 1200);
689
++      do_res_search (probe_name, op, 1201, 1200);
690
++      do_res_search (probe_name, op, 65535, 1200);
691
++    }
692
++}
693
++
694
++static int
695
++do_test (void)
696
++{
697
++  for (int do_edns = 0; do_edns < 2; ++do_edns)
698
++    for (int do_dnssec = 0; do_dnssec < 2; ++do_dnssec)
699
++      for (int do_tcp = 0; do_tcp < 2; ++do_tcp)
700
++        {
701
++          struct resolv_test *aux = resolv_test_start
702
++            ((struct resolv_redirect_config)
703
++             {
704
++               .response_callback = response,
705
++                 });
706
++
707
++          use_edns = do_edns;
708
++          if (do_edns)
709
++            _res.options |= RES_USE_EDNS0;
710
++          use_dnssec = do_dnssec;
711
++          if (do_dnssec)
712
++            _res.options |= RES_USE_DNSSEC;
713
++
714
++          char *probe_name = xstrdup (EDNS_PROBE_EXAMPLE);
715
++          if (do_tcp)
716
++            {
717
++              char *n = xasprintf ("tcp.%s", probe_name);
718
++              free (probe_name);
719
++              probe_name = n;
720
++            }
721
++
722
++          run_test (probe_name);
723
++
724
++          free (probe_name);
725
++          resolv_test_end (aux);
726
++        }
727
++
728
++  free_response_data ();
729
++  return 0;
730
++}
731
++
732
++#include <support/test-driver.c>
733
+diff --git a/support/resolv_test.c b/support/resolv_test.c
734
+new file mode 100644
735
+index 49ed210..5c5a463
736
+--- /dev/null
737
+@@ -0,0 +1,1201 @@
738
++/* DNS test framework and libresolv redirection.
739
++   Copyright (C) 2016-2017 Free Software Foundation, Inc.
740
++   This file is part of the GNU C Library.
741
++
742
++   The GNU C Library is free software; you can redistribute it and/or
743
++   modify it under the terms of the GNU Lesser General Public
744
++   License as published by the Free Software Foundation; either
745
++   version 2.1 of the License, or (at your option) any later version.
746
++
747
++   The GNU C Library is distributed in the hope that it will be useful,
748
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
749
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
750
++   Lesser General Public License for more details.
751
++
752
++   You should have received a copy of the GNU Lesser General Public
753
++   License along with the GNU C Library; if not, see
754
++   <http://www.gnu.org/licenses/>.  */
755
++
756
++#include <support/resolv_test.h>
757
++
758
++#include <arpa/inet.h>
759
++#include <errno.h>
760
++#include <fcntl.h>
761
++#include <nss.h>
762
++#include <resolv.h>
763
++#include <search.h>
764
++#include <stdlib.h>
765
++#include <string.h>
766
++#include <support/check.h>
767
++#include <support/namespace.h>
768
++#include <support/support.h>
769
++#include <support/test-driver.h>
770
++#include <support/xsocket.h>
771
++#include <support/xthread.h>
772
++#include <support/xunistd.h>
773
++#include <unistd.h>
774
++
775
++/* Response builder.  */
776
++
777
++enum
778
++  {
779
++    max_response_length = 65536
780
++  };
781
++
782
++/* List of pointers to be freed.  The hash table implementation
783
++   (struct hsearch_data) does not provide a way to deallocate all
784
++   objects, so this approach is used to avoid memory leaks.  */
785
++struct to_be_freed
786
++{
787
++  struct to_be_freed *next;
788
++  void *ptr;
789
++};
790
++
791
++struct resolv_response_builder
792
++{
793
++  const unsigned char *query_buffer;
794
++  size_t query_length;
795
++
796
++  size_t offset;                /* Bytes written so far in buffer.  */
797
++  ns_sect section;              /* Current section in the DNS packet.  */
798
++  unsigned int truncate_bytes;  /* Bytes to remove at end of response. */
799
++  bool drop;                    /* Discard generated response.  */
800
++  bool close;                   /* Close TCP client connection.  */
801
++
802
++  /* Offset of the two-byte RDATA length field in the currently
803
++     written RDATA sub-structure.  0 if no RDATA is being written.  */
804
++  size_t current_rdata_offset;
805
++
806
++  /* Hash table for locating targets for label compression.  */
807
++  struct hsearch_data compression_offsets;
808
++  /* List of pointers which need to be freed.  Used for domain names
809
++     involved in label compression.  */
810
++  struct to_be_freed *to_be_freed;
811
++
812
++  /* Must be last.  Not zeroed for performance reasons.  */
813
++  unsigned char buffer[max_response_length];
814
++};
815
++
816
++/* Response builder. */
817
++
818
++/* Add a pointer to the list of pointers to be freed when B is
819
++   deallocated.  */
820
++static void
821
++response_push_pointer_to_free (struct resolv_response_builder *b, void *ptr)
822
++{
823
++  if (ptr == NULL)
824
++    return;
825
++  struct to_be_freed *e = xmalloc (sizeof (*e));
826
++  *e = (struct to_be_freed) {b->to_be_freed, ptr};
827
++  b->to_be_freed = e;
828
++}
829
++
830
++void
831
++resolv_response_init (struct resolv_response_builder *b,
832
++                      struct resolv_response_flags flags)
833
++{
834
++  if (b->offset > 0)
835
++    FAIL_EXIT1 ("response_init: called at offset %zu", b->offset);
836
++  if (b->query_length < 12)
837
++    FAIL_EXIT1 ("response_init called for a query of size %zu",
838
++                b->query_length);
839
++  if (flags.rcode > 15)
840
++    FAIL_EXIT1 ("response_init: invalid RCODE %u", flags.rcode);
841
++
842
++  /* Copy the transaction ID.  */
843
++  b->buffer[0] = b->query_buffer[0];
844
++  b->buffer[1] = b->query_buffer[1];
845
++
846
++  /* Initialize the flags.  */
847
++  b->buffer[2] = 0x80;                       /* Mark as response.   */
848
++  b->buffer[2] |= b->query_buffer[2] & 0x01; /* Copy the RD bit.  */
849
++  if (flags.tc)
850
++    b->buffer[2] |= 0x02;
851
++  b->buffer[3] = 0x80 | flags.rcode; /* Always set RA.  */
852
++
853
++  /* Fill in the initial section count values.  */
854
++  b->buffer[4] = flags.qdcount >> 8;
855
++  b->buffer[5] = flags.qdcount;
856
++  b->buffer[6] = flags.ancount >> 8;
857
++  b->buffer[7] = flags.ancount;
858
++  b->buffer[8] = flags.nscount >> 8;
859
++  b->buffer[9] = flags.nscount;
860
++  b->buffer[10] = flags.adcount >> 8;
861
++  b->buffer[11] = flags.adcount;
862
++
863
++  b->offset = 12;
864
++}
865
++
866
++void
867
++resolv_response_section (struct resolv_response_builder *b, ns_sect section)
868
++{
869
++  if (b->offset == 0)
870
++    FAIL_EXIT1 ("resolv_response_section: response_init not called before");
871
++  if (section < b->section)
872
++    FAIL_EXIT1 ("resolv_response_section: cannot go back to previous section");
873
++  b->section = section;
874
++}
875
++
876
++/* Add a single byte to B.  */
877
++static inline void
878
++response_add_byte (struct resolv_response_builder *b, unsigned char ch)
879
++{
880
++  if (b->offset == max_response_length)
881
++    FAIL_EXIT1 ("DNS response exceeds 64 KiB limit");
882
++  b->buffer[b->offset] = ch;
883
++  ++b->offset;
884
++}
885
++
886
++/* Add a 16-bit word VAL to B, in big-endian format.  */
887
++static void
888
++response_add_16 (struct resolv_response_builder *b, uint16_t val)
889
++{
890
++  response_add_byte (b, val >> 8);
891
++  response_add_byte (b, val);
892
++}
893
++
894
++/* Increment the pers-section record counter in the packet header.  */
895
++static void
896
++response_count_increment (struct resolv_response_builder *b)
897
++{
898
++  unsigned int offset = b->section;
899
++  offset = 4 + 2 * offset;
900
++  ++b->buffer[offset + 1];
901
++  if (b->buffer[offset + 1] == 0)
902
++    {
903
++      /* Carry.  */
904
++      ++b->buffer[offset];
905
++      if (b->buffer[offset] == 0)
906
++        /* Overflow.  */
907
++        FAIL_EXIT1 ("too many records in section");
908
++    }
909
++}
910
++
911
++void
912
++resolv_response_add_question (struct resolv_response_builder *b,
913
++                              const char *name, uint16_t class, uint16_t type)
914
++{
915
++  if (b->offset == 0)
916
++    FAIL_EXIT1 ("resolv_response_add_question: "
917
++                "resolv_response_init not called");
918
++  if (b->section != ns_s_qd)
919
++    FAIL_EXIT1 ("resolv_response_add_question: "
920
++                "must be called in the question section");
921
++
922
++  resolv_response_add_name (b, name);
923
++  response_add_16 (b, type);
924
++  response_add_16 (b, class);
925
++
926
++  response_count_increment (b);
927
++}
928
++
929
++void
930
++resolv_response_add_name (struct resolv_response_builder *b,
931
++                          const char *const origname)
932
++{
933
++  /* Normalized name.  */
934
++  char *name;
935
++  /* Normalized name with case preserved.  */
936
++  char *name_case;
937
++  {
938
++    size_t namelen = strlen (origname);
939
++    /* Remove trailing dots.  FIXME: Handle trailing quoted dots.  */
940
++    while (namelen > 0 && origname[namelen - 1] == '.')
941
++      --namelen;
942
++    name = xmalloc (namelen + 1);
943
++    name_case = xmalloc (namelen + 1);
944
++    /* Copy and convert to lowercase.  FIXME: This needs to normalize
945
++       escaping as well.  */
946
++    for (size_t i = 0; i < namelen; ++i)
947
++      {
948
++        char ch = origname[i];
949
++        name_case[i] = ch;
950
++        if ('A' <= ch && ch <= 'Z')
951
++          ch = ch - 'A' + 'a';
952
++        name[i] = ch;
953
++      }
954
++    name[namelen] = 0;
955
++    name_case[namelen] = 0;
956
++  }
957
++  char *name_start = name;
958
++  char *name_case_start = name_case;
959
++
960
++  bool compression = false;
961
++  while (*name)
962
++    {
963
++      /* Search for a previous name we can reference.  */
964
++      ENTRY new_entry =
965
++        {
966
++          .key = name,
967
++          .data = (void *) (uintptr_t) b->offset,
968
++        };
969
++
970
++      /* If the label can be a compression target because it is at a
971
++         reachable offset, add it to the hash table.  */
972
++      ACTION action;
973
++      if (b->offset < (1 << 12))
974
++        action = ENTER;
975
++      else
976
++        action = FIND;
977
++
978
++      /* Search for known compression offsets in the hash table.  */
979
++      ENTRY *e;
980
++      if (hsearch_r (new_entry, action, &e, &b->compression_offsets) == 0)
981
++        {
982
++          if (action == FIND && errno == ESRCH)
983
++            /* Fall through.  */
984
++            e = NULL;
985
++          else
986
++            FAIL_EXIT1 ("hsearch_r failure in name compression: %m");
987
++        }
988
++
989
++      /* The name is known.  Reference the previous location.  */
990
++      if (e != NULL && e->data != new_entry.data)
991
++        {
992
++          size_t old_offset = (uintptr_t) e->data;
993
++          response_add_byte (b, 0xC0 | (old_offset >> 8));
994
++          response_add_byte (b, old_offset);
995
++          compression = true;
996
++          break;
997
++        }
998
++
999
++      /* The name does not exist yet.  Write one label.  First, add
1000
++         room for the label length.  */
1001
++      size_t buffer_label_offset = b->offset;
1002
++      response_add_byte (b, 0);
1003
++
1004
++      /* Copy the label.  */
1005
++      while (true)
1006
++        {
1007
++          char ch = *name_case;
1008
++          if (ch == '\0')
1009
++            break;
1010
++          ++name;
1011
++          ++name_case;
1012
++          if (ch == '.')
1013
++            break;
1014
++          /* FIXME: Handle escaping.  */
1015
++          response_add_byte (b, ch);
1016
++        }
1017
++
1018
++      /* Patch in the label length.  */
1019
++      size_t label_length = b->offset - buffer_label_offset - 1;
1020
++      if (label_length == 0)
1021
++        FAIL_EXIT1 ("empty label in name compression: %s", origname);
1022
++      if (label_length > 63)
1023
++        FAIL_EXIT1 ("label too long in name compression: %s", origname);
1024
++      b->buffer[buffer_label_offset] = label_length;
1025
++
1026
++      /* Continue with the tail of the name and the next label.  */
1027
++    }
1028
++
1029
++  if (compression)
1030
++    {
1031
++      /* If we found an immediate match for the name, we have not put
1032
++         it into the hash table, and can free it immediately.  */
1033
++      if (name == name_start)
1034
++        free (name_start);
1035
++      else
1036
++        response_push_pointer_to_free (b, name_start);
1037
++    }
1038
++  else
1039
++    {
1040
++      /* Terminate the sequence of labels.  With compression, this is
1041
++         implicit in the compression reference.  */
1042
++      response_add_byte (b, 0);
1043
++      response_push_pointer_to_free (b, name_start);
1044
++    }
1045
++
1046
++  free (name_case_start);
1047
++}
1048
++
1049
++void
1050
++resolv_response_open_record (struct resolv_response_builder *b,
1051
++                             const char *name,
1052
++                             uint16_t class, uint16_t type, uint32_t ttl)
1053
++{
1054
++  if (b->section == ns_s_qd)
1055
++    FAIL_EXIT1 ("resolv_response_open_record called in question section");
1056
++  if (b->current_rdata_offset != 0)
1057
++    FAIL_EXIT1 ("resolv_response_open_record called with open record");
1058
++
1059
++  resolv_response_add_name (b, name);
1060
++  response_add_16 (b, type);
1061
++  response_add_16 (b, class);
1062
++  response_add_16 (b, ttl >> 16);
1063
++  response_add_16 (b, ttl);
1064
++
1065
++  b->current_rdata_offset = b->offset;
1066
++  /* Add room for the RDATA length.  */
1067
++  response_add_16 (b, 0);
1068
++}
1069
++
1070
++
1071
++void
1072
++resolv_response_close_record (struct resolv_response_builder *b)
1073
++{
1074
++  size_t rdata_offset = b->current_rdata_offset;
1075
++  if (rdata_offset == 0)
1076
++    FAIL_EXIT1 ("response_close_record called without open record");
1077
++  size_t rdata_length = b->offset - rdata_offset - 2;
1078
++  if (rdata_length > 65535)
1079
++    FAIL_EXIT1 ("RDATA length %zu exceeds limit", rdata_length);
1080
++  b->buffer[rdata_offset] = rdata_length >> 8;
1081
++  b->buffer[rdata_offset + 1] = rdata_length;
1082
++  response_count_increment (b);
1083
++  b->current_rdata_offset = 0;
1084
++}
1085
++
1086
++void
1087
++resolv_response_add_data (struct resolv_response_builder *b,
1088
++                          const void *data, size_t length)
1089
++{
1090
++  size_t remaining = max_response_length - b->offset;
1091
++  if (remaining < length)
1092
++    FAIL_EXIT1 ("resolv_response_add_data: not enough room for %zu bytes",
1093
++                length);
1094
++  memcpy (b->buffer + b->offset, data, length);
1095
++  b->offset += length;
1096
++}
1097
++
1098
++void
1099
++resolv_response_drop (struct resolv_response_builder *b)
1100
++{
1101
++  b->drop = true;
1102
++}
1103
++
1104
++void
1105
++resolv_response_close (struct resolv_response_builder *b)
1106
++{
1107
++  b->close = true;
1108
++}
1109
++
1110
++void
1111
++resolv_response_truncate_data (struct resolv_response_builder *b, size_t count)
1112
++{
1113
++  if (count > 65535)
1114
++    FAIL_EXIT1 ("resolv_response_truncate_data: argument too large: %zu",
1115
++                count);
1116
++  b->truncate_bytes = count;
1117
++}
1118
++
1119
++
1120
++size_t
1121
++resolv_response_length (const struct resolv_response_builder *b)
1122
++{
1123
++  return b->offset;
1124
++}
1125
++
1126
++unsigned char *
1127
++resolv_response_buffer (const struct resolv_response_builder *b)
1128
++{
1129
++  unsigned char *result = xmalloc (b->offset);
1130
++  memcpy (result, b->buffer, b->offset);
1131
++  return result;
1132
++}
1133
++
1134
++static struct resolv_response_builder *
1135
++response_builder_allocate
1136
++  (const unsigned char *query_buffer, size_t query_length)
1137
++{
1138
++  struct resolv_response_builder *b = xmalloc (sizeof (*b));
1139
++  memset (b, 0, offsetof (struct resolv_response_builder, buffer));
1140
++  b->query_buffer = query_buffer;
1141
++  b->query_length = query_length;
1142
++  TEST_VERIFY_EXIT (hcreate_r (10000, &b->compression_offsets) != 0);
1143
++  return b;
1144
++}
1145
++
1146
++static void
1147
++response_builder_free (struct resolv_response_builder *b)
1148
++{
1149
++  struct to_be_freed *current = b->to_be_freed;
1150
++  while (current != NULL)
1151
++    {
1152
++      struct to_be_freed *next = current->next;
1153
++      free (current->ptr);
1154
++      free (current);
1155
++      current = next;
1156
++    }
1157
++  hdestroy_r (&b->compression_offsets);
1158
++  free (b);
1159
++}
1160
++
1161
++/* DNS query processing. */
1162
++
1163
++/* Data extracted from the question section of a DNS packet.  */
1164
++struct query_info
1165
++{
1166
++  char qname[MAXDNAME];
1167
++  uint16_t qclass;
1168
++  uint16_t qtype;
1169
++  struct resolv_edns_info edns;
1170
++};
1171
++
1172
++/* Update *INFO from the specified DNS packet.  */
1173
++static void
1174
++parse_query (struct query_info *info,
1175
++             const unsigned char *buffer, size_t length)
1176
++{
1177
++  HEADER hd;
1178
++  _Static_assert (sizeof (hd) == 12, "DNS header size");
1179
++  if (length < sizeof (hd))
1180
++    FAIL_EXIT1 ("malformed DNS query: too short: %zu bytes", length);
1181
++  memcpy (&hd, buffer, sizeof (hd));
1182
++
1183
++  if (ntohs (hd.qdcount) != 1)
1184
++    FAIL_EXIT1 ("malformed DNS query: wrong question count: %d",
1185
++                (int) ntohs (hd.qdcount));
1186
++  if (ntohs (hd.ancount) != 0)
1187
++    FAIL_EXIT1 ("malformed DNS query: wrong answer count: %d",
1188
++                (int) ntohs (hd.ancount));
1189
++  if (ntohs (hd.nscount) != 0)
1190
++    FAIL_EXIT1 ("malformed DNS query: wrong authority count: %d",
1191
++                (int) ntohs (hd.nscount));
1192
++  if (ntohs (hd.arcount) > 1)
1193
++    FAIL_EXIT1 ("malformed DNS query: wrong additional count: %d",
1194
++                (int) ntohs (hd.arcount));
1195
++
1196
++  int ret = dn_expand (buffer, buffer + length, buffer + sizeof (hd),
1197
++                       info->qname, sizeof (info->qname));
1198
++  if (ret < 0)
1199
++    FAIL_EXIT1 ("malformed DNS query: cannot uncompress QNAME");
1200
++
1201
++  /* Obtain QTYPE and QCLASS.  */
1202
++  size_t remaining = length - (12 + ret);
1203
++  struct
1204
++  {
1205
++    uint16_t qtype;
1206
++    uint16_t qclass;
1207
++  } qtype_qclass;
1208
++  if (remaining < sizeof (qtype_qclass))
1209
++    FAIL_EXIT1 ("malformed DNS query: "
1210
++                "query lacks QCLASS/QTYPE, QNAME: %s", info->qname);
1211
++  memcpy (&qtype_qclass, buffer + 12 + ret, sizeof (qtype_qclass));
1212
++  info->qclass = ntohs (qtype_qclass.qclass);
1213
++  info->qtype = ntohs (qtype_qclass.qtype);
1214
++
1215
++  memset (&info->edns, 0, sizeof (info->edns));
1216
++  if (ntohs (hd.arcount) > 0)
1217
++    {
1218
++      /* Parse EDNS record.  */
1219
++      struct __attribute__ ((packed, aligned (1)))
1220
++      {
1221
++        uint8_t root;
1222
++        uint16_t rtype;
1223
++        uint16_t payload;
1224
++        uint8_t edns_extended_rcode;
1225
++        uint8_t edns_version;
1226
++        uint16_t flags;
1227
++        uint16_t rdatalen;
1228
++      } rr;
1229
++      _Static_assert (sizeof (rr) == 11, "EDNS record size");
1230
++
1231
++      if (remaining < 4 + sizeof (rr))
1232
++        FAIL_EXIT1 ("mailformed DNS query: no room for EDNS record");
1233
++      memcpy (&rr, buffer + 12 + ret + 4, sizeof (rr));
1234
++      if (rr.root != 0)
1235
++        FAIL_EXIT1 ("malformed DNS query: invalid OPT RNAME: %d\n", rr.root);
1236
++      if (rr.rtype != htons (41))
1237
++        FAIL_EXIT1 ("malformed DNS query: invalid OPT type: %d\n",
1238
++                    ntohs (rr.rtype));
1239
++      info->edns.active = true;
1240
++      info->edns.extended_rcode = rr.edns_extended_rcode;
1241
++      info->edns.version = rr.edns_version;
1242
++      info->edns.flags = ntohs (rr.flags);
1243
++      info->edns.payload_size = ntohs (rr.payload);
1244
++    }
1245
++}
1246
++
1247
++
1248
++/* Main testing framework.  */
1249
++
1250
++/* Per-server information.  One struct is allocated for each test
1251
++   server.  */
1252
++struct resolv_test_server
1253
++{
1254
++  /* Local address of the server.  UDP and TCP use the same port.  */
1255
++  struct sockaddr_in address;
1256
++
1257
++  /* File descriptor of the UDP server, or -1 if this server is
1258
++     disabled.  */
1259
++  int socket_udp;
1260
++
1261
++  /* File descriptor of the TCP server, or -1 if this server is
1262
++     disabled.  */
1263
++  int socket_tcp;
1264
++
1265
++  /* Counter of the number of responses processed so far.  */
1266
++  size_t response_number;
1267
++
1268
++  /* Thread handles for the server threads (if not disabled in the
1269
++     configuration).  */
1270
++  pthread_t thread_udp;
1271
++  pthread_t thread_tcp;
1272
++};
1273
++
1274
++/* Main struct for keeping track of libresolv redirection and
1275
++   testing.  */
1276
++struct resolv_test
1277
++{
1278
++  /* After initialization, any access to the struct must be performed
1279
++     while this lock is acquired.  */
1280
++  pthread_mutex_t lock;
1281
++
1282
++  /* Data for each test server. */
1283
++  struct resolv_test_server servers[resolv_max_test_servers];
1284
++
1285
++  /* Used if config.single_thread_udp is true.  */
1286
++  pthread_t thread_udp_single;
1287
++
1288
++  struct resolv_redirect_config config;
1289
++  bool termination_requested;
1290
++};
1291
++
1292
++/* Function implementing a server thread.  */
1293
++typedef void (*thread_callback) (struct resolv_test *, int server_index);
1294
++
1295
++/* Storage for thread-specific data, for passing to the
1296
++   thread_callback function.  */
1297
++struct thread_closure
1298
++{
1299
++  struct resolv_test *obj;      /* Current test object.  */
1300
++  thread_callback callback;     /* Function to call.  */
1301
++  int server_index;             /* Index of the implemented server.  */
1302
++};
1303
++
1304
++/* Wrap response_callback as a function which can be passed to
1305
++   pthread_create.  */
1306
++static void *
1307
++thread_callback_wrapper (void *arg)
1308
++{
1309
++  struct thread_closure *closure = arg;
1310
++  closure->callback (closure->obj, closure->server_index);
1311
++  free (closure);
1312
++  return NULL;
1313
++}
1314
++
1315
++/* Start a server thread for the specified SERVER_INDEX, implemented
1316
++   by CALLBACK.  */
1317
++static pthread_t
1318
++start_server_thread (struct resolv_test *obj, int server_index,
1319
++                     thread_callback callback)
1320
++{
1321
++  struct thread_closure *closure = xmalloc (sizeof (*closure));
1322
++  *closure = (struct thread_closure)
1323
++    {
1324
++      .obj = obj,
1325
++      .callback = callback,
1326
++      .server_index = server_index,
1327
++    };
1328
++  return xpthread_create (NULL, thread_callback_wrapper, closure);
1329
++}
1330
++
1331
++/* Process one UDP query.  Return false if a termination requested has
1332
++   been detected.  */
1333
++static bool
1334
++server_thread_udp_process_one (struct resolv_test *obj, int server_index)
1335
++{
1336
++  unsigned char query[512];
1337
++  struct sockaddr_storage peer;
1338
++  socklen_t peerlen = sizeof (peer);
1339
++  size_t length = xrecvfrom (obj->servers[server_index].socket_udp,
1340
++                             query, sizeof (query), 0,
1341
++                             (struct sockaddr *) &peer, &peerlen);
1342
++  /* Check for termination.  */
1343
++  {
1344
++    bool termination_requested;
1345
++    xpthread_mutex_lock (&obj->lock);
1346
++    termination_requested = obj->termination_requested;
1347
++    xpthread_mutex_unlock (&obj->lock);
1348
++    if (termination_requested)
1349
++      return false;
1350
++  }
1351
++
1352
++
1353
++  struct query_info qinfo;
1354
++  parse_query (&qinfo, query, length);
1355
++  if (test_verbose > 0)
1356
++    {
1357
++      if (test_verbose > 1)
1358
++        printf ("info: UDP server %d: incoming query:"
1359
++                " %zd bytes, %s/%u/%u, tnxid=0x%02x%02x\n",
1360
++                server_index, length, qinfo.qname, qinfo.qclass, qinfo.qtype,
1361
++                query[0], query[1]);
1362
++      else
1363
++        printf ("info: UDP server %d: incoming query:"
1364
++                " %zd bytes, %s/%u/%u\n",
1365
++                server_index, length, qinfo.qname, qinfo.qclass, qinfo.qtype);
1366
++    }
1367
++
1368
++  struct resolv_response_context ctx =
1369
++    {
1370
++      .query_buffer = query,
1371
++      .query_length = length,
1372
++      .server_index = server_index,
1373
++      .tcp = false,
1374
++      .edns = qinfo.edns,
1375
++    };
1376
++  struct resolv_response_builder *b = response_builder_allocate (query, length);
1377
++  obj->config.response_callback
1378
++    (&ctx, b, qinfo.qname, qinfo.qclass, qinfo.qtype);
1379
++
1380
++  if (b->drop)
1381
++    {
1382
++      if (test_verbose)
1383
++        printf ("info: UDP server %d: dropping response to %s/%u/%u\n",
1384
++                server_index, qinfo.qname, qinfo.qclass, qinfo.qtype);
1385
++    }
1386
++  else
1387
++    {
1388
++      if (test_verbose)
1389
++        {
1390
++          if (b->offset >= 12)
1391
++            printf ("info: UDP server %d: sending response:"
1392
++                    " %zu bytes, RCODE %d (for %s/%u/%u)\n",
1393
++                    server_index, b->offset, b->buffer[3] & 0x0f,
1394
++                    qinfo.qname, qinfo.qclass, qinfo.qtype);
1395
++          else
1396
++            printf ("info: UDP server %d: sending response: %zu bytes"
1397
++                    " (for %s/%u/%u)\n",
1398
++                    server_index, b->offset,
1399
++                    qinfo.qname, qinfo.qclass, qinfo.qtype);
1400
++          if (b->truncate_bytes > 0)
1401
++            printf ("info:    truncated by %u bytes\n", b->truncate_bytes);
1402
++        }
1403
++      size_t to_send = b->offset;
1404
++      if (to_send < b->truncate_bytes)
1405
++        to_send = 0;
1406
++      else
1407
++        to_send -= b->truncate_bytes;
1408
++
1409
++      /* Ignore most errors here because the other end may have closed
1410
++         the socket. */
1411
++      if (sendto (obj->servers[server_index].socket_udp,
1412
++                  b->buffer, to_send, 0,
1413
++                  (struct sockaddr *) &peer, peerlen) < 0)
1414
++        TEST_VERIFY_EXIT (errno != EBADF);
1415
++    }
1416
++  response_builder_free (b);
1417
++  return true;
1418
++}
1419
++
1420
++/* UDP thread_callback function.  Variant for one thread per
1421
++   server.  */
1422
++static void
1423
++server_thread_udp (struct resolv_test *obj, int server_index)
1424
++{
1425
++  while (server_thread_udp_process_one (obj, server_index))
1426
++    ;
1427
++}
1428
++
1429
++/* Single-threaded UDP processing function, for the single_thread_udp
1430
++   case.  */
1431
++static void *
1432
++server_thread_udp_single (void *closure)
1433
++{
1434
++  struct resolv_test *obj = closure;
1435
++
1436
++  struct pollfd fds[resolv_max_test_servers];
1437
++  for (int server_index = 0; server_index < resolv_max_test_servers;
1438
++       ++server_index)
1439
++    if (obj->config.servers[server_index].disable_udp)
1440
++      fds[server_index] = (struct pollfd) {.fd = -1};
1441
++    else
1442
++      {
1443
++        fds[server_index] = (struct pollfd)
1444
++          {
1445
++            .fd = obj->servers[server_index].socket_udp,
1446
++            .events = POLLIN
1447
++          };
1448
++
1449
++        /* Make the socket non-blocking.  */
1450
++        int flags = fcntl (obj->servers[server_index].socket_udp, F_GETFL, 0);
1451
++        if (flags < 0)
1452
++          FAIL_EXIT1 ("fcntl (F_GETFL): %m");
1453
++        flags |= O_NONBLOCK;
1454
++        if (fcntl (obj->servers[server_index].socket_udp, F_SETFL, flags) < 0)
1455
++          FAIL_EXIT1 ("fcntl (F_SETFL): %m");
1456
++      }
1457
++
1458
++  while (true)
1459
++    {
1460
++      xpoll (fds, resolv_max_test_servers, -1);
1461
++      for (int server_index = 0; server_index < resolv_max_test_servers;
1462
++           ++server_index)
1463
++        if (fds[server_index].revents != 0)
1464
++          {
1465
++            if (!server_thread_udp_process_one (obj, server_index))
1466
++              goto out;
1467
++            fds[server_index].revents = 0;
1468
++          }
1469
++    }
1470
++
1471
++ out:
1472
++  return NULL;
1473
++}
1474
++
1475
++/* Start the single UDP handler thread (for the single_thread_udp
1476
++   case).  */
1477
++static void
1478
++start_server_thread_udp_single (struct resolv_test *obj)
1479
++{
1480
++  obj->thread_udp_single
1481
++    = xpthread_create (NULL, server_thread_udp_single, obj);
1482
++}
1483
++
1484
++/* Data describing a TCP client connect.  */
1485
++struct tcp_thread_closure
1486
++{
1487
++  struct resolv_test *obj;
1488
++  int server_index;
1489
++  int client_socket;
1490
++};
1491
++
1492
++/* Read a complete DNS query packet.  If EOF_OK, an immediate
1493
++   end-of-file condition is acceptable.  */
1494
++static bool
1495
++read_fully (int fd, void *buf, size_t len, bool eof_ok)
1496
++{
1497
++  const void *const end = buf + len;
1498
++  while (buf < end)
1499
++    {
1500
++      ssize_t ret = read (fd, buf, end - buf);
1501
++      if (ret == 0)
1502
++        {
1503
++          if (!eof_ok)
1504
++            {
1505
++              support_record_failure ();
1506
++              printf ("error: unexpected EOF on TCP connection\n");
1507
++            }
1508
++          return false;
1509
++        }
1510
++      else if (ret < 0)
1511
++        {
1512
++          if (!eof_ok || errno != ECONNRESET)
1513
++            {
1514
++              support_record_failure ();
1515
++              printf ("error: TCP read: %m\n");
1516
++            }
1517
++          return false;
1518
++        }
1519
++      buf += ret;
1520
++      eof_ok = false;
1521
++    }
1522
++  return true;
1523
++}
1524
++
1525
++/* Write an array of iovecs.  Terminate the process on failure.  */
1526
++static void
1527
++writev_fully (int fd, struct iovec *buffers, size_t count)
1528
++{
1529
++  while (count > 0)
1530
++    {
1531
++      /* Skip zero-length write requests.  */
1532
++      if (buffers->iov_len == 0)
1533
++        {
1534
++          ++buffers;
1535
++          --count;
1536
++          continue;
1537
++        }
1538
++      /* Try to rewrite the remaing buffers.  */
1539
++      ssize_t ret = writev (fd, buffers, count);
1540
++      if (ret < 0)
1541
++        FAIL_EXIT1 ("writev: %m");
1542
++      if (ret == 0)
1543
++        FAIL_EXIT1 ("writev: invalid return value zero");
1544
++      /* Find the buffers that were successfully written.  */
1545
++      while (ret > 0)
1546
++        {
1547
++          if (count == 0)
1548
++            FAIL_EXIT1 ("internal writev consistency failure");
1549
++          /* Current buffer was partially written.  */
1550
++          if (buffers->iov_len > (size_t) ret)
1551
++            {
1552
++              buffers->iov_base += ret;
1553
++              buffers->iov_len -= ret;
1554
++              ret = 0;
1555
++            }
1556
++          else
1557
++            {
1558
++              ret -= buffers->iov_len;
1559
++              buffers->iov_len = 0;
1560
++              ++buffers;
1561
++              --count;
1562
++            }
1563
++        }
1564
++    }
1565
++}
1566
++
1567
++/* Thread callback for handling a single established TCP connection to
1568
++   a client.  */
1569
++static void *
1570
++server_thread_tcp_client (void *arg)
1571
++{
1572
++  struct tcp_thread_closure *closure = arg;
1573
++
1574
++  while (true)
1575
++    {
1576
++      /* Read packet length.  */
1577
++      uint16_t query_length;
1578
++      if (!read_fully (closure->client_socket,
1579
++                       &query_length, sizeof (query_length), true))
1580
++        break;
1581
++      query_length = ntohs (query_length);
1582
++
1583
++      /* Read the packet.  */
1584
++      unsigned char *query_buffer = xmalloc (query_length);
1585
++      read_fully (closure->client_socket, query_buffer, query_length, false);
1586
++
1587
++      struct query_info qinfo;
1588
++      parse_query (&qinfo, query_buffer, query_length);
1589
++      if (test_verbose > 0)
1590
++        {
1591
++          if (test_verbose > 1)
1592
++            printf ("info: UDP server %d: incoming query:"
1593
++                    " %d bytes, %s/%u/%u, tnxid=0x%02x%02x\n",
1594
++                    closure->server_index, query_length,
1595
++                    qinfo.qname, qinfo.qclass, qinfo.qtype,
1596
++                    query_buffer[0], query_buffer[1]);
1597
++          else
1598
++            printf ("info: TCP server %d: incoming query:"
1599
++                    " %u bytes, %s/%u/%u\n",
1600
++                    closure->server_index, query_length,
1601
++                    qinfo.qname, qinfo.qclass, qinfo.qtype);
1602
++        }
1603
++
1604
++      struct resolv_response_context ctx =
1605
++        {
1606
++          .query_buffer = query_buffer,
1607
++          .query_length = query_length,
1608
++          .server_index = closure->server_index,
1609
++          .tcp = true,
1610
++          .edns = qinfo.edns,
1611
++        };
1612
++      struct resolv_response_builder *b = response_builder_allocate
1613
++        (query_buffer, query_length);
1614
++      closure->obj->config.response_callback
1615
++        (&ctx, b, qinfo.qname, qinfo.qclass, qinfo.qtype);
1616
++
1617
++      if (b->drop)
1618
++        {
1619
++          if (test_verbose)
1620
++            printf ("info: TCP server %d: dropping response to %s/%u/%u\n",
1621
++                    closure->server_index,
1622
++                    qinfo.qname, qinfo.qclass, qinfo.qtype);
1623
++        }
1624
++      else
1625
++        {
1626
++          if (test_verbose)
1627
++            printf ("info: TCP server %d: sending response: %zu bytes"
1628
++                    " (for %s/%u/%u)\n",
1629
++                    closure->server_index, b->offset,
1630
++                    qinfo.qname, qinfo.qclass, qinfo.qtype);
1631
++          uint16_t length = htons (b->offset);
1632
++          size_t to_send = b->offset;
1633
++          if (to_send < b->truncate_bytes)
1634
++            to_send = 0;
1635
++          else
1636
++            to_send -= b->truncate_bytes;
1637
++          struct iovec buffers[2] =
1638
++            {
1639
++              {&length, sizeof (length)},
1640
++              {b->buffer, to_send}
1641
++            };
1642
++          writev_fully (closure->client_socket, buffers, 2);
1643
++        }
1644
++      bool close_flag = b->close;
1645
++      response_builder_free (b);
1646
++      free (query_buffer);
1647
++      if (close_flag)
1648
++        break;
1649
++    }
1650
++
1651
++  xclose (closure->client_socket);
1652
++  free (closure);
1653
++  return NULL;
1654
++}
1655
++
1656
++/* thread_callback for the TCP case.  Accept connections and create a
1657
++   new thread for each client.  */
1658
++static void
1659
++server_thread_tcp (struct resolv_test *obj, int server_index)
1660
++{
1661
++  while (true)
1662
++    {
1663
++      /* Get the client conenction.  */
1664
++      int client_socket = xaccept
1665
++        (obj->servers[server_index].socket_tcp, NULL, NULL);
1666
++
1667
++      /* Check for termination.  */
1668
++      xpthread_mutex_lock (&obj->lock);
1669
++      if (obj->termination_requested)
1670
++        {
1671
++          xpthread_mutex_unlock (&obj->lock);
1672
++          xclose (client_socket);
1673
++          break;
1674
++        }
1675
++      xpthread_mutex_unlock (&obj->lock);
1676
++
1677
++      /* Spawn a new thread for handling this connection.  */
1678
++      struct tcp_thread_closure *closure = xmalloc (sizeof (*closure));
1679
++      *closure = (struct tcp_thread_closure)
1680
++        {
1681
++          .obj = obj,
1682
++          .server_index = server_index,
1683
++          .client_socket = client_socket,
1684
++        };
1685
++
1686
++      pthread_t thr
1687
++        = xpthread_create (NULL, server_thread_tcp_client, closure);
1688
++      /* TODO: We should keep track of this thread so that we can
1689
++         block in resolv_test_end until it has exited.  */
1690
++      xpthread_detach (thr);
1691
++    }
1692
++}
1693
++
1694
++/* Create UDP and TCP server sockets.  */
1695
++static void
1696
++make_server_sockets (struct resolv_test_server *server)
1697
++{
1698
++  while (true)
1699
++    {
1700
++      server->socket_udp = xsocket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1701
++      server->socket_tcp = xsocket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
1702
++
1703
++      /* Pick the address for the UDP socket.  */
1704
++      server->address = (struct sockaddr_in)
1705
++        {
1706
++          .sin_family = AF_INET,
1707
++          .sin_addr = {.s_addr = htonl (INADDR_LOOPBACK)}
1708
++        };
1709
++      xbind (server->socket_udp,
1710
++             (struct sockaddr *)&server->address, sizeof (server->address));
1711
++
1712
++      /* Retrieve the address. */
1713
++      socklen_t addrlen = sizeof (server->address);
1714
++      xgetsockname (server->socket_udp,
1715
++                    (struct sockaddr *)&server->address, &addrlen);
1716
++
1717
++      /* Bind the TCP socket to the same address.  */
1718
++      {
1719
++        int on = 1;
1720
++        xsetsockopt (server->socket_tcp, SOL_SOCKET, SO_REUSEADDR,
1721
++                     &on, sizeof (on));
1722
++      }
1723
++      if (bind (server->socket_tcp,
1724
++                (struct sockaddr *)&server->address,
1725
++                sizeof (server->address)) != 0)
1726
++        {
1727
++          /* Port collision.  The UDP bind succeeded, but the TCP BIND
1728
++             failed.  We assume here that the kernel will pick the
1729
++             next local UDP address randomly.  */
1730
++          if (errno == EADDRINUSE)
1731
++            {
1732
++              xclose (server->socket_udp);
1733
++              xclose (server->socket_tcp);
1734
++              continue;
1735
++            }
1736
++          FAIL_EXIT1 ("TCP bind: %m");
1737
++        }
1738
++      xlisten (server->socket_tcp, 5);
1739
++      break;
1740
++    }
1741
++}
1742
++
1743
++/* One-time initialization of NSS.  */
1744
++static void
1745
++resolv_redirect_once (void)
1746
++{
1747
++  /* Only use nss_dns.  */
1748
++  __nss_configure_lookup ("hosts", "dns");
1749
++  __nss_configure_lookup ("networks", "dns");
1750
++  /* Enter a network namespace for isolation and firewall state
1751
++     cleanup.  The tests will still work if these steps fail, but they
1752
++     may be less reliable.  */
1753
++  support_become_root ();
1754
++  support_enter_network_namespace ();
1755
++}
1756
++pthread_once_t resolv_redirect_once_var = PTHREAD_ONCE_INIT;
1757
++
1758
++void
1759
++resolv_test_init (void)
1760
++{
1761
++  /* Perform one-time initialization of NSS.  */
1762
++  xpthread_once (&resolv_redirect_once_var, resolv_redirect_once);
1763
++}
1764
++
1765
++/* Copy the search path from CONFIG.search to the _res object.  */
1766
++static void
1767
++set_search_path (struct resolv_redirect_config config)
1768
++{
1769
++  memset (_res.defdname, 0, sizeof (_res.defdname));
1770
++  memset (_res.dnsrch, 0, sizeof (_res.dnsrch));
1771
++
1772
++  char *current = _res.defdname;
1773
++  char *end = current + sizeof (_res.defdname);
1774
++
1775
++  for (unsigned int i = 0;
1776
++       i < sizeof (config.search) / sizeof (config.search[0]); ++i)
1777
++    {
1778
++      if (config.search[i] == NULL)
1779
++        continue;
1780
++
1781
++      size_t length = strlen (config.search[i]) + 1;
1782
++      size_t remaining = end - current;
1783
++      TEST_VERIFY_EXIT (length <= remaining);
1784
++      memcpy (current, config.search[i], length);
1785
++      _res.dnsrch[i] = current;
1786
++      current += length;
1787
++    }
1788
++}
1789
++
1790
++struct resolv_test *
1791
++resolv_test_start (struct resolv_redirect_config config)
1792
++{
1793
++  /* Apply configuration defaults.  */
1794
++  if (config.nscount == 0)
1795
++    config.nscount = resolv_max_test_servers;
1796
++
1797
++  struct resolv_test *obj = xmalloc (sizeof (*obj));
1798
++  *obj = (struct resolv_test) {
1799
++    .config = config,
1800
++    .lock = PTHREAD_MUTEX_INITIALIZER,
1801
++  };
1802
++
1803
++  resolv_test_init ();
1804
++
1805
++  /* Create all the servers, to reserve the necessary ports.  */
1806
++  for (int server_index = 0; server_index < config.nscount; ++server_index)
1807
++    make_server_sockets (obj->servers + server_index);
1808
++
1809
++  /* Start server threads.  Disable the server ports, as
1810
++     requested.  */
1811
++  for (int server_index = 0; server_index < config.nscount; ++server_index)
1812
++    {
1813
++      struct resolv_test_server *server = obj->servers + server_index;
1814
++      if (config.servers[server_index].disable_udp)
1815
++        {
1816
++          xclose (server->socket_udp);
1817
++          server->socket_udp = -1;
1818
++        }
1819
++      else if (!config.single_thread_udp)
1820
++        server->thread_udp = start_server_thread (obj, server_index,
1821
++                                                  server_thread_udp);
1822
++      if (config.servers[server_index].disable_tcp)
1823
++        {
1824
++          xclose (server->socket_tcp);
1825
++          server->socket_tcp = -1;
1826
++        }
1827
++      else
1828
++        server->thread_tcp = start_server_thread (obj, server_index,
1829
++                                                  server_thread_tcp);
1830
++    }
1831
++  if (config.single_thread_udp)
1832
++    start_server_thread_udp_single (obj);
1833
++
1834
++  int timeout = 1;
1835
++
1836
++  /* Initialize libresolv.  */
1837
++  TEST_VERIFY_EXIT (res_init () == 0);
1838
++
1839
++  /* Disable IPv6 name server addresses.  The code below only
1840
++     overrides the IPv4 addresses.  */
1841
++  __res_iclose (&_res, true);
1842
++  _res._u._ext.nscount = 0;
1843
++
1844
++  /* Redirect queries to the server socket.  */
1845
++  if (test_verbose)
1846
++    {
1847
++      printf ("info: old timeout value: %d\n", _res.retrans);
1848
++      printf ("info: old retry attempt value: %d\n", _res.retry);
1849
++      printf ("info: old _res.options: 0x%lx\n", _res.options);
1850
++      printf ("info: old _res.nscount value: %d\n", _res.nscount);
1851
++      printf ("info: old _res.ndots value: %d\n", _res.ndots);
1852
++    }
1853
++  _res.retrans = timeout;
1854
++  _res.retry = 4;
1855
++  _res.nscount = config.nscount;
1856
++  _res.options = RES_INIT | RES_RECURSE | RES_DEFNAMES | RES_DNSRCH;
1857
++  _res.ndots = 1;
1858
++  if (test_verbose)
1859
++    {
1860
++      printf ("info: new timeout value: %d\n", _res.retrans);
1861
++      printf ("info: new retry attempt value: %d\n", _res.retry);
1862
++      printf ("info: new _res.options: 0x%lx\n", _res.options);
1863
++      printf ("info: new _res.nscount value: %d\n", _res.nscount);
1864
++      printf ("info: new _res.ndots value: %d\n", _res.ndots);
1865
++    }
1866
++  for (int server_index = 0; server_index < config.nscount; ++server_index)
1867
++    {
1868
++      _res.nsaddr_list[server_index] = obj->servers[server_index].address;
1869
++      if (test_verbose)
1870
++        {
1871
++          char buf[256];
1872
++          TEST_VERIFY_EXIT
1873
++            (inet_ntop (AF_INET, &obj->servers[server_index].address.sin_addr,
1874
++                        buf, sizeof (buf)) != NULL);
1875
++          printf ("info: server %d: %s/%u\n",
1876
++                  server_index, buf,
1877
++                  htons (obj->servers[server_index].address.sin_port));
1878
++        }
1879
++    }
1880
++
1881
++  set_search_path (config);
1882
++
1883
++  return obj;
1884
++}
1885
++
1886
++void
1887
++resolv_test_end (struct resolv_test *obj)
1888
++{
1889
++  res_close ();
1890
++
1891
++  xpthread_mutex_lock (&obj->lock);
1892
++  obj->termination_requested = true;
1893
++  xpthread_mutex_unlock (&obj->lock);
1894
++
1895
++  /* Send trigger packets to unblock the server threads.  */
1896
++  for (int server_index = 0; server_index < obj->config.nscount;
1897
++       ++server_index)
1898
++    {
1899
++      if (!obj->config.servers[server_index].disable_udp)
1900
++        {
1901
++          int sock = xsocket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1902
++          xsendto (sock, "", 1, 0,
1903
++                   (struct sockaddr *) &obj->servers[server_index].address,
1904
++                   sizeof (obj->servers[server_index].address));
1905
++          xclose (sock);
1906
++        }
1907
++      if (!obj->config.servers[server_index].disable_tcp)
1908
++        {
1909
++          int sock = xsocket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
1910
++          xconnect (sock,
1911
++                    (struct sockaddr *) &obj->servers[server_index].address,
1912
++                    sizeof (obj->servers[server_index].address));
1913
++          xclose (sock);
1914
++        }
1915
++    }
1916
++
1917
++  if (obj->config.single_thread_udp)
1918
++    xpthread_join (obj->thread_udp_single);
1919
++
1920
++  /* Wait for the server threads to terminate.  */
1921
++  for (int server_index = 0; server_index < obj->config.nscount;
1922
++       ++server_index)
1923
++    {
1924
++      if (!obj->config.servers[server_index].disable_udp)
1925
++        {
1926
++          if (!obj->config.single_thread_udp)
1927
++            xpthread_join (obj->servers[server_index].thread_udp);
1928
++          xclose (obj->servers[server_index].socket_udp);
1929
++        }
1930
++      if (!obj->config.servers[server_index].disable_tcp)
1931
++        {
1932
++          xpthread_join (obj->servers[server_index].thread_tcp);
1933
++          xclose (obj->servers[server_index].socket_tcp);
1934
++        }
1935
++    }
1936
++
1937
++  free (obj);
1938
++}
1939
+diff --git a/support/resolv_test.h b/support/resolv_test.h
1940
+new file mode 100644
1941
+index 7a9f1f7..6498751
1942
+--- /dev/null
1943
+@@ -0,0 +1,180 @@
1944
++/* DNS test framework and libresolv redirection.
1945
++   Copyright (C) 2016-2017 Free Software Foundation, Inc.
1946
++   This file is part of the GNU C Library.
1947
++
1948
++   The GNU C Library is free software; you can redistribute it and/or
1949
++   modify it under the terms of the GNU Lesser General Public
1950
++   License as published by the Free Software Foundation; either
1951
++   version 2.1 of the License, or (at your option) any later version.
1952
++
1953
++   The GNU C Library is distributed in the hope that it will be useful,
1954
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
1955
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1956
++   Lesser General Public License for more details.
1957
++
1958
++   You should have received a copy of the GNU Lesser General Public
1959
++   License along with the GNU C Library; if not, see
1960
++   <http://www.gnu.org/licenses/>.  */
1961
++
1962
++#ifndef SUPPORT_RESOLV_TEST_H
1963
++#define SUPPORT_RESOLV_TEST_H
1964
++
1965
++#include <arpa/nameser.h>
1966
++#include <stdbool.h>
1967
++#include <sys/cdefs.h>
1968
++
1969
++__BEGIN_DECLS
1970
++
1971
++/* Information about EDNS properties of a DNS query.  */
1972
++struct resolv_edns_info
1973
++{
1974
++  bool active;
1975
++  uint8_t extended_rcode;
1976
++  uint8_t version;
1977
++  uint16_t flags;
1978
++  uint16_t payload_size;
1979
++};
1980
++
1981
++/* This struct provides context information when the response callback
1982
++   specified in struct resolv_redirect_config is invoked. */
1983
++struct resolv_response_context
1984
++{
1985
++  const unsigned char *query_buffer;
1986
++  size_t query_length;
1987
++  int server_index;
1988
++  bool tcp;
1989
++  struct resolv_edns_info edns;
1990
++};
1991
++
1992
++/* This opaque struct is used to construct responses from within the
1993
++   response callback function.  */
1994
++struct resolv_response_builder;
1995
++
1996
++/* This opaque struct collects information about the resolver testing
1997
++   currently in progress.  */
1998
++struct resolv_test;
1999
++
2000
++enum
2001
++  {
2002
++    /* Maximum number of test servers supported by the framework.  */
2003
++    resolv_max_test_servers = 3,
2004
++  };
2005
++
2006
++/* Configuration settings specific to individual test servers.  */
2007
++struct resolv_redirect_server_config
2008
++{
2009
++  bool disable_tcp;             /* If true, no TCP server is listening.  */
2010
++  bool disable_udp;             /* If true, no UDP server is listening.  */
2011
++};
2012
++
2013
++/* Instructions for setting up the libresolv redirection.  */
2014
++struct resolv_redirect_config
2015
++{
2016
++  /* The response_callback function is called for every incoming DNS
2017
++     packet, over UDP or TCP.  It must be specified, the other
2018
++     configuration settings are optional.  */
2019
++  void (*response_callback) (const struct resolv_response_context *,
2020
++                             struct resolv_response_builder *,
2021
++                             const char *qname,
2022
++                             uint16_t qclass, uint16_t qtype);
2023
++
2024
++  /* Per-server configuration.  */
2025
++  struct resolv_redirect_server_config servers[resolv_max_test_servers];
2026
++
2027
++  /* Search path entries.  The first entry serves as the default
2028
++     domain name as well.  */
2029
++  const char *search[7];
2030
++
2031
++  /* Number of servers to activate in resolv.  0 means the default,
2032
++     resolv_max_test_servers.  */
2033
++  int nscount;
2034
++
2035
++  /* If true, use a single thread to process all UDP queries.  This
2036
++     may results in more predictable ordering of queries and
2037
++     responses.  */
2038
++  bool single_thread_udp;
2039
++};
2040
++
2041
++/* Configure NSS to use, nss_dns only for aplicable databases, and try
2042
++   to put the process into a network namespace for better isolation.
2043
++   This may have to be called before resolv_test_start, before the
2044
++   process creates any threads.  Otherwise, initialization is
2045
++   performed by resolv_test_start implicitly.  */
2046
++void resolv_test_init (void);
2047
++
2048
++/* Initiate resolver testing.  This updates the _res variable as
2049
++   needed.  As a side effect, NSS is reconfigured to use nss_dns only
2050
++   for aplicable databases, and the process may enter a network
2051
++   namespace for better isolation.  */
2052
++struct resolv_test *resolv_test_start (struct resolv_redirect_config);
2053
++
2054
++/* Call this function at the end of resolver testing, to free
2055
++   resources and report pending errors (if any).  */
2056
++void resolv_test_end (struct resolv_test *);
2057
++
2058
++/* The remaining facilities in this file are used for constructing
2059
++   response packets from the response_callback function.  */
2060
++
2061
++/* Special settings for constructing responses from the callback.  */
2062
++struct resolv_response_flags
2063
++{
2064
++  /* 4-bit response code to incorporate into the response. */
2065
++  unsigned char rcode;
2066
++
2067
++  /* If true, the TC (truncation) flag will be set.  */
2068
++  bool tc;
2069
++
2070
++  /* Initial section count values.  Can be used to artificially
2071
++     increase the counts, for malformed packet testing.*/
2072
++  unsigned short qdcount;
2073
++  unsigned short ancount;
2074
++  unsigned short nscount;
2075
++  unsigned short adcount;
2076
++};
2077
++
2078
++/* Begin a new response with the requested flags.  Must be called
2079
++   first.  */
2080
++void resolv_response_init (struct resolv_response_builder *,
2081
++                           struct resolv_response_flags);
2082
++
2083
++/* Switches to the section in the response packet.  Only forward
2084
++   movement is supported.  */
2085
++void resolv_response_section (struct resolv_response_builder *, ns_sect);
2086
++
2087
++/* Add a question record to the question section.  */
2088
++void resolv_response_add_question (struct resolv_response_builder *,
2089
++                                   const char *name, uint16_t class,
2090
++                                   uint16_t type);
2091
++/* Starts a new resource record with the specified owner name, class,
2092
++   type, and TTL.  Data is supplied with resolv_response_add_data or
2093
++   resolv_response_add_name.  */
2094
++void resolv_response_open_record (struct resolv_response_builder *,
2095
++                                  const char *name, uint16_t class,
2096
++                                  uint16_t type, uint32_t ttl);
2097
++
2098
++/* Add unstructed bytes to the RDATA part of a resource record.  */
2099
++void resolv_response_add_data (struct resolv_response_builder *,
2100
++                               const void *, size_t);
2101
++
2102
++/* Add a compressed domain name to the RDATA part of a resource
2103
++   record.  */
2104
++void resolv_response_add_name (struct resolv_response_builder *,
2105
++                               const char *name);
2106
++
2107
++/* Mark the end of the constructed record.  Must be called last.  */
2108
++void resolv_response_close_record (struct resolv_response_builder *);
2109
++
2110
++/* Drop this query packet (that is, do not send a response, not even
2111
++   an empty packet).  */
2112
++void resolv_response_drop (struct resolv_response_builder *);
2113
++
2114
++/* In TCP mode, close the connection after this packet (if a response
2115
++   is sent).  */
2116
++void resolv_response_close (struct resolv_response_builder *);
2117
++
2118
++/* The size of the response packet built so far.  */
2119
++size_t resolv_response_length (const struct resolv_response_builder *);
2120
++
2121
++__END_DECLS
2122
++
2123
++#endif /* SUPPORT_RESOLV_TEST_H */
2124
+-- 
2125
+2.9.3
... ...
@@ -6,7 +6,7 @@
6 6
 Summary:        Main C library
7 7
 Name:           glibc
8 8
 Version:        2.22
9
-Release:        22%{?dist}
9
+Release:        23%{?dist}
10 10
 License:        LGPLv2+
11 11
 URL:            http://www.gnu.org/software/libc
12 12
 Group:          Applications/System
... ...
@@ -51,6 +51,7 @@ Patch23:        glibc-fix-CVE-2018-6485.patch
51 51
 Patch24:        glibc-fix-CVE-2017-18269.patch
52 52
 Patch25:        glibc-fix-CVE-2018-11236.patch
53 53
 Patch26:        glibc-fix-CVE-2017-15671.patch
54
+Patch27:        glibc-fix-CVE-2017-12132.patch
54 55
 Provides:       rtld(GNU_HASH)
55 56
 Requires:       filesystem
56 57
 %description
... ...
@@ -103,6 +104,7 @@ sed -i 's/\\$$(pwd)/`pwd`/' timezone/Makefile
103 103
 %patch24 -p1
104 104
 %patch25 -p1
105 105
 %patch26 -p1
106
+%patch27 -p1
106 107
 
107 108
 install -vdm 755 %{_builddir}/%{name}-build
108 109
 # do not try to explicitly provide GLIBC_PRIVATE versioned libraries
... ...
@@ -230,6 +232,8 @@ popd
230 230
 %{_datarootdir}/locale/locale.alias
231 231
 
232 232
 %changelog
233
+*   Tue Jan 29 2019 Keerthana K <keerthanak@vmware.com> 2.22-23
234
+-   Fix for CVE-2017-12132.
233 235
 *   Thu Aug 09 2018 Keerthana K <keerthanak@vmware.com> 2.22-22
234 236
 -   Fix for CVE-2017-15761.
235 237
 *   Tue Jun 26 2018 Keerthana K <keerthnanak@vmware.com> 2.22-21