From 1607c9006e1af5388e9b3ae34ee0f32b0bd0e35c Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Wed, 28 Sep 2022 09:27:57 +0200 Subject: [PATCH] error_encode() allowed to pass along bits --- daemon/worker.c | 51 +++++++++++++++++++------------------------ util/data/msgencode.c | 23 ++++++++++++++----- util/data/msgencode.h | 19 +++++++++++++++- 3 files changed, 58 insertions(+), 35 deletions(-) diff --git a/daemon/worker.c b/daemon/worker.c index f2fee1040..a9deb0c71 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -1268,8 +1268,6 @@ worker_handle_request(struct comm_point* c, void* arg, int error, struct query_info qinfo_tmp; /* placeholder for lookup_qinfo */ struct respip_client_info* cinfo = NULL, cinfo_tmp; memset(&qinfo, 0, sizeof(qinfo)); - memset(&edns, 0, sizeof(edns)); - edns.udp_size = 512; if((error != NETEVENT_NOERROR && error != NETEVENT_DONE)|| !repinfo) { /* some bad tcp query DNS formats give these error calls */ @@ -1444,34 +1442,32 @@ worker_handle_request(struct comm_point* c, void* arg, int error, memset(&reply_edns, 0, sizeof(reply_edns)); reply_edns.edns_present = 1; reply_edns.udp_size = EDNS_ADVERTISED_SIZE; - LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), ret); error_encode(c->buffer, ret, &qinfo, *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), sldns_buffer_read_u16_at(c->buffer, 2), &reply_edns); regional_free_all(worker->scratchpad); goto send_reply; } - if(edns.edns_present && edns.edns_version != 0) { - edns.opt_list_in = NULL; - edns.opt_list_out = NULL; - edns.opt_list_inplace_cb_out = NULL; - edns.padding_block_size = 0; - edns.cookie_present = 0; - edns.cookie_valid = 0; - verbose(VERB_ALGO, "query with bad edns version."); - log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); - error_encode(c->buffer, EDNS_RCODE_BADVERS, &qinfo, - *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), - sldns_buffer_read_u16_at(c->buffer, 2), &edns); - regional_free_all(worker->scratchpad); - goto send_reply; - } - if(edns.udp_size < NORMAL_UDP_SIZE && - worker->daemon->cfg->harden_short_bufsize) { - verbose(VERB_QUERY, "worker request: EDNS bufsize %d ignored", - (int)edns.udp_size); - log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); - edns.udp_size = NORMAL_UDP_SIZE; + if(edns.edns_present) { + if(edns.edns_version != 0) { + edns.opt_list_in = NULL; + edns.opt_list_out = NULL; + edns.opt_list_inplace_cb_out = NULL; + verbose(VERB_ALGO, "query with bad edns version."); + log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); + extended_error_encode(c->buffer, EDNS_RCODE_BADVERS, &qinfo, + *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), + sldns_buffer_read_u16_at(c->buffer, 2), 0, &edns); + regional_free_all(worker->scratchpad); + goto send_reply; + } + if(edns.udp_size < NORMAL_UDP_SIZE && + worker->daemon->cfg->harden_short_bufsize) { + verbose(VERB_QUERY, "worker request: EDNS bufsize %d ignored", + (int)edns.udp_size); + log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); + edns.udp_size = NORMAL_UDP_SIZE; + } } /* "if, else if" sequence below deals with downstream DNS Cookies */ if (acl != acl_allow_cookie) @@ -1485,12 +1481,12 @@ worker_handle_request(struct comm_point* c, void* arg, int error, else if (edns.cookie_present) { /* Cookie present, but not valid: Cookie was bad! */ - error_encode(c->buffer, + extended_error_encode(c->buffer, LDNS_EXT_RCODE_BADCOOKIE, &qinfo, *(uint16_t*)(void *) sldns_buffer_begin(c->buffer), sldns_buffer_read_u16_at(c->buffer, 2), - &edns); + 0, &edns); regional_free_all(worker->scratchpad); goto send_reply; } else { @@ -1503,12 +1499,11 @@ worker_handle_request(struct comm_point* c, void* arg, int error, worker->scratchpad, LDNS_EDE_OTHER, "DNS Cookie needed for UDP replies"); error_encode(c->buffer, - LDNS_RCODE_REFUSED, &qinfo, + (LDNS_RCODE_REFUSED|BIT_TC), &qinfo, *(uint16_t*)(void *) sldns_buffer_begin(c->buffer), sldns_buffer_read_u16_at(c->buffer, 2), &edns); - LDNS_TC_SET(sldns_buffer_begin(c->buffer)); regional_free_all(worker->scratchpad); goto send_reply; } diff --git a/util/data/msgencode.c b/util/data/msgencode.c index 7b97a5466..b5c20adea 100644 --- a/util/data/msgencode.c +++ b/util/data/msgencode.c @@ -958,15 +958,17 @@ qinfo_query_encode(sldns_buffer* pkt, struct query_info* qinfo) sldns_buffer_flip(pkt); } + void -error_encode(sldns_buffer* buf, int r, struct query_info* qinfo, - uint16_t qid, uint16_t qflags, struct edns_data* edns) +extended_error_encode(sldns_buffer* buf, uint16_t rcode, struct query_info* qinfo, + uint16_t qid, uint16_t qflags, uint16_t xflags, struct edns_data* edns) { uint16_t flags; sldns_buffer_clear(buf); sldns_buffer_write(buf, &qid, sizeof(uint16_t)); - flags = (uint16_t)(BIT_QR | BIT_RA | (r & 0xF)); /* QR and retcode*/ + flags = (uint16_t)(BIT_QR | BIT_RA | (rcode & 0xF)); /* QR and retcode*/ + flags |= xflags; flags |= (qflags & (BIT_RD|BIT_CD)); /* copy RD and CD bit */ sldns_buffer_write_u16(buf, flags); if(qinfo) flags = 1; @@ -991,13 +993,22 @@ error_encode(sldns_buffer* buf, int r, struct query_info* qinfo, sldns_buffer_flip(buf); if(edns) { struct edns_data es = *edns; - size_t edns_field_size = calc_edns_field_size(&es); es.edns_version = EDNS_ADVERTISED_VERSION; es.udp_size = EDNS_ADVERTISED_SIZE; - es.ext_rcode = r >= 0x10 ? 1 : 0; + es.ext_rcode = (uint8_t)(rcode >> 4); es.bits &= EDNS_DO; - if(sldns_buffer_limit(buf) + edns_field_size > edns->udp_size) + if(sldns_buffer_limit(buf) + calc_edns_field_size(&es) > + edns->udp_size) return; attach_edns_record(buf, &es); } } + +void +error_encode(sldns_buffer* buf, int r, struct query_info* qinfo, + uint16_t qid, uint16_t qflags, struct edns_data* edns) +{ + extended_error_encode(buf, (r & 0x000F), qinfo, qid, qflags + , (r & 0xFFF0), edns); +} + diff --git a/util/data/msgencode.h b/util/data/msgencode.h index 30dc515cb..1b37ca870 100644 --- a/util/data/msgencode.h +++ b/util/data/msgencode.h @@ -120,7 +120,7 @@ void attach_edns_record(struct sldns_buffer* pkt, struct edns_data* edns); * Encode an error. With QR and RA set. * * @param pkt: where to store the packet. - * @param r: RCODE value to encode. + * @param r: RCODE value to encode (may contain extra flags). * @param qinfo: if not NULL, the query is included. * @param qid: query ID to set in packet. network order. * @param qflags: original query flags (to copy RD and CD bits). host order. @@ -130,4 +130,21 @@ void attach_edns_record(struct sldns_buffer* pkt, struct edns_data* edns); void error_encode(struct sldns_buffer* pkt, int r, struct query_info* qinfo, uint16_t qid, uint16_t qflags, struct edns_data* edns); +/** + * Encode an extended error. With QR and RA set. + * + * @param pkt: where to store the packet. + * @param rcode: Extended RCODE value to encode. + * @param qinfo: if not NULL, the query is included. + * @param qid: query ID to set in packet. network order. + * @param qflags: original query flags (to copy RD and CD bits). host order. + * @param xflags: extra flags to set (such as for example BIT_AA and/or BIT_TC) + * @param edns: if not NULL, this is the query edns info, + * and an edns reply is attached. Only attached if EDNS record fits reply. + * Without edns extended errors (i.e. > 15 )will not be conveyed. + */ +void extended_error_encode(struct sldns_buffer* pkt, uint16_t rcode, + struct query_info* qinfo, uint16_t qid, uint16_t qflags, + uint16_t xflags, struct edns_data* edns); + #endif /* UTIL_DATA_MSGENCODE_H */ -- 2.47.2