]>
Commit | Line | Data |
---|---|---|
c3b4c861 MF |
1 | From fa14bec83b2db010fd076910fddab56957b9375d Mon Sep 17 00:00:00 2001 |
2 | From: Simon Kelley <simon@thekelleys.org.uk> | |
3 | Date: Sun, 20 Dec 2015 17:12:16 +0000 | |
4 | Subject: [PATCH] Major tidy up of EDNS0 handling and computation/use of udp | |
5 | packet size. | |
6 | ||
7 | --- | |
8 | src/auth.c | 8 ++- | |
9 | src/dnsmasq.h | 7 ++- | |
10 | src/dnssec.c | 1 - | |
11 | src/forward.c | 184 ++++++++++++++++++++++++++++++++++++++++---------------- | |
12 | src/netlink.c | 3 +- | |
13 | src/rfc1035.c | 81 +++++++------------------ | |
14 | src/rrfilter.c | 2 +- | |
15 | 7 files changed, 168 insertions(+), 118 deletions(-) | |
16 | ||
17 | diff --git a/src/auth.c b/src/auth.c | |
18 | index 2b0b7d6..85bd5e7 100644 | |
19 | --- a/src/auth.c | |
20 | +++ b/src/auth.c | |
21 | @@ -81,7 +81,8 @@ int in_zone(struct auth_zone *zone, char *name, char **cut) | |
22 | } | |
23 | ||
24 | ||
25 | -size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr, int local_query) | |
26 | +size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr, | |
27 | + int local_query, int do_bit, int have_pseudoheader) | |
28 | { | |
29 | char *name = daemon->namebuff; | |
30 | unsigned char *p, *ansp; | |
31 | @@ -820,6 +821,11 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n | |
32 | header->ancount = htons(anscount); | |
33 | header->nscount = htons(authcount); | |
34 | header->arcount = htons(0); | |
35 | + | |
36 | + /* Advertise our packet size limit in our reply */ | |
37 | + if (have_pseudoheader) | |
38 | + return add_pseudoheader(header, ansp - (unsigned char *)header, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit); | |
39 | + | |
40 | return ansp - (unsigned char *)header; | |
41 | } | |
42 | ||
43 | diff --git a/src/dnsmasq.h b/src/dnsmasq.h | |
44 | index 39a930c..abb34c5 100644 | |
45 | --- a/src/dnsmasq.h | |
46 | +++ b/src/dnsmasq.h | |
47 | @@ -1113,7 +1113,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *namebuff, | |
48 | int no_cache, int secure, int *doctored); | |
49 | size_t answer_request(struct dns_header *header, char *limit, size_t qlen, | |
50 | struct in_addr local_addr, struct in_addr local_netmask, | |
51 | - time_t now, int *ad_reqd, int *do_bit); | |
52 | + time_t now, int ad_reqd, int do_bit, int have_pseudoheader); | |
53 | int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name, | |
54 | struct bogus_addr *addr, time_t now); | |
55 | int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr); | |
56 | @@ -1123,6 +1123,8 @@ int check_for_local_domain(char *name, time_t now); | |
57 | unsigned int questions_crc(struct dns_header *header, size_t plen, char *buff); | |
58 | size_t resize_packet(struct dns_header *header, size_t plen, | |
59 | unsigned char *pheader, size_t hlen); | |
60 | +size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit, | |
61 | + unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do); | |
62 | size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3); | |
63 | size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source); | |
64 | #ifdef HAVE_DNSSEC | |
65 | @@ -1141,7 +1143,8 @@ int private_net(struct in_addr addr, int ban_localhost); | |
66 | /* auth.c */ | |
67 | #ifdef HAVE_AUTH | |
68 | size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, | |
69 | - time_t now, union mysockaddr *peer_addr, int local_query); | |
70 | + time_t now, union mysockaddr *peer_addr, int local_query, | |
71 | + int do_bit, int have_pseudoheader); | |
72 | int in_zone(struct auth_zone *zone, char *name, char **cut); | |
73 | #endif | |
74 | ||
75 | diff --git a/src/dnssec.c b/src/dnssec.c | |
76 | index 82394ee..299ca64 100644 | |
77 | --- a/src/dnssec.c | |
78 | +++ b/src/dnssec.c | |
79 | @@ -67,7 +67,6 @@ static char *algo_digest_name(int algo) | |
80 | case 12: return "gosthash94"; | |
81 | case 13: return "sha256"; | |
82 | case 14: return "sha384"; | |
83 | - | |
84 | default: return NULL; | |
85 | } | |
86 | } | |
87 | diff --git a/src/forward.c b/src/forward.c | |
88 | index 3e801c8..041353c 100644 | |
89 | --- a/src/forward.c | |
90 | +++ b/src/forward.c | |
91 | @@ -244,7 +244,6 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, | |
92 | void *hash = &crc; | |
93 | #endif | |
94 | unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL); | |
95 | - unsigned char *pheader; | |
96 | ||
97 | (void)do_bit; | |
98 | ||
99 | @@ -264,7 +263,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, | |
100 | there's no point retrying the query, retry the key query instead...... */ | |
101 | if (forward->blocking_query) | |
102 | { | |
103 | - int fd; | |
104 | + int fd, is_sign; | |
105 | + unsigned char *pheader; | |
106 | ||
107 | forward->flags &= ~FREC_TEST_PKTSZ; | |
108 | ||
109 | @@ -276,8 +276,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, | |
110 | blockdata_retrieve(forward->stash, forward->stash_len, (void *)header); | |
111 | plen = forward->stash_len; | |
112 | ||
113 | - if (find_pseudoheader(header, plen, NULL, &pheader, NULL)) | |
114 | - PUTSHORT((forward->flags & FREC_TEST_PKTSZ) ? SAFE_PKTSZ : forward->sentto->edns_pktsz, pheader); | |
115 | + if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign) && !is_sign) | |
116 | + PUTSHORT(SAFE_PKTSZ, pheader); | |
117 | ||
118 | if (forward->sentto->addr.sa.sa_family == AF_INET) | |
119 | log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, "retry", (struct all_addr *)&forward->sentto->addr.in.sin_addr, "dnssec"); | |
120 | @@ -394,32 +394,40 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, | |
121 | forward->log_id = daemon->log_id; | |
122 | ||
123 | if (option_bool(OPT_ADD_MAC)) | |
124 | - plen = add_mac(header, plen, ((char *) header) + daemon->packet_buff_sz, &forward->source); | |
125 | - | |
126 | + { | |
127 | + size_t new = add_mac(header, plen, ((char *) header) + daemon->packet_buff_sz, &forward->source); | |
128 | + if (new != plen) | |
129 | + { | |
130 | + plen = new; | |
131 | + forward->flags |= FREC_ADDED_PHEADER; | |
132 | + } | |
133 | + } | |
134 | + | |
135 | if (option_bool(OPT_CLIENT_SUBNET)) | |
136 | { | |
137 | size_t new = add_source_addr(header, plen, ((char *) header) + daemon->packet_buff_sz, &forward->source); | |
138 | if (new != plen) | |
139 | { | |
140 | plen = new; | |
141 | - forward->flags |= FREC_HAS_SUBNET; | |
142 | + forward->flags |= FREC_HAS_SUBNET | FREC_ADDED_PHEADER; | |
143 | } | |
144 | } | |
145 | ||
146 | #ifdef HAVE_DNSSEC | |
147 | if (option_bool(OPT_DNSSEC_VALID)) | |
148 | { | |
149 | - size_t new_plen = add_do_bit(header, plen, ((char *) header) + daemon->packet_buff_sz); | |
150 | + size_t new = add_do_bit(header, plen, ((char *) header) + daemon->packet_buff_sz); | |
151 | ||
152 | + if (new != plen) | |
153 | + forward->flags |= FREC_ADDED_PHEADER; | |
154 | + | |
155 | + plen = new; | |
156 | + | |
157 | /* For debugging, set Checking Disabled, otherwise, have the upstream check too, | |
158 | this allows it to select auth servers when one is returning bad data. */ | |
159 | if (option_bool(OPT_DNSSEC_DEBUG)) | |
160 | header->hb4 |= HB4_CD; | |
161 | ||
162 | - if (new_plen != plen) | |
163 | - forward->flags |= FREC_ADDED_PHEADER; | |
164 | - | |
165 | - plen = new_plen; | |
166 | } | |
167 | #endif | |
168 | ||
169 | @@ -469,10 +477,23 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, | |
170 | } | |
171 | #endif | |
172 | } | |
173 | - | |
174 | - if (find_pseudoheader(header, plen, NULL, &pheader, NULL)) | |
175 | - PUTSHORT((forward->flags & FREC_TEST_PKTSZ) ? SAFE_PKTSZ : start->edns_pktsz, pheader); | |
176 | ||
177 | +#ifdef HAVE_DNSSEC | |
178 | + if (option_bool(OPT_DNSSEC_VALID) && !do_bit) | |
179 | + { | |
180 | + /* Difficult one here. If our client didn't send EDNS0, we will have set the UDP | |
181 | + packet size to 512. But that won't provide space for the RRSIGS in many cases. | |
182 | + The RRSIGS will be stripped out before the answer goes back, so the packet should | |
183 | + shrink again. So, if we added a do-bit, bump the udp packet size to the value | |
184 | + known to be OK for this server. Maybe check returned size after stripping and set | |
185 | + the truncated bit? */ | |
186 | + unsigned char *pheader; | |
187 | + int is_sign; | |
188 | + if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign)) | |
189 | + PUTSHORT(start->edns_pktsz, pheader); | |
190 | + } | |
191 | +#endif | |
192 | + | |
193 | if (retry_send(sendto(fd, (char *)header, plen, 0, | |
194 | &start->addr.sa, | |
195 | sa_len(&start->addr)))) | |
196 | @@ -563,30 +584,34 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server | |
197 | } | |
198 | #endif | |
199 | ||
200 | - /* If upstream is advertising a larger UDP packet size | |
201 | - than we allow, trim it so that we don't get overlarge | |
202 | - requests for the client. We can't do this for signed packets. */ | |
203 | - | |
204 | if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign))) | |
205 | { | |
206 | - unsigned short udpsz; | |
207 | - unsigned char *psave = sizep; | |
208 | - | |
209 | - GETSHORT(udpsz, sizep); | |
210 | - | |
211 | - if (!is_sign && udpsz > daemon->edns_pktsz) | |
212 | - PUTSHORT(daemon->edns_pktsz, psave); | |
213 | - | |
214 | if (check_subnet && !check_source(header, plen, pheader, query_source)) | |
215 | { | |
216 | my_syslog(LOG_WARNING, _("discarding DNS reply: subnet option mismatch")); | |
217 | return 0; | |
218 | } | |
219 | ||
220 | - if (added_pheader) | |
221 | + if (!is_sign) | |
222 | { | |
223 | - pheader = 0; | |
224 | - header->arcount = htons(0); | |
225 | + if (added_pheader) | |
226 | + { | |
227 | + /* client didn't send EDNS0, we added one, strip it off before returning answer. */ | |
228 | + n = rrfilter(header, n, 0); | |
229 | + pheader = NULL; | |
230 | + } | |
231 | + else | |
232 | + { | |
233 | + /* If upstream is advertising a larger UDP packet size | |
234 | + than we allow, trim it so that we don't get overlarge | |
235 | + requests for the client. We can't do this for signed packets. */ | |
236 | + unsigned short udpsz; | |
237 | + unsigned char *psave = sizep; | |
238 | + | |
239 | + GETSHORT(udpsz, sizep); | |
240 | + if (udpsz > daemon->edns_pktsz) | |
241 | + PUTSHORT(daemon->edns_pktsz, psave); | |
242 | + } | |
243 | } | |
244 | } | |
245 | ||
246 | @@ -655,14 +680,16 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server | |
247 | } | |
248 | ||
249 | if (option_bool(OPT_DNSSEC_VALID)) | |
250 | - header->hb4 &= ~HB4_AD; | |
251 | - | |
252 | - if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure) | |
253 | - header->hb4 |= HB4_AD; | |
254 | - | |
255 | - /* If the requestor didn't set the DO bit, don't return DNSSEC info. */ | |
256 | - if (!do_bit) | |
257 | - n = rrfilter(header, n, 1); | |
258 | + { | |
259 | + header->hb4 &= ~HB4_AD; | |
260 | + | |
261 | + if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure) | |
262 | + header->hb4 |= HB4_AD; | |
263 | + | |
264 | + /* If the requestor didn't set the DO bit, don't return DNSSEC info. */ | |
265 | + if (!do_bit) | |
266 | + n = rrfilter(header, n, 1); | |
267 | + } | |
268 | #endif | |
269 | ||
270 | /* do this after extract_addresses. Ensure NODATA reply and remove | |
271 | @@ -761,8 +788,14 @@ void reply_query(int fd, int family, time_t now) | |
272 | if ((nn = resize_packet(header, (size_t)n, pheader, plen))) | |
273 | { | |
274 | header->hb3 &= ~(HB3_QR | HB3_AA | HB3_TC); | |
275 | - header->hb4 &= ~(HB4_RA | HB4_RCODE); | |
276 | - forward_query(-1, NULL, NULL, 0, header, nn, now, forward, 0, 0); | |
277 | + header->hb4 &= ~(HB4_RA | HB4_RCODE | HB4_CD | HB4_AD); | |
278 | + if (forward->flags |= FREC_CHECKING_DISABLED) | |
279 | + header->hb4 |= HB4_CD; | |
280 | + if (forward->flags |= FREC_AD_QUESTION) | |
281 | + header->hb4 |= HB4_AD; | |
282 | + if (forward->flags & FREC_DO_QUESTION) | |
283 | + add_do_bit(header, nn, (char *)pheader + plen); | |
284 | + forward_query(-1, NULL, NULL, 0, header, nn, now, forward, forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION); | |
285 | return; | |
286 | } | |
287 | } | |
288 | @@ -1007,12 +1040,13 @@ void receive_query(struct listener *listen, time_t now) | |
289 | { | |
290 | struct dns_header *header = (struct dns_header *)daemon->packet; | |
291 | union mysockaddr source_addr; | |
292 | - unsigned short type; | |
293 | + unsigned char *pheader; | |
294 | + unsigned short type, udp_size = PACKETSZ; /* default if no EDNS0 */ | |
295 | struct all_addr dst_addr; | |
296 | struct in_addr netmask, dst_addr_4; | |
297 | size_t m; | |
298 | ssize_t n; | |
299 | - int if_index = 0, auth_dns = 0; | |
300 | + int if_index = 0, auth_dns = 0, do_bit = 0, have_pseudoheader = 0; | |
301 | #ifdef HAVE_AUTH | |
302 | int local_auth = 0; | |
303 | #endif | |
304 | @@ -1279,10 +1313,30 @@ void receive_query(struct listener *listen, time_t now) | |
305 | #endif | |
306 | } | |
307 | ||
308 | + if (find_pseudoheader(header, (size_t)n, NULL, &pheader, NULL)) | |
309 | + { | |
310 | + unsigned short flags; | |
311 | + | |
312 | + have_pseudoheader = 1; | |
313 | + GETSHORT(udp_size, pheader); | |
314 | + pheader += 2; /* ext_rcode */ | |
315 | + GETSHORT(flags, pheader); | |
316 | + | |
317 | + if (flags & 0x8000) | |
318 | + do_bit = 1;/* do bit */ | |
319 | + | |
320 | + /* If the client provides an EDNS0 UDP size, use that to limit our reply. | |
321 | + (bounded by the maximum configured). If no EDNS0, then it | |
322 | + defaults to 512 */ | |
323 | + if (udp_size > daemon->edns_pktsz) | |
324 | + udp_size = daemon->edns_pktsz; | |
325 | + } | |
326 | + | |
327 | #ifdef HAVE_AUTH | |
328 | if (auth_dns) | |
329 | { | |
330 | - m = answer_auth(header, ((char *) header) + daemon->packet_buff_sz, (size_t)n, now, &source_addr, local_auth); | |
331 | + m = answer_auth(header, ((char *) header) + udp_size, (size_t)n, now, &source_addr, | |
332 | + local_auth, do_bit, have_pseudoheader); | |
333 | if (m >= 1) | |
334 | { | |
335 | send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND), | |
336 | @@ -1293,9 +1347,13 @@ void receive_query(struct listener *listen, time_t now) | |
337 | else | |
338 | #endif | |
339 | { | |
340 | - int ad_reqd, do_bit; | |
341 | - m = answer_request(header, ((char *) header) + daemon->packet_buff_sz, (size_t)n, | |
342 | - dst_addr_4, netmask, now, &ad_reqd, &do_bit); | |
343 | + int ad_reqd = do_bit; | |
344 | + /* RFC 6840 5.7 */ | |
345 | + if (header->hb4 & HB4_AD) | |
346 | + ad_reqd = 1; | |
347 | + | |
348 | + m = answer_request(header, ((char *) header) + udp_size, (size_t)n, | |
349 | + dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader); | |
350 | ||
351 | if (m >= 1) | |
352 | { | |
353 | @@ -1397,7 +1455,7 @@ unsigned char *tcp_request(int confd, time_t now, | |
354 | #ifdef HAVE_AUTH | |
355 | int local_auth = 0; | |
356 | #endif | |
357 | - int checking_disabled, ad_question, do_bit, added_pheader = 0; | |
358 | + int checking_disabled, do_bit, added_pheader = 0, have_pseudoheader = 0; | |
359 | int check_subnet, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0; | |
360 | size_t m; | |
361 | unsigned short qtype; | |
362 | @@ -1414,6 +1472,7 @@ unsigned char *tcp_request(int confd, time_t now, | |
363 | union mysockaddr peer_addr; | |
364 | socklen_t peer_len = sizeof(union mysockaddr); | |
365 | int query_count = 0; | |
366 | + unsigned char *pheader; | |
367 | ||
368 | if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1) | |
369 | return packet; | |
370 | @@ -1508,15 +1567,35 @@ unsigned char *tcp_request(int confd, time_t now, | |
371 | else | |
372 | dst_addr_4.s_addr = 0; | |
373 | ||
374 | + do_bit = 0; | |
375 | + | |
376 | + if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL)) | |
377 | + { | |
378 | + unsigned short flags; | |
379 | + | |
380 | + have_pseudoheader = 1; | |
381 | + pheader += 4; /* udp_size, ext_rcode */ | |
382 | + GETSHORT(flags, pheader); | |
383 | + | |
384 | + if (flags & 0x8000) | |
385 | + do_bit = 1;/* do bit */ | |
386 | + } | |
387 | + | |
388 | #ifdef HAVE_AUTH | |
389 | if (auth_dns) | |
390 | - m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr, local_auth); | |
391 | + m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr, | |
392 | + local_auth, do_bit, have_pseudoheader); | |
393 | else | |
394 | #endif | |
395 | { | |
396 | - /* m > 0 if answered from cache */ | |
397 | - m = answer_request(header, ((char *) header) + 65536, (size_t)size, | |
398 | - dst_addr_4, netmask, now, &ad_question, &do_bit); | |
399 | + int ad_reqd = do_bit; | |
400 | + /* RFC 6840 5.7 */ | |
401 | + if (header->hb4 & HB4_AD) | |
402 | + ad_reqd = 1; | |
403 | + | |
404 | + /* m > 0 if answered from cache */ | |
405 | + m = answer_request(header, ((char *) header) + 65536, (size_t)size, | |
406 | + dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader); | |
407 | ||
408 | /* Do this by steam now we're not in the select() loop */ | |
409 | check_log_writer(1); | |
410 | @@ -1615,6 +1694,7 @@ unsigned char *tcp_request(int confd, time_t now, | |
411 | } | |
412 | ||
413 | #ifdef HAVE_DNSSEC | |
414 | + added_pheader = 0; | |
415 | if (option_bool(OPT_DNSSEC_VALID)) | |
416 | { | |
417 | size_t new_size = add_do_bit(header, size, ((char *) header) + 65536); | |
418 | @@ -1719,7 +1799,7 @@ unsigned char *tcp_request(int confd, time_t now, | |
419 | ||
420 | m = process_reply(header, now, last_server, (unsigned int)m, | |
421 | option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer, | |
422 | - ad_question, do_bit, added_pheader, check_subnet, &peer_addr); | |
423 | + ad_reqd, do_bit, added_pheader, check_subnet, &peer_addr); | |
424 | ||
425 | break; | |
426 | } | |
427 | diff --git a/src/netlink.c b/src/netlink.c | |
428 | index 753784d..3376d68 100644 | |
429 | --- a/src/netlink.c | |
430 | +++ b/src/netlink.c | |
431 | @@ -288,7 +288,8 @@ int iface_enumerate(int family, void *parm, int (*callback)()) | |
432 | rta = RTA_NEXT(rta, len1); | |
433 | } | |
434 | ||
435 | - if (inaddr && mac && callback_ok) | |
436 | + if (!(neigh->ndm_state & (NUD_NOARP | NUD_INCOMPLETE | NUD_FAILED)) && | |
437 | + inaddr && mac && callback_ok) | |
438 | if (!((*callback)(neigh->ndm_family, inaddr, mac, maclen, parm))) | |
439 | callback_ok = 0; | |
440 | } | |
441 | diff --git a/src/rfc1035.c b/src/rfc1035.c | |
442 | index 188d05f..18858a8 100644 | |
443 | --- a/src/rfc1035.c | |
444 | +++ b/src/rfc1035.c | |
445 | @@ -489,8 +489,8 @@ struct macparm { | |
446 | union mysockaddr *l3; | |
447 | }; | |
448 | ||
449 | -static size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit, | |
450 | - int optno, unsigned char *opt, size_t optlen, int set_do) | |
451 | +size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit, | |
452 | + unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do) | |
453 | { | |
454 | unsigned char *lenp, *datap, *p; | |
455 | int rdlen, is_sign; | |
456 | @@ -508,7 +508,7 @@ static size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned | |
457 | return plen; | |
458 | *p++ = 0; /* empty name */ | |
459 | PUTSHORT(T_OPT, p); | |
460 | - PUTSHORT(SAFE_PKTSZ, p); /* max packet length, this will be overwritten */ | |
461 | + PUTSHORT(udp_sz, p); /* max packet length, 512 if not given in EDNS0 header */ | |
462 | PUTSHORT(0, p); /* extended RCODE and version */ | |
463 | PUTSHORT(set_do ? 0x8000 : 0, p); /* DO flag */ | |
464 | lenp = p; | |
465 | @@ -594,7 +594,7 @@ static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *p | |
466 | if (!match) | |
467 | return 1; /* continue */ | |
468 | ||
469 | - parm->plen = add_pseudoheader(parm->header, parm->plen, parm->limit, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, 0); | |
470 | + parm->plen = add_pseudoheader(parm->header, parm->plen, parm->limit, PACKETSZ, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, 0); | |
471 | ||
472 | return 0; /* done */ | |
473 | } | |
474 | @@ -603,12 +603,6 @@ size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysock | |
475 | { | |
476 | struct macparm parm; | |
477 | ||
478 | -/* Must have an existing pseudoheader as the only ar-record, | |
479 | - or have no ar-records. Must also not be signed */ | |
480 | - | |
481 | - if (ntohs(header->arcount) > 1) | |
482 | - return plen; | |
483 | - | |
484 | parm.header = header; | |
485 | parm.limit = (unsigned char *)limit; | |
486 | parm.plen = plen; | |
487 | @@ -699,13 +693,13 @@ size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, unio | |
488 | struct subnet_opt opt; | |
489 | ||
490 | len = calc_subnet_opt(&opt, source); | |
491 | - return add_pseudoheader(header, plen, (unsigned char *)limit, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0); | |
492 | + return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0); | |
493 | } | |
494 | ||
495 | #ifdef HAVE_DNSSEC | |
496 | size_t add_do_bit(struct dns_header *header, size_t plen, char *limit) | |
497 | { | |
498 | - return add_pseudoheader(header, plen, (unsigned char *)limit, 0, NULL, 0, 1); | |
499 | + return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, 0, NULL, 0, 1); | |
500 | } | |
501 | #endif | |
502 | ||
503 | @@ -1525,16 +1519,16 @@ static unsigned long crec_ttl(struct crec *crecp, time_t now) | |
504 | /* return zero if we can't answer from cache, or packet size if we can */ | |
505 | size_t answer_request(struct dns_header *header, char *limit, size_t qlen, | |
506 | struct in_addr local_addr, struct in_addr local_netmask, | |
507 | - time_t now, int *ad_reqd, int *do_bit) | |
508 | + time_t now, int ad_reqd, int do_bit, int have_pseudoheader) | |
509 | { | |
510 | char *name = daemon->namebuff; | |
511 | - unsigned char *p, *ansp, *pheader; | |
512 | + unsigned char *p, *ansp; | |
513 | unsigned int qtype, qclass; | |
514 | struct all_addr addr; | |
515 | int nameoffset; | |
516 | unsigned short flag; | |
517 | int q, ans, anscount = 0, addncount = 0; | |
518 | - int dryrun = 0, sec_reqd = 0, have_pseudoheader = 0; | |
519 | + int dryrun = 0; | |
520 | struct crec *crecp; | |
521 | int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1; | |
522 | struct mx_srv_record *rec; | |
523 | @@ -1550,35 +1544,11 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, | |
524 | if (header->hb4 & HB4_CD) | |
525 | sec_data = 0; | |
526 | ||
527 | - /* RFC 6840 5.7 */ | |
528 | - *ad_reqd = header->hb4 & HB4_AD; | |
529 | - *do_bit = 0; | |
530 | - | |
531 | /* If there is an additional data section then it will be overwritten by | |
532 | partial replies, so we have to do a dry run to see if we can answer | |
533 | the query. */ | |
534 | - | |
535 | if (ntohs(header->arcount) != 0) | |
536 | - { | |
537 | - dryrun = 1; | |
538 | - | |
539 | - /* If there's an additional section, there might be an EDNS(0) pseudoheader */ | |
540 | - if (find_pseudoheader(header, qlen, NULL, &pheader, NULL)) | |
541 | - { | |
542 | - unsigned short flags; | |
543 | - | |
544 | - have_pseudoheader = 1; | |
545 | - | |
546 | - pheader += 4; /* udp size, ext_rcode */ | |
547 | - GETSHORT(flags, pheader); | |
548 | - | |
549 | - if ((sec_reqd = flags & 0x8000)) | |
550 | - { | |
551 | - *do_bit = 1;/* do bit */ | |
552 | - *ad_reqd = 1; | |
553 | - } | |
554 | - } | |
555 | - } | |
556 | + dryrun = 1; | |
557 | ||
558 | for (rec = daemon->mxnames; rec; rec = rec->next) | |
559 | rec->offset = 0; | |
560 | @@ -1603,11 +1573,6 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, | |
561 | GETSHORT(qtype, p); | |
562 | GETSHORT(qclass, p); | |
563 | ||
564 | - /* Don't filter RRSIGS from answers to ANY queries, even if do-bit | |
565 | - not set. */ | |
566 | - if (qtype == T_ANY) | |
567 | - *do_bit = 1; | |
568 | - | |
569 | ans = 0; /* have we answered this question */ | |
570 | ||
571 | if (qtype == T_TXT || qtype == T_ANY) | |
572 | @@ -1739,7 +1704,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, | |
573 | the zone is unsigned, which implies that we're doing | |
574 | validation. */ | |
575 | if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || | |
576 | - !sec_reqd || | |
577 | + !do_bit || | |
578 | (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK))) | |
579 | { | |
580 | do | |
581 | @@ -1927,7 +1892,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, | |
582 | } | |
583 | ||
584 | /* If the client asked for DNSSEC don't use cached data. */ | |
585 | - if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !sec_reqd || !(crecp->flags & F_DNSSECOK)) | |
586 | + if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !do_bit || !(crecp->flags & F_DNSSECOK)) | |
587 | do | |
588 | { | |
589 | /* don't answer wildcard queries with data not from /etc/hosts | |
590 | @@ -1961,17 +1926,12 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, | |
591 | ||
592 | if (crecp->flags & F_NEG) | |
593 | { | |
594 | - /* We don't cache NSEC records, so if a DNSSEC-validated negative answer | |
595 | - is cached and the client wants DNSSEC, forward rather than answering from the cache */ | |
596 | - if (!sec_reqd || !(crecp->flags & F_DNSSECOK)) | |
597 | - { | |
598 | - ans = 1; | |
599 | - auth = 0; | |
600 | - if (crecp->flags & F_NXDOMAIN) | |
601 | - nxdomain = 1; | |
602 | - if (!dryrun) | |
603 | - log_query(crecp->flags, name, NULL, NULL); | |
604 | - } | |
605 | + ans = 1; | |
606 | + auth = 0; | |
607 | + if (crecp->flags & F_NXDOMAIN) | |
608 | + nxdomain = 1; | |
609 | + if (!dryrun) | |
610 | + log_query(crecp->flags, name, NULL, NULL); | |
611 | } | |
612 | else | |
613 | { | |
614 | @@ -2209,10 +2169,11 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, | |
615 | ||
616 | len = ansp - (unsigned char *)header; | |
617 | ||
618 | + /* Advertise our packet size limit in our reply */ | |
619 | if (have_pseudoheader) | |
620 | - len = add_pseudoheader(header, len, (unsigned char *)limit, 0, NULL, 0, sec_reqd); | |
621 | + len = add_pseudoheader(header, len, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit); | |
622 | ||
623 | - if (*ad_reqd && sec_data) | |
624 | + if (ad_reqd && sec_data) | |
625 | header->hb4 |= HB4_AD; | |
626 | else | |
627 | header->hb4 &= ~HB4_AD; | |
628 | diff --git a/src/rrfilter.c b/src/rrfilter.c | |
629 | index ae12261..b26b39f 100644 | |
630 | --- a/src/rrfilter.c | |
631 | +++ b/src/rrfilter.c | |
632 | @@ -243,7 +243,7 @@ size_t rrfilter(struct dns_header *header, size_t plen, int mode) | |
633 | for (p = rrs[0], i = 1; i < rr_found; i += 2) | |
634 | { | |
635 | unsigned char *start = rrs[i]; | |
636 | - unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : ((unsigned char *)(header+1)) + plen; | |
637 | + unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : ((unsigned char *)header) + plen; | |
638 | ||
639 | memmove(p, start, end-start); | |
640 | p += end-start; | |
641 | -- | |
642 | 1.7.10.4 | |
643 |