{
struct msg_parse* prs;
struct edns_data edns;
+ struct edns_option* cookie;
sldns_buffer* pkt;
verbose(VERB_ALGO, "process_response: new external response event");
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,
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;
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);
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,
/* COOKIE @TODO move this to correct spot */
/**
- * @TODO write this
+ * The actual EDNS cookie data
*/
union edns_cookie_data {
uint8_t complete[24];
};
/**
- * @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;
* 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),
* @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.
// @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);
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)
{
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.