mirror of https://github.com/getdnsapi/getdns.git
Merge pull request #119 from dkg/ietf94-privacy-hackathon
Thank you dkg! Great work! Interestingly you've put the configuration of those two features at "context" level. Since both options (just like cookies) relate to upstreams, I think they should be configurable per upstream as well (perhaps using the context settings as the defaults, over-loadable by those upstream options). With my cookie implementation, I've implemented activation with an extension, but cookies also relate to upstreams, so perhaps they should be enableable per upstream as well (and have a global over-loadable setting in context). Cheers, -- Willem
This commit is contained in:
commit
7230031c0a
|
@ -408,6 +408,9 @@ esac
|
|||
AC_DEFINE_UNQUOTED([EDNS_COOKIE_OPCODE], [10], [The edns cookie option code.])
|
||||
AC_DEFINE_UNQUOTED([EDNS_COOKIE_ROLLOVER_TIME], [(24 * 60 * 60)], [How often the edns client cookie is refreshed.])
|
||||
|
||||
AC_DEFINE_UNQUOTED([MAXIMUM_UPSTREAM_OPTION_SPACE], [3000], [limit for dynamically-generated DNS options])
|
||||
AC_DEFINE_UNQUOTED([EDNS_PADDING_OPCODE], [65461], [The experimental edns padding option code.])
|
||||
|
||||
my_with_libunbound=1
|
||||
AC_ARG_ENABLE(stub-only, AC_HELP_STRING([--enable-stub-only], [Restricts resolution modes to STUB (which will be the default mode). Removes the libunbound dependency.]))
|
||||
case "$enable_stub_only" in
|
||||
|
|
|
@ -881,6 +881,8 @@ getdns_context_create_with_extended_memory_functions(
|
|||
result->edns_extended_rcode = 0;
|
||||
result->edns_version = 0;
|
||||
result->edns_do_bit = 0;
|
||||
result->edns_client_subnet_private = 0;
|
||||
result->tls_query_padding_blocksize = 1; /* default is to not try to pad */
|
||||
result-> tls_ctx = NULL;
|
||||
|
||||
result->extension = &result->mini_event.loop;
|
||||
|
@ -1897,6 +1899,46 @@ getdns_context_set_edns_do_bit(struct getdns_context *context, uint8_t value)
|
|||
return GETDNS_RETURN_GOOD;
|
||||
} /* getdns_context_set_edns_do_bit */
|
||||
|
||||
/*
|
||||
* getdns_context_set_edns_client_subnet_private
|
||||
*
|
||||
*/
|
||||
getdns_return_t
|
||||
getdns_context_set_edns_client_subnet_private(struct getdns_context *context, uint8_t value)
|
||||
{
|
||||
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
|
||||
/* only allow 1 */
|
||||
if (value != 0 && value != 1) {
|
||||
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
|
||||
}
|
||||
|
||||
context->edns_client_subnet_private = value;
|
||||
|
||||
dispatch_updated(context, GETDNS_CONTEXT_CODE_EDNS_CLIENT_SUBNET_PRIVATE);
|
||||
|
||||
return GETDNS_RETURN_GOOD;
|
||||
} /* getdns_context_set_edns_client_subnet_private */
|
||||
|
||||
/*
|
||||
* getdns_context_set_tls_query_padding_blocksize
|
||||
*
|
||||
*/
|
||||
getdns_return_t
|
||||
getdns_context_set_tls_query_padding_blocksize(struct getdns_context *context, uint16_t value)
|
||||
{
|
||||
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
|
||||
/* only allow values between 0 and MAXIMUM_UPSTREAM_OPTION_SPACE - 4
|
||||
(4 is for the overhead of the option itself) */
|
||||
if (value > MAXIMUM_UPSTREAM_OPTION_SPACE - 4) {
|
||||
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
|
||||
}
|
||||
|
||||
context->tls_query_padding_blocksize = value;
|
||||
|
||||
dispatch_updated(context, GETDNS_CONTEXT_CODE_TLS_QUERY_PADDING_BLOCKSIZE);
|
||||
|
||||
return GETDNS_RETURN_GOOD;
|
||||
} /* getdns_context_set_tls_query_padding_blocksize */
|
||||
/*
|
||||
* getdns_context_set_extended_memory_functions
|
||||
*
|
||||
|
@ -2200,8 +2242,8 @@ _getdns_context_prepare_for_resolution(struct getdns_context *context,
|
|||
if(context->tls_ctx == NULL)
|
||||
return GETDNS_RETURN_BAD_CONTEXT;
|
||||
/* Be strict and only use the cipher suites recommended in RFC7525
|
||||
Unless we later fallback to oppotunistic. */
|
||||
const char* const PREFERRED_CIPHERS = "EECDH+aRSA+AESGCM:EDH+aRSA+AESGCM";
|
||||
Unless we later fallback to opportunistic. */
|
||||
const char* const PREFERRED_CIPHERS = "EECDH+aRSA+AESGCM:EECDH+aECDSA+AESGCM:EDH+aRSA+AESGCM";
|
||||
if (!SSL_CTX_set_cipher_list(context->tls_ctx, PREFERRED_CIPHERS))
|
||||
return GETDNS_RETURN_BAD_CONTEXT;
|
||||
if (!SSL_CTX_set_default_verify_paths(context->tls_ctx))
|
||||
|
@ -2966,4 +3008,20 @@ getdns_context_get_edns_do_bit(getdns_context *context, uint8_t* value) {
|
|||
return GETDNS_RETURN_GOOD;
|
||||
}
|
||||
|
||||
getdns_return_t
|
||||
getdns_context_get_edns_client_subnet_private(getdns_context *context, uint8_t* value) {
|
||||
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
|
||||
RETURN_IF_NULL(value, GETDNS_RETURN_INVALID_PARAMETER);
|
||||
*value = context->edns_client_subnet_private;
|
||||
return GETDNS_RETURN_GOOD;
|
||||
}
|
||||
|
||||
getdns_return_t
|
||||
getdns_context_get_tls_query_padding_blocksize(getdns_context *context, uint16_t* value) {
|
||||
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
|
||||
RETURN_IF_NULL(value, GETDNS_RETURN_INVALID_PARAMETER);
|
||||
*value = context->tls_query_padding_blocksize;
|
||||
return GETDNS_RETURN_GOOD;
|
||||
}
|
||||
|
||||
/* context.c */
|
||||
|
|
|
@ -157,6 +157,8 @@ struct getdns_context {
|
|||
uint8_t edns_version;
|
||||
uint8_t edns_do_bit;
|
||||
int edns_maximum_udp_payload_size; /* -1 is unset */
|
||||
uint8_t edns_client_subnet_private;
|
||||
uint16_t tls_query_padding_blocksize;
|
||||
SSL_CTX* tls_ctx;
|
||||
|
||||
getdns_update_callback update_callback;
|
||||
|
|
|
@ -194,6 +194,16 @@ getdns_context_get_edns_version(getdns_context *context, uint8_t* value);
|
|||
getdns_return_t
|
||||
getdns_context_get_edns_do_bit(getdns_context *context, uint8_t* value);
|
||||
|
||||
getdns_return_t
|
||||
getdns_context_set_edns_client_subnet_private(getdns_context *context, uint8_t value);
|
||||
getdns_return_t
|
||||
getdns_context_get_edns_client_subnet_private(getdns_context *context, uint8_t* value);
|
||||
|
||||
getdns_return_t
|
||||
getdns_context_set_tls_query_padding_blocksize(getdns_context *context, uint16_t value);
|
||||
getdns_return_t
|
||||
getdns_context_get_tls_query_padding_blocksize(getdns_context *context, uint16_t* value);
|
||||
|
||||
|
||||
/**
|
||||
* Pretty print the getdns_dict in a given buffer snprintf style.
|
||||
|
@ -366,6 +376,10 @@ typedef enum getdns_tls_authentication_t {
|
|||
|
||||
#define GETDNS_CONTEXT_CODE_TLS_AUTHENTICATION 618
|
||||
#define GETDNS_CONTEXT_CODE_TLS_AUTHENTICATION_TEXT "Change related to getdns_context_set_tls_authentication"
|
||||
#define GETDNS_CONTEXT_CODE_EDNS_CLIENT_SUBNET_PRIVATE 619
|
||||
#define GETDNS_CONTEXT_CODE_EDNS_CLIENT_SUBNET_PRIVATE_TEXT "Change related to getdns_context_set_edns_client_subnet_private"
|
||||
#define GETDNS_CONTEXT_CODE_TLS_QUERY_PADDING_BLOCKSIZE 620
|
||||
#define GETDNS_CONTEXT_CODE_TLS_QUERY_PADDING_BLOCKSIZE_TEXT "Change related to getdns_context_set_tls_query_padding_blocksize"
|
||||
|
||||
getdns_return_t
|
||||
getdns_context_set_tls_authentication(
|
||||
|
|
|
@ -13,6 +13,7 @@ getdns_context_get_dnssec_allowed_skew
|
|||
getdns_context_get_dnssec_trust_anchors
|
||||
getdns_context_get_dns_transport
|
||||
getdns_context_get_dns_transport_list
|
||||
getdns_context_get_edns_client_subnet_private
|
||||
getdns_context_get_edns_do_bit
|
||||
getdns_context_get_edns_extended_rcode
|
||||
getdns_context_get_edns_maximum_udp_payload_size
|
||||
|
@ -25,6 +26,7 @@ getdns_context_get_num_pending_requests
|
|||
getdns_context_get_resolution_type
|
||||
getdns_context_get_suffix
|
||||
getdns_context_get_timeout
|
||||
getdns_context_get_tls_query_padding_blocksize
|
||||
getdns_context_get_update_callback
|
||||
getdns_context_get_upstream_recursive_servers
|
||||
getdns_context_process_async
|
||||
|
@ -36,6 +38,7 @@ getdns_context_set_dnssec_allowed_skew
|
|||
getdns_context_set_dnssec_trust_anchors
|
||||
getdns_context_set_dns_transport
|
||||
getdns_context_set_dns_transport_list
|
||||
getdns_context_set_edns_client_subnet_private
|
||||
getdns_context_set_edns_do_bit
|
||||
getdns_context_set_edns_extended_rcode
|
||||
getdns_context_set_edns_maximum_udp_payload_size
|
||||
|
@ -52,6 +55,7 @@ getdns_context_set_return_dnssec_status
|
|||
getdns_context_set_suffix
|
||||
getdns_context_set_timeout
|
||||
getdns_context_set_tls_authentication
|
||||
getdns_context_set_tls_query_padding_blocksize
|
||||
getdns_context_set_update_callback
|
||||
getdns_context_set_upstream_recursive_servers
|
||||
getdns_context_set_use_threads
|
||||
|
|
|
@ -113,6 +113,7 @@ network_req_init(getdns_network_req *net_req, getdns_dns_req *owner,
|
|||
? edns_maximum_udp_payload_size : 1432;
|
||||
net_req->write_queue_tail = NULL;
|
||||
net_req->response_len = 0;
|
||||
net_req->base_query_option_sz = opt_options_size;
|
||||
|
||||
net_req->wire_data_sz = wire_data_sz;
|
||||
if (max_query_sz) {
|
||||
|
@ -184,6 +185,75 @@ network_req_init(getdns_network_req *net_req, getdns_dns_req *owner,
|
|||
return r;
|
||||
}
|
||||
|
||||
/* req->opt + 9 is the length; req->opt + 11 is the start of the
|
||||
options.
|
||||
|
||||
clear_upstream_options() goes back to the per-query options.
|
||||
*/
|
||||
|
||||
void
|
||||
_getdns_network_req_clear_upstream_options(getdns_network_req * req)
|
||||
{
|
||||
size_t pktlen;
|
||||
if (req->opt) {
|
||||
gldns_write_uint16(req->opt + 9, req->base_query_option_sz);
|
||||
req->response = req->opt + 11 + req->base_query_option_sz;
|
||||
pktlen = req->response - req->query;
|
||||
gldns_write_uint16(req->query - 2, pktlen);
|
||||
}
|
||||
}
|
||||
|
||||
/* add_upstream_option appends an option that is derived at send time.
|
||||
(you can send data as NULL and it will fill with all zeros) */
|
||||
getdns_return_t
|
||||
_getdns_network_req_add_upstream_option(getdns_network_req * req, uint16_t code, uint16_t sz, const void* data)
|
||||
{
|
||||
uint16_t oldlen;
|
||||
uint32_t newlen;
|
||||
uint32_t pktlen;
|
||||
size_t cur_upstream_option_sz;
|
||||
|
||||
/* if no options are set, we can't add upstream options */
|
||||
if (!req->opt)
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
|
||||
/* if TCP, no overflow allowed for length field
|
||||
https://tools.ietf.org/html/rfc1035#section-4.2.2 */
|
||||
pktlen = req->response - req->query;
|
||||
pktlen += 4 + sz;
|
||||
if (pktlen > UINT16_MAX)
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
|
||||
/* no overflow allowed for OPT size either (maybe this is overkill
|
||||
given the above check?) */
|
||||
oldlen = gldns_read_uint16(req->opt + 9);
|
||||
newlen = oldlen + 4 + sz;
|
||||
if (newlen > UINT16_MAX)
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
|
||||
/* avoid overflowing MAXIMUM_UPSTREAM_OPTION_SPACE */
|
||||
cur_upstream_option_sz = (size_t)oldlen - req->base_query_option_sz;
|
||||
if (cur_upstream_option_sz + 4 + sz > MAXIMUM_UPSTREAM_OPTION_SPACE)
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
|
||||
/* actually add the option: */
|
||||
gldns_write_uint16(req->opt + 11 + oldlen, code);
|
||||
gldns_write_uint16(req->opt + 11 + oldlen + 2, sz);
|
||||
if (data != NULL)
|
||||
memcpy(req->opt + 11 + oldlen + 4, data, sz);
|
||||
else
|
||||
memset(req->opt + 11 + oldlen + 4, 0, sz);
|
||||
gldns_write_uint16(req->opt + 9, newlen);
|
||||
|
||||
/* the response should start right after the options end: */
|
||||
req->response = req->opt + 11 + newlen;
|
||||
|
||||
/* for TCP, adjust the size of the wire format itself: */
|
||||
gldns_write_uint16(req->query - 2, pktlen);
|
||||
|
||||
return GETDNS_RETURN_GOOD;
|
||||
}
|
||||
|
||||
void
|
||||
_getdns_dns_req_free(getdns_dns_req * req)
|
||||
{
|
||||
|
@ -297,7 +367,8 @@ _getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop,
|
|||
|
||||
with_opt = edns_do_bit != 0 || edns_maximum_udp_payload_size != 512 ||
|
||||
edns_extended_rcode != 0 || edns_version != 0 || noptions ||
|
||||
edns_cookies;
|
||||
edns_cookies || context->edns_client_subnet_private ||
|
||||
context->tls_query_padding_blocksize > 1;
|
||||
|
||||
edns_maximum_udp_payload_size = with_opt &&
|
||||
( edns_maximum_udp_payload_size == -1 ||
|
||||
|
@ -323,12 +394,7 @@ _getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop,
|
|||
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) */
|
||||
+ ( !edns_cookies ? 0
|
||||
: 2 /* EDNS0 Option Code */
|
||||
+ 2 /* Option length = 8 + 16 = 24 */
|
||||
+ 8 /* client cookie */
|
||||
+ 16 /* server cookie */
|
||||
)
|
||||
+ MAXIMUM_UPSTREAM_OPTION_SPACE
|
||||
/* TODO: TSIG */
|
||||
+ 7) / 8 * 8;
|
||||
}
|
||||
|
@ -372,6 +438,8 @@ _getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop,
|
|||
result->dnssec_return_only_secure = dnssec_return_only_secure;
|
||||
result->dnssec_return_validation_chain = dnssec_return_validation_chain;
|
||||
result->edns_cookies = edns_cookies;
|
||||
result->edns_client_subnet_private = context->edns_client_subnet_private;
|
||||
result->tls_query_padding_blocksize = context->tls_query_padding_blocksize;
|
||||
|
||||
/* will be set by caller */
|
||||
result->user_pointer = NULL;
|
||||
|
|
121
src/stub.c
121
src/stub.c
|
@ -46,6 +46,7 @@
|
|||
#include "util-internal.h"
|
||||
#include "general.h"
|
||||
|
||||
#define STUB_OUT_OF_OPTIONS -5 /* upstream options exceeded MAXIMUM_UPSTREAM_OPTION_SPACE */
|
||||
#define STUB_TLS_SETUP_ERROR -4
|
||||
#define STUB_TCP_AGAIN -3
|
||||
#define STUB_TCP_ERROR -2
|
||||
|
@ -129,9 +130,27 @@ calc_new_cookie(getdns_upstream *upstream, uint8_t *cookie)
|
|||
cookie[i % 8] ^= md_value[i];
|
||||
}
|
||||
|
||||
static uint8_t *
|
||||
attach_edns_cookie(getdns_upstream *upstream, uint8_t *opt)
|
||||
static getdns_return_t
|
||||
attach_edns_client_subnet_private(getdns_network_req *req)
|
||||
{
|
||||
/* see
|
||||
* https://tools.ietf.org/html/draft-ietf-dnsop-edns-client-subnet-04#section-6 */
|
||||
/* all-zeros is a request to not leak the data further: */
|
||||
/* "\x00\x00" FAMILY: 0 (because no address) */
|
||||
/* "\x00" SOURCE PREFIX-LENGTH: 0 */
|
||||
/* "\x00"; SCOPE PREFIX-LENGTH: 0 */
|
||||
return _getdns_network_req_add_upstream_option(req,
|
||||
GLDNS_EDNS_CLIENT_SUBNET,
|
||||
4, NULL);
|
||||
}
|
||||
|
||||
static getdns_return_t
|
||||
attach_edns_cookie(getdns_network_req *req)
|
||||
{
|
||||
getdns_upstream *upstream = req->upstream;
|
||||
uint16_t sz;
|
||||
void* val;
|
||||
uint8_t buf[8 + 32]; /* server cookies can be no larger than 32 bytes */
|
||||
rollover_secret();
|
||||
|
||||
if (!upstream->has_client_cookie) {
|
||||
|
@ -139,12 +158,8 @@ attach_edns_cookie(getdns_upstream *upstream, uint8_t *opt)
|
|||
upstream->secret = secret;
|
||||
upstream->has_client_cookie = 1;
|
||||
|
||||
gldns_write_uint16(opt + 9, 12); /* rdata len */
|
||||
gldns_write_uint16(opt + 11, EDNS_COOKIE_OPCODE);
|
||||
gldns_write_uint16(opt + 13, 8); /* opt len */
|
||||
memcpy(opt + 15, upstream->client_cookie, 8);
|
||||
return opt + 23;
|
||||
|
||||
sz = 8;
|
||||
val = upstream->client_cookie;
|
||||
} else if (upstream->secret != secret) {
|
||||
memcpy( upstream->prev_client_cookie
|
||||
, upstream->client_cookie, 8);
|
||||
|
@ -152,29 +167,19 @@ attach_edns_cookie(getdns_upstream *upstream, uint8_t *opt)
|
|||
calc_new_cookie(upstream, upstream->client_cookie);
|
||||
upstream->secret = secret;
|
||||
|
||||
gldns_write_uint16(opt + 9, 12); /* rdata len */
|
||||
gldns_write_uint16(opt + 11, EDNS_COOKIE_OPCODE);
|
||||
gldns_write_uint16(opt + 13, 8); /* opt len */
|
||||
memcpy(opt + 15, upstream->client_cookie, 8);
|
||||
return opt + 23;
|
||||
|
||||
sz = 8;
|
||||
val = upstream->client_cookie;
|
||||
} else if (!upstream->has_server_cookie) {
|
||||
gldns_write_uint16(opt + 9, 12); /* rdata len */
|
||||
gldns_write_uint16(opt + 11, EDNS_COOKIE_OPCODE);
|
||||
gldns_write_uint16(opt + 13, 8); /* opt len */
|
||||
memcpy(opt + 15, upstream->client_cookie, 8);
|
||||
return opt + 23;
|
||||
sz = 8;
|
||||
val = upstream->client_cookie;
|
||||
} else {
|
||||
gldns_write_uint16( opt + 9, 12 /* rdata len */
|
||||
+ upstream->server_cookie_len);
|
||||
gldns_write_uint16(opt + 11, EDNS_COOKIE_OPCODE);
|
||||
gldns_write_uint16(opt + 13, 8 /* opt len */
|
||||
+ upstream->server_cookie_len);
|
||||
memcpy(opt + 15, upstream->client_cookie, 8);
|
||||
memcpy(opt + 23, upstream->server_cookie
|
||||
, upstream->server_cookie_len);
|
||||
return opt + 23+ upstream->server_cookie_len;
|
||||
sz = 8 + upstream->server_cookie_len;
|
||||
memcpy(buf, upstream->client_cookie, 8);
|
||||
memcpy(buf+8, upstream->server_cookie, upstream->server_cookie_len);
|
||||
val = buf;
|
||||
}
|
||||
return _getdns_network_req_add_upstream_option(req, EDNS_COOKIE_OPCODE, sz, val);
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -681,7 +686,7 @@ static int
|
|||
stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq)
|
||||
{
|
||||
|
||||
size_t pkt_len = netreq->response - netreq->query;
|
||||
size_t pkt_len;
|
||||
ssize_t written;
|
||||
uint16_t query_id;
|
||||
intptr_t query_id_intptr;
|
||||
|
@ -704,16 +709,18 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq)
|
|||
|
||||
GLDNS_ID_SET(netreq->query, query_id);
|
||||
if (netreq->opt) {
|
||||
_getdns_network_req_clear_upstream_options(netreq);
|
||||
/* no limits on the max udp payload size with tcp */
|
||||
gldns_write_uint16(netreq->opt + 3, 65535);
|
||||
|
||||
if (netreq->owner->edns_cookies) {
|
||||
netreq->response = attach_edns_cookie(
|
||||
netreq->upstream, netreq->opt);
|
||||
pkt_len = netreq->response - netreq->query;
|
||||
gldns_write_uint16(netreq->query - 2, pkt_len);
|
||||
}
|
||||
if (netreq->owner->edns_cookies)
|
||||
if (attach_edns_cookie(netreq))
|
||||
return STUB_OUT_OF_OPTIONS;
|
||||
if (netreq->owner->edns_client_subnet_private)
|
||||
if (attach_edns_client_subnet_private(netreq))
|
||||
return STUB_OUT_OF_OPTIONS;
|
||||
}
|
||||
pkt_len = netreq->response - netreq->query;
|
||||
/* We have an initialized packet buffer.
|
||||
* Lets see how much of it we can write
|
||||
*/
|
||||
|
@ -908,7 +915,7 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream)
|
|||
return NULL;
|
||||
}
|
||||
#endif
|
||||
/* Allow fallback to oppotunisitc if settings permit it*/
|
||||
/* Allow fallback to opportunistic if settings permit it*/
|
||||
if (dnsreq->netreqs[0]->tls_auth_min == GETDNS_AUTHENTICATION_HOSTNAME)
|
||||
SSL_set_verify(ssl, SSL_VERIFY_PEER, tls_verify_callback);
|
||||
else {
|
||||
|
@ -923,6 +930,7 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream)
|
|||
upstream->tls_auth_failed = 1;
|
||||
return NULL;
|
||||
} else {
|
||||
/* no hostname verification, so we will make opportunistic connections */
|
||||
DEBUG_STUB("--- %s, PROCEEDING WITHOUT HOSTNAME VALIDATION!!\n", __FUNCTION__);
|
||||
upstream->tls_auth_failed = 1;
|
||||
SSL_set_verify(ssl, SSL_VERIFY_NONE, tls_verify_callback_with_fallback);
|
||||
|
@ -1125,11 +1133,12 @@ static int
|
|||
stub_tls_write(getdns_upstream *upstream, getdns_tcp_state *tcp,
|
||||
getdns_network_req *netreq)
|
||||
{
|
||||
size_t pkt_len = netreq->response - netreq->query;
|
||||
size_t pkt_len;
|
||||
ssize_t written;
|
||||
uint16_t query_id;
|
||||
intptr_t query_id_intptr;
|
||||
SSL* tls_obj = upstream->tls_obj;
|
||||
uint16_t padding_sz;
|
||||
|
||||
int q = tls_connected(upstream);
|
||||
if (q != 0)
|
||||
|
@ -1155,10 +1164,30 @@ stub_tls_write(getdns_upstream *upstream, getdns_tcp_state *tcp,
|
|||
&netreq->upstream->netreq_by_query_id, &netreq->node));
|
||||
|
||||
GLDNS_ID_SET(netreq->query, query_id);
|
||||
if (netreq->opt)
|
||||
if (netreq->opt) {
|
||||
_getdns_network_req_clear_upstream_options(netreq);
|
||||
/* no limits on the max udp payload size with tcp */
|
||||
gldns_write_uint16(netreq->opt + 3, 65535);
|
||||
/* we do not edns_cookie over TLS, since TLS
|
||||
* provides stronger guarantees than cookies
|
||||
* already */
|
||||
if (netreq->owner->edns_client_subnet_private)
|
||||
if (attach_edns_client_subnet_private(netreq))
|
||||
return STUB_OUT_OF_OPTIONS;
|
||||
if (netreq->owner->tls_query_padding_blocksize > 1) {
|
||||
pkt_len = netreq->response - netreq->query;
|
||||
pkt_len += 4; /* this accounts for the OPTION-CODE and OPTION-LENGTH of the padding */
|
||||
padding_sz = pkt_len % netreq->owner->tls_query_padding_blocksize;
|
||||
if (padding_sz)
|
||||
padding_sz = netreq->owner->tls_query_padding_blocksize - padding_sz;
|
||||
if (_getdns_network_req_add_upstream_option(netreq,
|
||||
EDNS_PADDING_OPCODE,
|
||||
padding_sz, NULL))
|
||||
return STUB_OUT_OF_OPTIONS;
|
||||
}
|
||||
}
|
||||
|
||||
pkt_len = netreq->response - netreq->query;
|
||||
/* We have an initialized packet buffer.
|
||||
* Lets see how much of it we can write */
|
||||
|
||||
|
@ -1247,25 +1276,27 @@ stub_udp_write_cb(void *userarg)
|
|||
DEBUG_STUB("%s\n", __FUNCTION__);
|
||||
getdns_network_req *netreq = (getdns_network_req *)userarg;
|
||||
getdns_dns_req *dnsreq = netreq->owner;
|
||||
size_t pkt_len = netreq->response - netreq->query;
|
||||
size_t pkt_len;
|
||||
|
||||
GETDNS_CLEAR_EVENT(dnsreq->loop, &netreq->event);
|
||||
|
||||
netreq->query_id = arc4random();
|
||||
GLDNS_ID_SET(netreq->query, netreq->query_id);
|
||||
if (netreq->opt) {
|
||||
_getdns_network_req_clear_upstream_options(netreq);
|
||||
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 (netreq->owner->edns_cookies) {
|
||||
netreq->response = attach_edns_cookie(
|
||||
netreq->upstream, netreq->opt);
|
||||
pkt_len = netreq->response - netreq->query;
|
||||
}
|
||||
if (netreq->owner->edns_cookies)
|
||||
if (attach_edns_cookie(netreq))
|
||||
return; /* too many upstream options */
|
||||
if (netreq->owner->edns_client_subnet_private)
|
||||
if (attach_edns_client_subnet_private(netreq))
|
||||
return; /* too many upstream options */
|
||||
}
|
||||
|
||||
pkt_len = netreq->response - netreq->query;
|
||||
if ((ssize_t)pkt_len != sendto(netreq->fd, netreq->query, pkt_len, 0,
|
||||
(struct sockaddr *)&netreq->upstream->addr,
|
||||
netreq->upstream->addr_len)) {
|
||||
|
|
|
@ -365,6 +365,54 @@
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (getdns_context_set_context_update_callback_20)
|
||||
{
|
||||
/*
|
||||
* Create a context by calling getdns_context_create()
|
||||
* Define a callback routine for context changes and call getdns_context_set_context_update_callback() so that it gets called when there are context changes
|
||||
* Call getdns_context_set_edns_client_subnet_private() setting to 1
|
||||
* expect: GETDNS_CONTEXT_CODE_EDNS_CLIENT_SUBNET_PRIVATE
|
||||
*/
|
||||
struct getdns_context *context = NULL;
|
||||
CONTEXT_CREATE(TRUE);
|
||||
|
||||
ASSERT_RC(getdns_context_set_context_update_callback(context, update_callbackfn),
|
||||
GETDNS_RETURN_GOOD, "Return code from getdns_context_set_context_update_callback()");
|
||||
|
||||
expected_changed_item = GETDNS_CONTEXT_CODE_EDNS_CLIENT_SUBNET_PRIVATE;
|
||||
|
||||
ASSERT_RC(getdns_context_set_edns_client_subnet_private(context, 1),
|
||||
GETDNS_RETURN_GOOD, "Return code from getdns_context_set_edns_client_subnet_private()");
|
||||
|
||||
CONTEXT_DESTROY;
|
||||
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (getdns_context_set_context_update_callback_21)
|
||||
{
|
||||
/*
|
||||
* Create a context by calling getdns_context_create()
|
||||
* Define a callback routine for context changes and call getdns_context_set_context_update_callback() so that it gets called when there are context changes
|
||||
* Call getdns_context_set_edns_client_subnet_private() setting to 1
|
||||
* expect: GETDNS_CONTEXT_CODE_TLS_QUERY_PADDING_BLOCKSIZE
|
||||
*/
|
||||
struct getdns_context *context = NULL;
|
||||
CONTEXT_CREATE(TRUE);
|
||||
|
||||
ASSERT_RC(getdns_context_set_context_update_callback(context, update_callbackfn),
|
||||
GETDNS_RETURN_GOOD, "Return code from getdns_context_set_context_update_callback()");
|
||||
|
||||
expected_changed_item = GETDNS_CONTEXT_CODE_TLS_QUERY_PADDING_BLOCKSIZE;
|
||||
|
||||
ASSERT_RC(getdns_context_set_tls_query_padding_blocksize(context, 1400),
|
||||
GETDNS_RETURN_GOOD, "Return code from getdns_context_set_tls_query_padding_blocksize()");
|
||||
|
||||
CONTEXT_DESTROY;
|
||||
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
|
||||
Suite *
|
||||
|
@ -391,6 +439,8 @@
|
|||
tcase_add_test(tc_pos, getdns_context_set_context_update_callback_17);
|
||||
tcase_add_test(tc_pos, getdns_context_set_context_update_callback_18);
|
||||
tcase_add_test(tc_pos, getdns_context_set_context_update_callback_19);
|
||||
tcase_add_test(tc_pos, getdns_context_set_context_update_callback_20);
|
||||
tcase_add_test(tc_pos, getdns_context_set_context_update_callback_21);
|
||||
suite_add_tcase(s, tc_pos);
|
||||
|
||||
return s;
|
||||
|
|
|
@ -261,7 +261,7 @@ static char *name;
|
|||
static getdns_context *context;
|
||||
static getdns_dict *extensions;
|
||||
static uint16_t request_type = GETDNS_RRTYPE_NS;
|
||||
static int timeout, edns0_size;
|
||||
static int timeout, edns0_size, padding_blocksize;
|
||||
static int async = 0, interactive = 0;
|
||||
static enum { GENERAL, ADDRESS, HOSTNAME, SERVICE } calltype = GENERAL;
|
||||
|
||||
|
@ -368,6 +368,7 @@ print_usage(FILE *out, const char *progname)
|
|||
fprintf(out, "\t-A\taddress lookup (<type> is ignored)\n");
|
||||
fprintf(out, "\t-B\tBatch mode. Schedule all messages before processing responses.\n");
|
||||
fprintf(out, "\t-b <bufsize>\tSet edns0 max_udp_payload size\n");
|
||||
fprintf(out, "\t-c\tSend Client Subnet privacy request\n");
|
||||
fprintf(out, "\t-D\tSet edns0 do bit\n");
|
||||
fprintf(out, "\t-d\tclear edns0 do bit\n");
|
||||
fprintf(out, "\t-e <idle_timeout>\tSet idle timeout in miliseconds\n");
|
||||
|
@ -383,6 +384,7 @@ print_usage(FILE *out, const char *progname)
|
|||
fprintf(out, "\t-n\tSet TLS authentication mode to NONE (default)\n");
|
||||
fprintf(out, "\t-m\tSet TLS authentication mode to HOSTNAME\n");
|
||||
fprintf(out, "\t-p\tPretty print response dict\n");
|
||||
fprintf(out, "\t-P <blocksize>\tPad TLS queries to a multiple of blocksize\n");
|
||||
fprintf(out, "\t-r\tSet recursing resolution type\n");
|
||||
fprintf(out, "\t-q\tQuiet mode - don't print response\n");
|
||||
fprintf(out, "\t-s\tSet stub resolution type (default = recursing)\n");
|
||||
|
@ -655,6 +657,10 @@ getdns_return_t parse_args(int argc, char **argv)
|
|||
getdns_context_set_edns_maximum_udp_payload_size(
|
||||
context, (uint16_t) edns0_size);
|
||||
goto next;
|
||||
case 'c':
|
||||
if (getdns_context_set_edns_client_subnet_private(context, 1))
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
break;
|
||||
case 'D':
|
||||
(void) getdns_context_set_edns_do_bit(context, 1);
|
||||
break;
|
||||
|
@ -702,6 +708,23 @@ getdns_return_t parse_args(int argc, char **argv)
|
|||
getdns_context_set_tls_authentication(context,
|
||||
GETDNS_AUTHENTICATION_HOSTNAME);
|
||||
break;
|
||||
case 'P':
|
||||
if (c[1] != 0 || ++i >= argc || !*argv[i]) {
|
||||
fprintf(stderr, "tls_query_padding_blocksize "
|
||||
"expected after -P\n");
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
}
|
||||
padding_blocksize = strtol(argv[i], &endptr, 10);
|
||||
if (*endptr || padding_blocksize < 0) {
|
||||
fprintf(stderr, "non-negative "
|
||||
"numeric padding blocksize expected "
|
||||
"after -P\n");
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
}
|
||||
if (getdns_context_set_tls_query_padding_blocksize(
|
||||
context, padding_blocksize))
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
goto next;
|
||||
case 'p':
|
||||
json = 0;
|
||||
case 'q':
|
||||
|
|
|
@ -232,6 +232,19 @@ typedef struct getdns_network_req
|
|||
*/
|
||||
uint8_t *query;
|
||||
uint8_t *opt; /* offset of OPT RR in query */
|
||||
|
||||
/* each network_req has a set of base options that are
|
||||
* specific to the query, which are static and included when
|
||||
* the network_req is created. When the query is sent out to
|
||||
* a given upstream, some additional options are added that
|
||||
* are specific to the upstream. There can be at most
|
||||
* GETDNS_MAXIMUM_UPSTREAM_OPTION_SPACE bytes of
|
||||
* upstream-specific options.
|
||||
|
||||
* use _getdns_network_req_clear_upstream_options() and
|
||||
* _getdns_network_req_add_upstream_option() to fiddle with the
|
||||
*/
|
||||
size_t base_query_option_sz;
|
||||
size_t response_len;
|
||||
uint8_t *response;
|
||||
size_t wire_data_sz;
|
||||
|
@ -262,6 +275,8 @@ typedef struct getdns_dns_req {
|
|||
int dnssec_return_only_secure;
|
||||
int dnssec_return_validation_chain;
|
||||
int edns_cookies;
|
||||
int edns_client_subnet_private;
|
||||
uint16_t tls_query_padding_blocksize;
|
||||
|
||||
/* Internally used by return_validation_chain */
|
||||
int dnssec_ok_checking_disabled;
|
||||
|
@ -344,5 +359,10 @@ getdns_dns_req *_getdns_dns_req_new(getdns_context *context, getdns_eventloop *l
|
|||
|
||||
void _getdns_dns_req_free(getdns_dns_req * req);
|
||||
|
||||
/* network request utils */
|
||||
getdns_return_t _getdns_network_req_add_upstream_option(getdns_network_req * req,
|
||||
uint16_t code, uint16_t sz, const void* data);
|
||||
void _getdns_network_req_clear_upstream_options(getdns_network_req * req);
|
||||
|
||||
#endif
|
||||
/* types-internal.h */
|
||||
|
|
Loading…
Reference in New Issue