From f1b916aac8cf64ea265323dced1983a433cc381c Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Tue, 3 Feb 2015 10:46:44 +0100 Subject: [PATCH] Store wireformat queries in netreq's too --- src/general.c | 10 +- src/request-internal.c | 248 +++++++++++++++++++++++++++---- src/stub.c | 326 ++++------------------------------------- src/stub.h | 1 + src/types-internal.h | 11 +- src/util-internal.c | 116 ++------------- src/util-internal.h | 12 -- 7 files changed, 276 insertions(+), 448 deletions(-) diff --git a/src/general.c b/src/general.c index 8b04b08c..b44343b1 100644 --- a/src/general.c +++ b/src/general.c @@ -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) { diff --git a/src/request-internal.c b/src/request-internal.c index 8866edf1..d2b85434 100644 --- a/src/request-internal.c +++ b/src/request-internal.c @@ -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; } diff --git a/src/stub.c b/src/stub.c index 7512a01e..13f0a62e 100644 --- a/src/stub.c +++ b/src/stub.c @@ -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 diff --git a/src/stub.h b/src/stub.h index 7a26eb20..d96d1bb0 100644 --- a/src/stub.h +++ b/src/stub.h @@ -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 diff --git a/src/types-internal.h b/src/types-internal.h index 8ff2aa32..9558b84c 100644 --- a/src/types-internal.h +++ b/src/types-internal.h @@ -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; diff --git a/src/util-internal.c b/src/util-internal.c index 6e94691f..74925a6b 100644 --- a/src/util-internal.c +++ b/src/util-internal.c @@ -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 */ diff --git a/src/util-internal.h b/src/util-internal.h index 344c2ced..044ac5ca 100644 --- a/src/util-internal.h +++ b/src/util-internal.h @@ -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; \