]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
Plumming for ub_send and ub_send_async
authorWillem Toorop <willem@nlnetlabs.nl>
Sat, 5 Nov 2022 17:50:57 +0000 (18:50 +0100)
committerWillem Toorop <willem@nlnetlabs.nl>
Sat, 5 Nov 2022 17:50:57 +0000 (18:50 +0100)
libunbound/context.c
libunbound/context.h
libunbound/libunbound.c
libunbound/libworker.c
services/outside_network.c
services/outside_network.h
util/data/msgreply.h

index c8d911f13c7f9b90fa4c605313fb89b5612c7e63..61b2dd442cd7459fb7b5e4035a83978d28817e7a 100644 (file)
@@ -53,6 +53,7 @@
 #include "util/storage/slabhash.h"
 #include "util/edns.h"
 #include "sldns/sbuffer.h"
+#include "sldns/wire2str.h"
 
 int 
 context_finalize(struct ub_ctx* ctx)
@@ -144,9 +145,17 @@ find_id(struct ub_ctx* ctx, int* id)
 
 struct ctx_query* 
 context_new(struct ub_ctx* ctx, const char* name, int rrtype, int rrclass, 
-       ub_callback_type cb, ub_event_callback_type cb_event, void* cbarg)
+       ub_callback_type cb, ub_event_callback_type cb_event, void* cbarg,
+       const uint8_t* qbuf, size_t qbuf_len)
 {
        struct ctx_query* q = (struct ctx_query*)calloc(1, sizeof(*q));
+       char qname_str_buf[1024];
+       char *qname_str = qname_str_buf;
+       size_t qname_str_len = sizeof(qname_str_buf);
+       uint8_t *qname;
+       size_t qname_len;
+       int comprloop;
+
        if(!q) return NULL;
        lock_basic_lock(&ctx->cfglock);
        if(!find_id(ctx, &q->querynum)) {
@@ -165,6 +174,32 @@ context_new(struct ub_ctx* ctx, const char* name, int rrtype, int rrclass,
                free(q);
                return NULL;
        }
+       if(!name && qbuf) {
+               if(qbuf_len < 12) {
+                       free(q->res);
+                       free(q);
+                       return NULL;
+               }
+               qname = (uint8_t* )qbuf + 12;
+               qname_len = qbuf_len - 12;
+               comprloop = 0;
+
+               /* get query name from the input buffer */
+               sldns_wire2str_dname_scan(
+                               &qname, &qname_len,
+                               &qname_str, &qname_str_len,
+                               (uint8_t *)qbuf, qbuf_len,
+                               &comprloop);
+               *qname_str = 0;
+               name = qname_str_buf;
+               if (qname_len < 4) {
+                       free(q->res);
+                       free(q);
+                       return NULL;
+               }
+               rrtype = sldns_read_uint16(qname);
+               rrclass = sldns_read_uint16(qname + 2);
+       }
        q->res->qname = strdup(name);
        if(!q->res->qname) {
                free(q->res);
index c0c86fb526978e0f142cdd4bb9e367a98e5b859a..399c1eaef4516de557704eb685a7b7f6462b97e9 100644 (file)
@@ -171,6 +171,11 @@ struct ctx_query {
        /** store libworker that is handling this query */
        struct libworker* w;
 
+       /** raw query packet */
+       const uint8_t *qbuf;
+       /** length of raw query packet */
+       size_t qbuf_len;
+
        /** result structure, also contains original query, type, class.
         * malloced ptr ready to hand to the client. */
        struct ub_result* res;
@@ -224,7 +229,7 @@ void context_query_delete(struct ctx_query* q);
  */
 struct ctx_query* context_new(struct ub_ctx* ctx, const char* name, int rrtype,
         int rrclass,  ub_callback_type cb, ub_event_callback_type cb_event,
-       void* cbarg);
+       void* cbarg, const uint8_t* qbuf, size_t qbuf_len);
 
 /**
  * Get a new alloc. Creates a new one or uses a cached one.
index ea5ef24bb01ca0acb412d1be2375f7267bcfd03e..5ce736a67834d77a594acba80dfafa49f2b6924b 100644 (file)
@@ -714,7 +714,8 @@ ub_resolve(struct ub_ctx* ctx, const char* name, int rrtype,
        }
        /* create new ctx_query and attempt to add to the list */
        lock_basic_unlock(&ctx->cfglock);
-       q = context_new(ctx, name, rrtype, rrclass, NULL, NULL, NULL);
+       q = context_new(ctx, name, rrtype, rrclass,
+                       NULL, NULL, NULL, NULL, 0);
        if(!q)
                return UB_NOMEM;
        /* become a resolver thread for a bit */
@@ -771,7 +772,8 @@ ub_resolve_event(struct ub_ctx* ctx, const char* name, int rrtype,
        ub_comm_base_now(ctx->event_worker->base);
 
        /* create new ctx_query and attempt to add to the list */
-       q = context_new(ctx, name, rrtype, rrclass, NULL, callback, mydata);
+       q = context_new(ctx, name, rrtype, rrclass,
+                       NULL, callback, mydata, NULL, 0);
        if(!q)
                return UB_NOMEM;
 
@@ -816,7 +818,8 @@ ub_resolve_async(struct ub_ctx* ctx, const char* name, int rrtype,
        }
 
        /* create new ctx_query and attempt to add to the list */
-       q = context_new(ctx, name, rrtype, rrclass, callback, NULL, mydata);
+       q = context_new(ctx, name, rrtype, rrclass,
+                       callback, NULL, mydata, NULL, 0);
        if(!q)
                return UB_NOMEM;
 
@@ -845,6 +848,116 @@ ub_resolve_async(struct ub_ctx* ctx, const char* name, int rrtype,
        return UB_NOERROR;
 }
 
+int
+ub_send(struct ub_ctx* ctx, const char* packet, int length,
+        struct ub_result** result)
+{
+       struct ctx_query* q;
+       int r;
+       *result = NULL;
+
+       lock_basic_lock(&ctx->cfglock);
+       if(!ctx->finalized) {
+               r = context_finalize(ctx);
+               if(r) {
+                       lock_basic_unlock(&ctx->cfglock);
+                       return r;
+               }
+       }
+       /* create new ctx_query and attempt to add to the list */
+       lock_basic_unlock(&ctx->cfglock);
+       q = context_new(ctx, NULL, 0, 0,
+                       NULL, NULL, NULL, (const uint8_t *)packet, length);
+       if(!q)
+               return UB_NOMEM;
+       /* become a resolver thread for a bit */
+
+       r = libworker_fg(ctx, q);
+       if(r) {
+               lock_basic_lock(&ctx->cfglock);
+               (void)rbtree_delete(&ctx->queries, q->node.key);
+               context_query_delete(q);
+               lock_basic_unlock(&ctx->cfglock);
+               return r;
+       }
+       q->res->answer_packet = q->msg;
+       q->res->answer_len = (int)q->msg_len;
+       q->msg = NULL;
+       *result = q->res;
+       q->res = NULL;
+
+       lock_basic_lock(&ctx->cfglock);
+       (void)rbtree_delete(&ctx->queries, q->node.key);
+       context_query_delete(q);
+       lock_basic_unlock(&ctx->cfglock);
+       return UB_NOERROR;
+}
+
+int 
+ub_send_async(struct ub_ctx* ctx, const char* packet, int length,
+               void* mydata, ub_callback_type callback, int* async_id)
+{
+       struct ctx_query* q;
+       uint8_t* msg = NULL;
+       uint32_t len = 0;
+
+       if(async_id)
+               *async_id = 0;
+       lock_basic_lock(&ctx->cfglock);
+       if(!ctx->finalized) {
+               int r = context_finalize(ctx);
+               if(r) {
+                       lock_basic_unlock(&ctx->cfglock);
+                       return r;
+               }
+       }
+       if(!ctx->created_bg) {
+               int r;
+               ctx->created_bg = 1;
+               lock_basic_unlock(&ctx->cfglock);
+               r = libworker_bg(ctx);
+               if(r) {
+                       lock_basic_lock(&ctx->cfglock);
+                       ctx->created_bg = 0;
+                       lock_basic_unlock(&ctx->cfglock);
+                       return r;
+               }
+       } else {
+               lock_basic_unlock(&ctx->cfglock);
+       }
+
+       /* create new ctx_query and attempt to add to the list */
+       q = context_new(ctx, NULL, 0, 0, callback, NULL,
+                       mydata, (const uint8_t*)packet, length);
+       if(!q)
+               return UB_NOMEM;
+
+       /* write over pipe to background worker */
+       lock_basic_lock(&ctx->cfglock);
+       msg = context_serialize_new_query(q, &len);
+       if(!msg) {
+               (void)rbtree_delete(&ctx->queries, q->node.key);
+               ctx->num_async--;
+               context_query_delete(q);
+               lock_basic_unlock(&ctx->cfglock);
+               return UB_NOMEM;
+       }
+       if(async_id)
+               *async_id = q->querynum;
+       lock_basic_unlock(&ctx->cfglock);
+       
+       lock_basic_lock(&ctx->qqpipe_lock);
+       if(!tube_write_msg(ctx->qq_pipe, msg, len, 0)) {
+               lock_basic_unlock(&ctx->qqpipe_lock);
+               free(msg);
+               return UB_PIPE;
+       }
+       lock_basic_unlock(&ctx->qqpipe_lock);
+       free(msg);
+       return UB_NOERROR;
+}
+
+
 int 
 ub_cancel(struct ub_ctx* ctx, int async_id)
 {
index 11bf5f9db555d0f9e69c4547fdd6287fcff24394..5bb13fa677985ec5b1a8c5f25daafdc6d337ecd1 100644 (file)
@@ -596,6 +596,8 @@ setup_qinfo_edns(struct libworker* w, struct ctx_query* q,
        if(!qinfo->qname) {
                return 0;
        }
+       qinfo->qbuf = q->qbuf;
+       qinfo->qbuf_len = q->qbuf_len;
        edns->edns_present = 1;
        edns->ext_rcode = 0;
        edns->edns_version = 0;
index a4529ade52e0a79b462ae9e7104c0f846c48bae2..e4a9e37504bb28684e10a06079f1be6ac7da41df 100644 (file)
@@ -2574,6 +2574,7 @@ serviced_create(struct outside_network* outnet, sldns_buffer* buff, int dnssec,
        int want_dnssec, int nocaps, int tcp_upstream, int ssl_upstream,
        char* tls_auth_name, struct sockaddr_storage* addr, socklen_t addrlen,
        uint8_t* zone, size_t zonelen, int qtype, struct edns_option* opt_list,
+       const uint8_t* raw_qbuf, size_t raw_qbuf_len,
        size_t pad_queries_block_size, struct alloc_cache* alloc,
        struct regional* region)
 {
@@ -2597,6 +2598,8 @@ serviced_create(struct outside_network* outnet, sldns_buffer* buff, int dnssec,
                return NULL;
        }
        sq->qbuflen = sldns_buffer_limit(buff);
+       sq->raw_qbuf = raw_qbuf;
+       sq->raw_qbuf_len = raw_qbuf_len;
        sq->zone = regional_alloc_init(region, zone, zonelen);
        if(!sq->zone) {
                alloc_reg_release(alloc, region);
@@ -2800,6 +2803,13 @@ serviced_encode(struct serviced_query* sq, sldns_buffer* buff, int with_edns)
        if(sq->outnet->use_caps_for_id && !sq->nocaps) {
                serviced_perturb_qname(sq->outnet->rnd, sq->qbuf, sq->qbuflen);
        }
+       if (sq->raw_qbuf) {
+               /* use the raw packet from libunbound's ub_send */
+               sldns_buffer_clear(buff);
+               sldns_buffer_write(buff, sq->raw_qbuf, sq->raw_qbuf_len);
+               sldns_buffer_flip(buff);
+               return;
+       }
        /* generate query */
        sldns_buffer_clear(buff);
        sldns_buffer_write_u16(buff, 0); /* id placeholder */
@@ -3439,6 +3449,7 @@ outnet_serviced_query(struct outside_network* outnet,
                        tcp_upstream, ssl_upstream, tls_auth_name, addr,
                        addrlen, zone, zonelen, (int)qinfo->qtype,
                        per_upstream_opt_list,
+                       qinfo->qbuf, qinfo->qbuf_len,
                        ( ssl_upstream && env->cfg->pad_queries
                        ? env->cfg->pad_queries_block_size : 0 ),
                        env->alloc, region);
index 467c81f60ca2de00657160d39e979ad4ca2a93ea..13d0c03e6238fa95e71594e8803ba212286eca79 100644 (file)
@@ -456,6 +456,10 @@ struct serviced_query {
        uint8_t* qbuf;
        /** length of qbuf. */
        size_t qbuflen;
+       /** raw_qbuf for sending precreated packets */
+       const uint8_t *raw_qbuf;
+       /** Precreated packet length */
+       size_t raw_qbuf_len;
        /** If an EDNS section is included, the DO/CD bit will be turned on. */
        int dnssec;
        /** We want signatures, or else the answer is likely useless */
index 9538adc5a8b2bf7d48b02c72b2c53af14bfa9777..93df8332b569f4d2cb72758002c9218d55800ef7 100644 (file)
@@ -97,6 +97,11 @@ struct query_info {
         * have to be generated if it has to be kept during iterative
         * resolution. */
        struct local_rrset* local_alias;
+
+       /** raw query packet */
+       const uint8_t *qbuf;
+       /** length of raw query packet */
+       size_t qbuf_len;
 };
 
 /**