]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
store complete cookie when receiving from downstream. Add function through search...
authorTCY16 <tom@nlnetlabs.nl>
Thu, 19 May 2022 11:24:00 +0000 (13:24 +0200)
committerTCY16 <tom@nlnetlabs.nl>
Thu, 19 May 2022 11:24:00 +0000 (13:24 +0200)
iterator/iterator.c
services/cache/infra.c
services/cache/infra.h
services/outside_network.c
util/data/msgparse.c
util/data/msgparse.h

index 3cfb286f44914a0f1bf10b08e2b3107b8c53dd8c..3f61651dbb1997b1eff2923a82dbbbde91fafd7b 100644 (file)
@@ -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,
index 2ae3c242d466211475fc2959b9a0a4855c77d577..e1c7845403cc9edae67f5f79340844455028691a 100644 (file)
@@ -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,
index 5ecd3e2fd3ad4432b6b23c0740b0b3183c056477..90761eaa7ec3073310bc506937bf56c2ea6235dd 100644 (file)
@@ -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.
index c1fdb9fdd4f0f190d54cfda808b39653b7b57896..78b06739ba93a0965558e875897a171e787e17e8 100644 (file)
@@ -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);
index 5bb69d6ed06fc2fff257bddb591def269c94236c..1923ff0d0986a87e9f6af93e3577d74955c648e0 100644 (file)
@@ -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)
 {
index 0c458e6e8e251e2a9200af44bfaf6fac3166dfff..f15ab2bccc6695d83f9b8e0eaa407cec90a356f3 100644 (file)
@@ -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.