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 66 query->axfr_current_domain = qdomain; 67 query->axfr_current_rrset = NULL; 68 query->axfr_current_rr = 0; 69 if(query->tsig.status == TSIG_OK) { 70 query->tsig_sign_it = 1; /* sign first packet in stream */ 71 } 72 73 query_add_compression_domain(query, qdomain, QHEADERSZ); 74 75 assert(query->axfr_zone->soa_rrset->rr_count == 1); 76 added = packet_encode_rr(query, 77 query->axfr_zone->apex, 78 &query->axfr_zone->soa_rrset->rrs[0], 79 query->axfr_zone->soa_rrset->rrs[0].ttl); 80 if (!added) { 81 /* XXX: This should never happen... generate error code? */ 82 abort(); 83 } 84 ++total_added; 85 } else { 86 /* 87 * Query name and EDNS need not be repeated after the 88 * first response packet. 89 */ 90 query->edns.status = EDNS_NOT_PRESENT; 91 buffer_set_limit(query->packet, QHEADERSZ); 92 QDCOUNT_SET(query->packet, 0); 93 query_prepare_response(query); 94 } 95 96 /* Add zone RRs until answer is full. */ 97 assert(query->axfr_current_domain); 98 99 do { 100 if (!query->axfr_current_rrset) { 101 query->axfr_current_rrset = domain_find_any_rrset( 102 query->axfr_current_domain, 103 query->axfr_zone); 104 query->axfr_current_rr = 0; 105 } 106 while (query->axfr_current_rrset) { 107 if (query->axfr_current_rrset != query->axfr_zone->soa_rrset 108 && query->axfr_current_rrset->zone == query->axfr_zone) 109 { 110 while (query->axfr_current_rr < query->axfr_current_rrset->rr_count) { 111 added = packet_encode_rr( 112 query, 113 query->axfr_current_domain, 114 &query->axfr_current_rrset->rrs[query->axfr_current_rr], 115 query->axfr_current_rrset->rrs[query->axfr_current_rr].ttl); 116 if (!added) 117 goto return_answer; 118 ++total_added; 119 ++query->axfr_current_rr; 120 } 121 } 122 123 query->axfr_current_rrset = query->axfr_current_rrset->next; 124 query->axfr_current_rr = 0; 125 } 126 assert(query->axfr_current_domain); 127 query->axfr_current_domain 128 = domain_next(query->axfr_current_domain); 129 } 130 while (query->axfr_current_domain != NULL && 131 domain_is_subdomain(query->axfr_current_domain, 132 query->axfr_zone->apex)); 133 134 /* Add terminating SOA RR. */ 135 assert(query->axfr_zone->soa_rrset->rr_count == 1); 136 added = packet_encode_rr(query, 137 query->axfr_zone->apex, 138 &query->axfr_zone->soa_rrset->rrs[0], 139 query->axfr_zone->soa_rrset->rrs[0].ttl); 140 if (added) { 141 ++total_added; 142 query->tsig_sign_it = 1; /* sign last packet */ 143 query->axfr_is_done = 1; 144 } 145 146 return_answer: 147 AA_SET(query->packet); 148 ANCOUNT_SET(query->packet, total_added); 149 NSCOUNT_SET(query->packet, 0); 150 ARCOUNT_SET(query->packet, 0); 151 152 /* check if it needs tsig signatures */ 153 if(query->tsig.status == TSIG_OK) { 154 if(query->tsig.updates_since_last_prepare >= AXFR_TSIG_SIGN_EVERY_NTH) { 155 query->tsig_sign_it = 1; 156 } 157 } 158 query_clear_compression_tables(query); 159 return QUERY_IN_AXFR; 160 } 161 162 /* 163 * Answer if this is an AXFR or IXFR query. 164 */ 165 query_state_type 166 answer_axfr_ixfr(struct nsd *nsd, struct query *q) 167 { 168 acl_options_t *acl = NULL; 169 /* Is it AXFR? */ 170 switch (q->qtype) { 171 case TYPE_AXFR: 172 if (q->tcp) { 173 zone_options_t* zone_opt; 174 zone_opt = zone_options_find(nsd->options, q->qname); 175 if(!zone_opt || 176 acl_check_incoming(zone_opt->pattern->provide_xfr, q, &acl)==-1) 177 { 178 if (verbosity > 0) { 179 char a[128]; 180 addr2str(&q->addr, a, sizeof(a)); 181 VERBOSITY(1, (LOG_INFO, "axfr for zone %s from client %s refused, %s", 182 dname_to_string(q->qname, NULL), a, acl?"blocked":"no acl matches")); 183 } 184 DEBUG(DEBUG_XFRD,1, (LOG_INFO, "axfr refused, %s", 185 acl?"blocked":"no acl matches")); 186 if (!zone_opt) { 187 RCODE_SET(q->packet, RCODE_NOTAUTH); 188 } else { 189 RCODE_SET(q->packet, RCODE_REFUSE); 190 } 191 return QUERY_PROCESSED; 192 } 193 DEBUG(DEBUG_XFRD,1, (LOG_INFO, "axfr admitted acl %s %s", 194 acl->ip_address_spec, acl->key_name?acl->key_name:"NOKEY")); 195 return query_axfr(nsd, q); 196 } 197 /** Fallthrough: AXFR over UDP queries are discarded. */ 198 case TYPE_IXFR: 199 RCODE_SET(q->packet, RCODE_IMPL); 200 return QUERY_PROCESSED; 201 default: 202 return QUERY_DISCARDED; 203 } 204 } 205