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