diff options
Diffstat (limited to 'external/unbound/util/data')
-rw-r--r-- | external/unbound/util/data/dname.c | 26 | ||||
-rw-r--r-- | external/unbound/util/data/dname.h | 5 | ||||
-rw-r--r-- | external/unbound/util/data/msgencode.c | 99 | ||||
-rw-r--r-- | external/unbound/util/data/msgparse.c | 109 | ||||
-rw-r--r-- | external/unbound/util/data/msgparse.h | 45 | ||||
-rw-r--r-- | external/unbound/util/data/msgreply.c | 367 | ||||
-rw-r--r-- | external/unbound/util/data/msgreply.h | 242 | ||||
-rw-r--r-- | external/unbound/util/data/packed_rrset.c | 4 | ||||
-rw-r--r-- | external/unbound/util/data/packed_rrset.h | 17 |
9 files changed, 845 insertions, 69 deletions
diff --git a/external/unbound/util/data/dname.c b/external/unbound/util/data/dname.c index 79bf52ad4..517af2843 100644 --- a/external/unbound/util/data/dname.c +++ b/external/unbound/util/data/dname.c @@ -256,11 +256,13 @@ dname_pkt_compare(sldns_buffer* pkt, uint8_t* d1, uint8_t* d2) log_assert(len1 == len2 && len1 != 0); /* compare labels */ while(len1--) { - if(tolower((unsigned char)*d1++) != tolower((unsigned char)*d2++)) { - if(tolower((unsigned char)d1[-1]) < tolower((unsigned char)d2[-1])) + if(tolower((unsigned char)*d1) != tolower((unsigned char)*d2)) { + if(tolower((unsigned char)*d1) < tolower((unsigned char)*d2)) return -1; return 1; } + d1++; + d2++; } len1 = *d1++; len2 = *d2++; @@ -268,8 +270,8 @@ dname_pkt_compare(sldns_buffer* pkt, uint8_t* d1, uint8_t* d2) return 0; } -hashvalue_t -dname_query_hash(uint8_t* dname, hashvalue_t h) +hashvalue_type +dname_query_hash(uint8_t* dname, hashvalue_type h) { uint8_t labuf[LDNS_MAX_LABELLEN+1]; uint8_t lablen; @@ -281,8 +283,10 @@ dname_query_hash(uint8_t* dname, hashvalue_t h) log_assert(lablen <= LDNS_MAX_LABELLEN); labuf[0] = lablen; i=0; - while(lablen--) - labuf[++i] = (uint8_t)tolower((unsigned char)*dname++); + while(lablen--) { + labuf[++i] = (uint8_t)tolower((unsigned char)*dname); + dname++; + } h = hashlittle(labuf, labuf[0] + 1, h); lablen = *dname++; } @@ -290,8 +294,8 @@ dname_query_hash(uint8_t* dname, hashvalue_t h) return h; } -hashvalue_t -dname_pkt_hash(sldns_buffer* pkt, uint8_t* dname, hashvalue_t h) +hashvalue_type +dname_pkt_hash(sldns_buffer* pkt, uint8_t* dname, hashvalue_type h) { uint8_t labuf[LDNS_MAX_LABELLEN+1]; uint8_t lablen; @@ -309,8 +313,10 @@ dname_pkt_hash(sldns_buffer* pkt, uint8_t* dname, hashvalue_t h) log_assert(lablen <= LDNS_MAX_LABELLEN); labuf[0] = lablen; i=0; - while(lablen--) - labuf[++i] = (uint8_t)tolower((unsigned char)*dname++); + while(lablen--) { + labuf[++i] = (uint8_t)tolower((unsigned char)*dname); + dname++; + } h = hashlittle(labuf, labuf[0] + 1, h); lablen = *dname++; } diff --git a/external/unbound/util/data/dname.h b/external/unbound/util/data/dname.h index ae2fbadc1..53b341bf7 100644 --- a/external/unbound/util/data/dname.h +++ b/external/unbound/util/data/dname.h @@ -127,7 +127,7 @@ int dname_pkt_compare(struct sldns_buffer* pkt, uint8_t* d1, uint8_t* d2); * @param h: initial hash value. * @return: result hash value. */ -hashvalue_t dname_query_hash(uint8_t* dname, hashvalue_t h); +hashvalue_type dname_query_hash(uint8_t* dname, hashvalue_type h); /** * Hash dname, label by label, lowercasing, into hashvalue. @@ -139,7 +139,8 @@ hashvalue_t dname_query_hash(uint8_t* dname, hashvalue_t h); * @return: result hash value. * Result is the same as dname_query_hash, even if compression is used. */ -hashvalue_t dname_pkt_hash(struct sldns_buffer* pkt, uint8_t* dname, hashvalue_t h); +hashvalue_type dname_pkt_hash(struct sldns_buffer* pkt, uint8_t* dname, + hashvalue_type h); /** * Copy over a valid dname and decompress it. diff --git a/external/unbound/util/data/msgencode.c b/external/unbound/util/data/msgencode.c index 43464e9bb..1f72a03b8 100644 --- a/external/unbound/util/data/msgencode.c +++ b/external/unbound/util/data/msgencode.c @@ -48,6 +48,7 @@ #include "util/regional.h" #include "util/net_help.h" #include "sldns/sbuffer.h" +#include "services/localzone.h" /** return code that means the function ran out of memory. negative so it does * not conflict with DNS rcodes. */ @@ -458,6 +459,10 @@ packed_rrset_encode(struct ub_packed_rrset_key* key, sldns_buffer* pkt, owner_labs = dname_count_labels(key->rk.dname); owner_pos = sldns_buffer_position(pkt); + /* For an rrset with a fixed TTL, use the rrset's TTL as given */ + if((key->rk.flags & PACKED_RRSET_FIXEDTTL) != 0) + timenow = 0; + if(do_data) { const sldns_rr_descriptor* c = type_rdata_compressable(key); for(i=0; i<data->count; i++) { @@ -534,7 +539,11 @@ insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs, { int r; size_t i, setstart; - *num_rrs = 0; + /* we now allow this function to be called multiple times for the + * same section, incrementally updating num_rrs. The caller is + * responsible for initializing it (which is the case in the current + * implementation). */ + if(s != LDNS_SECTION_ADDITIONAL) { if(s == LDNS_SECTION_ANSWER && qtype == LDNS_RR_TYPE_ANY) dnssec = 1; /* include all types in ANY answer */ @@ -581,17 +590,20 @@ static int insert_query(struct query_info* qinfo, struct compress_tree_node** tree, sldns_buffer* buffer, struct regional* region) { + uint8_t* qname = qinfo->local_alias ? + qinfo->local_alias->rrset->rk.dname : qinfo->qname; + size_t qname_len = qinfo->local_alias ? + qinfo->local_alias->rrset->rk.dname_len : qinfo->qname_len; if(sldns_buffer_remaining(buffer) < qinfo->qname_len+sizeof(uint16_t)*2) return RETVAL_TRUNC; /* buffer too small */ /* the query is the first name inserted into the tree */ - if(!compress_tree_store(qinfo->qname, - dname_count_labels(qinfo->qname), + if(!compress_tree_store(qname, dname_count_labels(qname), sldns_buffer_position(buffer), region, NULL, tree)) return RETVAL_OUTMEM; - if(sldns_buffer_current(buffer) == qinfo->qname) - sldns_buffer_skip(buffer, (ssize_t)qinfo->qname_len); - else sldns_buffer_write(buffer, qinfo->qname, qinfo->qname_len); + if(sldns_buffer_current(buffer) == qname) + sldns_buffer_skip(buffer, (ssize_t)qname_len); + else sldns_buffer_write(buffer, qname, qname_len); sldns_buffer_write_u16(buffer, qinfo->qtype); sldns_buffer_write_u16(buffer, qinfo->qclass); return RETVAL_OK; @@ -662,6 +674,33 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep, * for different roundrobins for sequential id client senders. */ rr_offset = RRSET_ROUNDROBIN?ntohs(id):0; + /* "prepend" any local alias records in the answer section if this + * response is supposed to be authoritative. Currently it should + * be a single CNAME record (sanity-checked in worker_handle_request()) + * but it can be extended if and when we support more variations of + * aliases. */ + if(qinfo->local_alias && (flags & BIT_AA)) { + struct reply_info arep; + time_t timezero = 0; /* to use the 'authoritative' TTL */ + memset(&arep, 0, sizeof(arep)); + arep.flags = rep->flags; + arep.an_numrrsets = 1; + arep.rrset_count = 1; + arep.rrsets = &qinfo->local_alias->rrset; + if((r=insert_section(&arep, 1, &ancount, buffer, 0, + timezero, region, &tree, LDNS_SECTION_ANSWER, + qinfo->qtype, dnssec, rr_offset)) != RETVAL_OK) { + if(r == RETVAL_TRUNC) { + /* create truncated message */ + sldns_buffer_write_u16_at(buffer, 6, ancount); + LDNS_TC_SET(sldns_buffer_begin(buffer)); + sldns_buffer_flip(buffer); + return 1; + } + return 0; + } + } + /* insert answer section */ if((r=insert_section(rep, rep->an_numrrsets, &ancount, buffer, 0, timenow, region, &tree, LDNS_SECTION_ANSWER, qinfo->qtype, @@ -717,16 +756,23 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep, uint16_t calc_edns_field_size(struct edns_data* edns) { + size_t rdatalen = 0; + struct edns_option* opt; if(!edns || !edns->edns_present) return 0; - /* domain root '.' + type + class + ttl + rdatalen(=0) */ - return 1 + 2 + 2 + 4 + 2; + for(opt = edns->opt_list; opt; opt = opt->next) { + rdatalen += 4 + opt->opt_len; + } + /* domain root '.' + type + class + ttl + rdatalen */ + return 1 + 2 + 2 + 4 + 2 + rdatalen; } void attach_edns_record(sldns_buffer* pkt, struct edns_data* edns) { size_t len; + size_t rdatapos; + struct edns_option* opt; if(!edns || !edns->edns_present) return; /* inc additional count */ @@ -742,7 +788,18 @@ attach_edns_record(sldns_buffer* pkt, struct edns_data* edns) sldns_buffer_write_u8(pkt, edns->ext_rcode); /* ttl */ sldns_buffer_write_u8(pkt, edns->edns_version); sldns_buffer_write_u16(pkt, edns->bits); + rdatapos = sldns_buffer_position(pkt); sldns_buffer_write_u16(pkt, 0); /* rdatalen */ + /* write rdata */ + for(opt=edns->opt_list; opt; opt=opt->next) { + sldns_buffer_write_u16(pkt, opt->opt_code); + sldns_buffer_write_u16(pkt, opt->opt_len); + if(opt->opt_len != 0) + sldns_buffer_write(pkt, opt->opt_data, opt->opt_len); + } + if(edns->opt_list) + sldns_buffer_write_u16_at(pkt, rdatapos, + sldns_buffer_position(pkt)-rdatapos-2); sldns_buffer_flip(pkt); } @@ -764,6 +821,15 @@ reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep, } if(secure && (dnssec || (qflags&BIT_AD))) flags |= BIT_AD; + /* restore AA bit if we have a local alias and the response can be + * authoritative. Also clear AD bit if set as the local data is the + * primary answer. */ + if(qinf->local_alias && + (FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NOERROR || + FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NXDOMAIN)) { + flags |= BIT_AA; + flags &= ~BIT_AD; + } log_assert(flags & BIT_QR); /* QR bit must be on in our replies */ if(udpsize < LDNS_HEADER_SIZE) return 0; @@ -789,13 +855,17 @@ void qinfo_query_encode(sldns_buffer* pkt, struct query_info* qinfo) { uint16_t flags = 0; /* QUERY, NOERROR */ + const uint8_t* qname = qinfo->local_alias ? + qinfo->local_alias->rrset->rk.dname : qinfo->qname; + size_t qname_len = qinfo->local_alias ? + qinfo->local_alias->rrset->rk.dname_len : qinfo->qname_len; sldns_buffer_clear(pkt); log_assert(sldns_buffer_remaining(pkt) >= 12+255+4/*max query*/); sldns_buffer_skip(pkt, 2); /* id done later */ sldns_buffer_write_u16(pkt, flags); sldns_buffer_write_u16(pkt, 1); /* query count */ sldns_buffer_write(pkt, "\000\000\000\000\000\000", 6); /* counts */ - sldns_buffer_write(pkt, qinfo->qname, qinfo->qname_len); + sldns_buffer_write(pkt, qname, qname_len); sldns_buffer_write_u16(pkt, qinfo->qtype); sldns_buffer_write_u16(pkt, qinfo->qclass); sldns_buffer_flip(pkt); @@ -820,9 +890,14 @@ error_encode(sldns_buffer* buf, int r, struct query_info* qinfo, sldns_buffer_write(buf, &flags, sizeof(uint16_t)); sldns_buffer_write(buf, &flags, sizeof(uint16_t)); if(qinfo) { - if(sldns_buffer_current(buf) == qinfo->qname) - sldns_buffer_skip(buf, (ssize_t)qinfo->qname_len); - else sldns_buffer_write(buf, qinfo->qname, qinfo->qname_len); + const uint8_t* qname = qinfo->local_alias ? + qinfo->local_alias->rrset->rk.dname : qinfo->qname; + size_t qname_len = qinfo->local_alias ? + qinfo->local_alias->rrset->rk.dname_len : + qinfo->qname_len; + if(sldns_buffer_current(buf) == qname) + sldns_buffer_skip(buf, (ssize_t)qname_len); + else sldns_buffer_write(buf, qname, qname_len); sldns_buffer_write_u16(buf, qinfo->qtype); sldns_buffer_write_u16(buf, qinfo->qclass); } diff --git a/external/unbound/util/data/msgparse.c b/external/unbound/util/data/msgparse.c index 108c9dacb..5381500e1 100644 --- a/external/unbound/util/data/msgparse.c +++ b/external/unbound/util/data/msgparse.c @@ -38,6 +38,7 @@ */ #include "config.h" #include "util/data/msgparse.h" +#include "util/data/msgreply.h" #include "util/data/dname.h" #include "util/data/packed_rrset.h" #include "util/storage/lookup3.h" @@ -70,7 +71,7 @@ smart_compare(sldns_buffer* pkt, uint8_t* dnow, */ static struct rrset_parse* new_rrset(struct msg_parse* msg, uint8_t* dname, size_t dnamelen, - uint16_t type, uint16_t dclass, hashvalue_t hash, + uint16_t type, uint16_t dclass, hashvalue_type hash, uint32_t rrset_flags, sldns_pkt_section section, struct regional* region) { @@ -158,13 +159,13 @@ pkt_rrset_flags(sldns_buffer* pkt, uint16_t type, sldns_pkt_section sec) return f; } -hashvalue_t +hashvalue_type pkt_hash_rrset(sldns_buffer* pkt, uint8_t* dname, uint16_t type, uint16_t dclass, uint32_t rrset_flags) { /* note this MUST be identical to rrset_key_hash in packed_rrset.c */ /* this routine handles compressed names */ - hashvalue_t h = 0xab; + hashvalue_type h = 0xab; h = dname_pkt_hash(pkt, dname, h); h = hashlittle(&type, sizeof(type), h); /* host order */ h = hashlittle(&dclass, sizeof(dclass), h); /* netw order */ @@ -173,25 +174,25 @@ pkt_hash_rrset(sldns_buffer* pkt, uint8_t* dname, uint16_t type, } /** create partial dname hash for rrset hash */ -static hashvalue_t +static hashvalue_type pkt_hash_rrset_first(sldns_buffer* pkt, uint8_t* dname) { /* works together with pkt_hash_rrset_rest */ /* note this MUST be identical to rrset_key_hash in packed_rrset.c */ /* this routine handles compressed names */ - hashvalue_t h = 0xab; + hashvalue_type h = 0xab; h = dname_pkt_hash(pkt, dname, h); return h; } /** create a rrset hash from a partial dname hash */ -static hashvalue_t -pkt_hash_rrset_rest(hashvalue_t dname_h, uint16_t type, uint16_t dclass, +static hashvalue_type +pkt_hash_rrset_rest(hashvalue_type dname_h, uint16_t type, uint16_t dclass, uint32_t rrset_flags) { /* works together with pkt_hash_rrset_first */ /* note this MUST be identical to rrset_key_hash in packed_rrset.c */ - hashvalue_t h; + hashvalue_type h; h = hashlittle(&type, sizeof(type), dname_h); /* host order */ h = hashlittle(&dclass, sizeof(dclass), h); /* netw order */ h = hashlittle(&rrset_flags, sizeof(uint32_t), h); @@ -200,7 +201,7 @@ pkt_hash_rrset_rest(hashvalue_t dname_h, uint16_t type, uint16_t dclass, /** compare rrset_parse with data */ static int -rrset_parse_equals(struct rrset_parse* p, sldns_buffer* pkt, hashvalue_t h, +rrset_parse_equals(struct rrset_parse* p, sldns_buffer* pkt, hashvalue_type h, uint32_t rrset_flags, uint8_t* dname, size_t dnamelen, uint16_t type, uint16_t dclass) { @@ -214,8 +215,8 @@ rrset_parse_equals(struct rrset_parse* p, sldns_buffer* pkt, hashvalue_t h, struct rrset_parse* msgparse_hashtable_lookup(struct msg_parse* msg, sldns_buffer* pkt, - hashvalue_t h, uint32_t rrset_flags, uint8_t* dname, size_t dnamelen, - uint16_t type, uint16_t dclass) + hashvalue_type h, uint32_t rrset_flags, uint8_t* dname, + size_t dnamelen, uint16_t type, uint16_t dclass) { struct rrset_parse* p = msg->hashtable[h & (PARSE_TABLE_SIZE-1)]; while(p) { @@ -387,7 +388,7 @@ change_rrsig_rrset(struct rrset_parse* sigset, struct msg_parse* msg, int hasother, sldns_pkt_section section, struct regional* region) { struct rrset_parse* dataset = sigset; - hashvalue_t hash = pkt_hash_rrset(pkt, sigset->dname, datatype, + hashvalue_type hash = pkt_hash_rrset(pkt, sigset->dname, datatype, sigset->rrset_class, rrset_flags); log_assert( sigset->type == LDNS_RR_TYPE_RRSIG ); log_assert( datatype != LDNS_RR_TYPE_RRSIG ); @@ -454,14 +455,14 @@ change_rrsig_rrset(struct rrset_parse* sigset, struct msg_parse* msg, */ static int find_rrset(struct msg_parse* msg, sldns_buffer* pkt, uint8_t* dname, - size_t dnamelen, uint16_t type, uint16_t dclass, hashvalue_t* hash, + size_t dnamelen, uint16_t type, uint16_t dclass, hashvalue_type* hash, uint32_t* rrset_flags, uint8_t** prev_dname_first, uint8_t** prev_dname_last, size_t* prev_dnamelen, uint16_t* prev_type, uint16_t* prev_dclass, struct rrset_parse** rrset_prev, sldns_pkt_section section, struct regional* region) { - hashvalue_t dname_h = pkt_hash_rrset_first(pkt, dname); + hashvalue_type dname_h = pkt_hash_rrset_first(pkt, dname); uint16_t covtype; if(*rrset_prev) { /* check if equal to previous item */ @@ -823,7 +824,7 @@ parse_section(sldns_buffer* pkt, struct msg_parse* msg, uint16_t type, prev_type = 0; uint16_t dclass, prev_dclass = 0; uint32_t rrset_flags = 0; - hashvalue_t hash = 0; + hashvalue_type hash = 0; struct rrset_parse* rrset = NULL; int r; @@ -933,13 +934,41 @@ parse_packet(sldns_buffer* pkt, struct msg_parse* msg, struct regional* region) return 0; } +/** parse EDNS options from EDNS wireformat rdata */ +static int +parse_edns_options(uint8_t* rdata_ptr, size_t rdata_len, + struct edns_data* edns, struct regional* region) +{ + /* while still more options, and have code+len to read */ + /* ignores partial content (i.e. rdata len 3) */ + while(rdata_len >= 4) { + uint16_t opt_code = sldns_read_uint16(rdata_ptr); + uint16_t opt_len = sldns_read_uint16(rdata_ptr+2); + rdata_ptr += 4; + rdata_len -= 4; + if(opt_len > rdata_len) + break; /* option code partial */ + if(!edns_opt_append(edns, region, opt_code, opt_len, + rdata_ptr)) { + log_err("out of memory"); + return 0; + } + rdata_ptr += opt_len; + rdata_len -= opt_len; + } + return 1; +} + int -parse_extract_edns(struct msg_parse* msg, struct edns_data* edns) +parse_extract_edns(struct msg_parse* msg, struct edns_data* edns, + struct regional* region) { struct rrset_parse* rrset = msg->rrset_first; struct rrset_parse* prev = 0; struct rrset_parse* found = 0; struct rrset_parse* found_prev = 0; + size_t rdata_len; + uint8_t* rdata_ptr; /* since the class encodes the UDP size, we cannot use hash table to * find the EDNS OPT record. Scan the packet. */ while(rrset) { @@ -986,13 +1015,25 @@ parse_extract_edns(struct msg_parse* msg, struct edns_data* edns) edns->edns_version = found->rr_last->ttl_data[1]; edns->bits = sldns_read_uint16(&found->rr_last->ttl_data[2]); edns->udp_size = ntohs(found->rrset_class); - /* ignore rdata and rrsigs */ + edns->opt_list = NULL; + + /* take the options */ + rdata_len = found->rr_first->size; + rdata_ptr = found->rr_first->ttl_data+6; + if(!parse_edns_options(rdata_ptr, rdata_len, edns, region)) + return 0; + + /* ignore rrsigs */ + return 0; } int -parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns) +parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns, + struct regional* region) { + size_t rdata_len; + uint8_t* rdata_ptr; log_assert(LDNS_QDCOUNT(sldns_buffer_begin(pkt)) == 1); log_assert(LDNS_ANCOUNT(sldns_buffer_begin(pkt)) == 0); log_assert(LDNS_NSCOUNT(sldns_buffer_begin(pkt)) == 0); @@ -1017,6 +1058,36 @@ parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns) edns->ext_rcode = sldns_buffer_read_u8(pkt); /* ttl used for bits */ edns->edns_version = sldns_buffer_read_u8(pkt); edns->bits = sldns_buffer_read_u16(pkt); - /* ignore rdata and rrsigs */ + edns->opt_list = NULL; + + /* take the options */ + rdata_len = sldns_buffer_read_u16(pkt); + if(sldns_buffer_remaining(pkt) < rdata_len) + return LDNS_RCODE_FORMERR; + rdata_ptr = sldns_buffer_current(pkt); + if(!parse_edns_options(rdata_ptr, rdata_len, edns, region)) + return LDNS_RCODE_SERVFAIL; + + /* ignore rrsigs */ + return 0; } + +void +log_edns_opt_list(enum verbosity_value level, const char* info_str, + struct edns_option* list) +{ + if(verbosity >= level && list) { + char str[128], *s; + size_t slen; + verbose(level, "%s", info_str); + while(list) { + s = str; + slen = sizeof(str); + (void)sldns_wire2str_edns_option_print(&s, &slen, list->opt_code, + list->opt_data, list->opt_len); + verbose(level, " %s", str); + list = list->next; + } + } +} diff --git a/external/unbound/util/data/msgparse.h b/external/unbound/util/data/msgparse.h index 44497c8ca..e21f8504e 100644 --- a/external/unbound/util/data/msgparse.h +++ b/external/unbound/util/data/msgparse.h @@ -69,6 +69,7 @@ struct sldns_buffer; struct rrset_parse; struct rr_parse; struct regional; +struct edns_option; /** number of buckets in parse rrset hash table. Must be power of 2. */ #define PARSE_TABLE_SIZE 32 @@ -137,7 +138,7 @@ struct rrset_parse { /** next in list of all rrsets */ struct rrset_parse* rrset_all_next; /** hash value of rrset */ - hashvalue_t hash; + hashvalue_type hash; /** which section was it found in: one of * LDNS_SECTION_ANSWER, LDNS_SECTION_AUTHORITY, LDNS_SECTION_ADDITIONAL */ @@ -202,7 +203,8 @@ struct rr_parse { /** * EDNS data storage - * EDNS rdata is ignored. + * rdata is parsed in a list (has accessor functions). allocated in a + * region. */ struct edns_data { /** if EDNS OPT record was present */ @@ -215,6 +217,22 @@ struct edns_data { uint16_t bits; /** UDP reassembly size. */ uint16_t udp_size; + /** rdata element list, or NULL if none */ + struct edns_option* opt_list; +}; + +/** + * EDNS option + */ +struct edns_option { + /** next item in list */ + struct edns_option* next; + /** type of this edns option */ + uint16_t opt_code; + /** length of this edns option (cannot exceed uint16 in encoding) */ + size_t opt_len; + /** data of this edns option; allocated in region, or NULL if len=0 */ + uint8_t* opt_data; }; /** @@ -249,10 +267,12 @@ int parse_packet(struct sldns_buffer* pkt, struct msg_parse* msg, * @param msg: parsed message structure. Modified on exit, if EDNS was present * it is removed from the additional section. * @param edns: the edns data is stored here. Does not have to be initialised. + * @param region: region to alloc results in (edns option contents) * @return: 0 on success. or an RCODE on an error. * RCODE formerr if OPT in wrong section, and so on. */ -int parse_extract_edns(struct msg_parse* msg, struct edns_data* edns); +int parse_extract_edns(struct msg_parse* msg, struct edns_data* edns, + struct regional* region); /** * If EDNS data follows a query section, extract it and initialize edns struct. @@ -260,10 +280,12 @@ int parse_extract_edns(struct msg_parse* msg, struct edns_data* edns); * section. At end, right after EDNS data or no movement if failed. * @param edns: the edns data allocated by the caller. Does not have to be * initialised. + * @param region: region to alloc results in (edns option contents) * @return: 0 on success, or an RCODE on error. * RCODE formerr if OPT is badly formatted and so on. */ -int parse_edns_from_pkt(struct sldns_buffer* pkt, struct edns_data* edns); +int parse_edns_from_pkt(struct sldns_buffer* pkt, struct edns_data* edns, + struct regional* region); /** * Calculate hash value for rrset in packet. @@ -274,8 +296,8 @@ int parse_edns_from_pkt(struct sldns_buffer* pkt, struct edns_data* edns); * @param rrset_flags: rrset flags (same as packed_rrset flags). * @return hash value */ -hashvalue_t pkt_hash_rrset(struct sldns_buffer* pkt, uint8_t* dname, uint16_t type, - uint16_t dclass, uint32_t rrset_flags); +hashvalue_type pkt_hash_rrset(struct sldns_buffer* pkt, uint8_t* dname, + uint16_t type, uint16_t dclass, uint32_t rrset_flags); /** * Lookup in msg hashtable to find a rrset. @@ -290,7 +312,7 @@ hashvalue_t pkt_hash_rrset(struct sldns_buffer* pkt, uint8_t* dname, uint16_t ty * @return NULL or the rrset_parse if found. */ struct rrset_parse* msgparse_hashtable_lookup(struct msg_parse* msg, - struct sldns_buffer* pkt, hashvalue_t h, uint32_t rrset_flags, + struct sldns_buffer* pkt, hashvalue_type h, uint32_t rrset_flags, uint8_t* dname, size_t dnamelen, uint16_t type, uint16_t dclass); /** @@ -300,4 +322,13 @@ struct rrset_parse* msgparse_hashtable_lookup(struct msg_parse* msg, */ void msgparse_bucket_remove(struct msg_parse* msg, struct rrset_parse* rrset); +/** + * Log the edns options in the edns option list. + * @param level: the verbosity level. + * @param info_str: the informational string to be printed before the options. + * @param list: the edns option list. + */ +void log_edns_opt_list(enum verbosity_value level, const char* info_str, + struct edns_option* list); + #endif /* UTIL_DATA_MSGPARSE_H */ diff --git a/external/unbound/util/data/msgreply.c b/external/unbound/util/data/msgreply.c index 06593ffe1..2ce898d7f 100644 --- a/external/unbound/util/data/msgreply.c +++ b/external/unbound/util/data/msgreply.c @@ -52,6 +52,8 @@ #include "util/data/msgencode.h" #include "sldns/sbuffer.h" #include "sldns/wire2str.h" +#include "util/module.h" +#include "util/fptr_wlist.h" /** MAX TTL default for messages and rrsets */ time_t MAX_TTL = 3600 * 24 * 10; /* ten days */ @@ -76,6 +78,7 @@ parse_create_qinfo(sldns_buffer* pkt, struct msg_parse* msg, qinf->qname_len = msg->qname_len; qinf->qtype = msg->qtype; qinf->qclass = msg->qclass; + qinf->local_alias = NULL; return 1; } @@ -130,9 +133,8 @@ parse_create_repinfo(struct msg_parse* msg, struct reply_info** rep, return 1; } -/** allocate (special) rrset keys, return 0 on error */ -static int -repinfo_alloc_rrset_keys(struct reply_info* rep, struct alloc_cache* alloc, +int +reply_info_alloc_rrset_keys(struct reply_info* rep, struct alloc_cache* alloc, struct regional* region) { size_t i; @@ -435,7 +437,7 @@ parse_create_msg(sldns_buffer* pkt, struct msg_parse* msg, return 0; if(!parse_create_repinfo(msg, rep, region)) return 0; - if(!repinfo_alloc_rrset_keys(*rep, alloc, region)) + if(!reply_info_alloc_rrset_keys(*rep, alloc, region)) return 0; if(!parse_copy_decompress(pkt, msg, *rep, region)) return 0; @@ -451,6 +453,7 @@ int reply_info_parse(sldns_buffer* pkt, struct alloc_cache* alloc, int ret; qinf->qname = NULL; + qinf->local_alias = NULL; *rep = NULL; if(!(msg = regional_alloc(region, sizeof(*msg)))) { return LDNS_RCODE_SERVFAIL; @@ -461,7 +464,7 @@ int reply_info_parse(sldns_buffer* pkt, struct alloc_cache* alloc, if((ret = parse_packet(pkt, msg, region)) != 0) { return ret; } - if((ret = parse_extract_edns(msg, edns)) != 0) + if((ret = parse_extract_edns(msg, edns, region)) != 0) return ret; /* parse OK, allocate return structures */ @@ -542,6 +545,7 @@ query_info_parse(struct query_info* m, sldns_buffer* query) return 0; /* need qtype, qclass */ m->qtype = sldns_buffer_read_u16(query); m->qclass = sldns_buffer_read_u16(query); + m->local_alias = NULL; return 1; } @@ -603,10 +607,10 @@ reply_info_delete(void* d, void* ATTR_UNUSED(arg)) free(r); } -hashvalue_t +hashvalue_type query_info_hash(struct query_info *q, uint16_t flags) { - hashvalue_t h = 0xab; + hashvalue_type h = 0xab; h = hashlittle(&q->qtype, sizeof(q->qtype), h); if(q->qtype == LDNS_RR_TYPE_AAAA && (flags&BIT_CD)) h++; @@ -617,7 +621,7 @@ query_info_hash(struct query_info *q, uint16_t flags) struct msgreply_entry* query_info_entrysetup(struct query_info* q, struct reply_info* r, - hashvalue_t h) + hashvalue_type h) { struct msgreply_entry* e = (struct msgreply_entry*)malloc( sizeof(struct msgreply_entry)); @@ -683,7 +687,7 @@ reply_info_copy(struct reply_info* rep, struct alloc_cache* alloc, if(!cp) return NULL; /* allocate ub_key structures special or not */ - if(!repinfo_alloc_rrset_keys(cp, alloc, region)) { + if(!reply_info_alloc_rrset_keys(cp, alloc, region)) { if(!region) reply_info_parsedelete(cp, alloc); return NULL; @@ -814,7 +818,39 @@ log_dns_msg(const char* str, struct query_info* qinfo, struct reply_info* rep) regional_destroy(region); } -void +void +log_reply_info(enum verbosity_value v, struct query_info *qinf, + struct sockaddr_storage *addr, socklen_t addrlen, struct timeval dur, + int cached, struct sldns_buffer *rmsg) +{ + char qname_buf[LDNS_MAX_DOMAINLEN+1]; + char clientip_buf[128]; + char rcode_buf[16]; + char type_buf[16]; + char class_buf[16]; + size_t pktlen; + uint16_t rcode = FLAGS_GET_RCODE(sldns_buffer_read_u16_at(rmsg, 2)); + + if(verbosity < v) + return; + + sldns_wire2str_rcode_buf((int)rcode, rcode_buf, sizeof(rcode_buf)); + addr_to_str(addr, addrlen, clientip_buf, sizeof(clientip_buf)); + if(rcode == LDNS_RCODE_FORMERR) + { + log_info("%s - - - %s - - - ", clientip_buf, rcode_buf); + } else { + dname_str(qinf->qname, qname_buf); + pktlen = sldns_buffer_limit(rmsg); + sldns_wire2str_type_buf(qinf->qtype, type_buf, sizeof(type_buf)); + sldns_wire2str_class_buf(qinf->qclass, class_buf, sizeof(class_buf)); + log_info("%s %s %s %s %s " ARG_LL "d.%6.6d %d %d", + clientip_buf, qname_buf, type_buf, class_buf, + rcode_buf, (long long)dur.tv_sec, (int)dur.tv_usec, cached, (int)pktlen); + } +} + +void log_query_info(enum verbosity_value v, const char* str, struct query_info* qinf) { @@ -857,3 +893,314 @@ reply_all_rrsets_secure(struct reply_info* rep) } return 1; } + +int edns_opt_append(struct edns_data* edns, struct regional* region, + uint16_t code, size_t len, uint8_t* data) +{ + struct edns_option** prevp; + struct edns_option* opt; + + /* allocate new element */ + opt = (struct edns_option*)regional_alloc(region, sizeof(*opt)); + if(!opt) + return 0; + opt->next = NULL; + opt->opt_code = code; + opt->opt_len = len; + opt->opt_data = NULL; + if(len > 0) { + opt->opt_data = regional_alloc_init(region, data, len); + if(!opt->opt_data) + return 0; + } + + /* append at end of list */ + prevp = &edns->opt_list; + while(*prevp != NULL) + prevp = &((*prevp)->next); + *prevp = opt; + return 1; +} + +int edns_opt_list_append(struct edns_option** list, uint16_t code, size_t len, + uint8_t* data, struct regional* region) +{ + struct edns_option** prevp; + struct edns_option* opt; + + /* allocate new element */ + opt = (struct edns_option*)regional_alloc(region, sizeof(*opt)); + if(!opt) + return 0; + opt->next = NULL; + opt->opt_code = code; + opt->opt_len = len; + opt->opt_data = NULL; + if(len > 0) { + opt->opt_data = regional_alloc_init(region, data, len); + if(!opt->opt_data) + return 0; + } + + /* append at end of list */ + prevp = list; + while(*prevp != NULL) { + prevp = &((*prevp)->next); + } + *prevp = opt; + return 1; +} + +int edns_opt_list_remove(struct edns_option** list, uint16_t code) +{ + /* The list should already be allocated in a region. Freeing the + * allocated space in a region is not possible. We just unlink the + * required elements and they will be freed together with the region. */ + + struct edns_option* prev; + struct edns_option* curr; + if(!list || !(*list)) return 0; + + /* Unlink and repoint if the element(s) are first in list */ + while(list && *list && (*list)->opt_code == code) { + *list = (*list)->next; + } + + if(!list || !(*list)) return 1; + /* Unlink elements and reattach the list */ + prev = *list; + curr = (*list)->next; + while(curr != NULL) { + if(curr->opt_code == code) { + prev->next = curr->next; + curr = curr->next; + } else { + prev = curr; + curr = curr->next; + } + } + return 1; +} + +static int inplace_cb_reply_call_generic( + struct inplace_cb* callback_list, enum inplace_cb_list_type type, + struct query_info* qinfo, struct module_qstate* qstate, + struct reply_info* rep, int rcode, struct edns_data* edns, + struct regional* region) +{ + struct inplace_cb* cb; + struct edns_option* opt_list_out = NULL; + if(qstate) + opt_list_out = qstate->edns_opts_front_out; + for(cb=callback_list; cb; cb=cb->next) { + fptr_ok(fptr_whitelist_inplace_cb_reply_generic( + (inplace_cb_reply_func_type*)cb->cb, type)); + (void)(*(inplace_cb_reply_func_type*)cb->cb)(qinfo, qstate, rep, + rcode, edns, &opt_list_out, region, cb->id, cb->cb_arg); + } + edns->opt_list = opt_list_out; + return 1; +} + +int inplace_cb_reply_call(struct module_env* env, struct query_info* qinfo, + struct module_qstate* qstate, struct reply_info* rep, int rcode, + struct edns_data* edns, struct regional* region) +{ + return inplace_cb_reply_call_generic( + env->inplace_cb_lists[inplace_cb_reply], inplace_cb_reply, qinfo, + qstate, rep, rcode, edns, region); +} + +int inplace_cb_reply_cache_call(struct module_env* env, + struct query_info* qinfo, struct module_qstate* qstate, + struct reply_info* rep, int rcode, struct edns_data* edns, + struct regional* region) +{ + return inplace_cb_reply_call_generic( + env->inplace_cb_lists[inplace_cb_reply_cache], inplace_cb_reply_cache, + qinfo, qstate, rep, rcode, edns, region); +} + +int inplace_cb_reply_local_call(struct module_env* env, + struct query_info* qinfo, struct module_qstate* qstate, + struct reply_info* rep, int rcode, struct edns_data* edns, + struct regional* region) +{ + return inplace_cb_reply_call_generic( + env->inplace_cb_lists[inplace_cb_reply_local], inplace_cb_reply_local, + qinfo, qstate, rep, rcode, edns, region); +} + +int inplace_cb_reply_servfail_call(struct module_env* env, + struct query_info* qinfo, struct module_qstate* qstate, + struct reply_info* rep, int rcode, struct edns_data* edns, + struct regional* region) +{ + /* We are going to servfail. Remove any potential edns options. */ + if(qstate) + qstate->edns_opts_front_out = NULL; + return inplace_cb_reply_call_generic( + env->inplace_cb_lists[inplace_cb_reply_servfail], + inplace_cb_reply_servfail, qinfo, qstate, rep, rcode, edns, region); +} + +int inplace_cb_query_call(struct module_env* env, struct query_info* qinfo, + uint16_t flags, struct sockaddr_storage* addr, socklen_t addrlen, + uint8_t* zone, size_t zonelen, struct module_qstate* qstate, + struct regional* region) +{ + struct inplace_cb* cb = env->inplace_cb_lists[inplace_cb_query]; + for(; cb; cb=cb->next) { + fptr_ok(fptr_whitelist_inplace_cb_query( + (inplace_cb_query_func_type*)cb->cb)); + (void)(*(inplace_cb_query_func_type*)cb->cb)(qinfo, flags, + qstate, addr, addrlen, zone, zonelen, region, + cb->id, cb->cb_arg); + } + return 1; +} + +int inplace_cb_edns_back_parsed_call(struct module_env* env, + struct module_qstate* qstate) +{ + struct inplace_cb* cb = + env->inplace_cb_lists[inplace_cb_edns_back_parsed]; + for(; cb; cb=cb->next) { + fptr_ok(fptr_whitelist_inplace_cb_edns_back_parsed( + (inplace_cb_edns_back_parsed_func_type*)cb->cb)); + (void)(*(inplace_cb_edns_back_parsed_func_type*)cb->cb)(qstate, + cb->id, cb->cb_arg); + } + return 1; +} + +int inplace_cb_query_response_call(struct module_env* env, + struct module_qstate* qstate, struct dns_msg* response) { + struct inplace_cb* cb = + env->inplace_cb_lists[inplace_cb_query_response]; + for(; cb; cb=cb->next) { + fptr_ok(fptr_whitelist_inplace_cb_query_response( + (inplace_cb_query_response_func_type*)cb->cb)); + (void)(*(inplace_cb_query_response_func_type*)cb->cb)(qstate, + response, cb->id, cb->cb_arg); + } + return 1; +} + +struct edns_option* edns_opt_copy_region(struct edns_option* list, + struct regional* region) +{ + struct edns_option* result = NULL, *cur = NULL, *s; + while(list) { + /* copy edns option structure */ + s = regional_alloc_init(region, list, sizeof(*list)); + if(!s) return NULL; + s->next = NULL; + + /* copy option data */ + if(s->opt_data) { + s->opt_data = regional_alloc_init(region, s->opt_data, + s->opt_len); + if(!s->opt_data) + return NULL; + } + + /* link into list */ + if(cur) + cur->next = s; + else result = s; + cur = s; + + /* examine next element */ + list = list->next; + } + return result; +} + +int edns_opt_compare(struct edns_option* p, struct edns_option* q) +{ + if(!p && !q) return 0; + if(!p) return -1; + if(!q) return 1; + log_assert(p && q); + if(p->opt_code != q->opt_code) + return (int)q->opt_code - (int)p->opt_code; + if(p->opt_len != q->opt_len) + return (int)q->opt_len - (int)p->opt_len; + if(p->opt_len != 0) + return memcmp(p->opt_data, q->opt_data, p->opt_len); + return 0; +} + +int edns_opt_list_compare(struct edns_option* p, struct edns_option* q) +{ + int r; + while(p && q) { + r = edns_opt_compare(p, q); + if(r != 0) + return r; + p = p->next; + q = q->next; + } + if(p || q) { + /* uneven length lists */ + if(p) return 1; + if(q) return -1; + } + return 0; +} + +void edns_opt_list_free(struct edns_option* list) +{ + struct edns_option* n; + while(list) { + free(list->opt_data); + n = list->next; + free(list); + list = n; + } +} + +struct edns_option* edns_opt_copy_alloc(struct edns_option* list) +{ + struct edns_option* result = NULL, *cur = NULL, *s; + while(list) { + /* copy edns option structure */ + s = memdup(list, sizeof(*list)); + if(!s) { + edns_opt_list_free(result); + return NULL; + } + s->next = NULL; + + /* copy option data */ + if(s->opt_data) { + s->opt_data = memdup(s->opt_data, s->opt_len); + if(!s->opt_data) { + free(s); + edns_opt_list_free(result); + return NULL; + } + } + + /* link into list */ + if(cur) + cur->next = s; + else result = s; + cur = s; + + /* examine next element */ + list = list->next; + } + return result; +} + +struct edns_option* edns_opt_list_find(struct edns_option* list, uint16_t code) +{ + struct edns_option* p; + for(p=list; p; p=p->next) { + if(p->opt_code == code) + return p; + } + return NULL; +} diff --git a/external/unbound/util/data/msgreply.h b/external/unbound/util/data/msgreply.h index 708897950..acbdd3deb 100644 --- a/external/unbound/util/data/msgreply.h +++ b/external/unbound/util/data/msgreply.h @@ -49,8 +49,14 @@ struct alloc_cache; struct iovec; struct regional; struct edns_data; +struct edns_option; +struct inplace_cb; +struct module_qstate; +struct module_env; struct msg_parse; struct rrset_parse; +struct local_rrset; +struct dns_msg; /** calculate the prefetch TTL as 90% of original. Calculation * without numerical overflow (uin32_t) */ @@ -73,6 +79,23 @@ struct query_info { uint16_t qtype; /** qclass, host byte order */ uint16_t qclass; + /** + * Alias local answer(s) for the qname. If 'qname' is an alias defined + * in a local zone, this field will be set to the corresponding local + * RRset when the alias is determined. + * In the initial implementation this can only be a single CNAME RR + * (or NULL), but it could possibly be extended to be a DNAME or a + * chain of aliases. + * Users of this structure are responsible to initialize this field + * to be NULL; otherwise other part of query handling code may be + * confused. + * Users also have to be careful about the lifetime of data. On return + * from local zone lookup, it may point to data derived from + * configuration that may be dynamically invalidated or data allocated + * in an ephemeral regional allocator. A deep copy of the data may + * have to be generated if it has to be kept during iterative + * resolution. */ + struct local_rrset* local_alias; }; /** @@ -82,7 +105,7 @@ struct rrset_ref { /** the key with lock, and ptr to packed data. */ struct ub_packed_rrset_key* key; /** id needed */ - rrset_id_t id; + rrset_id_type id; }; /** @@ -307,7 +330,7 @@ void reply_info_delete(void* d, void* arg); /** calculate hash value of query_info, lowercases the qname, * uses CD flag for AAAA qtype */ -hashvalue_t query_info_hash(struct query_info *q, uint16_t flags); +hashvalue_type query_info_hash(struct query_info *q, uint16_t flags); /** * Setup query info entry @@ -317,7 +340,7 @@ hashvalue_t query_info_hash(struct query_info *q, uint16_t flags); * @return: newly allocated message reply cache item. */ struct msgreply_entry* query_info_entrysetup(struct query_info* q, - struct reply_info* r, hashvalue_t h); + struct reply_info* r, hashvalue_type h); /** * Copy reply_info and all rrsets in it and allocate. @@ -334,6 +357,21 @@ struct reply_info* reply_info_copy(struct reply_info* rep, struct alloc_cache* alloc, struct regional* region); /** + * Allocate (special) rrset keys. + * @param rep: reply info in which the rrset keys to be allocated, rrset[] + * array should have bee allocated with NULL pointers. + * @param alloc: how to allocate rrset keys. + * Not used if region!=NULL, it can be NULL in that case. + * @param region: if this parameter is NULL then the alloc is used. + * otherwise, rrset keys are allocated in this region. + * In a region, no special rrset key structures are needed (not shared). + * and no rrset_ref array in the reply needs to be built up. + * @return 1 on success, 0 on error + */ +int reply_info_alloc_rrset_keys(struct reply_info* rep, + struct alloc_cache* alloc, struct regional* region); + +/** * Copy a parsed rrset into given key, decompressing and allocating rdata. * @param pkt: packet for decompression * @param msg: the parser message (for flags for trust). @@ -425,10 +463,27 @@ struct ub_packed_rrset_key* reply_find_rrset(struct reply_info* rep, * @param qinfo: query section. * @param rep: rest of message. */ -void log_dns_msg(const char* str, struct query_info* qinfo, +void log_dns_msg(const char* str, struct query_info* qinfo, struct reply_info* rep); /** + * Print string with neat domain name, type, class, + * status code from, and size of a query response. + * + * @param v: at what verbosity level to print this. + * @param qinf: query section. + * @param addr: address of the client. + * @param addrlen: length of the client address. + * @param dur: how long it took to complete the query. + * @param cached: whether or not the reply is coming from + * the cache, or an outside network. + * @param rmsg: sldns buffer packet. + */ +void log_reply_info(enum verbosity_value v, struct query_info *qinf, + struct sockaddr_storage *addr, socklen_t addrlen, struct timeval dur, + int cached, struct sldns_buffer *rmsg); + +/** * Print string with neat domain name, type, class from query info. * @param v: at what verbosity level to print this. * @param str: string of message. @@ -437,4 +492,183 @@ void log_dns_msg(const char* str, struct query_info* qinfo, void log_query_info(enum verbosity_value v, const char* str, struct query_info* qinf); +/** + * Append edns option to edns data structure + * @param edns: the edns data structure to append the edns option to. + * @param region: region to allocate the new edns option. + * @param code: the edns option's code. + * @param len: the edns option's length. + * @param data: the edns option's data. + * @return false on failure. + */ +int edns_opt_append(struct edns_data* edns, struct regional* region, + uint16_t code, size_t len, uint8_t* data); + +/** + * Append edns option to edns option list + * @param list: the edns option list to append the edns option to. + * @param code: the edns option's code. + * @param len: the edns option's length. + * @param data: the edns option's data. + * @param region: region to allocate the new edns option. + * @return false on failure. + */ +int edns_opt_list_append(struct edns_option** list, uint16_t code, size_t len, + uint8_t* data, struct regional* region); + +/** + * Remove any option found on the edns option list that matches the code. + * @param list: the list of edns options. + * @param code: the opt code to remove. + * @return true when at least one edns option was removed, false otherwise. + */ +int edns_opt_list_remove(struct edns_option** list, uint16_t code); + +/** + * Find edns option in edns list + * @param list: list of edns options (eg. edns.opt_list) + * @param code: opt code to find. + * @return NULL or the edns_option element. + */ +struct edns_option* edns_opt_list_find(struct edns_option* list, uint16_t code); + +/** + * Call the registered functions in the inplace_cb_reply linked list. + * This function is going to get called while answering with a resolved query. + * @param env: module environment. + * @param qinfo: query info. + * @param qstate: module qstate. + * @param rep: Reply info. Could be NULL. + * @param rcode: return code. + * @param edns: edns data of the reply. + * @param region: region to store data. + * @return false on failure (a callback function returned an error). + */ +int inplace_cb_reply_call(struct module_env* env, struct query_info* qinfo, + struct module_qstate* qstate, struct reply_info* rep, int rcode, + struct edns_data* edns, struct regional* region); + +/** + * Call the registered functions in the inplace_cb_reply_cache linked list. + * This function is going to get called while answering from cache. + * @param env: module environment. + * @param qinfo: query info. + * @param qstate: module qstate. NULL when replying from cache. + * @param rep: Reply info. + * @param rcode: return code. + * @param edns: edns data of the reply. Edns input can be found here. + * @param region: region to store data. + * @return false on failure (a callback function returned an error). + */ +int inplace_cb_reply_cache_call(struct module_env* env, + struct query_info* qinfo, struct module_qstate* qstate, + struct reply_info* rep, int rcode, struct edns_data* edns, + struct regional* region); + +/** + * Call the registered functions in the inplace_cb_reply_local linked list. + * This function is going to get called while answering with local data. + * @param env: module environment. + * @param qinfo: query info. + * @param qstate: module qstate. NULL when replying from cache. + * @param rep: Reply info. + * @param rcode: return code. + * @param edns: edns data of the reply. Edns input can be found here. + * @param region: region to store data. + * @return false on failure (a callback function returned an error). + */ +int inplace_cb_reply_local_call(struct module_env* env, + struct query_info* qinfo, struct module_qstate* qstate, + struct reply_info* rep, int rcode, struct edns_data* edns, + struct regional* region); + +/** + * Call the registered functions in the inplace_cb_reply linked list. + * This function is going to get called while answering with a servfail. + * @param env: module environment. + * @param qinfo: query info. + * @param qstate: module qstate. Contains the edns option lists. Could be NULL. + * @param rep: Reply info. NULL when servfail. + * @param rcode: return code. LDNS_RCODE_SERVFAIL. + * @param edns: edns data of the reply. Edns input can be found here if qstate + * is NULL. + * @param region: region to store data. + * @return false on failure (a callback function returned an error). + */ +int inplace_cb_reply_servfail_call(struct module_env* env, + struct query_info* qinfo, struct module_qstate* qstate, + struct reply_info* rep, int rcode, struct edns_data* edns, + struct regional* region); + +/** + * Call the registered functions in the inplace_cb_query linked list. + * This function is going to get called just before sending a query to a + * nameserver. + * @param env: module environment. + * @param qinfo: query info. + * @param flags: flags of the query. + * @param addr: to which server to send the query. + * @param addrlen: length of addr. + * @param zone: name of the zone of the delegation point. wireformat dname. + * This is the delegation point name for which the server is deemed + * authoritative. + * @param zonelen: length of zone. + * @param qstate: module qstate. + * @param region: region to store data. + * @return false on failure (a callback function returned an error). + */ +int inplace_cb_query_call(struct module_env* env, struct query_info* qinfo, + uint16_t flags, struct sockaddr_storage* addr, socklen_t addrlen, + uint8_t* zone, size_t zonelen, struct module_qstate* qstate, + struct regional* region); + +/** + * Call the registered functions in the inplace_cb_edns_back_parsed linked list. + * This function is going to get called after parsing the EDNS data on the + * reply from a nameserver. + * @param env: module environment. + * @param qstate: module qstate. + * @return false on failure (a callback function returned an error). + */ +int inplace_cb_edns_back_parsed_call(struct module_env* env, + struct module_qstate* qstate); + +/** + * Call the registered functions in the inplace_cb_query_reponse linked list. + * This function is going to get called after receiving a reply from a + * nameserver. + * @param env: module environment. + * @param qstate: module qstate. + * @param response: received response + * @return false on failure (a callback function returned an error). + */ +int inplace_cb_query_response_call(struct module_env* env, + struct module_qstate* qstate, struct dns_msg* response); + +/** + * Copy edns option list allocated to the new region + */ +struct edns_option* edns_opt_copy_region(struct edns_option* list, + struct regional* region); + +/** + * Copy edns option list allocated with malloc + */ +struct edns_option* edns_opt_copy_alloc(struct edns_option* list); + +/** + * Free edns option list allocated with malloc + */ +void edns_opt_list_free(struct edns_option* list); + +/** + * Compare an edns option. (not entire list). Also compares contents. + */ +int edns_opt_compare(struct edns_option* p, struct edns_option* q); + +/** + * Compare edns option lists, also the order and contents of edns-options. + */ +int edns_opt_list_compare(struct edns_option* p, struct edns_option* q); + #endif /* UTIL_DATA_MSGREPLY_H */ diff --git a/external/unbound/util/data/packed_rrset.c b/external/unbound/util/data/packed_rrset.c index 66399085a..9944087cb 100644 --- a/external/unbound/util/data/packed_rrset.c +++ b/external/unbound/util/data/packed_rrset.c @@ -158,14 +158,14 @@ rrsetdata_equal(struct packed_rrset_data* d1, struct packed_rrset_data* d2) return 1; } -hashvalue_t +hashvalue_type rrset_key_hash(struct packed_rrset_key* key) { /* type is hashed in host order */ uint16_t t = ntohs(key->type); /* Note this MUST be identical to pkt_hash_rrset in msgparse.c */ /* this routine does not have a compressed name */ - hashvalue_t h = 0xab; + hashvalue_type h = 0xab; h = dname_query_hash(key->dname, h); h = hashlittle(&t, sizeof(t), h); h = hashlittle(&key->rrset_class, sizeof(uint16_t), h); diff --git a/external/unbound/util/data/packed_rrset.h b/external/unbound/util/data/packed_rrset.h index 6039aef24..28f603d6f 100644 --- a/external/unbound/util/data/packed_rrset.h +++ b/external/unbound/util/data/packed_rrset.h @@ -47,7 +47,7 @@ struct regional; /** type used to uniquely identify rrsets. Cannot be reused without * clearing the cache. */ -typedef uint64_t rrset_id_t; +typedef uint64_t rrset_id_type; /** this rrset is NSEC and is at zone apex (at child side of zonecut) */ #define PACKED_RRSET_NSEC_AT_APEX 0x1 @@ -57,6 +57,10 @@ typedef uint64_t rrset_id_t; * this is set on SOA rrsets in the authority section, to keep its TTL separate * from the SOA in the answer section from a direct SOA query or ANY query. */ #define PACKED_RRSET_SOA_NEG 0x4 +/** This rrset is considered to have a fixed TTL; its TTL doesn't have to be + * updated on encoding in a reply. This flag is not expected to be set in + * cached data. */ +#define PACKED_RRSET_FIXEDTTL 0x80000000 /** number of rrs and rrsets for integer overflow protection. More than * this is not really possible (64K packet has much less RRs and RRsets) in @@ -83,6 +87,7 @@ struct packed_rrset_key { * o PACKED_RRSET_NSEC_AT_APEX * o PACKED_RRSET_PARENT_SIDE * o PACKED_RRSET_SOA_NEG + * o PACKED_RRSET_FIXEDTTL (not supposed to be cached) */ uint32_t flags; /** the rrset type in network format */ @@ -114,7 +119,7 @@ struct ub_packed_rrset_key { * The other values in this struct may only be altered after changing * the id (which needs a writelock on entry.lock). */ - rrset_id_t id; + rrset_id_type id; /** key data: dname, type and class */ struct packed_rrset_key rk; }; @@ -191,6 +196,12 @@ enum sec_status { * RRset data. * * The data is packed, stored contiguously in memory. + * + * It is not always stored contiguously, in that case, an unpacked-packed + * rrset has the arrays separate. A bunch of routines work on that, but + * the packed rrset that is contiguous is for the rrset-cache and the + * cache-response routines in daemon/worker.c. + * * memory layout: * o base struct * o rr_len size_t array @@ -334,7 +345,7 @@ void rrset_data_delete(void* data, void* userdata); * @param key: the rrset key with name, type, class, flags. * @return hash value. */ -hashvalue_t rrset_key_hash(struct packed_rrset_key* key); +hashvalue_type rrset_key_hash(struct packed_rrset_key* key); /** * Fixup pointers in fixed data packed_rrset_data blob. |