From 23e04d7f39f6552d660ef623dfbc15ab6a8347d2 Mon Sep 17 00:00:00 2001 From: TCY16 Date: Mon, 16 May 2022 15:33:56 +0200 Subject: [PATCH] add functionality to store the client cookie and attach both client and server cookie to the upstream query --- services/cache/infra.c | 46 +++++++++++++++++++++++++++++- services/cache/infra.h | 58 ++++++++++++++++++++++++++++++++++++++ services/outside_network.c | 29 +++++++++++++++++-- 3 files changed, 129 insertions(+), 4 deletions(-) diff --git a/services/cache/infra.c b/services/cache/infra.c index 252e1e288..2ae3c242d 100644 --- a/services/cache/infra.c +++ b/services/cache/infra.c @@ -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, diff --git a/services/cache/infra.h b/services/cache/infra.h index 6a2371aca..5ecd3e2fd 100644 --- a/services/cache/infra.h +++ b/services/cache/infra.h @@ -52,6 +52,43 @@ 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. diff --git a/services/outside_network.c b/services/outside_network.c index 4578bf8fc..c1fdb9fdd 100644 --- a/services/outside_network.c +++ b/services/outside_network.c @@ -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);