added edns_client_subnet_private to getdns_context

https://tools.ietf.org/html/draft-ietf-dnsop-edns-client-subnet-04

Using the above spec, an intermediate resolver may forward a chunk of
the client's IP address to the authoritative resolver.

Setting edns_client_subnet_private to a getdns_context in stub mode
will indicate to the next-hop recursive resolver that the client
wishes to keep their address information private.
This commit is contained in:
Daniel Kahn Gillmor 2015-11-01 12:20:12 +09:00
parent 0b388872ea
commit df3725e635
7 changed files with 65 additions and 1 deletions

View File

@ -881,6 +881,7 @@ 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_ctx = NULL;
result->extension = &result->mini_event.loop;
@ -1897,6 +1898,26 @@ 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_extended_memory_functions
*
@ -2966,4 +2987,12 @@ 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;
}
/* context.c */

View File

@ -157,6 +157,7 @@ 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;
SSL_CTX* tls_ctx;
getdns_update_callback update_callback;

View File

@ -194,6 +194,11 @@ 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);
/**
* Pretty print the getdns_dict in a given buffer snprintf style.
@ -366,6 +371,8 @@ 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"
getdns_return_t
getdns_context_set_tls_authentication(

View File

@ -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
@ -36,6 +37,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

View File

@ -367,7 +367,7 @@ _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;
edns_maximum_udp_payload_size = with_opt &&
( edns_maximum_udp_payload_size == -1 ||
@ -437,6 +437,7 @@ _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;
/* will be set by caller */
result->user_pointer = NULL;

View File

@ -130,6 +130,20 @@ calc_new_cookie(getdns_upstream *upstream, uint8_t *cookie)
cookie[i % 8] ^= md_value[i];
}
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)
{
@ -702,6 +716,9 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq)
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.
@ -1153,6 +1170,9 @@ stub_tls_write(getdns_upstream *upstream, getdns_tcp_state *tcp,
/* 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;
}
pkt_len = netreq->response - netreq->query;
@ -1260,6 +1280,9 @@ stub_udp_write_cb(void *userarg)
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,

View File

@ -275,6 +275,7 @@ typedef struct getdns_dns_req {
int dnssec_return_only_secure;
int dnssec_return_validation_chain;
int edns_cookies;
int edns_client_subnet_private;
/* Internally used by return_validation_chain */
int dnssec_ok_checking_disabled;