Skip to content

Commit

Permalink
intermediate commit for privacy aware cookies; add fix to test case
Browse files Browse the repository at this point in the history
  • Loading branch information
TCY16 committed Jul 1, 2022
1 parent aebf1db commit f5f8060
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 18 deletions.
16 changes: 14 additions & 2 deletions iterator/iterator.c
Original file line number Diff line number Diff line change
Expand Up @@ -3829,6 +3829,17 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
if (edns.opt_list_in &&
(cookie = edns_list_get_option(edns.opt_list_in,
LDNS_EDNS_COOKIE))){
struct sockaddr_storage bound_addr;
socklen_t bound_addrlen = sizeof(struct sockaddr);

if(getsockname(qstate->reply->c->fd,
(struct sockaddr *) &bound_addr,
&bound_addrlen) != -1) {

log_addr(VERB_DETAIL, "!!!!! udp socket:", &bound_addr, bound_addrlen);
} else {
bound_addrlen = 0;
}
/* verify this is a 'complete cookie' (client+server)
* (RFC9018) with the length and store the complete
* cookie in the infra_cache. Do nothing when the cookie
Expand All @@ -3837,7 +3848,8 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
if (cookie->opt_len == 24 &&
infra_set_server_cookie(qstate->env->infra_cache,
&qstate->reply->addr, qstate->reply->addrlen,
iq->dp->name, iq->dp->namelen, cookie) >= 0) {
iq->dp->name, iq->dp->namelen, &bound_addr,
bound_addrlen, cookie) >= 0) {
/* log_hex() uses the verbosity levels of verbose() */
log_hex("complete cookie: ", cookie->opt_data,
cookie->opt_len);
Expand All @@ -3853,7 +3865,7 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
}
}

