xref: /openbsd-src/usr.sbin/nsd/query.c (revision bf87c3c07c3ad89262e2b8cae09f17e70aa9e1ee)
162ac0c33Sjakob /*
262ac0c33Sjakob  * query.c -- nsd(8) the resolver.
362ac0c33Sjakob  *
4dd5b221eSsthen  * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
562ac0c33Sjakob  *
662ac0c33Sjakob  * See LICENSE for the license.
762ac0c33Sjakob  *
862ac0c33Sjakob  */
962ac0c33Sjakob 
10d11a62c8Ssthen #include "config.h"
1162ac0c33Sjakob 
1262ac0c33Sjakob #include <sys/types.h>
1362ac0c33Sjakob #include <sys/socket.h>
1462ac0c33Sjakob #include <netinet/in.h>
1562ac0c33Sjakob #include <arpa/inet.h>
1662ac0c33Sjakob #include <assert.h>
1762ac0c33Sjakob #include <ctype.h>
1862ac0c33Sjakob #include <errno.h>
1962ac0c33Sjakob #include <limits.h>
2062ac0c33Sjakob #include <stddef.h>
2162ac0c33Sjakob #include <stdio.h>
2262ac0c33Sjakob #include <stdlib.h>
2362ac0c33Sjakob #include <string.h>
2462ac0c33Sjakob #include <time.h>
2562ac0c33Sjakob #include <unistd.h>
2662ac0c33Sjakob #include <netdb.h>
2762ac0c33Sjakob 
2862ac0c33Sjakob #include "answer.h"
2962ac0c33Sjakob #include "axfr.h"
3062ac0c33Sjakob #include "dns.h"
3162ac0c33Sjakob #include "dname.h"
3262ac0c33Sjakob #include "nsd.h"
3362ac0c33Sjakob #include "namedb.h"
3462ac0c33Sjakob #include "query.h"
3562ac0c33Sjakob #include "util.h"
3662ac0c33Sjakob #include "options.h"
3762ac0c33Sjakob #include "nsec3.h"
3862ac0c33Sjakob #include "tsig.h"
3962ac0c33Sjakob 
4062ac0c33Sjakob /* [Bug #253] Adding unnecessary NS RRset may lead to undesired truncation.
41f72b2965Sjakob  * This function determines if the final response packet needs the NS RRset
42f72b2965Sjakob  * included. Currently, it will only return negative if QTYPE == DNSKEY|DS.
43f72b2965Sjakob  * This way, resolvers won't fallback to TCP unnecessarily when priming
44f72b2965Sjakob  * trust anchors.
4562ac0c33Sjakob  */
4662ac0c33Sjakob static int answer_needs_ns(struct query  *query);
4762ac0c33Sjakob 
4862ac0c33Sjakob static int add_rrset(struct query  *query,
4962ac0c33Sjakob 		     answer_type    *answer,
5062ac0c33Sjakob 		     rr_section_type section,
5162ac0c33Sjakob 		     domain_type    *owner,
5262ac0c33Sjakob 		     rrset_type     *rrset);
5362ac0c33Sjakob 
5462ac0c33Sjakob static void answer_authoritative(struct nsd	  *nsd,
5562ac0c33Sjakob 				 struct query     *q,
5662ac0c33Sjakob 				 answer_type      *answer,
57dd5b221eSsthen 				 size_t            domain_number,
5862ac0c33Sjakob 				 int               exact,
5962ac0c33Sjakob 				 domain_type      *closest_match,
6062ac0c33Sjakob 				 domain_type      *closest_encloser,
6162ac0c33Sjakob 				 const dname_type *qname);
6262ac0c33Sjakob 
6362ac0c33Sjakob static void answer_lookup_zone(struct nsd *nsd, struct query *q,
64dd5b221eSsthen 			       answer_type *answer, size_t domain_number,
6562ac0c33Sjakob 			       int exact, domain_type *closest_match,
6662ac0c33Sjakob 			       domain_type *closest_encloser,
6762ac0c33Sjakob 			       const dname_type *qname);
6862ac0c33Sjakob 
6962ac0c33Sjakob void
query_put_dname_offset(struct query * q,domain_type * domain,uint16_t offset)7062ac0c33Sjakob query_put_dname_offset(struct query *q, domain_type *domain, uint16_t offset)
7162ac0c33Sjakob {
7262ac0c33Sjakob 	assert(q);
7362ac0c33Sjakob 	assert(domain);
7462ac0c33Sjakob 	assert(domain->number > 0);
7562ac0c33Sjakob 
7662ac0c33Sjakob 	if (offset > MAX_COMPRESSION_OFFSET)
7762ac0c33Sjakob 		return;
7862ac0c33Sjakob 	if (q->compressed_dname_count >= MAX_COMPRESSED_DNAMES)
7962ac0c33Sjakob 		return;
8062ac0c33Sjakob 
8162ac0c33Sjakob 	q->compressed_dname_offsets[domain->number] = offset;
8262ac0c33Sjakob 	q->compressed_dnames[q->compressed_dname_count] = domain;
8362ac0c33Sjakob 	++q->compressed_dname_count;
8462ac0c33Sjakob }
8562ac0c33Sjakob 
8662ac0c33Sjakob void
query_clear_dname_offsets(struct query * q,size_t max_offset)8762ac0c33Sjakob query_clear_dname_offsets(struct query *q, size_t max_offset)
8862ac0c33Sjakob {
8962ac0c33Sjakob 	while (q->compressed_dname_count > 0
9062ac0c33Sjakob 	       && (q->compressed_dname_offsets[q->compressed_dnames[q->compressed_dname_count - 1]->number]
9162ac0c33Sjakob 		   >= max_offset))
9262ac0c33Sjakob 	{
9362ac0c33Sjakob 		q->compressed_dname_offsets[q->compressed_dnames[q->compressed_dname_count - 1]->number] = 0;
9462ac0c33Sjakob 		--q->compressed_dname_count;
9562ac0c33Sjakob 	}
9662ac0c33Sjakob }
9762ac0c33Sjakob 
9862ac0c33Sjakob void
query_clear_compression_tables(struct query * q)9962ac0c33Sjakob query_clear_compression_tables(struct query *q)
10062ac0c33Sjakob {
10162ac0c33Sjakob 	uint16_t i;
10262ac0c33Sjakob 
10362ac0c33Sjakob 	for (i = 0; i < q->compressed_dname_count; ++i) {
10462ac0c33Sjakob 		assert(q->compressed_dnames);
10562ac0c33Sjakob 		q->compressed_dname_offsets[q->compressed_dnames[i]->number] = 0;
10662ac0c33Sjakob 	}
10762ac0c33Sjakob 	q->compressed_dname_count = 0;
10862ac0c33Sjakob }
10962ac0c33Sjakob 
11062ac0c33Sjakob void
query_add_compression_domain(struct query * q,domain_type * domain,uint16_t offset)11162ac0c33Sjakob query_add_compression_domain(struct query *q, domain_type *domain, uint16_t offset)
11262ac0c33Sjakob {
11362ac0c33Sjakob 	while (domain->parent) {
11462ac0c33Sjakob 		DEBUG(DEBUG_NAME_COMPRESSION, 2,
11562ac0c33Sjakob 		      (LOG_INFO, "query dname: %s, number: %lu, offset: %u\n",
116dd5b221eSsthen 		       domain_to_string(domain),
11762ac0c33Sjakob 		       (unsigned long) domain->number,
11862ac0c33Sjakob 		       offset));
11962ac0c33Sjakob 		query_put_dname_offset(q, domain, offset);
12062ac0c33Sjakob 		offset += label_length(dname_name(domain_dname(domain))) + 1;
12162ac0c33Sjakob 		domain = domain->parent;
12262ac0c33Sjakob 	}
12362ac0c33Sjakob }
12462ac0c33Sjakob 
12562ac0c33Sjakob /*
12662ac0c33Sjakob  * Generate an error response with the specified RCODE.
12762ac0c33Sjakob  */
12862ac0c33Sjakob query_state_type
query_error(struct query * q,nsd_rc_type rcode)12962ac0c33Sjakob query_error (struct query *q, nsd_rc_type rcode)
13062ac0c33Sjakob {
13162ac0c33Sjakob 	if (rcode == NSD_RC_DISCARD) {
13262ac0c33Sjakob 		return QUERY_DISCARDED;
13362ac0c33Sjakob 	}
13462ac0c33Sjakob 
13562ac0c33Sjakob 	buffer_clear(q->packet);
13662ac0c33Sjakob 
13762ac0c33Sjakob 	QR_SET(q->packet);	   /* This is an answer.  */
138e3d8a0a5Ssthen 	AD_CLR(q->packet);
13962ac0c33Sjakob 	RCODE_SET(q->packet, (int) rcode); /* Error code.  */
14062ac0c33Sjakob 
14162ac0c33Sjakob 	/* Truncate the question as well... */
14262ac0c33Sjakob 	QDCOUNT_SET(q->packet, 0);
14362ac0c33Sjakob 	ANCOUNT_SET(q->packet, 0);
14462ac0c33Sjakob 	NSCOUNT_SET(q->packet, 0);
14562ac0c33Sjakob 	ARCOUNT_SET(q->packet, 0);
14662ac0c33Sjakob 	buffer_set_position(q->packet, QHEADERSZ);
14762ac0c33Sjakob 	return QUERY_PROCESSED;
14862ac0c33Sjakob }
14962ac0c33Sjakob 
1508d8f1862Ssthen static int
query_ratelimit_err(nsd_type * nsd)1518d8f1862Ssthen query_ratelimit_err(nsd_type* nsd)
1528d8f1862Ssthen {
1538d8f1862Ssthen 	time_t now = time(NULL);
1548d8f1862Ssthen 	if(nsd->err_limit_time == now) {
1558d8f1862Ssthen 		/* see if limit is exceeded for this second */
1568d8f1862Ssthen 		if(nsd->err_limit_count++ > ERROR_RATELIMIT)
1578d8f1862Ssthen 			return 1;
1588d8f1862Ssthen 	} else {
1598d8f1862Ssthen 		/* new second, new limits */
1608d8f1862Ssthen 		nsd->err_limit_time = now;
1618d8f1862Ssthen 		nsd->err_limit_count = 1;
1628d8f1862Ssthen 	}
1638d8f1862Ssthen 	return 0;
1648d8f1862Ssthen }
1658d8f1862Ssthen 
16662ac0c33Sjakob static query_state_type
query_formerr(struct query * query,nsd_type * nsd)1678d8f1862Ssthen query_formerr (struct query *query, nsd_type* nsd)
16862ac0c33Sjakob {
16962ac0c33Sjakob 	int opcode = OPCODE(query->packet);
1708d8f1862Ssthen 	if(query_ratelimit_err(nsd))
1718d8f1862Ssthen 		return QUERY_DISCARDED;
17262ac0c33Sjakob 	FLAGS_SET(query->packet, FLAGS(query->packet) & 0x0100U);
17362ac0c33Sjakob 			/* Preserve the RD flag. Clear the rest. */
17462ac0c33Sjakob 	OPCODE_SET(query->packet, opcode);
17562ac0c33Sjakob 	return query_error(query, NSD_RC_FORMAT);
17662ac0c33Sjakob }
17762ac0c33Sjakob 
17862ac0c33Sjakob static void
query_cleanup(void * data)17962ac0c33Sjakob query_cleanup(void *data)
18062ac0c33Sjakob {
18162ac0c33Sjakob 	query_type *query = (query_type *) data;
18262ac0c33Sjakob 	region_destroy(query->region);
18362ac0c33Sjakob }
18462ac0c33Sjakob 
18562ac0c33Sjakob query_type *
query_create(region_type * region,uint16_t * compressed_dname_offsets,size_t compressed_dname_size,domain_type ** compressed_dnames)18662ac0c33Sjakob query_create(region_type *region, uint16_t *compressed_dname_offsets,
187bfd0b123Sflorian 	size_t compressed_dname_size, domain_type **compressed_dnames)
18862ac0c33Sjakob {
18962ac0c33Sjakob 	query_type *query
19062ac0c33Sjakob 		= (query_type *) region_alloc_zero(region, sizeof(query_type));
19162ac0c33Sjakob 	/* create region with large block size, because the initial chunk
19262ac0c33Sjakob 	   saves many mallocs in the server */
19362ac0c33Sjakob 	query->region = region_create_custom(xalloc, free, 16384, 16384/8, 32, 0);
19462ac0c33Sjakob 	query->compressed_dname_offsets = compressed_dname_offsets;
195bfd0b123Sflorian 	query->compressed_dnames = compressed_dnames;
19662ac0c33Sjakob 	query->packet = buffer_create(region, QIOBUFSZ);
19762ac0c33Sjakob 	region_add_cleanup(region, query_cleanup, query);
19862ac0c33Sjakob 	query->compressed_dname_offsets_size = compressed_dname_size;
19962ac0c33Sjakob 	tsig_create_record(&query->tsig, region);
20062ac0c33Sjakob 	query->tsig_prepare_it = 1;
20162ac0c33Sjakob 	query->tsig_update_it = 1;
20262ac0c33Sjakob 	query->tsig_sign_it = 1;
20362ac0c33Sjakob 	return query;
20462ac0c33Sjakob }
20562ac0c33Sjakob 
20662ac0c33Sjakob void
query_reset(query_type * q,size_t maxlen,int is_tcp)20762ac0c33Sjakob query_reset(query_type *q, size_t maxlen, int is_tcp)
20862ac0c33Sjakob {
20962ac0c33Sjakob 	/*
21062ac0c33Sjakob 	 * As long as less than 4Kb (region block size) has been used,
21162ac0c33Sjakob 	 * this call to free_all is free, the block is saved for re-use,
21262ac0c33Sjakob 	 * so no malloc() or free() calls are done.
21362ac0c33Sjakob 	 * at present use of the region is for:
21462ac0c33Sjakob 	 *   o query qname dname_type (255 max).
21562ac0c33Sjakob 	 *   o wildcard expansion domain_type (7*ptr+u32+2bytes)+(5*ptr nsec3)
21662ac0c33Sjakob 	 *   o wildcard expansion for additional section domain_type.
21762ac0c33Sjakob 	 *   o nsec3 hashed name(s) (3 dnames for a nonexist_proof,
21862ac0c33Sjakob 	 *     one proof per wildcard and for nx domain).
21962ac0c33Sjakob 	 */
22062ac0c33Sjakob 	region_free_all(q->region);
221b71395eaSflorian 	q->remote_addrlen = (socklen_t)sizeof(q->remote_addr);
222b71395eaSflorian 	q->client_addrlen = (socklen_t)sizeof(q->client_addr);
223b71395eaSflorian 	q->is_proxied = 0;
22462ac0c33Sjakob 	q->maxlen = maxlen;
22562ac0c33Sjakob 	q->reserved_space = 0;
22662ac0c33Sjakob 	buffer_clear(q->packet);
22762ac0c33Sjakob 	edns_init_record(&q->edns);
22862ac0c33Sjakob 	tsig_init_record(&q->tsig, NULL, NULL);
22962ac0c33Sjakob 	q->tsig_prepare_it = 1;
23062ac0c33Sjakob 	q->tsig_update_it = 1;
23162ac0c33Sjakob 	q->tsig_sign_it = 1;
23262ac0c33Sjakob 	q->tcp = is_tcp;
23362ac0c33Sjakob 	q->qname = NULL;
23462ac0c33Sjakob 	q->qtype = 0;
23562ac0c33Sjakob 	q->qclass = 0;
23662ac0c33Sjakob 	q->zone = NULL;
23762ac0c33Sjakob 	q->opcode = 0;
23862ac0c33Sjakob 	q->cname_count = 0;
23962ac0c33Sjakob 	q->delegation_domain = NULL;
24062ac0c33Sjakob 	q->delegation_rrset = NULL;
24162ac0c33Sjakob 	q->compressed_dname_count = 0;
24262ac0c33Sjakob 	q->number_temporary_domains = 0;
24362ac0c33Sjakob 
24462ac0c33Sjakob 	q->axfr_is_done = 0;
24562ac0c33Sjakob 	q->axfr_zone = NULL;
24662ac0c33Sjakob 	q->axfr_current_domain = NULL;
24762ac0c33Sjakob 	q->axfr_current_rrset = NULL;
24862ac0c33Sjakob 	q->axfr_current_rr = 0;
24975343be4Ssthen 
2504564029fSflorian 	q->ixfr_is_done = 0;
2514564029fSflorian 	q->ixfr_data = NULL;
2524564029fSflorian 	q->ixfr_count_newsoa = 0;
2534564029fSflorian 	q->ixfr_count_oldsoa = 0;
2544564029fSflorian 	q->ixfr_count_del = 0;
2554564029fSflorian 	q->ixfr_count_add = 0;
2564564029fSflorian 
25775343be4Ssthen #ifdef RATELIMIT
25875343be4Ssthen 	q->wildcard_domain = NULL;
25975343be4Ssthen #endif
26062ac0c33Sjakob }
26162ac0c33Sjakob 
26262ac0c33Sjakob /* get a temporary domain number (or 0=failure) */
26362ac0c33Sjakob static domain_type*
query_get_tempdomain(struct query * q)26462ac0c33Sjakob query_get_tempdomain(struct query *q)
26562ac0c33Sjakob {
26662ac0c33Sjakob 	static domain_type d[EXTRA_DOMAIN_NUMBERS];
26762ac0c33Sjakob 	if(q->number_temporary_domains >= EXTRA_DOMAIN_NUMBERS)
26862ac0c33Sjakob 		return 0;
26962ac0c33Sjakob 	q->number_temporary_domains ++;
27062ac0c33Sjakob 	memset(&d[q->number_temporary_domains-1], 0, sizeof(domain_type));
27162ac0c33Sjakob 	d[q->number_temporary_domains-1].number = q->compressed_dname_offsets_size +
27262ac0c33Sjakob 		q->number_temporary_domains - 1;
27362ac0c33Sjakob 	return &d[q->number_temporary_domains-1];
27462ac0c33Sjakob }
27562ac0c33Sjakob 
27662ac0c33Sjakob static void
query_addtxt(struct query * q,const uint8_t * dname,uint16_t klass,uint32_t ttl,const char * txt)27762ac0c33Sjakob query_addtxt(struct query  *q,
27862ac0c33Sjakob 	     const uint8_t *dname,
27962ac0c33Sjakob 	     uint16_t       klass,
28062ac0c33Sjakob 	     uint32_t       ttl,
28162ac0c33Sjakob 	     const char    *txt)
28262ac0c33Sjakob {
28362ac0c33Sjakob 	size_t txt_length = strlen(txt);
28462ac0c33Sjakob 	uint8_t len = (uint8_t) txt_length;
28562ac0c33Sjakob 
28662ac0c33Sjakob 	assert(txt_length <= UCHAR_MAX);
28762ac0c33Sjakob 
28862ac0c33Sjakob 	/* Add the dname */
28962ac0c33Sjakob 	if (dname >= buffer_begin(q->packet)
29062ac0c33Sjakob 	    && dname <= buffer_current(q->packet))
29162ac0c33Sjakob 	{
29262ac0c33Sjakob 		buffer_write_u16(q->packet,
29362ac0c33Sjakob 				 0xc000 | (dname - buffer_begin(q->packet)));
29462ac0c33Sjakob 	} else {
29562ac0c33Sjakob 		buffer_write(q->packet, dname + 1, *dname);
29662ac0c33Sjakob 	}
29762ac0c33Sjakob 
29862ac0c33Sjakob 	buffer_write_u16(q->packet, TYPE_TXT);
29962ac0c33Sjakob 	buffer_write_u16(q->packet, klass);
30062ac0c33Sjakob 	buffer_write_u32(q->packet, ttl);
30162ac0c33Sjakob 	buffer_write_u16(q->packet, len + 1);
30262ac0c33Sjakob 	buffer_write_u8(q->packet, len);
30362ac0c33Sjakob 	buffer_write(q->packet, txt, len);
30462ac0c33Sjakob }
30562ac0c33Sjakob 
30662ac0c33Sjakob /*
30762ac0c33Sjakob  * Parse the question section of a query.  The normalized query name
30862ac0c33Sjakob  * is stored in QUERY->name, the class in QUERY->klass, and the type
30962ac0c33Sjakob  * in QUERY->type.
31062ac0c33Sjakob  */
31162ac0c33Sjakob static int
process_query_section(query_type * query)31262ac0c33Sjakob process_query_section(query_type *query)
31362ac0c33Sjakob {
31462ac0c33Sjakob 	uint8_t qnamebuf[MAXDOMAINLEN];
31562ac0c33Sjakob 
31662ac0c33Sjakob 	buffer_set_position(query->packet, QHEADERSZ);
31762ac0c33Sjakob 	/* Lets parse the query name and convert it to lower case.  */
31862ac0c33Sjakob 	if(!packet_read_query_section(query->packet, qnamebuf,
31962ac0c33Sjakob 		&query->qtype, &query->qclass))
32062ac0c33Sjakob 		return 0;
32162ac0c33Sjakob 	query->qname = dname_make(query->region, qnamebuf, 1);
32262ac0c33Sjakob 	return 1;
32362ac0c33Sjakob }
32462ac0c33Sjakob 
32562ac0c33Sjakob 
32662ac0c33Sjakob /*
32762ac0c33Sjakob  * Process an optional EDNS OPT record.  Sets QUERY->EDNS to 0 if
32862ac0c33Sjakob  * there was no EDNS record, to -1 if there was an invalid or
32962ac0c33Sjakob  * unsupported EDNS record, and to 1 otherwise.  Updates QUERY->MAXLEN
33062ac0c33Sjakob  * if the EDNS record specifies a maximum supported response length.
33162ac0c33Sjakob  *
33262ac0c33Sjakob  * Return NSD_RC_FORMAT on failure, NSD_RC_OK on success.
33362ac0c33Sjakob  */
33462ac0c33Sjakob static nsd_rc_type
process_edns(nsd_type * nsd,struct query * q)33562ac0c33Sjakob process_edns(nsd_type* nsd, struct query *q)
33662ac0c33Sjakob {
33762ac0c33Sjakob 	if (q->edns.status == EDNS_ERROR) {
338d11a62c8Ssthen 		/* The only error is VERSION not implemented */
33962ac0c33Sjakob 		return NSD_RC_FORMAT;
34062ac0c33Sjakob 	}
34162ac0c33Sjakob 
34262ac0c33Sjakob 	if (q->edns.status == EDNS_OK) {
34362ac0c33Sjakob 		/* Only care about UDP size larger than normal... */
34462ac0c33Sjakob 		if (!q->tcp && q->edns.maxlen > UDP_MAX_MESSAGE_LEN) {
34562ac0c33Sjakob 			size_t edns_size;
34662ac0c33Sjakob #if defined(INET6)
347b71395eaSflorian 			if (q->client_addr.ss_family == AF_INET6) {
34862ac0c33Sjakob 				edns_size = nsd->ipv6_edns_size;
34962ac0c33Sjakob 			} else
35062ac0c33Sjakob #endif
35162ac0c33Sjakob 			edns_size = nsd->ipv4_edns_size;
35262ac0c33Sjakob 
35362ac0c33Sjakob 			if (q->edns.maxlen < edns_size) {
35462ac0c33Sjakob 				q->maxlen = q->edns.maxlen;
35562ac0c33Sjakob 			} else {
35662ac0c33Sjakob 				q->maxlen = edns_size;
35762ac0c33Sjakob 			}
35862ac0c33Sjakob 
35962ac0c33Sjakob #if defined(INET6) && !defined(IPV6_USE_MIN_MTU) && !defined(IPV6_MTU)
36062ac0c33Sjakob 			/*
36162ac0c33Sjakob 			 * Use IPv6 minimum MTU to avoid sending
36262ac0c33Sjakob 			 * packets that are too large for some links.
36362ac0c33Sjakob 			 * IPv6 will not automatically fragment in
36462ac0c33Sjakob 			 * this case (unlike IPv4).
36562ac0c33Sjakob 			 */
366b71395eaSflorian 			if (q->client_addr.ss_family == AF_INET6
36762ac0c33Sjakob 			    && q->maxlen > IPV6_MIN_MTU)
36862ac0c33Sjakob 			{
36962ac0c33Sjakob 				q->maxlen = IPV6_MIN_MTU;
37062ac0c33Sjakob 			}
37162ac0c33Sjakob #endif
37262ac0c33Sjakob 		}
37362ac0c33Sjakob 
37462ac0c33Sjakob 		/* Strip the OPT resource record off... */
37562ac0c33Sjakob 		buffer_set_position(q->packet, q->edns.position);
37662ac0c33Sjakob 		buffer_set_limit(q->packet, q->edns.position);
37762ac0c33Sjakob 		ARCOUNT_SET(q->packet, ARCOUNT(q->packet) - 1);
37862ac0c33Sjakob 	}
37962ac0c33Sjakob 	return NSD_RC_OK;
38062ac0c33Sjakob }
38162ac0c33Sjakob 
38262ac0c33Sjakob /*
38362ac0c33Sjakob  * Processes TSIG.
38462ac0c33Sjakob  * Sets error when tsig does not verify on the query.
38562ac0c33Sjakob  */
38662ac0c33Sjakob static nsd_rc_type
process_tsig(struct query * q)38762ac0c33Sjakob process_tsig(struct query* q)
38862ac0c33Sjakob {
38962ac0c33Sjakob 	if(q->tsig.status == TSIG_ERROR)
39062ac0c33Sjakob 		return NSD_RC_FORMAT;
39162ac0c33Sjakob 	if(q->tsig.status == TSIG_OK) {
39262ac0c33Sjakob 		if(!tsig_from_query(&q->tsig)) {
393dd5b221eSsthen 			char a[128];
394b71395eaSflorian 			addr2str(&q->client_addr, a, sizeof(a));
395dd5b221eSsthen 			log_msg(LOG_ERR, "query: bad tsig (%s) for key %s from %s",
396dd5b221eSsthen 				tsig_error(q->tsig.error_code),
397dd5b221eSsthen 				dname_to_string(q->tsig.key_name, NULL), a);
39875343be4Ssthen 			return NSD_RC_NOTAUTH;
39962ac0c33Sjakob 		}
40062ac0c33Sjakob 		buffer_set_limit(q->packet, q->tsig.position);
40162ac0c33Sjakob 		ARCOUNT_SET(q->packet, ARCOUNT(q->packet) - 1);
40262ac0c33Sjakob 		tsig_prepare(&q->tsig);
40362ac0c33Sjakob 		tsig_update(&q->tsig, q->packet, buffer_limit(q->packet));
40462ac0c33Sjakob 		if(!tsig_verify(&q->tsig)) {
405dd5b221eSsthen 			char a[128];
406b71395eaSflorian 			addr2str(&q->client_addr, a, sizeof(a));
407dd5b221eSsthen 			log_msg(LOG_ERR, "query: bad tsig signature for key %s from %s",
408dd5b221eSsthen 				dname_to_string(q->tsig.key->name, NULL), a);
40975343be4Ssthen 			return NSD_RC_NOTAUTH;
41062ac0c33Sjakob 		}
41162ac0c33Sjakob 		DEBUG(DEBUG_XFRD,1, (LOG_INFO, "query good tsig signature for %s",
41262ac0c33Sjakob 			dname_to_string(q->tsig.key->name, NULL)));
41362ac0c33Sjakob 	}
41462ac0c33Sjakob 	return NSD_RC_OK;
41562ac0c33Sjakob }
41662ac0c33Sjakob 
41762ac0c33Sjakob /*
41862ac0c33Sjakob  * Check notify acl and forward to xfrd (or return an error).
41962ac0c33Sjakob  */
42062ac0c33Sjakob static query_state_type
answer_notify(struct nsd * nsd,struct query * query)42162ac0c33Sjakob answer_notify(struct nsd* nsd, struct query *query)
42262ac0c33Sjakob {
42372f0a8e9Ssthen 	int acl_num, acl_num_xfr;
424fe5fe5f6Sflorian 	struct acl_options *why;
42562ac0c33Sjakob 	nsd_rc_type rc;
42662ac0c33Sjakob 
427fe5fe5f6Sflorian 	struct zone_options* zone_opt;
42862ac0c33Sjakob 	DEBUG(DEBUG_XFRD,1, (LOG_INFO, "got notify %s processing acl",
42962ac0c33Sjakob 		dname_to_string(query->qname, NULL)));
43062ac0c33Sjakob 
43162ac0c33Sjakob 	zone_opt = zone_options_find(nsd->options, query->qname);
43262ac0c33Sjakob 	if(!zone_opt)
43362ac0c33Sjakob 		return query_error(query, NSD_RC_NXDOMAIN);
43462ac0c33Sjakob 
43562ac0c33Sjakob 	if(!nsd->this_child) /* we are in debug mode or something */
43662ac0c33Sjakob 		return query_error(query, NSD_RC_SERVFAIL);
43762ac0c33Sjakob 
43862ac0c33Sjakob 	if(!tsig_find_rr(&query->tsig, query->packet)) {
43962ac0c33Sjakob 		DEBUG(DEBUG_XFRD,2, (LOG_ERR, "bad tsig RR format"));
44062ac0c33Sjakob 		return query_error(query, NSD_RC_FORMAT);
44162ac0c33Sjakob 	}
44262ac0c33Sjakob 	rc = process_tsig(query);
44362ac0c33Sjakob 	if(rc != NSD_RC_OK)
44462ac0c33Sjakob 		return query_error(query, rc);
44562ac0c33Sjakob 
44662ac0c33Sjakob 	/* check if it passes acl */
447b71395eaSflorian 	if(query->is_proxied && acl_check_incoming_block_proxy(
448b71395eaSflorian 		zone_opt->pattern->allow_notify, query, &why) == -1) {
449b71395eaSflorian 		/* the proxy address is blocked */
450b71395eaSflorian 		if (verbosity >= 2) {
451b71395eaSflorian 			char address[128], proxy[128];
452b71395eaSflorian 			addr2str(&query->client_addr, address, sizeof(address));
453b71395eaSflorian 			addr2str(&query->remote_addr, proxy, sizeof(proxy));
454b71395eaSflorian 			VERBOSITY(2, (LOG_INFO, "notify for %s from %s via proxy %s refused because of proxy, %s %s",
455b71395eaSflorian 				dname_to_string(query->qname, NULL),
456b71395eaSflorian 				address, proxy,
457b71395eaSflorian 				(why?why->ip_address_spec:"."),
458b71395eaSflorian 				(why ? ( why->nokey    ? "NOKEY"
459b71395eaSflorian 				       : why->blocked  ? "BLOCKED"
460b71395eaSflorian 				       : why->key_name )
461b71395eaSflorian 				     : "no acl matches")));
462b71395eaSflorian 		}
463b71395eaSflorian 		return query_error(query, NSD_RC_REFUSE);
464b71395eaSflorian 	}
465dd5b221eSsthen 	if((acl_num = acl_check_incoming(zone_opt->pattern->allow_notify, query,
46662ac0c33Sjakob 		&why)) != -1)
46762ac0c33Sjakob 	{
46862ac0c33Sjakob 		sig_atomic_t mode = NSD_PASS_TO_XFRD;
46962ac0c33Sjakob 		int s = nsd->this_child->parent_fd;
47062ac0c33Sjakob 		uint16_t sz;
47162ac0c33Sjakob 		uint32_t acl_send = htonl(acl_num);
4720b3518aaSsthen 		uint32_t acl_xfr;
47362ac0c33Sjakob 		size_t pos;
4740b3518aaSsthen 
4750b3518aaSsthen 		/* Find priority candidate for request XFR. -1 if no match */
4760b3518aaSsthen 		acl_num_xfr = acl_check_incoming(
477dd5b221eSsthen 			zone_opt->pattern->request_xfr, query, NULL);
478dd5b221eSsthen 
4790b3518aaSsthen 		acl_xfr = htonl(acl_num_xfr);
4800b3518aaSsthen 
481dd5b221eSsthen 		assert(why);
48262ac0c33Sjakob 		DEBUG(DEBUG_XFRD,1, (LOG_INFO, "got notify %s passed acl %s %s",
48362ac0c33Sjakob 			dname_to_string(query->qname, NULL),
48462ac0c33Sjakob 			why->ip_address_spec,
48562ac0c33Sjakob 			why->nokey?"NOKEY":
48662ac0c33Sjakob 			(why->blocked?"BLOCKED":why->key_name)));
48762ac0c33Sjakob 		sz = buffer_limit(query->packet);
48862ac0c33Sjakob 		if(buffer_limit(query->packet) > MAX_PACKET_SIZE)
48962ac0c33Sjakob 			return query_error(query, NSD_RC_SERVFAIL);
49062ac0c33Sjakob 		/* forward to xfrd for processing
49162ac0c33Sjakob 		   Note. Blocking IPC I/O, but acl is OK. */
49262ac0c33Sjakob 		sz = htons(sz);
49362ac0c33Sjakob 		if(!write_socket(s, &mode, sizeof(mode)) ||
49462ac0c33Sjakob 			!write_socket(s, &sz, sizeof(sz)) ||
49562ac0c33Sjakob 			!write_socket(s, buffer_begin(query->packet),
49662ac0c33Sjakob 				buffer_limit(query->packet)) ||
49772f0a8e9Ssthen 			!write_socket(s, &acl_send, sizeof(acl_send)) ||
49872f0a8e9Ssthen 			!write_socket(s, &acl_xfr, sizeof(acl_xfr))) {
49962ac0c33Sjakob 			log_msg(LOG_ERR, "error in IPC notify server2main, %s",
50062ac0c33Sjakob 				strerror(errno));
50162ac0c33Sjakob 			return query_error(query, NSD_RC_SERVFAIL);
50262ac0c33Sjakob 		}
5038d8f1862Ssthen 		if(verbosity >= 1) {
5048d8f1862Ssthen 			uint32_t serial = 0;
5058d8f1862Ssthen 			char address[128];
506b71395eaSflorian 			addr2str(&query->client_addr, address, sizeof(address));
5078d8f1862Ssthen 			if(packet_find_notify_serial(query->packet, &serial))
5088d8f1862Ssthen 			  VERBOSITY(1, (LOG_INFO, "notify for %s from %s serial %u",
5098d8f1862Ssthen 				dname_to_string(query->qname, NULL), address,
5108d8f1862Ssthen 				(unsigned)serial));
5118d8f1862Ssthen 			else
5128d8f1862Ssthen 			  VERBOSITY(1, (LOG_INFO, "notify for %s from %s",
5138d8f1862Ssthen 				dname_to_string(query->qname, NULL), address));
5148d8f1862Ssthen 		}
51562ac0c33Sjakob 
51662ac0c33Sjakob 		/* create notify reply - keep same query contents */
51762ac0c33Sjakob 		QR_SET(query->packet);         /* This is an answer.  */
51862ac0c33Sjakob 		AA_SET(query->packet);	   /* we are authoritative. */
51962ac0c33Sjakob 		ANCOUNT_SET(query->packet, 0);
52062ac0c33Sjakob 		NSCOUNT_SET(query->packet, 0);
52162ac0c33Sjakob 		ARCOUNT_SET(query->packet, 0);
52262ac0c33Sjakob 		RCODE_SET(query->packet, RCODE_OK); /* Error code.  */
52362ac0c33Sjakob 		/* position is right after the query */
52462ac0c33Sjakob 		pos = buffer_position(query->packet);
52562ac0c33Sjakob 		buffer_clear(query->packet);
52662ac0c33Sjakob 		buffer_set_position(query->packet, pos);
52762ac0c33Sjakob 		/* tsig is added in add_additional later (if needed) */
52862ac0c33Sjakob 		return QUERY_PROCESSED;
52962ac0c33Sjakob 	}
5303b0b19f7Sjakob 
5318d8f1862Ssthen 	if (verbosity >= 2) {
5323b0b19f7Sjakob 		char address[128];
533b71395eaSflorian 		addr2str(&query->client_addr, address, sizeof(address));
5348d8f1862Ssthen 		VERBOSITY(2, (LOG_INFO, "notify for %s from %s refused, %s %s",
53562ac0c33Sjakob 			dname_to_string(query->qname, NULL),
5363b0b19f7Sjakob 			address,
537b71395eaSflorian 			(why?why->ip_address_spec:"."),
538b71395eaSflorian 			(why ? ( why->nokey    ? "NOKEY"
539b71395eaSflorian 			       : why->blocked  ? "BLOCKED"
540b71395eaSflorian 			       : why->key_name )
541b71395eaSflorian 			     : "no acl matches")));
5423b0b19f7Sjakob 	}
5433b0b19f7Sjakob 
54462ac0c33Sjakob 	return query_error(query, NSD_RC_REFUSE);
54562ac0c33Sjakob }
54662ac0c33Sjakob 
54762ac0c33Sjakob 
54862ac0c33Sjakob /*
54962ac0c33Sjakob  * Answer a query in the CHAOS class.
55062ac0c33Sjakob  */
55162ac0c33Sjakob static query_state_type
answer_chaos(struct nsd * nsd,query_type * q)55262ac0c33Sjakob answer_chaos(struct nsd *nsd, query_type *q)
55362ac0c33Sjakob {
55462ac0c33Sjakob 	AA_CLR(q->packet);
55562ac0c33Sjakob 	switch (q->qtype) {
55662ac0c33Sjakob 	case TYPE_ANY:
55762ac0c33Sjakob 	case TYPE_TXT:
55862ac0c33Sjakob 		if ((q->qname->name_size == 11
55962ac0c33Sjakob 		     && memcmp(dname_name(q->qname), "\002id\006server", 11) == 0) ||
56062ac0c33Sjakob 		    (q->qname->name_size ==  15
56162ac0c33Sjakob 		     && memcmp(dname_name(q->qname), "\010hostname\004bind", 15) == 0))
56262ac0c33Sjakob 		{
563eab1363eSsthen 			if(!nsd->options->hide_identity) {
56462ac0c33Sjakob 				/* Add ID */
56562ac0c33Sjakob 				query_addtxt(q,
56662ac0c33Sjakob 				     buffer_begin(q->packet) + QHEADERSZ,
56762ac0c33Sjakob 				     CLASS_CH,
56862ac0c33Sjakob 				     0,
56962ac0c33Sjakob 				     nsd->identity);
57062ac0c33Sjakob 				ANCOUNT_SET(q->packet, ANCOUNT(q->packet) + 1);
571eab1363eSsthen 			} else {
572eab1363eSsthen 				RCODE_SET(q->packet, RCODE_REFUSE);
5738d298c9fSsthen 				/* RFC8914 - Extended DNS Errors
5748d298c9fSsthen 				 * 4.19. Extended DNS Error Code 18 - Prohibited */
5758d298c9fSsthen 				q->edns.ede = EDE_PROHIBITED;
576eab1363eSsthen 			}
57762ac0c33Sjakob 		} else if ((q->qname->name_size == 16
57862ac0c33Sjakob 			    && memcmp(dname_name(q->qname), "\007version\006server", 16) == 0) ||
57962ac0c33Sjakob 			   (q->qname->name_size == 14
58062ac0c33Sjakob 			    && memcmp(dname_name(q->qname), "\007version\004bind", 14) == 0))
58162ac0c33Sjakob 		{
58262ac0c33Sjakob 			if(!nsd->options->hide_version) {
58362ac0c33Sjakob 				/* Add version */
58462ac0c33Sjakob 				query_addtxt(q,
58562ac0c33Sjakob 				     buffer_begin(q->packet) + QHEADERSZ,
58662ac0c33Sjakob 				     CLASS_CH,
58762ac0c33Sjakob 				     0,
58862ac0c33Sjakob 				     nsd->version);
58962ac0c33Sjakob 				ANCOUNT_SET(q->packet, ANCOUNT(q->packet) + 1);
59062ac0c33Sjakob 			} else {
59162ac0c33Sjakob 				RCODE_SET(q->packet, RCODE_REFUSE);
5928d298c9fSsthen 				/* RFC8914 - Extended DNS Errors
5938d298c9fSsthen 				 * 4.19. Extended DNS Error Code 18 - Prohibited */
5948d298c9fSsthen 				q->edns.ede = EDE_PROHIBITED;
59562ac0c33Sjakob 			}
59603739794Sbrad 		} else {
59703739794Sbrad 			RCODE_SET(q->packet, RCODE_REFUSE);
5988d298c9fSsthen 			/* RFC8914 - Extended DNS Errors
5998d298c9fSsthen 			 * 4.22. Extended DNS Error Code 21 - Not Supported */
6008d298c9fSsthen 			q->edns.ede = EDE_NOT_SUPPORTED;
6018d298c9fSsthen 
60262ac0c33Sjakob 		}
60362ac0c33Sjakob 		break;
60462ac0c33Sjakob 	default:
60562ac0c33Sjakob 		RCODE_SET(q->packet, RCODE_REFUSE);
6068d298c9fSsthen 		/* RFC8914 - Extended DNS Errors
6078d298c9fSsthen 		 * 4.22. Extended DNS Error Code 21 - Not Supported */
6088d298c9fSsthen 		q->edns.ede = EDE_NOT_SUPPORTED;
60962ac0c33Sjakob 		break;
61062ac0c33Sjakob 	}
61162ac0c33Sjakob 
61262ac0c33Sjakob 	return QUERY_PROCESSED;
61362ac0c33Sjakob }
61462ac0c33Sjakob 
61562ac0c33Sjakob 
61662ac0c33Sjakob /*
61762ac0c33Sjakob  * Find the covering NSEC for a non-existent domain name.  Normally
61862ac0c33Sjakob  * the NSEC will be located at CLOSEST_MATCH, except when it is an
61962ac0c33Sjakob  * empty non-terminal.  In this case the NSEC may be located at the
62062ac0c33Sjakob  * previous domain name (in canonical ordering).
62162ac0c33Sjakob  */
62262ac0c33Sjakob static domain_type *
find_covering_nsec(domain_type * closest_match,zone_type * zone,rrset_type ** nsec_rrset)62362ac0c33Sjakob find_covering_nsec(domain_type *closest_match,
62462ac0c33Sjakob 		   zone_type   *zone,
62562ac0c33Sjakob 		   rrset_type **nsec_rrset)
62662ac0c33Sjakob {
62762ac0c33Sjakob 	assert(closest_match);
62862ac0c33Sjakob 	assert(nsec_rrset);
62962ac0c33Sjakob 
63062ac0c33Sjakob 	/* loop away temporary created domains. For real ones it is &RBTREE_NULL */
631c1e73312Sflorian #ifdef USE_RADIX_TREE
632dd5b221eSsthen 	while (closest_match->rnode == NULL)
633c1e73312Sflorian #else
634c1e73312Sflorian 	while (closest_match->node.parent == NULL)
635c1e73312Sflorian #endif
63662ac0c33Sjakob 		closest_match = closest_match->parent;
63762ac0c33Sjakob 	while (closest_match) {
63862ac0c33Sjakob 		*nsec_rrset = domain_find_rrset(closest_match, zone, TYPE_NSEC);
63962ac0c33Sjakob 		if (*nsec_rrset) {
64062ac0c33Sjakob 			return closest_match;
64162ac0c33Sjakob 		}
64262ac0c33Sjakob 		if (closest_match == zone->apex) {
64362ac0c33Sjakob 			/* Don't look outside the current zone.  */
64462ac0c33Sjakob 			return NULL;
64562ac0c33Sjakob 		}
64662ac0c33Sjakob 		closest_match = domain_previous(closest_match);
64762ac0c33Sjakob 	}
64862ac0c33Sjakob 	return NULL;
64962ac0c33Sjakob }
65062ac0c33Sjakob 
65162ac0c33Sjakob 
65262ac0c33Sjakob struct additional_rr_types
65362ac0c33Sjakob {
65462ac0c33Sjakob 	uint16_t        rr_type;
65562ac0c33Sjakob 	rr_section_type rr_section;
65662ac0c33Sjakob };
65762ac0c33Sjakob 
65862ac0c33Sjakob struct additional_rr_types default_additional_rr_types[] = {
65962ac0c33Sjakob 	{ TYPE_A, ADDITIONAL_A_SECTION },
66062ac0c33Sjakob 	{ TYPE_AAAA, ADDITIONAL_AAAA_SECTION },
66162ac0c33Sjakob 	{ 0, (rr_section_type) 0 }
66262ac0c33Sjakob };
66362ac0c33Sjakob 
664275a8d89Sflorian struct additional_rr_types swap_aaaa_additional_rr_types[] = {
665275a8d89Sflorian 	{ TYPE_AAAA, ADDITIONAL_A_SECTION },
666275a8d89Sflorian 	{ TYPE_A, ADDITIONAL_AAAA_SECTION },
667275a8d89Sflorian 	{ 0, (rr_section_type) 0 }
668275a8d89Sflorian };
669275a8d89Sflorian 
67062ac0c33Sjakob struct additional_rr_types rt_additional_rr_types[] = {
67162ac0c33Sjakob 	{ TYPE_A, ADDITIONAL_A_SECTION },
67262ac0c33Sjakob 	{ TYPE_AAAA, ADDITIONAL_AAAA_SECTION },
67362ac0c33Sjakob 	{ TYPE_X25, ADDITIONAL_OTHER_SECTION },
67462ac0c33Sjakob 	{ TYPE_ISDN, ADDITIONAL_OTHER_SECTION },
67562ac0c33Sjakob 	{ 0, (rr_section_type) 0 }
67662ac0c33Sjakob };
67762ac0c33Sjakob 
67862ac0c33Sjakob static void
add_additional_rrsets(struct query * query,answer_type * answer,rrset_type * master_rrset,size_t rdata_index,int allow_glue,struct additional_rr_types types[])67962ac0c33Sjakob add_additional_rrsets(struct query *query, answer_type *answer,
68062ac0c33Sjakob 		      rrset_type *master_rrset, size_t rdata_index,
68162ac0c33Sjakob 		      int allow_glue, struct additional_rr_types types[])
68262ac0c33Sjakob {
68362ac0c33Sjakob 	size_t i;
68462ac0c33Sjakob 
68562ac0c33Sjakob 	assert(query);
68662ac0c33Sjakob 	assert(answer);
68762ac0c33Sjakob 	assert(master_rrset);
68862ac0c33Sjakob 	assert(rdata_atom_is_domain(rrset_rrtype(master_rrset), rdata_index));
68962ac0c33Sjakob 
69062ac0c33Sjakob 	for (i = 0; i < master_rrset->rr_count; ++i) {
69162ac0c33Sjakob 		int j;
69262ac0c33Sjakob 		domain_type *additional = rdata_atom_domain(master_rrset->rrs[i].rdatas[rdata_index]);
69362ac0c33Sjakob 		domain_type *match = additional;
69462ac0c33Sjakob 
69562ac0c33Sjakob 		assert(additional);
69662ac0c33Sjakob 
69762ac0c33Sjakob 		if (!allow_glue && domain_is_glue(match, query->zone))
69862ac0c33Sjakob 			continue;
69962ac0c33Sjakob 
70062ac0c33Sjakob 		/*
70162ac0c33Sjakob 		 * Check to see if we need to generate the dependent
70262ac0c33Sjakob 		 * based on a wildcard domain.
70362ac0c33Sjakob 		 */
70462ac0c33Sjakob 		while (!match->is_existing) {
70562ac0c33Sjakob 			match = match->parent;
70662ac0c33Sjakob 		}
70762ac0c33Sjakob 		if (additional != match && domain_wildcard_child(match)) {
70862ac0c33Sjakob 			domain_type *wildcard_child = domain_wildcard_child(match);
70962ac0c33Sjakob 			domain_type *temp = (domain_type *) region_alloc(
71062ac0c33Sjakob 				query->region, sizeof(domain_type));
711c1e73312Sflorian #ifdef USE_RADIX_TREE
712dd5b221eSsthen 			temp->rnode = NULL;
713dd5b221eSsthen 			temp->dname = additional->dname;
714c1e73312Sflorian #else
715fe5fe5f6Sflorian 			memcpy(&temp->node, &additional->node, sizeof(rbnode_type));
716c1e73312Sflorian 			temp->node.parent = NULL;
717c1e73312Sflorian #endif
71862ac0c33Sjakob 			temp->number = additional->number;
71962ac0c33Sjakob 			temp->parent = match;
72062ac0c33Sjakob 			temp->wildcard_child_closest_match = temp;
72162ac0c33Sjakob 			temp->rrsets = wildcard_child->rrsets;
72262ac0c33Sjakob 			temp->is_existing = wildcard_child->is_existing;
72362ac0c33Sjakob 			additional = temp;
72462ac0c33Sjakob 		}
72562ac0c33Sjakob 
72662ac0c33Sjakob 		for (j = 0; types[j].rr_type != 0; ++j) {
72762ac0c33Sjakob 			rrset_type *rrset = domain_find_rrset(
72862ac0c33Sjakob 				additional, query->zone, types[j].rr_type);
72962ac0c33Sjakob 			if (rrset) {
73062ac0c33Sjakob 				answer_add_rrset(answer, types[j].rr_section,
73162ac0c33Sjakob 						 additional, rrset);
73262ac0c33Sjakob 			}
73362ac0c33Sjakob 		}
73462ac0c33Sjakob 	}
73562ac0c33Sjakob }
73662ac0c33Sjakob 
73762ac0c33Sjakob static int
answer_needs_ns(struct query * query)73862ac0c33Sjakob answer_needs_ns(struct query* query)
73962ac0c33Sjakob {
74062ac0c33Sjakob 	assert(query);
741f72b2965Sjakob 	/* Currently, only troublesome for DNSKEY and DS,
742f72b2965Sjakob          * cuz their RRSETs are quite large. */
743a1bac035Sflorian 	return (query->qtype != TYPE_DNSKEY && query->qtype != TYPE_DS
744a1bac035Sflorian 		&& query->qtype != TYPE_ANY);
74562ac0c33Sjakob }
74662ac0c33Sjakob 
74762ac0c33Sjakob static int
add_rrset(struct query * query,answer_type * answer,rr_section_type section,domain_type * owner,rrset_type * rrset)74862ac0c33Sjakob add_rrset(struct query   *query,
74962ac0c33Sjakob 	  answer_type    *answer,
75062ac0c33Sjakob 	  rr_section_type section,
75162ac0c33Sjakob 	  domain_type    *owner,
75262ac0c33Sjakob 	  rrset_type     *rrset)
75362ac0c33Sjakob {
75462ac0c33Sjakob 	int result;
75562ac0c33Sjakob 
75662ac0c33Sjakob 	assert(query);
75762ac0c33Sjakob 	assert(answer);
75862ac0c33Sjakob 	assert(owner);
75962ac0c33Sjakob 	assert(rrset);
76062ac0c33Sjakob 	assert(rrset_rrclass(rrset) == CLASS_IN);
76162ac0c33Sjakob 
76262ac0c33Sjakob 	result = answer_add_rrset(answer, section, owner, rrset);
763db7d0d02Sflorian 	if(minimal_responses && section != AUTHORITY_SECTION &&
764db7d0d02Sflorian 		query->qtype != TYPE_NS)
765db7d0d02Sflorian 		return result;
76662ac0c33Sjakob 	switch (rrset_rrtype(rrset)) {
76762ac0c33Sjakob 	case TYPE_NS:
7686e9bf1eeSflorian #if defined(INET6)
769275a8d89Sflorian 		/* if query over IPv6, swap A and AAAA; put AAAA first */
77062ac0c33Sjakob 		add_additional_rrsets(query, answer, rrset, 0, 1,
771b71395eaSflorian 			(query->client_addr.ss_family == AF_INET6)?
772275a8d89Sflorian 			swap_aaaa_additional_rr_types:
77362ac0c33Sjakob 			default_additional_rr_types);
7746e9bf1eeSflorian #else
7756e9bf1eeSflorian 		add_additional_rrsets(query, answer, rrset, 0, 1,
7766e9bf1eeSflorian 				      default_additional_rr_types);
7776e9bf1eeSflorian #endif
77862ac0c33Sjakob 		break;
77962ac0c33Sjakob 	case TYPE_MB:
78062ac0c33Sjakob 		add_additional_rrsets(query, answer, rrset, 0, 0,
78162ac0c33Sjakob 				      default_additional_rr_types);
78262ac0c33Sjakob 		break;
78362ac0c33Sjakob 	case TYPE_MX:
78462ac0c33Sjakob 	case TYPE_KX:
78562ac0c33Sjakob 		add_additional_rrsets(query, answer, rrset, 1, 0,
78662ac0c33Sjakob 				      default_additional_rr_types);
78762ac0c33Sjakob 		break;
78862ac0c33Sjakob 	case TYPE_RT:
78962ac0c33Sjakob 		add_additional_rrsets(query, answer, rrset, 1, 0,
79062ac0c33Sjakob 				      rt_additional_rr_types);
79162ac0c33Sjakob 		break;
792c1e73312Sflorian 	case TYPE_SRV:
793c1e73312Sflorian 		add_additional_rrsets(query, answer, rrset, 3, 0,
794c1e73312Sflorian 				      default_additional_rr_types);
795c1e73312Sflorian 		break;
79662ac0c33Sjakob 	default:
79762ac0c33Sjakob 		break;
79862ac0c33Sjakob 	}
79962ac0c33Sjakob 
80062ac0c33Sjakob 	return result;
80162ac0c33Sjakob }
80262ac0c33Sjakob 
80362ac0c33Sjakob 
80462ac0c33Sjakob /* returns 0 on error, or the domain number for to_name.
80562ac0c33Sjakob    from_name is changes to to_name by the DNAME rr.
80662ac0c33Sjakob    DNAME rr is from src to dest.
80762ac0c33Sjakob    closest encloser encloses the to_name. */
808dd5b221eSsthen static size_t
query_synthesize_cname(struct query * q,struct answer * answer,const dname_type * from_name,const dname_type * to_name,domain_type * src,domain_type * to_closest_encloser,domain_type ** to_closest_match,uint32_t ttl)80962ac0c33Sjakob query_synthesize_cname(struct query* q, struct answer* answer, const dname_type* from_name,
81062ac0c33Sjakob 	const dname_type* to_name, domain_type* src, domain_type* to_closest_encloser,
81121c23707Sbrad 	domain_type** to_closest_match, uint32_t ttl)
81262ac0c33Sjakob {
81362ac0c33Sjakob 	/* add temporary domains for from_name and to_name and all
81462ac0c33Sjakob 	   their (not allocated yet) parents */
81562ac0c33Sjakob 	/* any domains below src are not_existing (because of DNAME at src) */
81662ac0c33Sjakob 	int i;
8178d298c9fSsthen 	size_t j;
81862ac0c33Sjakob 	domain_type* cname_domain;
81962ac0c33Sjakob 	domain_type* cname_dest;
82062ac0c33Sjakob 	rrset_type* rrset;
82162ac0c33Sjakob 
82262ac0c33Sjakob 	domain_type* lastparent = src;
82362ac0c33Sjakob 	assert(q && answer && from_name && to_name && src && to_closest_encloser);
82462ac0c33Sjakob 	assert(to_closest_match);
8258d298c9fSsthen 
8268d298c9fSsthen 	/* check for loop by duplicate CNAME rrset synthesized */
8278d298c9fSsthen 	for(j=0; j<answer->rrset_count; ++j) {
8288d298c9fSsthen 		if(answer->section[j] == ANSWER_SECTION &&
8298d298c9fSsthen 			answer->rrsets[j]->rr_count == 1 &&
8308d298c9fSsthen 			answer->rrsets[j]->rrs[0].type == TYPE_CNAME &&
8318d298c9fSsthen 			dname_compare(domain_dname(answer->rrsets[j]->rrs[0].owner), from_name) == 0 &&
8328d298c9fSsthen 			answer->rrsets[j]->rrs[0].rdata_count == 1 &&
8338d298c9fSsthen 			dname_compare(domain_dname(answer->rrsets[j]->rrs[0].rdatas->domain), to_name) == 0) {
8348d298c9fSsthen 			DEBUG(DEBUG_QUERY,2, (LOG_INFO, "loop for synthesized CNAME rrset for query %s", dname_to_string(q->qname, NULL)));
8358d298c9fSsthen 			return 0;
8368d298c9fSsthen 		}
8378d298c9fSsthen 	}
8388d298c9fSsthen 
8398d298c9fSsthen 	/* allocate source part */
84062ac0c33Sjakob 	for(i=0; i < from_name->label_count - domain_dname(src)->label_count; i++)
84162ac0c33Sjakob 	{
84262ac0c33Sjakob 		domain_type* newdom = query_get_tempdomain(q);
84362ac0c33Sjakob 		if(!newdom)
84462ac0c33Sjakob 			return 0;
84562ac0c33Sjakob 		newdom->is_existing = 1;
84662ac0c33Sjakob 		newdom->parent = lastparent;
847c1e73312Sflorian #ifdef USE_RADIX_TREE
848dd5b221eSsthen 		newdom->dname
849c1e73312Sflorian #else
850c1e73312Sflorian 		newdom->node.key
851c1e73312Sflorian #endif
852dd5b221eSsthen 			= dname_partial_copy(q->region,
85362ac0c33Sjakob 			from_name, domain_dname(src)->label_count + i + 1);
85462ac0c33Sjakob 		if(dname_compare(domain_dname(newdom), q->qname) == 0) {
85562ac0c33Sjakob 			/* 0 good for query name, otherwise new number */
85662ac0c33Sjakob 			newdom->number = 0;
85762ac0c33Sjakob 		}
85862ac0c33Sjakob 		DEBUG(DEBUG_QUERY,2, (LOG_INFO, "created temp domain src %d. %s nr %d", i,
859dd5b221eSsthen 			domain_to_string(newdom), (int)newdom->number));
86062ac0c33Sjakob 		lastparent = newdom;
86162ac0c33Sjakob 	}
86262ac0c33Sjakob 	cname_domain = lastparent;
86362ac0c33Sjakob 
86462ac0c33Sjakob 	/* allocate dest part */
86562ac0c33Sjakob 	lastparent = to_closest_encloser;
86662ac0c33Sjakob 	for(i=0; i < to_name->label_count - domain_dname(to_closest_encloser)->label_count;
86762ac0c33Sjakob 		i++)
86862ac0c33Sjakob 	{
86962ac0c33Sjakob 		domain_type* newdom = query_get_tempdomain(q);
87062ac0c33Sjakob 		if(!newdom)
87162ac0c33Sjakob 			return 0;
87262ac0c33Sjakob 		newdom->is_existing = 0;
87362ac0c33Sjakob 		newdom->parent = lastparent;
874c1e73312Sflorian #ifdef USE_RADIX_TREE
875dd5b221eSsthen 		newdom->dname
876c1e73312Sflorian #else
877c1e73312Sflorian 		newdom->node.key
878c1e73312Sflorian #endif
879dd5b221eSsthen 			= dname_partial_copy(q->region,
88062ac0c33Sjakob 			to_name, domain_dname(to_closest_encloser)->label_count + i + 1);
88162ac0c33Sjakob 		DEBUG(DEBUG_QUERY,2, (LOG_INFO, "created temp domain dest %d. %s nr %d", i,
882dd5b221eSsthen 			domain_to_string(newdom), (int)newdom->number));
88362ac0c33Sjakob 		lastparent = newdom;
88462ac0c33Sjakob 	}
88562ac0c33Sjakob 	cname_dest = lastparent;
88662ac0c33Sjakob 	*to_closest_match = cname_dest;
88762ac0c33Sjakob 
88862ac0c33Sjakob 	/* allocate the CNAME RR */
88962ac0c33Sjakob 	rrset = (rrset_type*) region_alloc(q->region, sizeof(rrset_type));
89062ac0c33Sjakob 	memset(rrset, 0, sizeof(rrset_type));
89162ac0c33Sjakob 	rrset->zone = q->zone;
89262ac0c33Sjakob 	rrset->rr_count = 1;
89362ac0c33Sjakob 	rrset->rrs = (rr_type*) region_alloc(q->region, sizeof(rr_type));
89462ac0c33Sjakob 	memset(rrset->rrs, 0, sizeof(rr_type));
89562ac0c33Sjakob 	rrset->rrs->owner = cname_domain;
89621c23707Sbrad 	rrset->rrs->ttl = ttl;
89762ac0c33Sjakob 	rrset->rrs->type = TYPE_CNAME;
89862ac0c33Sjakob 	rrset->rrs->klass = CLASS_IN;
89962ac0c33Sjakob 	rrset->rrs->rdata_count = 1;
90062ac0c33Sjakob 	rrset->rrs->rdatas = (rdata_atom_type*)region_alloc(q->region,
90162ac0c33Sjakob 		sizeof(rdata_atom_type));
90262ac0c33Sjakob 	rrset->rrs->rdatas->domain = cname_dest;
90362ac0c33Sjakob 
90462ac0c33Sjakob 	if(!add_rrset(q, answer, ANSWER_SECTION, cname_domain, rrset)) {
9058d298c9fSsthen 		DEBUG(DEBUG_QUERY,2, (LOG_INFO, "could not add synthesized CNAME rrset to packet for query %s", dname_to_string(q->qname, NULL)));
9068d298c9fSsthen 		/* failure to add CNAME; likely is a loop, the same twice */
9078d298c9fSsthen 		return 0;
90862ac0c33Sjakob 	}
90962ac0c33Sjakob 
91062ac0c33Sjakob 	return cname_dest->number;
91162ac0c33Sjakob }
91262ac0c33Sjakob 
91362ac0c33Sjakob /*
91462ac0c33Sjakob  * Answer delegation information.
91562ac0c33Sjakob  *
91662ac0c33Sjakob  * DNSSEC: Include the DS RRset if present.  Otherwise include an NSEC
91762ac0c33Sjakob  * record proving the DS RRset does not exist.
91862ac0c33Sjakob  */
91962ac0c33Sjakob static void
answer_delegation(query_type * query,answer_type * answer)92062ac0c33Sjakob answer_delegation(query_type *query, answer_type *answer)
92162ac0c33Sjakob {
92262ac0c33Sjakob 	assert(answer);
92362ac0c33Sjakob 	assert(query->delegation_domain);
92462ac0c33Sjakob 	assert(query->delegation_rrset);
92562ac0c33Sjakob 
9265bcb494bSjakob 	if (query->cname_count == 0) {
92762ac0c33Sjakob 		AA_CLR(query->packet);
9285bcb494bSjakob 	} else {
9295bcb494bSjakob 		AA_SET(query->packet);
9305bcb494bSjakob 	}
9315bcb494bSjakob 
93262ac0c33Sjakob 	add_rrset(query,
93362ac0c33Sjakob 		  answer,
93462ac0c33Sjakob 		  AUTHORITY_SECTION,
93562ac0c33Sjakob 		  query->delegation_domain,
93662ac0c33Sjakob 		  query->delegation_rrset);
93762ac0c33Sjakob 	if (query->edns.dnssec_ok && zone_is_secure(query->zone)) {
93862ac0c33Sjakob 		rrset_type *rrset;
93962ac0c33Sjakob 		if ((rrset = domain_find_rrset(query->delegation_domain, query->zone, TYPE_DS))) {
94062ac0c33Sjakob 			add_rrset(query, answer, AUTHORITY_SECTION,
94162ac0c33Sjakob 				  query->delegation_domain, rrset);
94262ac0c33Sjakob #ifdef NSEC3
943dd5b221eSsthen 		} else if (query->zone->nsec3_param) {
94462ac0c33Sjakob 			nsec3_answer_delegation(query, answer);
94562ac0c33Sjakob #endif
94662ac0c33Sjakob 		} else if ((rrset = domain_find_rrset(query->delegation_domain, query->zone, TYPE_NSEC))) {
94762ac0c33Sjakob 			add_rrset(query, answer, AUTHORITY_SECTION,
94862ac0c33Sjakob 				  query->delegation_domain, rrset);
94962ac0c33Sjakob 		}
95062ac0c33Sjakob 	}
95162ac0c33Sjakob }
95262ac0c33Sjakob 
95362ac0c33Sjakob 
95462ac0c33Sjakob /*
95562ac0c33Sjakob  * Answer SOA information.
95662ac0c33Sjakob  */
95762ac0c33Sjakob static void
answer_soa(struct query * query,answer_type * answer)95862ac0c33Sjakob answer_soa(struct query *query, answer_type *answer)
95962ac0c33Sjakob {
96062ac0c33Sjakob 	if (query->qclass != CLASS_ANY) {
96162ac0c33Sjakob 		add_rrset(query, answer,
96262ac0c33Sjakob 			  AUTHORITY_SECTION,
96362ac0c33Sjakob 			  query->zone->apex,
96462ac0c33Sjakob 			  query->zone->soa_nx_rrset);
96562ac0c33Sjakob 	}
96662ac0c33Sjakob }
96762ac0c33Sjakob 
96862ac0c33Sjakob 
96962ac0c33Sjakob /*
97062ac0c33Sjakob  * Answer that the domain name exists but there is no RRset with the
97162ac0c33Sjakob  * requested type.
97262ac0c33Sjakob  *
97362ac0c33Sjakob  * DNSSEC: Include the correct NSEC record proving that the type does
97462ac0c33Sjakob  * not exist.  In the wildcard no data (3.1.3.4) case the wildcard IS
97562ac0c33Sjakob  * NOT expanded, so the ORIGINAL parameter must point to the original
97662ac0c33Sjakob  * wildcard entry, not to the generated entry.
97762ac0c33Sjakob  */
97862ac0c33Sjakob static void
answer_nodata(struct query * query,answer_type * answer,domain_type * original)97962ac0c33Sjakob answer_nodata(struct query *query, answer_type *answer, domain_type *original)
98062ac0c33Sjakob {
98162ac0c33Sjakob 	answer_soa(query, answer);
98262ac0c33Sjakob 
98362ac0c33Sjakob #ifdef NSEC3
984dd5b221eSsthen 	if (query->edns.dnssec_ok && query->zone->nsec3_param) {
98562ac0c33Sjakob 		nsec3_answer_nodata(query, answer, original);
98662ac0c33Sjakob 	} else
98762ac0c33Sjakob #endif
98862ac0c33Sjakob 	if (query->edns.dnssec_ok && zone_is_secure(query->zone)) {
98962ac0c33Sjakob 		domain_type *nsec_domain;
99062ac0c33Sjakob 		rrset_type *nsec_rrset;
99162ac0c33Sjakob 
99262ac0c33Sjakob 		nsec_domain = find_covering_nsec(original, query->zone, &nsec_rrset);
99362ac0c33Sjakob 		if (nsec_domain) {
99462ac0c33Sjakob 			add_rrset(query, answer, AUTHORITY_SECTION, nsec_domain, nsec_rrset);
99562ac0c33Sjakob 		}
99662ac0c33Sjakob 	}
99762ac0c33Sjakob }
99862ac0c33Sjakob 
99962ac0c33Sjakob static void
answer_nxdomain(query_type * query,answer_type * answer)100062ac0c33Sjakob answer_nxdomain(query_type *query, answer_type *answer)
100162ac0c33Sjakob {
100262ac0c33Sjakob 	RCODE_SET(query->packet, RCODE_NXDOMAIN);
100362ac0c33Sjakob 	answer_soa(query, answer);
100462ac0c33Sjakob }
100562ac0c33Sjakob 
100662ac0c33Sjakob 
100762ac0c33Sjakob /*
100862ac0c33Sjakob  * Answer domain information (or SOA if we do not have an RRset for
100962ac0c33Sjakob  * the type specified by the query).
101062ac0c33Sjakob  */
101162ac0c33Sjakob static void
answer_domain(struct nsd * nsd,struct query * q,answer_type * answer,domain_type * domain,domain_type * original)101262ac0c33Sjakob answer_domain(struct nsd* nsd, struct query *q, answer_type *answer,
101362ac0c33Sjakob 	      domain_type *domain, domain_type *original)
101462ac0c33Sjakob {
101562ac0c33Sjakob 	rrset_type *rrset;
101662ac0c33Sjakob 
101762ac0c33Sjakob 	if (q->qtype == TYPE_ANY) {
1018308d2509Sflorian 		rrset_type *preferred_rrset = NULL;
1019308d2509Sflorian 		rrset_type *normal_rrset = NULL;
1020308d2509Sflorian 		rrset_type *non_preferred_rrset = NULL;
1021308d2509Sflorian 
1022308d2509Sflorian 		/*
1023308d2509Sflorian 		 * Minimize response size for ANY, with one RRset
1024308d2509Sflorian 		 * according to RFC 8482(4.1).
1025308d2509Sflorian 		 * Prefers popular and not large rtypes (A,AAAA,...)
1026308d2509Sflorian 		 * lowering large ones (DNSKEY,RRSIG,...).
1027308d2509Sflorian 		 */
102862ac0c33Sjakob 		for (rrset = domain_find_any_rrset(domain, q->zone); rrset; rrset = rrset->next) {
102962ac0c33Sjakob 			if (rrset->zone == q->zone
103062ac0c33Sjakob #ifdef NSEC3
103162ac0c33Sjakob 				&& rrset_rrtype(rrset) != TYPE_NSEC3
103262ac0c33Sjakob #endif
103362ac0c33Sjakob 			    /*
103462ac0c33Sjakob 			     * Don't include the RRSIG RRset when
103562ac0c33Sjakob 			     * DNSSEC is used, because it is added
103662ac0c33Sjakob 			     * automatically on an per-RRset basis.
103762ac0c33Sjakob 			     */
103862ac0c33Sjakob 			    && !(q->edns.dnssec_ok
103962ac0c33Sjakob 				 && zone_is_secure(q->zone)
104062ac0c33Sjakob 				 && rrset_rrtype(rrset) == TYPE_RRSIG))
104162ac0c33Sjakob 			{
1042308d2509Sflorian 				switch(rrset_rrtype(rrset)) {
1043308d2509Sflorian 					case TYPE_A:
1044308d2509Sflorian 					case TYPE_AAAA:
1045308d2509Sflorian 					case TYPE_SOA:
1046308d2509Sflorian 					case TYPE_MX:
1047308d2509Sflorian 					case TYPE_PTR:
1048308d2509Sflorian 						preferred_rrset = rrset;
1049a1bac035Sflorian 						break;
1050308d2509Sflorian 					case TYPE_DNSKEY:
1051308d2509Sflorian 					case TYPE_RRSIG:
1052308d2509Sflorian 					case TYPE_NSEC:
1053308d2509Sflorian 						non_preferred_rrset = rrset;
1054308d2509Sflorian 						break;
1055308d2509Sflorian 					default:
1056308d2509Sflorian 						normal_rrset = rrset;
1057308d2509Sflorian 				}
1058308d2509Sflorian 				if (preferred_rrset) break;
105962ac0c33Sjakob 			}
106062ac0c33Sjakob 		}
1061308d2509Sflorian 		if (preferred_rrset) {
1062308d2509Sflorian 			add_rrset(q, answer, ANSWER_SECTION, domain, preferred_rrset);
1063308d2509Sflorian 		} else if (normal_rrset) {
1064308d2509Sflorian 			add_rrset(q, answer, ANSWER_SECTION, domain, normal_rrset);
1065308d2509Sflorian 		} else if (non_preferred_rrset) {
1066308d2509Sflorian 			add_rrset(q, answer, ANSWER_SECTION, domain, non_preferred_rrset);
1067308d2509Sflorian 		} else {
106862ac0c33Sjakob 			answer_nodata(q, answer, original);
106962ac0c33Sjakob 			return;
107062ac0c33Sjakob 		}
107162ac0c33Sjakob #ifdef NSEC3
107262ac0c33Sjakob 	} else if (q->qtype == TYPE_NSEC3) {
107362ac0c33Sjakob 		answer_nodata(q, answer, original);
107462ac0c33Sjakob 		return;
107562ac0c33Sjakob #endif
107662ac0c33Sjakob 	} else if ((rrset = domain_find_rrset(domain, q->zone, q->qtype))) {
107762ac0c33Sjakob 		add_rrset(q, answer, ANSWER_SECTION, domain, rrset);
107862ac0c33Sjakob 	} else if ((rrset = domain_find_rrset(domain, q->zone, TYPE_CNAME))) {
107962ac0c33Sjakob 		int added;
108062ac0c33Sjakob 
108162ac0c33Sjakob 		/*
108262ac0c33Sjakob 		 * If the CNAME is not added it is already in the
108362ac0c33Sjakob 		 * answer, so we have a CNAME loop.  Don't follow the
108462ac0c33Sjakob 		 * CNAME target in this case.
108562ac0c33Sjakob 		 */
108662ac0c33Sjakob 		added = add_rrset(q, answer, ANSWER_SECTION, domain, rrset);
108762ac0c33Sjakob 		assert(rrset->rr_count > 0);
108862ac0c33Sjakob 		if (added) {
108962ac0c33Sjakob 			/* only process first CNAME record */
109062ac0c33Sjakob 			domain_type *closest_match = rdata_atom_domain(rrset->rrs[0].rdatas[0]);
109162ac0c33Sjakob 			domain_type *closest_encloser = closest_match;
109262ac0c33Sjakob 			zone_type* origzone = q->zone;
109362ac0c33Sjakob 			++q->cname_count;
109462ac0c33Sjakob 
109562ac0c33Sjakob 			answer_lookup_zone(nsd, q, answer, closest_match->number,
109662ac0c33Sjakob 					     closest_match == closest_encloser,
109762ac0c33Sjakob 					     closest_match, closest_encloser,
109862ac0c33Sjakob 					     domain_dname(closest_match));
109962ac0c33Sjakob 			q->zone = origzone;
110062ac0c33Sjakob 		}
11015bcb494bSjakob 		return;
110262ac0c33Sjakob 	} else {
110362ac0c33Sjakob 		answer_nodata(q, answer, original);
110462ac0c33Sjakob 		return;
110562ac0c33Sjakob 	}
110662ac0c33Sjakob 
1107db7d0d02Sflorian 	if (q->qclass != CLASS_ANY && q->zone->ns_rrset && answer_needs_ns(q)
1108db7d0d02Sflorian 		&& !minimal_responses) {
11095bcb494bSjakob 		add_rrset(q, answer, OPTIONAL_AUTHORITY_SECTION, q->zone->apex,
111062ac0c33Sjakob 			  q->zone->ns_rrset);
111162ac0c33Sjakob 	}
111262ac0c33Sjakob }
111362ac0c33Sjakob 
111462ac0c33Sjakob 
111562ac0c33Sjakob /*
111662ac0c33Sjakob  * Answer with authoritative data.  If a wildcard is matched the owner
111762ac0c33Sjakob  * name will be expanded to the domain name specified by
111862ac0c33Sjakob  * DOMAIN_NUMBER.  DOMAIN_NUMBER 0 (zero) is reserved for the original
111962ac0c33Sjakob  * query name.
112062ac0c33Sjakob  *
112162ac0c33Sjakob  * DNSSEC: Include the necessary NSEC records in case the request
112262ac0c33Sjakob  * domain name does not exist and/or a wildcard match does not exist.
112362ac0c33Sjakob  */
112462ac0c33Sjakob static void
answer_authoritative(struct nsd * nsd,struct query * q,answer_type * answer,size_t domain_number,int exact,domain_type * closest_match,domain_type * closest_encloser,const dname_type * qname)112562ac0c33Sjakob answer_authoritative(struct nsd   *nsd,
112662ac0c33Sjakob 		     struct query *q,
112762ac0c33Sjakob 		     answer_type  *answer,
1128dd5b221eSsthen 		     size_t        domain_number,
112962ac0c33Sjakob 		     int           exact,
113062ac0c33Sjakob 		     domain_type  *closest_match,
113162ac0c33Sjakob 		     domain_type  *closest_encloser,
113262ac0c33Sjakob 		     const dname_type *qname)
113362ac0c33Sjakob {
113462ac0c33Sjakob 	domain_type *match;
113562ac0c33Sjakob 	domain_type *original = closest_match;
1136275a8d89Sflorian 	domain_type *dname_ce;
11378d298c9fSsthen 	domain_type *wildcard_child;
113862ac0c33Sjakob 	rrset_type *rrset;
113962ac0c33Sjakob 
114062ac0c33Sjakob #ifdef NSEC3
114162ac0c33Sjakob 	if(exact && domain_has_only_NSEC3(closest_match, q->zone)) {
114262ac0c33Sjakob 		exact = 0; /* pretend it does not exist */
114362ac0c33Sjakob 		if(closest_encloser->parent)
114462ac0c33Sjakob 			closest_encloser = closest_encloser->parent;
114562ac0c33Sjakob 	}
114662ac0c33Sjakob #endif /* NSEC3 */
1147275a8d89Sflorian 	if((dname_ce = find_dname_above(closest_encloser, q->zone)) != NULL) {
1148275a8d89Sflorian 		/* occlude the found data, the DNAME is closest_encloser */
1149275a8d89Sflorian 		closest_encloser = dname_ce;
1150275a8d89Sflorian 		exact = 0;
1151275a8d89Sflorian 	}
115262ac0c33Sjakob 
115362ac0c33Sjakob 	if (exact) {
115462ac0c33Sjakob 		match = closest_match;
115562ac0c33Sjakob 	} else if ((rrset=domain_find_rrset(closest_encloser, q->zone, TYPE_DNAME))) {
115662ac0c33Sjakob 		/* process DNAME */
115762ac0c33Sjakob 		const dname_type* name = qname;
11588d298c9fSsthen 		domain_type* src = closest_encloser;
115962ac0c33Sjakob 		domain_type *dest = rdata_atom_domain(rrset->rrs[0].rdatas[0]);
11608d298c9fSsthen 		const dname_type* newname;
11618d298c9fSsthen 		size_t newnum = 0;
11628d298c9fSsthen 		zone_type* origzone = q->zone;
116362ac0c33Sjakob 		assert(rrset->rr_count > 0);
116462ac0c33Sjakob 		if(domain_number != 0) /* we followed CNAMEs or DNAMEs */
116562ac0c33Sjakob 			name = domain_dname(closest_match);
116662ac0c33Sjakob 		DEBUG(DEBUG_QUERY,2, (LOG_INFO, "expanding DNAME for q=%s", dname_to_string(name, NULL)));
116762ac0c33Sjakob 		DEBUG(DEBUG_QUERY,2, (LOG_INFO, "->src is %s",
1168dd5b221eSsthen 			domain_to_string(closest_encloser)));
116962ac0c33Sjakob 		DEBUG(DEBUG_QUERY,2, (LOG_INFO, "->dest is %s",
1170dd5b221eSsthen 			domain_to_string(dest)));
11718d298c9fSsthen 		if(!add_rrset(q, answer, ANSWER_SECTION, closest_encloser, rrset)) {
11728d298c9fSsthen 			/* stop if DNAME loops, when added second time */
11738d298c9fSsthen 			if(dname_is_subdomain(domain_dname(dest), domain_dname(src))) {
11748d298c9fSsthen 				return;
11758d298c9fSsthen 			}
11768d298c9fSsthen 		}
11778d298c9fSsthen 		newname = dname_replace(q->region, name,
117862ac0c33Sjakob 			domain_dname(src), domain_dname(dest));
117962ac0c33Sjakob 		++q->cname_count;
118062ac0c33Sjakob 		if(!newname) { /* newname too long */
118162ac0c33Sjakob 			RCODE_SET(q->packet, RCODE_YXDOMAIN);
11828d298c9fSsthen 			/* RFC 8914 - Extended DNS Errors
11838d298c9fSsthen 			 * 4.21. Extended DNS Error Code 0 - Other */
11848d298c9fSsthen 			ASSIGN_EDE_CODE_AND_STRING_LITERAL(q->edns.ede,
11858d298c9fSsthen 				EDE_OTHER, "DNAME expansion became too large");
118662ac0c33Sjakob 			return;
118762ac0c33Sjakob 		}
118862ac0c33Sjakob 		DEBUG(DEBUG_QUERY,2, (LOG_INFO, "->result is %s", dname_to_string(newname, NULL)));
118962ac0c33Sjakob 		/* follow the DNAME */
1190b90bb40eSsthen 		(void)namedb_lookup(nsd->db, newname, &closest_match, &closest_encloser);
119162ac0c33Sjakob 		/* synthesize CNAME record */
119262ac0c33Sjakob 		newnum = query_synthesize_cname(q, answer, name, newname,
119321c23707Sbrad 			src, closest_encloser, &closest_match, rrset->rrs[0].ttl);
119462ac0c33Sjakob 		if(!newnum) {
119562ac0c33Sjakob 			/* could not synthesize the CNAME. */
119662ac0c33Sjakob 			/* return previous CNAMEs to make resolver recurse for us */
119762ac0c33Sjakob 			return;
119862ac0c33Sjakob 		}
11998d298c9fSsthen 		if(q->qtype == TYPE_CNAME) {
12008d298c9fSsthen 			/* The synthesized CNAME is the answer to
12018d298c9fSsthen 			 * that query, same as BIND does for query
12028d298c9fSsthen 			 * of type CNAME */
12038d298c9fSsthen 			return;
12048d298c9fSsthen 		}
120562ac0c33Sjakob 
120662ac0c33Sjakob 		answer_lookup_zone(nsd, q, answer, newnum,
120762ac0c33Sjakob 			closest_match == closest_encloser,
120862ac0c33Sjakob 			closest_match, closest_encloser, newname);
120962ac0c33Sjakob 		q->zone = origzone;
121062ac0c33Sjakob 		return;
12118d298c9fSsthen 	} else if ((wildcard_child=domain_wildcard_child(closest_encloser))!=NULL &&
12128d298c9fSsthen 		wildcard_child->is_existing) {
121362ac0c33Sjakob 		/* Generate the domain from the wildcard.  */
121475343be4Ssthen #ifdef RATELIMIT
121575343be4Ssthen 		q->wildcard_domain = wildcard_child;
121675343be4Ssthen #endif
121762ac0c33Sjakob 
121862ac0c33Sjakob 		match = (domain_type *) region_alloc(q->region,
121962ac0c33Sjakob 						     sizeof(domain_type));
1220c1e73312Sflorian #ifdef USE_RADIX_TREE
1221dd5b221eSsthen 		match->rnode = NULL;
1222dd5b221eSsthen 		match->dname = wildcard_child->dname;
1223c1e73312Sflorian #else
1224fe5fe5f6Sflorian 		memcpy(&match->node, &wildcard_child->node, sizeof(rbnode_type));
1225c1e73312Sflorian 		match->node.parent = NULL;
1226c1e73312Sflorian #endif
122762ac0c33Sjakob 		match->parent = closest_encloser;
122862ac0c33Sjakob 		match->wildcard_child_closest_match = match;
122962ac0c33Sjakob 		match->number = domain_number;
123062ac0c33Sjakob 		match->rrsets = wildcard_child->rrsets;
123162ac0c33Sjakob 		match->is_existing = wildcard_child->is_existing;
123262ac0c33Sjakob #ifdef NSEC3
1233dd5b221eSsthen 		match->nsec3 = wildcard_child->nsec3;
1234dd5b221eSsthen 		/* copy over these entries:
12355bcb494bSjakob 		match->nsec3_is_exact = wildcard_child->nsec3_is_exact;
1236dd5b221eSsthen 		match->nsec3_cover = wildcard_child->nsec3_cover;
123762ac0c33Sjakob 		match->nsec3_wcard_child_cover = wildcard_child->nsec3_wcard_child_cover;
123862ac0c33Sjakob 		match->nsec3_ds_parent_is_exact = wildcard_child->nsec3_ds_parent_is_exact;
123962ac0c33Sjakob 		match->nsec3_ds_parent_cover = wildcard_child->nsec3_ds_parent_cover;
1240dd5b221eSsthen 		*/
1241dd5b221eSsthen 
1242dd5b221eSsthen 		if (q->edns.dnssec_ok && q->zone->nsec3_param) {
124362ac0c33Sjakob 			/* Only add nsec3 wildcard data when do bit is set */
1244dd5b221eSsthen 			nsec3_answer_wildcard(q, answer, wildcard_child, qname);
124562ac0c33Sjakob 		}
124662ac0c33Sjakob #endif
124762ac0c33Sjakob 
124862ac0c33Sjakob 		/*
124962ac0c33Sjakob 		 * Remember the original domain in case a Wildcard No
125062ac0c33Sjakob 		 * Data (3.1.3.4) response needs to be generated.  In
125162ac0c33Sjakob 		 * this particular case the wildcard IS NOT
125262ac0c33Sjakob 		 * expanded.
125362ac0c33Sjakob 		 */
125462ac0c33Sjakob 		original = wildcard_child;
125562ac0c33Sjakob 	} else {
125662ac0c33Sjakob 		match = NULL;
125762ac0c33Sjakob 	}
125862ac0c33Sjakob 
12592fd875a4Ssthen 	/* Authoritative zone.  */
126062ac0c33Sjakob #ifdef NSEC3
1261dd5b221eSsthen 	if (q->edns.dnssec_ok && q->zone->nsec3_param) {
126262ac0c33Sjakob 		nsec3_answer_authoritative(&match, q, answer,
1263dd5b221eSsthen 			closest_encloser, qname);
126462ac0c33Sjakob 	} else
126562ac0c33Sjakob #endif
126662ac0c33Sjakob 	if (q->edns.dnssec_ok && zone_is_secure(q->zone)) {
126762ac0c33Sjakob 		if (match != closest_encloser) {
126862ac0c33Sjakob 			domain_type *nsec_domain;
126962ac0c33Sjakob 			rrset_type *nsec_rrset;
127062ac0c33Sjakob 
127162ac0c33Sjakob 			/*
127262ac0c33Sjakob 			 * No match found or generated from wildcard,
127362ac0c33Sjakob 			 * include NSEC record.
127462ac0c33Sjakob 			 */
127562ac0c33Sjakob 			nsec_domain = find_covering_nsec(closest_match, q->zone, &nsec_rrset);
127662ac0c33Sjakob 			if (nsec_domain) {
127762ac0c33Sjakob 				add_rrset(q, answer, AUTHORITY_SECTION, nsec_domain, nsec_rrset);
127862ac0c33Sjakob 			}
127962ac0c33Sjakob 		}
128062ac0c33Sjakob 		if (!match) {
128162ac0c33Sjakob 			domain_type *nsec_domain;
128262ac0c33Sjakob 			rrset_type *nsec_rrset;
128362ac0c33Sjakob 
128462ac0c33Sjakob 			/*
128562ac0c33Sjakob 			 * No match and no wildcard.  Include NSEC
128662ac0c33Sjakob 			 * proving there is no wildcard.
128762ac0c33Sjakob 			 */
1288a1bac035Sflorian 			if(closest_encloser && (nsec_domain =
1289a1bac035Sflorian 				find_covering_nsec(closest_encloser->
1290a1bac035Sflorian 					wildcard_child_closest_match, q->zone,
1291a1bac035Sflorian 					&nsec_rrset)) != NULL) {
129262ac0c33Sjakob 				add_rrset(q, answer, AUTHORITY_SECTION, nsec_domain, nsec_rrset);
129362ac0c33Sjakob 			}
129462ac0c33Sjakob 		}
129562ac0c33Sjakob 	}
129662ac0c33Sjakob 
129762ac0c33Sjakob #ifdef NSEC3
129862ac0c33Sjakob 	if (RCODE(q->packet)!=RCODE_OK) {
129962ac0c33Sjakob 		return; /* nsec3 collision failure */
130062ac0c33Sjakob 	}
130162ac0c33Sjakob #endif
130262ac0c33Sjakob 	if (match) {
130362ac0c33Sjakob 		answer_domain(nsd, q, answer, match, original);
130462ac0c33Sjakob 	} else {
130562ac0c33Sjakob 		answer_nxdomain(q, answer);
130662ac0c33Sjakob 	}
130762ac0c33Sjakob }
130862ac0c33Sjakob 
130962ac0c33Sjakob /*
131062ac0c33Sjakob  * qname may be different after CNAMEs have been followed from query->qname.
131162ac0c33Sjakob  */
131262ac0c33Sjakob static void
answer_lookup_zone(struct nsd * nsd,struct query * q,answer_type * answer,size_t domain_number,int exact,domain_type * closest_match,domain_type * closest_encloser,const dname_type * qname)131362ac0c33Sjakob answer_lookup_zone(struct nsd *nsd, struct query *q, answer_type *answer,
1314dd5b221eSsthen 	size_t domain_number, int exact, domain_type *closest_match,
131562ac0c33Sjakob 	domain_type *closest_encloser, const dname_type *qname)
131662ac0c33Sjakob {
13175435475dSsthen 	zone_type* origzone = q->zone;
13185fab9a23Sbrad 	q->zone = domain_find_zone(nsd->db, closest_encloser);
131962ac0c33Sjakob 	if (!q->zone) {
13205fab9a23Sbrad 		/* no zone for this */
13218d298c9fSsthen 		if(q->cname_count == 0) {
13225fab9a23Sbrad 			RCODE_SET(q->packet, RCODE_REFUSE);
13238d298c9fSsthen 			/* RFC 8914 - Extended DNS Errors
13248d298c9fSsthen 			 * 4.21. Extended DNS Error Code 20 - Not Authoritative */
13258d298c9fSsthen 			q->edns.ede = EDE_NOT_AUTHORITATIVE;
13268d298c9fSsthen 		}
13275fab9a23Sbrad 		return;
13285fab9a23Sbrad 	}
1329bfd0b123Sflorian 	assert(closest_encloser); /* otherwise, no q->zone would be found */
13308d298c9fSsthen 	if(q->zone->opts && q->zone->opts->pattern
13318d298c9fSsthen 	&& q->zone->opts->pattern->allow_query) {
13328d298c9fSsthen 		struct acl_options *why = NULL;
13338d298c9fSsthen 
13348d298c9fSsthen 		/* check if it passes acl */
1335b71395eaSflorian 		if(q->is_proxied && acl_check_incoming_block_proxy(
1336b71395eaSflorian 			q->zone->opts->pattern->allow_query, q, &why) == -1) {
1337b71395eaSflorian 			/* the proxy address is blocked */
1338b71395eaSflorian 			if (verbosity >= 2) {
1339b71395eaSflorian 				char address[128], proxy[128];
1340b71395eaSflorian 				addr2str(&q->client_addr, address, sizeof(address));
1341b71395eaSflorian 				addr2str(&q->remote_addr, proxy, sizeof(proxy));
1342b71395eaSflorian 				VERBOSITY(2, (LOG_INFO, "query %s from %s via proxy %s refused because of proxy, %s %s",
1343b71395eaSflorian 					dname_to_string(q->qname, NULL),
1344b71395eaSflorian 					address, proxy,
1345b71395eaSflorian 					(why?why->ip_address_spec:"."),
1346b71395eaSflorian 					(why ? ( why->nokey    ? "NOKEY"
1347b71395eaSflorian 					      : why->blocked  ? "BLOCKED"
1348b71395eaSflorian 					      : why->key_name )
1349b71395eaSflorian 					    : "no acl matches")));
1350b71395eaSflorian 			}
1351b71395eaSflorian 			/* no zone for this */
1352b71395eaSflorian 			if(q->cname_count == 0) {
1353b71395eaSflorian 				RCODE_SET(q->packet, RCODE_REFUSE);
1354b71395eaSflorian 				/* RFC8914 - Extended DNS Errors
1355b71395eaSflorian 				 * 4.19. Extended DNS Error Code 18 - Prohibited */
1356b71395eaSflorian 				q->edns.ede = EDE_PROHIBITED;
1357b71395eaSflorian 			}
1358b71395eaSflorian 			return;
1359b71395eaSflorian 		}
13608d298c9fSsthen 		if(acl_check_incoming(
13618d298c9fSsthen 		   q->zone->opts->pattern->allow_query, q, &why) != -1) {
13628d298c9fSsthen 			assert(why);
13638d298c9fSsthen 			DEBUG(DEBUG_QUERY,1, (LOG_INFO, "query %s passed acl %s %s",
13648d298c9fSsthen 				dname_to_string(q->qname, NULL),
13658d298c9fSsthen 				why->ip_address_spec,
13668d298c9fSsthen 				why->nokey?"NOKEY":
13678d298c9fSsthen 				(why->blocked?"BLOCKED":why->key_name)));
1368*bf87c3c0Sflorian 		} else if(q->qtype == TYPE_SOA
1369*bf87c3c0Sflorian 		       &&  0 == dname_compare(q->qname,
1370*bf87c3c0Sflorian 				(const dname_type*)q->zone->opts->node.key)
1371*bf87c3c0Sflorian 		       && -1 != acl_check_incoming(
1372*bf87c3c0Sflorian 				q->zone->opts->pattern->provide_xfr, q,&why)) {
1373*bf87c3c0Sflorian 			assert(why);
1374*bf87c3c0Sflorian 			DEBUG(DEBUG_QUERY,1, (LOG_INFO, "SOA apex query %s "
1375*bf87c3c0Sflorian 				"passed request-xfr acl %s %s",
1376*bf87c3c0Sflorian 				dname_to_string(q->qname, NULL),
1377*bf87c3c0Sflorian 				why->ip_address_spec,
1378*bf87c3c0Sflorian 				why->nokey?"NOKEY":
1379*bf87c3c0Sflorian 				(why->blocked?"BLOCKED":why->key_name)));
13808d298c9fSsthen 		} else {
13818d298c9fSsthen 			if (verbosity >= 2) {
13828d298c9fSsthen 				char address[128];
1383b71395eaSflorian 				addr2str(&q->client_addr, address, sizeof(address));
13848d298c9fSsthen 				VERBOSITY(2, (LOG_INFO, "query %s from %s refused, %s %s",
13858d298c9fSsthen 					dname_to_string(q->qname, NULL),
13868d298c9fSsthen 					address,
13878d298c9fSsthen 					why ? ( why->nokey    ? "NOKEY"
13888d298c9fSsthen 					      : why->blocked  ? "BLOCKED"
13898d298c9fSsthen 					      : why->key_name )
13908d298c9fSsthen 					    : "no acl matches",
13918d298c9fSsthen 					why?why->ip_address_spec:"."));
13928d298c9fSsthen 			}
13938d298c9fSsthen 			/* no zone for this */
13948d298c9fSsthen 			if(q->cname_count == 0) {
13958d298c9fSsthen 				RCODE_SET(q->packet, RCODE_REFUSE);
13968d298c9fSsthen 				/* RFC8914 - Extended DNS Errors
13978d298c9fSsthen 				 * 4.19. Extended DNS Error Code 18 - Prohibited */
13988d298c9fSsthen 				q->edns.ede = EDE_PROHIBITED;
13998d298c9fSsthen 			}
14008d298c9fSsthen 			return;
14018d298c9fSsthen 		}
14028d298c9fSsthen 	}
14035fab9a23Sbrad 	if(!q->zone->apex || !q->zone->soa_rrset) {
14045fab9a23Sbrad 		/* zone is configured but not loaded */
14058d298c9fSsthen 		if(q->cname_count == 0) {
140662ac0c33Sjakob 			RCODE_SET(q->packet, RCODE_SERVFAIL);
14078d298c9fSsthen 			/* RFC 8914 - Extended DNS Errors
14088d298c9fSsthen 			 * 4.15. Extended DNS Error Code 14 - Not Ready */
14098d298c9fSsthen 			q->edns.ede = EDE_NOT_READY;
14108d298c9fSsthen 			ASSIGN_EDE_CODE_AND_STRING_LITERAL(q->edns.ede,
14118d298c9fSsthen 			    EDE_NOT_READY, "Zone is configured but not loaded");
14128d298c9fSsthen 		}
141362ac0c33Sjakob 		return;
141462ac0c33Sjakob 	}
14155435475dSsthen 
14165435475dSsthen 	/*
14175435475dSsthen 	 * If confine-to-zone is set to yes do not return additional
14185435475dSsthen 	 * information for a zone with a different apex from the query zone.
14195435475dSsthen 	*/
14205435475dSsthen 	if (nsd->options->confine_to_zone &&
14215435475dSsthen 	   (origzone != NULL && dname_compare(domain_dname(origzone->apex), domain_dname(q->zone->apex)) != 0)) {
14225435475dSsthen 		return;
14235435475dSsthen 	}
14245435475dSsthen 
1425275a8d89Sflorian 	/* now move up the closest encloser until it exists, previous
1426275a8d89Sflorian 	 * (possibly empty) closest encloser was useful to finding the zone
1427275a8d89Sflorian 	 * (for empty zones too), but now we want actual data nodes */
1428275a8d89Sflorian 	if (closest_encloser && !closest_encloser->is_existing) {
1429275a8d89Sflorian 		exact = 0;
1430275a8d89Sflorian 		while (closest_encloser != NULL && !closest_encloser->is_existing)
1431275a8d89Sflorian 			closest_encloser = closest_encloser->parent;
1432275a8d89Sflorian 	}
143362ac0c33Sjakob 
143462ac0c33Sjakob 	/*
143562ac0c33Sjakob 	 * See RFC 4035 (DNSSEC protocol) section 3.1.4.1 Responding
143662ac0c33Sjakob 	 * to Queries for DS RRs.
143762ac0c33Sjakob 	 */
143862ac0c33Sjakob 	if (exact && q->qtype == TYPE_DS && closest_encloser == q->zone->apex) {
143962ac0c33Sjakob 		/*
144062ac0c33Sjakob 		 * Type DS query at a zone cut, use the responsible
144162ac0c33Sjakob 		 * parent zone to generate the answer if we are
144262ac0c33Sjakob 		 * authoritative for the parent zone.
144362ac0c33Sjakob 		 */
14446e9bf1eeSflorian 		zone_type *zone = domain_find_parent_zone(nsd->db, q->zone);
1445ee5153b7Sflorian 		if (zone) {
144662ac0c33Sjakob 			q->zone = zone;
1447ee5153b7Sflorian 			if(!q->zone->apex || !q->zone->soa_rrset) {
1448ee5153b7Sflorian 				/* zone is configured but not loaded */
14498d298c9fSsthen 				if(q->cname_count == 0) {
1450ee5153b7Sflorian 					RCODE_SET(q->packet, RCODE_SERVFAIL);
14518d298c9fSsthen 					/* RFC 8914 - Extended DNS Errors
14528d298c9fSsthen 					 * 4.15. Extended DNS Error Code 14 - Not Ready */
14538d298c9fSsthen 					ASSIGN_EDE_CODE_AND_STRING_LITERAL(
14548d298c9fSsthen 					   q->edns.ede, EDE_NOT_READY,
14558d298c9fSsthen 					   "Zone is configured but not loaded");
14568d298c9fSsthen 				}
1457ee5153b7Sflorian 				return;
1458ee5153b7Sflorian 			}
1459ee5153b7Sflorian 		}
146062ac0c33Sjakob 	}
146162ac0c33Sjakob 
146262ac0c33Sjakob 	/* see if the zone has expired (for secondary zones) */
1463dd5b221eSsthen 	if(q->zone && q->zone->opts && q->zone->opts->pattern &&
1464dd5b221eSsthen 		q->zone->opts->pattern->request_xfr != 0 && !q->zone->is_ok) {
14658d298c9fSsthen 		if(q->cname_count == 0) {
146662ac0c33Sjakob 			RCODE_SET(q->packet, RCODE_SERVFAIL);
14678d298c9fSsthen 			/* RFC 8914 - Extended DNS Errors
14688d298c9fSsthen 			 * 4.25. Extended DNS Error Code 24 - Invalid Data */
14698d298c9fSsthen 			ASSIGN_EDE_CODE_AND_STRING_LITERAL(q->edns.ede,
14708d298c9fSsthen 				EDE_INVALID_DATA, "Zone has expired");
14718d298c9fSsthen 		}
147262ac0c33Sjakob 		return;
147362ac0c33Sjakob 	}
147462ac0c33Sjakob 
147562ac0c33Sjakob 	if (exact && q->qtype == TYPE_DS && closest_encloser == q->zone->apex) {
147662ac0c33Sjakob 		/*
147762ac0c33Sjakob 		 * Type DS query at the zone apex (and the server is
14782fd875a4Ssthen 		 * not authoritative for the parent zone).
147962ac0c33Sjakob 		 */
148062ac0c33Sjakob 		if (q->qclass == CLASS_ANY) {
148162ac0c33Sjakob 			AA_CLR(q->packet);
148262ac0c33Sjakob 		} else {
148362ac0c33Sjakob 			AA_SET(q->packet);
148462ac0c33Sjakob 		}
148562ac0c33Sjakob 		answer_nodata(q, answer, closest_encloser);
148662ac0c33Sjakob 	} else {
148762ac0c33Sjakob 		q->delegation_domain = domain_find_ns_rrsets(
148862ac0c33Sjakob 			closest_encloser, q->zone, &q->delegation_rrset);
1489275a8d89Sflorian 		if(q->delegation_domain && find_dname_above(q->delegation_domain, q->zone)) {
1490275a8d89Sflorian 			q->delegation_domain = NULL; /* use higher DNAME */
1491275a8d89Sflorian 		}
149262ac0c33Sjakob 
149362ac0c33Sjakob 		if (!q->delegation_domain
1494a904e103Sflorian 		    || !q->delegation_rrset
149562ac0c33Sjakob 		    || (exact && q->qtype == TYPE_DS && closest_encloser == q->delegation_domain))
149662ac0c33Sjakob 		{
149762ac0c33Sjakob 			if (q->qclass == CLASS_ANY) {
149862ac0c33Sjakob 				AA_CLR(q->packet);
149962ac0c33Sjakob 			} else {
150062ac0c33Sjakob 				AA_SET(q->packet);
150162ac0c33Sjakob 			}
150262ac0c33Sjakob 			answer_authoritative(nsd, q, answer, domain_number, exact,
150362ac0c33Sjakob 					     closest_match, closest_encloser, qname);
150462ac0c33Sjakob 		}
150562ac0c33Sjakob 		else {
150662ac0c33Sjakob 			answer_delegation(q, answer);
150762ac0c33Sjakob 		}
150862ac0c33Sjakob 	}
150962ac0c33Sjakob }
151062ac0c33Sjakob 
151162ac0c33Sjakob static void
answer_query(struct nsd * nsd,struct query * q)151262ac0c33Sjakob answer_query(struct nsd *nsd, struct query *q)
151362ac0c33Sjakob {
151462ac0c33Sjakob 	domain_type *closest_match;
151562ac0c33Sjakob 	domain_type *closest_encloser;
151662ac0c33Sjakob 	int exact;
151762ac0c33Sjakob 	uint16_t offset;
151862ac0c33Sjakob 	answer_type answer;
151962ac0c33Sjakob 
152062ac0c33Sjakob 	answer_init(&answer);
152162ac0c33Sjakob 
152262ac0c33Sjakob 	exact = namedb_lookup(nsd->db, q->qname, &closest_match, &closest_encloser);
152362ac0c33Sjakob 
152462ac0c33Sjakob 	answer_lookup_zone(nsd, q, &answer, 0, exact, closest_match,
152562ac0c33Sjakob 		closest_encloser, q->qname);
1526c1404d4fSbrad 	ZTATUP2(nsd, q->zone, opcode, q->opcode);
1527c1404d4fSbrad 	ZTATUP2(nsd, q->zone, qtype, q->qtype);
1528c1404d4fSbrad 	ZTATUP2(nsd, q->zone, qclass, q->qclass);
152962ac0c33Sjakob 
153062ac0c33Sjakob 	offset = dname_label_offsets(q->qname)[domain_dname(closest_encloser)->label_count - 1] + QHEADERSZ;
153162ac0c33Sjakob 	query_add_compression_domain(q, closest_encloser, offset);
1532d11a62c8Ssthen 	encode_answer(q, &answer);
153362ac0c33Sjakob 	query_clear_compression_tables(q);
153462ac0c33Sjakob }
153562ac0c33Sjakob 
153662ac0c33Sjakob void
query_prepare_response(query_type * q)1537c1e73312Sflorian query_prepare_response(query_type *q)
153862ac0c33Sjakob {
153962ac0c33Sjakob 	uint16_t flags;
154062ac0c33Sjakob 
154162ac0c33Sjakob 	/*
154262ac0c33Sjakob 	 * Preserve the data up-to the current packet's limit.
154362ac0c33Sjakob 	 */
154462ac0c33Sjakob 	buffer_set_position(q->packet, buffer_limit(q->packet));
154562ac0c33Sjakob 	buffer_set_limit(q->packet, buffer_capacity(q->packet));
154662ac0c33Sjakob 
154762ac0c33Sjakob 	/*
154862ac0c33Sjakob 	 * Reserve space for the EDNS records if required.
154962ac0c33Sjakob 	 */
155062ac0c33Sjakob 	q->reserved_space = edns_reserved_space(&q->edns);
155162ac0c33Sjakob 	q->reserved_space += tsig_reserved_space(&q->tsig);
155262ac0c33Sjakob 
155362ac0c33Sjakob 	/* Update the flags.  */
155462ac0c33Sjakob 	flags = FLAGS(q->packet);
155562ac0c33Sjakob 	flags &= 0x0100U;	/* Preserve the RD flag.  */
155662ac0c33Sjakob 				/* CD flag must be cleared for auth answers */
155762ac0c33Sjakob 	flags |= 0x8000U;	/* Set the QR flag.  */
155862ac0c33Sjakob 	FLAGS_SET(q->packet, flags);
155962ac0c33Sjakob }
156062ac0c33Sjakob 
156162ac0c33Sjakob /*
156262ac0c33Sjakob  * Processes the query.
156362ac0c33Sjakob  *
156462ac0c33Sjakob  */
156562ac0c33Sjakob query_state_type
query_process(query_type * q,nsd_type * nsd,uint32_t * now_p)1566063644e9Sflorian query_process(query_type *q, nsd_type *nsd, uint32_t *now_p)
156762ac0c33Sjakob {
156862ac0c33Sjakob 	/* The query... */
156962ac0c33Sjakob 	nsd_rc_type rc;
157062ac0c33Sjakob 	query_state_type query_state;
157162ac0c33Sjakob 	uint16_t arcount;
157262ac0c33Sjakob 
157362ac0c33Sjakob 	/* Sanity checks */
157462ac0c33Sjakob 	if (buffer_limit(q->packet) < QHEADERSZ) {
157562ac0c33Sjakob 		/* packet too small to contain DNS header.
157662ac0c33Sjakob 		Now packet investigation macros will work without problems. */
157762ac0c33Sjakob 		return QUERY_DISCARDED;
157862ac0c33Sjakob 	}
157962ac0c33Sjakob 	if (QR(q->packet)) {
158062ac0c33Sjakob 		/* Not a query? Drop it on the floor. */
158162ac0c33Sjakob 		return QUERY_DISCARDED;
158262ac0c33Sjakob 	}
158362ac0c33Sjakob 
15843126abd5Ssthen 	/* check opcode early on, because new opcodes may have different
15853126abd5Ssthen 	 * specification of the meaning of the rest of the packet */
15863126abd5Ssthen 	q->opcode = OPCODE(q->packet);
15873126abd5Ssthen 	if(q->opcode != OPCODE_QUERY && q->opcode != OPCODE_NOTIFY) {
15883126abd5Ssthen 		if(query_ratelimit_err(nsd))
15893126abd5Ssthen 			return QUERY_DISCARDED;
1590308d2509Sflorian 		if(nsd->options->drop_updates && q->opcode == OPCODE_UPDATE)
1591308d2509Sflorian 			return QUERY_DISCARDED;
15923126abd5Ssthen 		return query_error(q, NSD_RC_IMPL);
15933126abd5Ssthen 	}
15943126abd5Ssthen 
1595d11a62c8Ssthen 	if (RCODE(q->packet) != RCODE_OK || !process_query_section(q)) {
15968d8f1862Ssthen 		return query_formerr(q, nsd);
159762ac0c33Sjakob 	}
159862ac0c33Sjakob 
159962ac0c33Sjakob 	/* Update statistics.  */
160062ac0c33Sjakob 	STATUP2(nsd, opcode, q->opcode);
160162ac0c33Sjakob 	STATUP2(nsd, qtype, q->qtype);
160262ac0c33Sjakob 	STATUP2(nsd, qclass, q->qclass);
160362ac0c33Sjakob 
160462ac0c33Sjakob 	if (q->opcode != OPCODE_QUERY) {
160562ac0c33Sjakob 		if (q->opcode == OPCODE_NOTIFY) {
160662ac0c33Sjakob 			return answer_notify(nsd, q);
160762ac0c33Sjakob 		} else {
16088d8f1862Ssthen 			if(query_ratelimit_err(nsd))
16098d8f1862Ssthen 				return QUERY_DISCARDED;
161062ac0c33Sjakob 			return query_error(q, NSD_RC_IMPL);
161162ac0c33Sjakob 		}
161262ac0c33Sjakob 	}
161362ac0c33Sjakob 
161462ac0c33Sjakob 	/* Dont bother to answer more than one question at once... */
1615d11a62c8Ssthen 	if (QDCOUNT(q->packet) != 1) {
1616977db6e5Sflorian 		if(QDCOUNT(q->packet) == 0 && ANCOUNT(q->packet) == 0 &&
1617977db6e5Sflorian 			NSCOUNT(q->packet) == 0 && ARCOUNT(q->packet) == 1 &&
1618977db6e5Sflorian 			buffer_limit(q->packet) >= QHEADERSZ+OPT_LEN+
1619977db6e5Sflorian 			OPT_RDATA) {
1620977db6e5Sflorian 			/* add edns section to answer */
1621977db6e5Sflorian 			buffer_set_position(q->packet, QHEADERSZ);
1622977db6e5Sflorian 			if (edns_parse_record(&q->edns, q->packet, q, nsd)) {
1623977db6e5Sflorian 				if(process_edns(nsd, q) == NSD_RC_OK) {
1624977db6e5Sflorian 					int opcode = OPCODE(q->packet);
1625977db6e5Sflorian 					(void)query_error(q, NSD_RC_FORMAT);
1626063644e9Sflorian 					query_add_optional(q, nsd, now_p);
1627977db6e5Sflorian 					FLAGS_SET(q->packet, FLAGS(q->packet) & 0x0100U);
1628977db6e5Sflorian 						/* Preserve the RD flag. Clear the rest. */
1629977db6e5Sflorian 					OPCODE_SET(q->packet, opcode);
1630977db6e5Sflorian 					QR_SET(q->packet);
1631977db6e5Sflorian 					return QUERY_PROCESSED;
1632977db6e5Sflorian 				}
1633977db6e5Sflorian 			}
1634977db6e5Sflorian 		}
163562ac0c33Sjakob 		FLAGS_SET(q->packet, 0);
16368d8f1862Ssthen 		return query_formerr(q, nsd);
163762ac0c33Sjakob 	}
1638d11a62c8Ssthen 	/* Ignore settings of flags */
163962ac0c33Sjakob 
164062ac0c33Sjakob 	/* Dont allow any records in the answer or authority section...
164162ac0c33Sjakob 	   except for IXFR queries. */
164262ac0c33Sjakob 	if (ANCOUNT(q->packet) != 0 ||
164362ac0c33Sjakob 		(q->qtype!=TYPE_IXFR && NSCOUNT(q->packet) != 0)) {
16448d8f1862Ssthen 		return query_formerr(q, nsd);
164562ac0c33Sjakob 	}
164662ac0c33Sjakob 	if(q->qtype==TYPE_IXFR && NSCOUNT(q->packet) > 0) {
1647308d2509Sflorian 		unsigned int i; /* skip ixfr soa information data here */
1648308d2509Sflorian 		unsigned int nscount = (unsigned)NSCOUNT(q->packet);
1649308d2509Sflorian 		/* define a bound on the number of extraneous records allowed,
1650308d2509Sflorian 		 * we expect 1, a SOA serial record, and no more.
1651308d2509Sflorian 		 * perhaps RRSIGs (but not needed), otherwise we do not
1652308d2509Sflorian 		 * understand what this means.  We do not want too many
1653308d2509Sflorian 		 * because the high iteration counts slow down. */
1654308d2509Sflorian 		if(nscount > 64) return query_formerr(q, nsd);
1655308d2509Sflorian 		for(i=0; i< nscount; i++)
165662ac0c33Sjakob 			if(!packet_skip_rr(q->packet, 0))
16578d8f1862Ssthen 				return query_formerr(q, nsd);
165862ac0c33Sjakob 	}
165962ac0c33Sjakob 
166062ac0c33Sjakob 	arcount = ARCOUNT(q->packet);
16618d298c9fSsthen 	/* A TSIG RR is not allowed before the EDNS OPT RR.
16628d298c9fSsthen 	 * In RFC6891 (about EDNS) it says:
16639c620270Ssthen 	 * "The placement flexibility for the OPT RR does not
16649c620270Ssthen 	 * override the need for the TSIG or SIG(0) RRs to be
16659c620270Ssthen 	 * the last in the additional section whenever they are
16669c620270Ssthen 	 * present."
16678d298c9fSsthen 	 * And in RFC8945 (about TSIG) it says:
16688d298c9fSsthen 	 * "If multiple TSIG records are detected or a TSIG record is
16698d298c9fSsthen 	 * present in any other position, the DNS message is dropped
16708d298c9fSsthen 	 * and a response with RCODE 1 (FORMERR) MUST be returned."
16719c620270Ssthen 	 */
16729c620270Ssthen 	/* See if there is an OPT RR. */
167362ac0c33Sjakob 	if (arcount > 0) {
1674c1e73312Sflorian 		if (edns_parse_record(&q->edns, q->packet, q, nsd))
167562ac0c33Sjakob 			--arcount;
167662ac0c33Sjakob 	}
16779c620270Ssthen 	/* See if there is a TSIG RR. */
167862ac0c33Sjakob 	if (arcount > 0 && q->tsig.status == TSIG_NOT_PRESENT) {
167962ac0c33Sjakob 		/* see if tsig is after the edns record */
168062ac0c33Sjakob 		if (!tsig_parse_rr(&q->tsig, q->packet))
16818d8f1862Ssthen 			return query_formerr(q, nsd);
168262ac0c33Sjakob 		if(q->tsig.status != TSIG_NOT_PRESENT)
168362ac0c33Sjakob 			--arcount;
168462ac0c33Sjakob 	}
16859c620270Ssthen 	/* If more RRs left in Add. Section, FORMERR. */
168662ac0c33Sjakob 	if (arcount > 0) {
16878d8f1862Ssthen 		return query_formerr(q, nsd);
168862ac0c33Sjakob 	}
168962ac0c33Sjakob 
169062ac0c33Sjakob 	/* Do we have any trailing garbage? */
169162ac0c33Sjakob #ifdef	STRICT_MESSAGE_PARSE
169262ac0c33Sjakob 	if (buffer_remaining(q->packet) > 0) {
169362ac0c33Sjakob 		/* If we're strict.... */
16948d8f1862Ssthen 		return query_formerr(q, nsd);
169562ac0c33Sjakob 	}
169662ac0c33Sjakob #endif
169762ac0c33Sjakob 	/* Remove trailing garbage.  */
169862ac0c33Sjakob 	buffer_set_limit(q->packet, buffer_position(q->packet));
169962ac0c33Sjakob 
170062ac0c33Sjakob 	rc = process_tsig(q);
170162ac0c33Sjakob 	if (rc != NSD_RC_OK) {
170262ac0c33Sjakob 		return query_error(q, rc);
170362ac0c33Sjakob 	}
170462ac0c33Sjakob 	rc = process_edns(nsd, q);
170562ac0c33Sjakob 	if (rc != NSD_RC_OK) {
170662ac0c33Sjakob 		/* We should not return FORMERR, but BADVERS (=16).
170762ac0c33Sjakob 		 * BADVERS is created with Ext. RCODE, followed by RCODE.
170862ac0c33Sjakob 		 * Ext. RCODE is set to 1, RCODE must be 0 (getting 0x10 = 16).
170962ac0c33Sjakob 		 * Thus RCODE = NOERROR = NSD_RC_OK. */
1710ac5517e4Sflorian 		RCODE_SET(q->packet, NSD_RC_OK);
1711ac5517e4Sflorian 		buffer_clear(q->packet);
1712ac5517e4Sflorian 		buffer_set_position(q->packet,
1713ac5517e4Sflorian 			QHEADERSZ + 4 + q->qname->name_size);
1714ac5517e4Sflorian 		QR_SET(q->packet);
1715ac5517e4Sflorian 		AD_CLR(q->packet);
1716ac5517e4Sflorian 		QDCOUNT_SET(q->packet, 1);
1717ac5517e4Sflorian 		ANCOUNT_SET(q->packet, 0);
1718ac5517e4Sflorian 		NSCOUNT_SET(q->packet, 0);
1719ac5517e4Sflorian 		ARCOUNT_SET(q->packet, 0);
1720ac5517e4Sflorian 		return QUERY_PROCESSED;
172162ac0c33Sjakob 	}
172262ac0c33Sjakob 
1723063644e9Sflorian 	if (q->edns.cookie_status == COOKIE_UNVERIFIED)
1724063644e9Sflorian 		cookie_verify(q, nsd, now_p);
1725063644e9Sflorian 
1726c1e73312Sflorian 	query_prepare_response(q);
172762ac0c33Sjakob 
172862ac0c33Sjakob 	if (q->qclass != CLASS_IN && q->qclass != CLASS_ANY) {
172962ac0c33Sjakob 		if (q->qclass == CLASS_CH) {
173062ac0c33Sjakob 			return answer_chaos(nsd, q);
173162ac0c33Sjakob 		} else {
17328d298c9fSsthen 			/* RFC8914 - Extended DNS Errors
17338d298c9fSsthen 			 * 4.22. Extended DNS Error Code 21 - Not Supported */
17348d298c9fSsthen 			q->edns.ede = EDE_NOT_SUPPORTED;
17358d298c9fSsthen 			return query_error(q, RCODE_REFUSE);
173662ac0c33Sjakob 		}
173762ac0c33Sjakob 	}
173862ac0c33Sjakob 	query_state = answer_axfr_ixfr(nsd, q);
17394564029fSflorian 	if (query_state == QUERY_PROCESSED || query_state == QUERY_IN_AXFR
17404564029fSflorian 		|| query_state == QUERY_IN_IXFR) {
174162ac0c33Sjakob 		return query_state;
174262ac0c33Sjakob 	}
1743b3163e5fSflorian 	if(q->qtype == TYPE_ANY && nsd->options->refuse_any && !q->tcp) {
1744b3163e5fSflorian 		TC_SET(q->packet);
1745b3163e5fSflorian 		return query_error(q, NSD_RC_OK);
1746b3163e5fSflorian 	}
174762ac0c33Sjakob 
174862ac0c33Sjakob 	answer_query(nsd, q);
174962ac0c33Sjakob 
175062ac0c33Sjakob 	return QUERY_PROCESSED;
175162ac0c33Sjakob }
175262ac0c33Sjakob 
175362ac0c33Sjakob void
query_add_optional(query_type * q,nsd_type * nsd,uint32_t * now_p)1754063644e9Sflorian query_add_optional(query_type *q, nsd_type *nsd, uint32_t *now_p)
175562ac0c33Sjakob {
175662ac0c33Sjakob 	struct edns_data *edns = &nsd->edns_ipv4;
175762ac0c33Sjakob #if defined(INET6)
1758b71395eaSflorian 	if (q->client_addr.ss_family == AF_INET6) {
175962ac0c33Sjakob 		edns = &nsd->edns_ipv6;
176062ac0c33Sjakob 	}
176162ac0c33Sjakob #endif
1762129edcbcSphessler 	if (RCODE(q->packet) == RCODE_FORMAT) {
1763129edcbcSphessler 		return;
1764129edcbcSphessler 	}
176562ac0c33Sjakob 	switch (q->edns.status) {
176662ac0c33Sjakob 	case EDNS_NOT_PRESENT:
176762ac0c33Sjakob 		break;
176862ac0c33Sjakob 	case EDNS_OK:
17695bcb494bSjakob 		if (q->edns.dnssec_ok)	edns->ok[7] = 0x80;
17705bcb494bSjakob 		else			edns->ok[7] = 0x00;
177162ac0c33Sjakob 		buffer_write(q->packet, edns->ok, OPT_LEN);
17728d298c9fSsthen 
17738d298c9fSsthen 		/* Add Extended DNS Error (RFC8914)
17748d298c9fSsthen 		 * to verify that we stay in bounds */
17758d298c9fSsthen 		if (q->edns.ede >= 0)
17768d298c9fSsthen 			q->edns.opt_reserved_space +=
17778d298c9fSsthen 				6 + ( q->edns.ede_text_len
17788d298c9fSsthen 			            ? q->edns.ede_text_len : 0);
17798d298c9fSsthen 
1780c1e73312Sflorian 		if(q->edns.opt_reserved_space == 0 || !buffer_available(
1781c1e73312Sflorian 			q->packet, 2+q->edns.opt_reserved_space)) {
1782c1e73312Sflorian 			/* fill with NULLs */
1783c1e73312Sflorian 			buffer_write(q->packet, edns->rdata_none, OPT_RDATA);
1784c1e73312Sflorian 		} else {
178562ac0c33Sjakob 			/* rdata length */
1786c1e73312Sflorian 			buffer_write_u16(q->packet, q->edns.opt_reserved_space);
1787c1e73312Sflorian 			/* edns options */
1788c1e73312Sflorian 			if(q->edns.nsid) {
178962ac0c33Sjakob 				/* nsid opt header */
179062ac0c33Sjakob 				buffer_write(q->packet, edns->nsid, OPT_HDR);
179162ac0c33Sjakob 				/* nsid payload */
179262ac0c33Sjakob 				buffer_write(q->packet, nsd->nsid, nsd->nsid_len);
1793c1e73312Sflorian 			}
1794063644e9Sflorian 			if(q->edns.cookie_status != COOKIE_NOT_PRESENT) {
1795063644e9Sflorian 				/* cookie opt header */
1796063644e9Sflorian 				buffer_write(q->packet, edns->cookie, OPT_HDR);
1797063644e9Sflorian 				/* cookie payload */
1798063644e9Sflorian 				cookie_create(q, nsd, now_p);
1799063644e9Sflorian 				buffer_write(q->packet, q->edns.cookie, 24);
1800063644e9Sflorian 			}
18018d298c9fSsthen 			/* Append Extended DNS Error (RFC8914) option if needed */
18028d298c9fSsthen 			if (q->edns.ede >= 0) { /* < 0 means no EDE */
18038d298c9fSsthen 				/* OPTION-CODE */
18048d298c9fSsthen 				buffer_write_u16(q->packet, EDE_CODE);
18058d298c9fSsthen 				/* OPTION-LENGTH */
18068d298c9fSsthen 				buffer_write_u16(q->packet,
18078d298c9fSsthen 					2 + ( q->edns.ede_text_len
18088d298c9fSsthen 					    ? q->edns.ede_text_len : 0));
18098d298c9fSsthen 				/* INFO-CODE */
18108d298c9fSsthen 				buffer_write_u16(q->packet, q->edns.ede);
18118d298c9fSsthen 				/* EXTRA-TEXT */
18128d298c9fSsthen 				if (q->edns.ede_text_len)
18138d298c9fSsthen 					buffer_write(q->packet,
18148d298c9fSsthen 							q->edns.ede_text,
18158d298c9fSsthen 							q->edns.ede_text_len);
18168d298c9fSsthen 			}
181762ac0c33Sjakob 		}
181862ac0c33Sjakob 		ARCOUNT_SET(q->packet, ARCOUNT(q->packet) + 1);
181962ac0c33Sjakob 		STATUP(nsd, edns);
1820c1404d4fSbrad 		ZTATUP(nsd, q->zone, edns);
182162ac0c33Sjakob 		break;
182262ac0c33Sjakob 	case EDNS_ERROR:
18235bcb494bSjakob 		if (q->edns.dnssec_ok)	edns->error[7] = 0x80;
18245bcb494bSjakob 		else			edns->error[7] = 0x00;
182562ac0c33Sjakob 		buffer_write(q->packet, edns->error, OPT_LEN);
182662ac0c33Sjakob 		buffer_write(q->packet, edns->rdata_none, OPT_RDATA);
182762ac0c33Sjakob 		ARCOUNT_SET(q->packet, ARCOUNT(q->packet) + 1);
182862ac0c33Sjakob 		STATUP(nsd, ednserr);
1829c1404d4fSbrad 		ZTATUP(nsd, q->zone, ednserr);
183062ac0c33Sjakob 		break;
183162ac0c33Sjakob 	}
183262ac0c33Sjakob 
183362ac0c33Sjakob 	if (q->tsig.status != TSIG_NOT_PRESENT) {
183462ac0c33Sjakob 		if (q->tsig.status == TSIG_ERROR ||
183562ac0c33Sjakob 			q->tsig.error_code != TSIG_ERROR_NOERROR) {
183662ac0c33Sjakob 			tsig_error_reply(&q->tsig);
183762ac0c33Sjakob 			tsig_append_rr(&q->tsig, q->packet);
183862ac0c33Sjakob 			ARCOUNT_SET(q->packet, ARCOUNT(q->packet) + 1);
183962ac0c33Sjakob 		} else if(q->tsig.status == TSIG_OK &&
184062ac0c33Sjakob 			q->tsig.error_code == TSIG_ERROR_NOERROR)
184162ac0c33Sjakob 		{
184262ac0c33Sjakob 			if(q->tsig_prepare_it)
184362ac0c33Sjakob 				tsig_prepare(&q->tsig);
184462ac0c33Sjakob 			if(q->tsig_update_it)
184562ac0c33Sjakob 				tsig_update(&q->tsig, q->packet, buffer_position(q->packet));
184662ac0c33Sjakob 			if(q->tsig_sign_it) {
184762ac0c33Sjakob 				tsig_sign(&q->tsig);
184862ac0c33Sjakob 				tsig_append_rr(&q->tsig, q->packet);
184962ac0c33Sjakob 				ARCOUNT_SET(q->packet, ARCOUNT(q->packet) + 1);
185062ac0c33Sjakob 			}
185162ac0c33Sjakob 		}
185262ac0c33Sjakob 	}
185362ac0c33Sjakob }
1854