| File: | src/usr.sbin/nsd/namedb.h |
| Warning: | line 275, 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->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
|
9.1 | Field 'delegation_domain' is null |
| 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 | struct zone_ixfr; | |||
| 25 | ||||
| 26 | typedef union rdata_atom rdata_atom_type; | |||
| 27 | typedef struct rrset rrset_type; | |||
| 28 | typedef struct rr rr_type; | |||
| 29 | ||||
| 30 | /* | |||
| 31 | * A domain name table supporting fast insert and search operations. | |||
| 32 | */ | |||
| 33 | typedef struct domain_table domain_table_type; | |||
| 34 | typedef struct domain domain_type; | |||
| 35 | typedef struct zone zone_type; | |||
| 36 | typedef struct namedb namedb_type; | |||
| 37 | ||||
| 38 | struct domain_table | |||
| 39 | { | |||
| 40 | region_type* region; | |||
| 41 | #ifdef USE_RADIX_TREE | |||
| 42 | struct radtree *nametree; | |||
| 43 | #else | |||
| 44 | rbtree_type *names_to_domains; | |||
| 45 | #endif | |||
| 46 | domain_type* root; | |||
| 47 | /* ptr to biggest domain.number and last in list. | |||
| 48 | * the root is the lowest and first in the list. */ | |||
| 49 | domain_type *numlist_last; | |||
| 50 | #ifdef NSEC3 | |||
| 51 | /* the prehash list, start of the list */ | |||
| 52 | domain_type* prehash_list; | |||
| 53 | #endif /* NSEC3 */ | |||
| 54 | }; | |||
| 55 | ||||
| 56 | #ifdef NSEC3 | |||
| 57 | typedef struct nsec3_hash_node nsec3_hash_node_type; | |||
| 58 | struct nsec3_hash_node { | |||
| 59 | /* hash value */ | |||
| 60 | uint8_t hash[NSEC3_HASH_LEN20]; | |||
| 61 | /* entry in the hashtree */ | |||
| 62 | rbnode_type node; | |||
| 63 | } ATTR_PACKED; | |||
| 64 | ||||
| 65 | typedef struct nsec3_hash_wc_node nsec3_hash_wc_node_type; | |||
| 66 | struct nsec3_hash_wc_node { | |||
| 67 | nsec3_hash_node_type hash; | |||
| 68 | nsec3_hash_node_type wc; | |||
| 69 | }; | |||
| 70 | ||||
| 71 | struct nsec3_domain_data { | |||
| 72 | /* (if nsec3 chain complete) always the covering nsec3 record */ | |||
| 73 | domain_type* nsec3_cover; | |||
| 74 | /* the nsec3 that covers the wildcard child of this domain. */ | |||
| 75 | domain_type* nsec3_wcard_child_cover; | |||
| 76 | /* for the DS case we must answer on the parent side of zone cut */ | |||
| 77 | domain_type* nsec3_ds_parent_cover; | |||
| 78 | /* NSEC3 domains to prehash, prev and next on the list or cleared */ | |||
| 79 | domain_type* prehash_prev, *prehash_next; | |||
| 80 | /* entry in the nsec3tree (for NSEC3s in the chain in use) */ | |||
| 81 | rbnode_type nsec3_node; | |||
| 82 | ||||
| 83 | /* node for the precompiled domain and the precompiled wildcard */ | |||
| 84 | nsec3_hash_wc_node_type* hash_wc; | |||
| 85 | ||||
| 86 | /* node for the precompiled parent ds */ | |||
| 87 | nsec3_hash_node_type* ds_parent_hash; | |||
| 88 | ||||
| 89 | /* if the domain has an NSEC3 for it, use cover ptr to get it. */ | |||
| 90 | unsigned nsec3_is_exact : 1; | |||
| 91 | /* same but on parent side */ | |||
| 92 | unsigned nsec3_ds_parent_is_exact : 1; | |||
| 93 | } ATTR_PACKED; | |||
| 94 | #endif /* NSEC3 */ | |||
| 95 | ||||
| 96 | struct domain | |||
| 97 | { | |||
| 98 | #ifdef USE_RADIX_TREE | |||
| 99 | struct radnode* rnode; | |||
| 100 | const dname_type* dname; | |||
| 101 | #else | |||
| 102 | rbnode_type node; | |||
| 103 | #endif | |||
| 104 | domain_type* parent; | |||
| 105 | domain_type* wildcard_child_closest_match; | |||
| 106 | rrset_type* rrsets; | |||
| 107 | #ifdef NSEC3 | |||
| 108 | struct nsec3_domain_data* nsec3; | |||
| 109 | #endif | |||
| 110 | /* double-linked list sorted by domain.number */ | |||
| 111 | domain_type* numlist_prev, *numlist_next; | |||
| 112 | uint32_t number; /* Unique domain name number. */ | |||
| 113 | uint32_t usage; /* number of ptrs to this from RRs(in rdata) and | |||
| 114 | from zone-apex pointers, also the root has one | |||
| 115 | more to make sure it cannot be deleted. */ | |||
| 116 | ||||
| 117 | /* | |||
| 118 | * This domain name exists (see wildcard clarification draft). | |||
| 119 | */ | |||
| 120 | unsigned is_existing : 1; | |||
| 121 | unsigned is_apex : 1; | |||
| 122 | } ATTR_PACKED; | |||
| 123 | ||||
| 124 | struct zone | |||
| 125 | { | |||
| 126 | struct radnode *node; /* this entry in zonetree */ | |||
| 127 | domain_type* apex; | |||
| 128 | rrset_type* soa_rrset; | |||
| 129 | rrset_type* soa_nx_rrset; /* see bug #103 */ | |||
| 130 | rrset_type* ns_rrset; | |||
| 131 | #ifdef NSEC3 | |||
| 132 | rr_type* nsec3_param; /* NSEC3PARAM RR of chain in use or NULL */ | |||
| 133 | domain_type* nsec3_last; /* last domain with nsec3, wraps */ | |||
| 134 | /* in these trees, the root contains an elem ptr to the radtree* */ | |||
| 135 | rbtree_type* nsec3tree; /* tree with relevant NSEC3 domains */ | |||
| 136 | rbtree_type* hashtree; /* tree, hashed NSEC3precompiled domains */ | |||
| 137 | rbtree_type* wchashtree; /* tree, wildcard hashed domains */ | |||
| 138 | rbtree_type* dshashtree; /* tree, ds-parent-hash domains */ | |||
| 139 | #endif | |||
| 140 | struct zone_options* opts; | |||
| 141 | struct zone_ixfr* ixfr; | |||
| 142 | char* filename; /* set if read from file, which file */ | |||
| 143 | char* logstr; /* set for zone xfer, the log string */ | |||
| 144 | struct timespec mtime; /* time of last modification */ | |||
| 145 | unsigned zonestatid; /* array index for zone stats */ | |||
| 146 | unsigned is_secure : 1; /* zone uses DNSSEC */ | |||
| 147 | unsigned is_ok : 1; /* zone has not expired */ | |||
| 148 | unsigned is_changed : 1; /* zone changes must be written to disk */ | |||
| 149 | unsigned is_updated : 1; /* zone was changed by XFR */ | |||
| 150 | unsigned is_skipped : 1; /* subsequent zone updates are skipped */ | |||
| 151 | unsigned is_checked : 1; /* zone already verified */ | |||
| 152 | unsigned is_bad : 1; /* zone failed verification */ | |||
| 153 | } ATTR_PACKED; | |||
| 154 | ||||
| 155 | /* a RR in DNS */ | |||
| 156 | struct rr { | |||
| 157 | domain_type* owner; | |||
| 158 | rdata_atom_type* rdatas; | |||
| 159 | uint32_t ttl; | |||
| 160 | uint16_t type; | |||
| 161 | uint16_t klass; | |||
| 162 | uint16_t rdata_count; | |||
| 163 | } ATTR_PACKED; | |||
| 164 | ||||
| 165 | /* | |||
| 166 | * An RRset consists of at least one RR. All RRs are from the same | |||
| 167 | * zone. | |||
| 168 | */ | |||
| 169 | struct rrset | |||
| 170 | { | |||
| 171 | rrset_type* next; | |||
| 172 | zone_type* zone; | |||
| 173 | rr_type* rrs; | |||
| 174 | uint16_t rr_count; | |||
| 175 | } ATTR_PACKED; | |||
| 176 | ||||
| 177 | /* | |||
| 178 | * The field used is based on the wireformat the atom is stored in. | |||
| 179 | * The allowed wireformats are defined by the rdata_wireformat_type | |||
| 180 | * enumeration. | |||
| 181 | */ | |||
| 182 | union rdata_atom | |||
| 183 | { | |||
| 184 | /* RDATA_WF_COMPRESSED_DNAME, RDATA_WF_UNCOMPRESSED_DNAME */ | |||
| 185 | domain_type* domain; | |||
| 186 | ||||
| 187 | /* Default. */ | |||
| 188 | uint16_t* data; | |||
| 189 | }; | |||
| 190 | ||||
| 191 | /* | |||
| 192 | * Create a new domain_table containing only the root domain. | |||
| 193 | */ | |||
| 194 | domain_table_type *domain_table_create(region_type *region); | |||
| 195 | ||||
| 196 | /* | |||
| 197 | * Search the domain table for a match and the closest encloser. | |||
| 198 | */ | |||
| 199 | int domain_table_search(domain_table_type* table, | |||
| 200 | const dname_type* dname, | |||
| 201 | domain_type **closest_match, | |||
| 202 | domain_type **closest_encloser); | |||
| 203 | ||||
| 204 | /* | |||
| 205 | * The number of domains stored in the table (minimum is one for the | |||
| 206 | * root domain). | |||
| 207 | */ | |||
| 208 | static inline uint32_t | |||
| 209 | domain_table_count(domain_table_type* table) | |||
| 210 | { | |||
| 211 | #ifdef USE_RADIX_TREE | |||
| 212 | return table->nametree->count; | |||
| 213 | #else | |||
| 214 | return table->names_to_domains->count; | |||
| 215 | #endif | |||
| 216 | } | |||
| 217 | ||||
| 218 | /* | |||
| 219 | * Find the specified dname in the domain_table. NULL is returned if | |||
| 220 | * there is no exact match. | |||
| 221 | */ | |||
| 222 | domain_type* domain_table_find(domain_table_type* table, | |||
| 223 | const dname_type* dname); | |||
| 224 | ||||
| 225 | /* | |||
| 226 | * Insert a domain name in the domain table. If the domain name is | |||
| 227 | * not yet present in the table it is copied and a new dname_info node | |||
| 228 | * is created (as well as for the missing parent domain names, if | |||
| 229 | * any). Otherwise the domain_type that is already in the | |||
| 230 | * domain_table is returned. | |||
| 231 | */ | |||
| 232 | domain_type *domain_table_insert(domain_table_type *table, | |||
| 233 | const dname_type *dname); | |||
| 234 | ||||
| 235 | /* put domain into nsec3 hash space tree */ | |||
| 236 | void zone_add_domain_in_hash_tree(region_type* region, rbtree_type** tree, | |||
| 237 | int (*cmpf)(const void*, const void*), domain_type* domain, | |||
| 238 | rbnode_type* node); | |||
| 239 | void zone_del_domain_in_hash_tree(rbtree_type* tree, rbnode_type* node); | |||
| 240 | void hash_tree_delete(region_type* region, rbtree_type* tree); | |||
| 241 | void prehash_clear(domain_table_type* table); | |||
| 242 | void prehash_add(domain_table_type* table, domain_type* domain); | |||
| 243 | void prehash_del(domain_table_type* table, domain_type* domain); | |||
| 244 | int domain_is_prehash(domain_table_type* table, domain_type* domain); | |||
| 245 | ||||
| 246 | /* | |||
| 247 | * Add an RRset to the specified domain. Updates the is_existing flag | |||
| 248 | * as required. | |||
| 249 | */ | |||
| 250 | void domain_add_rrset(domain_type* domain, rrset_type* rrset); | |||
| 251 | ||||
| 252 | rrset_type* domain_find_rrset(domain_type* domain, zone_type* zone, uint16_t type); | |||
| 253 | rrset_type* domain_find_any_rrset(domain_type* domain, zone_type* zone); | |||
| 254 | ||||
| 255 | zone_type* domain_find_zone(namedb_type* db, domain_type* domain); | |||
| 256 | zone_type* domain_find_parent_zone(namedb_type* db, zone_type* zone); | |||
| 257 | ||||
| 258 | domain_type* domain_find_ns_rrsets(domain_type* domain, zone_type* zone, rrset_type **ns); | |||
| 259 | /* find DNAME rrset in domain->parent or higher and return that domain */ | |||
| 260 | domain_type * find_dname_above(domain_type* domain, zone_type* zone); | |||
| 261 | ||||
| 262 | int domain_is_glue(domain_type* domain, zone_type* zone); | |||
| 263 | ||||
| 264 | rrset_type* domain_find_non_cname_rrset(domain_type* domain, zone_type* zone); | |||
| 265 | ||||
| 266 | domain_type* domain_wildcard_child(domain_type* domain); | |||
| 267 | domain_type *domain_previous_existing_child(domain_type* domain); | |||
| 268 | ||||
| 269 | int zone_is_secure(zone_type* zone); | |||
| 270 | ||||
| 271 | static inline dname_type * | |||
| 272 | domain_dname(domain_type* domain) | |||
| 273 | { | |||
| 274 | #ifdef USE_RADIX_TREE | |||
| 275 | return (dname_type *) domain->dname; | |||
| ||||
| 276 | #else | |||
| 277 | return (dname_type *) domain->node.key; | |||
| 278 | #endif | |||
| 279 | } | |||
| 280 | ||||
| 281 | static inline const dname_type * | |||
| 282 | domain_dname_const(const domain_type* domain) | |||
| 283 | { | |||
| 284 | #ifdef USE_RADIX_TREE | |||
| 285 | return domain->dname; | |||
| 286 | #else | |||
| 287 | return (const dname_type *) domain->node.key; | |||
| 288 | #endif | |||
| 289 | } | |||
| 290 | ||||
| 291 | static inline domain_type * | |||
| 292 | domain_previous(domain_type* domain) | |||
| 293 | { | |||
| 294 | #ifdef USE_RADIX_TREE | |||
| 295 | struct radnode* prev = radix_prev(domain->rnode); | |||
| 296 | return prev == NULL((void *)0) ? NULL((void *)0) : (domain_type*)prev->elem; | |||
| 297 | #else | |||
| 298 | rbnode_type *prev = rbtree_previous((rbnode_type *) domain); | |||
| 299 | return prev == RBTREE_NULL&rbtree_null_node ? NULL((void *)0) : (domain_type *) prev; | |||
| 300 | #endif | |||
| 301 | } | |||
| 302 | ||||
| 303 | static inline domain_type * | |||
| 304 | domain_next(domain_type* domain) | |||
| 305 | { | |||
| 306 | #ifdef USE_RADIX_TREE | |||
| 307 | struct radnode* next = radix_next(domain->rnode); | |||
| 308 | return next == NULL((void *)0) ? NULL((void *)0) : (domain_type*)next->elem; | |||
| 309 | #else | |||
| 310 | rbnode_type *next = rbtree_next((rbnode_type *) domain); | |||
| 311 | return next == RBTREE_NULL&rbtree_null_node ? NULL((void *)0) : (domain_type *) next; | |||
| 312 | #endif | |||
| 313 | } | |||
| 314 | ||||
| 315 | /* easy comparison for subdomain, true if d1 is subdomain of d2. */ | |||
| 316 | static inline int domain_is_subdomain(domain_type* d1, domain_type* d2) | |||
| 317 | { return dname_is_subdomain(domain_dname(d1), domain_dname(d2)); } | |||
| 318 | /* easy printout, to static buffer of dname_to_string, fqdn. */ | |||
| 319 | static inline const char* domain_to_string(domain_type* domain) | |||
| 320 | { return dname_to_string(domain_dname(domain), NULL((void *)0)); } | |||
| 321 | ||||
| 322 | /* | |||
| 323 | * The type covered by the signature in the specified RRSIG RR. | |||
| 324 | */ | |||
| 325 | uint16_t rr_rrsig_type_covered(rr_type* rr); | |||
| 326 | ||||
| 327 | struct namedb | |||
| 328 | { | |||
| 329 | region_type* region; | |||
| 330 | domain_table_type* domains; | |||
| 331 | struct radtree* zonetree; | |||
| 332 | /* the timestamp on the ixfr.db file */ | |||
| 333 | struct timeval diff_timestamp; | |||
| 334 | /* if diff_skip=1, diff_pos contains the nsd.diff place to continue */ | |||
| 335 | uint8_t diff_skip; | |||
| 336 | off_t diff_pos; | |||
| 337 | }; | |||
| 338 | ||||
| 339 | static inline int rdata_atom_is_domain(uint16_t type, size_t index); | |||
| 340 | static inline int rdata_atom_is_literal_domain(uint16_t type, size_t index); | |||
| 341 | ||||
| 342 | static inline domain_type * | |||
| 343 | rdata_atom_domain(rdata_atom_type atom) | |||
| 344 | { | |||
| 345 | return atom.domain; | |||
| 346 | } | |||
| 347 | ||||
| 348 | static inline uint16_t | |||
| 349 | rdata_atom_size(rdata_atom_type atom) | |||
| 350 | { | |||
| 351 | return *atom.data; | |||
| 352 | } | |||
| 353 | ||||
| 354 | static inline uint8_t * | |||
| 355 | rdata_atom_data(rdata_atom_type atom) | |||
| 356 | { | |||
| 357 | return (uint8_t *) (atom.data + 1); | |||
| 358 | } | |||
| 359 | ||||
| 360 | ||||
| 361 | /* Find the zone for the specified dname in DB. */ | |||
| 362 | zone_type *namedb_find_zone(namedb_type *db, const dname_type *dname); | |||
| 363 | /* | |||
| 364 | * Delete a domain name from the domain table. Removes dname_info node. | |||
| 365 | * Only deletes if usage is 0, has no rrsets and no children. Checks parents | |||
| 366 | * for deletion as well. Adjusts numberlist(domain.number), and | |||
| 367 | * wcard_child closest match. | |||
| 368 | */ | |||
| 369 | void domain_table_deldomain(namedb_type* db, domain_type* domain); | |||
| 370 | ||||
| 371 | /** dbcreate.c */ | |||
| 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(struct nsd_options* opt); | |||
| 382 | void namedb_close(struct namedb* db); | |||
| 383 | /* free ixfr data stored for zones */ | |||
| 384 | void namedb_free_ixfr(struct namedb* db); | |||
| 385 | void namedb_check_zonefiles(struct nsd* nsd, struct nsd_options* opt, | |||
| 386 | struct udb_base* taskudb, struct udb_ptr* last_task); | |||
| 387 | void namedb_check_zonefile(struct nsd* nsd, struct udb_base* taskudb, | |||
| 388 | struct udb_ptr* last_task, struct zone_options* zo); | |||
| 389 | /** zone one zonefile into memory and revert on parse error, write to udb */ | |||
| 390 | void namedb_read_zonefile(struct nsd* nsd, struct zone* zone, | |||
| 391 | struct udb_base* taskudb, struct udb_ptr* last_task); | |||
| 392 | zone_type* namedb_zone_create(namedb_type* db, const dname_type* dname, | |||
| 393 | struct zone_options* zopt); | |||
| 394 | void namedb_zone_delete(namedb_type* db, zone_type* zone); | |||
| 395 | void namedb_write_zonefile(struct nsd* nsd, struct zone_options* zopt); | |||
| 396 | void namedb_write_zonefiles(struct nsd* nsd, struct nsd_options* options); | |||
| 397 | int create_dirs(const char* path); | |||
| 398 | int file_get_mtime(const char* file, struct timespec* mtime, int* nonexist); | |||
| 399 | void allocate_domain_nsec3(domain_table_type *table, domain_type *result); | |||
| 400 | ||||
| 401 | static inline int | |||
| 402 | rdata_atom_is_domain(uint16_t type, size_t index) | |||
| 403 | { | |||
| 404 | const rrtype_descriptor_type *descriptor | |||
| 405 | = rrtype_descriptor_by_type(type); | |||
| 406 | return (index < descriptor->maximum | |||
| 407 | && (descriptor->wireformat[index] == RDATA_WF_COMPRESSED_DNAME | |||
| 408 | || descriptor->wireformat[index] == RDATA_WF_UNCOMPRESSED_DNAME)); | |||
| 409 | } | |||
| 410 | ||||
| 411 | static inline int | |||
| 412 | rdata_atom_is_literal_domain(uint16_t type, size_t index) | |||
| 413 | { | |||
| 414 | const rrtype_descriptor_type *descriptor | |||
| 415 | = rrtype_descriptor_by_type(type); | |||
| 416 | return (index < descriptor->maximum | |||
| 417 | && (descriptor->wireformat[index] == RDATA_WF_LITERAL_DNAME)); | |||
| 418 | } | |||
| 419 | ||||
| 420 | static inline rdata_wireformat_type | |||
| 421 | rdata_atom_wireformat_type(uint16_t type, size_t index) | |||
| 422 | { | |||
| 423 | const rrtype_descriptor_type *descriptor | |||
| 424 | = rrtype_descriptor_by_type(type); | |||
| 425 | assert(index < descriptor->maximum)((void)0); | |||
| 426 | return (rdata_wireformat_type) descriptor->wireformat[index]; | |||
| 427 | } | |||
| 428 | ||||
| 429 | static inline uint16_t | |||
| 430 | rrset_rrtype(rrset_type* rrset) | |||
| 431 | { | |||
| 432 | assert(rrset)((void)0); | |||
| 433 | assert(rrset->rr_count > 0)((void)0); | |||
| 434 | return rrset->rrs[0].type; | |||
| 435 | } | |||
| 436 | ||||
| 437 | static inline uint16_t | |||
| 438 | rrset_rrclass(rrset_type* rrset) | |||
| 439 | { | |||
| 440 | assert(rrset)((void)0); | |||
| 441 | assert(rrset->rr_count > 0)((void)0); | |||
| 442 | return rrset->rrs[0].klass; | |||
| 443 | } | |||
| 444 | ||||
| 445 | /* | |||
| 446 | * zone_rr_iter can be used to iterate over all RRs in a given zone. the | |||
| 447 | * SOA RRSET is guaranteed to be returned first. | |||
| 448 | */ | |||
| 449 | typedef struct zone_rr_iter zone_rr_iter_type; | |||
| 450 | ||||
| 451 | struct zone_rr_iter { | |||
| 452 | zone_type *zone; | |||
| 453 | domain_type *domain; | |||
| 454 | rrset_type *rrset; | |||
| 455 | ssize_t index; | |||
| 456 | }; | |||
| 457 | ||||
| 458 | void zone_rr_iter_init(zone_rr_iter_type *iter, zone_type *zone); | |||
| 459 | ||||
| 460 | rr_type *zone_rr_iter_next(zone_rr_iter_type *iter); | |||
| 461 | ||||
| 462 | #endif /* NAMEDB_H */ |