mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-08-17 21:25:50 +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/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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
+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 */
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -31,6 +31,8 @@ ub_resolve
|
||||
ub_resolve_async
|
||||
ub_resolve_event
|
||||
ub_resolve_free
|
||||
ub_send
|
||||
ub_send_async
|
||||
ub_strerror
|
||||
ub_version
|
||||
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 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.
|
||||
* 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,
|
||||
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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user