summaryrefslogtreecommitdiffstats
path: root/main/gdnsd/0001-Fix-auth-section-of-ANY-query-on-CNAME.patch
blob: fb703b352d7ee3645793bd3b69bd5cd99d0bb809 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
From 22b0dcf8a19aaeb1e6f32ad9f0aad95ab26b8a61 Mon Sep 17 00:00:00 2001
From: Brandon Black <blblack@gmail.com>
Date: Thu, 11 Jul 2013 14:37:57 -0500
Subject: [PATCH] Fix auth section of ANY-query on CNAME

Queries with QTYPE=ANY for a name which has a CNAME RR
  should be treated as if QTYPE=CNAME.  Prior to this
  fix, they were being treated more like QTYPE=A.  Given
  it's QTYPE=ANY and the effects seem to be limited to
  the auth section, I doubt this is a production concern
  for anyone, but it's good to be correct.

Fixes Issue #51 (thanks Timo!)
---
 gdnsd/dnspacket.c            |  11 ++-
 t/012cname/001cname.t        | 157 +++++++++++++++++++++++++++++++++++++++++++
 t/012cname/gdnsd.conf        |  11 +++
 t/012cname/zones/example.com |  24 +++++++
 4 files changed, 201 insertions(+), 2 deletions(-)
 create mode 100644 t/012cname/001cname.t
 create mode 100644 t/012cname/gdnsd.conf
 create mode 100644 t/012cname/zones/example.com

