#include "util/storage/slabhash.h"
#include "util/edns.h"
#include "sldns/sbuffer.h"
+#include "sldns/wire2str.h"
int
context_finalize(struct ub_ctx* ctx)
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)) {
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);
}
/* 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 */
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;
}
/* 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;
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)
{
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)
{
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);
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 */
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);