Parse /etc/resolv.conf ourselves

At the ame time IPv6 local-link scope_id support
This commit is contained in:
Willem Toorop 2014-09-30 15:12:48 +02:00
parent ad127c9e56
commit 1c6ce72f74
5 changed files with 271 additions and 247 deletions

View File

@ -62,7 +62,7 @@ srcdir = @srcdir@
VPATH = @srcdir@
CC=@CC@
CFLAGS=@CFLAGS@ -Wall -I$(srcdir) -I. -std=c99
CFLAGS=@CFLAGS@ -Wall -I$(srcdir) -I. -std=c99 -D_POSIX_C_SOURCE=200112L
LDFLAGS=@LDFLAGS@ @LIBS@
EXTENSION_LIBEVENT_LIB=@EXTENSION_LIBEVENT_LIB@

View File

@ -43,6 +43,7 @@
#include <sys/time.h>
#include <unbound.h>
#include <assert.h>
#include <netdb.h>
#include "config.h"
#include "context.h"
@ -63,10 +64,6 @@ getdns_return_t create_local_hosts(struct getdns_context *context);
getdns_return_t destroy_local_hosts(struct getdns_context *context);
static struct getdns_list *create_default_root_servers(void);
static getdns_return_t add_ip_str(struct getdns_dict *);
static struct getdns_dict *create_ipaddr_dict_from_rdf(struct getdns_context *,
ldns_rdf *);
static struct getdns_list *create_from_ldns_list(struct getdns_context *,
ldns_rdf **, size_t);
static getdns_return_t set_os_defaults(struct getdns_context *);
static int transaction_id_cmp(const void *, const void *);
static int timeout_cmp(const void *, const void *);
@ -92,7 +89,7 @@ static getdns_return_t set_ldns_dns_transport(struct getdns_context* context,
static void set_ldns_edns_maximum_udp_payload_size(struct getdns_context*,
uint16_t);
static getdns_return_t set_ldns_nameservers(struct getdns_context*,
struct getdns_list * upstreams);
getdns_upstreams *upstreams);
/* Stuff to make it compile pedantically */
#define RETURN_IF_NULL(ptr, code) if(ptr == NULL) return code;
@ -295,65 +292,53 @@ filechg_check(struct getdns_context *context, struct filechg *fchg)
return fchg->changes;
} /* filechg */
static struct getdns_dict *
create_ipaddr_dict_from_rdf(struct getdns_context *context, ldns_rdf * rdf)
static size_t
upstream_addr_len(struct getdns_upstream *upstream)
{
ldns_rdf_type rt = ldns_rdf_get_type(rdf);
size_t sz = ldns_rdf_size(rdf);
struct getdns_dict *result = getdns_dict_create_with_context(context);
/* set type */
if (rt == LDNS_RDF_TYPE_A) {
getdns_dict_util_set_string(result, GETDNS_STR_ADDRESS_TYPE,
GETDNS_STR_IPV4);
} else {
getdns_dict_util_set_string(result, GETDNS_STR_ADDRESS_TYPE,
GETDNS_STR_IPV6);
}
/* set data */
struct getdns_bindata data_bin = { sz, ldns_rdf_data(rdf) };
getdns_dict_set_bindata(result, GETDNS_STR_ADDRESS_DATA, &data_bin);
add_ip_str(result);
return result;
return upstream->addr.ss_family == AF_INET ? 4 : 16;
}
static struct getdns_list *
create_from_ldns_list(struct getdns_context *context, ldns_rdf ** ldns_list,
size_t count)
static uint8_t*
upstream_addr(struct getdns_upstream *upstream)
{
size_t i = 0;
size_t idx = 0;
struct getdns_list *result = getdns_list_create_with_context(context);
for (i = 0; i < count; ++i) {
ldns_rdf *rdf = ldns_list[i];
switch (ldns_rdf_get_type(rdf)) {
case LDNS_RDF_TYPE_A:
case LDNS_RDF_TYPE_AAAA:
{
struct getdns_dict *ipaddr =
create_ipaddr_dict_from_rdf(context, rdf);
getdns_list_add_item(result, &idx);
getdns_list_set_dict(result, idx, ipaddr);
getdns_dict_destroy(ipaddr);
}
break;
return upstream->addr.ss_family == AF_INET
? (void *)&((struct sockaddr_in*)&upstream->addr)->sin_addr
: (void *)&((struct sockaddr_in6*)&upstream->addr)->sin6_addr;
}
case LDNS_RDF_TYPE_DNAME:
{
struct getdns_bindata item;
char *srch = ldns_rdf2str(rdf);
item.size = strlen(srch) + 1;
item.data = (uint8_t *) srch;
getdns_list_add_item(result, &idx);
getdns_list_set_bindata(result, idx, &item);
free(srch);
}
break;
static in_port_t
upstream_port(struct getdns_upstream *upstream)
{
return ntohs(upstream->addr.ss_family == AF_INET
? ((struct sockaddr_in *)&upstream->addr)->sin_port
: ((struct sockaddr_in6*)&upstream->addr)->sin6_port);
}
default:
break;
}
}
return result;
static uint32_t *
upstream_scope_id(struct getdns_upstream *upstream)
{
return upstream->addr.ss_family == AF_INET ? NULL
: (upstream_addr(upstream)[0] == 0xFE &&
(upstream_addr(upstream)[1] & 0xC0) == 0x80 ?
&((struct sockaddr_in6*)&upstream->addr)->sin6_scope_id : NULL);
}
void
upstream_ntop_buf(struct getdns_upstream *upstream, char *buf, size_t len)
{
/* Also possible but prints scope_id by name (nor parsed by unbound)
*
* getnameinfo((struct sockaddr *)&upstream->addr, upstream->addr_len,
* buf, len, NULL, 0, NI_NUMERICHOST)
*/
(void) inet_ntop(upstream->addr.ss_family, upstream_addr(upstream),
buf, len);
if (upstream_scope_id(upstream))
(void) snprintf(buf + strlen(buf), len - strlen(buf),
"%%%d", (int)*upstream_scope_id(upstream));
if (upstream_port(upstream) != 53 && upstream_port(upstream) != 0)
(void) snprintf(buf + strlen(buf), len - strlen(buf),
"@%d", (int)upstream_port(upstream));
}
/*---------------------------------------- set_os_defaults
@ -363,16 +348,20 @@ create_from_ldns_list(struct getdns_context *context, ldns_rdf ** ldns_list,
static getdns_return_t
set_os_defaults(struct getdns_context *context)
{
ldns_resolver *lr = NULL;
ldns_rdf **rdf_list;
size_t rdf_list_sz;
FILE *in;
char line[1024], domain[1024];
char *parse, *token, prev_ch;
size_t upstreams_limit = 10, length;
struct getdns_bindata bindata;
struct addrinfo hints;
struct addrinfo *result;
struct getdns_upstream *upstream;
struct getdns_dict *addr;
int s;
if (ldns_resolver_new_frm_file(&lr, NULL) != LDNS_STATUS_OK)
return GETDNS_RETURN_GENERIC_ERROR;
if(context->fchg_resolvconf == NULL)
{
context->fchg_resolvconf = GETDNS_MALLOC(context->my_mf, struct filechg);
if(context->fchg_resolvconf == NULL) {
context->fchg_resolvconf =
GETDNS_MALLOC(context->my_mf, struct filechg);
if(context->fchg_resolvconf == NULL)
return GETDNS_RETURN_MEMORY_ERROR;
context->fchg_resolvconf->fn = "/etc/resolv.conf";
@ -382,22 +371,130 @@ set_os_defaults(struct getdns_context *context)
}
filechg_check(context, context->fchg_resolvconf);
rdf_list = ldns_resolver_nameservers(lr);
rdf_list_sz = ldns_resolver_nameserver_count(lr);
if (rdf_list_sz > 0) {
context->upstream_list =
create_from_ldns_list(context, rdf_list, rdf_list_sz);
}
context->upstream_list = getdns_list_create_with_context(context);
context->suffix = getdns_list_create_with_context(context);
context->upstreams = (void *) GETDNS_XMALLOC(context->mf, char,
sizeof(getdns_upstreams) +
sizeof(struct getdns_upstream) * upstreams_limit);
context->upstreams->mf = context->mf;
context->upstreams->referenced = 1;
context->upstreams->count = 0;
rdf_list = ldns_resolver_searchlist(lr);
rdf_list_sz = ldns_resolver_searchlist_count(lr);
if (rdf_list_sz > 0) {
context->suffix = create_from_ldns_list(context, rdf_list,
rdf_list_sz);
}
ldns_resolver_deep_free(lr);
in = fopen(context->fchg_resolvconf->fn, "r");
if (!in)
return GETDNS_RETURN_GOOD;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
hints.ai_socktype = 0; /* Datagram socket */
hints.ai_flags = AI_NUMERICHOST; /* No reverse name lookups */
hints.ai_protocol = 0; /* Any protocol */
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_next = NULL;
return GETDNS_RETURN_GOOD;
*domain = 0;
while (fgets(line, (int)sizeof(line), in)) {
line[sizeof(line)-1] = 0;
/* parse = line + strspn(line, " \t"); */ /* No leading whitespace */
parse = line;
if (strncmp(parse, "domain", 6) == 0) {
parse += 6;
parse += strspn(parse, " \t");
if (*parse == 0 || *parse == '#') continue;
token = parse + strcspn(parse, " \t\r\n");
*token = 0;
(void) strcpy(domain, parse);
} else if (strncmp(parse, "search", 6) == 0) {
parse += 6;
do {
parse += strspn(parse, " \t");
if (*parse == '#' || *parse == '\n') break;
token = parse + strcspn(parse, " \t\r\n");
prev_ch = *token;
*token = 0;
bindata.data = (uint8_t *)parse;
bindata.size = strlen(parse) + 1;
(void) getdns_list_get_length(
context->suffix, &length);
(void) getdns_list_set_bindata(
context->suffix, length, &bindata);
*token = prev_ch;
parse = token;
} while (*parse);
} else if (strncmp(parse, "nameserver", 10) != 0)
continue;
parse += 10;
parse += strspn(parse, " \t");
if (*parse == 0 || *parse == '#') continue;
token = parse + strcspn(parse, " \t\r\n");
*token = 0;
if ((s = getaddrinfo(parse, "53", &hints, &result)))
continue;
/* No lookups, so maximal 1 result */
if (! result) continue;
/* Grow array when needed */
if (context->upstreams->count == upstreams_limit) {
upstreams_limit *= 2;
context->upstreams = (void *) GETDNS_XREALLOC(
context->mf, context->upstreams, char,
sizeof(getdns_upstreams) +
sizeof(struct getdns_upstream) * upstreams_limit);
}
upstream = &context->upstreams->
upstreams[context->upstreams->count++];
upstream->rtt = 1;
upstream->tcp_fd = -1;
upstream->addr_len = result->ai_addrlen;
(void) memcpy(&upstream->addr,
result->ai_addr, result->ai_addrlen);
freeaddrinfo(result);
/*****************************************************
* Add to context->upstream_list too.
* TODO: remove this after async stub is finished.
*/
addr = getdns_dict_create_with_context(context);
bindata.size = upstream_addr_len(upstream);
bindata.data = upstream_addr(upstream);
(void) getdns_dict_set_int(
addr, "port", upstream_port(upstream));
(void) getdns_dict_set_bindata(addr, "address_data", &bindata);
if ((parse = strchr(parse, '%'))) {
parse += 1;
bindata.size = strlen(parse) + 1;
bindata.data = (uint8_t *)parse;
(void) getdns_dict_set_bindata(
addr, "scope_id", &bindata);
}
(void) getdns_list_get_length(context->upstream_list, &length);
(void) getdns_list_set_dict(
context->upstream_list, length, addr);
getdns_dict_destroy(addr);
/*
*****************************************************/
}
fclose(in);
(void) getdns_list_get_length(context->suffix, &length);
if (length == 0 && *domain != 0) {
bindata.data = (uint8_t *)domain;
bindata.size = strlen(domain) + 1;
(void) getdns_list_set_bindata(context->suffix, 0, &bindata);
}
return GETDNS_RETURN_GOOD;
} /* set_os_defaults */
/* compare of transaction ids in DESCENDING order
@ -696,6 +793,9 @@ getdns_context_destroy(struct getdns_context *context)
GETDNS_FREE(context->my_mf, context->local_hosts);
}
if (--context->upstreams->referenced == 0)
GETDNS_FREE(context->upstreams->mf, context->upstreams);
GETDNS_FREE(context->my_mf, context);
} /* getdns_context_destroy */
@ -788,7 +888,7 @@ rebuild_ldns_res(struct getdns_context* context) {
return result;
/* We need to set up the upstream recursive servers from the context */
result = set_ldns_nameservers(context, context->upstream_list);
result = set_ldns_nameservers(context, context->upstreams);
if (result != GETDNS_RETURN_GOOD)
return result;
@ -1406,35 +1506,20 @@ getdns_cancel_callback(struct getdns_context *context,
} /* getdns_cancel_callback */
static getdns_return_t
ub_setup_stub(struct ub_ctx *ctx, struct getdns_list * upstreams)
ub_setup_stub(struct ub_ctx *ctx, getdns_upstreams *upstreams)
{
getdns_return_t r = GETDNS_RETURN_GOOD;
size_t i;
size_t count;
struct getdns_dict *dict;
struct getdns_bindata *address_string;
getdns_return_t r;
struct getdns_upstream *upstream;
char addr[1024];
r = getdns_list_get_length(upstreams, &count);
if (r != GETDNS_RETURN_GOOD)
return r;
if (count == 0)
return GETDNS_RETURN_BAD_CONTEXT;
/* reset forwarding servers */
(void) ub_ctx_set_fwd(ctx, NULL);
for (i = 0; i < count; ++i) {
r = getdns_list_get_dict(upstreams, i, &dict);
if (r != GETDNS_RETURN_GOOD)
break;
r = getdns_dict_get_bindata(dict, GETDNS_STR_ADDRESS_STRING,
&address_string);
if (r != GETDNS_RETURN_GOOD)
break;
(void) ub_ctx_set_fwd(ctx, (char *)address_string->data);
for (i = 0; i < upstreams->count; i++) {
upstream = &upstreams->upstreams[i];
upstream_ntop_buf(upstream, addr, 1024);
ub_ctx_set_fwd(ctx, addr);
}
/* Allow lookups of:
*/
/* - localhost */
@ -1496,41 +1581,24 @@ ub_setup_stub(struct ub_ctx *ctx, struct getdns_list * upstreams)
static getdns_return_t
set_ldns_nameservers(struct getdns_context *context,
struct getdns_list * upstreams)
getdns_upstreams *upstreams)
{
getdns_return_t r = GETDNS_RETURN_GOOD;
size_t i;
size_t count;
struct getdns_dict *dict;
struct getdns_bindata *address_string;
char *address_type = NULL;
ldns_rdf* ns_rdf = NULL;
getdns_return_t r;
struct getdns_upstream *upstream;
ldns_rdf *pop, *ns_rdf;
uint16_t port = 53;
r = getdns_list_get_length(upstreams, &count);
if (r != GETDNS_RETURN_GOOD)
return r;
if (count == 0 || context->ldns_res == NULL)
if (context->ldns_res == NULL)
return GETDNS_RETURN_BAD_CONTEXT;
/* remove current list of nameservers from resolver */
ldns_rdf *pop;
while((pop = ldns_resolver_pop_nameserver(context->ldns_res))) {
ldns_rdf_deep_free(pop);
}
for (i = 0; i < count; ++i) {
r = getdns_list_get_dict(upstreams, i, &dict);
if (r != GETDNS_RETURN_GOOD)
break;
r = getdns_dict_get_bindata(dict, GETDNS_STR_ADDRESS_STRING,
&address_string);
if (r != GETDNS_RETURN_GOOD)
break;
r = getdns_dict_util_get_string(dict, GETDNS_STR_ADDRESS_TYPE,
&address_type);
if (r != GETDNS_RETURN_GOOD)
break;
for (i = 0; i < upstreams->count; i++) {
upstream = &upstreams->upstreams[i];
/* TODO: PROBLEM! The upstream list is implemented such that there is both
* an IP address and a port in the bindata for each nameserver. Unbound
@ -1540,42 +1608,16 @@ set_ldns_nameservers(struct getdns_context *context,
* nameserver in the list. Wrong, but this will support the test scripts
* in the short term which rely on being able to set a port for a single
* nameserver. */
char *address_char = (char *)address_string->data;
char *port_char = NULL;
char *at_symbol_position = strchr(address_char, '@');
if (at_symbol_position != NULL) {
int ip_length = at_symbol_position - address_char;
int port_length = strlen(address_char) - ip_length;
address_char = (char*) malloc(ip_length + 1);
memcpy(address_char, (char *)address_string->data, ip_length);
address_char[ip_length] = '\0';
port_char = (char*) malloc(port_length);
memcpy(port_char, (char *)(address_string->data + ip_length + 1), port_length);
port_char[port_length] = '\0';
}
if (strncmp(GETDNS_STR_IPV4, address_type,
strlen(GETDNS_STR_IPV4)) == 0) {
ns_rdf = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A,
address_char);
} else if (strncmp(GETDNS_STR_IPV6, address_type,
strlen(GETDNS_STR_IPV6)) == 0) {
ns_rdf = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_AAAA,
address_char);
}
ns_rdf = ldns_sockaddr_storage2rdf(&upstream->addr, &port);
if (ns_rdf == NULL)
return GETDNS_RETURN_GENERIC_ERROR;
ldns_resolver_push_nameserver(context->ldns_res, ns_rdf);
ldns_rdf_deep_free(ns_rdf);
if (at_symbol_position != NULL) {
ldns_resolver_set_port(context->ldns_res, atoi(port_char));
free(port_char);
free(address_char);
}
}
return GETDNS_RETURN_GOOD;
ldns_resolver_set_port(context->ldns_res, port);
return r;
}
static getdns_return_t
@ -1592,7 +1634,7 @@ priv_getdns_ns_dns_setup(struct getdns_context *context)
/* We get away with just setting up ldns here here because sync mode
* always hits this method because at the moment all sync calls use DNS
* namespace */
r = ub_setup_stub(context->unbound_ctx, context->upstream_list);
r = ub_setup_stub(context->unbound_ctx, context->upstreams);
if (r != GETDNS_RETURN_GOOD)
return r;
return rebuild_ldns_res(context);

View File

@ -66,8 +66,21 @@ struct filechg {
struct stat *prevstat;
};
struct getdns_context {
struct getdns_upstream {
socklen_t addr_len;
struct sockaddr_storage addr;
int tcp_fd;
int rtt;
};
typedef struct getdns_upstreams {
struct mem_funcs mf;
size_t referenced;
size_t count;
struct getdns_upstream upstreams[];
} getdns_upstreams;
struct getdns_context {
/* Context values */
getdns_resolution_t resolution_type;
getdns_namespace_t *namespaces;
@ -79,19 +92,19 @@ struct getdns_context {
struct getdns_list *suffix;
struct getdns_list *dnssec_trust_anchors;
struct getdns_list *upstream_list;
getdns_transport_t dns_transport;
uint16_t limit_outstanding_queries;
uint32_t dnssec_allowed_skew;
getdns_transport_t dns_transport;
uint16_t limit_outstanding_queries;
uint32_t dnssec_allowed_skew;
uint8_t edns_extended_rcode;
uint8_t edns_version;
uint8_t edns_do_bit;
uint16_t edns_maximum_udp_payload_size;
uint16_t edns_maximum_udp_payload_size;
getdns_update_callback update_callback;
int processing;
int destroying;
int processing;
int destroying;
struct mem_funcs mf;
struct mem_funcs my_mf;
@ -102,7 +115,7 @@ struct getdns_context {
/* A tree to hold local host information*/
struct ldns_rbtree_t *local_hosts;
int has_ta; /* No DNSSEC without trust anchor */
int return_dnssec_status;
int return_dnssec_status;
/* which resolution type the contexts are configured for
* 0 means nothing set
@ -114,25 +127,25 @@ struct getdns_context {
*/
struct ldns_rbtree_t *outbound_requests;
/*
* Event loop extension functions
* These structs are static and should never be freed
* since they are just a collection of function pointers
*/
getdns_eventloop_extension* extension;
/*
* Extension data that will be freed by the functions
* in the extension struct
*/
void* extension_data;
/*
* Event loop extension functions
* These structs are static and should never be freed
* since they are just a collection of function pointers
*/
getdns_eventloop_extension* extension;
/*
* Extension data that will be freed by the functions
* in the extension struct
*/
void* extension_data;
/*
* Timeout info one tree to manage timeout data
* keyed by transaction id. Second to manage by
* timeout time (ascending)
*/
struct ldns_rbtree_t *timeouts_by_id;
struct ldns_rbtree_t *timeouts_by_time;
/*
* Timeout info one tree to manage timeout data
* keyed by transaction id. Second to manage by
* timeout time (ascending)
*/
struct ldns_rbtree_t *timeouts_by_id;
struct ldns_rbtree_t *timeouts_by_time;
/*
* state data used to detect changes to the system config files
@ -140,6 +153,7 @@ struct getdns_context {
struct filechg *fchg_resolvconf;
struct filechg *fchg_hosts;
getdns_upstreams *upstreams;
}; /* getdns_context */
/** internal functions **/

View File

@ -47,11 +47,13 @@
typedef struct stub_resolver {
struct getdns_event_base *base;
getdns_context *context;
const char *name;
uint16_t request_type;
getdns_dict *extensions;
gldns_buffer *response;
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;
@ -74,9 +76,6 @@ cb_udp_request(int fd, short bits, void *arg)
gldns_buffer_remaining(resolver->response),
0, NULL, NULL);
#if STUBDEBUG
fprintf(stderr, "read: %d\n", read);
#endif
if (read == -1 || read == 0)
return;
@ -91,69 +90,37 @@ cb_udp_request(int fd, short bits, void *arg)
free(str);
} while(0);
#endif
(void) getdns_event_base_loopexit(resolver->base, NULL);
if (--resolver->upstreams->referenced == 0)
GETDNS_FREE(resolver->upstreams->mf, resolver->upstreams);
GETDNS_FREE(resolver->context->mf, resolver);
}
static getdns_return_t
query_ns(stub_resolver *resolver)
{
size_t n_upstreams;
getdns_return_t r;
getdns_dict *upstream;
getdns_bindata *address_data;
uint32_t port = 53;
struct sockaddr_in dst4;
struct sockaddr_in6 dst6;
struct getdns_upstream *upstream;
ssize_t sent;
struct getdns_event *ev;
assert(resolver);
r = getdns_list_get_length(
resolver->context->upstream_list, &n_upstreams);
if (r) return r;
r = getdns_list_get_dict(
resolver->context->upstream_list, resolver->ns_index, &upstream);
if (r) return r;
r = getdns_dict_get_bindata(upstream, "address_data", &address_data);
if (r) return r;
(void) getdns_dict_get_int(upstream, "port", &port);
#if STUBDEBUG
fprintf(stderr, "upstream: %s\n", getdns_pretty_print_dict(upstream));
#endif
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
* Also later on... for example when socket returns -1
*/
/* TODO: Check how to connect first (udp or tcp) */
resolver->sockfd = socket(address_data->size == 4 ? AF_INET : AF_INET6,
SOCK_DGRAM, IPPROTO_UDP);
if (address_data->size == 4) {
memset(&dst4, 0, sizeof(struct sockaddr_in));
dst4.sin_family = AF_INET;
dst4.sin_port = (in_port_t)htons((uint16_t)port);
memcpy(&dst4.sin_addr, address_data->data, 4);
sent = sendto(resolver->sockfd,
resolver->request_pkt, resolver->request_pkt_len, 0,
(struct sockaddr *)&dst4, sizeof(dst4));
} else {
memset(&dst6, 0, sizeof(struct sockaddr_in6));
dst6.sin6_family = AF_INET;
dst6.sin6_port = (in_port_t)htons((uint16_t)port);
memcpy(&dst6.sin6_addr, address_data->data, 16);
sent = sendto(resolver->sockfd,
resolver->request_pkt, resolver->request_pkt_len, 0,
(struct sockaddr *)&dst6, sizeof(dst6));
}
resolver->sockfd = socket(upstream->addr.ss_family, SOCK_DGRAM,
IPPROTO_UDP);
sent = sendto(resolver->sockfd,
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;
@ -179,6 +146,8 @@ getdns_stub_dns_query_async(struct getdns_event_base *base,
resolver->base = base;
resolver->context = context;
resolver->upstreams = context->upstreams;
resolver->upstreams->referenced++;
resolver->name = name;
resolver->request_type = request_type;
resolver->extensions = extensions;
@ -199,8 +168,11 @@ getdns_stub_dns_query_async(struct getdns_event_base *base,
#endif
resolver->ns_index = 0;
r = query_ns(resolver);
if (r)
if (r) {
if (--resolver->upstreams->referenced == 0)
GETDNS_FREE(resolver->upstreams->mf, resolver->upstreams);
GETDNS_FREE(context->mf, resolver);
}
return r;
}

View File

@ -82,10 +82,6 @@ static getdns_return_t submit_request_sync_rec(
static getdns_return_t submit_request_sync_stub(
getdns_dns_req* req, uint64_t *timeout)
{
uint8_t *pkt;
size_t pkt_len;
char *str;
ldns_rdf *qname;
getdns_network_req *netreq = req->first_req;
uint16_t qflags = 0;