static int xfrd_xfr_process_tsig(xfrd_zone_t* zone, buffer_type* packet) { int have_tsig = 0; assert(zone && zone->master && zone->master->key_options && zone->master->key_options->tsig_key && packet); if(!tsig_find_rr(&zone->tsig, packet)) { log_msg(LOG_ERR, "xfrd: zone %s, from %s: malformed tsig RR", zone->apex_str, zone->master->ip_address_spec); return 0; } if(zone->tsig.status == TSIG_OK) { have_tsig = 1; } if(have_tsig) { /* strip the TSIG resource record off... */ buffer_set_limit(packet, zone->tsig.position); ARCOUNT_SET(packet, ARCOUNT(packet) - 1); } /* keep running the TSIG hash */ tsig_update(&zone->tsig, packet, buffer_limit(packet)); if(have_tsig) { if (!tsig_verify(&zone->tsig)) { log_msg(LOG_ERR, "xfrd: zone %s, from %s: bad tsig signature", zone->apex_str, zone->master->ip_address_spec); return 0; } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s, from %s: good tsig signature", zone->apex_str, zone->master->ip_address_spec)); /* prepare for next tsigs */ tsig_prepare(&zone->tsig); } else if(zone->tsig.updates_since_last_prepare > XFRD_TSIG_MAX_UNSIGNED) { /* we allow a number of non-tsig signed packets */ log_msg(LOG_INFO, "xfrd: zone %s, from %s: too many consecutive " "packets without TSIG", zone->apex_str, zone->master->ip_address_spec); return 0; } if(!have_tsig && zone->msg_seq_nr == 0) { log_msg(LOG_ERR, "xfrd: zone %s, from %s: no tsig in first packet of reply", zone->apex_str, zone->master->ip_address_spec); return 0; } return 1; }
query_state_type rrl_slip(query_type* query) { /* discard half the packets, randomly */ if((random() & 0x1)) { /* set TC on the rest */ TC_SET(query->packet); ANCOUNT_SET(query->packet, 0); NSCOUNT_SET(query->packet, 0); ARCOUNT_SET(query->packet, 0); if(query->qname) /* header, type, class, qname */ buffer_set_position(query->packet, QHEADERSZ+4+query->qname->name_size); else buffer_set_position(query->packet, QHEADERSZ); return QUERY_PROCESSED; } return QUERY_DISCARDED; }
void xfrd_setup_packet(buffer_type* packet, uint16_t type, uint16_t klass, const dname_type* dname) { /* Set up the header */ buffer_clear(packet); ID_SET(packet, qid_generate()); FLAGS_SET(packet, 0); OPCODE_SET(packet, OPCODE_QUERY); QDCOUNT_SET(packet, 1); ANCOUNT_SET(packet, 0); NSCOUNT_SET(packet, 0); ARCOUNT_SET(packet, 0); buffer_skip(packet, QHEADERSZ); /* The question record. */ buffer_write(packet, dname_name(dname), dname->name_size); buffer_write_u16(packet, type); buffer_write_u16(packet, klass); }
void xfrd_tsig_sign_request(buffer_type* packet, tsig_record_type* tsig, acl_options_t* acl) { tsig_algorithm_type* algo; assert(acl->key_options && acl->key_options->tsig_key); algo = tsig_get_algorithm_by_name(acl->key_options->algorithm); if(!algo) { log_msg(LOG_ERR, "tsig unknown algorithm %s", acl->key_options->algorithm); return; } assert(algo); tsig_init_record(tsig, algo, acl->key_options->tsig_key); tsig_init_query(tsig, ID(packet)); tsig_prepare(tsig); tsig_update(tsig, packet, buffer_position(packet)); tsig_sign(tsig); tsig_append_rr(tsig, packet); ARCOUNT_SET(packet, ARCOUNT(packet) + 1); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "appending tsig to packet")); /* prepare for validating tsigs */ tsig_prepare(tsig); }
query_state_type query_axfr(struct nsd *nsd, struct query *query) { domain_type *closest_match; domain_type *closest_encloser; int exact; int added; uint16_t total_added = 0; if (query->axfr_is_done) return QUERY_PROCESSED; if (query->maxlen > AXFR_MAX_MESSAGE_LEN) query->maxlen = AXFR_MAX_MESSAGE_LEN; assert(!query_overflow(query)); /* only keep running values for most packets */ query->tsig_prepare_it = 0; query->tsig_update_it = 1; if(query->tsig_sign_it) { /* prepare for next updates */ query->tsig_prepare_it = 1; query->tsig_sign_it = 0; } if (query->axfr_zone == NULL) { domain_type* qdomain; /* Start AXFR. */ STATUP(nsd, raxfr); exact = namedb_lookup(nsd->db, query->qname, &closest_match, &closest_encloser); qdomain = closest_encloser; query->axfr_zone = domain_find_zone(nsd->db, closest_encloser); if (!exact || query->axfr_zone == NULL || query->axfr_zone->apex != qdomain || query->axfr_zone->soa_rrset == NULL) { /* No SOA no transfer */ RCODE_SET(query->packet, RCODE_NOTAUTH); return QUERY_PROCESSED; } ZTATUP(nsd, query->axfr_zone, raxfr); query->axfr_current_domain = qdomain; query->axfr_current_rrset = NULL; query->axfr_current_rr = 0; if(query->tsig.status == TSIG_OK) { query->tsig_sign_it = 1; /* sign first packet in stream */ } query_add_compression_domain(query, qdomain, QHEADERSZ); assert(query->axfr_zone->soa_rrset->rr_count == 1); added = packet_encode_rr(query, query->axfr_zone->apex, &query->axfr_zone->soa_rrset->rrs[0], query->axfr_zone->soa_rrset->rrs[0].ttl); if (!added) { /* XXX: This should never happen... generate error code? */ abort(); } ++total_added; } else { /* * Query name and EDNS need not be repeated after the * first response packet. */ query->edns.status = EDNS_NOT_PRESENT; buffer_set_limit(query->packet, QHEADERSZ); QDCOUNT_SET(query->packet, 0); query_prepare_response(query); } /* Add zone RRs until answer is full. */ while (query->axfr_current_domain != NULL && domain_is_subdomain(query->axfr_current_domain, query->axfr_zone->apex)) { if (!query->axfr_current_rrset) { query->axfr_current_rrset = domain_find_any_rrset( query->axfr_current_domain, query->axfr_zone); query->axfr_current_rr = 0; } while (query->axfr_current_rrset) { if (query->axfr_current_rrset != query->axfr_zone->soa_rrset && query->axfr_current_rrset->zone == query->axfr_zone) { while (query->axfr_current_rr < query->axfr_current_rrset->rr_count) { added = packet_encode_rr( query, query->axfr_current_domain, &query->axfr_current_rrset->rrs[query->axfr_current_rr], query->axfr_current_rrset->rrs[query->axfr_current_rr].ttl); if (!added) goto return_answer; ++total_added; ++query->axfr_current_rr; } } query->axfr_current_rrset = query->axfr_current_rrset->next; query->axfr_current_rr = 0; } assert(query->axfr_current_domain); query->axfr_current_domain = domain_next(query->axfr_current_domain); } /* Add terminating SOA RR. */ assert(query->axfr_zone->soa_rrset->rr_count == 1); added = packet_encode_rr(query, query->axfr_zone->apex, &query->axfr_zone->soa_rrset->rrs[0], query->axfr_zone->soa_rrset->rrs[0].ttl); if (added) { ++total_added; query->tsig_sign_it = 1; /* sign last packet */ query->axfr_is_done = 1; } return_answer: AA_SET(query->packet); ANCOUNT_SET(query->packet, total_added); NSCOUNT_SET(query->packet, 0); ARCOUNT_SET(query->packet, 0); /* check if it needs tsig signatures */ if(query->tsig.status == TSIG_OK) { if(query->tsig.updates_since_last_prepare >= AXFR_TSIG_SIGN_EVERY_NTH) { query->tsig_sign_it = 1; } } query_clear_compression_tables(query); return QUERY_IN_AXFR; }