Home | History | Annotate | Line # | Download | only in dist
      1      1.1  christos /*
      2      1.1  christos  * axfr.c -- generating AXFR responses.
      3      1.1  christos  *
      4      1.1  christos  * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
      5      1.1  christos  *
      6      1.1  christos  * See LICENSE for the license.
      7      1.1  christos  *
      8      1.1  christos  */
      9      1.1  christos 
     10      1.1  christos #include "config.h"
     11      1.1  christos 
     12      1.1  christos #include "axfr.h"
     13      1.1  christos #include "dns.h"
     14      1.1  christos #include "packet.h"
     15      1.1  christos #include "options.h"
     16  1.1.1.4  christos #include "ixfr.h"
     17      1.1  christos 
     18  1.1.1.3  christos /* draft-ietf-dnsop-rfc2845bis-06, section 5.3.1 says to sign every packet */
     19  1.1.1.3  christos #define AXFR_TSIG_SIGN_EVERY_NTH	0	/* tsig sign every N packets. */
     20      1.1  christos 
     21      1.1  christos query_state_type
     22  1.1.1.4  christos query_axfr(struct nsd *nsd, struct query *query, int wstats)
     23      1.1  christos {
     24      1.1  christos 	domain_type *closest_match;
     25      1.1  christos 	domain_type *closest_encloser;
     26      1.1  christos 	int exact;
     27      1.1  christos 	int added;
     28      1.1  christos 	uint16_t total_added = 0;
     29      1.1  christos 
     30      1.1  christos 	if (query->axfr_is_done)
     31      1.1  christos 		return QUERY_PROCESSED;
     32      1.1  christos 
     33      1.1  christos 	if (query->maxlen > AXFR_MAX_MESSAGE_LEN)
     34      1.1  christos 		query->maxlen = AXFR_MAX_MESSAGE_LEN;
     35      1.1  christos 
     36      1.1  christos 	assert(!query_overflow(query));
     37      1.1  christos 	/* only keep running values for most packets */
     38      1.1  christos 	query->tsig_prepare_it = 0;
     39      1.1  christos 	query->tsig_update_it = 1;
     40      1.1  christos 	if(query->tsig_sign_it) {
     41      1.1  christos 		/* prepare for next updates */
     42      1.1  christos 		query->tsig_prepare_it = 1;
     43      1.1  christos 		query->tsig_sign_it = 0;
     44      1.1  christos 	}
     45      1.1  christos 
     46      1.1  christos 	if (query->axfr_zone == NULL) {
     47      1.1  christos 		domain_type* qdomain;
     48      1.1  christos 		/* Start AXFR.  */
     49  1.1.1.4  christos 		if(wstats) {
     50  1.1.1.4  christos 			STATUP(nsd, raxfr);
     51  1.1.1.4  christos 		}
     52      1.1  christos 		exact = namedb_lookup(nsd->db,
     53      1.1  christos 				      query->qname,
     54      1.1  christos 				      &closest_match,
     55      1.1  christos 				      &closest_encloser);
     56      1.1  christos 
     57      1.1  christos 		qdomain = closest_encloser;
     58      1.1  christos 		query->axfr_zone = domain_find_zone(nsd->db, closest_encloser);
     59      1.1  christos 
     60      1.1  christos 		if (!exact
     61      1.1  christos 		    || query->axfr_zone == NULL
     62      1.1  christos 		    || query->axfr_zone->apex != qdomain
     63      1.1  christos 		    || query->axfr_zone->soa_rrset == NULL)
     64      1.1  christos 		{
     65      1.1  christos 			/* No SOA no transfer */
     66      1.1  christos 			RCODE_SET(query->packet, RCODE_NOTAUTH);
     67      1.1  christos 			return QUERY_PROCESSED;
     68      1.1  christos 		}
     69  1.1.1.4  christos 		if(wstats) {
     70  1.1.1.4  christos 			ZTATUP(nsd, query->axfr_zone, raxfr);
     71  1.1.1.4  christos 		}
     72      1.1  christos 
     73      1.1  christos 		query->axfr_current_domain = qdomain;
     74      1.1  christos 		query->axfr_current_rrset = NULL;
     75      1.1  christos 		query->axfr_current_rr = 0;
     76      1.1  christos 		if(query->tsig.status == TSIG_OK) {
     77      1.1  christos 			query->tsig_sign_it = 1; /* sign first packet in stream */
     78      1.1  christos 		}
     79      1.1  christos 
     80      1.1  christos 		query_add_compression_domain(query, qdomain, QHEADERSZ);
     81      1.1  christos 
     82      1.1  christos 		assert(query->axfr_zone->soa_rrset->rr_count == 1);
     83      1.1  christos 		added = packet_encode_rr(query,
     84      1.1  christos 					 query->axfr_zone->apex,
     85  1.1.1.6  christos 					 query->axfr_zone->soa_rrset->rrs[0],
     86  1.1.1.6  christos 					 query->axfr_zone->soa_rrset->rrs[0]->ttl);
     87      1.1  christos 		if (!added) {
     88      1.1  christos 			/* XXX: This should never happen... generate error code? */
     89      1.1  christos 			abort();
     90      1.1  christos 		}
     91      1.1  christos 		++total_added;
     92      1.1  christos 	} else {
     93      1.1  christos 		/*
     94      1.1  christos 		 * Query name and EDNS need not be repeated after the
     95      1.1  christos 		 * first response packet.
     96      1.1  christos 		 */
     97      1.1  christos 		query->edns.status = EDNS_NOT_PRESENT;
     98      1.1  christos 		buffer_set_limit(query->packet, QHEADERSZ);
     99      1.1  christos 		QDCOUNT_SET(query->packet, 0);
    100      1.1  christos 		query_prepare_response(query);
    101      1.1  christos 	}
    102      1.1  christos 
    103      1.1  christos 	/* Add zone RRs until answer is full.  */
    104      1.1  christos 	while (query->axfr_current_domain != NULL &&
    105      1.1  christos 			domain_is_subdomain(query->axfr_current_domain,
    106      1.1  christos 					    query->axfr_zone->apex))
    107      1.1  christos 	{
    108      1.1  christos 		if (!query->axfr_current_rrset) {
    109      1.1  christos 			query->axfr_current_rrset = domain_find_any_rrset(
    110      1.1  christos 				query->axfr_current_domain,
    111      1.1  christos 				query->axfr_zone);
    112      1.1  christos 			query->axfr_current_rr = 0;
    113      1.1  christos 		}
    114      1.1  christos 		while (query->axfr_current_rrset) {
    115      1.1  christos 			if (query->axfr_current_rrset != query->axfr_zone->soa_rrset
    116      1.1  christos 			    && query->axfr_current_rrset->zone == query->axfr_zone)
    117      1.1  christos 			{
    118      1.1  christos 				while (query->axfr_current_rr < query->axfr_current_rrset->rr_count) {
    119  1.1.1.5  christos 					size_t oldmaxlen = query->maxlen;
    120  1.1.1.5  christos 					if(total_added == 0)
    121  1.1.1.5  christos 						/* RR > 16K can be first RR */
    122  1.1.1.5  christos 						query->maxlen = (query->tcp?TCP_MAX_MESSAGE_LEN:UDP_MAX_MESSAGE_LEN);
    123      1.1  christos 					added = packet_encode_rr(
    124      1.1  christos 						query,
    125      1.1  christos 						query->axfr_current_domain,
    126  1.1.1.6  christos 						query->axfr_current_rrset->rrs[query->axfr_current_rr],
    127  1.1.1.6  christos 						query->axfr_current_rrset->rrs[query->axfr_current_rr]->ttl);
    128  1.1.1.5  christos 					if(total_added == 0) {
    129  1.1.1.5  christos 						query->maxlen = oldmaxlen;
    130  1.1.1.5  christos 						if(query_overflow(query)) {
    131  1.1.1.5  christos 							if(added) {
    132  1.1.1.5  christos 								++total_added;
    133  1.1.1.5  christos 								++query->axfr_current_rr;
    134  1.1.1.5  christos 								goto return_answer;
    135  1.1.1.5  christos 							}
    136  1.1.1.5  christos 						}
    137  1.1.1.5  christos 					}
    138      1.1  christos 					if (!added)
    139      1.1  christos 						goto return_answer;
    140      1.1  christos 					++total_added;
    141      1.1  christos 					++query->axfr_current_rr;
    142      1.1  christos 				}
    143      1.1  christos 			}
    144      1.1  christos 
    145      1.1  christos 			query->axfr_current_rrset = query->axfr_current_rrset->next;
    146      1.1  christos 			query->axfr_current_rr = 0;
    147      1.1  christos 		}
    148      1.1  christos 		assert(query->axfr_current_domain);
    149      1.1  christos 		query->axfr_current_domain
    150      1.1  christos 			= domain_next(query->axfr_current_domain);
    151      1.1  christos 	}
    152      1.1  christos 
    153      1.1  christos 	/* Add terminating SOA RR.  */
    154      1.1  christos 	assert(query->axfr_zone->soa_rrset->rr_count == 1);
    155      1.1  christos 	added = packet_encode_rr(query,
    156      1.1  christos 				 query->axfr_zone->apex,
    157  1.1.1.6  christos 				 query->axfr_zone->soa_rrset->rrs[0],
    158  1.1.1.6  christos 				 query->axfr_zone->soa_rrset->rrs[0]->ttl);
    159      1.1  christos 	if (added) {
    160      1.1  christos 		++total_added;
    161      1.1  christos 		query->tsig_sign_it = 1; /* sign last packet */
    162      1.1  christos 		query->axfr_is_done = 1;
    163      1.1  christos 	}
    164      1.1  christos 
    165      1.1  christos return_answer:
    166      1.1  christos 	AA_SET(query->packet);
    167      1.1  christos 	ANCOUNT_SET(query->packet, total_added);
    168      1.1  christos 	NSCOUNT_SET(query->packet, 0);
    169      1.1  christos 	ARCOUNT_SET(query->packet, 0);
    170      1.1  christos 
    171      1.1  christos 	/* check if it needs tsig signatures */
    172      1.1  christos 	if(query->tsig.status == TSIG_OK) {
    173  1.1.1.3  christos #if AXFR_TSIG_SIGN_EVERY_NTH > 0
    174      1.1  christos 		if(query->tsig.updates_since_last_prepare >= AXFR_TSIG_SIGN_EVERY_NTH) {
    175  1.1.1.3  christos #endif
    176      1.1  christos 			query->tsig_sign_it = 1;
    177  1.1.1.3  christos #if AXFR_TSIG_SIGN_EVERY_NTH > 0
    178      1.1  christos 		}
    179  1.1.1.3  christos #endif
    180      1.1  christos 	}
    181      1.1  christos 	query_clear_compression_tables(query);
    182      1.1  christos 	return QUERY_IN_AXFR;
    183      1.1  christos }
    184      1.1  christos 
    185  1.1.1.4  christos /* See if the query can be admitted. */
    186  1.1.1.4  christos static int axfr_ixfr_can_admit_query(struct nsd* nsd, struct query* q)
    187  1.1.1.4  christos {
    188  1.1.1.4  christos 	struct acl_options *acl = NULL;
    189  1.1.1.4  christos 	struct zone_options* zone_opt;
    190  1.1.1.6  christos 
    191  1.1.1.6  christos #ifdef HAVE_SSL
    192  1.1.1.6  christos 	/* tls-auth-xfr-only is set and this is not an authenticated TLS */
    193  1.1.1.6  christos 	if (nsd->options->tls_auth_xfr_only && !q->tls_auth) {
    194  1.1.1.6  christos 		if (verbosity >= 2) {
    195  1.1.1.6  christos 			char address[128], proxy[128];
    196  1.1.1.6  christos 			addr2str(&q->client_addr, address, sizeof(address));
    197  1.1.1.6  christos 			addr2str(&q->remote_addr, proxy, sizeof(proxy));
    198  1.1.1.6  christos 			VERBOSITY(2, (LOG_INFO, "%s for %s from %s refused tls-auth-xfr-only",
    199  1.1.1.6  christos 				(q->qtype==TYPE_AXFR?"axfr":"ixfr"),
    200  1.1.1.6  christos 				dname_to_string(q->qname, NULL),
    201  1.1.1.6  christos 				address));
    202  1.1.1.6  christos 		}
    203  1.1.1.6  christos 		RCODE_SET(q->packet, RCODE_REFUSE);
    204  1.1.1.6  christos 		/* RFC8914 - Extended DNS Errors
    205  1.1.1.6  christos 		 * 4.19.  Extended DNS Error Code 18 - Prohibited */
    206  1.1.1.6  christos 		q->edns.ede = EDE_PROHIBITED;
    207  1.1.1.6  christos 		return 0;
    208  1.1.1.6  christos 	}
    209  1.1.1.6  christos #endif
    210  1.1.1.6  christos 
    211  1.1.1.4  christos 	zone_opt = zone_options_find(nsd->options, q->qname);
    212  1.1.1.5  christos 	if(zone_opt && q->is_proxied && acl_check_incoming_block_proxy(
    213  1.1.1.5  christos 		zone_opt->pattern->provide_xfr, q, &acl) == -1) {
    214  1.1.1.5  christos 		/* the proxy address is blocked */
    215  1.1.1.5  christos 		if (verbosity >= 2) {
    216  1.1.1.5  christos 			char address[128], proxy[128];
    217  1.1.1.5  christos 			addr2str(&q->client_addr, address, sizeof(address));
    218  1.1.1.5  christos 			addr2str(&q->remote_addr, proxy, sizeof(proxy));
    219  1.1.1.5  christos 			VERBOSITY(2, (LOG_INFO, "%s for %s from %s via proxy %s refused because of proxy, %s %s",
    220  1.1.1.5  christos 				(q->qtype==TYPE_AXFR?"axfr":"ixfr"),
    221  1.1.1.5  christos 				dname_to_string(q->qname, NULL),
    222  1.1.1.5  christos 				address, proxy,
    223  1.1.1.5  christos 				(acl?acl->ip_address_spec:"."),
    224  1.1.1.5  christos 				(acl ? ( acl->nokey    ? "NOKEY"
    225  1.1.1.5  christos 				      : acl->blocked  ? "BLOCKED"
    226  1.1.1.5  christos 				      : acl->key_name )
    227  1.1.1.5  christos 				    : "no acl matches")));
    228  1.1.1.5  christos 		}
    229  1.1.1.5  christos 		RCODE_SET(q->packet, RCODE_REFUSE);
    230  1.1.1.5  christos 		/* RFC8914 - Extended DNS Errors
    231  1.1.1.5  christos 		 * 4.19.  Extended DNS Error Code 18 - Prohibited */
    232  1.1.1.5  christos 		q->edns.ede = EDE_PROHIBITED;
    233  1.1.1.5  christos 		return 0;
    234  1.1.1.5  christos 	}
    235  1.1.1.4  christos 	if(!zone_opt ||
    236  1.1.1.4  christos 	   acl_check_incoming(zone_opt->pattern->provide_xfr, q, &acl)==-1)
    237  1.1.1.4  christos 	{
    238  1.1.1.4  christos 		if (verbosity >= 2) {
    239  1.1.1.4  christos 			char a[128];
    240  1.1.1.5  christos 			addr2str(&q->client_addr, a, sizeof(a));
    241  1.1.1.4  christos 			VERBOSITY(2, (LOG_INFO, "%s for %s from %s refused, %s",
    242  1.1.1.4  christos 				(q->qtype==TYPE_AXFR?"axfr":"ixfr"),
    243  1.1.1.4  christos 				dname_to_string(q->qname, NULL), a, acl?"blocked":"no acl matches"));
    244  1.1.1.4  christos 		}
    245  1.1.1.4  christos 		DEBUG(DEBUG_XFRD,1, (LOG_INFO, "%s refused, %s",
    246  1.1.1.4  christos 			(q->qtype==TYPE_AXFR?"axfr":"ixfr"),
    247  1.1.1.4  christos 			acl?"blocked":"no acl matches"));
    248  1.1.1.4  christos 		if (!zone_opt) {
    249  1.1.1.4  christos 			RCODE_SET(q->packet, RCODE_NOTAUTH);
    250  1.1.1.4  christos 		} else {
    251  1.1.1.4  christos 			RCODE_SET(q->packet, RCODE_REFUSE);
    252  1.1.1.4  christos 			/* RFC8914 - Extended DNS Errors
    253  1.1.1.4  christos 			 * 4.19.  Extended DNS Error Code 18 - Prohibited */
    254  1.1.1.4  christos 			q->edns.ede = EDE_PROHIBITED;
    255  1.1.1.4  christos 		}
    256  1.1.1.4  christos 		return 0;
    257  1.1.1.4  christos 	}
    258  1.1.1.6  christos #ifdef HAVE_SSL
    259  1.1.1.6  christos 	DEBUG(DEBUG_XFRD,1, (LOG_INFO, "%s admitted acl %s %s %s",
    260  1.1.1.6  christos 		(q->qtype==TYPE_AXFR?"axfr":"ixfr"),
    261  1.1.1.6  christos 		acl->ip_address_spec, acl->key_name?acl->key_name:"NOKEY",
    262  1.1.1.6  christos 		(q->tls||q->tls_auth)?(q->tls?"tls":"tls-auth"):""));
    263  1.1.1.6  christos #else
    264  1.1.1.4  christos 	DEBUG(DEBUG_XFRD,1, (LOG_INFO, "%s admitted acl %s %s",
    265  1.1.1.4  christos 		(q->qtype==TYPE_AXFR?"axfr":"ixfr"),
    266  1.1.1.4  christos 		acl->ip_address_spec, acl->key_name?acl->key_name:"NOKEY"));
    267  1.1.1.6  christos #endif
    268  1.1.1.4  christos 	if (verbosity >= 1) {
    269  1.1.1.4  christos 		char a[128];
    270  1.1.1.5  christos 		addr2str(&q->client_addr, a, sizeof(a));
    271  1.1.1.6  christos #ifdef HAVE_SSL
    272  1.1.1.6  christos 		VERBOSITY(1, (LOG_INFO, "%s for %s from %s %s %s",
    273  1.1.1.6  christos 			(q->qtype==TYPE_AXFR?"axfr":"ixfr"),
    274  1.1.1.6  christos 			dname_to_string(q->qname, NULL), a,
    275  1.1.1.6  christos 			(q->tls||q->tls_auth)?(q->tls?"tls":"tls-auth"):"",
    276  1.1.1.6  christos 			q->cert_cn?q->cert_cn:"not-verified"));
    277  1.1.1.6  christos #else
    278  1.1.1.4  christos 		VERBOSITY(1, (LOG_INFO, "%s for %s from %s",
    279  1.1.1.4  christos 			(q->qtype==TYPE_AXFR?"axfr":"ixfr"),
    280  1.1.1.4  christos 			dname_to_string(q->qname, NULL), a));
    281  1.1.1.6  christos #endif
    282  1.1.1.4  christos 	}
    283  1.1.1.4  christos 	return 1;
    284  1.1.1.4  christos }
    285  1.1.1.4  christos 
    286      1.1  christos /*
    287      1.1  christos  * Answer if this is an AXFR or IXFR query.
    288      1.1  christos  */
    289      1.1  christos query_state_type
    290      1.1  christos answer_axfr_ixfr(struct nsd *nsd, struct query *q)
    291      1.1  christos {
    292      1.1  christos 	/* Is it AXFR? */
    293      1.1  christos 	switch (q->qtype) {
    294      1.1  christos 	case TYPE_AXFR:
    295      1.1  christos 		if (q->tcp) {
    296  1.1.1.4  christos 			if(!axfr_ixfr_can_admit_query(nsd, q))
    297      1.1  christos 				return QUERY_PROCESSED;
    298  1.1.1.4  christos 			return query_axfr(nsd, q, 1);
    299      1.1  christos 		}
    300  1.1.1.3  christos 		/* AXFR over UDP queries are discarded. */
    301  1.1.1.3  christos 		RCODE_SET(q->packet, RCODE_IMPL);
    302  1.1.1.3  christos 		return QUERY_PROCESSED;
    303      1.1  christos 	case TYPE_IXFR:
    304  1.1.1.4  christos 		if(!axfr_ixfr_can_admit_query(nsd, q)) {
    305  1.1.1.4  christos 			/* get rid of authority section, if present */
    306  1.1.1.4  christos 			NSCOUNT_SET(q->packet, 0);
    307  1.1.1.4  christos 			ARCOUNT_SET(q->packet, 0);
    308  1.1.1.4  christos 			if(QDCOUNT(q->packet) > 0 && (size_t)QHEADERSZ+4+
    309  1.1.1.4  christos 				q->qname->name_size <= buffer_limit(q->packet)) {
    310  1.1.1.4  christos 				buffer_set_position(q->packet, QHEADERSZ+4+
    311  1.1.1.4  christos 					q->qname->name_size);
    312  1.1.1.4  christos 			}
    313  1.1.1.4  christos 			return QUERY_PROCESSED;
    314  1.1.1.3  christos 		}
    315  1.1.1.4  christos 		return query_ixfr(nsd, q);
    316      1.1  christos 	default:
    317      1.1  christos 		return QUERY_DISCARDED;
    318      1.1  christos 	}
    319      1.1  christos }
    320