From: Willem Toorop Date: Sat, 5 Nov 2022 17:50:57 +0000 (+0100) Subject: Plumming for ub_send and ub_send_async X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f3c9be889f17946185918203d586d88ae59e5b5c;p=thirdparty%2Funbound.git Plumming for ub_send and ub_send_async --- diff --git a/libunbound/context.c b/libunbound/context.c index c8d911f13..61b2dd442 100644 --- a/libunbound/context.c +++ b/libunbound/context.c @@ -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); diff --git a/libunbound/context.h b/libunbound/context.h index c0c86fb52..399c1eaef 100644 --- a/libunbound/context.h +++ b/libunbound/context.h @@ -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. diff --git a/libunbound/libunbound.c b/libunbound/libunbound.c index ea5ef24bb..5ce736a67 100644 --- a/libunbound/libunbound.c +++ b/libunbound/libunbound.c @@ -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) { diff --git a/libunbound/libworker.c b/libunbound/libworker.c index 11bf5f9db..5bb13fa67 100644 --- a/libunbound/libworker.c +++ b/libunbound/libworker.c @@ -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; diff --git a/services/outside_network.c b/services/outside_network.c index a4529ade5..e4a9e3750 100644 --- a/services/outside_network.c +++ b/services/outside_network.c @@ -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); diff --git a/services/outside_network.h b/services/outside_network.h index 467c81f60..13d0c03e6 100644 --- a/services/outside_network.h +++ b/services/outside_network.h @@ -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 */ diff --git a/util/data/msgreply.h b/util/data/msgreply.h index 9538adc5a..93df8332b 100644 --- a/util/data/msgreply.h +++ b/util/data/msgreply.h @@ -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; }; /**