1 /* Test the behavior of the trust-ad option.
2    Copyright (C) 2019-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 <resolv.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <support/check.h>
23 #include <support/check_nss.h>
24 #include <support/resolv_test.h>
25 #include <support/support.h>
26 
27 /* This controls properties of the response.  volatile because
28    __res_send is incorrectly declared as __THROW.  */
29 static volatile unsigned char response_number;
30 static volatile bool response_ad_bit;
31 static volatile bool query_ad_bit;
32 
33 static void
response(const struct resolv_response_context * ctx,struct resolv_response_builder * b,const char * qname,uint16_t qclass,uint16_t qtype)34 response (const struct resolv_response_context *ctx,
35           struct resolv_response_builder *b,
36           const char *qname, uint16_t qclass, uint16_t qtype)
37 {
38   TEST_COMPARE (qclass, C_IN);
39   TEST_COMPARE (qtype, T_A);
40   TEST_COMPARE_STRING (qname, "www.example");
41 
42   HEADER header;
43   memcpy (&header, ctx->query_buffer, sizeof (header));
44   TEST_COMPARE (header.ad, query_ad_bit);
45 
46   struct resolv_response_flags flags = { .ad = response_ad_bit, };
47   resolv_response_init (b, flags);
48   resolv_response_add_question (b, qname, qclass, qtype);
49   resolv_response_section (b, ns_s_an);
50   resolv_response_open_record (b, qname, qclass, T_A, 0x12345678);
51   char addr[4] = { 192, 0, 2, response_number };
52   resolv_response_add_data (b, addr, sizeof (addr));
53   resolv_response_close_record (b);
54 }
55 
56 static void
check_answer(const unsigned char * buffer,size_t buffer_length,bool expected_ad)57 check_answer (const unsigned char *buffer, size_t buffer_length,
58               bool expected_ad)
59 {
60   HEADER header;
61   TEST_VERIFY (buffer_length > sizeof (header));
62   memcpy (&header, buffer, sizeof (header));
63   TEST_COMPARE (0, header.aa);
64   TEST_COMPARE (expected_ad, header.ad);
65   TEST_COMPARE (0, header.opcode);
66   TEST_COMPARE (1, header.qr);
67   TEST_COMPARE (0, header.rcode);
68   TEST_COMPARE (1, header.rd);
69   TEST_COMPARE (0, header.tc);
70   TEST_COMPARE (1, ntohs (header.qdcount));
71   TEST_COMPARE (1, ntohs (header.ancount));
72   TEST_COMPARE (0, ntohs (header.nscount));
73   TEST_COMPARE (0, ntohs (header.arcount));
74 
75   char *description = xasprintf ("response=%d ad=%d",
76                                  response_number, expected_ad);
77   char *expected = xasprintf ("name: www.example\n"
78                               "address: 192.0.2.%d\n", response_number);
79   check_dns_packet (description, buffer, buffer_length, expected);
80   free (expected);
81   free (description);
82 }
83 
84 static int
do_test(void)85 do_test (void)
86 {
87   struct resolv_test *aux = resolv_test_start
88     ((struct resolv_redirect_config)
89      {
90        .response_callback = response,
91      });
92 
93   /* By default, the resolver is not trusted, and the AD bit is
94      cleared.  */
95 
96   static const unsigned char hand_crafted_query[] =
97     {
98      10, 11,                    /* Transaction ID.  */
99      1, 0x20,                   /* Query with RD, AD flags.  */
100      0, 1,                      /* One question.  */
101      0, 0, 0, 0, 0, 0,          /* The other sections are empty.  */
102      3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0,
103      0, T_A,                    /* A query.  */
104      0, 1,                      /* Class IN.  */
105     };
106 
107   ++response_number;
108   response_ad_bit = false;
109 
110   unsigned char buffer[512];
111   memset (buffer, 255, sizeof (buffer));
112   query_ad_bit = true;
113   int ret = res_send (hand_crafted_query, sizeof (hand_crafted_query),
114                       buffer, sizeof (buffer));
115   TEST_VERIFY (ret > 0);
116   check_answer (buffer, ret, false);
117 
118   ++response_number;
119   memset (buffer, 255, sizeof (buffer));
120   query_ad_bit = false;
121   ret = res_query ("www.example", C_IN, T_A, buffer, sizeof (buffer));
122   TEST_VERIFY (ret > 0);
123   check_answer (buffer, ret, false);
124   response_ad_bit = true;
125 
126   response_ad_bit = true;
127 
128   ++response_number;
129   query_ad_bit = true;
130   ret = res_send (hand_crafted_query, sizeof (hand_crafted_query),
131                   buffer, sizeof (buffer));
132   TEST_VERIFY (ret > 0);
133   check_answer (buffer, ret, false);
134 
135   ++response_number;
136   memset (buffer, 255, sizeof (buffer));
137   query_ad_bit = false;
138   ret = res_query ("www.example", C_IN, T_A, buffer, sizeof (buffer));
139   TEST_VERIFY (ret > 0);
140   check_answer (buffer, ret, false);
141 
142   /* No AD bit set in generated queries.  */
143   memset (buffer, 255, sizeof (buffer));
144   ret = res_mkquery (QUERY, "www.example", C_IN, T_A,
145                      (const unsigned char *) "", 0, NULL,
146                      buffer, sizeof (buffer));
147   HEADER header;
148   memcpy (&header, buffer, sizeof (header));
149   TEST_VERIFY (!header.ad);
150 
151   /* With RES_TRUSTAD, the AD bit is passed through if it set in the
152      response.  It is also included in queries.  */
153 
154   _res.options |= RES_TRUSTAD;
155   query_ad_bit = true;
156 
157   response_ad_bit = false;
158 
159   ++response_number;
160   memset (buffer, 255, sizeof (buffer));
161   ret = res_send (hand_crafted_query, sizeof (hand_crafted_query),
162                   buffer, sizeof (buffer));
163   TEST_VERIFY (ret > 0);
164   check_answer (buffer, ret, false);
165 
166   ++response_number;
167   memset (buffer, 255, sizeof (buffer));
168   ret = res_query ("www.example", C_IN, T_A, buffer, sizeof (buffer));
169   TEST_VERIFY (ret > 0);
170   check_answer (buffer, ret, false);
171 
172   response_ad_bit = true;
173 
174   ++response_number;
175   memset (buffer, 0, sizeof (buffer));
176   ret = res_send (hand_crafted_query, sizeof (hand_crafted_query),
177                   buffer, sizeof (buffer));
178   TEST_VERIFY (ret > 0);
179   check_answer (buffer, ret, true);
180 
181   ++response_number;
182   memset (buffer, 0, sizeof (buffer));
183   ret = res_query ("www.example", C_IN, T_A, buffer, sizeof (buffer));
184   TEST_VERIFY (ret > 0);
185   check_answer (buffer, ret, true);
186 
187   /* AD bit set in generated queries.  */
188   memset (buffer, 0, sizeof (buffer));
189   ret = res_mkquery (QUERY, "www.example", C_IN, T_A,
190                      (const unsigned char *) "", 0, NULL,
191                      buffer, sizeof (buffer));
192   memcpy (&header, buffer, sizeof (header));
193   TEST_VERIFY (header.ad);
194 
195   resolv_test_end (aux);
196 
197   return 0;
198 }
199 
200 #include <support/test-driver.c>
201