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
query_axfr(struct nsd * nsd,struct query * query,int wstats)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. */
axfr_ixfr_can_admit_query(struct nsd * nsd,struct query * q)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
answer_axfr_ixfr(struct nsd * nsd,struct query * q)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