From: Tom Carpay Date: Mon, 1 Nov 2021 13:48:31 +0000 (+0000) Subject: Move option handling to parse-time X-Git-Tag: release-1.14.0rc1~27^2~9 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5f8447830ae74cba4c602cf6fa5367eee033b5af;p=thirdparty%2Funbound.git Move option handling to parse-time --- diff --git a/daemon/worker.c b/daemon/worker.c index abfb84fbe..67b2e3166 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -1242,7 +1242,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error, } goto send_reply; } - if((ret=parse_edns_from_pkt(c->buffer, &edns, worker->scratchpad)) != 0) { + if((ret=parse_edns_from_pkt(c->buffer, &edns, worker->env.cfg, c, + worker->scratchpad)) != 0) { struct edns_data reply_edns; verbose(VERB_ALGO, "worker parse edns: formerror."); log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); diff --git a/services/mesh.c b/services/mesh.c index 0bfa152ee..e91c28485 100644 --- a/services/mesh.c +++ b/services/mesh.c @@ -1503,20 +1503,15 @@ int mesh_state_add_cb(struct mesh_state* s, struct edns_data* edns, r->cb = cb; r->cb_arg = cb_arg; r->edns = *edns; - if(edns->opt_list_in || edns->opt_list_out || edns->opt_list_modules_out) { - r->edns.opt_list_in = edns_opt_copy_region(edns->opt_list_in, - s->s.region); - if(!r->edns.opt_list_in) - return 0; - r->edns.opt_list_out = edns_opt_copy_region(edns->opt_list_out, - s->s.region); - if(!r->edns.opt_list_out) - return 0; - r->edns.opt_list_modules_out = edns_opt_copy_region(edns->opt_list_modules_out, - s->s.region); - if(!r->edns.opt_list_modules_out) - return 0; - } + if(edns->opt_list_in && !(r->edns.opt_list_in = + edns_opt_copy_region(edns->opt_list_in, s->s.region))) + return 0; + if(edns->opt_list_out && !(r->edns.opt_list_out = + edns_opt_copy_region(edns->opt_list_out, s->s.region))) + return 0; + if(edns->opt_list_modules_out && !(r->edns.opt_list_modules_out = + edns_opt_copy_region(edns->opt_list_modules_out, s->s.region))) + return 0; r->qid = qid; r->qflags = qflags; r->next = s->cb_list; @@ -1535,20 +1530,15 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns, return 0; r->query_reply = *rep; r->edns = *edns; - if(edns->opt_list_in || edns->opt_list_out || edns->opt_list_modules_out) { - r->edns.opt_list_in = edns_opt_copy_region(edns->opt_list_in, - s->s.region); - if(!r->edns.opt_list_in) - return 0; - r->edns.opt_list_out = edns_opt_copy_region(edns->opt_list_out, - s->s.region); - if(!r->edns.opt_list_out) - return 0; - r->edns.opt_list_modules_out = edns_opt_copy_region(edns->opt_list_modules_out, - s->s.region); - if(!r->edns.opt_list_modules_out) - return 0; - } + if(edns->opt_list_in && !(r->edns.opt_list_in = + edns_opt_copy_region(edns->opt_list_in, s->s.region))) + return 0; + if(edns->opt_list_out && !(r->edns.opt_list_out = + edns_opt_copy_region(edns->opt_list_out, s->s.region))) + return 0; + if(edns->opt_list_modules_out && !(r->edns.opt_list_modules_out = + edns_opt_copy_region(edns->opt_list_modules_out, s->s.region))) + return 0; r->qid = qid; r->qflags = qflags; r->start_time = *s->s.env->now_tv; diff --git a/util/data/msgparse.c b/util/data/msgparse.c index b3ff35341..1fc7f2d55 100644 --- a/util/data/msgparse.c +++ b/util/data/msgparse.c @@ -37,10 +37,12 @@ * Routines for message parsing a packet buffer to a descriptive structure. */ #include "config.h" +#include "util/config_file.h" #include "util/data/msgparse.h" #include "util/data/msgreply.h" #include "util/data/dname.h" #include "util/data/packed_rrset.h" +#include "util/netevent.h" #include "util/storage/lookup3.h" #include "util/regional.h" #include "sldns/rrdef.h" @@ -941,8 +943,12 @@ parse_packet(sldns_buffer* pkt, struct msg_parse* msg, struct regional* region) /** 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) + struct edns_data* edns, struct config_file* cfg, struct comm_point* c, + struct regional* region) { + int keepalive; + uint8_t data[2]; /* For keepalive value */ + /* while still more options, and have code+len to read */ /* ignores partial content (i.e. rdata len 3) */ while(rdata_len >= 4) { @@ -952,10 +958,61 @@ parse_edns_options(uint8_t* rdata_ptr, size_t rdata_len, rdata_len -= 4; if(opt_len > rdata_len) break; /* option code partial */ - if(!edns_opt_list_append(&edns->opt_list_in, opt_code, opt_len, - rdata_ptr, region)) { - log_err("out of memory"); - return 0; + + /* handle parse time edns options here */ + switch(opt_code) { + case LDNS_EDNS_NSID: + if (!cfg->nsid) + break; + if(!edns_opt_list_append(&edns->opt_list_out, + LDNS_EDNS_NSID, cfg->nsid_len, + cfg->nsid, region)) { + log_err("out of memory"); + return 0; + } + break; + + case LDNS_EDNS_KEEPALIVE: + /* To respond with a Keepalive option, the client + * connection must have received one message with a TCP + * Keepalive EDNS option, and that option must have 0 + * length data. Subsequent messages sent on that + * connection will have a TCP Keepalive option. + */ + if (!cfg->do_tcp_keepalive || c->type != comm_udp || + !c->tcp_keepalive) + break; + keepalive = c->tcp_timeout_msec / 100; + data[0] = (uint8_t)((keepalive >> 8) & 0xff); + data[1] = (uint8_t)(keepalive & 0xff); + if(!edns_opt_list_append(&edns->opt_list_out, + LDNS_EDNS_KEEPALIVE, + sizeof(data), data, region)) { + log_err("out of memory"); + return 0; + } + c->tcp_keepalive = 1; + break; + + case LDNS_EDNS_PADDING: + if(!cfg->pad_responses || c->type != comm_tcp ||!c->ssl) + break; + if(!edns_opt_list_append(&edns->opt_list_out, + LDNS_EDNS_PADDING, + 0, NULL, region)) { + log_err("out of memory"); + return 0; + } + edns->padding_block_size = cfg->pad_responses_block_size; + break; + + default: + if(!edns_opt_list_append(&edns->opt_list_in, + opt_code, opt_len, rdata_ptr, region)) { + log_err("out of memory"); + return 0; + } + break; } rdata_ptr += opt_len; rdata_len -= opt_len; @@ -1027,7 +1084,7 @@ parse_extract_edns(struct msg_parse* msg, struct edns_data* edns, /* take the options */ rdata_len = found->rr_first->size-2; rdata_ptr = found->rr_first->ttl_data+6; - if(!parse_edns_options(rdata_ptr, rdata_len, edns, region)) + if(!parse_edns_options(rdata_ptr, rdata_len, edns, NULL, NULL, region)) return 0; /* ignore rrsigs */ @@ -1063,7 +1120,7 @@ skip_pkt_rrs(sldns_buffer* pkt, int num) int parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns, - struct regional* region) + struct config_file* cfg, struct comm_point* c, struct regional* region) { size_t rdata_len; uint8_t* rdata_ptr; @@ -1105,7 +1162,7 @@ parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns, 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)) + if(!parse_edns_options(rdata_ptr, rdata_len, edns, cfg, c, region)) return LDNS_RCODE_SERVFAIL; /* ignore rrsigs */ diff --git a/util/data/msgparse.h b/util/data/msgparse.h index 4bb82cc3c..518161760 100644 --- a/util/data/msgparse.h +++ b/util/data/msgparse.h @@ -70,6 +70,8 @@ struct rrset_parse; struct rr_parse; struct regional; struct edns_option; +struct config_file; +struct comm_point; /** number of buckets in parse rrset hash table. Must be power of 2. */ #define PARSE_TABLE_SIZE 32 @@ -297,12 +299,14 @@ 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 cfg: the configuration (with nsid value etc.) + * @param c: commpoint to determine transport (if needed) * @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, - struct regional* region); + struct config_file* cfg, struct comm_point* c, struct regional* region); /** * Calculate hash value for rrset in packet. diff --git a/util/edns.c b/util/edns.c index 2081cd1e6..f55dcb97e 100644 --- a/util/edns.c +++ b/util/edns.c @@ -128,53 +128,3 @@ edns_string_addr_lookup(rbtree_type* tree, struct sockaddr_storage* addr, return (struct edns_string_addr*)addr_tree_lookup(tree, addr, addrlen); } -static int edns_keepalive(struct edns_data* edns_out, struct edns_data* edns_in, - struct comm_point* c, struct regional* region) -{ - if(c->type == comm_udp) - return 1; - - /* To respond with a Keepalive option, the client connection - * must have received one message with a TCP Keepalive EDNS option, - * and that option must have 0 length data. Subsequent messages - * sent on that connection will have a TCP Keepalive option. - */ - if(c->tcp_keepalive || - edns_opt_list_find(edns_in->opt_list_in, LDNS_EDNS_KEEPALIVE)) { - int keepalive = c->tcp_timeout_msec / 100; - uint8_t data[2]; - data[0] = (uint8_t)((keepalive >> 8) & 0xff); - data[1] = (uint8_t)(keepalive & 0xff); - if(!edns_opt_list_append(&edns_out->opt_list_out, LDNS_EDNS_KEEPALIVE, - sizeof(data), data, region)) - return 0; - c->tcp_keepalive = 1; - } - return 1; -} - -int apply_edns_options(struct edns_data* edns_out, struct edns_data* edns_in, - struct config_file* cfg, struct comm_point* c, struct regional* region) -{ - if(cfg->do_tcp_keepalive && - !edns_keepalive(edns_out, edns_in, c, region)) - return 0; - - if (cfg->nsid && edns_opt_list_find(edns_in->opt_list_in, LDNS_EDNS_NSID) - && !edns_opt_list_append(&edns_out->opt_list_out, - LDNS_EDNS_NSID, cfg->nsid_len, cfg->nsid, region)) - return 0; - - if(!cfg->pad_responses || c->type != comm_tcp || !c->ssl - || !edns_opt_list_find(edns_in->opt_list_in, LDNS_EDNS_PADDING)) { - ; /* pass */ - } - - else if(!edns_opt_list_append(&edns_out->opt_list_out, LDNS_EDNS_PADDING - , 0, NULL, region)) - return 0; - else - edns_out->padding_block_size = cfg->pad_responses_block_size; - - return 1; -} diff --git a/util/edns.h b/util/edns.h index 11742eb5b..d9ded0b84 100644 --- a/util/edns.h +++ b/util/edns.h @@ -106,16 +106,4 @@ struct edns_string_addr* edns_string_addr_lookup(rbtree_type* tree, struct sockaddr_storage* addr, socklen_t addrlen); -/** - * Apply common EDNS options. - * - * @param edns_out: initialised edns information with outbound edns. - * @param edns_in: initialised edns information with received edns. - * @param cfg: configuration. - * @param c: comm channel. - * @param region: the region to allocate the edns options in. - */ -int apply_edns_options(struct edns_data* edns_out, struct edns_data* edns_in, - struct config_file* cfg, struct comm_point* c, struct regional* region); - #endif