mirror of https://github.com/getdnsapi/getdns.git
Async stub resolver using crafted packets
This commit is contained in:
parent
8f254913f1
commit
ee316741ac
|
@ -1471,6 +1471,8 @@ cancel_dns_req(getdns_dns_req * req)
|
||||||
ub_cancel(req->context->unbound_ctx,
|
ub_cancel(req->context->unbound_ctx,
|
||||||
netreq->unbound_id);
|
netreq->unbound_id);
|
||||||
netreq->unbound_id = -1;
|
netreq->unbound_id = -1;
|
||||||
|
} else if (netreq->event.ev) {
|
||||||
|
req->loop->vmt->clear(req->loop, &netreq->event);
|
||||||
}
|
}
|
||||||
netreq = netreq->next;
|
netreq = netreq->next;
|
||||||
}
|
}
|
||||||
|
|
166
src/general.c
166
src/general.c
|
@ -44,6 +44,10 @@
|
||||||
#include "types-internal.h"
|
#include "types-internal.h"
|
||||||
#include "util-internal.h"
|
#include "util-internal.h"
|
||||||
#include "dnssec.h"
|
#include "dnssec.h"
|
||||||
|
#include "stub.h"
|
||||||
|
#include "gldns/str2wire.h"
|
||||||
|
#include "gldns/pkthdr.h"
|
||||||
|
|
||||||
|
|
||||||
/* stuff to make it compile pedantically */
|
/* stuff to make it compile pedantically */
|
||||||
#define UNUSED_PARAM(x) ((void)(x))
|
#define UNUSED_PARAM(x) ((void)(x))
|
||||||
|
@ -54,14 +58,6 @@ static void ub_resolve_timeout(void *arg);
|
||||||
|
|
||||||
static void handle_network_request_error(getdns_network_req * netreq, int err);
|
static void handle_network_request_error(getdns_network_req * netreq, int err);
|
||||||
static void handle_dns_request_complete(getdns_dns_req * dns_req);
|
static void handle_dns_request_complete(getdns_dns_req * dns_req);
|
||||||
static int submit_network_request(getdns_network_req * netreq);
|
|
||||||
|
|
||||||
typedef struct netreq_cb_data
|
|
||||||
{
|
|
||||||
getdns_network_req *netreq;
|
|
||||||
int err;
|
|
||||||
struct ub_result* ub_res;
|
|
||||||
} netreq_cb_data;
|
|
||||||
|
|
||||||
/* cancel, cleanup and send timeout to callback */
|
/* cancel, cleanup and send timeout to callback */
|
||||||
static void
|
static void
|
||||||
|
@ -106,18 +102,140 @@ handle_dns_request_complete(getdns_dns_req * dns_req)
|
||||||
dns_req, create_getdns_response(dns_req));
|
dns_req, create_getdns_response(dns_req));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static void
|
||||||
submit_network_request(getdns_network_req * netreq)
|
stub_resolve_timeout_cb(void *userarg)
|
||||||
|
{
|
||||||
|
getdns_network_req *netreq = (getdns_network_req *)userarg;
|
||||||
|
getdns_dns_req *dns_req = netreq->owner;
|
||||||
|
|
||||||
|
(void) getdns_context_request_timed_out(dns_req);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
stub_resolve_read_cb(void *userarg)
|
||||||
|
{
|
||||||
|
getdns_network_req *netreq = (getdns_network_req *)userarg;
|
||||||
|
getdns_dns_req *dns_req = netreq->owner;
|
||||||
|
|
||||||
|
static size_t pkt_buf_len = 4096;
|
||||||
|
size_t pkt_len = pkt_buf_len;
|
||||||
|
uint8_t pkt_buf[pkt_buf_len];
|
||||||
|
uint8_t *pkt = pkt_buf;
|
||||||
|
|
||||||
|
size_t read;
|
||||||
|
|
||||||
|
dns_req->loop->vmt->clear(dns_req->loop, &netreq->event);
|
||||||
|
|
||||||
|
read = recvfrom(netreq->udp_fd, pkt, pkt_len, 0, NULL, NULL);
|
||||||
|
if (read < GLDNS_HEADER_SIZE)
|
||||||
|
return; /* Not DNS */
|
||||||
|
|
||||||
|
if (GLDNS_ID_WIRE(pkt) != netreq->query_id)
|
||||||
|
return; /* Cache poisoning attempt ;) */
|
||||||
|
|
||||||
|
close(netreq->udp_fd);
|
||||||
|
netreq->state = NET_REQ_FINISHED;
|
||||||
|
ldns_wire2pkt(&(netreq->result), pkt, read);
|
||||||
|
|
||||||
|
/* Do the dnssec here */
|
||||||
|
netreq->secure = 0;
|
||||||
|
netreq->bogus = 0;
|
||||||
|
|
||||||
|
netreq = dns_req->first_req;
|
||||||
|
while (netreq) {
|
||||||
|
if (netreq->state != NET_REQ_FINISHED &&
|
||||||
|
netreq->state != NET_REQ_CANCELED)
|
||||||
|
return;
|
||||||
|
netreq = netreq->next;
|
||||||
|
}
|
||||||
|
handle_dns_request_complete(dns_req);
|
||||||
|
}
|
||||||
|
|
||||||
|
static getdns_return_t
|
||||||
|
submit_stub_request(getdns_network_req *netreq)
|
||||||
{
|
{
|
||||||
getdns_dns_req *dns_req = netreq->owner;
|
getdns_dns_req *dns_req = netreq->owner;
|
||||||
int r = ub_resolve_async(dns_req->context->unbound_ctx,
|
static size_t pkt_buf_len = 4096;
|
||||||
dns_req->name,
|
size_t pkt_len = pkt_buf_len;
|
||||||
netreq->request_type,
|
uint8_t pkt_buf[pkt_buf_len];
|
||||||
netreq->request_class,
|
uint8_t *pkt = pkt_buf;
|
||||||
netreq,
|
int s;
|
||||||
ub_resolve_callback,
|
struct getdns_upstream *upstream;
|
||||||
&(netreq->unbound_id));
|
ssize_t sent;
|
||||||
return r;
|
|
||||||
|
s = getdns_make_query_pkt_buf(dns_req->context, dns_req->name,
|
||||||
|
netreq->request_type, dns_req->extensions, pkt_buf, &pkt_len);
|
||||||
|
if (s == GLDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL) {
|
||||||
|
/* TODO: Allocate 64K and retry */
|
||||||
|
return GETDNS_RETURN_GENERIC_ERROR;
|
||||||
|
} else if (s)
|
||||||
|
return GETDNS_RETURN_GENERIC_ERROR;
|
||||||
|
|
||||||
|
netreq->query_id = ldns_get_random();
|
||||||
|
GLDNS_ID_SET(pkt, netreq->query_id);
|
||||||
|
|
||||||
|
upstream = &dns_req->upstreams->upstreams[dns_req->ns_index];
|
||||||
|
|
||||||
|
/* TODO: TCP */
|
||||||
|
if (dns_req->context->dns_transport != GETDNS_TRANSPORT_UDP_ONLY &&
|
||||||
|
dns_req->context->dns_transport !=
|
||||||
|
GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP)
|
||||||
|
return GETDNS_RETURN_GENERIC_ERROR;
|
||||||
|
|
||||||
|
if ((netreq->udp_fd = socket(
|
||||||
|
upstream->addr.ss_family, SOCK_DGRAM, IPPROTO_UDP)) == -1)
|
||||||
|
return GETDNS_RETURN_GENERIC_ERROR;
|
||||||
|
|
||||||
|
sent = sendto(netreq->udp_fd, pkt, pkt_len, 0,
|
||||||
|
(struct sockaddr *)&upstream->addr, upstream->addr_len);
|
||||||
|
if (sent != pkt_len) {
|
||||||
|
close(netreq->udp_fd);
|
||||||
|
return GETDNS_RETURN_GENERIC_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
netreq->event.userarg = netreq;
|
||||||
|
netreq->event.read_cb = stub_resolve_read_cb;
|
||||||
|
netreq->event.write_cb = NULL;
|
||||||
|
netreq->event.timeout_cb = stub_resolve_timeout_cb;
|
||||||
|
netreq->event.ev = NULL;
|
||||||
|
dns_req->loop->vmt->schedule(dns_req->loop,
|
||||||
|
netreq->udp_fd, dns_req->context->timeout, &netreq->event);
|
||||||
|
|
||||||
|
if (s == GLDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL) {
|
||||||
|
/* TODO: Free the 64K allocated buffer */
|
||||||
|
}
|
||||||
|
return GETDNS_RETURN_GOOD;
|
||||||
|
}
|
||||||
|
|
||||||
|
static getdns_return_t
|
||||||
|
submit_network_request(getdns_network_req *netreq)
|
||||||
|
{
|
||||||
|
getdns_return_t r;
|
||||||
|
getdns_dns_req *dns_req = netreq->owner;
|
||||||
|
|
||||||
|
if (dns_req->context->resolution_type == GETDNS_RESOLUTION_RECURSING ||
|
||||||
|
dns_req->context->dns_transport == GETDNS_TRANSPORT_TCP_ONLY ||
|
||||||
|
dns_req->context->dns_transport == GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN) {
|
||||||
|
|
||||||
|
/* schedule the timeout */
|
||||||
|
if (! dns_req->timeout.timeout_cb) {
|
||||||
|
dns_req->timeout.userarg = dns_req;
|
||||||
|
dns_req->timeout.read_cb = NULL;
|
||||||
|
dns_req->timeout.write_cb = NULL;
|
||||||
|
dns_req->timeout.timeout_cb = ub_resolve_timeout;
|
||||||
|
dns_req->timeout.ev = NULL;
|
||||||
|
if ((r = dns_req->loop->vmt->schedule(dns_req->loop, -1,
|
||||||
|
dns_req->context->timeout, &dns_req->timeout)))
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ub_resolve_async(dns_req->context->unbound_ctx,
|
||||||
|
dns_req->name, netreq->request_type, netreq->request_class,
|
||||||
|
netreq, ub_resolve_callback, &(netreq->unbound_id)) ?
|
||||||
|
GETDNS_RETURN_GENERIC_ERROR : GETDNS_RETURN_GOOD;
|
||||||
|
}
|
||||||
|
/* Submit with stub resolver */
|
||||||
|
return submit_stub_request(netreq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -189,18 +307,6 @@ getdns_general_ns(getdns_context *context, getdns_eventloop *loop,
|
||||||
|
|
||||||
getdns_context_track_outbound_request(req);
|
getdns_context_track_outbound_request(req);
|
||||||
|
|
||||||
if (1 || context->resolution_type == GETDNS_RESOLUTION_RECURSING) {
|
|
||||||
/* schedule the timeout */
|
|
||||||
req->timeout.userarg = req;
|
|
||||||
req->timeout.read_cb = NULL;
|
|
||||||
req->timeout.write_cb = NULL;
|
|
||||||
req->timeout.timeout_cb = ub_resolve_timeout;
|
|
||||||
req->timeout.ev = NULL;
|
|
||||||
if ((r = loop->vmt->schedule(
|
|
||||||
loop, -1, context->timeout, &req->timeout)))
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!usenamespaces)
|
if (!usenamespaces)
|
||||||
/* issue all network requests */
|
/* issue all network requests */
|
||||||
for (netreq = req->first_req; !r && netreq; netreq = netreq->next)
|
for (netreq = req->first_req; !r && netreq; netreq = netreq->next)
|
||||||
|
|
|
@ -72,6 +72,10 @@ network_req_new(getdns_dns_req * owner,
|
||||||
|
|
||||||
/* TODO: records and other extensions */
|
/* TODO: records and other extensions */
|
||||||
|
|
||||||
|
net_req->query_id = -1;
|
||||||
|
net_req->udp_fd = -1;
|
||||||
|
memset(&net_req->event, 0, sizeof(net_req->event));
|
||||||
|
|
||||||
return net_req;
|
return net_req;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,6 +90,9 @@ dns_req_free(getdns_dns_req * req)
|
||||||
/* free extensions */
|
/* free extensions */
|
||||||
getdns_dict_destroy(req->extensions);
|
getdns_dict_destroy(req->extensions);
|
||||||
|
|
||||||
|
if (req->upstreams && --req->upstreams->referenced == 0)
|
||||||
|
GETDNS_FREE(req->upstreams->mf, req->upstreams);
|
||||||
|
|
||||||
/* free network requests */
|
/* free network requests */
|
||||||
net_req = req->first_req;
|
net_req = req->first_req;
|
||||||
while (net_req) {
|
while (net_req) {
|
||||||
|
@ -125,8 +132,7 @@ dns_req_new(struct getdns_context *context, getdns_eventloop *loop,
|
||||||
result->canceled = 0;
|
result->canceled = 0;
|
||||||
result->current_req = NULL;
|
result->current_req = NULL;
|
||||||
result->first_req = NULL;
|
result->first_req = NULL;
|
||||||
result->trans_id = ((uint64_t) ldns_get_random())
|
result->trans_id = (uint64_t)(((intptr_t) result) ^ ldns_get_random());
|
||||||
^ ((intptr_t) result);
|
|
||||||
|
|
||||||
getdns_dict_copy(extensions, &result->extensions);
|
getdns_dict_copy(extensions, &result->extensions);
|
||||||
result->return_dnssec_status = context->return_dnssec_status;
|
result->return_dnssec_status = context->return_dnssec_status;
|
||||||
|
@ -139,6 +145,11 @@ dns_req_new(struct getdns_context *context, getdns_eventloop *loop,
|
||||||
/* check the specify_class extension */
|
/* check the specify_class extension */
|
||||||
(void) getdns_dict_get_int(extensions, "specify_class", &klass);
|
(void) getdns_dict_get_int(extensions, "specify_class", &klass);
|
||||||
|
|
||||||
|
result->upstreams = context->upstreams;
|
||||||
|
if (result->upstreams)
|
||||||
|
result->upstreams->referenced++;
|
||||||
|
result->ns_index = 0;
|
||||||
|
|
||||||
/* create the requests */
|
/* create the requests */
|
||||||
req = network_req_new(result, request_type, klass, extensions);
|
req = network_req_new(result, request_type, klass, extensions);
|
||||||
if (!req) {
|
if (!req) {
|
||||||
|
|
173
src/stub.c
173
src/stub.c
|
@ -39,179 +39,6 @@
|
||||||
#include "context.h"
|
#include "context.h"
|
||||||
#include <ldns/util.h>
|
#include <ldns/util.h>
|
||||||
#include "util-internal.h"
|
#include "util-internal.h"
|
||||||
#include "gldns/gbuffer.h"
|
|
||||||
#include "gldns/wire2str.h"
|
|
||||||
#include "extension/libmini_event.h"
|
|
||||||
|
|
||||||
#define STUBDEBUG 1
|
|
||||||
|
|
||||||
typedef struct stub_resolver {
|
|
||||||
getdns_eventloop *ext;
|
|
||||||
getdns_context *context;
|
|
||||||
getdns_upstreams *upstreams;
|
|
||||||
const char *name;
|
|
||||||
uint16_t request_type;
|
|
||||||
getdns_dict *extensions;
|
|
||||||
gldns_buffer *response;
|
|
||||||
|
|
||||||
|
|
||||||
size_t request_pkt_len;
|
|
||||||
uint8_t *request_pkt;
|
|
||||||
|
|
||||||
size_t ns_index;
|
|
||||||
size_t to_retry;
|
|
||||||
int udp_fd;
|
|
||||||
|
|
||||||
getdns_eventloop_event event;
|
|
||||||
} stub_resolver;
|
|
||||||
|
|
||||||
static void
|
|
||||||
udp_request_timeout_cb(void *arg)
|
|
||||||
{
|
|
||||||
stub_resolver *resolver = (stub_resolver *)arg;
|
|
||||||
resolver->ext->vmt->clear(resolver->ext, &resolver->event);
|
|
||||||
fprintf(stderr, "TIMEOUT!\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
udp_request_read_cb(void *arg)
|
|
||||||
{
|
|
||||||
stub_resolver *resolver = (stub_resolver *)arg;
|
|
||||||
ssize_t read;
|
|
||||||
|
|
||||||
resolver->ext->vmt->clear(resolver->ext, &resolver->event);
|
|
||||||
|
|
||||||
read = recvfrom(resolver->udp_fd,
|
|
||||||
gldns_buffer_current(resolver->response),
|
|
||||||
gldns_buffer_remaining(resolver->response),
|
|
||||||
0, NULL, NULL);
|
|
||||||
|
|
||||||
if (read == -1 || read == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
gldns_buffer_skip(resolver->response, read);
|
|
||||||
gldns_buffer_flip(resolver->response);
|
|
||||||
#if STUBDEBUG
|
|
||||||
do {
|
|
||||||
char *str = gldns_wire2str_pkt(
|
|
||||||
gldns_buffer_current(resolver->response),
|
|
||||||
gldns_buffer_limit(resolver->response));
|
|
||||||
fprintf(stderr, "%s\n", str);
|
|
||||||
free(str);
|
|
||||||
} while(0);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static getdns_return_t
|
|
||||||
query_ns(stub_resolver *resolver)
|
|
||||||
{
|
|
||||||
struct getdns_upstream *upstream;
|
|
||||||
ssize_t sent;
|
|
||||||
|
|
||||||
assert(resolver);
|
|
||||||
|
|
||||||
if (resolver->ns_index >= resolver->upstreams->count)
|
|
||||||
return GETDNS_RETURN_GENERIC_ERROR;
|
|
||||||
|
|
||||||
upstream = &resolver->upstreams->upstreams[resolver->ns_index];
|
|
||||||
/* TODO: Try next upstream if something is not right with this one
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* TODO: Check how to connect first (udp or tcp) */
|
|
||||||
if (resolver->context->dns_transport != GETDNS_TRANSPORT_UDP_ONLY &&
|
|
||||||
resolver->context->dns_transport !=
|
|
||||||
GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP)
|
|
||||||
return GETDNS_RETURN_GENERIC_ERROR;
|
|
||||||
|
|
||||||
resolver->udp_fd = socket(upstream->addr.ss_family, SOCK_DGRAM,
|
|
||||||
IPPROTO_UDP);
|
|
||||||
if (resolver->udp_fd == -1) {
|
|
||||||
/* Retry with tcp? */
|
|
||||||
return GETDNS_RETURN_GENERIC_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
sent = sendto(resolver->udp_fd,
|
|
||||||
resolver->request_pkt, resolver->request_pkt_len, 0,
|
|
||||||
(struct sockaddr *)&upstream->addr, upstream->addr_len);
|
|
||||||
if (sent == -1 || sent != resolver->request_pkt_len)
|
|
||||||
return GETDNS_RETURN_GENERIC_ERROR;
|
|
||||||
|
|
||||||
resolver->event.userarg = resolver;
|
|
||||||
resolver->event.read_cb = udp_request_read_cb;
|
|
||||||
resolver->event.write_cb = NULL;
|
|
||||||
resolver->event.timeout_cb = udp_request_timeout_cb;
|
|
||||||
resolver->ext->vmt->schedule(resolver->ext, resolver->udp_fd,
|
|
||||||
resolver->context->timeout, &resolver->event);
|
|
||||||
|
|
||||||
return GETDNS_RETURN_GOOD;
|
|
||||||
}
|
|
||||||
|
|
||||||
getdns_return_t
|
|
||||||
getdns_stub_dns_query_async(struct getdns_eventloop *ext,
|
|
||||||
getdns_context *context, const char *name, uint16_t request_type,
|
|
||||||
getdns_dict *extensions, gldns_buffer *response)
|
|
||||||
{
|
|
||||||
getdns_return_t r;
|
|
||||||
stub_resolver *resolver;
|
|
||||||
|
|
||||||
resolver = GETDNS_MALLOC(context->mf, stub_resolver);
|
|
||||||
if (! resolver)
|
|
||||||
return GETDNS_RETURN_MEMORY_ERROR;
|
|
||||||
|
|
||||||
resolver->ext = ext;
|
|
||||||
resolver->context = context;
|
|
||||||
resolver->upstreams = context->upstreams;
|
|
||||||
resolver->upstreams->referenced++;
|
|
||||||
resolver->name = name;
|
|
||||||
resolver->request_type = request_type;
|
|
||||||
resolver->extensions = extensions;
|
|
||||||
resolver->response = response;
|
|
||||||
resolver->request_pkt = getdns_make_query_pkt(context,
|
|
||||||
name, request_type, extensions, &resolver->request_pkt_len);
|
|
||||||
if (! resolver->request_pkt) {
|
|
||||||
GETDNS_FREE(context->mf, resolver);
|
|
||||||
return GETDNS_RETURN_GENERIC_ERROR;
|
|
||||||
}
|
|
||||||
#if STUBDEBUG
|
|
||||||
do {
|
|
||||||
char *str = gldns_wire2str_pkt(
|
|
||||||
resolver->request_pkt, resolver->request_pkt_len);
|
|
||||||
fprintf(stderr, "%s\n", str);
|
|
||||||
free(str);
|
|
||||||
} while(0);
|
|
||||||
#endif
|
|
||||||
resolver->ns_index = 0;
|
|
||||||
resolver->to_retry = 2;
|
|
||||||
r = query_ns(resolver);
|
|
||||||
if (r) {
|
|
||||||
if (--resolver->upstreams->referenced == 0)
|
|
||||||
GETDNS_FREE(resolver->upstreams->mf, resolver->upstreams);
|
|
||||||
GETDNS_FREE(context->mf, resolver);
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
getdns_return_t
|
|
||||||
getdns_stub_dns_query_sync(
|
|
||||||
getdns_context *context, const char *name, uint16_t request_type,
|
|
||||||
getdns_dict *extensions, gldns_buffer *response)
|
|
||||||
{
|
|
||||||
getdns_return_t r;
|
|
||||||
getdns_mini_event mini_event;
|
|
||||||
getdns_eventloop *ext = &mini_event.loop;
|
|
||||||
|
|
||||||
r = getdns_mini_event_init(context, &mini_event);
|
|
||||||
if (r)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
r = getdns_stub_dns_query_async(ext, context, name, request_type,
|
|
||||||
extensions, response);
|
|
||||||
if (r)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
ext->vmt->run(ext);
|
|
||||||
return GETDNS_RETURN_GOOD;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
getdns_make_query_pkt_buf(getdns_context *context, const char *name,
|
getdns_make_query_pkt_buf(getdns_context *context, const char *name,
|
||||||
|
|
|
@ -41,6 +41,8 @@
|
||||||
#include "getdns/getdns.h"
|
#include "getdns/getdns.h"
|
||||||
#include "getdns/getdns_extra.h"
|
#include "getdns/getdns_extra.h"
|
||||||
struct getdns_context;
|
struct getdns_context;
|
||||||
|
typedef struct getdns_upstreams getdns_upstreams;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \defgroup strings String Constants
|
* \defgroup strings String Constants
|
||||||
|
@ -170,6 +172,12 @@ typedef struct getdns_network_req
|
||||||
|
|
||||||
/* next request to issue after this one */
|
/* next request to issue after this one */
|
||||||
struct getdns_network_req *next;
|
struct getdns_network_req *next;
|
||||||
|
|
||||||
|
/* For stub resolving */
|
||||||
|
int udp_fd;
|
||||||
|
uint16_t query_id;
|
||||||
|
getdns_eventloop_event event;
|
||||||
|
|
||||||
} getdns_network_req;
|
} getdns_network_req;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -215,6 +223,10 @@ typedef struct getdns_dns_req
|
||||||
/* mem funcs */
|
/* mem funcs */
|
||||||
struct mem_funcs my_mf;
|
struct mem_funcs my_mf;
|
||||||
|
|
||||||
|
/* Stuff for stub resolving */
|
||||||
|
getdns_upstreams *upstreams;
|
||||||
|
size_t ns_index;
|
||||||
|
|
||||||
} getdns_dns_req;
|
} getdns_dns_req;
|
||||||
|
|
||||||
#define GETDNS_XMALLOC(obj, type, count) \
|
#define GETDNS_XMALLOC(obj, type, count) \
|
||||||
|
|
Loading…
Reference in New Issue