diff --git a/gdnsd/dnspacket.c b/gdnsd/dnspacket.c
index 3c26d83..db7e26a 100644
--- a/gdnsd/dnspacket.c
+++ b/gdnsd/dnspacket.c
@@ -1190,6 +1190,9 @@ static unsigned int encode_rrs_any(dnspacket_context_t* c, unsigned int offset,
             case DNS_TYPE_SOA:
                 offset = encode_rr_soa(c, offset, (const void*)rrset, true);
                 break;
+            case DNS_TYPE_CNAME:
+                offset = encode_rr_cname(c, offset, (const void*)rrset, true);
+                break;
             case DNS_TYPE_NS:
                 offset = encode_rrs_ns(c, offset, (const void*)rrset, true);
                 break;
@@ -1659,8 +1662,12 @@ static unsigned int answer_from_db(dnspacket_context_t* c, const uint8_t* qname,
         //  for the normal response handling code below.  The explicit check of the first
         //  rrsets entry works because if CNAME exists at all, by definition it is the only
         //  type of rrset at this node.
-        while(resdom && resdom->rrsets
-            && resdom->rrsets->gen.type == DNS_TYPE_CNAME && c->qtype != DNS_TYPE_CNAME) {
+        while(resdom
+            && resdom->rrsets
+            && resdom->rrsets->gen.type == DNS_TYPE_CNAME
+            && c->qtype != DNS_TYPE_CNAME
+            && c->qtype != DNS_TYPE_ANY) {
+
             dmn_assert(status == DNAME_AUTH);
 
             res_hdr->flags1 |= 4; // AA bit
diff --git a/t/012cname/001cname.t b/t/012cname/001cname.t
new file mode 100644
index 0000000..6e96335
--- /dev/null
+++ b/t/012cname/001cname.t
@@ -0,0 +1,157 @@
+
+# CNAME test, with include_optional_ns to get the auth section right...
+# this is basically going through A, CNAME, and ANY queries against
+#  five different classes of CNAME targets (local nonexistent,
+#  local existent, delegation, delegation glue record, and external).
+# CNAME and ANY responses should be identical (this was the bug that
+#  triggered writing these testcases - ANY was being treated more like A).
+
+use _GDT ();
+use FindBin ();
+use File::Spec ();
+use Test::More tests => 17;
+
+my $standard_soa = 'example.com 21600 SOA ns1.example.com hmaster.example.net 1 7200 1800 259200 900';
+
+my $pid = _GDT->test_spawn_daemon(File::Spec->catfile($FindBin::Bin, 'gdnsd.conf'));
+
+_GDT->test_dns(
+    qname => 'cn-nx.example.com', qtype => 'A',
+    header => { rcode => 'NXDOMAIN' },
+    answer => 'cn-nx.example.com 21600 CNAME nx.example.com',
+    auth => $standard_soa,
+    stats => [qw/udp_reqs nxdomain/],
+);
+
+foreach my $qt (qw/CNAME ANY/) {
+    _GDT->test_dns(
+        qname => 'cn-nx.example.com', qtype => $qt,
+        answer => 'cn-nx.example.com 21600 CNAME nx.example.com',
+        auth => [
+	    'example.com 21600 NS ns1.example.com',
+	    'example.com 21600 NS ns2.example.com',
+        ],
+        addtl => [
+            'ns1.example.com 21600 A 192.0.2.1',
+            'ns2.example.com 21600 A 192.0.2.2',
+        ],
+    );
+}
+
+_GDT->test_dns(
+    qname => 'cn-local.example.com', qtype => 'A',
+    answer => [
+        'cn-local.example.com 21600 CNAME ns1.example.com',
+        'ns1.example.com 21600 A 192.0.2.1',
+    ],
+    auth => [
+	'example.com 21600 NS ns1.example.com',
+	'example.com 21600 NS ns2.example.com',
+    ],
+    addtl => [
+        'ns2.example.com 21600 A 192.0.2.2',
+    ],
+);
+
+foreach my $qt (qw/CNAME ANY/) {
+    _GDT->test_dns(
+        qname => 'cn-local.example.com', qtype => $qt,
+        answer => [
+            'cn-local.example.com 21600 CNAME ns1.example.com'
+        ],
+        auth => [
+	    'example.com 21600 NS ns1.example.com',
+	    'example.com 21600 NS ns2.example.com',
+        ],
+        addtl => [
+            'ns1.example.com 21600 A 192.0.2.1',
+            'ns2.example.com 21600 A 192.0.2.2',
+        ],
+    );
+}
+
+_GDT->test_dns(
+    qname => 'cn-deleg.example.com', qtype => 'A',
+    answer => [
+        'cn-deleg.example.com 21600 CNAME foo.subz.example.com',
+    ],
+    auth => [
+	'subz.example.com 21600 NS ns1.subz.example.com',
+	'subz.example.com 21600 NS ns2.subz.example.com',
+    ],
+    addtl => [
+        'ns1.subz.example.com 21600 A 192.0.2.10',
+        'ns2.subz.example.com 21600 A 192.0.2.20',
+    ],
+);
+
+foreach my $qt (qw/CNAME ANY/) {
+    _GDT->test_dns(
+        qname => 'cn-deleg.example.com', qtype => $qt,
+        answer => [
+            'cn-deleg.example.com 21600 CNAME foo.subz.example.com',
+        ],
+        auth => [
+	    'example.com 21600 NS ns1.example.com',
+	    'example.com 21600 NS ns2.example.com',
+        ],
+        addtl => [
+            'ns1.example.com 21600 A 192.0.2.1',
+            'ns2.example.com 21600 A 192.0.2.2',
+        ],
+    );
+}
+
+_GDT->test_dns(
+    qname => 'cn-deleg-glue.example.com', qtype => 'A',
+    answer => [
+        'cn-deleg-glue.example.com 21600 CNAME ns1.subz.example.com',
+    ],
+    auth => [
+	'subz.example.com 21600 NS ns1.subz.example.com',
+	'subz.example.com 21600 NS ns2.subz.example.com',
+    ],
+    addtl => [
+        'ns1.subz.example.com 21600 A 192.0.2.10',
+        'ns2.subz.example.com 21600 A 192.0.2.20',
+    ],
+);
+
+foreach my $qt (qw/CNAME ANY/) {
+    _GDT->test_dns(
+        qname => 'cn-deleg-glue.example.com', qtype => $qt,
+        answer => [
+            'cn-deleg-glue.example.com 21600 CNAME ns1.subz.example.com',
+        ],
+        auth => [
+	    'example.com 21600 NS ns1.example.com',
+	    'example.com 21600 NS ns2.example.com',
+        ],
+        addtl => [
+            'ns1.example.com 21600 A 192.0.2.1',
+            'ns2.example.com 21600 A 192.0.2.2',
+        ],
+    );
+}
+
+_GDT->test_dns(
+    qname => 'cn-ext.example.com', qtype => 'A',
+    answer => 'cn-ext.example.com 21600 CNAME www.example.net',
+);
+
+foreach my $qt (qw/CNAME ANY/) {
+    _GDT->test_dns(
+        qname => 'cn-ext.example.com', qtype => $qt,
+        answer => 'cn-ext.example.com 21600 CNAME www.example.net',
+        auth => [
+	    'example.com 21600 NS ns1.example.com',
+	    'example.com 21600 NS ns2.example.com',
+        ],
+        addtl => [
+            'ns1.example.com 21600 A 192.0.2.1',
+            'ns2.example.com 21600 A 192.0.2.2',
+        ],
+    );
+}
+
+_GDT->test_kill_daemon($pid);
diff --git a/t/012cname/gdnsd.conf b/t/012cname/gdnsd.conf
new file mode 100644
index 0000000..2bc6c92
--- /dev/null
+++ b/t/012cname/gdnsd.conf
@@ -0,0 +1,11 @@
+options => {
+  listen => @dns_lspec@
+  http_listen => @http_lspec@
+  dns_port => @dns_port@
+  http_port => @http_port@
+  zones_default_ttl = 21600
+  realtime_stats = true
+  max_response = 62464
+  chaos_response = "some random string"
+  include_optional_ns = true
+}
diff --git a/t/012cname/zones/example.com b/t/012cname/zones/example.com
new file mode 100644
index 0000000..94a452f
--- /dev/null
+++ b/t/012cname/zones/example.com
@@ -0,0 +1,24 @@
+
+@	SOA ns1 hmaster.example.net. (
+	1      ; serial
+	7200   ; refresh
+	1800   ; retry
+	259200 ; expire
+        900    ; ncache
+)
+
+@		NS	ns1
+@		NS	ns2
+ns1		A	192.0.2.1
+ns2		A	192.0.2.2
+
+subz		NS	ns1.subz
+subz		NS	ns2.subz
+ns1.subz	A	192.0.2.10
+ns2.subz	A	192.0.2.20
+
+cn-nx		CNAME	nx
+cn-local	CNAME	ns1
+cn-deleg	CNAME	foo.subz
+cn-deleg-glue	CNAME	ns1.subz
+cn-ext		CNAME	www.example.net.
-- 
1.8.3.2