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 17 #define AXFR_TSIG_SIGN_EVERY_NTH 96 /* tsig sign every N packets. */ 18 19 query_state_type 20 query_axfr(struct nsd *nsd, struct query *query) 21 { 22 domain_type *closest_match; 23 domain_type *closest_encloser; 24 int exact; 25 int added; 26 uint16_t total_added = 0; 27 28 if (query->axfr_is_done) 29 return QUERY_PROCESSED; 30 31 if (query->maxlen > AXFR_MAX_MESSAGE_LEN) 32 query->maxlen = AXFR_MAX_MESSAGE_LEN; 33 34 assert(!query_overflow(query)); 35 /* only keep running values for most packets */ 36 query->tsig_prepare_it = 0; 37 query->tsig_update_it = 1; 38 if(query->tsig_sign_it) { 39 /* prepare for next updates */ 40 query->tsig_prepare_it = 1; 41 query->tsig_sign_it = 0; 42 } 43 44 if (query->axfr_zone == NULL) { 45 domain_type* qdomain; 46 /* Start AXFR. */ 47 STATUP(nsd, raxfr); 48 exact = namedb_lookup(nsd->db, 49 query->qname, 50 &closest_match, 51 &closest_encloser); 52 53 qdomain = closest_encloser; 54 query->axfr_zone = domain_find_zone(nsd->db, closest_encloser); 55 56 if (!exact 57 || query->axfr_zone == NULL 58 || query->axfr_zone->apex != qdomain 59 || query->axfr_zone->soa_rrset == NULL) 60 { 61 /* No SOA no transfer */ 62 RCODE_SET(query->packet, RCODE_NOTAUTH); 63 return QUERY_PROCESSED; 64 } 65 ZTATUP(nsd, query->axfr_zone, raxfr); 66 67 query->axfr_current_domain = qdomain; 68 query->axfr_current_rrset = NULL; 69 query->axfr_current_rr = 0; 70 if(query->tsig.status == TSIG_OK) { 71 query->tsig_sign_it = 1; /* sign first packet in stream */ 72 } 73 74 query_add_compression_domain(query, qdomain, QHEADERSZ); 75 76 assert(query->axfr_zone->soa_rrset->rr_count == 1); 77 added = packet_encode_rr(query, 78 query->axfr_zone->apex, 79 &query->axfr_zone->soa_rrset->rrs[0], 80 query->axfr_zone->soa_rrset->rrs[0].ttl); 81 if (!added) { 82 /* XXX: This should never happen... generate error code? */ 83 abort(); 84 } 85 ++total_added; 86 } else { 87 /* 88 * Query name and EDNS need not be repeated after the 89 * first response packet. 90 */ 91 query->edns.status = EDNS_NOT_PRESENT; 92 buffer_set_limit(query->packet, QHEADERSZ); 93 QDCOUNT_SET(query->packet, 0); 94 query_prepare_response(query); 95 } 96 97 /* Add zone RRs until answer is full. */ 98 assert(query->axfr_current_domain); 99 100 do { 101 if (!query->axfr_current_rrset) { 102 query->axfr_current_rrset = domain_find_any_rrset( 103 query->axfr_current_domain, 104 query->axfr_zone); 105 query->axfr_current_rr = 0; 106 } 107 while (query->axfr_current_rrset) { 108 if (query->axfr_current_rrset != query->axfr_zone->soa_rrset 109 && query->axfr_current_rrset->zone == query->axfr_zone) 110 { 111 while (query->axfr_current_rr < query->axfr_current_rrset->rr_count) { 112 added = packet_encode_rr( 113 query, 114 query->axfr_current_domain, 115 &query->axfr_current_rrset->rrs[query->axfr_current_rr], 116 query->axfr_current_rrset->rrs[query->axfr_current_rr].ttl); 117 if (!added) 118 goto return_answer; 119 ++total_added; 120 ++query->axfr_current_rr; 121 } 122 } 123 124 query->axfr_current_rrset = query->axfr_current_rrset->next; 125 query->axfr_current_rr = 0; 126 } 127 assert(query->axfr_current_domain); 128 query->axfr_current_domain 129 = domain_next(query->axfr_current_domain); 130 } 131 while (query->axfr_current_domain != NULL && 132 domain_is_subdomain(query->axfr_current_domain, 133 query->axfr_zone->apex)); 134 135 /* Add terminating SOA RR. */ 136 assert(query->axfr_zone->soa_rrset->rr_count == 1); 137 added = packet_encode_rr(query, 138 query->axfr_zone->apex, 139 &query->axfr_zone->soa_rrset->rrs[0], 140 query->axfr_zone->soa_rrset->rrs[0].ttl); 141 if (added) { 142 ++total_added; 143 query->tsig_sign_it = 1; /* sign last packet */ 144 query->axfr_is_done = 1; 145 } 146 147 return_answer: 148 AA_SET(query->packet); 149 ANCOUNT_SET(query->packet, total_added); 150 NSCOUNT_SET(query->packet, 0); 151 ARCOUNT_SET(query->packet, 0); 152 153 /* check if it needs tsig signatures */ 154 if(query->tsig.status == TSIG_OK) { 155 if(query->tsig.updates_since_last_prepare >= AXFR_TSIG_SIGN_EVERY_NTH) { 156 query->tsig_sign_it = 1; 157 } 158 } 159 query_clear_compression_tables(query); 160 return QUERY_IN_AXFR; 161 } 162 163 /* 164 * Answer if this is an AXFR or IXFR query. 165 */ 166 query_state_type 167 answer_axfr_ixfr(struct nsd *nsd, struct query *q) 168 { 169 acl_options_t *acl = NULL; 170 /* Is it AXFR? */ 171 switch (q->qtype) { 172 case TYPE_AXFR: 173 if (q->tcp) { 174 zone_options_t* zone_opt; 175 zone_opt = zone_options_find(nsd->options, q->qname); 176 if(!zone_opt || 177 acl_check_incoming(zone_opt->pattern->provide_xfr, q, &acl)==-1) 178 { 179 if (verbosity > 0) { 180 char a[128]; 181 addr2str(&q->addr, a, sizeof(a)); 182 VERBOSITY(1, (LOG_INFO, "axfr for zone %s from client %s refused, %s", 183 dname_to_string(q->qname, NULL), a, acl?"blocked":"no acl matches")); 184 } 185 DEBUG(DEBUG_XFRD,1, (LOG_INFO, "axfr refused, %s", 186 acl?"blocked":"no acl matches")); 187 if (!zone_opt) { 188 RCODE_SET(q->packet, RCODE_NOTAUTH); 189 } else { 190 RCODE_SET(q->packet, RCODE_REFUSE); 191 } 192 return QUERY_PROCESSED; 193 } 194 DEBUG(DEBUG_XFRD,1, (LOG_INFO, "axfr admitted acl %s %s", 195 acl->ip_address_spec, acl->key_name?acl->key_name:"NOKEY")); 196 return query_axfr(nsd, q); 197 } 198 /** Fallthrough: AXFR over UDP queries are discarded. */ 199 case TYPE_IXFR: 200 RCODE_SET(q->packet, RCODE_IMPL); 201 return QUERY_PROCESSED; 202 default: 203 return QUERY_DISCARDED; 204 } 205 } 206