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_NOTAUTH); 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 AA_SET(query->packet); 140 ANCOUNT_SET(query->packet, total_added); 141 NSCOUNT_SET(query->packet, 0); 142 ARCOUNT_SET(query->packet, 0); 143 144 /* check if it needs tsig signatures */ 145 if(query->tsig.status == TSIG_OK) { 146 if(query->tsig.updates_since_last_prepare >= AXFR_TSIG_SIGN_EVERY_NTH) { 147 query->tsig_sign_it = 1; 148 } 149 } 150 query_clear_compression_tables(query); 151 return QUERY_IN_AXFR; 152 } 153 154 /* 155 * Answer if this is an AXFR or IXFR query. 156 */ 157 query_state_type 158 answer_axfr_ixfr(struct nsd *nsd, struct query *q) 159 { 160 acl_options_t *acl; 161 /* Is it AXFR? */ 162 switch (q->qtype) { 163 case TYPE_AXFR: 164 if (q->tcp) { 165 zone_options_t* zone_opt; 166 zone_opt = zone_options_find(nsd->options, q->qname); 167 if(!zone_opt || 168 acl_check_incoming(zone_opt->provide_xfr, q, &acl)==-1) 169 { 170 if (verbosity > 0) { 171 char address[128]; 172 if (addr2ip(q->addr, address, sizeof(address))) { 173 DEBUG(DEBUG_XFRD,1, (LOG_INFO, 174 "addr2ip failed")); 175 strlcpy(address, "[unknown]", sizeof(address)); 176 } 177 VERBOSITY(1, (LOG_INFO, "axfr for zone %s from client %s refused, %s", 178 dname_to_string(q->qname, NULL), address, acl?"blocked":"no acl matches")); 179 } 180 DEBUG(DEBUG_XFRD,1, (LOG_INFO, "axfr refused, %s", 181 acl?"blocked":"no acl matches")); 182 if (!zone_opt) { 183 RCODE_SET(q->packet, RCODE_NOTAUTH); 184 } else { 185 RCODE_SET(q->packet, RCODE_REFUSE); 186 } 187 return QUERY_PROCESSED; 188 } 189 DEBUG(DEBUG_XFRD,1, (LOG_INFO, "axfr admitted acl %s %s", 190 acl->ip_address_spec, acl->key_name?acl->key_name:"NOKEY")); 191 return query_axfr(nsd, q); 192 } 193 case TYPE_IXFR: 194 RCODE_SET(q->packet, RCODE_IMPL); 195 return QUERY_PROCESSED; 196 default: 197 return QUERY_DISCARDED; 198 } 199 } 200