File: | src/usr.sbin/nsd/query.c |
Warning: | line 1143, column 6 Access to field 'parent' results in a dereference of a null pointer (loaded from variable 'closest_encloser') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | ||||
2 | * query.c -- nsd(8) the resolver. | ||||
3 | * | ||||
4 | * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. | ||||
5 | * | ||||
6 | * See LICENSE for the license. | ||||
7 | * | ||||
8 | */ | ||||
9 | |||||
10 | #include "config.h" | ||||
11 | |||||
12 | #include <sys/types.h> | ||||
13 | #include <sys/socket.h> | ||||
14 | #include <netinet/in.h> | ||||
15 | #include <arpa/inet.h> | ||||
16 | #include <assert.h> | ||||
17 | #include <ctype.h> | ||||
18 | #include <errno(*__errno()).h> | ||||
19 | #include <limits.h> | ||||
20 | #include <stddef.h> | ||||
21 | #include <stdio.h> | ||||
22 | #include <stdlib.h> | ||||
23 | #include <string.h> | ||||
24 | #include <time.h> | ||||
25 | #include <unistd.h> | ||||
26 | #include <netdb.h> | ||||
27 | |||||
28 | #include "answer.h" | ||||
29 | #include "axfr.h" | ||||
30 | #include "dns.h" | ||||
31 | #include "dname.h" | ||||
32 | #include "nsd.h" | ||||
33 | #include "namedb.h" | ||||
34 | #include "query.h" | ||||
35 | #include "util.h" | ||||
36 | #include "options.h" | ||||
37 | #include "nsec3.h" | ||||
38 | #include "tsig.h" | ||||
39 | |||||
40 | /* [Bug #253] Adding unnecessary NS RRset may lead to undesired truncation. | ||||
41 | * This function determines if the final response packet needs the NS RRset | ||||
42 | * included. Currently, it will only return negative if QTYPE == DNSKEY|DS. | ||||
43 | * This way, resolvers won't fallback to TCP unnecessarily when priming | ||||
44 | * trust anchors. | ||||
45 | */ | ||||
46 | static int answer_needs_ns(struct query *query); | ||||
47 | |||||
48 | static int add_rrset(struct query *query, | ||||
49 | answer_type *answer, | ||||
50 | rr_section_type section, | ||||
51 | domain_type *owner, | ||||
52 | rrset_type *rrset); | ||||
53 | |||||
54 | static void answer_authoritative(struct nsd *nsd, | ||||
55 | struct query *q, | ||||
56 | answer_type *answer, | ||||
57 | size_t domain_number, | ||||
58 | int exact, | ||||
59 | domain_type *closest_match, | ||||
60 | domain_type *closest_encloser, | ||||
61 | const dname_type *qname); | ||||
62 | |||||
63 | static void answer_lookup_zone(struct nsd *nsd, struct query *q, | ||||
64 | answer_type *answer, size_t domain_number, | ||||
65 | int exact, domain_type *closest_match, | ||||
66 | domain_type *closest_encloser, | ||||
67 | const dname_type *qname); | ||||
68 | |||||
69 | void | ||||
70 | query_put_dname_offset(struct query *q, domain_type *domain, uint16_t offset) | ||||
71 | { | ||||
72 | assert(q)((void)0); | ||||
73 | assert(domain)((void)0); | ||||
74 | assert(domain->number > 0)((void)0); | ||||
75 | |||||
76 | if (offset > MAX_COMPRESSION_OFFSET16383) | ||||
77 | return; | ||||
78 | if (q->compressed_dname_count >= MAX_COMPRESSED_DNAMES10240) | ||||
79 | return; | ||||
80 | |||||
81 | q->compressed_dname_offsets[domain->number] = offset; | ||||
82 | q->compressed_dnames[q->compressed_dname_count] = domain; | ||||
83 | ++q->compressed_dname_count; | ||||
84 | } | ||||
85 | |||||
86 | void | ||||
87 | query_clear_dname_offsets(struct query *q, size_t max_offset) | ||||
88 | { | ||||
89 | while (q->compressed_dname_count > 0 | ||||
90 | && (q->compressed_dname_offsets[q->compressed_dnames[q->compressed_dname_count - 1]->number] | ||||
91 | >= max_offset)) | ||||
92 | { | ||||
93 | q->compressed_dname_offsets[q->compressed_dnames[q->compressed_dname_count - 1]->number] = 0; | ||||
94 | --q->compressed_dname_count; | ||||
95 | } | ||||
96 | } | ||||
97 | |||||
98 | void | ||||
99 | query_clear_compression_tables(struct query *q) | ||||
100 | { | ||||
101 | uint16_t i; | ||||
102 | |||||
103 | for (i = 0; i < q->compressed_dname_count; ++i) { | ||||
104 | assert(q->compressed_dnames)((void)0); | ||||
105 | q->compressed_dname_offsets[q->compressed_dnames[i]->number] = 0; | ||||
106 | } | ||||
107 | q->compressed_dname_count = 0; | ||||
108 | } | ||||
109 | |||||
110 | void | ||||
111 | query_add_compression_domain(struct query *q, domain_type *domain, uint16_t offset) | ||||
112 | { | ||||
113 | while (domain->parent) { | ||||
114 | DEBUG(DEBUG_NAME_COMPRESSION, 2, | ||||
115 | (LOG_INFO, "query dname: %s, number: %lu, offset: %u\n", | ||||
116 | domain_to_string(domain), | ||||
117 | (unsigned long) domain->number, | ||||
118 | offset)); | ||||
119 | query_put_dname_offset(q, domain, offset); | ||||
120 | offset += label_length(dname_name(domain_dname(domain))) + 1; | ||||
121 | domain = domain->parent; | ||||
122 | } | ||||
123 | } | ||||
124 | |||||
125 | /* | ||||
126 | * Generate an error response with the specified RCODE. | ||||
127 | */ | ||||
128 | query_state_type | ||||
129 | query_error (struct query *q, nsd_rc_type rcode) | ||||
130 | { | ||||
131 | if (rcode == NSD_RC_DISCARD) { | ||||
132 | return QUERY_DISCARDED; | ||||
133 | } | ||||
134 | |||||
135 | buffer_clear(q->packet); | ||||
136 | |||||
137 | QR_SET(q->packet)(*buffer_at((q->packet), 2) |= 0x80U); /* This is an answer. */ | ||||
138 | AD_CLR(q->packet)(*buffer_at((q->packet), 3) &= ~0x20U); | ||||
139 | RCODE_SET(q->packet, (int) rcode)(*buffer_at((q->packet), 3) = (*buffer_at((q->packet), 3 ) & ~0x0fU) | ((int) rcode)); /* Error code. */ | ||||
140 | |||||
141 | /* Truncate the question as well... */ | ||||
142 | QDCOUNT_SET(q->packet, 0)(buffer_write_u16_at((q->packet), 4, (0))); | ||||
143 | ANCOUNT_SET(q->packet, 0)(buffer_write_u16_at((q->packet), 6, (0))); | ||||
144 | NSCOUNT_SET(q->packet, 0)(buffer_write_u16_at((q->packet), 8, (0))); | ||||
145 | ARCOUNT_SET(q->packet, 0)(buffer_write_u16_at((q->packet), 10, (0))); | ||||
146 | buffer_set_position(q->packet, QHEADERSZ12); | ||||
147 | return QUERY_PROCESSED; | ||||
148 | } | ||||
149 | |||||
150 | static int | ||||
151 | query_ratelimit_err(nsd_type* nsd) | ||||
152 | { | ||||
153 | time_t now = time(NULL((void *)0)); | ||||
154 | if(nsd->err_limit_time == now) { | ||||
155 | /* see if limit is exceeded for this second */ | ||||
156 | if(nsd->err_limit_count++ > ERROR_RATELIMIT100) | ||||
157 | return 1; | ||||
158 | } else { | ||||
159 | /* new second, new limits */ | ||||
160 | nsd->err_limit_time = now; | ||||
161 | nsd->err_limit_count = 1; | ||||
162 | } | ||||
163 | return 0; | ||||
164 | } | ||||
165 | |||||
166 | static query_state_type | ||||
167 | query_formerr (struct query *query, nsd_type* nsd) | ||||
168 | { | ||||
169 | int opcode = OPCODE(query->packet)((*buffer_at((query->packet), 2) & 0x78U) >> 3); | ||||
170 | if(query_ratelimit_err(nsd)) | ||||
171 | return QUERY_DISCARDED; | ||||
172 | FLAGS_SET(query->packet, FLAGS(query->packet) & 0x0100U)(buffer_write_u16_at((query->packet), 2, ((buffer_read_u16_at ((query->packet), 2)) & 0x0100U))); | ||||
173 | /* Preserve the RD flag. Clear the rest. */ | ||||
174 | OPCODE_SET(query->packet, opcode)(*buffer_at((query->packet), 2) = (*buffer_at((query->packet ), 2) & ~0x78U) | ((opcode) << 3)); | ||||
175 | return query_error(query, NSD_RC_FORMAT); | ||||
176 | } | ||||
177 | |||||
178 | static void | ||||
179 | query_cleanup(void *data) | ||||
180 | { | ||||
181 | query_type *query = (query_type *) data; | ||||
182 | region_destroy(query->region); | ||||
183 | } | ||||
184 | |||||
185 | query_type * | ||||
186 | query_create(region_type *region, uint16_t *compressed_dname_offsets, | ||||
187 | size_t compressed_dname_size, domain_type **compressed_dnames) | ||||
188 | { | ||||
189 | query_type *query | ||||
190 | = (query_type *) region_alloc_zero(region, sizeof(query_type)); | ||||
191 | /* create region with large block size, because the initial chunk | ||||
192 | saves many mallocs in the server */ | ||||
193 | query->region = region_create_custom(xalloc, free, 16384, 16384/8, 32, 0); | ||||
194 | query->compressed_dname_offsets = compressed_dname_offsets; | ||||
195 | query->compressed_dnames = compressed_dnames; | ||||
196 | query->packet = buffer_create(region, QIOBUFSZ(65535 + (255 + sizeof(uint32_t) + 4*sizeof(uint16_t) + 65535 ))); | ||||
197 | region_add_cleanup(region, query_cleanup, query); | ||||
198 | query->compressed_dname_offsets_size = compressed_dname_size; | ||||
199 | tsig_create_record(&query->tsig, region); | ||||
200 | query->tsig_prepare_it = 1; | ||||
201 | query->tsig_update_it = 1; | ||||
202 | query->tsig_sign_it = 1; | ||||
203 | return query; | ||||
204 | } | ||||
205 | |||||
206 | void | ||||
207 | query_reset(query_type *q, size_t maxlen, int is_tcp) | ||||
208 | { | ||||
209 | /* | ||||
210 | * As long as less than 4Kb (region block size) has been used, | ||||
211 | * this call to free_all is free, the block is saved for re-use, | ||||
212 | * so no malloc() or free() calls are done. | ||||
213 | * at present use of the region is for: | ||||
214 | * o query qname dname_type (255 max). | ||||
215 | * o wildcard expansion domain_type (7*ptr+u32+2bytes)+(5*ptr nsec3) | ||||
216 | * o wildcard expansion for additional section domain_type. | ||||
217 | * o nsec3 hashed name(s) (3 dnames for a nonexist_proof, | ||||
218 | * one proof per wildcard and for nx domain). | ||||
219 | */ | ||||
220 | region_free_all(q->region); | ||||
221 | q->remote_addrlen = (socklen_t)sizeof(q->remote_addr); | ||||
222 | q->client_addrlen = (socklen_t)sizeof(q->client_addr); | ||||
223 | q->is_proxied = 0; | ||||
224 | q->maxlen = maxlen; | ||||
225 | q->reserved_space = 0; | ||||
226 | buffer_clear(q->packet); | ||||
227 | edns_init_record(&q->edns); | ||||
228 | tsig_init_record(&q->tsig, NULL((void *)0), NULL((void *)0)); | ||||
229 | q->tsig_prepare_it = 1; | ||||
230 | q->tsig_update_it = 1; | ||||
231 | q->tsig_sign_it = 1; | ||||
232 | q->tcp = is_tcp; | ||||
233 | q->qname = NULL((void *)0); | ||||
234 | q->qtype = 0; | ||||
235 | q->qclass = 0; | ||||
236 | q->zone = NULL((void *)0); | ||||
237 | q->opcode = 0; | ||||
238 | q->cname_count = 0; | ||||
239 | q->delegation_domain = NULL((void *)0); | ||||
240 | q->delegation_rrset = NULL((void *)0); | ||||
241 | q->compressed_dname_count = 0; | ||||
242 | q->number_temporary_domains = 0; | ||||
243 | |||||
244 | q->axfr_is_done = 0; | ||||
245 | q->axfr_zone = NULL((void *)0); | ||||
246 | q->axfr_current_domain = NULL((void *)0); | ||||
247 | q->axfr_current_rrset = NULL((void *)0); | ||||
248 | q->axfr_current_rr = 0; | ||||
249 | |||||
250 | q->ixfr_is_done = 0; | ||||
251 | q->ixfr_data = NULL((void *)0); | ||||
252 | q->ixfr_count_newsoa = 0; | ||||
253 | q->ixfr_count_oldsoa = 0; | ||||
254 | q->ixfr_count_del = 0; | ||||
255 | q->ixfr_count_add = 0; | ||||
256 | |||||
257 | #ifdef RATELIMIT | ||||
258 | q->wildcard_domain = NULL((void *)0); | ||||
259 | #endif | ||||
260 | } | ||||
261 | |||||
262 | /* get a temporary domain number (or 0=failure) */ | ||||
263 | static domain_type* | ||||
264 | query_get_tempdomain(struct query *q) | ||||
265 | { | ||||
266 | static domain_type d[EXTRA_DOMAIN_NUMBERS1024]; | ||||
267 | if(q->number_temporary_domains >= EXTRA_DOMAIN_NUMBERS1024) | ||||
268 | return 0; | ||||
269 | q->number_temporary_domains ++; | ||||
270 | memset(&d[q->number_temporary_domains-1], 0, sizeof(domain_type)); | ||||
271 | d[q->number_temporary_domains-1].number = q->compressed_dname_offsets_size + | ||||
272 | q->number_temporary_domains - 1; | ||||
273 | return &d[q->number_temporary_domains-1]; | ||||
274 | } | ||||
275 | |||||
276 | static void | ||||
277 | query_addtxt(struct query *q, | ||||
278 | const uint8_t *dname, | ||||
279 | uint16_t klass, | ||||
280 | uint32_t ttl, | ||||
281 | const char *txt) | ||||
282 | { | ||||
283 | size_t txt_length = strlen(txt); | ||||
284 | uint8_t len = (uint8_t) txt_length; | ||||
285 | |||||
286 | assert(txt_length <= UCHAR_MAX)((void)0); | ||||
287 | |||||
288 | /* Add the dname */ | ||||
289 | if (dname >= buffer_begin(q->packet) | ||||
290 | && dname <= buffer_current(q->packet)) | ||||
291 | { | ||||
292 | buffer_write_u16(q->packet, | ||||
293 | 0xc000 | (dname - buffer_begin(q->packet))); | ||||
294 | } else { | ||||
295 | buffer_write(q->packet, dname + 1, *dname); | ||||
296 | } | ||||
297 | |||||
298 | buffer_write_u16(q->packet, TYPE_TXT16); | ||||
299 | buffer_write_u16(q->packet, klass); | ||||
300 | buffer_write_u32(q->packet, ttl); | ||||
301 | buffer_write_u16(q->packet, len + 1); | ||||
302 | buffer_write_u8(q->packet, len); | ||||
303 | buffer_write(q->packet, txt, len); | ||||
304 | } | ||||
305 | |||||
306 | /* | ||||
307 | * Parse the question section of a query. The normalized query name | ||||
308 | * is stored in QUERY->name, the class in QUERY->klass, and the type | ||||
309 | * in QUERY->type. | ||||
310 | */ | ||||
311 | static int | ||||
312 | process_query_section(query_type *query) | ||||
313 | { | ||||
314 | uint8_t qnamebuf[MAXDOMAINLEN255]; | ||||
315 | |||||
316 | buffer_set_position(query->packet, QHEADERSZ12); | ||||
317 | /* Lets parse the query name and convert it to lower case. */ | ||||
318 | if(!packet_read_query_section(query->packet, qnamebuf, | ||||
319 | &query->qtype, &query->qclass)) | ||||
320 | return 0; | ||||
321 | query->qname = dname_make(query->region, qnamebuf, 1); | ||||
322 | return 1; | ||||
323 | } | ||||
324 | |||||
325 | |||||
326 | /* | ||||
327 | * Process an optional EDNS OPT record. Sets QUERY->EDNS to 0 if | ||||
328 | * there was no EDNS record, to -1 if there was an invalid or | ||||
329 | * unsupported EDNS record, and to 1 otherwise. Updates QUERY->MAXLEN | ||||
330 | * if the EDNS record specifies a maximum supported response length. | ||||
331 | * | ||||
332 | * Return NSD_RC_FORMAT on failure, NSD_RC_OK on success. | ||||
333 | */ | ||||
334 | static nsd_rc_type | ||||
335 | process_edns(nsd_type* nsd, struct query *q) | ||||
336 | { | ||||
337 | if (q->edns.status == EDNS_ERROR) { | ||||
338 | /* The only error is VERSION not implemented */ | ||||
339 | return NSD_RC_FORMAT; | ||||
340 | } | ||||
341 | |||||
342 | if (q->edns.status == EDNS_OK) { | ||||
343 | /* Only care about UDP size larger than normal... */ | ||||
344 | if (!q->tcp && q->edns.maxlen > UDP_MAX_MESSAGE_LEN512) { | ||||
345 | size_t edns_size; | ||||
346 | #if defined(INET6) | ||||
347 | if (q->client_addr.ss_family == AF_INET624) { | ||||
348 | edns_size = nsd->ipv6_edns_size; | ||||
349 | } else | ||||
350 | #endif | ||||
351 | edns_size = nsd->ipv4_edns_size; | ||||
352 | |||||
353 | if (q->edns.maxlen < edns_size) { | ||||
354 | q->maxlen = q->edns.maxlen; | ||||
355 | } else { | ||||
356 | q->maxlen = edns_size; | ||||
357 | } | ||||
358 | |||||
359 | #if defined(INET6) && !defined(IPV6_USE_MIN_MTU42) && !defined(IPV6_MTU) | ||||
360 | /* | ||||
361 | * Use IPv6 minimum MTU to avoid sending | ||||
362 | * packets that are too large for some links. | ||||
363 | * IPv6 will not automatically fragment in | ||||
364 | * this case (unlike IPv4). | ||||
365 | */ | ||||
366 | if (q->client_addr.ss_family == AF_INET624 | ||||
367 | && q->maxlen > IPV6_MIN_MTU1280) | ||||
368 | { | ||||
369 | q->maxlen = IPV6_MIN_MTU1280; | ||||
370 | } | ||||
371 | #endif | ||||
372 | } | ||||
373 | |||||
374 | /* Strip the OPT resource record off... */ | ||||
375 | buffer_set_position(q->packet, q->edns.position); | ||||
376 | buffer_set_limit(q->packet, q->edns.position); | ||||
377 | ARCOUNT_SET(q->packet, ARCOUNT(q->packet) - 1)(buffer_write_u16_at((q->packet), 10, ((buffer_read_u16_at ((q->packet), 10)) - 1))); | ||||
378 | } | ||||
379 | return NSD_RC_OK; | ||||
380 | } | ||||
381 | |||||
382 | /* | ||||
383 | * Processes TSIG. | ||||
384 | * Sets error when tsig does not verify on the query. | ||||
385 | */ | ||||
386 | static nsd_rc_type | ||||
387 | process_tsig(struct query* q) | ||||
388 | { | ||||
389 | if(q->tsig.status == TSIG_ERROR) | ||||
390 | return NSD_RC_FORMAT; | ||||
391 | if(q->tsig.status == TSIG_OK) { | ||||
392 | if(!tsig_from_query(&q->tsig)) { | ||||
393 | char a[128]; | ||||
394 | addr2str(&q->client_addr, a, sizeof(a)); | ||||
395 | log_msg(LOG_ERR3, "query: bad tsig (%s) for key %s from %s", | ||||
396 | tsig_error(q->tsig.error_code), | ||||
397 | dname_to_string(q->tsig.key_name, NULL((void *)0)), a); | ||||
398 | return NSD_RC_NOTAUTH; | ||||
399 | } | ||||
400 | buffer_set_limit(q->packet, q->tsig.position); | ||||
401 | ARCOUNT_SET(q->packet, ARCOUNT(q->packet) - 1)(buffer_write_u16_at((q->packet), 10, ((buffer_read_u16_at ((q->packet), 10)) - 1))); | ||||
402 | tsig_prepare(&q->tsig); | ||||
403 | tsig_update(&q->tsig, q->packet, buffer_limit(q->packet)); | ||||
404 | if(!tsig_verify(&q->tsig)) { | ||||
405 | char a[128]; | ||||
406 | addr2str(&q->client_addr, a, sizeof(a)); | ||||
407 | log_msg(LOG_ERR3, "query: bad tsig signature for key %s from %s", | ||||
408 | dname_to_string(q->tsig.key->name, NULL((void *)0)), a); | ||||
409 | return NSD_RC_NOTAUTH; | ||||
410 | } | ||||
411 | DEBUG(DEBUG_XFRD,1, (LOG_INFO, "query good tsig signature for %s", | ||||
412 | dname_to_string(q->tsig.key->name, NULL))); | ||||
413 | } | ||||
414 | return NSD_RC_OK; | ||||
415 | } | ||||
416 | |||||
417 | /* | ||||
418 | * Check notify acl and forward to xfrd (or return an error). | ||||
419 | */ | ||||
420 | static query_state_type | ||||
421 | answer_notify(struct nsd* nsd, struct query *query) | ||||
422 | { | ||||
423 | int acl_num, acl_num_xfr; | ||||
424 | struct acl_options *why; | ||||
425 | nsd_rc_type rc; | ||||
426 | |||||
427 | struct zone_options* zone_opt; | ||||
428 | DEBUG(DEBUG_XFRD,1, (LOG_INFO, "got notify %s processing acl", | ||||
429 | dname_to_string(query->qname, NULL))); | ||||
430 | |||||
431 | zone_opt = zone_options_find(nsd->options, query->qname); | ||||
432 | if(!zone_opt) | ||||
433 | return query_error(query, NSD_RC_NXDOMAIN); | ||||
434 | |||||
435 | if(!nsd->this_child) /* we are in debug mode or something */ | ||||
436 | return query_error(query, NSD_RC_SERVFAIL); | ||||
437 | |||||
438 | if(!tsig_find_rr(&query->tsig, query->packet)) { | ||||
439 | DEBUG(DEBUG_XFRD,2, (LOG_ERR, "bad tsig RR format")); | ||||
440 | return query_error(query, NSD_RC_FORMAT); | ||||
441 | } | ||||
442 | rc = process_tsig(query); | ||||
443 | if(rc != NSD_RC_OK) | ||||
444 | return query_error(query, rc); | ||||
445 | |||||
446 | /* check if it passes acl */ | ||||
447 | if(query->is_proxied && acl_check_incoming_block_proxy( | ||||
448 | zone_opt->pattern->allow_notify, query, &why) == -1) { | ||||
449 | /* the proxy address is blocked */ | ||||
450 | if (verbosity >= 2) { | ||||
451 | char address[128], proxy[128]; | ||||
452 | addr2str(&query->client_addr, address, sizeof(address)); | ||||
453 | addr2str(&query->remote_addr, proxy, sizeof(proxy)); | ||||
454 | VERBOSITY(2, (LOG_INFO, "notify for %s from %s via proxy %s refused because of proxy, %s %s",do { if ((2) <= verbosity) { log_msg (6, "notify for %s from %s via proxy %s refused because of proxy, %s %s" , dname_to_string(query->qname, ((void *)0)), address, proxy , (why?why->ip_address_spec:"."), (why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why->key_name ) : "no acl matches")) ; } } while (0) | ||||
455 | dname_to_string(query->qname, NULL),do { if ((2) <= verbosity) { log_msg (6, "notify for %s from %s via proxy %s refused because of proxy, %s %s" , dname_to_string(query->qname, ((void *)0)), address, proxy , (why?why->ip_address_spec:"."), (why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why->key_name ) : "no acl matches")) ; } } while (0) | ||||
456 | address, proxy,do { if ((2) <= verbosity) { log_msg (6, "notify for %s from %s via proxy %s refused because of proxy, %s %s" , dname_to_string(query->qname, ((void *)0)), address, proxy , (why?why->ip_address_spec:"."), (why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why->key_name ) : "no acl matches")) ; } } while (0) | ||||
457 | (why?why->ip_address_spec:"."),do { if ((2) <= verbosity) { log_msg (6, "notify for %s from %s via proxy %s refused because of proxy, %s %s" , dname_to_string(query->qname, ((void *)0)), address, proxy , (why?why->ip_address_spec:"."), (why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why->key_name ) : "no acl matches")) ; } } while (0) | ||||
458 | (why ? ( why->nokey ? "NOKEY"do { if ((2) <= verbosity) { log_msg (6, "notify for %s from %s via proxy %s refused because of proxy, %s %s" , dname_to_string(query->qname, ((void *)0)), address, proxy , (why?why->ip_address_spec:"."), (why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why->key_name ) : "no acl matches")) ; } } while (0) | ||||
459 | : why->blocked ? "BLOCKED"do { if ((2) <= verbosity) { log_msg (6, "notify for %s from %s via proxy %s refused because of proxy, %s %s" , dname_to_string(query->qname, ((void *)0)), address, proxy , (why?why->ip_address_spec:"."), (why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why->key_name ) : "no acl matches")) ; } } while (0) | ||||
460 | : why->key_name )do { if ((2) <= verbosity) { log_msg (6, "notify for %s from %s via proxy %s refused because of proxy, %s %s" , dname_to_string(query->qname, ((void *)0)), address, proxy , (why?why->ip_address_spec:"."), (why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why->key_name ) : "no acl matches")) ; } } while (0) | ||||
461 | : "no acl matches")))do { if ((2) <= verbosity) { log_msg (6, "notify for %s from %s via proxy %s refused because of proxy, %s %s" , dname_to_string(query->qname, ((void *)0)), address, proxy , (why?why->ip_address_spec:"."), (why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why->key_name ) : "no acl matches")) ; } } while (0); | ||||
462 | } | ||||
463 | return query_error(query, NSD_RC_REFUSE); | ||||
464 | } | ||||
465 | if((acl_num = acl_check_incoming(zone_opt->pattern->allow_notify, query, | ||||
466 | &why)) != -1) | ||||
467 | { | ||||
468 | sig_atomic_t mode = NSD_PASS_TO_XFRD6; | ||||
469 | int s = nsd->this_child->parent_fd; | ||||
470 | uint16_t sz; | ||||
471 | uint32_t acl_send = htonl(acl_num)(__uint32_t)(__builtin_constant_p(acl_num) ? (__uint32_t)(((__uint32_t )(acl_num) & 0xff) << 24 | ((__uint32_t)(acl_num) & 0xff00) << 8 | ((__uint32_t)(acl_num) & 0xff0000) >> 8 | ((__uint32_t)(acl_num) & 0xff000000) >> 24) : __swap32md (acl_num)); | ||||
472 | uint32_t acl_xfr; | ||||
473 | size_t pos; | ||||
474 | |||||
475 | /* Find priority candidate for request XFR. -1 if no match */ | ||||
476 | acl_num_xfr = acl_check_incoming( | ||||
477 | zone_opt->pattern->request_xfr, query, NULL((void *)0)); | ||||
478 | |||||
479 | acl_xfr = htonl(acl_num_xfr)(__uint32_t)(__builtin_constant_p(acl_num_xfr) ? (__uint32_t) (((__uint32_t)(acl_num_xfr) & 0xff) << 24 | ((__uint32_t )(acl_num_xfr) & 0xff00) << 8 | ((__uint32_t)(acl_num_xfr ) & 0xff0000) >> 8 | ((__uint32_t)(acl_num_xfr) & 0xff000000) >> 24) : __swap32md(acl_num_xfr)); | ||||
480 | |||||
481 | assert(why)((void)0); | ||||
482 | DEBUG(DEBUG_XFRD,1, (LOG_INFO, "got notify %s passed acl %s %s", | ||||
483 | dname_to_string(query->qname, NULL), | ||||
484 | why->ip_address_spec, | ||||
485 | why->nokey?"NOKEY": | ||||
486 | (why->blocked?"BLOCKED":why->key_name))); | ||||
487 | sz = buffer_limit(query->packet); | ||||
488 | if(buffer_limit(query->packet) > MAX_PACKET_SIZE65535) | ||||
489 | return query_error(query, NSD_RC_SERVFAIL); | ||||
490 | /* forward to xfrd for processing | ||||
491 | Note. Blocking IPC I/O, but acl is OK. */ | ||||
492 | sz = htons(sz)(__uint16_t)(__builtin_constant_p(sz) ? (__uint16_t)(((__uint16_t )(sz) & 0xffU) << 8 | ((__uint16_t)(sz) & 0xff00U ) >> 8) : __swap16md(sz)); | ||||
493 | if(!write_socket(s, &mode, sizeof(mode)) || | ||||
494 | !write_socket(s, &sz, sizeof(sz)) || | ||||
495 | !write_socket(s, buffer_begin(query->packet), | ||||
496 | buffer_limit(query->packet)) || | ||||
497 | !write_socket(s, &acl_send, sizeof(acl_send)) || | ||||
498 | !write_socket(s, &acl_xfr, sizeof(acl_xfr))) { | ||||
499 | log_msg(LOG_ERR3, "error in IPC notify server2main, %s", | ||||
500 | strerror(errno(*__errno()))); | ||||
501 | return query_error(query, NSD_RC_SERVFAIL); | ||||
502 | } | ||||
503 | if(verbosity >= 1) { | ||||
504 | uint32_t serial = 0; | ||||
505 | char address[128]; | ||||
506 | addr2str(&query->client_addr, address, sizeof(address)); | ||||
507 | if(packet_find_notify_serial(query->packet, &serial)) | ||||
508 | VERBOSITY(1, (LOG_INFO, "notify for %s from %s serial %u",do { if ((1) <= verbosity) { log_msg (6, "notify for %s from %s serial %u" , dname_to_string(query->qname, ((void *)0)), address, (unsigned )serial) ; } } while (0) | ||||
509 | dname_to_string(query->qname, NULL), address,do { if ((1) <= verbosity) { log_msg (6, "notify for %s from %s serial %u" , dname_to_string(query->qname, ((void *)0)), address, (unsigned )serial) ; } } while (0) | ||||
510 | (unsigned)serial))do { if ((1) <= verbosity) { log_msg (6, "notify for %s from %s serial %u" , dname_to_string(query->qname, ((void *)0)), address, (unsigned )serial) ; } } while (0); | ||||
511 | else | ||||
512 | VERBOSITY(1, (LOG_INFO, "notify for %s from %s",do { if ((1) <= verbosity) { log_msg (6, "notify for %s from %s" , dname_to_string(query->qname, ((void *)0)), address) ; } } while (0) | ||||
513 | dname_to_string(query->qname, NULL), address))do { if ((1) <= verbosity) { log_msg (6, "notify for %s from %s" , dname_to_string(query->qname, ((void *)0)), address) ; } } while (0); | ||||
514 | } | ||||
515 | |||||
516 | /* create notify reply - keep same query contents */ | ||||
517 | QR_SET(query->packet)(*buffer_at((query->packet), 2) |= 0x80U); /* This is an answer. */ | ||||
518 | AA_SET(query->packet)(*buffer_at((query->packet), 2) |= 0x04U); /* we are authoritative. */ | ||||
519 | ANCOUNT_SET(query->packet, 0)(buffer_write_u16_at((query->packet), 6, (0))); | ||||
520 | NSCOUNT_SET(query->packet, 0)(buffer_write_u16_at((query->packet), 8, (0))); | ||||
521 | ARCOUNT_SET(query->packet, 0)(buffer_write_u16_at((query->packet), 10, (0))); | ||||
522 | RCODE_SET(query->packet, RCODE_OK)(*buffer_at((query->packet), 3) = (*buffer_at((query->packet ), 3) & ~0x0fU) | (0)); /* Error code. */ | ||||
523 | /* position is right after the query */ | ||||
524 | pos = buffer_position(query->packet); | ||||
525 | buffer_clear(query->packet); | ||||
526 | buffer_set_position(query->packet, pos); | ||||
527 | /* tsig is added in add_additional later (if needed) */ | ||||
528 | return QUERY_PROCESSED; | ||||
529 | } | ||||
530 | |||||
531 | if (verbosity >= 2) { | ||||
532 | char address[128]; | ||||
533 | addr2str(&query->client_addr, address, sizeof(address)); | ||||
534 | VERBOSITY(2, (LOG_INFO, "notify for %s from %s refused, %s %s",do { if ((2) <= verbosity) { log_msg (6, "notify for %s from %s refused, %s %s" , dname_to_string(query->qname, ((void *)0)), address, (why ?why->ip_address_spec:"."), (why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why->key_name ) : "no acl matches" )) ; } } while (0) | ||||
535 | dname_to_string(query->qname, NULL),do { if ((2) <= verbosity) { log_msg (6, "notify for %s from %s refused, %s %s" , dname_to_string(query->qname, ((void *)0)), address, (why ?why->ip_address_spec:"."), (why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why->key_name ) : "no acl matches" )) ; } } while (0) | ||||
536 | address,do { if ((2) <= verbosity) { log_msg (6, "notify for %s from %s refused, %s %s" , dname_to_string(query->qname, ((void *)0)), address, (why ?why->ip_address_spec:"."), (why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why->key_name ) : "no acl matches" )) ; } } while (0) | ||||
537 | (why?why->ip_address_spec:"."),do { if ((2) <= verbosity) { log_msg (6, "notify for %s from %s refused, %s %s" , dname_to_string(query->qname, ((void *)0)), address, (why ?why->ip_address_spec:"."), (why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why->key_name ) : "no acl matches" )) ; } } while (0) | ||||
538 | (why ? ( why->nokey ? "NOKEY"do { if ((2) <= verbosity) { log_msg (6, "notify for %s from %s refused, %s %s" , dname_to_string(query->qname, ((void *)0)), address, (why ?why->ip_address_spec:"."), (why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why->key_name ) : "no acl matches" )) ; } } while (0) | ||||
539 | : why->blocked ? "BLOCKED"do { if ((2) <= verbosity) { log_msg (6, "notify for %s from %s refused, %s %s" , dname_to_string(query->qname, ((void *)0)), address, (why ?why->ip_address_spec:"."), (why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why->key_name ) : "no acl matches" )) ; } } while (0) | ||||
540 | : why->key_name )do { if ((2) <= verbosity) { log_msg (6, "notify for %s from %s refused, %s %s" , dname_to_string(query->qname, ((void *)0)), address, (why ?why->ip_address_spec:"."), (why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why->key_name ) : "no acl matches" )) ; } } while (0) | ||||
541 | : "no acl matches")))do { if ((2) <= verbosity) { log_msg (6, "notify for %s from %s refused, %s %s" , dname_to_string(query->qname, ((void *)0)), address, (why ?why->ip_address_spec:"."), (why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why->key_name ) : "no acl matches" )) ; } } while (0); | ||||
542 | } | ||||
543 | |||||
544 | return query_error(query, NSD_RC_REFUSE); | ||||
545 | } | ||||
546 | |||||
547 | |||||
548 | /* | ||||
549 | * Answer a query in the CHAOS class. | ||||
550 | */ | ||||
551 | static query_state_type | ||||
552 | answer_chaos(struct nsd *nsd, query_type *q) | ||||
553 | { | ||||
554 | AA_CLR(q->packet)(*buffer_at((q->packet), 2) &= ~0x04U); | ||||
555 | switch (q->qtype) { | ||||
556 | case TYPE_ANY255: | ||||
557 | case TYPE_TXT16: | ||||
558 | if ((q->qname->name_size == 11 | ||||
559 | && memcmp(dname_name(q->qname), "\002id\006server", 11) == 0) || | ||||
560 | (q->qname->name_size == 15 | ||||
561 | && memcmp(dname_name(q->qname), "\010hostname\004bind", 15) == 0)) | ||||
562 | { | ||||
563 | if(!nsd->options->hide_identity) { | ||||
564 | /* Add ID */ | ||||
565 | query_addtxt(q, | ||||
566 | buffer_begin(q->packet) + QHEADERSZ12, | ||||
567 | CLASS_CH3, | ||||
568 | 0, | ||||
569 | nsd->identity); | ||||
570 | ANCOUNT_SET(q->packet, ANCOUNT(q->packet) + 1)(buffer_write_u16_at((q->packet), 6, ((buffer_read_u16_at( (q->packet), 6)) + 1))); | ||||
571 | } else { | ||||
572 | RCODE_SET(q->packet, RCODE_REFUSE)(*buffer_at((q->packet), 3) = (*buffer_at((q->packet), 3 ) & ~0x0fU) | (5)); | ||||
573 | /* RFC8914 - Extended DNS Errors | ||||
574 | * 4.19. Extended DNS Error Code 18 - Prohibited */ | ||||
575 | q->edns.ede = EDE_PROHIBITED18; | ||||
576 | } | ||||
577 | } else if ((q->qname->name_size == 16 | ||||
578 | && memcmp(dname_name(q->qname), "\007version\006server", 16) == 0) || | ||||
579 | (q->qname->name_size == 14 | ||||
580 | && memcmp(dname_name(q->qname), "\007version\004bind", 14) == 0)) | ||||
581 | { | ||||
582 | if(!nsd->options->hide_version) { | ||||
583 | /* Add version */ | ||||
584 | query_addtxt(q, | ||||
585 | buffer_begin(q->packet) + QHEADERSZ12, | ||||
586 | CLASS_CH3, | ||||
587 | 0, | ||||
588 | nsd->version); | ||||
589 | ANCOUNT_SET(q->packet, ANCOUNT(q->packet) + 1)(buffer_write_u16_at((q->packet), 6, ((buffer_read_u16_at( (q->packet), 6)) + 1))); | ||||
590 | } else { | ||||
591 | RCODE_SET(q->packet, RCODE_REFUSE)(*buffer_at((q->packet), 3) = (*buffer_at((q->packet), 3 ) & ~0x0fU) | (5)); | ||||
592 | /* RFC8914 - Extended DNS Errors | ||||
593 | * 4.19. Extended DNS Error Code 18 - Prohibited */ | ||||
594 | q->edns.ede = EDE_PROHIBITED18; | ||||
595 | } | ||||
596 | } else { | ||||
597 | RCODE_SET(q->packet, RCODE_REFUSE)(*buffer_at((q->packet), 3) = (*buffer_at((q->packet), 3 ) & ~0x0fU) | (5)); | ||||
598 | /* RFC8914 - Extended DNS Errors | ||||
599 | * 4.22. Extended DNS Error Code 21 - Not Supported */ | ||||
600 | q->edns.ede = EDE_NOT_SUPPORTED21; | ||||
601 | |||||
602 | } | ||||
603 | break; | ||||
604 | default: | ||||
605 | RCODE_SET(q->packet, RCODE_REFUSE)(*buffer_at((q->packet), 3) = (*buffer_at((q->packet), 3 ) & ~0x0fU) | (5)); | ||||
606 | /* RFC8914 - Extended DNS Errors | ||||
607 | * 4.22. Extended DNS Error Code 21 - Not Supported */ | ||||
608 | q->edns.ede = EDE_NOT_SUPPORTED21; | ||||
609 | break; | ||||
610 | } | ||||
611 | |||||
612 | return QUERY_PROCESSED; | ||||
613 | } | ||||
614 | |||||
615 | |||||
616 | /* | ||||
617 | * Find the covering NSEC for a non-existent domain name. Normally | ||||
618 | * the NSEC will be located at CLOSEST_MATCH, except when it is an | ||||
619 | * empty non-terminal. In this case the NSEC may be located at the | ||||
620 | * previous domain name (in canonical ordering). | ||||
621 | */ | ||||
622 | static domain_type * | ||||
623 | find_covering_nsec(domain_type *closest_match, | ||||
624 | zone_type *zone, | ||||
625 | rrset_type **nsec_rrset) | ||||
626 | { | ||||
627 | assert(closest_match)((void)0); | ||||
628 | assert(nsec_rrset)((void)0); | ||||
629 | |||||
630 | /* loop away temporary created domains. For real ones it is &RBTREE_NULL */ | ||||
631 | #ifdef USE_RADIX_TREE | ||||
632 | while (closest_match->rnode == NULL((void *)0)) | ||||
633 | #else | ||||
634 | while (closest_match->node.parent == NULL((void *)0)) | ||||
635 | #endif | ||||
636 | closest_match = closest_match->parent; | ||||
637 | while (closest_match) { | ||||
638 | *nsec_rrset = domain_find_rrset(closest_match, zone, TYPE_NSEC47); | ||||
639 | if (*nsec_rrset) { | ||||
640 | return closest_match; | ||||
641 | } | ||||
642 | if (closest_match == zone->apex) { | ||||
643 | /* Don't look outside the current zone. */ | ||||
644 | return NULL((void *)0); | ||||
645 | } | ||||
646 | closest_match = domain_previous(closest_match); | ||||
647 | } | ||||
648 | return NULL((void *)0); | ||||
649 | } | ||||
650 | |||||
651 | |||||
652 | struct additional_rr_types | ||||
653 | { | ||||
654 | uint16_t rr_type; | ||||
655 | rr_section_type rr_section; | ||||
656 | }; | ||||
657 | |||||
658 | struct additional_rr_types default_additional_rr_types[] = { | ||||
659 | { TYPE_A1, ADDITIONAL_A_SECTION }, | ||||
660 | { TYPE_AAAA28, ADDITIONAL_AAAA_SECTION }, | ||||
661 | { 0, (rr_section_type) 0 } | ||||
662 | }; | ||||
663 | |||||
664 | struct additional_rr_types swap_aaaa_additional_rr_types[] = { | ||||
665 | { TYPE_AAAA28, ADDITIONAL_A_SECTION }, | ||||
666 | { TYPE_A1, ADDITIONAL_AAAA_SECTION }, | ||||
667 | { 0, (rr_section_type) 0 } | ||||
668 | }; | ||||
669 | |||||
670 | struct additional_rr_types rt_additional_rr_types[] = { | ||||
671 | { TYPE_A1, ADDITIONAL_A_SECTION }, | ||||
672 | { TYPE_AAAA28, ADDITIONAL_AAAA_SECTION }, | ||||
673 | { TYPE_X2519, ADDITIONAL_OTHER_SECTION }, | ||||
674 | { TYPE_ISDN20, ADDITIONAL_OTHER_SECTION }, | ||||
675 | { 0, (rr_section_type) 0 } | ||||
676 | }; | ||||
677 | |||||
678 | static void | ||||
679 | add_additional_rrsets(struct query *query, answer_type *answer, | ||||
680 | rrset_type *master_rrset, size_t rdata_index, | ||||
681 | int allow_glue, struct additional_rr_types types[]) | ||||
682 | { | ||||
683 | size_t i; | ||||
684 | |||||
685 | assert(query)((void)0); | ||||
686 | assert(answer)((void)0); | ||||
687 | assert(master_rrset)((void)0); | ||||
688 | assert(rdata_atom_is_domain(rrset_rrtype(master_rrset), rdata_index))((void)0); | ||||
689 | |||||
690 | for (i = 0; i < master_rrset->rr_count; ++i) { | ||||
691 | int j; | ||||
692 | domain_type *additional = rdata_atom_domain(master_rrset->rrs[i].rdatas[rdata_index]); | ||||
693 | domain_type *match = additional; | ||||
694 | |||||
695 | assert(additional)((void)0); | ||||
696 | |||||
697 | if (!allow_glue && domain_is_glue(match, query->zone)) | ||||
698 | continue; | ||||
699 | |||||
700 | /* | ||||
701 | * Check to see if we need to generate the dependent | ||||
702 | * based on a wildcard domain. | ||||
703 | */ | ||||
704 | while (!match->is_existing) { | ||||
705 | match = match->parent; | ||||
706 | } | ||||
707 | if (additional != match && domain_wildcard_child(match)) { | ||||
708 | domain_type *wildcard_child = domain_wildcard_child(match); | ||||
709 | domain_type *temp = (domain_type *) region_alloc( | ||||
710 | query->region, sizeof(domain_type)); | ||||
711 | #ifdef USE_RADIX_TREE | ||||
712 | temp->rnode = NULL((void *)0); | ||||
713 | temp->dname = additional->dname; | ||||
714 | #else | ||||
715 | memcpy(&temp->node, &additional->node, sizeof(rbnode_type)); | ||||
716 | temp->node.parent = NULL((void *)0); | ||||
717 | #endif | ||||
718 | temp->number = additional->number; | ||||
719 | temp->parent = match; | ||||
720 | temp->wildcard_child_closest_match = temp; | ||||
721 | temp->rrsets = wildcard_child->rrsets; | ||||
722 | temp->is_existing = wildcard_child->is_existing; | ||||
723 | additional = temp; | ||||
724 | } | ||||
725 | |||||
726 | for (j = 0; types[j].rr_type != 0; ++j) { | ||||
727 | rrset_type *rrset = domain_find_rrset( | ||||
728 | additional, query->zone, types[j].rr_type); | ||||
729 | if (rrset) { | ||||
730 | answer_add_rrset(answer, types[j].rr_section, | ||||
731 | additional, rrset); | ||||
732 | } | ||||
733 | } | ||||
734 | } | ||||
735 | } | ||||
736 | |||||
737 | static int | ||||
738 | answer_needs_ns(struct query* query) | ||||
739 | { | ||||
740 | assert(query)((void)0); | ||||
741 | /* Currently, only troublesome for DNSKEY and DS, | ||||
742 | * cuz their RRSETs are quite large. */ | ||||
743 | return (query->qtype != TYPE_DNSKEY48 && query->qtype != TYPE_DS43 | ||||
744 | && query->qtype != TYPE_ANY255); | ||||
745 | } | ||||
746 | |||||
747 | static int | ||||
748 | add_rrset(struct query *query, | ||||
749 | answer_type *answer, | ||||
750 | rr_section_type section, | ||||
751 | domain_type *owner, | ||||
752 | rrset_type *rrset) | ||||
753 | { | ||||
754 | int result; | ||||
755 | |||||
756 | assert(query)((void)0); | ||||
757 | assert(answer)((void)0); | ||||
758 | assert(owner)((void)0); | ||||
759 | assert(rrset)((void)0); | ||||
760 | assert(rrset_rrclass(rrset) == CLASS_IN)((void)0); | ||||
761 | |||||
762 | result = answer_add_rrset(answer, section, owner, rrset); | ||||
763 | if(minimal_responses && section != AUTHORITY_SECTION && | ||||
764 | query->qtype != TYPE_NS2) | ||||
765 | return result; | ||||
766 | switch (rrset_rrtype(rrset)) { | ||||
767 | case TYPE_NS2: | ||||
768 | #if defined(INET6) | ||||
769 | /* if query over IPv6, swap A and AAAA; put AAAA first */ | ||||
770 | add_additional_rrsets(query, answer, rrset, 0, 1, | ||||
771 | (query->client_addr.ss_family == AF_INET624)? | ||||
772 | swap_aaaa_additional_rr_types: | ||||
773 | default_additional_rr_types); | ||||
774 | #else | ||||
775 | add_additional_rrsets(query, answer, rrset, 0, 1, | ||||
776 | default_additional_rr_types); | ||||
777 | #endif | ||||
778 | break; | ||||
779 | case TYPE_MB7: | ||||
780 | add_additional_rrsets(query, answer, rrset, 0, 0, | ||||
781 | default_additional_rr_types); | ||||
782 | break; | ||||
783 | case TYPE_MX15: | ||||
784 | case TYPE_KX36: | ||||
785 | add_additional_rrsets(query, answer, rrset, 1, 0, | ||||
786 | default_additional_rr_types); | ||||
787 | break; | ||||
788 | case TYPE_RT21: | ||||
789 | add_additional_rrsets(query, answer, rrset, 1, 0, | ||||
790 | rt_additional_rr_types); | ||||
791 | break; | ||||
792 | case TYPE_SRV33: | ||||
793 | add_additional_rrsets(query, answer, rrset, 3, 0, | ||||
794 | default_additional_rr_types); | ||||
795 | break; | ||||
796 | default: | ||||
797 | break; | ||||
798 | } | ||||
799 | |||||
800 | return result; | ||||
801 | } | ||||
802 | |||||
803 | |||||
804 | /* returns 0 on error, or the domain number for to_name. | ||||
805 | from_name is changes to to_name by the DNAME rr. | ||||
806 | DNAME rr is from src to dest. | ||||
807 | closest encloser encloses the to_name. */ | ||||
808 | static size_t | ||||
809 | query_synthesize_cname(struct query* q, struct answer* answer, const dname_type* from_name, | ||||
810 | const dname_type* to_name, domain_type* src, domain_type* to_closest_encloser, | ||||
811 | domain_type** to_closest_match, uint32_t ttl) | ||||
812 | { | ||||
813 | /* add temporary domains for from_name and to_name and all | ||||
814 | their (not allocated yet) parents */ | ||||
815 | /* any domains below src are not_existing (because of DNAME at src) */ | ||||
816 | int i; | ||||
817 | size_t j; | ||||
818 | domain_type* cname_domain; | ||||
819 | domain_type* cname_dest; | ||||
820 | rrset_type* rrset; | ||||
821 | |||||
822 | domain_type* lastparent = src; | ||||
823 | assert(q && answer && from_name && to_name && src && to_closest_encloser)((void)0); | ||||
824 | assert(to_closest_match)((void)0); | ||||
825 | |||||
826 | /* check for loop by duplicate CNAME rrset synthesized */ | ||||
827 | for(j=0; j<answer->rrset_count; ++j) { | ||||
828 | if(answer->section[j] == ANSWER_SECTION && | ||||
829 | answer->rrsets[j]->rr_count == 1 && | ||||
830 | answer->rrsets[j]->rrs[0].type == TYPE_CNAME5 && | ||||
831 | dname_compare(domain_dname(answer->rrsets[j]->rrs[0].owner), from_name) == 0 && | ||||
832 | answer->rrsets[j]->rrs[0].rdata_count == 1 && | ||||
833 | dname_compare(domain_dname(answer->rrsets[j]->rrs[0].rdatas->domain), to_name) == 0) { | ||||
834 | DEBUG(DEBUG_QUERY,2, (LOG_INFO, "loop for synthesized CNAME rrset for query %s", dname_to_string(q->qname, NULL))); | ||||
835 | return 0; | ||||
836 | } | ||||
837 | } | ||||
838 | |||||
839 | /* allocate source part */ | ||||
840 | for(i=0; i < from_name->label_count - domain_dname(src)->label_count; i++) | ||||
841 | { | ||||
842 | domain_type* newdom = query_get_tempdomain(q); | ||||
843 | if(!newdom) | ||||
844 | return 0; | ||||
845 | newdom->is_existing = 1; | ||||
846 | newdom->parent = lastparent; | ||||
847 | #ifdef USE_RADIX_TREE | ||||
848 | newdom->dname | ||||
849 | #else | ||||
850 | newdom->node.key | ||||
851 | #endif | ||||
852 | = dname_partial_copy(q->region, | ||||
853 | from_name, domain_dname(src)->label_count + i + 1); | ||||
854 | if(dname_compare(domain_dname(newdom), q->qname) == 0) { | ||||
855 | /* 0 good for query name, otherwise new number */ | ||||
856 | newdom->number = 0; | ||||
857 | } | ||||
858 | DEBUG(DEBUG_QUERY,2, (LOG_INFO, "created temp domain src %d. %s nr %d", i, | ||||
859 | domain_to_string(newdom), (int)newdom->number)); | ||||
860 | lastparent = newdom; | ||||
861 | } | ||||
862 | cname_domain = lastparent; | ||||
863 | |||||
864 | /* allocate dest part */ | ||||
865 | lastparent = to_closest_encloser; | ||||
866 | for(i=0; i < to_name->label_count - domain_dname(to_closest_encloser)->label_count; | ||||
867 | i++) | ||||
868 | { | ||||
869 | domain_type* newdom = query_get_tempdomain(q); | ||||
870 | if(!newdom) | ||||
871 | return 0; | ||||
872 | newdom->is_existing = 0; | ||||
873 | newdom->parent = lastparent; | ||||
874 | #ifdef USE_RADIX_TREE | ||||
875 | newdom->dname | ||||
876 | #else | ||||
877 | newdom->node.key | ||||
878 | #endif | ||||
879 | = dname_partial_copy(q->region, | ||||
880 | to_name, domain_dname(to_closest_encloser)->label_count + i + 1); | ||||
881 | DEBUG(DEBUG_QUERY,2, (LOG_INFO, "created temp domain dest %d. %s nr %d", i, | ||||
882 | domain_to_string(newdom), (int)newdom->number)); | ||||
883 | lastparent = newdom; | ||||
884 | } | ||||
885 | cname_dest = lastparent; | ||||
886 | *to_closest_match = cname_dest; | ||||
887 | |||||
888 | /* allocate the CNAME RR */ | ||||
889 | rrset = (rrset_type*) region_alloc(q->region, sizeof(rrset_type)); | ||||
890 | memset(rrset, 0, sizeof(rrset_type)); | ||||
891 | rrset->zone = q->zone; | ||||
892 | rrset->rr_count = 1; | ||||
893 | rrset->rrs = (rr_type*) region_alloc(q->region, sizeof(rr_type)); | ||||
894 | memset(rrset->rrs, 0, sizeof(rr_type)); | ||||
895 | rrset->rrs->owner = cname_domain; | ||||
896 | rrset->rrs->ttl = ttl; | ||||
897 | rrset->rrs->type = TYPE_CNAME5; | ||||
898 | rrset->rrs->klass = CLASS_IN1; | ||||
899 | rrset->rrs->rdata_count = 1; | ||||
900 | rrset->rrs->rdatas = (rdata_atom_type*)region_alloc(q->region, | ||||
901 | sizeof(rdata_atom_type)); | ||||
902 | rrset->rrs->rdatas->domain = cname_dest; | ||||
903 | |||||
904 | if(!add_rrset(q, answer, ANSWER_SECTION, cname_domain, rrset)) { | ||||
905 | DEBUG(DEBUG_QUERY,2, (LOG_INFO, "could not add synthesized CNAME rrset to packet for query %s", dname_to_string(q->qname, NULL))); | ||||
906 | /* failure to add CNAME; likely is a loop, the same twice */ | ||||
907 | return 0; | ||||
908 | } | ||||
909 | |||||
910 | return cname_dest->number; | ||||
911 | } | ||||
912 | |||||
913 | /* | ||||
914 | * Answer delegation information. | ||||
915 | * | ||||
916 | * DNSSEC: Include the DS RRset if present. Otherwise include an NSEC | ||||
917 | * record proving the DS RRset does not exist. | ||||
918 | */ | ||||
919 | static void | ||||
920 | answer_delegation(query_type *query, answer_type *answer) | ||||
921 | { | ||||
922 | assert(answer)((void)0); | ||||
923 | assert(query->delegation_domain)((void)0); | ||||
924 | assert(query->delegation_rrset)((void)0); | ||||
925 | |||||
926 | if (query->cname_count == 0) { | ||||
927 | AA_CLR(query->packet)(*buffer_at((query->packet), 2) &= ~0x04U); | ||||
928 | } else { | ||||
929 | AA_SET(query->packet)(*buffer_at((query->packet), 2) |= 0x04U); | ||||
930 | } | ||||
931 | |||||
932 | add_rrset(query, | ||||
933 | answer, | ||||
934 | AUTHORITY_SECTION, | ||||
935 | query->delegation_domain, | ||||
936 | query->delegation_rrset); | ||||
937 | if (query->edns.dnssec_ok && zone_is_secure(query->zone)) { | ||||
938 | rrset_type *rrset; | ||||
939 | if ((rrset = domain_find_rrset(query->delegation_domain, query->zone, TYPE_DS43))) { | ||||
940 | add_rrset(query, answer, AUTHORITY_SECTION, | ||||
941 | query->delegation_domain, rrset); | ||||
942 | #ifdef NSEC3 | ||||
943 | } else if (query->zone->nsec3_param) { | ||||
944 | nsec3_answer_delegation(query, answer); | ||||
945 | #endif | ||||
946 | } else if ((rrset = domain_find_rrset(query->delegation_domain, query->zone, TYPE_NSEC47))) { | ||||
947 | add_rrset(query, answer, AUTHORITY_SECTION, | ||||
948 | query->delegation_domain, rrset); | ||||
949 | } | ||||
950 | } | ||||
951 | } | ||||
952 | |||||
953 | |||||
954 | /* | ||||
955 | * Answer SOA information. | ||||
956 | */ | ||||
957 | static void | ||||
958 | answer_soa(struct query *query, answer_type *answer) | ||||
959 | { | ||||
960 | if (query->qclass != CLASS_ANY255) { | ||||
961 | add_rrset(query, answer, | ||||
962 | AUTHORITY_SECTION, | ||||
963 | query->zone->apex, | ||||
964 | query->zone->soa_nx_rrset); | ||||
965 | } | ||||
966 | } | ||||
967 | |||||
968 | |||||
969 | /* | ||||
970 | * Answer that the domain name exists but there is no RRset with the | ||||
971 | * requested type. | ||||
972 | * | ||||
973 | * DNSSEC: Include the correct NSEC record proving that the type does | ||||
974 | * not exist. In the wildcard no data (3.1.3.4) case the wildcard IS | ||||
975 | * NOT expanded, so the ORIGINAL parameter must point to the original | ||||
976 | * wildcard entry, not to the generated entry. | ||||
977 | */ | ||||
978 | static void | ||||
979 | answer_nodata(struct query *query, answer_type *answer, domain_type *original) | ||||
980 | { | ||||
981 | answer_soa(query, answer); | ||||
982 | |||||
983 | #ifdef NSEC3 | ||||
984 | if (query->edns.dnssec_ok && query->zone->nsec3_param) { | ||||
985 | nsec3_answer_nodata(query, answer, original); | ||||
986 | } else | ||||
987 | #endif | ||||
988 | if (query->edns.dnssec_ok && zone_is_secure(query->zone)) { | ||||
989 | domain_type *nsec_domain; | ||||
990 | rrset_type *nsec_rrset; | ||||
991 | |||||
992 | nsec_domain = find_covering_nsec(original, query->zone, &nsec_rrset); | ||||
993 | if (nsec_domain) { | ||||
994 | add_rrset(query, answer, AUTHORITY_SECTION, nsec_domain, nsec_rrset); | ||||
995 | } | ||||
996 | } | ||||
997 | } | ||||
998 | |||||
999 | static void | ||||
1000 | answer_nxdomain(query_type *query, answer_type *answer) | ||||
1001 | { | ||||
1002 | RCODE_SET(query->packet, RCODE_NXDOMAIN)(*buffer_at((query->packet), 3) = (*buffer_at((query->packet ), 3) & ~0x0fU) | (3)); | ||||
1003 | answer_soa(query, answer); | ||||
1004 | } | ||||
1005 | |||||
1006 | |||||
1007 | /* | ||||
1008 | * Answer domain information (or SOA if we do not have an RRset for | ||||
1009 | * the type specified by the query). | ||||
1010 | */ | ||||
1011 | static void | ||||
1012 | answer_domain(struct nsd* nsd, struct query *q, answer_type *answer, | ||||
1013 | domain_type *domain, domain_type *original) | ||||
1014 | { | ||||
1015 | rrset_type *rrset; | ||||
1016 | |||||
1017 | if (q->qtype == TYPE_ANY255) { | ||||
1018 | rrset_type *preferred_rrset = NULL((void *)0); | ||||
1019 | rrset_type *normal_rrset = NULL((void *)0); | ||||
1020 | rrset_type *non_preferred_rrset = NULL((void *)0); | ||||
1021 | |||||
1022 | /* | ||||
1023 | * Minimize response size for ANY, with one RRset | ||||
1024 | * according to RFC 8482(4.1). | ||||
1025 | * Prefers popular and not large rtypes (A,AAAA,...) | ||||
1026 | * lowering large ones (DNSKEY,RRSIG,...). | ||||
1027 | */ | ||||
1028 | for (rrset = domain_find_any_rrset(domain, q->zone); rrset; rrset = rrset->next) { | ||||
1029 | if (rrset->zone == q->zone | ||||
1030 | #ifdef NSEC3 | ||||
1031 | && rrset_rrtype(rrset) != TYPE_NSEC350 | ||||
1032 | #endif | ||||
1033 | /* | ||||
1034 | * Don't include the RRSIG RRset when | ||||
1035 | * DNSSEC is used, because it is added | ||||
1036 | * automatically on an per-RRset basis. | ||||
1037 | */ | ||||
1038 | && !(q->edns.dnssec_ok | ||||
1039 | && zone_is_secure(q->zone) | ||||
1040 | && rrset_rrtype(rrset) == TYPE_RRSIG46)) | ||||
1041 | { | ||||
1042 | switch(rrset_rrtype(rrset)) { | ||||
1043 | case TYPE_A1: | ||||
1044 | case TYPE_AAAA28: | ||||
1045 | case TYPE_SOA6: | ||||
1046 | case TYPE_MX15: | ||||
1047 | case TYPE_PTR12: | ||||
1048 | preferred_rrset = rrset; | ||||
1049 | break; | ||||
1050 | case TYPE_DNSKEY48: | ||||
1051 | case TYPE_RRSIG46: | ||||
1052 | case TYPE_NSEC47: | ||||
1053 | non_preferred_rrset = rrset; | ||||
1054 | break; | ||||
1055 | default: | ||||
1056 | normal_rrset = rrset; | ||||
1057 | } | ||||
1058 | if (preferred_rrset) break; | ||||
1059 | } | ||||
1060 | } | ||||
1061 | if (preferred_rrset) { | ||||
1062 | add_rrset(q, answer, ANSWER_SECTION, domain, preferred_rrset); | ||||
1063 | } else if (normal_rrset) { | ||||
1064 | add_rrset(q, answer, ANSWER_SECTION, domain, normal_rrset); | ||||
1065 | } else if (non_preferred_rrset) { | ||||
1066 | add_rrset(q, answer, ANSWER_SECTION, domain, non_preferred_rrset); | ||||
1067 | } else { | ||||
1068 | answer_nodata(q, answer, original); | ||||
1069 | return; | ||||
1070 | } | ||||
1071 | #ifdef NSEC3 | ||||
1072 | } else if (q->qtype == TYPE_NSEC350) { | ||||
1073 | answer_nodata(q, answer, original); | ||||
1074 | return; | ||||
1075 | #endif | ||||
1076 | } else if ((rrset = domain_find_rrset(domain, q->zone, q->qtype))) { | ||||
1077 | add_rrset(q, answer, ANSWER_SECTION, domain, rrset); | ||||
1078 | } else if ((rrset = domain_find_rrset(domain, q->zone, TYPE_CNAME5))) { | ||||
1079 | int added; | ||||
1080 | |||||
1081 | /* | ||||
1082 | * If the CNAME is not added it is already in the | ||||
1083 | * answer, so we have a CNAME loop. Don't follow the | ||||
1084 | * CNAME target in this case. | ||||
1085 | */ | ||||
1086 | added = add_rrset(q, answer, ANSWER_SECTION, domain, rrset); | ||||
1087 | assert(rrset->rr_count > 0)((void)0); | ||||
1088 | if (added) { | ||||
1089 | /* only process first CNAME record */ | ||||
1090 | domain_type *closest_match = rdata_atom_domain(rrset->rrs[0].rdatas[0]); | ||||
1091 | domain_type *closest_encloser = closest_match; | ||||
1092 | zone_type* origzone = q->zone; | ||||
1093 | ++q->cname_count; | ||||
1094 | |||||
1095 | answer_lookup_zone(nsd, q, answer, closest_match->number, | ||||
1096 | closest_match == closest_encloser, | ||||
1097 | closest_match, closest_encloser, | ||||
1098 | domain_dname(closest_match)); | ||||
1099 | q->zone = origzone; | ||||
1100 | } | ||||
1101 | return; | ||||
1102 | } else { | ||||
1103 | answer_nodata(q, answer, original); | ||||
1104 | return; | ||||
1105 | } | ||||
1106 | |||||
1107 | if (q->qclass != CLASS_ANY255 && q->zone->ns_rrset && answer_needs_ns(q) | ||||
1108 | && !minimal_responses) { | ||||
1109 | add_rrset(q, answer, OPTIONAL_AUTHORITY_SECTION, q->zone->apex, | ||||
1110 | q->zone->ns_rrset); | ||||
1111 | } | ||||
1112 | } | ||||
1113 | |||||
1114 | |||||
1115 | /* | ||||
1116 | * Answer with authoritative data. If a wildcard is matched the owner | ||||
1117 | * name will be expanded to the domain name specified by | ||||
1118 | * DOMAIN_NUMBER. DOMAIN_NUMBER 0 (zero) is reserved for the original | ||||
1119 | * query name. | ||||
1120 | * | ||||
1121 | * DNSSEC: Include the necessary NSEC records in case the request | ||||
1122 | * domain name does not exist and/or a wildcard match does not exist. | ||||
1123 | */ | ||||
1124 | static void | ||||
1125 | answer_authoritative(struct nsd *nsd, | ||||
1126 | struct query *q, | ||||
1127 | answer_type *answer, | ||||
1128 | size_t domain_number, | ||||
1129 | int exact, | ||||
1130 | domain_type *closest_match, | ||||
1131 | domain_type *closest_encloser, | ||||
1132 | const dname_type *qname) | ||||
1133 | { | ||||
1134 | domain_type *match; | ||||
1135 | domain_type *original = closest_match; | ||||
1136 | domain_type *dname_ce; | ||||
1137 | domain_type *wildcard_child; | ||||
1138 | rrset_type *rrset; | ||||
1139 | |||||
1140 | #ifdef NSEC3 | ||||
1141 | if(exact
| ||||
1142 | exact = 0; /* pretend it does not exist */ | ||||
1143 | if(closest_encloser->parent) | ||||
| |||||
1144 | closest_encloser = closest_encloser->parent; | ||||
1145 | } | ||||
1146 | #endif /* NSEC3 */ | ||||
1147 | if((dname_ce = find_dname_above(closest_encloser, q->zone)) != NULL((void *)0)) { | ||||
1148 | /* occlude the found data, the DNAME is closest_encloser */ | ||||
1149 | closest_encloser = dname_ce; | ||||
1150 | exact = 0; | ||||
1151 | } | ||||
1152 | |||||
1153 | if (exact) { | ||||
1154 | match = closest_match; | ||||
1155 | } else if ((rrset=domain_find_rrset(closest_encloser, q->zone, TYPE_DNAME39))) { | ||||
1156 | /* process DNAME */ | ||||
1157 | const dname_type* name = qname; | ||||
1158 | domain_type* src = closest_encloser; | ||||
1159 | domain_type *dest = rdata_atom_domain(rrset->rrs[0].rdatas[0]); | ||||
1160 | const dname_type* newname; | ||||
1161 | size_t newnum = 0; | ||||
1162 | zone_type* origzone = q->zone; | ||||
1163 | assert(rrset->rr_count > 0)((void)0); | ||||
1164 | if(domain_number != 0) /* we followed CNAMEs or DNAMEs */ | ||||
1165 | name = domain_dname(closest_match); | ||||
1166 | DEBUG(DEBUG_QUERY,2, (LOG_INFO, "expanding DNAME for q=%s", dname_to_string(name, NULL))); | ||||
1167 | DEBUG(DEBUG_QUERY,2, (LOG_INFO, "->src is %s", | ||||
1168 | domain_to_string(closest_encloser))); | ||||
1169 | DEBUG(DEBUG_QUERY,2, (LOG_INFO, "->dest is %s", | ||||
1170 | domain_to_string(dest))); | ||||
1171 | if(!add_rrset(q, answer, ANSWER_SECTION, closest_encloser, rrset)) { | ||||
1172 | /* stop if DNAME loops, when added second time */ | ||||
1173 | if(dname_is_subdomain(domain_dname(dest), domain_dname(src))) { | ||||
1174 | return; | ||||
1175 | } | ||||
1176 | } | ||||
1177 | newname = dname_replace(q->region, name, | ||||
1178 | domain_dname(src), domain_dname(dest)); | ||||
1179 | ++q->cname_count; | ||||
1180 | if(!newname) { /* newname too long */ | ||||
1181 | RCODE_SET(q->packet, RCODE_YXDOMAIN)(*buffer_at((q->packet), 3) = (*buffer_at((q->packet), 3 ) & ~0x0fU) | (6)); | ||||
1182 | /* RFC 8914 - Extended DNS Errors | ||||
1183 | * 4.21. Extended DNS Error Code 0 - Other */ | ||||
1184 | ASSIGN_EDE_CODE_AND_STRING_LITERAL(q->edns.ede,do { q->edns.ede = (0); q->edns.ede_text = ("DNAME expansion became too large" ""); q->edns.ede_text_len = sizeof("DNAME expansion became too large" ) - 1; } while (0) | ||||
1185 | EDE_OTHER, "DNAME expansion became too large")do { q->edns.ede = (0); q->edns.ede_text = ("DNAME expansion became too large" ""); q->edns.ede_text_len = sizeof("DNAME expansion became too large" ) - 1; } while (0); | ||||
1186 | return; | ||||
1187 | } | ||||
1188 | DEBUG(DEBUG_QUERY,2, (LOG_INFO, "->result is %s", dname_to_string(newname, NULL))); | ||||
1189 | /* follow the DNAME */ | ||||
1190 | (void)namedb_lookup(nsd->db, newname, &closest_match, &closest_encloser); | ||||
1191 | /* synthesize CNAME record */ | ||||
1192 | newnum = query_synthesize_cname(q, answer, name, newname, | ||||
1193 | src, closest_encloser, &closest_match, rrset->rrs[0].ttl); | ||||
1194 | if(!newnum) { | ||||
1195 | /* could not synthesize the CNAME. */ | ||||
1196 | /* return previous CNAMEs to make resolver recurse for us */ | ||||
1197 | return; | ||||
1198 | } | ||||
1199 | if(q->qtype == TYPE_CNAME5) { | ||||
1200 | /* The synthesized CNAME is the answer to | ||||
1201 | * that query, same as BIND does for query | ||||
1202 | * of type CNAME */ | ||||
1203 | return; | ||||
1204 | } | ||||
1205 | |||||
1206 | answer_lookup_zone(nsd, q, answer, newnum, | ||||
1207 | closest_match == closest_encloser, | ||||
1208 | closest_match, closest_encloser, newname); | ||||
1209 | q->zone = origzone; | ||||
1210 | return; | ||||
1211 | } else if ((wildcard_child=domain_wildcard_child(closest_encloser))!=NULL((void *)0) && | ||||
1212 | wildcard_child->is_existing) { | ||||
1213 | /* Generate the domain from the wildcard. */ | ||||
1214 | #ifdef RATELIMIT | ||||
1215 | q->wildcard_domain = wildcard_child; | ||||
1216 | #endif | ||||
1217 | |||||
1218 | match = (domain_type *) region_alloc(q->region, | ||||
1219 | sizeof(domain_type)); | ||||
1220 | #ifdef USE_RADIX_TREE | ||||
1221 | match->rnode = NULL((void *)0); | ||||
1222 | match->dname = wildcard_child->dname; | ||||
1223 | #else | ||||
1224 | memcpy(&match->node, &wildcard_child->node, sizeof(rbnode_type)); | ||||
1225 | match->node.parent = NULL((void *)0); | ||||
1226 | #endif | ||||
1227 | match->parent = closest_encloser; | ||||
1228 | match->wildcard_child_closest_match = match; | ||||
1229 | match->number = domain_number; | ||||
1230 | match->rrsets = wildcard_child->rrsets; | ||||
1231 | match->is_existing = wildcard_child->is_existing; | ||||
1232 | #ifdef NSEC3 | ||||
1233 | match->nsec3 = wildcard_child->nsec3; | ||||
1234 | /* copy over these entries: | ||||
1235 | match->nsec3_is_exact = wildcard_child->nsec3_is_exact; | ||||
1236 | match->nsec3_cover = wildcard_child->nsec3_cover; | ||||
1237 | match->nsec3_wcard_child_cover = wildcard_child->nsec3_wcard_child_cover; | ||||
1238 | match->nsec3_ds_parent_is_exact = wildcard_child->nsec3_ds_parent_is_exact; | ||||
1239 | match->nsec3_ds_parent_cover = wildcard_child->nsec3_ds_parent_cover; | ||||
1240 | */ | ||||
1241 | |||||
1242 | if (q->edns.dnssec_ok && q->zone->nsec3_param) { | ||||
1243 | /* Only add nsec3 wildcard data when do bit is set */ | ||||
1244 | nsec3_answer_wildcard(q, answer, wildcard_child, qname); | ||||
1245 | } | ||||
1246 | #endif | ||||
1247 | |||||
1248 | /* | ||||
1249 | * Remember the original domain in case a Wildcard No | ||||
1250 | * Data (3.1.3.4) response needs to be generated. In | ||||
1251 | * this particular case the wildcard IS NOT | ||||
1252 | * expanded. | ||||
1253 | */ | ||||
1254 | original = wildcard_child; | ||||
1255 | } else { | ||||
1256 | match = NULL((void *)0); | ||||
1257 | } | ||||
1258 | |||||
1259 | /* Authoritative zone. */ | ||||
1260 | #ifdef NSEC3 | ||||
1261 | if (q->edns.dnssec_ok && q->zone->nsec3_param) { | ||||
1262 | nsec3_answer_authoritative(&match, q, answer, | ||||
1263 | closest_encloser, qname); | ||||
1264 | } else | ||||
1265 | #endif | ||||
1266 | if (q->edns.dnssec_ok && zone_is_secure(q->zone)) { | ||||
1267 | if (match != closest_encloser) { | ||||
1268 | domain_type *nsec_domain; | ||||
1269 | rrset_type *nsec_rrset; | ||||
1270 | |||||
1271 | /* | ||||
1272 | * No match found or generated from wildcard, | ||||
1273 | * include NSEC record. | ||||
1274 | */ | ||||
1275 | nsec_domain = find_covering_nsec(closest_match, q->zone, &nsec_rrset); | ||||
1276 | if (nsec_domain) { | ||||
1277 | add_rrset(q, answer, AUTHORITY_SECTION, nsec_domain, nsec_rrset); | ||||
1278 | } | ||||
1279 | } | ||||
1280 | if (!match) { | ||||
1281 | domain_type *nsec_domain; | ||||
1282 | rrset_type *nsec_rrset; | ||||
1283 | |||||
1284 | /* | ||||
1285 | * No match and no wildcard. Include NSEC | ||||
1286 | * proving there is no wildcard. | ||||
1287 | */ | ||||
1288 | if(closest_encloser && (nsec_domain = | ||||
1289 | find_covering_nsec(closest_encloser-> | ||||
1290 | wildcard_child_closest_match, q->zone, | ||||
1291 | &nsec_rrset)) != NULL((void *)0)) { | ||||
1292 | add_rrset(q, answer, AUTHORITY_SECTION, nsec_domain, nsec_rrset); | ||||
1293 | } | ||||
1294 | } | ||||
1295 | } | ||||
1296 | |||||
1297 | #ifdef NSEC3 | ||||
1298 | if (RCODE(q->packet)(*buffer_at((q->packet), 3) & 0x0fU)!=RCODE_OK0) { | ||||
1299 | return; /* nsec3 collision failure */ | ||||
1300 | } | ||||
1301 | #endif | ||||
1302 | if (match) { | ||||
1303 | answer_domain(nsd, q, answer, match, original); | ||||
1304 | } else { | ||||
1305 | answer_nxdomain(q, answer); | ||||
1306 | } | ||||
1307 | } | ||||
1308 | |||||
1309 | /* | ||||
1310 | * qname may be different after CNAMEs have been followed from query->qname. | ||||
1311 | */ | ||||
1312 | static void | ||||
1313 | answer_lookup_zone(struct nsd *nsd, struct query *q, answer_type *answer, | ||||
1314 | size_t domain_number, int exact, domain_type *closest_match, | ||||
1315 | domain_type *closest_encloser, const dname_type *qname) | ||||
1316 | { | ||||
1317 | zone_type* origzone = q->zone; | ||||
1318 | q->zone = domain_find_zone(nsd->db, closest_encloser); | ||||
1319 | if (!q->zone) { | ||||
| |||||
1320 | /* no zone for this */ | ||||
1321 | if(q->cname_count == 0) { | ||||
1322 | RCODE_SET(q->packet, RCODE_REFUSE)(*buffer_at((q->packet), 3) = (*buffer_at((q->packet), 3 ) & ~0x0fU) | (5)); | ||||
1323 | /* RFC 8914 - Extended DNS Errors | ||||
1324 | * 4.21. Extended DNS Error Code 20 - Not Authoritative */ | ||||
1325 | q->edns.ede = EDE_NOT_AUTHORITATIVE20; | ||||
1326 | } | ||||
1327 | return; | ||||
1328 | } | ||||
1329 | assert(closest_encloser)((void)0); /* otherwise, no q->zone would be found */ | ||||
1330 | if(q->zone->opts && q->zone->opts->pattern | ||||
1331 | && q->zone->opts->pattern->allow_query) { | ||||
1332 | struct acl_options *why = NULL((void *)0); | ||||
1333 | |||||
1334 | /* check if it passes acl */ | ||||
1335 | if(q->is_proxied && acl_check_incoming_block_proxy( | ||||
1336 | q->zone->opts->pattern->allow_query, q, &why) == -1) { | ||||
1337 | /* the proxy address is blocked */ | ||||
1338 | if (verbosity >= 2) { | ||||
1339 | char address[128], proxy[128]; | ||||
1340 | addr2str(&q->client_addr, address, sizeof(address)); | ||||
1341 | addr2str(&q->remote_addr, proxy, sizeof(proxy)); | ||||
1342 | VERBOSITY(2, (LOG_INFO, "query %s from %s via proxy %s refused because of proxy, %s %s",do { if ((2) <= verbosity) { log_msg (6, "query %s from %s via proxy %s refused because of proxy, %s %s" , dname_to_string(q->qname, ((void *)0)), address, proxy, ( why?why->ip_address_spec:"."), (why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why->key_name ) : "no acl matches" )) ; } } while (0) | ||||
1343 | dname_to_string(q->qname, NULL),do { if ((2) <= verbosity) { log_msg (6, "query %s from %s via proxy %s refused because of proxy, %s %s" , dname_to_string(q->qname, ((void *)0)), address, proxy, ( why?why->ip_address_spec:"."), (why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why->key_name ) : "no acl matches" )) ; } } while (0) | ||||
1344 | address, proxy,do { if ((2) <= verbosity) { log_msg (6, "query %s from %s via proxy %s refused because of proxy, %s %s" , dname_to_string(q->qname, ((void *)0)), address, proxy, ( why?why->ip_address_spec:"."), (why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why->key_name ) : "no acl matches" )) ; } } while (0) | ||||
1345 | (why?why->ip_address_spec:"."),do { if ((2) <= verbosity) { log_msg (6, "query %s from %s via proxy %s refused because of proxy, %s %s" , dname_to_string(q->qname, ((void *)0)), address, proxy, ( why?why->ip_address_spec:"."), (why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why->key_name ) : "no acl matches" )) ; } } while (0) | ||||
1346 | (why ? ( why->nokey ? "NOKEY"do { if ((2) <= verbosity) { log_msg (6, "query %s from %s via proxy %s refused because of proxy, %s %s" , dname_to_string(q->qname, ((void *)0)), address, proxy, ( why?why->ip_address_spec:"."), (why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why->key_name ) : "no acl matches" )) ; } } while (0) | ||||
1347 | : why->blocked ? "BLOCKED"do { if ((2) <= verbosity) { log_msg (6, "query %s from %s via proxy %s refused because of proxy, %s %s" , dname_to_string(q->qname, ((void *)0)), address, proxy, ( why?why->ip_address_spec:"."), (why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why->key_name ) : "no acl matches" )) ; } } while (0) | ||||
1348 | : why->key_name )do { if ((2) <= verbosity) { log_msg (6, "query %s from %s via proxy %s refused because of proxy, %s %s" , dname_to_string(q->qname, ((void *)0)), address, proxy, ( why?why->ip_address_spec:"."), (why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why->key_name ) : "no acl matches" )) ; } } while (0) | ||||
1349 | : "no acl matches")))do { if ((2) <= verbosity) { log_msg (6, "query %s from %s via proxy %s refused because of proxy, %s %s" , dname_to_string(q->qname, ((void *)0)), address, proxy, ( why?why->ip_address_spec:"."), (why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why->key_name ) : "no acl matches" )) ; } } while (0); | ||||
1350 | } | ||||
1351 | /* no zone for this */ | ||||
1352 | if(q->cname_count == 0) { | ||||
1353 | RCODE_SET(q->packet, RCODE_REFUSE)(*buffer_at((q->packet), 3) = (*buffer_at((q->packet), 3 ) & ~0x0fU) | (5)); | ||||
1354 | /* RFC8914 - Extended DNS Errors | ||||
1355 | * 4.19. Extended DNS Error Code 18 - Prohibited */ | ||||
1356 | q->edns.ede = EDE_PROHIBITED18; | ||||
1357 | } | ||||
1358 | return; | ||||
1359 | } | ||||
1360 | if(acl_check_incoming( | ||||
1361 | q->zone->opts->pattern->allow_query, q, &why) != -1) { | ||||
1362 | assert(why)((void)0); | ||||
1363 | DEBUG(DEBUG_QUERY,1, (LOG_INFO, "query %s passed acl %s %s", | ||||
1364 | dname_to_string(q->qname, NULL), | ||||
1365 | why->ip_address_spec, | ||||
1366 | why->nokey?"NOKEY": | ||||
1367 | (why->blocked?"BLOCKED":why->key_name))); | ||||
1368 | } else { | ||||
1369 | if (verbosity >= 2) { | ||||
1370 | char address[128]; | ||||
1371 | addr2str(&q->client_addr, address, sizeof(address)); | ||||
1372 | VERBOSITY(2, (LOG_INFO, "query %s from %s refused, %s %s",do { if ((2) <= verbosity) { log_msg (6, "query %s from %s refused, %s %s" , dname_to_string(q->qname, ((void *)0)), address, why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why-> key_name ) : "no acl matches", why?why->ip_address_spec:"." ) ; } } while (0) | ||||
1373 | dname_to_string(q->qname, NULL),do { if ((2) <= verbosity) { log_msg (6, "query %s from %s refused, %s %s" , dname_to_string(q->qname, ((void *)0)), address, why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why-> key_name ) : "no acl matches", why?why->ip_address_spec:"." ) ; } } while (0) | ||||
1374 | address,do { if ((2) <= verbosity) { log_msg (6, "query %s from %s refused, %s %s" , dname_to_string(q->qname, ((void *)0)), address, why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why-> key_name ) : "no acl matches", why?why->ip_address_spec:"." ) ; } } while (0) | ||||
1375 | why ? ( why->nokey ? "NOKEY"do { if ((2) <= verbosity) { log_msg (6, "query %s from %s refused, %s %s" , dname_to_string(q->qname, ((void *)0)), address, why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why-> key_name ) : "no acl matches", why?why->ip_address_spec:"." ) ; } } while (0) | ||||
1376 | : why->blocked ? "BLOCKED"do { if ((2) <= verbosity) { log_msg (6, "query %s from %s refused, %s %s" , dname_to_string(q->qname, ((void *)0)), address, why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why-> key_name ) : "no acl matches", why?why->ip_address_spec:"." ) ; } } while (0) | ||||
1377 | : why->key_name )do { if ((2) <= verbosity) { log_msg (6, "query %s from %s refused, %s %s" , dname_to_string(q->qname, ((void *)0)), address, why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why-> key_name ) : "no acl matches", why?why->ip_address_spec:"." ) ; } } while (0) | ||||
1378 | : "no acl matches",do { if ((2) <= verbosity) { log_msg (6, "query %s from %s refused, %s %s" , dname_to_string(q->qname, ((void *)0)), address, why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why-> key_name ) : "no acl matches", why?why->ip_address_spec:"." ) ; } } while (0) | ||||
1379 | why?why->ip_address_spec:"."))do { if ((2) <= verbosity) { log_msg (6, "query %s from %s refused, %s %s" , dname_to_string(q->qname, ((void *)0)), address, why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why-> key_name ) : "no acl matches", why?why->ip_address_spec:"." ) ; } } while (0); | ||||
1380 | } | ||||
1381 | /* no zone for this */ | ||||
1382 | if(q->cname_count == 0) { | ||||
1383 | RCODE_SET(q->packet, RCODE_REFUSE)(*buffer_at((q->packet), 3) = (*buffer_at((q->packet), 3 ) & ~0x0fU) | (5)); | ||||
1384 | /* RFC8914 - Extended DNS Errors | ||||
1385 | * 4.19. Extended DNS Error Code 18 - Prohibited */ | ||||
1386 | q->edns.ede = EDE_PROHIBITED18; | ||||
1387 | } | ||||
1388 | return; | ||||
1389 | } | ||||
1390 | } | ||||
1391 | if(!q->zone->apex || !q->zone->soa_rrset) { | ||||
1392 | /* zone is configured but not loaded */ | ||||
1393 | if(q->cname_count == 0) { | ||||
1394 | RCODE_SET(q->packet, RCODE_SERVFAIL)(*buffer_at((q->packet), 3) = (*buffer_at((q->packet), 3 ) & ~0x0fU) | (2)); | ||||
1395 | /* RFC 8914 - Extended DNS Errors | ||||
1396 | * 4.15. Extended DNS Error Code 14 - Not Ready */ | ||||
1397 | q->edns.ede = EDE_NOT_READY14; | ||||
1398 | ASSIGN_EDE_CODE_AND_STRING_LITERAL(q->edns.ede,do { q->edns.ede = (14); q->edns.ede_text = ("Zone is configured but not loaded" ""); q->edns.ede_text_len = sizeof("Zone is configured but not loaded" ) - 1; } while (0) | ||||
1399 | EDE_NOT_READY, "Zone is configured but not loaded")do { q->edns.ede = (14); q->edns.ede_text = ("Zone is configured but not loaded" ""); q->edns.ede_text_len = sizeof("Zone is configured but not loaded" ) - 1; } while (0); | ||||
1400 | } | ||||
1401 | return; | ||||
1402 | } | ||||
1403 | |||||
1404 | /* | ||||
1405 | * If confine-to-zone is set to yes do not return additional | ||||
1406 | * information for a zone with a different apex from the query zone. | ||||
1407 | */ | ||||
1408 | if (nsd->options->confine_to_zone && | ||||
1409 | (origzone != NULL((void *)0) && dname_compare(domain_dname(origzone->apex), domain_dname(q->zone->apex)) != 0)) { | ||||
1410 | return; | ||||
1411 | } | ||||
1412 | |||||
1413 | /* now move up the closest encloser until it exists, previous | ||||
1414 | * (possibly empty) closest encloser was useful to finding the zone | ||||
1415 | * (for empty zones too), but now we want actual data nodes */ | ||||
1416 | if (closest_encloser && !closest_encloser->is_existing) { | ||||
1417 | exact = 0; | ||||
1418 | while (closest_encloser != NULL((void *)0) && !closest_encloser->is_existing) | ||||
1419 | closest_encloser = closest_encloser->parent; | ||||
1420 | } | ||||
1421 | |||||
1422 | /* | ||||
1423 | * See RFC 4035 (DNSSEC protocol) section 3.1.4.1 Responding | ||||
1424 | * to Queries for DS RRs. | ||||
1425 | */ | ||||
1426 | if (exact && q->qtype == TYPE_DS43 && closest_encloser == q->zone->apex) { | ||||
1427 | /* | ||||
1428 | * Type DS query at a zone cut, use the responsible | ||||
1429 | * parent zone to generate the answer if we are | ||||
1430 | * authoritative for the parent zone. | ||||
1431 | */ | ||||
1432 | zone_type *zone = domain_find_parent_zone(nsd->db, q->zone); | ||||
1433 | if (zone) { | ||||
1434 | q->zone = zone; | ||||
1435 | if(!q->zone->apex || !q->zone->soa_rrset) { | ||||
1436 | /* zone is configured but not loaded */ | ||||
1437 | if(q->cname_count == 0) { | ||||
1438 | RCODE_SET(q->packet, RCODE_SERVFAIL)(*buffer_at((q->packet), 3) = (*buffer_at((q->packet), 3 ) & ~0x0fU) | (2)); | ||||
1439 | /* RFC 8914 - Extended DNS Errors | ||||
1440 | * 4.15. Extended DNS Error Code 14 - Not Ready */ | ||||
1441 | ASSIGN_EDE_CODE_AND_STRING_LITERAL(do { q->edns.ede = (14); q->edns.ede_text = ("Zone is configured but not loaded" ""); q->edns.ede_text_len = sizeof("Zone is configured but not loaded" ) - 1; } while (0) | ||||
1442 | q->edns.ede, EDE_NOT_READY,do { q->edns.ede = (14); q->edns.ede_text = ("Zone is configured but not loaded" ""); q->edns.ede_text_len = sizeof("Zone is configured but not loaded" ) - 1; } while (0) | ||||
1443 | "Zone is configured but not loaded")do { q->edns.ede = (14); q->edns.ede_text = ("Zone is configured but not loaded" ""); q->edns.ede_text_len = sizeof("Zone is configured but not loaded" ) - 1; } while (0); | ||||
1444 | } | ||||
1445 | return; | ||||
1446 | } | ||||
1447 | } | ||||
1448 | } | ||||
1449 | |||||
1450 | /* see if the zone has expired (for secondary zones) */ | ||||
1451 | if(q->zone
| ||||
1452 | q->zone->opts->pattern->request_xfr != 0 && !q->zone->is_ok) { | ||||
1453 | if(q->cname_count == 0) { | ||||
1454 | RCODE_SET(q->packet, RCODE_SERVFAIL)(*buffer_at((q->packet), 3) = (*buffer_at((q->packet), 3 ) & ~0x0fU) | (2)); | ||||
1455 | /* RFC 8914 - Extended DNS Errors | ||||
1456 | * 4.25. Extended DNS Error Code 24 - Invalid Data */ | ||||
1457 | ASSIGN_EDE_CODE_AND_STRING_LITERAL(q->edns.ede,do { q->edns.ede = (24); q->edns.ede_text = ("Zone has expired" ""); q->edns.ede_text_len = sizeof("Zone has expired") - 1 ; } while (0) | ||||
1458 | EDE_INVALID_DATA, "Zone has expired")do { q->edns.ede = (24); q->edns.ede_text = ("Zone has expired" ""); q->edns.ede_text_len = sizeof("Zone has expired") - 1 ; } while (0); | ||||
1459 | } | ||||
1460 | return; | ||||
1461 | } | ||||
1462 | |||||
1463 | if (exact
| ||||
1464 | /* | ||||
1465 | * Type DS query at the zone apex (and the server is | ||||
1466 | * not authoritative for the parent zone). | ||||
1467 | */ | ||||
1468 | if (q->qclass == CLASS_ANY255) { | ||||
1469 | AA_CLR(q->packet)(*buffer_at((q->packet), 2) &= ~0x04U); | ||||
1470 | } else { | ||||
1471 | AA_SET(q->packet)(*buffer_at((q->packet), 2) |= 0x04U); | ||||
1472 | } | ||||
1473 | answer_nodata(q, answer, closest_encloser); | ||||
1474 | } else { | ||||
1475 | q->delegation_domain = domain_find_ns_rrsets( | ||||
1476 | closest_encloser, q->zone, &q->delegation_rrset); | ||||
1477 | if(q->delegation_domain && find_dname_above(q->delegation_domain, q->zone)) { | ||||
1478 | q->delegation_domain = NULL((void *)0); /* use higher DNAME */ | ||||
1479 | } | ||||
1480 | |||||
1481 | if (!q->delegation_domain |
10.1 | Field 'delegation_domain' is null |