162ac0c33Sjakob /*
262ac0c33Sjakob * axfr.c -- generating AXFR responses.
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 "axfr.h"
1362ac0c33Sjakob #include "dns.h"
1462ac0c33Sjakob #include "packet.h"
1562ac0c33Sjakob #include "options.h"
164564029fSflorian #include "ixfr.h"
1762ac0c33Sjakob
18308d2509Sflorian /* draft-ietf-dnsop-rfc2845bis-06, section 5.3.1 says to sign every packet */
19308d2509Sflorian #define AXFR_TSIG_SIGN_EVERY_NTH 0 /* tsig sign every N packets. */
2062ac0c33Sjakob
2162ac0c33Sjakob query_state_type
query_axfr(struct nsd * nsd,struct query * query,int wstats)224564029fSflorian query_axfr(struct nsd *nsd, struct query *query, int wstats)
2362ac0c33Sjakob {
2462ac0c33Sjakob domain_type *closest_match;
2562ac0c33Sjakob domain_type *closest_encloser;
2662ac0c33Sjakob int exact;
2762ac0c33Sjakob int added;
2862ac0c33Sjakob uint16_t total_added = 0;
2962ac0c33Sjakob
3062ac0c33Sjakob if (query->axfr_is_done)
3162ac0c33Sjakob return QUERY_PROCESSED;
3262ac0c33Sjakob
3362ac0c33Sjakob if (query->maxlen > AXFR_MAX_MESSAGE_LEN)
3462ac0c33Sjakob query->maxlen = AXFR_MAX_MESSAGE_LEN;
3562ac0c33Sjakob
3662ac0c33Sjakob assert(!query_overflow(query));
3762ac0c33Sjakob /* only keep running values for most packets */
3862ac0c33Sjakob query->tsig_prepare_it = 0;
3962ac0c33Sjakob query->tsig_update_it = 1;
4062ac0c33Sjakob if(query->tsig_sign_it) {
4162ac0c33Sjakob /* prepare for next updates */
4262ac0c33Sjakob query->tsig_prepare_it = 1;
4362ac0c33Sjakob query->tsig_sign_it = 0;
4462ac0c33Sjakob }
4562ac0c33Sjakob
4662ac0c33Sjakob if (query->axfr_zone == NULL) {
47dd5b221eSsthen domain_type* qdomain;
4862ac0c33Sjakob /* Start AXFR. */
494564029fSflorian if(wstats) {
50dd5b221eSsthen STATUP(nsd, raxfr);
514564029fSflorian }
5262ac0c33Sjakob exact = namedb_lookup(nsd->db,
5362ac0c33Sjakob query->qname,
5462ac0c33Sjakob &closest_match,
5562ac0c33Sjakob &closest_encloser);
5662ac0c33Sjakob
57dd5b221eSsthen qdomain = closest_encloser;
585fab9a23Sbrad query->axfr_zone = domain_find_zone(nsd->db, closest_encloser);
5962ac0c33Sjakob
6062ac0c33Sjakob if (!exact
6162ac0c33Sjakob || query->axfr_zone == NULL
625fab9a23Sbrad || query->axfr_zone->apex != qdomain
635fab9a23Sbrad || query->axfr_zone->soa_rrset == NULL)
6462ac0c33Sjakob {
6562ac0c33Sjakob /* No SOA no transfer */
66d11a62c8Ssthen RCODE_SET(query->packet, RCODE_NOTAUTH);
6762ac0c33Sjakob return QUERY_PROCESSED;
6862ac0c33Sjakob }
694564029fSflorian if(wstats) {
70c1404d4fSbrad ZTATUP(nsd, query->axfr_zone, raxfr);
714564029fSflorian }
7262ac0c33Sjakob
73dd5b221eSsthen query->axfr_current_domain = qdomain;
7462ac0c33Sjakob query->axfr_current_rrset = NULL;
7562ac0c33Sjakob query->axfr_current_rr = 0;
7662ac0c33Sjakob if(query->tsig.status == TSIG_OK) {
7762ac0c33Sjakob query->tsig_sign_it = 1; /* sign first packet in stream */
7862ac0c33Sjakob }
7962ac0c33Sjakob
80dd5b221eSsthen query_add_compression_domain(query, qdomain, QHEADERSZ);
8162ac0c33Sjakob
8262ac0c33Sjakob assert(query->axfr_zone->soa_rrset->rr_count == 1);
8362ac0c33Sjakob added = packet_encode_rr(query,
8462ac0c33Sjakob query->axfr_zone->apex,
85a302926fSbrad &query->axfr_zone->soa_rrset->rrs[0],
86a302926fSbrad query->axfr_zone->soa_rrset->rrs[0].ttl);
8762ac0c33Sjakob if (!added) {
8862ac0c33Sjakob /* XXX: This should never happen... generate error code? */
8962ac0c33Sjakob abort();
9062ac0c33Sjakob }
9162ac0c33Sjakob ++total_added;
9262ac0c33Sjakob } else {
9362ac0c33Sjakob /*
9462ac0c33Sjakob * Query name and EDNS need not be repeated after the
9562ac0c33Sjakob * first response packet.
9662ac0c33Sjakob */
9762ac0c33Sjakob query->edns.status = EDNS_NOT_PRESENT;
9862ac0c33Sjakob buffer_set_limit(query->packet, QHEADERSZ);
9962ac0c33Sjakob QDCOUNT_SET(query->packet, 0);
100c1e73312Sflorian query_prepare_response(query);
10162ac0c33Sjakob }
10262ac0c33Sjakob
10362ac0c33Sjakob /* Add zone RRs until answer is full. */
104275a8d89Sflorian while (query->axfr_current_domain != NULL &&
105275a8d89Sflorian domain_is_subdomain(query->axfr_current_domain,
106275a8d89Sflorian query->axfr_zone->apex))
107275a8d89Sflorian {
10862ac0c33Sjakob if (!query->axfr_current_rrset) {
10962ac0c33Sjakob query->axfr_current_rrset = domain_find_any_rrset(
11062ac0c33Sjakob query->axfr_current_domain,
11162ac0c33Sjakob query->axfr_zone);
11262ac0c33Sjakob query->axfr_current_rr = 0;
11362ac0c33Sjakob }
11462ac0c33Sjakob while (query->axfr_current_rrset) {
11562ac0c33Sjakob if (query->axfr_current_rrset != query->axfr_zone->soa_rrset
11662ac0c33Sjakob && query->axfr_current_rrset->zone == query->axfr_zone)
11762ac0c33Sjakob {
11862ac0c33Sjakob while (query->axfr_current_rr < query->axfr_current_rrset->rr_count) {
1193efee2e1Sflorian size_t oldmaxlen = query->maxlen;
1203efee2e1Sflorian if(total_added == 0)
1213efee2e1Sflorian /* RR > 16K can be first RR */
1223efee2e1Sflorian query->maxlen = (query->tcp?TCP_MAX_MESSAGE_LEN:UDP_MAX_MESSAGE_LEN);
12362ac0c33Sjakob added = packet_encode_rr(
12462ac0c33Sjakob query,
12562ac0c33Sjakob query->axfr_current_domain,
126a302926fSbrad &query->axfr_current_rrset->rrs[query->axfr_current_rr],
127a302926fSbrad query->axfr_current_rrset->rrs[query->axfr_current_rr].ttl);
1283efee2e1Sflorian if(total_added == 0) {
1293efee2e1Sflorian query->maxlen = oldmaxlen;
1303efee2e1Sflorian if(query_overflow(query)) {
1313efee2e1Sflorian if(added) {
1323efee2e1Sflorian ++total_added;
1333efee2e1Sflorian ++query->axfr_current_rr;
1343efee2e1Sflorian goto return_answer;
1353efee2e1Sflorian }
1363efee2e1Sflorian }
1373efee2e1Sflorian }
13862ac0c33Sjakob if (!added)
13962ac0c33Sjakob goto return_answer;
14062ac0c33Sjakob ++total_added;
14162ac0c33Sjakob ++query->axfr_current_rr;
14262ac0c33Sjakob }
14362ac0c33Sjakob }
14462ac0c33Sjakob
14562ac0c33Sjakob query->axfr_current_rrset = query->axfr_current_rrset->next;
14662ac0c33Sjakob query->axfr_current_rr = 0;
14762ac0c33Sjakob }
14862ac0c33Sjakob assert(query->axfr_current_domain);
14962ac0c33Sjakob query->axfr_current_domain
150dd5b221eSsthen = domain_next(query->axfr_current_domain);
15162ac0c33Sjakob }
15262ac0c33Sjakob
15362ac0c33Sjakob /* Add terminating SOA RR. */
15462ac0c33Sjakob assert(query->axfr_zone->soa_rrset->rr_count == 1);
15562ac0c33Sjakob added = packet_encode_rr(query,
15662ac0c33Sjakob query->axfr_zone->apex,
157a302926fSbrad &query->axfr_zone->soa_rrset->rrs[0],
158a302926fSbrad query->axfr_zone->soa_rrset->rrs[0].ttl);
15962ac0c33Sjakob if (added) {
16062ac0c33Sjakob ++total_added;
16162ac0c33Sjakob query->tsig_sign_it = 1; /* sign last packet */
16262ac0c33Sjakob query->axfr_is_done = 1;
16362ac0c33Sjakob }
16462ac0c33Sjakob
16562ac0c33Sjakob return_answer:
166d11a62c8Ssthen AA_SET(query->packet);
16762ac0c33Sjakob ANCOUNT_SET(query->packet, total_added);
16862ac0c33Sjakob NSCOUNT_SET(query->packet, 0);
16962ac0c33Sjakob ARCOUNT_SET(query->packet, 0);
17062ac0c33Sjakob
17162ac0c33Sjakob /* check if it needs tsig signatures */
17262ac0c33Sjakob if(query->tsig.status == TSIG_OK) {
173308d2509Sflorian #if AXFR_TSIG_SIGN_EVERY_NTH > 0
17462ac0c33Sjakob if(query->tsig.updates_since_last_prepare >= AXFR_TSIG_SIGN_EVERY_NTH) {
175308d2509Sflorian #endif
17662ac0c33Sjakob query->tsig_sign_it = 1;
177308d2509Sflorian #if AXFR_TSIG_SIGN_EVERY_NTH > 0
17862ac0c33Sjakob }
179308d2509Sflorian #endif
18062ac0c33Sjakob }
18162ac0c33Sjakob query_clear_compression_tables(query);
18262ac0c33Sjakob return QUERY_IN_AXFR;
18362ac0c33Sjakob }
18462ac0c33Sjakob
1854564029fSflorian /* See if the query can be admitted. */
axfr_ixfr_can_admit_query(struct nsd * nsd,struct query * q)1864564029fSflorian static int axfr_ixfr_can_admit_query(struct nsd* nsd, struct query* q)
18762ac0c33Sjakob {
188fe5fe5f6Sflorian struct acl_options *acl = NULL;
189fe5fe5f6Sflorian struct zone_options* zone_opt;
190dd5b221eSsthen zone_opt = zone_options_find(nsd->options, q->qname);
191*b71395eaSflorian if(zone_opt && q->is_proxied && acl_check_incoming_block_proxy(
192*b71395eaSflorian zone_opt->pattern->provide_xfr, q, &acl) == -1) {
193*b71395eaSflorian /* the proxy address is blocked */
194*b71395eaSflorian if (verbosity >= 2) {
195*b71395eaSflorian char address[128], proxy[128];
196*b71395eaSflorian addr2str(&q->client_addr, address, sizeof(address));
197*b71395eaSflorian addr2str(&q->remote_addr, proxy, sizeof(proxy));
198*b71395eaSflorian VERBOSITY(2, (LOG_INFO, "%s for %s from %s via proxy %s refused because of proxy, %s %s",
199*b71395eaSflorian (q->qtype==TYPE_AXFR?"axfr":"ixfr"),
200*b71395eaSflorian dname_to_string(q->qname, NULL),
201*b71395eaSflorian address, proxy,
202*b71395eaSflorian (acl?acl->ip_address_spec:"."),
203*b71395eaSflorian (acl ? ( acl->nokey ? "NOKEY"
204*b71395eaSflorian : acl->blocked ? "BLOCKED"
205*b71395eaSflorian : acl->key_name )
206*b71395eaSflorian : "no acl matches")));
207*b71395eaSflorian }
208*b71395eaSflorian RCODE_SET(q->packet, RCODE_REFUSE);
209*b71395eaSflorian /* RFC8914 - Extended DNS Errors
210*b71395eaSflorian * 4.19. Extended DNS Error Code 18 - Prohibited */
211*b71395eaSflorian q->edns.ede = EDE_PROHIBITED;
212*b71395eaSflorian return 0;
213*b71395eaSflorian }
21462ac0c33Sjakob if(!zone_opt ||
215dd5b221eSsthen acl_check_incoming(zone_opt->pattern->provide_xfr, q, &acl)==-1)
21662ac0c33Sjakob {
2178d8f1862Ssthen if (verbosity >= 2) {
218dd5b221eSsthen char a[128];
219*b71395eaSflorian addr2str(&q->client_addr, a, sizeof(a));
2204564029fSflorian VERBOSITY(2, (LOG_INFO, "%s for %s from %s refused, %s",
2214564029fSflorian (q->qtype==TYPE_AXFR?"axfr":"ixfr"),
222dd5b221eSsthen dname_to_string(q->qname, NULL), a, acl?"blocked":"no acl matches"));
2233b0b19f7Sjakob }
2244564029fSflorian DEBUG(DEBUG_XFRD,1, (LOG_INFO, "%s refused, %s",
2254564029fSflorian (q->qtype==TYPE_AXFR?"axfr":"ixfr"),
22662ac0c33Sjakob acl?"blocked":"no acl matches"));
227d11a62c8Ssthen if (!zone_opt) {
228d11a62c8Ssthen RCODE_SET(q->packet, RCODE_NOTAUTH);
229d11a62c8Ssthen } else {
23062ac0c33Sjakob RCODE_SET(q->packet, RCODE_REFUSE);
2318d298c9fSsthen /* RFC8914 - Extended DNS Errors
2328d298c9fSsthen * 4.19. Extended DNS Error Code 18 - Prohibited */
2338d298c9fSsthen q->edns.ede = EDE_PROHIBITED;
234d11a62c8Ssthen }
2354564029fSflorian return 0;
23662ac0c33Sjakob }
2374564029fSflorian DEBUG(DEBUG_XFRD,1, (LOG_INFO, "%s admitted acl %s %s",
2384564029fSflorian (q->qtype==TYPE_AXFR?"axfr":"ixfr"),
23962ac0c33Sjakob acl->ip_address_spec, acl->key_name?acl->key_name:"NOKEY"));
240e3d8a0a5Ssthen if (verbosity >= 1) {
241e3d8a0a5Ssthen char a[128];
242*b71395eaSflorian addr2str(&q->client_addr, a, sizeof(a));
243e3d8a0a5Ssthen VERBOSITY(1, (LOG_INFO, "%s for %s from %s",
244e3d8a0a5Ssthen (q->qtype==TYPE_AXFR?"axfr":"ixfr"),
245e3d8a0a5Ssthen dname_to_string(q->qname, NULL), a));
246e3d8a0a5Ssthen }
2474564029fSflorian return 1;
2484564029fSflorian }
2494564029fSflorian
2504564029fSflorian /*
2514564029fSflorian * Answer if this is an AXFR or IXFR query.
2524564029fSflorian */
2534564029fSflorian query_state_type
answer_axfr_ixfr(struct nsd * nsd,struct query * q)2544564029fSflorian answer_axfr_ixfr(struct nsd *nsd, struct query *q)
2554564029fSflorian {
2564564029fSflorian /* Is it AXFR? */
2574564029fSflorian switch (q->qtype) {
2584564029fSflorian case TYPE_AXFR:
2594564029fSflorian if (q->tcp) {
2604564029fSflorian if(!axfr_ixfr_can_admit_query(nsd, q))
2614564029fSflorian return QUERY_PROCESSED;
2624564029fSflorian return query_axfr(nsd, q, 1);
26362ac0c33Sjakob }
264308d2509Sflorian /* AXFR over UDP queries are discarded. */
265308d2509Sflorian RCODE_SET(q->packet, RCODE_IMPL);
266308d2509Sflorian return QUERY_PROCESSED;
26762ac0c33Sjakob case TYPE_IXFR:
2684564029fSflorian if(!axfr_ixfr_can_admit_query(nsd, q)) {
269308d2509Sflorian /* get rid of authority section, if present */
270308d2509Sflorian NSCOUNT_SET(q->packet, 0);
2714564029fSflorian ARCOUNT_SET(q->packet, 0);
272308d2509Sflorian if(QDCOUNT(q->packet) > 0 && (size_t)QHEADERSZ+4+
273308d2509Sflorian q->qname->name_size <= buffer_limit(q->packet)) {
274308d2509Sflorian buffer_set_position(q->packet, QHEADERSZ+4+
275308d2509Sflorian q->qname->name_size);
276308d2509Sflorian }
27762ac0c33Sjakob return QUERY_PROCESSED;
2784564029fSflorian }
2794564029fSflorian return query_ixfr(nsd, q);
28062ac0c33Sjakob default:
28162ac0c33Sjakob return QUERY_DISCARDED;
28262ac0c33Sjakob }
28362ac0c33Sjakob }
284