1 /* 2 * axfr.c -- generating AXFR responses. 3 * 4 * Copyright (c) 2001-2011, 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 /* Start AXFR. */ 46 exact = namedb_lookup(nsd->db, 47 query->qname, 48 &closest_match, 49 &closest_encloser); 50 51 query->domain = closest_encloser; 52 query->axfr_zone = domain_find_zone(closest_encloser); 53 54 if (!exact 55 || query->axfr_zone == NULL 56 || query->axfr_zone->apex != query->domain) 57 { 58 /* No SOA no transfer */ 59 RCODE_SET(query->packet, RCODE_REFUSE); 60 return QUERY_PROCESSED; 61 } 62 63 query->axfr_current_domain 64 = (domain_type *) rbtree_first(nsd->db->domains->names_to_domains); 65 query->axfr_current_rrset = NULL; 66 query->axfr_current_rr = 0; 67 if(query->tsig.status == TSIG_OK) { 68 query->tsig_sign_it = 1; /* sign first packet in stream */ 69 } 70 71 query_add_compression_domain(query, query->domain, QHEADERSZ); 72 73 assert(query->axfr_zone->soa_rrset->rr_count == 1); 74 added = packet_encode_rr(query, 75 query->axfr_zone->apex, 76 &query->axfr_zone->soa_rrset->rrs[0]); 77 if (!added) { 78 /* XXX: This should never happen... generate error code? */ 79 abort(); 80 } 81 ++total_added; 82 } else { 83 /* 84 * Query name and EDNS need not be repeated after the 85 * first response packet. 86 */ 87 query->edns.status = EDNS_NOT_PRESENT; 88 buffer_set_limit(query->packet, QHEADERSZ); 89 QDCOUNT_SET(query->packet, 0); 90 query_prepare_response(query); 91 } 92 93 /* Add zone RRs until answer is full. */ 94 assert(query->axfr_current_domain); 95 96 while ((rbnode_t *) query->axfr_current_domain != RBTREE_NULL) { 97 if (!query->axfr_current_rrset) { 98 query->axfr_current_rrset = domain_find_any_rrset( 99 query->axfr_current_domain, 100 query->axfr_zone); 101 query->axfr_current_rr = 0; 102 } 103 while (query->axfr_current_rrset) { 104 if (query->axfr_current_rrset != query->axfr_zone->soa_rrset 105 && query->axfr_current_rrset->zone == query->axfr_zone) 106 { 107 while (query->axfr_current_rr < query->axfr_current_rrset->rr_count) { 108 added = packet_encode_rr( 109 query, 110 query->axfr_current_domain, 111 &query->axfr_current_rrset->rrs[query->axfr_current_rr]); 112 if (!added) 113 goto return_answer; 114 ++total_added; 115 ++query->axfr_current_rr; 116 } 117 } 118 119 query->axfr_current_rrset = query->axfr_current_rrset->next; 120 query->axfr_current_rr = 0; 121 } 122 assert(query->axfr_current_domain); 123 query->axfr_current_domain 124 = (domain_type *) rbtree_next((rbnode_t *) query->axfr_current_domain); 125 } 126 127 /* Add terminating SOA RR. */ 128 assert(query->axfr_zone->soa_rrset->rr_count == 1); 129 added = packet_encode_rr(query, 130 query->axfr_zone->apex, 131 &query->axfr_zone->soa_rrset->rrs[0]); 132 if (added) { 133 ++total_added; 134 query->tsig_sign_it = 1; /* sign last packet */ 135 query->axfr_is_done = 1; 136 } 137 138 return_answer: 139 ANCOUNT_SET(query->packet, total_added); 140 NSCOUNT_SET(query->packet, 0); 141 ARCOUNT_SET(query->packet, 0); 142 143 /* check if it needs tsig signatures */ 144 if(query->tsig.status == TSIG_OK) { 145 if(query->tsig.updates_since_last_prepare >= AXFR_TSIG_SIGN_EVERY_NTH) { 146 query->tsig_sign_it = 1; 147 } 148 } 149 query_clear_compression_tables(query); 150 return QUERY_IN_AXFR; 151 } 152 153 /* 154 * Answer if this is an AXFR or IXFR query. 155 */ 156 query_state_type 157 answer_axfr_ixfr(struct nsd *nsd, struct query *q) 158 { 159 acl_options_t *acl; 160 /* Is it AXFR? */ 161 switch (q->qtype) { 162 case TYPE_AXFR: 163 if (q->tcp) { 164 zone_options_t* zone_opt; 165 zone_opt = zone_options_find(nsd->options, q->qname); 166 if(!zone_opt || 167 acl_check_incoming(zone_opt->provide_xfr, q, &acl)==-1) 168 { 169 if (verbosity > 0) { 170 char address[128]; 171 if (addr2ip(q->addr, address, sizeof(address))) { 172 DEBUG(DEBUG_XFRD,1, (LOG_INFO, 173 "addr2ip failed")); 174 strlcpy(address, "[unknown]", sizeof(address)); 175 } 176 VERBOSITY(1, (LOG_INFO, "axfr for zone %s from client %s refused, %s", 177 dname_to_string(q->qname, NULL), address, acl?"blocked":"no acl matches")); 178 } 179 DEBUG(DEBUG_XFRD,1, (LOG_INFO, "axfr refused, %s", 180 acl?"blocked":"no acl matches")); 181 RCODE_SET(q->packet, RCODE_REFUSE); 182 return QUERY_PROCESSED; 183 } 184 DEBUG(DEBUG_XFRD,1, (LOG_INFO, "axfr admitted acl %s %s", 185 acl->ip_address_spec, acl->key_name?acl->key_name:"NOKEY")); 186 return query_axfr(nsd, q); 187 } 188 case TYPE_IXFR: 189 RCODE_SET(q->packet, RCODE_IMPL); 190 return QUERY_PROCESSED; 191 default: 192 return QUERY_DISCARDED; 193 } 194 } 195