/* Copy the edns options we may got from the back end */
/* Copy the edns options we may have gotten from the back end */
if(edns.opt_list_in) {
qstate->edns_opts_back_in = edns_opt_copy_region(edns.opt_list_in,
qstate->region);
Expand Down
19 changes: 14 additions & 5 deletions services/cache/infra.c
Original file line number Diff line number Diff line change
Expand Up @@ -708,8 +708,7 @@ infra_edns_update(struct infra_cache* infra, struct sockaddr_storage* addr,

struct edns_cookie*
infra_get_cookie(struct infra_cache* infra, struct sockaddr_storage* addr,
socklen_t addrlen, uint8_t* name, size_t namelen,
time_t timenow)
socklen_t addrlen, uint8_t* name, size_t namelen, time_t timenow)
{
struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen,
name, namelen, 1);
Expand All @@ -725,7 +724,6 @@ infra_get_cookie(struct infra_cache* infra, struct sockaddr_storage* addr,
/* EDNS cookies have their own timeout logic controlled by the
* upstream, so we just copy the cookie from the old cache entry */
struct edns_cookie c = ((struct infra_data*)e->data)->cookie;
/* @TODO create logic for saving server cookie? -> not sure, find out */

/* create new cookie if the cache TTL expired */
data_entry_init(infra, e, timenow);
Expand All @@ -745,7 +743,9 @@ infra_get_cookie(struct infra_cache* infra, struct sockaddr_storage* addr,

int
infra_set_server_cookie(struct infra_cache* infra, struct sockaddr_storage* addr,
socklen_t addrlen, uint8_t* name, size_t namelen, struct edns_option* cookie)
socklen_t addrlen, uint8_t* name, size_t namelen,
struct sockaddr_storage* bound_addr, socklen_t bound_addrlen,
struct edns_option* cookie)
{
struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen,
name, namelen, 1);
Expand Down Expand Up @@ -778,6 +778,12 @@ infra_set_server_cookie(struct infra_cache* infra, struct sockaddr_storage* addr
return -1;
}

if (!(data->cookie.bound_addrlen == bound_addrlen) &&
memcpy(&data->cookie.bound_addr, bound_addr, bound_addrlen)){

// @TODO do something? this _should_ only happen on reloads?
}

/* the server cookie has changed, but the client cookie has not
* so we update the server cookie */
if (memcmp(data->cookie.data.complete+8,
Expand Down Expand Up @@ -811,7 +817,10 @@ infra_set_server_cookie(struct infra_cache* infra, struct sockaddr_storage* addr
/* else; store the client cookie */
memcpy(data->cookie.data.complete, cookie->opt_data, 24);
data->cookie.state = SERVER_COOKIE_LEARNED;

if (bound_addrlen > 0) {
memcpy(&data->cookie.bound_addr, bound_addr, bound_addrlen);
data->cookie.bound_addrlen = bound_addrlen;
}
verbose(VERB_QUERY, "storing received server cookie from upstream");
lock_rw_unlock(&e->lock);
return 1;
Expand Down
17 changes: 11 additions & 6 deletions services/cache/infra.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,17 @@ enum edns_cookie_state
};

/**
* Structure for an EDNS cookie (RFC9018) and it's internal state
* Structure for an EDNS cookie (RFC9018), it's internal state, and the
* the outgoing address that we bind this cookie to for privacy (RFC9018)
*/
struct edns_cookie {
enum edns_cookie_state state;
union edns_cookie_data data;
struct sockaddr_storage bound_addr;
socklen_t bound_addrlen;
};



/**
* Host information kept for every server, per zone.
*/
Expand Down Expand Up @@ -368,12 +370,12 @@ int infra_edns_update(struct infra_cache* infra,
* @param name: name of zone
* @param namelen: length of name
* @param timenow: what time it is now.
* @param outnet: outside network, with the outgoing IPs.
* @return: struct ends_cookie*
*/
struct edns_cookie*
infra_get_cookie(struct infra_cache* infra, struct sockaddr_storage* addr,
socklen_t addrlen, uint8_t* name, size_t namelen,
time_t timenow);
socklen_t addrlen, uint8_t* name, size_t namelen, time_t timenow);

/**
* Find the cookie entry in the cache and update it with to make a complete
Expand All @@ -386,12 +388,15 @@ infra_get_cookie(struct infra_cache* infra, struct sockaddr_storage* addr,
* @param name: name of zone
* @param namelen: length of name
* @param timenow: what time it is now.
* @param bound_addr: the outgoing address that we bind to this cookie
* @param bound_addr: the length of the bound address
* @param cookie: the EDNS cookie option we want to store.
* @return true if the complete cookie is stored, and false if it is not
*/
int infra_set_server_cookie(struct infra_cache* infra, struct sockaddr_storage* addr,
socklen_t addrlen, uint8_t* name, size_t namelen, struct edns_option* cookie);

socklen_t addrlen, uint8_t* name, size_t namelen,
struct sockaddr_storage* bound_addr, socklen_t bound_addrlen,
struct edns_option* cookie);

/**
* Get Lameness information and average RTT if host is in the cache.
Expand Down
50 changes: 47 additions & 3 deletions services/outside_network.c
Original file line number Diff line number Diff line change
Expand Up @@ -1376,6 +1376,7 @@ outnet_send_wait_udp(struct outside_network* outnet)
pend->pkt_len = 0;
log_assert(!pend->sq->busy);
pend->sq->busy = 1;

if(!randomize_and_send_udp(pend, outnet->udp_buff,
pend->timeout)) {
/* callback error on pending */
Expand Down Expand Up @@ -2011,6 +2012,25 @@ static int udp_connect_needs_log(int err)
return 1;
}

/** find the bound addr in the list of interfaces */
static int
get_bound_ip_if(struct port_if* ifs, int num_if,
struct sockaddr_storage bound_addr, socklen_t bound_addrlen,
struct port_if* pif)
{
int i = 0;

for (i = 0; i < num_if; i++) {
struct port_if iface = ifs[i];

if (iface.addrlen == bound_addrlen &&
memcmp(&iface.addr, &bound_addr, bound_addrlen)) {
pif = &iface;
return 1;
}
}
return 0;
}

/** Select random interface and port */
static int
Expand All @@ -2028,8 +2048,19 @@ select_ifport(struct outside_network* outnet, struct pending* pend,
log_assert(outnet->unused_fds);
tries = 0;
while(1) {
my_if = ub_random_max(outnet->rnd, num_if);
pif = &ifs[my_if];
/* if we have a bound IP address for the EDNS cookie in the
* message, use that interface */

log_err("!!!!! bound_addrlen: %d", pend->sq->bound_addrlen);
log_addr(VERB_ALGO, "!!!!! bound_addrlen:", &pend->sq->bound_addr, pend->sq->bound_addrlen);

// @TODO this shouldn't fail, as we leak the cookie then
if (!(pend->sq->bound_addrlen > 0 || get_bound_ip_if(ifs, num_if,
pend->sq->bound_addr, pend->sq->bound_addrlen, pif)
/* @TODO && cfg->upstream_cookies? */)) {
my_if = ub_random_max(outnet->rnd, num_if);
pif = &ifs[my_if];
}
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
if(outnet->udp_connect) {
/* if we connect() we cannot reuse fds for a port */
Expand All @@ -2052,6 +2083,9 @@ select_ifport(struct outside_network* outnet, struct pending* pend,
break;
}
}

log_err("!!!!! pif->inuse: %d, pif->maxout: %d", pif->inuse, pif->maxout);

/* try to open new port, if fails, loop to try again */
log_assert(pif->inuse < pif->maxout);
portno = pif->avail_ports[my_port - pif->inuse];
Expand Down Expand Up @@ -2186,6 +2220,7 @@ pending_udp_query(struct serviced_query* sq, struct sldns_buffer* packet,
pend->cb = cb;
pend->cb_arg = cb_arg;
pend->node.key = pend;

pend->timer = comm_timer_create(sq->outnet->base, pending_udp_timer_cb,
pend);
if(!pend->timer) {
Expand Down Expand Up @@ -2532,6 +2567,7 @@ serviced_create(struct outside_network* outnet, sldns_buffer* buff, int dnssec,
char* tls_auth_name, struct sockaddr_storage* addr, socklen_t addrlen,
uint8_t* zone, size_t zonelen, int qtype, struct edns_option* opt_list,
size_t pad_queries_block_size, struct alloc_cache* alloc,
struct sockaddr_storage bound_addr, socklen_t bound_addrlen,
struct regional* region)
{
struct serviced_query* sq = (struct serviced_query*)malloc(sizeof(*sq));
Expand Down Expand Up @@ -2593,6 +2629,8 @@ serviced_create(struct outside_network* outnet, sldns_buffer* buff, int dnssec,
sq->status = serviced_initial;
sq->retry = 0;
sq->to_be_deleted = 0;
sq->bound_addr = bound_addr;
sq->bound_addrlen = bound_addrlen;
sq->padding_block_size = pad_queries_block_size;
#ifdef UNBOUND_DEBUG
ins =
Expand Down Expand Up @@ -3353,6 +3391,8 @@ outnet_serviced_query(struct outside_network* outnet,
struct edns_option* backed_up_opt_list = qstate->edns_opts_back_out;
struct edns_option* per_upstream_opt_list = NULL;
time_t timenow = 0;
struct sockaddr_storage bound_addr;
socklen_t bound_addrlen;

/* If we have an already populated EDNS option list make a copy since
* we may now add upstream specific EDNS options. */
Expand Down Expand Up @@ -3397,11 +3437,15 @@ outnet_serviced_query(struct outside_network* outnet,
/* We known the complete cookie, so we attach it */
edns_opt_list_append(&per_upstream_opt_list, LDNS_EDNS_COOKIE,
24, cookie->data.complete, region);

} else if (cookie->state == SERVER_COOKIE_UNKNOWN) {
/* We know just client cookie, so we attach it */
edns_opt_list_append(&per_upstream_opt_list, LDNS_EDNS_COOKIE,
8, cookie->data.components.client, region);
} /* We ignore COOKIE_NOT_SUPPORTED */

bound_addr = cookie->bound_addr;
bound_addrlen = cookie->bound_addrlen;
}

serviced_gen_query(buff, qinfo->qname, qinfo->qname_len, qinfo->qtype,
Expand Down Expand Up @@ -3436,7 +3480,7 @@ outnet_serviced_query(struct outside_network* outnet,
per_upstream_opt_list,
( ssl_upstream && env->cfg->pad_queries
? env->cfg->pad_queries_block_size : 0 ),
env->alloc, region);
env->alloc, bound_addr, bound_addrlen, region);
if(!sq) {
if(check_ratelimit) {
infra_ratelimit_dec(env->infra_cache,
Expand Down
5 changes: 5 additions & 0 deletions services/outside_network.h
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,11 @@ struct serviced_query {
struct comm_timer* timer;
/** true if serviced_query is currently doing net I/O and may block */
int busy;
/** outbound IP addres that the query is bound to, to keep the EDNS client
* cookie private per IP address (RFC9018) */
struct sockaddr_storage bound_addr;
/** length of the bound outgoing IP address */
socklen_t bound_addrlen;
};

/**
Expand Down
3 changes: 1 addition & 2 deletions testcode/testpkts.c
Original file line number Diff line number Diff line change
Expand Up @@ -1894,9 +1894,8 @@ adjust_packet(struct entry* match, uint8_t** answer_pkt, size_t *answer_len,

reslen = origlen + 28;
} else if (sldns_read_uint16(walk_query+2) == 24) {
/* update the RDLEN and OPTLEN */
/* update the RDLEN */
sldns_write_uint16(rdlen_ptr_response, 28);
sldns_write_uint16(walk_response+2, 24);

/* we fake verification of the cookie and send
* it back like it's still valid. We renew the cookie
Expand Down

0 comments on commit f5f8060

Please sign in to comment.