mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-09-29 13:14:56 +02:00
store complete cookie when receiving from downstream. Add function through search through an edns_option list
This commit is contained in:
@@ -3764,6 +3764,7 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
{
|
||||
struct msg_parse* prs;
|
||||
struct edns_data edns;
|
||||
struct edns_option* cookie;
|
||||
sldns_buffer* pkt;
|
||||
|
||||
verbose(VERB_ALGO, "process_response: new external response event");
|
||||
@@ -3823,6 +3824,22 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
goto handle_it;
|
||||
}
|
||||
|
||||
if((cookie = edns_list_get_option(edns.opt_list_in, 10 /*@TODO change to cookie with downstream merge*/))) {
|
||||
/* verify this is a 'complete cookie' (RFC9018) with the length */
|
||||
if (cookie->opt_len == 24) {
|
||||
/* store the complete cookie in the infra_cache */
|
||||
infra_set_server_cookie(qstate->env->infra_cache,
|
||||
&qstate->reply->addr, qstate->reply->addrlen,
|
||||
iq->dp->name, iq->dp->namelen, cookie);
|
||||
|
||||
log_hex("complete cookie: ", cookie->opt_data,
|
||||
cookie->opt_len);
|
||||
} else {
|
||||
// @TODO just log error? set state to COOKIE_NOT_SUPPORTED?
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Copy the edns options we may got from the back end */
|
||||
if(edns.opt_list_in) {
|
||||
qstate->edns_opts_back_in = edns_opt_copy_region(edns.opt_list_in,
|
||||
|
||||
Vendored
+33
-5
@@ -697,16 +697,16 @@ 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* nm, size_t nmlen,
|
||||
socklen_t addrlen, uint8_t* name, size_t namelen,
|
||||
time_t timenow)
|
||||
{
|
||||
struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen,
|
||||
nm, nmlen, 1);
|
||||
name, namelen, 1);
|
||||
struct infra_data* data;
|
||||
int needtoinsert = 0;
|
||||
|
||||
if(!e) {
|
||||
if(!(e = new_entry(infra, addr, addrlen, nm, nmlen, timenow))) {
|
||||
if(!(e = new_entry(infra, addr, addrlen, name, namelen, timenow))) {
|
||||
return 0;
|
||||
}
|
||||
needtoinsert = 1;
|
||||
@@ -717,8 +717,7 @@ infra_get_cookie(struct infra_cache* infra, struct sockaddr_storage* addr,
|
||||
data_entry_init(infra, e, timenow);
|
||||
}
|
||||
|
||||
/* we have an entry; update the rtt, and the ttl */
|
||||
data = (struct infra_data*)e->data;
|
||||
data = (struct infra_data*) e->data;
|
||||
|
||||
if(needtoinsert) {
|
||||
slabhash_insert(infra->hosts, e->hash, e, e->data, NULL);
|
||||
@@ -729,6 +728,35 @@ infra_get_cookie(struct infra_cache* infra, struct sockaddr_storage* addr,
|
||||
return &data->cookie;
|
||||
}
|
||||
|
||||
void
|
||||
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)
|
||||
{
|
||||
struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen,
|
||||
name, namelen, 1);
|
||||
struct infra_data* data;
|
||||
|
||||
/* cookie length verification should be checked and handled by caller */
|
||||
assert(cookie->opt_len == 24);
|
||||
|
||||
/* the client cookie was set on the outgoing upstream, so the entry
|
||||
* must exists here */
|
||||
assert(e);
|
||||
|
||||
data = (struct infra_data*) e->data;
|
||||
|
||||
/* check if we already know the complete cookie */
|
||||
if (data->cookie.state == SERVER_COOKIE_UNKNOWN) {
|
||||
memcpy(data->cookie.data.complete, cookie->opt_data, 24);
|
||||
data->cookie.state = SERVER_COOKIE_LEARNED;
|
||||
}
|
||||
else {
|
||||
lock_rw_unlock(&e->lock);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
infra_get_lame_rtt(struct infra_cache* infra,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen,
|
||||
|
||||
Vendored
+23
-8
@@ -55,7 +55,7 @@ struct config_file;
|
||||
/* COOKIE @TODO move this to correct spot */
|
||||
|
||||
/**
|
||||
* @TODO write this
|
||||
* The actual EDNS cookie data
|
||||
*/
|
||||
union edns_cookie_data {
|
||||
uint8_t complete[24];
|
||||
@@ -69,17 +69,17 @@ union edns_cookie_data {
|
||||
};
|
||||
|
||||
/**
|
||||
* @TODO write this
|
||||
* The different states the EDNS cookie can be in
|
||||
*/
|
||||
enum edns_cookie_state
|
||||
{
|
||||
SERVER_COOKIE_UNKNOWN = 0, /* server cookie unknown, client cookie known */
|
||||
SERVER_COOKIE_LEARNED = 1, /* server (and client) cookie learned */
|
||||
SERVER_COOKIE_LEARNED = 1, /* server (and client) cookie known */
|
||||
COOKIE_NOT_SUPPORTED = 2, /* upstream does not supported EDNS/cookies */
|
||||
};
|
||||
|
||||
/**
|
||||
* @TODO write this
|
||||
* Structure for an EDNS cookie (RFC9018) and it's internal state
|
||||
*/
|
||||
struct edns_cookie {
|
||||
enum edns_cookie_state state;
|
||||
@@ -125,7 +125,7 @@ struct infra_data {
|
||||
* and cause a timeout */
|
||||
uint8_t edns_lame_known;
|
||||
|
||||
/* The EDNS cookie containing both the client and server cookie */
|
||||
/* The EDNS cookie containing the cookie and the internal state */
|
||||
struct edns_cookie cookie;
|
||||
|
||||
/** is the host lame (does not serve the zone authoritatively),
|
||||
@@ -366,16 +366,31 @@ int infra_edns_update(struct infra_cache* infra,
|
||||
* @param addrlen: length of addr.
|
||||
* @param name: name of zone
|
||||
* @param namelen: length of name
|
||||
* @param edns_version: the version that it publishes.
|
||||
* If it is known to support EDNS then no-EDNS is not stored over it.
|
||||
* @param timenow: what time it is now.
|
||||
* @return: struct ends_cookie*
|
||||
*/
|
||||
struct edns_cookie*
|
||||
infra_get_cookie(struct infra_cache* infra, struct sockaddr_storage* addr,
|
||||
socklen_t addrlen, uint8_t* nm, size_t nmlen,
|
||||
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
|
||||
* cookie (RFC9018). This function assumes that the cookie param contains a
|
||||
* complete cookie with a length of 24 bytes. It also assumes that a previous
|
||||
* entry in the cache already exists, as it will update the entry.
|
||||
* @param infra: infrastructure cache.
|
||||
* @param addr: host address.
|
||||
* @param addrlen: length of addr.
|
||||
* @param name: name of zone
|
||||
* @param namelen: length of name
|
||||
* @param timenow: what time it is now.
|
||||
* @param cookie: the EDNS cookie option we want to store.
|
||||
*/
|
||||
void 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);
|
||||
|
||||
|
||||
/**
|
||||
* Get Lameness information and average RTT if host is in the cache.
|
||||
* This information is to be used for server selection.
|
||||
|
||||
@@ -3392,20 +3392,18 @@ outnet_serviced_query(struct outside_network* outnet,
|
||||
|
||||
// @TODO Make configurable
|
||||
|
||||
// 1. lookup the cookie information in the cache
|
||||
cookie = infra_get_cookie(env->infra_cache, addr, addrlen, zone, zonelen,
|
||||
*env->now);
|
||||
|
||||
// 2. attach cookie, dependent on if we know just the client or also the server
|
||||
if (cookie->state == SERVER_COOKIE_LEARNED) {
|
||||
/* We known the complete cookie, so we attach it */
|
||||
edns_opt_list_append(&per_upstream_opt_list, 10, /* @TODO 10 == COOKIE */
|
||||
24, cookie->data.complete, region);
|
||||
} else if (cookie->state == SERVER_COOKIE_UNKNOWN) {
|
||||
/* We known just client cookie, so we attach it */
|
||||
/* We know just client cookie, so we attach it */
|
||||
edns_opt_list_append(&per_upstream_opt_list, 10, /* @TODO 10 == COOKIE */
|
||||
8, cookie->data.components.client, region);
|
||||
}
|
||||
} /* We ignore COOKIE_NOT_SUPPORTED */
|
||||
|
||||
serviced_gen_query(buff, qinfo->qname, qinfo->qname_len, qinfo->qtype,
|
||||
qinfo->qclass, flags);
|
||||
|
||||
@@ -597,6 +597,19 @@ parse_query_section(sldns_buffer* pkt, struct msg_parse* msg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct edns_option*
|
||||
edns_list_get_option(struct edns_option* option, uint16_t code)
|
||||
{
|
||||
while (option) {
|
||||
if (option->opt_code == code) {
|
||||
return option;
|
||||
}
|
||||
|
||||
option = option->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t
|
||||
get_rdf_size(sldns_rdf_type rdf)
|
||||
{
|
||||
|
||||
@@ -254,6 +254,15 @@ struct edns_option {
|
||||
uint8_t* opt_data;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Search through an EDNS list to find if the specified option.
|
||||
* @param option: The EDNS list which we search in
|
||||
* @param code: the option code that we search for
|
||||
* @return: returns the option if it is there, and NULL when it is not
|
||||
*/
|
||||
struct edns_option* edns_list_get_option(struct edns_option* option, uint16_t code);
|
||||
|
||||
/**
|
||||
* Obtain size in the packet of an rr type, that is before dname type.
|
||||
* Do TYPE_DNAME, and type STR, yourself. Gives size for most regular types.
|
||||
|
||||
Reference in New Issue
Block a user