mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-10-01 22:24:55 +02:00
Move option handling to parse-time
This commit is contained in:
+2
-1
@@ -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);
|
||||
|
||||
+18
-28
@@ -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;
|
||||
|
||||
+65
-8
@@ -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 */
|
||||
|
||||
@@ -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.
|
||||
|
||||
-50
@@ -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;
|
||||
}
|
||||
|
||||
-12
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user