add unit test for server cookie init

This commit is contained in:
TCY16
2022-06-14 15:36:25 +02:00
parent e7b480a0a2
commit 069660af48
4 changed files with 130 additions and 1 deletions
+17
View File
@@ -1226,6 +1226,7 @@ struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
struct edns_option* backed_up_opt_list =
qstate->edns_opts_back_out;
struct edns_option* per_upstream_opt_list = NULL;
struct edns_cookie* cookie;
/* If we have an already populated EDNS option list make a copy
* since we may now add upstream specific EDNS options. */
if(qstate->edns_opts_back_out) {
@@ -1254,6 +1255,22 @@ struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
client_string_addr->string_len,
client_string_addr->string, qstate->region);
}
// @TODO Make configurable
cookie = infra_get_cookie(env->infra_cache, addr, addrlen, zone,
zonelen, *env->now);
if (cookie->state == SERVER_COOKIE_LEARNED) {
/* We known the complete cookie, so we attach it */
edns_opt_list_append(&per_upstream_opt_list, LDNS_EDNS_COOKIE,
24, cookie->data.complete, qstate->region);
} else if (cookie->state == SERVER_COOKIE_UNKNOWN) {
/* We know just client cookie, so we attach it */
edns_opt_list_append(&per_upstream_opt_list, LDNS_EDNS_COOKIE,
8, cookie->data.components.client, qstate->region);
} /* We ignore COOKIE_NOT_SUPPORTED */
/* add edns */
edns.edns_present = 1;
edns.ext_rcode = 0;
+106
View File
@@ -39,6 +39,8 @@ struct sockaddr_storage;
#define MAX_LINE 10240
/** string to show in warnings and errors */
static const char* prog_name = "testpkts";
/** hardcoded EDNS server cookie (RFC7876) */
static const char* hardcoded_server_cookie = "7e8b5fcc6a4bc7bc";
#ifndef UTIL_LOG_H
/** verbosity definition for compat */
@@ -140,6 +142,8 @@ static void matchline(char* line, struct entry* e)
e->match_noedns = 1;
} else if(str_keyword(&parse, "ednsdata")) {
e->match_ednsdata_raw = 1;
} else if(str_keyword(&parse, "random_client_cookie")) {
e->match_random_client_cookie = 1;
} else if(str_keyword(&parse, "UDP")) {
e->match_transport = transport_udp;
} else if(str_keyword(&parse, "TCP")) {
@@ -263,6 +267,8 @@ static void adjustline(char* line, struct entry* e,
pkt->packet_sleep = (unsigned int) strtol(parse, (char**)&parse, 10);
while(isspace((unsigned char)*parse))
parse++;
} else if (str_keyword(&parse, "add_server_cookie")) {
e->server_cookie = 1;
} else {
error("could not parse ADJUST: '%s'", parse);
}
@@ -1499,6 +1505,36 @@ match_ednsdata(uint8_t* q, size_t qlen, uint8_t* p, size_t plen)
return (memcmp(walk_p+8, walk_q+8, walk_qlen-8) == 0);
}
/** verify that a client cookie of length 8 is in the EDNS data of the query */
static int
match_random_client_cookie(uint8_t* query, size_t query_len)
{
uint8_t* walk_query = query;
size_t walk_query_len = query_len;
if(!pkt_find_edns_opt(&walk_query, &walk_query_len)) {
walk_query_len = 0;
log_err("!!!!!! no edns");
}
/* class + ttl + rdlen = 8 */
if(walk_query_len <= 8) {
verbose(3, "No edns opt, no cookie");
return 0;
}
if (sldns_read_uint16(walk_query+8) != 10 /* LDNS_EDNS_COOKIE */) {
verbose(3, "EDNS option is not a cookie");
return 0;
}
if (sldns_read_uint16(walk_query+10) != 8) {
verbose(3, "EDNS cookie is not 8 bytes, so not a correct client cookie");
return 0;
}
return 1;
}
/* finds entry in list, or returns NULL */
struct entry*
find_match(struct entry* entries, uint8_t* query_pkt, size_t len,
@@ -1594,6 +1630,11 @@ find_match(struct entry* entries, uint8_t* query_pkt, size_t len,
verbose(3, "bad EDNS data match.\n");
continue;
}
if (p->match_random_client_cookie &&
!match_random_client_cookie(query_pkt, len)) {
verbose(3, "bad client cookie match.\n");
continue;
}
if(p->match_transport != transport_any && p->match_transport != transport) {
verbose(3, "bad transport\n");
continue;
@@ -1690,6 +1731,71 @@ adjust_packet(struct entry* match, uint8_t** answer_pkt, size_t *answer_len,
if(match->copy_id && reslen >= 1 && query_len >= 1)
res[0] = query_pkt[0];
if(match->server_cookie) {
/** Find the cookie option and add the server cookie if
* the client cookie is present
* */
uint8_t* walk_query = query_pkt;
size_t walk_query_len = query_len;
uint8_t* walk_response = res;
size_t walk_response_len = reslen;
uint8_t* rd_len_ptr;
/* verify that we have a EDNS record */
if(!pkt_find_edns_opt(&walk_query, &walk_query_len)) {
walk_query_len = 0;
}
if(!pkt_find_edns_opt(&walk_response, &walk_response_len)) {
walk_response_len = 0;
}
/* verify that we have a EDNS option */
if (walk_query_len < 12) /* class + ttl + rdlen + opt_code + opt_len */ {
/* invalid or no (OPT) record in the query */
walk_query_len = 0;
}
if (walk_response_len < 8) /* class + ttl + rdlen */ {
walk_response_len = 0;
}
rd_len_ptr = walk_response + 6; /* store the location of the rdlen */
/* skip past the OPT record to get to the option */
walk_query += 8;
walk_query_len -= 8;
walk_response += 8;
walk_response_len -= 8;
/* assume one record in the query */
if (sldns_read_uint16(walk_query) != 10 /* LDNS_EDNS_COOKIE */ ||
sldns_read_uint16(walk_query+2) != 8) {/* client cookie length */
/* incorrect client cookie */
walk_query_len = 0;
}
/* verify that the client cookie exists */
if (walk_query_len < 12 /* opt_code + opt_len + client cookie */) {
walk_query_len = 0;
}
if (walk_query_len > 0 && walk_response_len == 0) {
/* copy the EDNS client cookie from the query packet to the response */
memcpy(walk_response, walk_query, 12);
/* add the server cookie to the client cookie to make it
* 'complete'. we fake the siphash specified in RFC9018
* by hardcoding the server cookie */
memcpy(walk_response+12, hardcoded_server_cookie, 16);
/* update the RDLEN and OPTLEN */
sldns_write_uint16(rd_len_ptr, 28);
sldns_write_uint16(walk_response+2, 24);
reslen = origlen + 28;
}
}
if(match->copy_ednsdata_assume_clientsubnet) {
/** Assume there is only one EDNS option, which is ECS.
* Copy source mask from query to scope mask in reply. Assume
+6
View File
@@ -214,6 +214,8 @@ struct entry {
uint8_t match_noedns;
/** match edns data field given in hex */
uint8_t match_ednsdata_raw;
/** match an EDNS cookie (RFC7873) of length 8 */
uint8_t match_random_client_cookie;
/** match query serial with this value. */
uint32_t ixfr_soa_serial;
/** match on UDP/TCP */
@@ -237,6 +239,10 @@ struct entry {
/** in seconds */
unsigned int sleeptime;
/** add a server cookie (RFC9018) to the response (provided the query
* contains a client cookie) */
uint8_t server_cookie;
/** some number that names this entry, line number in file or so */
int lineno;