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