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