]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
error_encode() allowed to pass along bits 322/head
authorWillem Toorop <willem@nlnetlabs.nl>
Wed, 28 Sep 2022 07:27:57 +0000 (09:27 +0200)
committerWillem Toorop <willem@nlnetlabs.nl>
Wed, 28 Sep 2022 07:27:57 +0000 (09:27 +0200)
daemon/worker.c
util/data/msgencode.c
util/data/msgencode.h

index f2fee104055fbff8ee43b25de637202c2c645638..a9deb0c717070217847ebf27276b34dfaa906cf4 100644 (file)
@@ -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;
        }
index 7b97a5466f5e441f2a5a854ee6e7720cccdae739..b5c20adeac08e9b2402aea508b0b651ded92a016 100644 (file)
@@ -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);
+}
+
index 30dc515cbe595eadcb0bf58b5ded21b32e55296c..1b37ca87092b8bb1a6778eb4dfdb793fe372287e 100644 (file)
@@ -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 */