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