Store wireformat queries in netreq's too

This commit is contained in:
Willem Toorop 2015-02-03 10:46:44 +01:00
parent 3f046cf573
commit f1b916aac8
7 changed files with 276 additions and 448 deletions

View File

@ -93,8 +93,7 @@ priv_getdns_check_dns_req_complete(getdns_dns_req *dns_req)
if (! results_found)
priv_getdns_call_user_callback(dns_req, NULL);
else if (is_extension_set(dns_req->extensions,
"dnssec_return_validation_chain"))
else if (dns_req->dnssec_return_validation_chain)
priv_getdns_get_validation_chain(dns_req);
else
priv_getdns_call_user_callback(
@ -135,10 +134,9 @@ submit_network_request(getdns_network_req *netreq)
/* TODO: Until DNSSEC with the new async stub resolver is finished,
* use unbound when we need DNSSEC.
*/
(dns_req->extensions && (
is_extension_set(dns_req->extensions, "dnssec_return_status") ||
is_extension_set(dns_req->extensions, "dnssec_return_only_secure") ||
is_extension_set(dns_req->extensions, "dnssec_return_validation_chain")))) {
dns_req->dnssec_return_status ||
dns_req->dnssec_return_only_secure ||
dns_req->dnssec_return_validation_chain) {
/* schedule the timeout */
if (! dns_req->timeout.timeout_cb) {

View File

@ -37,6 +37,22 @@
#include "types-internal.h"
#include "util-internal.h"
#include "gldns/rrdef.h"
#include "gldns/str2wire.h"
#include "gldns/gbuffer.h"
#include "gldns/pkthdr.h"
static int
is_extension_set(getdns_dict *extensions, const char *extension)
{
getdns_return_t r;
uint32_t value;
if (! extensions)
return 0;
r = getdns_dict_get_int(extensions, extension, &value);
return r == GETDNS_RETURN_GOOD && value == GETDNS_EXTENSION_TRUE;
}
static void
network_req_cleanup(getdns_network_req *net_req)
@ -46,15 +62,28 @@ network_req_cleanup(getdns_network_req *net_req)
if (net_req->result)
ldns_pkt_free(net_req->result);
if (net_req->response && net_req->response != net_req->wire_data)
if (net_req->response && (net_req->response < net_req->wire_data ||
net_req->response > net_req->wire_data+ net_req->wire_data_sz))
GETDNS_FREE(net_req->owner->my_mf, net_req->response);
}
static void
network_req_init(getdns_network_req *net_req,
getdns_dns_req *owner, uint16_t request_type,
uint16_t request_class, size_t wire_data_sz)
static int
network_req_init(getdns_network_req *net_req, getdns_dns_req *owner,
const char *name, uint16_t request_type, uint16_t request_class,
int dnssec_extension_set, int with_opt,
uint16_t edns_maximum_udp_payload_size,
uint8_t edns_extended_rcode, uint8_t edns_version, int edns_do_bit,
uint16_t opt_options_size, size_t noptions, getdns_list *options,
size_t wire_data_sz, size_t max_query_sz)
{
uint8_t *buf;
size_t dname_len;
getdns_dict *option;
uint32_t option_code;
getdns_bindata *option_data;
size_t i;
int r = 0;
net_req->result = NULL;
net_req->request_type = request_type;
@ -68,11 +97,78 @@ network_req_init(getdns_network_req *net_req,
memset(&net_req->event, 0, sizeof(net_req->event));
memset(&net_req->tcp, 0, sizeof(net_req->tcp));
net_req->query_id = 0;
net_req->max_udp_payload_size = 0;
net_req->edns_maximum_udp_payload_size = edns_maximum_udp_payload_size;
net_req->max_udp_payload_size = edns_maximum_udp_payload_size != -1
? edns_maximum_udp_payload_size : 1432;
net_req->write_queue_tail = NULL;
net_req->query_len = 0;
net_req->wire_data_sz = wire_data_sz;
net_req->response = NULL;
if (max_query_sz) {
/* first two bytes will contain query length (for tcp) */
buf = net_req->query = net_req->wire_data + 2;
gldns_write_uint16(buf + 2, 0); /* reset all flags */
GLDNS_RD_SET(buf);
if (dnssec_extension_set) /* We will do validation ourselves */
GLDNS_CD_SET(buf);
GLDNS_OPCODE_SET(buf, GLDNS_PACKET_QUERY);
gldns_write_uint16(buf + GLDNS_QDCOUNT_OFF, 1); /* 1 query */
gldns_write_uint16(buf + GLDNS_ANCOUNT_OFF, 0); /* 0 answers */
gldns_write_uint16(buf + GLDNS_NSCOUNT_OFF, 0); /* 0 authorities */
gldns_write_uint16(buf + GLDNS_ARCOUNT_OFF, with_opt ? 1 : 0);
buf += GLDNS_HEADER_SIZE;
dname_len = max_query_sz - GLDNS_HEADER_SIZE;
if ((r = gldns_str2wire_dname_buf(name, buf, &dname_len)))
return r;
buf += dname_len;
gldns_write_uint16(buf, request_type);
gldns_write_uint16(buf + 2, request_class);
buf += 4;
if (with_opt) {
net_req->opt = buf;
buf[0] = 0; /* dname for . */
gldns_write_uint16(buf + 1, GLDNS_RR_TYPE_OPT);
gldns_write_uint16(net_req->opt + 3,
net_req->max_udp_payload_size);
buf[5] = edns_extended_rcode;
buf[6] = edns_version;
buf[7] = edns_do_bit ? 0x80 : 0;
buf[8] = 0;
gldns_write_uint16(buf + 9, opt_options_size);
buf += 11;
for (i = 0; i < noptions; i++) {
if (getdns_list_get_dict(options, i, &option))
continue;
if (getdns_dict_get_int(
option, "option_code", &option_code))
continue;
if (getdns_dict_get_bindata(
option, "option_data", &option_data))
continue;
gldns_write_uint16(buf, (uint16_t) option_code);
gldns_write_uint16(buf + 2,
(uint16_t) option_data->size);
(void) memcpy(buf + 4, option_data->data,
option_data->size);
buf += option_data->size + 4;
}
} else
net_req->opt = NULL;
net_req->response = buf;
gldns_write_uint16(net_req->wire_data, net_req->response - net_req->query);
} else {
net_req->query = NULL;
net_req->opt = NULL;
net_req->response = net_req->wire_data;
}
return r;
}
void
@ -83,9 +179,6 @@ dns_req_free(getdns_dns_req * req)
return;
}
/* free extensions */
getdns_dict_destroy(req->extensions);
if (req->upstreams && --req->upstreams->referenced == 0)
GETDNS_FREE(req->upstreams->mf, req->upstreams);
@ -109,11 +202,37 @@ getdns_dns_req *
dns_req_new(getdns_context *context, getdns_eventloop *loop,
const char *name, uint16_t request_type, getdns_dict *extensions)
{
int dnssec_return_status = context->return_dnssec_status ||
is_extension_set(extensions, "dnssec_return_status");
int dnssec_return_only_secure
= is_extension_set(extensions, "dnssec_return_only_secure");
int dnssec_return_validation_chain
= is_extension_set(extensions, "dnssec_return_validation_chain");
int dnssec_extension_set = dnssec_return_status
|| dnssec_return_only_secure || dnssec_return_validation_chain;
uint32_t edns_do_bit;
int edns_maximum_udp_payload_size;
uint32_t get_edns_maximum_udp_payload_size;
uint32_t edns_extended_rcode;
uint32_t edns_version;
getdns_dict *add_opt_parameters;
int have_add_opt_parameters;
getdns_list *options;
size_t noptions = 0;
size_t i;
getdns_dict *option;
uint32_t option_code;
getdns_bindata *option_data;
size_t opt_options_size = 0;
int with_opt;
getdns_dns_req *result = NULL;
uint32_t klass = GLDNS_RR_CLASS_IN;
size_t edns_maximum_udp_payload_size =
getdns_get_maximum_udp_payload_size(context, extensions, NULL);
int a_aaaa_query =
is_extension_set(extensions, "return_both_v4_and_v6") &&
( request_type == GETDNS_RRTYPE_A ||
@ -122,12 +241,82 @@ dns_req_new(getdns_context *context, getdns_eventloop *loop,
* (to test for udp overflow) (hence the + 1),
* And align on the 8 byte boundry (hence the (x + 7) / 8 * 8)
*/
size_t netreq_sz = ( sizeof(getdns_network_req)
+ edns_maximum_udp_payload_size + 1 + 7) / 8 * 8;
size_t dnsreq_base_sz = ( sizeof(getdns_dns_req)
+ (a_aaaa_query ? 3 : 2)
* sizeof(getdns_network_req *));
size_t max_query_sz, max_response_sz, netreq_sz, dnsreq_base_sz;
uint8_t *region;
have_add_opt_parameters = getdns_dict_get_dict(extensions,
"add_opt_parameters", &add_opt_parameters) == GETDNS_RETURN_GOOD;
if (dnssec_extension_set) {
edns_maximum_udp_payload_size = -1;
edns_extended_rcode = 0;
edns_version = 0;
edns_do_bit = 1;
} else {
edns_maximum_udp_payload_size =
context->edns_maximum_udp_payload_size;
edns_extended_rcode = context->edns_extended_rcode;
edns_version = context->edns_version;
edns_do_bit = context->edns_do_bit;
if (have_add_opt_parameters) {
if (!getdns_dict_get_int(add_opt_parameters,
"maximum_udp_payload_size",
&get_edns_maximum_udp_payload_size))
edns_maximum_udp_payload_size =
get_edns_maximum_udp_payload_size;
(void) getdns_dict_get_int(add_opt_parameters,
"extended_rcode", &edns_extended_rcode);
(void) getdns_dict_get_int(add_opt_parameters,
"version", &edns_version);
(void) getdns_dict_get_int(add_opt_parameters,
"do_bit", &edns_do_bit);
}
}
if (have_add_opt_parameters && getdns_dict_get_list(
add_opt_parameters, "options", &options) == GETDNS_RETURN_GOOD)
(void) getdns_list_get_length(options, &noptions);
with_opt = edns_do_bit != 0 || edns_maximum_udp_payload_size != -1 ||
edns_extended_rcode != 0 || edns_version != 0 || noptions;
edns_maximum_udp_payload_size = with_opt &&
( edns_maximum_udp_payload_size == -1 ||
edns_maximum_udp_payload_size > 512 )
? edns_maximum_udp_payload_size : 512;
/* (x + 7) / 8 * 8 to align on 8 byte boundries */
if (context->resolution_type == GETDNS_RESOLUTION_RECURSING)
max_query_sz = 0;
else {
for (i = 0; i < noptions; i++) {
if (getdns_list_get_dict(options, i, &option)) continue;
if (getdns_dict_get_int(
option, "option_code", &option_code)) continue;
if (getdns_dict_get_bindata(
option, "option_data", &option_data)) continue;
opt_options_size += option_data->size
+ 2 /* option-code */
+ 2 /* option-length */
;
}
max_query_sz = ( GLDNS_HEADER_SIZE
+ strlen(name) + 1 + 4 /* dname always smaller then strlen(name) + 1 */
+ 12 + opt_options_size /* space needed for OPT (if needed) */
/* TODO: TSIG */
+ 7) / 8 * 8;
}
max_response_sz = (( edns_maximum_udp_payload_size != -1
? edns_maximum_udp_payload_size : 1432
) + 1 /* +1 for udp overflow detection */
+ 7 ) / 8 * 8;
netreq_sz = ( sizeof(getdns_network_req)
+ max_query_sz + max_response_sz + 7 ) / 8 * 8;
dnsreq_base_sz = (( sizeof(getdns_dns_req)
+ (a_aaaa_query ? 3 : 2) * sizeof(getdns_network_req*)
) + 7) / 8 * 8;
if (! (region = GETDNS_XMALLOC(context->mf, uint8_t,
dnsreq_base_sz + (a_aaaa_query ? 2 : 1) * netreq_sz)))
@ -148,9 +337,9 @@ dns_req_new(getdns_context *context, getdns_eventloop *loop,
result->loop = loop;
result->canceled = 0;
result->trans_id = (uint64_t)(((intptr_t) result) ^ ldns_get_random());
getdns_dict_copy(extensions, &result->extensions);
result->return_dnssec_status = context->return_dnssec_status;
result->dnssec_return_status = dnssec_return_status;
result->dnssec_return_only_secure = dnssec_return_only_secure;
result->dnssec_return_validation_chain = dnssec_return_validation_chain;
/* will be set by caller */
result->user_pointer = NULL;
@ -164,14 +353,23 @@ dns_req_new(getdns_context *context, getdns_eventloop *loop,
if (result->upstreams)
result->upstreams->referenced++;
network_req_init(result->netreqs[0], result, request_type,
klass, netreq_sz - sizeof(getdns_network_req));
network_req_init(result->netreqs[0], result,
name, request_type, klass,
dnssec_extension_set, with_opt,
edns_maximum_udp_payload_size,
edns_extended_rcode, edns_version, edns_do_bit,
opt_options_size, noptions, options,
netreq_sz - sizeof(getdns_network_req), max_query_sz);
if (a_aaaa_query)
network_req_init(result->netreqs[1], result,
network_req_init(result->netreqs[1], result, name,
( request_type == GETDNS_RRTYPE_A
? GETDNS_RRTYPE_AAAA : GETDNS_RRTYPE_A ),
klass, netreq_sz - sizeof(getdns_network_req));
? GETDNS_RRTYPE_AAAA : GETDNS_RRTYPE_A ), klass,
dnssec_extension_set, with_opt,
edns_maximum_udp_payload_size,
edns_extended_rcode, edns_version, edns_do_bit,
opt_options_size, noptions, options,
netreq_sz - sizeof(getdns_network_req), max_query_sz);
return result;
}

View File

@ -43,218 +43,6 @@
#include "util-internal.h"
#include "general.h"
static int
getdns_make_query_pkt_buf(const getdns_network_req *netreq, uint8_t *buf,
size_t *olen, uint16_t *omax_udp_payload_size)
{
size_t len;
getdns_dns_req *dnsreq = netreq->owner;
getdns_context *context = dnsreq->context;
getdns_dict *extensions = dnsreq->extensions;
int dnssec_return_status
= is_extension_set(extensions, "dnssec_return_status");
int dnssec_return_only_secure
= is_extension_set(extensions, "dnssec_return_only_secure");
int dnssec_return_validation_chain
= is_extension_set(extensions, "dnssec_return_validation_chain");
int dnssec_extension_set = dnssec_return_status
|| dnssec_return_only_secure || dnssec_return_validation_chain;
uint32_t edns_do_bit;
int edns_maximum_udp_payload_size;
uint32_t get_edns_maximum_udp_payload_size;
uint32_t edns_extended_rcode;
uint32_t edns_version;
getdns_dict *add_opt_parameters;
int have_add_opt_parameters;
getdns_list *options;
size_t noptions = 0;
size_t i;
getdns_dict *option;
uint32_t option_code;
getdns_bindata *option_data;
size_t opt_options_size = 0;
int with_opt;
int r;
size_t dname_len;
have_add_opt_parameters = getdns_dict_get_dict(extensions,
"add_opt_parameters", &add_opt_parameters) == GETDNS_RETURN_GOOD;
if (dnssec_extension_set) {
edns_maximum_udp_payload_size =
netreq->upstream->addr.ss_family == AF_INET6 ? 1232 : 1432;
edns_extended_rcode = 0;
edns_version = 0;
edns_do_bit = 1;
} else {
edns_maximum_udp_payload_size =
context->edns_maximum_udp_payload_size;
edns_extended_rcode = context->edns_extended_rcode;
edns_version = context->edns_version;
edns_do_bit = context->edns_do_bit;
if (have_add_opt_parameters) {
if (!getdns_dict_get_int(add_opt_parameters,
"maximum_udp_payload_size",
&get_edns_maximum_udp_payload_size))
edns_maximum_udp_payload_size =
get_edns_maximum_udp_payload_size;
(void) getdns_dict_get_int(add_opt_parameters,
"extended_rcode", &edns_extended_rcode);
(void) getdns_dict_get_int(add_opt_parameters,
"version", &edns_version);
(void) getdns_dict_get_int(add_opt_parameters,
"do_bit", &edns_do_bit);
}
}
if (have_add_opt_parameters && getdns_dict_get_list(
add_opt_parameters, "options", &options) == GETDNS_RETURN_GOOD)
(void) getdns_list_get_length(options, &noptions);
with_opt = edns_do_bit != 0 || edns_maximum_udp_payload_size != -1 ||
edns_extended_rcode != 0 || edns_version != 0 || noptions;
*omax_udp_payload_size = edns_maximum_udp_payload_size =
! with_opt ? 512
: edns_maximum_udp_payload_size == -1 ?
netreq->upstream->addr.ss_family==AF_INET6 ? 1232 : 1432
: edns_maximum_udp_payload_size > 512 ?
edns_maximum_udp_payload_size : 512;
assert(buf);
assert(olen);
len = *olen;
*olen = 0;
if (len < GLDNS_HEADER_SIZE)
return GLDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
gldns_write_uint16(buf + 2, 0); /* reset all flags */
GLDNS_RD_SET(buf);
if (dnssec_extension_set) /* We will do validation outselves */
GLDNS_CD_SET(buf);
GLDNS_OPCODE_SET(buf, GLDNS_PACKET_QUERY);
gldns_write_uint16(buf + GLDNS_QDCOUNT_OFF, 1); /* 1 query */
gldns_write_uint16(buf + GLDNS_ANCOUNT_OFF, 0); /* 0 answers */
gldns_write_uint16(buf + GLDNS_NSCOUNT_OFF, 0); /* 0 authorities */
gldns_write_uint16(buf + GLDNS_ARCOUNT_OFF, with_opt ? 1 : 0);
len -= GLDNS_HEADER_SIZE;
*olen += GLDNS_HEADER_SIZE;
buf += GLDNS_HEADER_SIZE;
dname_len = len;
if ((r = gldns_str2wire_dname_buf(dnsreq->name, buf, &dname_len)))
return r;
len -= dname_len;
*olen += dname_len;
buf += dname_len;
if (len < 4)
return GLDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
gldns_write_uint16(buf, netreq->request_type);
gldns_write_uint16(buf + 2, netreq->request_class);
len -= 4;
*olen += 4;
buf += 4;
if (with_opt) {
if (len < 11)
return GLDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
buf[0] = 0; /* dname for . */
gldns_write_uint16(buf + 1, GLDNS_RR_TYPE_OPT);
gldns_write_uint16(buf + 3,
(uint16_t) edns_maximum_udp_payload_size);
buf[5] = (uint8_t) edns_extended_rcode;
buf[6] = (uint8_t) edns_version;
buf[7] = edns_do_bit ? 0x80 : 0;
buf[8] = 0;
gldns_write_uint16(buf + 9, (uint16_t) opt_options_size);
len -= 11;
*olen += 11;
buf += 11;
for (i = 0; i < noptions; i++) {
if (getdns_list_get_dict(options, i, &option))
continue;
if (getdns_dict_get_int(
option, "option_code", &option_code)) continue;
if (getdns_dict_get_bindata(
option, "option_data", &option_data)) continue;
if (len < option_data->size + 4) {
gldns_write_uint16(buf - opt_options_size - 2,
(uint16_t) opt_options_size);
return GLDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
}
gldns_write_uint16(buf, (uint16_t) option_code);
gldns_write_uint16(buf + 2,
(uint16_t) option_data->size);
(void) memcpy(buf + 4, option_data->data,
option_data->size);
opt_options_size += option_data->size + 4;
len -= option_data->size + 4;
*olen += option_data->size + 4;
buf += option_data->size + 4;
}
gldns_write_uint16(buf - opt_options_size - 2,
(uint16_t) opt_options_size);
}
return 0;
}
/* Return a rough estimate for mallocs */
static size_t
getdns_get_query_pkt_size(getdns_context *context,
const char *name, uint16_t request_type, getdns_dict *extensions)
{
getdns_dict *add_opt_parameters;
getdns_list *options;
size_t noptions = 0;
size_t i;
getdns_dict *option;
uint32_t option_code;
getdns_bindata *option_data;
size_t opt_options_size = 0;
do {
if (getdns_dict_get_dict(extensions,
"add_opt_parameters", &add_opt_parameters)) break;
if (getdns_dict_get_list(
add_opt_parameters, "options", &options)) break;
if (getdns_list_get_length(options, &noptions)) break;
for (i = 0; i < noptions; i++) {
if (getdns_list_get_dict(options, i, &option)) continue;
if (getdns_dict_get_int(
option, "option_code", &option_code)) continue;
if (getdns_dict_get_bindata(
option, "option_data", &option_data)) continue;
opt_options_size += option_data->size
+ 2 /* option-code */
+ 2 /* option-length */
;
}
} while (0);
return GLDNS_HEADER_SIZE
+ strlen(name) + 1 + 4 /* dname always smaller then strlen(name) + 1 */
+ 12 + opt_options_size /* space needed for OPT (if needed) */
/* TODO: TSIG */
;
}
/** best effort to set nonblocking */
static void
@ -299,7 +87,6 @@ stub_cleanup(getdns_network_req *netreq)
GETDNS_CLEAR_EVENT(dnsreq->loop, &netreq->event);
GETDNS_NULL_FREE(dnsreq->context->mf, netreq->tcp.write_buf);
GETDNS_NULL_FREE(dnsreq->context->mf, netreq->tcp.read_buf);
/* Nothing globally scheduled? Then nothing queued */
@ -467,46 +254,29 @@ static void
stub_udp_write_cb(void *userarg)
{
getdns_network_req *netreq = (getdns_network_req *)userarg;
getdns_dns_req *dnsreq = netreq->owner;
static size_t pkt_buf_len = 4096;
uint8_t pkt_buf[pkt_buf_len];
uint8_t *pkt = pkt_buf;
size_t pkt_len;
size_t pkt_size_needed;
getdns_dns_req *dnsreq = netreq->owner;
size_t pkt_len = netreq->response - netreq->query;
GETDNS_CLEAR_EVENT(dnsreq->loop, &netreq->event);
pkt_size_needed = getdns_get_query_pkt_size(dnsreq->context,
dnsreq->name, netreq->request_type, dnsreq->extensions);
if (pkt_size_needed > pkt_buf_len) {
pkt = GETDNS_XMALLOC(
dnsreq->context->mf, uint8_t, pkt_size_needed);
pkt_len = pkt_size_needed;
} else
pkt_len = pkt_buf_len;
if (getdns_make_query_pkt_buf(netreq, pkt_buf, &pkt_len,
&netreq->max_udp_payload_size))
goto exit;
netreq->query_id = ldns_get_random();
GLDNS_ID_SET(pkt, netreq->query_id);
GLDNS_ID_SET(netreq->query, netreq->query_id);
if (netreq->edns_maximum_udp_payload_size == -1)
gldns_write_uint16(netreq->opt + 3,
( netreq->max_udp_payload_size =
netreq->upstream->addr.ss_family == AF_INET6
? 1232 : 1432));
if ((ssize_t)pkt_len != sendto(netreq->fd, pkt, pkt_len, 0,
if ((ssize_t)pkt_len != sendto(netreq->fd, netreq->query, pkt_len, 0,
(struct sockaddr *)&netreq->upstream->addr,
netreq->upstream->addr_len)) {
close(netreq->fd);
goto exit;
return;
}
GETDNS_SCHEDULE_EVENT(
dnsreq->loop, netreq->fd, dnsreq->context->timeout,
getdns_eventloop_event_init(&netreq->event, netreq,
stub_udp_read_cb, NULL, stub_timeout_cb));
exit:
if (pkt && pkt != pkt_buf)
GETDNS_FREE(dnsreq->context->mf, pkt);
}
static getdns_upstream *
@ -735,47 +505,15 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq)
{
getdns_dns_req *dnsreq = netreq->owner;
static size_t pkt_buf_len = 4096;
uint8_t pkt_buf[pkt_buf_len];
uint8_t *pkt = pkt_buf;
size_t pkt_len;
size_t query_pkt_size;
size_t pkt_len = netreq->response - netreq->query;
ssize_t written;
uint16_t query_id;
intptr_t query_id_intptr;
/* Do we have remaining data that we could not write before? */
if (! tcp->write_buf) {
/* No, this is an initial write.
* Create packet and try to send
/* No, this is an initial write. Try to send
*/
query_pkt_size = getdns_get_query_pkt_size(dnsreq->context,
dnsreq->name, netreq->request_type, dnsreq->extensions);
if (query_pkt_size + 2 > pkt_buf_len) {
/* Not enough space in out stack buffer.
* Allocate a buffer on the heap.
*/
if (!(pkt = GETDNS_XMALLOC(dnsreq->context->mf,
uint8_t, query_pkt_size + 2)))
return STUB_TCP_ERROR;
tcp->write_buf = pkt;
tcp->write_buf_len = query_pkt_size + 2;
tcp->written = 0;
pkt_len = query_pkt_size;
} else
pkt_len = pkt_buf_len - 2;
/* Construct query packet */
if (getdns_make_query_pkt_buf(netreq, pkt + 2, &pkt_len,
&netreq->max_udp_payload_size))
return STUB_TCP_ERROR;
/* Prepend length short */
gldns_write_uint16(pkt, pkt_len);
/* Not keeping connections open? Then the first random number
* will do as the query id.
@ -796,20 +534,23 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq)
} while (!getdns_rbtree_insert(
&netreq->upstream->netreq_by_query_id, &netreq->node));
GLDNS_ID_SET(pkt + 2, query_id);
GLDNS_ID_SET(netreq->query, query_id);
gldns_write_uint16(netreq->opt + 3, 65535); /* no limits on the
max udp payload
size with tcp */
/* We have an initialized packet buffer.
* Lets see how much of it we can write
*/
#ifdef USE_TCP_FASTOPEN
/* We use sendto() here which will do both a connect and send */
written = sendto(fd, pkt, pkt_len + 2, MSG_FASTOPEN,
(struct sockaddr *)&(netreq->upstream->addr),
netreq->upstream->addr_len);
written = sendto(fd, netreq->query - 2, pkt_len + 2,
MSG_FASTOPEN, (struct sockaddr *)&(netreq->upstream->addr),
netreq->upstream->addr_len);
/* If pipelining we will find that the connection is already up so
just fall back to a 'normal' write. */
if (written == -1 && errno == EISCONN)
written = write(fd, pkt, pkt_len + 2);
written = write(fd, netreq->query - 2, pkt_len + 2);
if ((written == -1 && (errno == EAGAIN ||
errno == EWOULDBLOCK ||
@ -819,26 +560,17 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq)
errno == EINPROGRESS)) ||
written < pkt_len + 2) {
#else
written = write(fd, pkt, pkt_len + 2);
written = write(fd, netreq->query - 2, pkt_len + 2);
if ((written == -1 && (errno == EAGAIN ||
errno == EWOULDBLOCK)) ||
written < pkt_len + 2) {
#endif
/* We couldn't write the whole packet.
* We have to return with STUB_TCP_AGAIN, but if
* the packet was on the stack only, we have to copy
* it to heap space fist, because the stack will be
* gone after return.
* We have to return with STUB_TCP_AGAIN.
* Setup tcp to track the state.
*/
if (!tcp->write_buf) {
/* Copy stack packet buffer to heap */
if (!(tcp->write_buf = GETDNS_XMALLOC(
dnsreq->context->mf,uint8_t,pkt_len + 2)))
return STUB_TCP_ERROR;
(void) memcpy(tcp->write_buf, pkt, pkt_len + 2);
tcp->write_buf_len = pkt_len + 2;
}
/* Because written could be -1 (and errno EAGAIN) */
tcp->write_buf = netreq->query - 2;
tcp->write_buf_len = pkt_len + 2;
tcp->written = written >= 0 ? written : 0;
return STUB_TCP_AGAIN;
@ -847,7 +579,7 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq)
return STUB_TCP_ERROR;
/* We were able to write everything! Start reading. */
GETDNS_NULL_FREE(dnsreq->context->mf, tcp->write_buf);
return (int) query_id;
} else {/* if (! tcp->write_buf) */
@ -867,12 +599,10 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq)
return STUB_TCP_AGAIN;
/* Done. Start reading */
query_id = GLDNS_ID_WIRE(tcp->write_buf + 2);
tcp->write_buf = NULL;
return (int)GLDNS_ID_WIRE(tcp->write_buf + 2);
} /* if (! tcp->write_buf) */
GETDNS_NULL_FREE(dnsreq->context->mf, tcp->write_buf);
return (int) query_id;
}
static void

View File

@ -38,6 +38,7 @@
#include "types-internal.h"
getdns_return_t priv_getdns_submit_stub_request(getdns_network_req *netreq);
void priv_getdns_cancel_stub_request(getdns_network_req *netreq);
#endif

View File

@ -198,6 +198,7 @@ typedef struct getdns_network_req
getdns_tcp_state tcp;
uint16_t query_id;
int edns_maximum_udp_payload_size;
uint16_t max_udp_payload_size;
/* Network requests scheduled to write after me */
@ -207,6 +208,9 @@ typedef struct getdns_network_req
* available in wire_data[], it will be allocated seperately.
* response will then not point to wire_data anymore.
*/
size_t query_len;
uint8_t *query;
uint8_t *opt; /* offset of OPT RR in query */
uint8_t *response;
size_t wire_data_sz;
uint8_t wire_data[];
@ -231,7 +235,9 @@ typedef struct getdns_dns_req {
struct getdns_context *context;
/* request extensions */
struct getdns_dict *extensions;
int dnssec_return_status;
int dnssec_return_only_secure;
int dnssec_return_validation_chain;
/* event loop */
getdns_eventloop *loop;
@ -246,9 +252,6 @@ typedef struct getdns_dns_req {
/* for scheduling timeouts when using libunbound */
getdns_eventloop_event timeout;
/* dnssec status */
int return_dnssec_status;
/* mem funcs */
struct mem_funcs my_mf;

View File

@ -536,13 +536,14 @@ rrsigs_in_answer(ldns_pkt *pkt)
}
struct getdns_dict *
create_getdns_response(struct getdns_dns_req * completed_request)
create_getdns_response(getdns_dns_req *completed_request)
{
struct getdns_dict *result = getdns_dict_create_with_context(completed_request->context);
struct getdns_list *replies_full = getdns_list_create_with_context(
getdns_dict *result = getdns_dict_create_with_context(
completed_request->context);
struct getdns_list *just_addrs = NULL;
struct getdns_list *replies_tree = getdns_list_create_with_context(
getdns_list *replies_full = getdns_list_create_with_context(
completed_request->context);
getdns_list *just_addrs = NULL;
getdns_list *replies_tree = getdns_list_create_with_context(
completed_request->context);
getdns_network_req *netreq, **netreq_p;
char *canonical_name = NULL;
@ -550,17 +551,10 @@ create_getdns_response(struct getdns_dns_req * completed_request)
int nreplies = 0, nanswers = 0, nsecure = 0, ninsecure = 0, nbogus = 0;
/* info (bools) about dns_req */
int dnssec_return_validation_chain;
int dnssec_return_only_secure;
int dnssec_return_status;
dnssec_return_validation_chain = is_extension_set(
completed_request->extensions, "dnssec_return_validation_chain");
dnssec_return_only_secure = is_extension_set(
completed_request->extensions, "dnssec_return_only_secure");
dnssec_return_status = dnssec_return_only_secure || is_extension_set(
completed_request->extensions, "dnssec_return_status") ||
completed_request->return_dnssec_status == GETDNS_EXTENSION_TRUE;
dnssec_return_status = completed_request->dnssec_return_status ||
completed_request->dnssec_return_only_secure;
if (completed_request->netreqs[0]->request_type == GETDNS_RRTYPE_A ||
completed_request->netreqs[0]->request_type == GETDNS_RRTYPE_AAAA)
@ -600,10 +594,10 @@ create_getdns_response(struct getdns_dns_req * completed_request)
ldns_pkt_get_rcode(netreq->result))
nanswers++;
if (! dnssec_return_validation_chain) {
if (! completed_request->dnssec_return_validation_chain) {
if (dnssec_return_status && netreq->bogus)
continue;
else if (dnssec_return_only_secure && ! netreq->secure)
else if (completed_request->dnssec_return_only_secure && ! netreq->secure)
continue;
}
struct getdns_bindata full_data;
@ -626,7 +620,7 @@ create_getdns_response(struct getdns_dns_req * completed_request)
r = GETDNS_RETURN_MEMORY_ERROR;
break;
}
if (dnssec_return_status || dnssec_return_validation_chain) {
if (dnssec_return_status || completed_request->dnssec_return_validation_chain) {
r = getdns_dict_set_int(reply, "dnssec_status",
( netreq->secure ? GETDNS_DNSSEC_SECURE
: netreq->bogus ? GETDNS_DNSSEC_BOGUS
@ -692,9 +686,9 @@ create_getdns_response(struct getdns_dns_req * completed_request)
}
r = getdns_dict_set_int(result, GETDNS_STR_KEY_STATUS,
nreplies == 0 ? GETDNS_RESPSTATUS_ALL_TIMEOUT :
dnssec_return_only_secure && nsecure == 0 && ninsecure > 0
completed_request->dnssec_return_only_secure && nsecure == 0 && ninsecure > 0
? GETDNS_RESPSTATUS_NO_SECURE_ANSWERS :
dnssec_return_only_secure && nsecure == 0 && nbogus > 0
completed_request->dnssec_return_only_secure && nsecure == 0 && nbogus > 0
? GETDNS_RESPSTATUS_ALL_BOGUS_ANSWERS :
nanswers == 0 ? GETDNS_RESPSTATUS_NO_NAME
: GETDNS_RESPSTATUS_GOOD);
@ -956,89 +950,5 @@ validate_dname(const char* dname) {
return GETDNS_RETURN_GOOD;
} /* validate_dname */
int
is_extension_set(getdns_dict *extensions, const char *extension)
{
getdns_return_t r;
uint32_t value;
if (! extensions)
return 0;
r = getdns_dict_get_int(extensions, extension, &value);
return r == GETDNS_RETURN_GOOD && value == GETDNS_EXTENSION_TRUE;
}
size_t
getdns_get_maximum_udp_payload_size(getdns_context *context,
getdns_dict *extensions, getdns_upstream *upstream)
{
int dnssec_return_status
= is_extension_set(extensions, "dnssec_return_status");
int dnssec_return_only_secure
= is_extension_set(extensions, "dnssec_return_only_secure");
int dnssec_return_validation_chain
= is_extension_set(extensions, "dnssec_return_validation_chain");
int dnssec_extension_set = dnssec_return_status
|| dnssec_return_only_secure || dnssec_return_validation_chain;
uint32_t edns_do_bit;
int edns_maximum_udp_payload_size;
uint32_t get_edns_maximum_udp_payload_size;
uint32_t edns_extended_rcode;
uint32_t edns_version;
getdns_dict *add_opt_parameters;
int have_add_opt_parameters;
getdns_list *options;
size_t noptions = 0;
int with_opt;
have_add_opt_parameters = getdns_dict_get_dict(extensions,
"add_opt_parameters", &add_opt_parameters) == GETDNS_RETURN_GOOD;
if (dnssec_extension_set) {
edns_maximum_udp_payload_size =
( upstream && upstream->addr.ss_family == AF_INET6 )
? 1232 : 1432;
edns_extended_rcode = 0;
edns_version = 0;
edns_do_bit = 1;
} else {
edns_maximum_udp_payload_size =
context->edns_maximum_udp_payload_size;
edns_extended_rcode = context->edns_extended_rcode;
edns_version = context->edns_version;
edns_do_bit = context->edns_do_bit;
if (have_add_opt_parameters) {
if (!getdns_dict_get_int(add_opt_parameters,
"maximum_udp_payload_size",
&get_edns_maximum_udp_payload_size))
edns_maximum_udp_payload_size =
get_edns_maximum_udp_payload_size;
(void) getdns_dict_get_int(add_opt_parameters,
"extended_rcode", &edns_extended_rcode);
(void) getdns_dict_get_int(add_opt_parameters,
"version", &edns_version);
(void) getdns_dict_get_int(add_opt_parameters,
"do_bit", &edns_do_bit);
}
}
if (have_add_opt_parameters && getdns_dict_get_list(
add_opt_parameters, "options", &options) == GETDNS_RETURN_GOOD)
(void) getdns_list_get_length(options, &noptions);
with_opt = edns_do_bit != 0 || edns_maximum_udp_payload_size != -1 ||
edns_extended_rcode != 0 || edns_version != 0 || noptions;
return ! with_opt ? 512
: edns_maximum_udp_payload_size == -1 ?
(upstream && upstream->addr.ss_family==AF_INET6 ) ? 1232 : 1432
: edns_maximum_udp_payload_size > 512 ?
edns_maximum_udp_payload_size : 512;
}
/* util-internal.c */

View File

@ -139,18 +139,6 @@ getdns_return_t validate_extensions(struct getdns_dict * extensions);
struct getdns_list *
create_list_from_rr_list(struct getdns_context *context, ldns_rr_list * rr_list);
/**
* helper to check if an extension is set.
* Should only be called for "boolean" type extensions that have a value of
* GETDNS_EXTENSION_TRUE or GETDNS_EXTENSION_FALSE
* @param extensions extensions dictionary
* @param extension name of extension to check
* @return int with value 1 if set to GETDNS_EXTENSION_TRUE and 0 otherwise
*/
int is_extension_set(getdns_dict *extensions, const char *extension);
size_t getdns_get_maximum_udp_payload_size(getdns_context *context,
getdns_dict *extensions, getdns_upstream *upstream);
#define DEBUG_ON(...) do { \
struct timeval tv; \