mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-09-11 12:27:43 +02:00
Merge branch 'master' into features/downstream-cookies
This commit is contained in:
+119
-9
@@ -806,6 +806,95 @@ calc_edns_field_size(struct edns_data* edns)
|
||||
return 1 + 2 + 2 + 4 + 2 + rdatalen;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
calc_edns_option_size(struct edns_data* edns, uint16_t code)
|
||||
{
|
||||
size_t rdatalen = 0;
|
||||
struct edns_option* opt;
|
||||
if(!edns || !edns->edns_present)
|
||||
return 0;
|
||||
for(opt = edns->opt_list_inplace_cb_out; opt; opt = opt->next) {
|
||||
if(opt->opt_code == code)
|
||||
rdatalen += 4 + opt->opt_len;
|
||||
}
|
||||
for(opt = edns->opt_list_out; opt; opt = opt->next) {
|
||||
if(opt->opt_code == code)
|
||||
rdatalen += 4 + opt->opt_len;
|
||||
}
|
||||
return rdatalen;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
calc_ede_option_size(struct edns_data* edns, uint16_t* txt_size)
|
||||
{
|
||||
size_t rdatalen = 0;
|
||||
struct edns_option* opt;
|
||||
*txt_size = 0;
|
||||
if(!edns || !edns->edns_present)
|
||||
return 0;
|
||||
for(opt = edns->opt_list_inplace_cb_out; opt; opt = opt->next) {
|
||||
if(opt->opt_code == LDNS_EDNS_EDE) {
|
||||
rdatalen += 4 + opt->opt_len;
|
||||
if(opt->opt_len > 2) *txt_size += opt->opt_len - 2;
|
||||
if(opt->opt_len >= 2 && sldns_read_uint16(
|
||||
opt->opt_data) == LDNS_EDE_OTHER) {
|
||||
*txt_size += 4 + 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
for(opt = edns->opt_list_out; opt; opt = opt->next) {
|
||||
if(opt->opt_code == LDNS_EDNS_EDE) {
|
||||
rdatalen += 4 + opt->opt_len;
|
||||
if(opt->opt_len > 2) *txt_size += opt->opt_len - 2;
|
||||
if(opt->opt_len >= 2 && sldns_read_uint16(
|
||||
opt->opt_data) == LDNS_EDE_OTHER) {
|
||||
*txt_size += 4 + 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rdatalen;
|
||||
}
|
||||
|
||||
/* Trims the EDE OPTION-DATA to not include any EXTRA-TEXT data.
|
||||
* Also removes any LDNS_EDE_OTHER options from the list since they are useless
|
||||
* without the extra text. */
|
||||
static void
|
||||
ede_trim_text(struct edns_option** list)
|
||||
{
|
||||
struct edns_option* curr, *prev = NULL;
|
||||
if(!list || !(*list)) return;
|
||||
/* Unlink and repoint if LDNS_EDE_OTHER are first in list */
|
||||
while(list && *list && (*list)->opt_code == LDNS_EDNS_EDE
|
||||
&& (*list)->opt_len >= 2
|
||||
&& sldns_read_uint16((*list)->opt_data) == LDNS_EDE_OTHER ) {
|
||||
*list = (*list)->next;
|
||||
}
|
||||
if(!list || !(*list)) return;
|
||||
curr = *list;
|
||||
while(curr) {
|
||||
if(curr->opt_code == LDNS_EDNS_EDE) {
|
||||
if(curr->opt_len >= 2 && sldns_read_uint16(
|
||||
curr->opt_data) == LDNS_EDE_OTHER) {
|
||||
/* LDNS_EDE_OTHER cannot be the first option in
|
||||
* this while, so prev is always initialized at
|
||||
* this point from the other branches;
|
||||
* cut this option off */
|
||||
prev->next = curr->next;
|
||||
curr = curr->next;
|
||||
} else if(curr->opt_len > 2) {
|
||||
/* trim this option's EXTRA-TEXT */
|
||||
curr->opt_len = 2;
|
||||
prev = curr;
|
||||
curr = curr->next;
|
||||
}
|
||||
} else {
|
||||
/* continue */
|
||||
prev = curr;
|
||||
curr = curr->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
attach_edns_record_max_msg_sz(sldns_buffer* pkt, struct edns_data* edns,
|
||||
uint16_t max_msg_sz)
|
||||
@@ -894,6 +983,7 @@ reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep,
|
||||
{
|
||||
uint16_t flags;
|
||||
unsigned int attach_edns = 0;
|
||||
uint16_t edns_field_size, ede_size, ede_txt_size;
|
||||
|
||||
if(!cached || rep->authoritative) {
|
||||
/* original flags, copy RD and CD bits from query. */
|
||||
@@ -916,25 +1006,39 @@ reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep,
|
||||
log_assert(flags & BIT_QR); /* QR bit must be on in our replies */
|
||||
if(udpsize < LDNS_HEADER_SIZE)
|
||||
return 0;
|
||||
/* currently edns does not change during calculations;
|
||||
* calculate sizes once here */
|
||||
edns_field_size = calc_edns_field_size(edns);
|
||||
ede_size = calc_ede_option_size(edns, &ede_txt_size);
|
||||
if(sldns_buffer_capacity(pkt) < udpsize)
|
||||
udpsize = sldns_buffer_capacity(pkt);
|
||||
if(udpsize < LDNS_HEADER_SIZE + calc_edns_field_size(edns)) {
|
||||
/* EDEs are optional, try to fit anything else before them */
|
||||
if(udpsize < LDNS_HEADER_SIZE + edns_field_size - ede_size) {
|
||||
/* packet too small to contain edns, omit it. */
|
||||
attach_edns = 0;
|
||||
} else {
|
||||
/* reserve space for edns record */
|
||||
attach_edns = (unsigned int)calc_edns_field_size(edns);
|
||||
udpsize -= attach_edns;
|
||||
attach_edns = (unsigned int)edns_field_size - ede_size;
|
||||
}
|
||||
|
||||
if(!reply_info_encode(qinf, rep, id, flags, pkt, timenow, region,
|
||||
udpsize, dnssec, MINIMAL_RESPONSES)) {
|
||||
udpsize - attach_edns, dnssec, MINIMAL_RESPONSES)) {
|
||||
log_err("reply encode: out of memory");
|
||||
return 0;
|
||||
}
|
||||
if(attach_edns && sldns_buffer_capacity(pkt) >=
|
||||
sldns_buffer_limit(pkt)+attach_edns)
|
||||
attach_edns_record_max_msg_sz(pkt, edns, udpsize+attach_edns);
|
||||
if(attach_edns) {
|
||||
if(udpsize >= sldns_buffer_limit(pkt) + edns_field_size)
|
||||
attach_edns_record_max_msg_sz(pkt, edns, udpsize);
|
||||
else if(udpsize >= sldns_buffer_limit(pkt) + edns_field_size - ede_txt_size) {
|
||||
ede_trim_text(&edns->opt_list_inplace_cb_out);
|
||||
ede_trim_text(&edns->opt_list_out);
|
||||
attach_edns_record_max_msg_sz(pkt, edns, udpsize);
|
||||
} else if(udpsize >= sldns_buffer_limit(pkt) + edns_field_size - ede_size) {
|
||||
edns_opt_list_remove(&edns->opt_list_inplace_cb_out, LDNS_EDNS_EDE);
|
||||
edns_opt_list_remove(&edns->opt_list_out, LDNS_EDNS_EDE);
|
||||
attach_edns_record_max_msg_sz(pkt, edns, udpsize);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -998,8 +1102,14 @@ extended_error_encode(sldns_buffer* buf, uint16_t rcode,
|
||||
es.ext_rcode = (uint8_t)(rcode >> 4);
|
||||
es.bits &= EDNS_DO;
|
||||
if(sldns_buffer_limit(buf) + calc_edns_field_size(&es) >
|
||||
edns->udp_size)
|
||||
return;
|
||||
edns->udp_size) {
|
||||
edns_opt_list_remove(&es.opt_list_inplace_cb_out, LDNS_EDNS_EDE);
|
||||
edns_opt_list_remove(&es.opt_list_out, LDNS_EDNS_EDE);
|
||||
if(sldns_buffer_limit(buf) + calc_edns_field_size(&es) >
|
||||
edns->udp_size) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
attach_edns_record(buf, &es);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user