diff options
Diffstat (limited to 'usr.sbin/unbound/libunbound')
-rw-r--r-- | usr.sbin/unbound/libunbound/libworker.c | 202 |
1 files changed, 142 insertions, 60 deletions
diff --git a/usr.sbin/unbound/libunbound/libworker.c b/usr.sbin/unbound/libunbound/libworker.c index 8f2aa489caf..4869f0bc004 100644 --- a/usr.sbin/unbound/libunbound/libworker.c +++ b/usr.sbin/unbound/libunbound/libworker.c @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -42,14 +42,13 @@ * returns from the procedure when done. */ #include "config.h" -#include <ldns/dname.h> -#include <ldns/wire2host.h> #ifdef HAVE_SSL #include <openssl/ssl.h> #endif #include "libunbound/libworker.h" #include "libunbound/context.h" #include "libunbound/unbound.h" +#include "libunbound/unbound-event.h" #include "services/outside_network.h" #include "services/mesh.h" #include "services/localzone.h" @@ -69,21 +68,22 @@ #include "util/tube.h" #include "iterator/iter_fwd.h" #include "iterator/iter_hints.h" +#include "ldns/sbuffer.h" +#include "ldns/str2wire.h" /** handle new query command for bg worker */ static void handle_newq(struct libworker* w, uint8_t* buf, uint32_t len); -/** delete libworker struct */ +/** delete libworker env */ static void -libworker_delete(struct libworker* w) +libworker_delete_env(struct libworker* w) { - if(!w) return; if(w->env) { outside_network_quit_prepare(w->back); mesh_delete(w->env->mesh); context_release_alloc(w->ctx, w->env->alloc, !w->is_bg || w->is_bg_thread); - ldns_buffer_free(w->env->scratch_buffer); + sldns_buffer_free(w->env->scratch_buffer); regional_destroy(w->env->scratch); forwards_delete(w->env->fwds); hints_delete(w->env->hints); @@ -94,13 +94,30 @@ libworker_delete(struct libworker* w) SSL_CTX_free(w->sslctx); #endif outside_network_delete(w->back); +} + +/** delete libworker struct */ +static void +libworker_delete(struct libworker* w) +{ + if(!w) return; + libworker_delete_env(w); comm_base_delete(w->base); free(w); } +void +libworker_delete_event(struct libworker* w) +{ + if(!w) return; + libworker_delete_env(w); + comm_base_delete_no_base(w->base); + free(w); +} + /** setup fresh libworker struct */ static struct libworker* -libworker_setup(struct ub_ctx* ctx, int is_bg) +libworker_setup(struct ub_ctx* ctx, int is_bg, struct event_base* eb) { unsigned int seed; struct libworker* w = (struct libworker*)calloc(1, sizeof(*w)); @@ -127,7 +144,7 @@ libworker_setup(struct ub_ctx* ctx, int is_bg) lock_basic_lock(&ctx->cfglock); } w->env->scratch = regional_create_custom(cfg->msg_buffer_size); - w->env->scratch_buffer = ldns_buffer_new(cfg->msg_buffer_size); + w->env->scratch_buffer = sldns_buffer_new(cfg->msg_buffer_size); w->env->fwds = forwards_create(); if(w->env->fwds && !forwards_apply_cfg(w->env->fwds, cfg)) { forwards_delete(w->env->fwds); @@ -188,7 +205,9 @@ libworker_setup(struct ub_ctx* ctx, int is_bg) } seed = 0; - w->base = comm_base_create(0); + if(eb) + w->base = comm_base_create_event(eb); + else w->base = comm_base_create(0); if(!w->base) { libworker_delete(w); return NULL; @@ -200,8 +219,9 @@ libworker_setup(struct ub_ctx* ctx, int is_bg) if(numports == 0) { int locked = !w->is_bg || w->is_bg_thread; libworker_delete(w); - if(locked) + if(locked) { lock_basic_unlock(&ctx->cfglock); + } return NULL; } w->back = outside_network_create(w->base, cfg->msg_buffer_size, @@ -210,7 +230,8 @@ libworker_setup(struct ub_ctx* ctx, int is_bg) cfg->do_tcp?cfg->outgoing_num_tcp:0, w->env->infra_cache, w->env->rnd, cfg->use_caps_bits_for_id, ports, numports, cfg->unwanted_threshold, - &libworker_alloc_cleanup, w, cfg->do_udp, w->sslctx); + &libworker_alloc_cleanup, w, cfg->do_udp, w->sslctx, + cfg->delay_close); if(!w->is_bg || w->is_bg_thread) { lock_basic_unlock(&ctx->cfglock); } @@ -233,6 +254,12 @@ libworker_setup(struct ub_ctx* ctx, int is_bg) return w; } +struct libworker* libworker_create_event(struct ub_ctx* ctx, + struct event_base* eb) +{ + return libworker_setup(ctx, 0, eb); +} + /** handle cancel command for bg worker */ static void handle_cancel(struct libworker* w, uint8_t* buf, uint32_t len) @@ -349,7 +376,7 @@ int libworker_bg(struct ub_ctx* ctx) lock_basic_lock(&ctx->cfglock); if(ctx->dothread) { lock_basic_unlock(&ctx->cfglock); - w = libworker_setup(ctx, 1); + w = libworker_setup(ctx, 1, NULL); if(!w) return UB_NOMEM; w->is_bg_thread = 1; #ifdef ENABLE_LOCK_CHECKS @@ -364,7 +391,7 @@ int libworker_bg(struct ub_ctx* ctx) #else /* HAVE_FORK */ switch((ctx->bg_pid=fork())) { case 0: - w = libworker_setup(ctx, 1); + w = libworker_setup(ctx, 1, NULL); if(!w) fatal_exit("out of memory"); /* close non-used parts of the pipes */ tube_close_write(ctx->qq_pipe); @@ -389,7 +416,7 @@ int libworker_bg(struct ub_ctx* ctx) /** get msg reply struct (in temp region) */ static struct reply_info* -parse_reply(ldns_buffer* pkt, struct regional* region, struct query_info* qi) +parse_reply(sldns_buffer* pkt, struct regional* region, struct query_info* qi) { struct reply_info* rep; struct msg_parse* msg; @@ -397,7 +424,7 @@ parse_reply(ldns_buffer* pkt, struct regional* region, struct query_info* qi) return NULL; } memset(msg, 0, sizeof(*msg)); - ldns_buffer_set_position(pkt, 0); + sldns_buffer_set_position(pkt, 0); if(parse_packet(pkt, msg, region) != 0) return 0; if(!parse_create_msg(pkt, msg, NULL, qi, &rep, region)) { @@ -473,7 +500,7 @@ fill_res(struct ub_result* res, struct ub_packed_rrset_key* answer, /** fill result from parsed message, on error fills servfail */ void -libworker_enter_result(struct ub_result* res, ldns_buffer* buf, +libworker_enter_result(struct ub_result* res, sldns_buffer* buf, struct regional* temp, enum sec_status msg_security) { struct query_info rq; @@ -501,7 +528,7 @@ libworker_enter_result(struct ub_result* res, ldns_buffer* buf, /** fillup fg results */ static void -libworker_fillup_fg(struct ctx_query* q, int rcode, ldns_buffer* buf, +libworker_fillup_fg(struct ctx_query* q, int rcode, sldns_buffer* buf, enum sec_status s, char* why_bogus) { if(why_bogus) @@ -514,8 +541,8 @@ libworker_fillup_fg(struct ctx_query* q, int rcode, ldns_buffer* buf, q->res->rcode = LDNS_RCODE_SERVFAIL; q->msg_security = 0; - q->msg = memdup(ldns_buffer_begin(buf), ldns_buffer_limit(buf)); - q->msg_len = ldns_buffer_limit(buf); + q->msg = memdup(sldns_buffer_begin(buf), sldns_buffer_limit(buf)); + q->msg_len = sldns_buffer_limit(buf); if(!q->msg) { return; /* the error is in the rcode */ } @@ -526,7 +553,7 @@ libworker_fillup_fg(struct ctx_query* q, int rcode, ldns_buffer* buf, } void -libworker_fg_done_cb(void* arg, int rcode, ldns_buffer* buf, enum sec_status s, +libworker_fg_done_cb(void* arg, int rcode, sldns_buffer* buf, enum sec_status s, char* why_bogus) { struct ctx_query* q = (struct ctx_query*)arg; @@ -541,37 +568,26 @@ static int setup_qinfo_edns(struct libworker* w, struct ctx_query* q, struct query_info* qinfo, struct edns_data* edns) { - ldns_rdf* rdf; qinfo->qtype = (uint16_t)q->res->qtype; qinfo->qclass = (uint16_t)q->res->qclass; - rdf = ldns_dname_new_frm_str(q->res->qname); - if(!rdf) { + qinfo->qname = sldns_str2wire_dname(q->res->qname, &qinfo->qname_len); + if(!qinfo->qname) { return 0; } -#ifdef UNBOUND_ALLOC_LITE - qinfo->qname = memdup(ldns_rdf_data(rdf), ldns_rdf_size(rdf)); - qinfo->qname_len = ldns_rdf_size(rdf); - ldns_rdf_deep_free(rdf); - rdf = 0; -#else - qinfo->qname = ldns_rdf_data(rdf); - qinfo->qname_len = ldns_rdf_size(rdf); -#endif edns->edns_present = 1; edns->ext_rcode = 0; edns->edns_version = 0; edns->bits = EDNS_DO; - if(ldns_buffer_capacity(w->back->udp_buff) < 65535) - edns->udp_size = (uint16_t)ldns_buffer_capacity( + if(sldns_buffer_capacity(w->back->udp_buff) < 65535) + edns->udp_size = (uint16_t)sldns_buffer_capacity( w->back->udp_buff); else edns->udp_size = 65535; - ldns_rdf_free(rdf); return 1; } int libworker_fg(struct ub_ctx* ctx, struct ctx_query* q) { - struct libworker* w = libworker_setup(ctx, 0); + struct libworker* w = libworker_setup(ctx, 0, NULL); uint16_t qflags, qid; struct query_info qinfo; struct edns_data edns; @@ -585,8 +601,8 @@ int libworker_fg(struct ub_ctx* ctx, struct ctx_query* q) qflags = BIT_RD; q->w = w; /* see if there is a fixed answer */ - ldns_buffer_write_u16_at(w->back->udp_buff, 0, qid); - ldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags); + sldns_buffer_write_u16_at(w->back->udp_buff, 0, qid); + sldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags); if(local_zones_answer(ctx->local_zones, &qinfo, &edns, w->back->udp_buff, w->env->scratch)) { regional_free_all(w->env->scratch); @@ -611,9 +627,75 @@ int libworker_fg(struct ub_ctx* ctx, struct ctx_query* q) return UB_NOERROR; } +void +libworker_event_done_cb(void* arg, int rcode, sldns_buffer* buf, + enum sec_status s, char* why_bogus) +{ + struct ctx_query* q = (struct ctx_query*)arg; + ub_event_callback_t cb = (ub_event_callback_t)q->cb; + void* cb_arg = q->cb_arg; + int cancelled = q->cancelled; + + /* delete it now */ + struct ub_ctx* ctx = q->w->ctx; + lock_basic_lock(&ctx->cfglock); + (void)rbtree_delete(&ctx->queries, q->node.key); + ctx->num_async--; + context_query_delete(q); + lock_basic_unlock(&ctx->cfglock); + + if(!cancelled) { + /* call callback */ + int sec = 0; + if(s == sec_status_bogus) + sec = 1; + else if(s == sec_status_secure) + sec = 2; + (*cb)(cb_arg, rcode, (void*)sldns_buffer_begin(buf), + (int)sldns_buffer_limit(buf), sec, why_bogus); + } +} + +int libworker_attach_mesh(struct ub_ctx* ctx, struct ctx_query* q, + int* async_id) +{ + struct libworker* w = ctx->event_worker; + uint16_t qflags, qid; + struct query_info qinfo; + struct edns_data edns; + if(!w) + return UB_INITFAIL; + if(!setup_qinfo_edns(w, q, &qinfo, &edns)) + return UB_SYNTAX; + qid = 0; + qflags = BIT_RD; + q->w = w; + /* see if there is a fixed answer */ + sldns_buffer_write_u16_at(w->back->udp_buff, 0, qid); + sldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags); + if(local_zones_answer(ctx->local_zones, &qinfo, &edns, + w->back->udp_buff, w->env->scratch)) { + regional_free_all(w->env->scratch); + free(qinfo.qname); + libworker_event_done_cb(q, LDNS_RCODE_NOERROR, + w->back->udp_buff, sec_status_insecure, NULL); + return UB_NOERROR; + } + /* process new query */ + if(async_id) + *async_id = q->querynum; + if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns, + w->back->udp_buff, qid, libworker_event_done_cb, q)) { + free(qinfo.qname); + return UB_NOMEM; + } + free(qinfo.qname); + return UB_NOERROR; +} + /** add result to the bg worker result queue */ static void -add_bg_result(struct libworker* w, struct ctx_query* q, ldns_buffer* pkt, +add_bg_result(struct libworker* w, struct ctx_query* q, sldns_buffer* pkt, int err, char* reason) { uint8_t* msg = NULL; @@ -625,8 +707,8 @@ add_bg_result(struct libworker* w, struct ctx_query* q, ldns_buffer* pkt, if(reason) q->res->why_bogus = strdup(reason); if(pkt) { - q->msg_len = ldns_buffer_remaining(pkt); - q->msg = memdup(ldns_buffer_begin(pkt), q->msg_len); + q->msg_len = sldns_buffer_remaining(pkt); + q->msg = memdup(sldns_buffer_begin(pkt), q->msg_len); if(!q->msg) msg = context_serialize_answer(q, UB_NOMEM, NULL, &len); @@ -654,7 +736,7 @@ add_bg_result(struct libworker* w, struct ctx_query* q, ldns_buffer* pkt, } void -libworker_bg_done_cb(void* arg, int rcode, ldns_buffer* buf, enum sec_status s, +libworker_bg_done_cb(void* arg, int rcode, sldns_buffer* buf, enum sec_status s, char* why_bogus) { struct ctx_query* q = (struct ctx_query*)arg; @@ -709,8 +791,8 @@ handle_newq(struct libworker* w, uint8_t* buf, uint32_t len) qid = 0; qflags = BIT_RD; /* see if there is a fixed answer */ - ldns_buffer_write_u16_at(w->back->udp_buff, 0, qid); - ldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags); + sldns_buffer_write_u16_at(w->back->udp_buff, 0, qid); + sldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags); if(local_zones_answer(w->ctx->local_zones, &qinfo, &edns, w->back->udp_buff, w->env->scratch)) { regional_free_all(w->env->scratch); @@ -772,10 +854,10 @@ libworker_handle_reply(struct comm_point* c, void* arg, int error, return 0; } /* sanity check. */ - if(!LDNS_QR_WIRE(ldns_buffer_begin(c->buffer)) - || LDNS_OPCODE_WIRE(ldns_buffer_begin(c->buffer)) != + if(!LDNS_QR_WIRE(sldns_buffer_begin(c->buffer)) + || LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) != LDNS_PACKET_QUERY - || LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) { + || LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) > 1) { /* error becomes timeout for the module as if this reply * never arrived. */ mesh_report_reply(lw->env->mesh, &e, reply_info, @@ -798,10 +880,10 @@ libworker_handle_service_reply(struct comm_point* c, void* arg, int error, return 0; } /* sanity check. */ - if(!LDNS_QR_WIRE(ldns_buffer_begin(c->buffer)) - || LDNS_OPCODE_WIRE(ldns_buffer_begin(c->buffer)) != + if(!LDNS_QR_WIRE(sldns_buffer_begin(c->buffer)) + || LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) != LDNS_PACKET_QUERY - || LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) { + || LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) > 1) { /* error becomes timeout for the module as if this reply * never arrived. */ mesh_report_reply(lw->env->mesh, e, reply_info, |