- For #762: Introduce rpl testing for DNS Cookies.

This commit is contained in:
George Thessalonikefs
2023-08-05 19:50:57 +02:00
parent b6e2f4dbf8
commit 8580a74b37
4 changed files with 312 additions and 15 deletions
+62 -11
View File
@@ -21,7 +21,6 @@
*/
#include "config.h"
struct sockaddr_storage;
#include <errno.h>
#include <stdarg.h>
#include <ctype.h>
@@ -140,6 +139,10 @@ 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, "client_cookie")) {
e->match_client_cookie = 1;
} else if(str_keyword(&parse, "server_cookie")) {
e->match_server_cookie = 1;
} else if(str_keyword(&parse, "UDP")) {
e->match_transport = transport_udp;
} else if(str_keyword(&parse, "TCP")) {
@@ -905,37 +908,64 @@ get_do_flag(uint8_t* pkt, size_t len)
return (int)(edns_bits&LDNS_EDNS_MASK_DO_BIT);
}
/** Snips the EDE option out of the OPT record and returns the EDNS EDE
* INFO-CODE if found, else -1 */
/** Snips the specified EDNS option out of the OPT record and puts it in the
* provided buffer. The buffer should be able to hold any opt data ie 65535.
* Returns the length of the option written,
* or 0 if not found, else -1 on error. */
static int
extract_ede(uint8_t* pkt, size_t len)
pkt_snip_edns_option(uint8_t* pkt, size_t len, sldns_edns_option code,
uint8_t* buf)
{
uint8_t *rdata, *opt_position = pkt;
uint16_t rdlen, optlen;
size_t remaining = len;
int ede_code;
if(!pkt_find_edns_opt(&opt_position, &remaining)) return -1;
if(!pkt_find_edns_opt(&opt_position, &remaining)) return 0;
if(remaining < 8) return -1; /* malformed */
rdlen = sldns_read_uint16(opt_position+6);
rdata = opt_position + 8;
while(rdlen > 0) {
if(rdlen < 4) return -1; /* malformed */
optlen = sldns_read_uint16(rdata+2);
if(sldns_read_uint16(rdata) == LDNS_EDNS_EDE) {
if(rdlen < 6) return -1; /* malformed */
ede_code = sldns_read_uint16(rdata+4);
if(sldns_read_uint16(rdata) == code) {
/* save data to buf for caller inspection */
memcpy(buf, rdata+4, optlen);
/* snip option from packet; assumes len is correct */
memmove(rdata, rdata+4+optlen,
(pkt+len)-(rdata+4+optlen));
/* update OPT size */
sldns_write_uint16(opt_position+6,
sldns_read_uint16(opt_position+6)-(4+optlen));
return ede_code;
return optlen;
}
rdlen -= 4 + optlen;
rdata += 4 + optlen;
}
return -1;
return 0;
}
/** Snips the EDE option out of the OPT record and returns the EDNS EDE
* INFO-CODE if found, else -1 */
static int
extract_ede(uint8_t* pkt, size_t len)
{
uint8_t buf[65535];
int buflen = pkt_snip_edns_option(pkt, len, LDNS_EDNS_EDE, buf);
if(buflen < 2 /*ede without text at minimum*/) return -1;
return sldns_read_uint16(buf);
}
/** Snips the EDNS Cookie option out of the OPT record and puts it in the
* provided cookie buffer (should be at least 24 octets).
* Returns the length of the cookie if found, else -1. */
static int
extract_cookie(uint8_t* pkt, size_t len, uint8_t* cookie)
{
uint8_t buf[65535];
int buflen = pkt_snip_edns_option(pkt, len, LDNS_EDNS_COOKIE, buf);
if(buflen != 8 /*client cookie*/ &&
buflen != 8 + 16 /*server cookie*/) return -1;
memcpy(cookie, buf, buflen);
return buflen;
}
/** zero TTLs in packet */
@@ -1530,6 +1560,27 @@ find_match(struct entry* entries, uint8_t* query_pkt, size_t len,
continue;
}
}
/* Cookies could also modify the query_pkt; keep them early */
if(p->match_client_cookie || p->match_server_cookie) {
uint8_t cookie[24];
int cookie_len = extract_cookie(query_pkt, len,
cookie);
if(cookie_len == -1) {
verbose(3, "bad EDNS Cookie. "
"Expected but not found\n");
continue;
} else if(p->match_client_cookie &&
cookie_len != 8) {
verbose(3, "bad EDNS Cookie. Expected client "
"cookie of length 8.");
continue;
} else if((p->match_server_cookie) &&
cookie_len != 24) {
verbose(3, "bad EDNS Cookie. Expected server "
"cookie of length 24.");
continue;
}
}
if(p->match_opcode && get_opcode(query_pkt, len) !=
get_opcode(reply, rlen)) {
verbose(3, "bad opcode\n");
+15 -3
View File
@@ -64,6 +64,14 @@ struct sldns_file_parse_state;
; 'ede=any' makes the query match any EDNS EDE info-code.
; It also snips the EDE record out of the packet to facilitate
; other matches.
; 'client_cookie' makes the query match any EDNS Cookie option with
; with a length of 8 octets.
; It also snips the EDNS Cookie record out of the packet to
; facilitate other matches.
; 'server_cookie' makes the query match any EDNS Cookie option with
; with a length of 24 octets.
; It also snips the EDNS Cookie record out of the packet to
; facilitate other matches.
MATCH [opcode] [qtype] [qname] [serial=<value>] [all] [ttl]
MATCH [UDP|TCP] DO
MATCH ...
@@ -104,11 +112,11 @@ struct sldns_file_parse_state;
; be parsed, ADJUST rules for the answer packet
; are ignored. Only copy_id is done.
HEX_ANSWER_END
HEX_EDNS_BEGIN ; follow with hex data.
HEX_EDNSDATA_BEGIN ; follow with hex data.
; Raw EDNS data to match against. It must be an
; exact match (all options are matched) and will be
; evaluated only when 'MATCH ednsdata' given.
HEX_EDNS_END
HEX_EDNSDATA_END
ENTRY_END
@@ -214,6 +222,10 @@ struct entry {
uint8_t match_noedns;
/** match edns data field given in hex */
uint8_t match_ednsdata_raw;
/** match an EDNS cookie of length 8 */
uint8_t match_client_cookie;
/** match an EDNS cookie of length 24 */
uint8_t match_server_cookie;
/** match query serial with this value. */
uint32_t ixfr_soa_serial;
/** match on UDP/TCP */
@@ -235,7 +247,7 @@ struct entry {
/** increment the ECS scope copied from the sourcemask by one */
uint8_t increment_ecs_scope;
/** in seconds */
unsigned int sleeptime;
unsigned int sleeptime;
/** some number that names this entry, line number in file or so */
int lineno;
-1
View File
@@ -559,7 +559,6 @@ edns_cookie_invalid_version(void)
sizeof(client_cookie), server_secret, sizeof(server_secret), 1,
buf, timestamp) == 0);
edns_cookie_server_write(buf, server_secret, 1, timestamp);
log_hex("server:", buf, 32);
unit_assert(memcmp(server_cookie, buf, 24) == 0);
}