]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
add functionality to store the client cookie and attach both client and server cookie...
authorTCY16 <tom@nlnetlabs.nl>
Mon, 16 May 2022 13:33:56 +0000 (15:33 +0200)
committerTCY16 <tom@nlnetlabs.nl>
Mon, 16 May 2022 13:33:56 +0000 (15:33 +0200)
services/cache/infra.c
services/cache/infra.h
services/outside_network.c

index 252e1e288b354e646315bf44ffdc8e46e24f5d5b..2ae3c242d466211475fc2959b9a0a4855c77d577 100644 (file)
@@ -383,12 +383,18 @@ static void
 data_entry_init(struct infra_cache* infra, struct lruhash_entry* e, 
        time_t timenow)
 {
+       uint8_t cookie[8] = {1,2,3,4,5,6,7,8};
+
        struct infra_data* data = (struct infra_data*)e->data;
        data->ttl = timenow + infra->host_ttl;
        rtt_init(&data->rtt);
        data->edns_version = 0;
        data->edns_lame_known = 0;
        data->probedelay = 0;
+       // @TODO create "random" cookie
+       memset(&data->cookie, 0, sizeof(struct edns_cookie));
+       memcpy(data->cookie.data.components.client, cookie, 8);
+
        data->isdnsseclame = 0;
        data->rec_lame = 0;
        data->lame_type_A = 0;
@@ -459,7 +465,11 @@ infra_host(struct infra_cache* infra, struct sockaddr_storage* addr,
                if(e) {
                        /* if its still there we have a writelock, init */
                        /* re-initialise */
-                       /* do not touch lameness, it may be valid still */
+
+                       // @TODO check if "do not touch lameness" is still true
+                       /* do not touch lameness, it may be valid still.
+                        * Also don't touch the cookie, as the cookie logic
+                        * will be handled by the server. */
                        data_entry_init(infra, e, timenow);
                        wr = 1;
                        /* TOP_TIMEOUT remains on reuse */
@@ -685,6 +695,40 @@ infra_edns_update(struct infra_cache* infra, struct sockaddr_storage* addr,
        return 1;
 }
 
+struct edns_cookie*
+infra_get_cookie(struct infra_cache* infra, struct sockaddr_storage* addr,
+       socklen_t addrlen, uint8_t* nm, size_t nmlen,
+       time_t timenow)
+{
+       struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen,
+               nm, nmlen, 1);
+       struct infra_data* data;
+       int needtoinsert = 0;
+
+       if(!e) {
+               if(!(e = new_entry(infra, addr, addrlen, nm, nmlen, timenow))) {
+                       return 0;
+               }
+               needtoinsert = 1;
+       } else if(((struct infra_data*)e->data)->ttl < timenow) {
+               /* @TODO create logic for saving server cookie? -> not sure, find out */
+
+               /* create new cookie if the TTL of the current one expired */
+               data_entry_init(infra, e, timenow);
+       }
+
+       /* we have an entry; update the rtt, and the ttl */
+       data = (struct infra_data*)e->data;
+
+       if(needtoinsert) {
+               slabhash_insert(infra->hosts, e->hash, e, e->data, NULL);
+       } else {
+               lock_rw_unlock(&e->lock);
+       }
+
+       return &data->cookie;
+}
+
 int
 infra_get_lame_rtt(struct infra_cache* infra,
         struct sockaddr_storage* addr, socklen_t addrlen,
index 6a2371aca4771b8b3e67bb90083f174b6a06d743..5ecd3e2fd3ad4432b6b23c0740b0b3183c056477 100644 (file)
 struct slabhash;
 struct config_file;
 
+/* COOKIE @TODO move this to correct spot */
+
+/**
+ * @TODO write this
+ */
+union edns_cookie_data {
+        uint8_t complete[24];
+        struct {
+                uint8_t client[8];
+                uint8_t version;
+                uint8_t reserved[3];
+                uint32_t timestamp;
+                uint8_t hash[8];
+        } components;
+};
+
+/**
+ * @TODO write this
+ */
+enum edns_cookie_state
+{
+        SERVER_COOKIE_UNKNOWN = 0, /* server cookie unknown, client cookie known */
+        SERVER_COOKIE_LEARNED = 1, /* server (and client) cookie learned */
+        COOKIE_NOT_SUPPORTED = 2, /* upstream does not supported EDNS/cookies */
+};
+
+/**
+ * @TODO write this
+ */
+struct edns_cookie {
+        enum edns_cookie_state state;
+        uint8_t timeout; // @TODO change this to correct value
+        union edns_cookie_data data;
+};
+
+
+
 /**
  * Host information kept for every server, per zone.
  */
@@ -88,6 +125,9 @@ struct infra_data {
         * and cause a timeout */
        uint8_t edns_lame_known;
 
+        /* The EDNS cookie containing both the client and server cookie */
+        struct edns_cookie cookie;
+
        /** is the host lame (does not serve the zone authoritatively),
         * or is the host dnssec lame (does not serve DNSSEC data) */
        uint8_t isdnsseclame;
@@ -318,6 +358,24 @@ int infra_edns_update(struct infra_cache* infra,
         struct sockaddr_storage* addr, socklen_t addrlen,
        uint8_t* name, size_t namelen, int edns_version, time_t timenow);
 
+/**
+ * Find and return the cookie from the infra cache data. Creates an entry in
+ * the cache if there isn't one.
+ * @param infra: infrastructure cache.
+ * @param addr: host address.
+ * @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,
+        time_t timenow);
+
 /**
  * Get Lameness information and average RTT if host is in the cache.
  * This information is to be used for server selection.
index 4578bf8fc451dba6ad5e398cdd28973acdd937d6..c1fdb9fdd4f0f190d54cfda808b39653b7b57896 100644 (file)
@@ -1030,7 +1030,8 @@ reuse_tcp_remove_tree_list(struct outside_network* outnet,
                        char buf[256];
                        addr_to_str(&reuse->addr, reuse->addrlen, buf,
                                sizeof(buf));
-                       log_err("reuse tcp delete: node not present, internal error, %s ssl %d lru %d", buf, reuse->is_ssl, reuse->item_on_lru_list);
+                       log_err("reuse tcp delete: node not present, internal error, %s ssl "
+                               "%d lru %d", buf, reuse->is_ssl, reuse->item_on_lru_list);
                }
                reuse->node.key = NULL;
                /* defend against loops on broken tree by zeroing the
@@ -1440,6 +1441,7 @@ outnet_udp_cb(struct comm_point* c, void* arg, int error,
 
        verbose(VERB_ALGO, "received udp reply.");
        log_buf(VERB_ALGO, "udp message", c->buffer);
+
        if(p->pc->cp != c) {
                verbose(VERB_QUERY, "received reply id,addr on wrong port. "
                        "dropped.");
@@ -3347,6 +3349,7 @@ outnet_serviced_query(struct outside_network* outnet,
        struct service_callback* cb;
        struct edns_string_addr* client_string_addr;
        struct regional* region;
+       struct edns_cookie* cookie;
        struct edns_option* backed_up_opt_list = qstate->edns_opts_back_out;
        struct edns_option* per_upstream_opt_list = NULL;
        time_t timenow = 0;
@@ -3386,6 +3389,24 @@ outnet_serviced_query(struct outside_network* outnet,
                        client_string_addr->string, region);
        }
 
+
+       // @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 */
+               edns_opt_list_append(&per_upstream_opt_list, 10, /* @TODO 10 == COOKIE */
+                       8, cookie->data.components.client, region);
+       }
+
        serviced_gen_query(buff, qinfo->qname, qinfo->qname_len, qinfo->qtype,
                qinfo->qclass, flags);
        sq = lookup_serviced(outnet, buff, dnssec, addr, addrlen,
@@ -3509,7 +3530,8 @@ fd_for_dest(struct outside_network* outnet, struct sockaddr_storage* to_addr,
                        if(outnet->num_ip6 == 0) {
                                char to[64];
                                addr_to_str(to_addr, to_addrlen, to, sizeof(to));
-                               verbose(VERB_QUERY, "need ipv6 to send, but no ipv6 outgoing interfaces, for %s", to);
+                               verbose(VERB_QUERY, "need ipv6 to send, but no ipv6 outgoing "
+                                       "interfaces, for %s", to);
                                return -1;
                        }
                        i = ub_random_max(outnet->rnd, outnet->num_ip6);
@@ -3518,7 +3540,8 @@ fd_for_dest(struct outside_network* outnet, struct sockaddr_storage* to_addr,
                        if(outnet->num_ip4 == 0) {
                                char to[64];
                                addr_to_str(to_addr, to_addrlen, to, sizeof(to));
-                               verbose(VERB_QUERY, "need ipv4 to send, but no ipv4 outgoing interfaces, for %s", to);
+                               verbose(VERB_QUERY, "need ipv4 to send, but no ipv4 outgoing "
+                                       "interfaces, for %s", to);
                                return -1;
                        }
                        i = ub_random_max(outnet->rnd, outnet->num_ip4);