mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-10-17 14:05:12 +02:00
Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4014e2aec4 | ||
|
|
f3c9be889f | ||
|
|
cd3ebb7e72 |
+36
-1
@@ -53,6 +53,7 @@
|
|||||||
#include "util/storage/slabhash.h"
|
#include "util/storage/slabhash.h"
|
||||||
#include "util/edns.h"
|
#include "util/edns.h"
|
||||||
#include "sldns/sbuffer.h"
|
#include "sldns/sbuffer.h"
|
||||||
|
#include "sldns/wire2str.h"
|
||||||
|
|
||||||
int
|
int
|
||||||
context_finalize(struct ub_ctx* ctx)
|
context_finalize(struct ub_ctx* ctx)
|
||||||
@@ -144,9 +145,17 @@ find_id(struct ub_ctx* ctx, int* id)
|
|||||||
|
|
||||||
struct ctx_query*
|
struct ctx_query*
|
||||||
context_new(struct ub_ctx* ctx, const char* name, int rrtype, int rrclass,
|
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));
|
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;
|
if(!q) return NULL;
|
||||||
lock_basic_lock(&ctx->cfglock);
|
lock_basic_lock(&ctx->cfglock);
|
||||||
if(!find_id(ctx, &q->querynum)) {
|
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);
|
free(q);
|
||||||
return NULL;
|
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);
|
q->res->qname = strdup(name);
|
||||||
if(!q->res->qname) {
|
if(!q->res->qname) {
|
||||||
free(q->res);
|
free(q->res);
|
||||||
|
|||||||
@@ -171,6 +171,11 @@ struct ctx_query {
|
|||||||
/** store libworker that is handling this query */
|
/** store libworker that is handling this query */
|
||||||
struct libworker* w;
|
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.
|
/** result structure, also contains original query, type, class.
|
||||||
* malloced ptr ready to hand to the client. */
|
* malloced ptr ready to hand to the client. */
|
||||||
struct ub_result* res;
|
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,
|
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,
|
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.
|
* Get a new alloc. Creates a new one or uses a cached one.
|
||||||
|
|||||||
+116
-3
@@ -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 */
|
/* create new ctx_query and attempt to add to the list */
|
||||||
lock_basic_unlock(&ctx->cfglock);
|
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)
|
if(!q)
|
||||||
return UB_NOMEM;
|
return UB_NOMEM;
|
||||||
/* become a resolver thread for a bit */
|
/* 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);
|
ub_comm_base_now(ctx->event_worker->base);
|
||||||
|
|
||||||
/* create new ctx_query and attempt to add to the list */
|
/* 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)
|
if(!q)
|
||||||
return UB_NOMEM;
|
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 */
|
/* 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)
|
if(!q)
|
||||||
return UB_NOMEM;
|
return UB_NOMEM;
|
||||||
|
|
||||||
@@ -845,6 +848,116 @@ ub_resolve_async(struct ub_ctx* ctx, const char* name, int rrtype,
|
|||||||
return UB_NOERROR;
|
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
|
int
|
||||||
ub_cancel(struct ub_ctx* ctx, int async_id)
|
ub_cancel(struct ub_ctx* ctx, int async_id)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -596,6 +596,8 @@ setup_qinfo_edns(struct libworker* w, struct ctx_query* q,
|
|||||||
if(!qinfo->qname) {
|
if(!qinfo->qname) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
qinfo->qbuf = q->qbuf;
|
||||||
|
qinfo->qbuf_len = q->qbuf_len;
|
||||||
edns->edns_present = 1;
|
edns->edns_present = 1;
|
||||||
edns->ext_rcode = 0;
|
edns->ext_rcode = 0;
|
||||||
edns->edns_version = 0;
|
edns->edns_version = 0;
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ ub_resolve
|
|||||||
ub_resolve_async
|
ub_resolve_async
|
||||||
ub_resolve_event
|
ub_resolve_event
|
||||||
ub_resolve_free
|
ub_resolve_free
|
||||||
|
ub_send
|
||||||
|
ub_send_async
|
||||||
ub_strerror
|
ub_strerror
|
||||||
ub_version
|
ub_version
|
||||||
ub_wait
|
ub_wait
|
||||||
|
|||||||
@@ -568,6 +568,50 @@ int ub_resolve(struct ub_ctx* ctx, const char* name, int rrtype,
|
|||||||
int ub_resolve_async(struct ub_ctx* ctx, const char* name, int rrtype,
|
int ub_resolve_async(struct ub_ctx* ctx, const char* name, int rrtype,
|
||||||
int rrclass, void* mydata, ub_callback_type callback, int* async_id);
|
int rrclass, void* mydata, ub_callback_type callback, int* async_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transmit a wire-encoded query packet directly to a nameserver.
|
||||||
|
* @param ctx: context.
|
||||||
|
* The context is finalized, and can no longer accept config changes.
|
||||||
|
* @param packet: wire-encoded query packet.
|
||||||
|
* @param length: length of encoded query packet.
|
||||||
|
* @param result: the reply packet, together with its validation status,
|
||||||
|
* is returned in a newly allocated result structure.
|
||||||
|
* May be NULL on return, in which case an error code is returned.
|
||||||
|
* @return 0 if OK, else error.
|
||||||
|
*/
|
||||||
|
int ub_send(struct ub_ctx* ctx, const char* packet, int length,
|
||||||
|
struct ub_result** result);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transmit a wire-encoded query packet directly to a nameserver.
|
||||||
|
* Asynchronous, after a while, the callback will be called with your
|
||||||
|
* data and the result.
|
||||||
|
* @param ctx: context.
|
||||||
|
* If no thread or process has been created yet to perform the
|
||||||
|
* work in the background, it is created now.
|
||||||
|
* The context is finalized, and can no longer accept config changes.
|
||||||
|
* @param packet: wire-encoded query packet.
|
||||||
|
* @param length: length of encoded query packet.
|
||||||
|
* @param mydata: this data is your own data (you can pass NULL),
|
||||||
|
* and is passed on to the callback function.
|
||||||
|
* @param callback: this is called on completion of the resolution.
|
||||||
|
* It is called as:
|
||||||
|
* void callback(void* mydata, int err, struct ub_result* result)
|
||||||
|
* with mydata: the same as passed here, you may pass NULL,
|
||||||
|
* with err: is 0 when a result has been found.
|
||||||
|
* with result: a newly allocated result structure.
|
||||||
|
* The result may be NULL, in that case err is set.
|
||||||
|
*
|
||||||
|
* If an error happens during processing, your callback will be called
|
||||||
|
* with error set to a nonzero value (and result==NULL).
|
||||||
|
* @param async_id: if you pass a non-NULL value, an identifier number is
|
||||||
|
* returned for the query as it is in progress. It can be used to
|
||||||
|
* cancel the query.
|
||||||
|
* @return 0 if OK, else error.
|
||||||
|
*/
|
||||||
|
int ub_send_async(struct ub_ctx* ctx, const char* packet, int length,
|
||||||
|
void* mydata, ub_callback_type callback, int* async_id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancel an async query in progress.
|
* Cancel an async query in progress.
|
||||||
* Its callback will not be called.
|
* Its callback will not be called.
|
||||||
|
|||||||
@@ -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,
|
int want_dnssec, int nocaps, int tcp_upstream, int ssl_upstream,
|
||||||
char* tls_auth_name, struct sockaddr_storage* addr, socklen_t addrlen,
|
char* tls_auth_name, struct sockaddr_storage* addr, socklen_t addrlen,
|
||||||
uint8_t* zone, size_t zonelen, int qtype, struct edns_option* opt_list,
|
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,
|
size_t pad_queries_block_size, struct alloc_cache* alloc,
|
||||||
struct regional* region)
|
struct regional* region)
|
||||||
{
|
{
|
||||||
@@ -2597,6 +2598,8 @@ serviced_create(struct outside_network* outnet, sldns_buffer* buff, int dnssec,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
sq->qbuflen = sldns_buffer_limit(buff);
|
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);
|
sq->zone = regional_alloc_init(region, zone, zonelen);
|
||||||
if(!sq->zone) {
|
if(!sq->zone) {
|
||||||
alloc_reg_release(alloc, region);
|
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) {
|
if(sq->outnet->use_caps_for_id && !sq->nocaps) {
|
||||||
serviced_perturb_qname(sq->outnet->rnd, sq->qbuf, sq->qbuflen);
|
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 */
|
/* generate query */
|
||||||
sldns_buffer_clear(buff);
|
sldns_buffer_clear(buff);
|
||||||
sldns_buffer_write_u16(buff, 0); /* id placeholder */
|
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,
|
tcp_upstream, ssl_upstream, tls_auth_name, addr,
|
||||||
addrlen, zone, zonelen, (int)qinfo->qtype,
|
addrlen, zone, zonelen, (int)qinfo->qtype,
|
||||||
per_upstream_opt_list,
|
per_upstream_opt_list,
|
||||||
|
qinfo->qbuf, qinfo->qbuf_len,
|
||||||
( ssl_upstream && env->cfg->pad_queries
|
( ssl_upstream && env->cfg->pad_queries
|
||||||
? env->cfg->pad_queries_block_size : 0 ),
|
? env->cfg->pad_queries_block_size : 0 ),
|
||||||
env->alloc, region);
|
env->alloc, region);
|
||||||
|
|||||||
@@ -456,6 +456,10 @@ struct serviced_query {
|
|||||||
uint8_t* qbuf;
|
uint8_t* qbuf;
|
||||||
/** length of qbuf. */
|
/** length of qbuf. */
|
||||||
size_t qbuflen;
|
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. */
|
/** If an EDNS section is included, the DO/CD bit will be turned on. */
|
||||||
int dnssec;
|
int dnssec;
|
||||||
/** We want signatures, or else the answer is likely useless */
|
/** We want signatures, or else the answer is likely useless */
|
||||||
|
|||||||
@@ -97,6 +97,11 @@ struct query_info {
|
|||||||
* have to be generated if it has to be kept during iterative
|
* have to be generated if it has to be kept during iterative
|
||||||
* resolution. */
|
* resolution. */
|
||||||
struct local_rrset* local_alias;
|
struct local_rrset* local_alias;
|
||||||
|
|
||||||
|
/** raw query packet */
|
||||||
|
const uint8_t *qbuf;
|
||||||
|
/** length of raw query packet */
|
||||||
|
size_t qbuf_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user