aboutsummaryrefslogtreecommitdiff
path: root/util/data/msgparse.c
diff options
context:
space:
mode:
Diffstat (limited to 'util/data/msgparse.c')
-rw-r--r--util/data/msgparse.c19
1 files changed, 14 insertions, 5 deletions
diff --git a/util/data/msgparse.c b/util/data/msgparse.c
index afbcbca5bc9d..9239f8fe396a 100644
--- a/util/data/msgparse.c
+++ b/util/data/msgparse.c
@@ -53,6 +53,8 @@
#include "sldns/parseutil.h"
#include "sldns/wire2str.h"
+#define MAX_PARSED_EDNS_OPTIONS 100
+
/** smart comparison of (compressed, valid) dnames from packet */
static int
smart_compare(sldns_buffer* pkt, uint8_t* dnow,
@@ -950,6 +952,7 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len,
struct comm_reply* repinfo, uint32_t now, struct regional* region,
struct cookie_secrets* cookie_secrets)
{
+ int i = 0, nsid_seen = 0, cookie_seen = 0, padding_seen = 0;
/* 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
@@ -969,7 +972,7 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len,
/* while still more options, and have code+len to read */
/* ignores partial content (i.e. rdata len 3) */
- while(rdata_len >= 4) {
+ while(rdata_len >= 4 && i < MAX_PARSED_EDNS_OPTIONS) {
uint16_t opt_code = sldns_read_uint16(rdata_ptr);
uint16_t opt_len = sldns_read_uint16(rdata_ptr+2);
uint8_t server_cookie[40];
@@ -984,8 +987,9 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len,
/* handle parse time edns options here */
switch(opt_code) {
case LDNS_EDNS_NSID:
- if (!cfg || !cfg->nsid)
+ if (!cfg || !cfg->nsid || nsid_seen)
break;
+ nsid_seen = 1;
if(!edns_opt_list_append(&edns->opt_list_out,
LDNS_EDNS_NSID, cfg->nsid_len,
cfg->nsid, region)) {
@@ -1027,8 +1031,9 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len,
case LDNS_EDNS_PADDING:
if(!cfg || !cfg->pad_responses ||
- !c || c->type != comm_tcp ||!c->ssl)
+ !c || c->type != comm_tcp ||!c->ssl || padding_seen)
break;
+ padding_seen = 1;
if(!edns_opt_list_append(&edns->opt_list_out,
LDNS_EDNS_PADDING,
0, NULL, region)) {
@@ -1039,8 +1044,9 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len,
break;
case LDNS_EDNS_COOKIE:
- if(!cfg || !cfg->do_answer_cookie || !repinfo)
+ if(!cfg || !cfg->do_answer_cookie || !repinfo || cookie_seen)
break;
+ cookie_seen = 1;
if(opt_len != 8 && (opt_len < 16 || opt_len > 40)) {
verbose(VERB_ALGO, "worker request: "
"badly formatted cookie");
@@ -1146,6 +1152,7 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len,
}
rdata_ptr += opt_len;
rdata_len -= opt_len;
+ i++;
}
return LDNS_RCODE_NOERROR;
}
@@ -1160,6 +1167,7 @@ parse_extract_edns_from_response_msg(struct msg_parse* msg,
struct rrset_parse* found_prev = 0;
size_t rdata_len;
uint8_t* rdata_ptr;
+ int i = 0;
/* since the class encodes the UDP size, we cannot use hash table to
* find the EDNS OPT record. Scan the packet. */
while(rrset) {
@@ -1219,7 +1227,7 @@ parse_extract_edns_from_response_msg(struct msg_parse* msg,
/* while still more options, and have code+len to read */
/* ignores partial content (i.e. rdata len 3) */
- while(rdata_len >= 4) {
+ while(rdata_len >= 4 && i < MAX_PARSED_EDNS_OPTIONS) {
uint16_t opt_code = sldns_read_uint16(rdata_ptr);
uint16_t opt_len = sldns_read_uint16(rdata_ptr+2);
rdata_ptr += 4;
@@ -1234,6 +1242,7 @@ parse_extract_edns_from_response_msg(struct msg_parse* msg,
}
rdata_ptr += opt_len;
rdata_len -= opt_len;
+ i++;
}
/* ignore rrsigs */
return LDNS_RCODE_NOERROR;