mirror of
https://github.com/NLnetLabs/unbound.git
synced 2024-09-21 06:37:08 +00:00
- For #762: Introduce rpl testing for DNS Cookies.
This commit is contained in:
parent
b6e2f4dbf8
commit
8580a74b37
@ -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");
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
235
testdata/edns_downstream_cookies.rpl
vendored
Normal file
235
testdata/edns_downstream_cookies.rpl
vendored
Normal file
@ -0,0 +1,235 @@
|
||||
; config options
|
||||
server:
|
||||
answer-cookie: yes
|
||||
cookie-secret: "000102030405060708090a0b0c0d0e0f"
|
||||
access-control: 127.0.0.1 allow_cookie
|
||||
access-control: 1.2.3.4 allow
|
||||
local-data: "test. TXT test"
|
||||
|
||||
CONFIG_END
|
||||
|
||||
SCENARIO_BEGIN Test downstream EDNS Cookies
|
||||
|
||||
; Note: When a valid hash was required, it was generated by running this test
|
||||
; with an invalid one and checking the output for the valid one.
|
||||
; Actual hash generation is tested with unit tests.
|
||||
|
||||
; Query without a client cookie ...
|
||||
STEP 0 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
ENTRY_END
|
||||
; ... get TC and refused
|
||||
STEP 1 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR RD RA TC REFUSED
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
ENTRY_END
|
||||
|
||||
; Query without a client cookie on TCP ...
|
||||
STEP 10 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
MATCH TCP
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
ENTRY_END
|
||||
; ... get an answer
|
||||
STEP 11 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR RD RA AA NOERROR
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
SECTION ANSWER
|
||||
test. IN TXT "test"
|
||||
ENTRY_END
|
||||
|
||||
; Query with only a client cookie ...
|
||||
STEP 20 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
SECTION ADDITIONAL
|
||||
HEX_EDNSDATA_BEGIN
|
||||
00 0a ; Opcode 10
|
||||
00 08 ; Length 8
|
||||
31 32 33 34 35 36 37 38 ; Random bits
|
||||
HEX_EDNSDATA_END
|
||||
ENTRY_END
|
||||
; ... get BADCOOKIE and a new cookie
|
||||
STEP 21 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all server_cookie
|
||||
REPLY QR RD RA DO YXRRSET ; BADCOOKIE is an extended rcode
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
ENTRY_END
|
||||
|
||||
; Query with an invalid cookie ...
|
||||
STEP 30 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
SECTION ADDITIONAL
|
||||
HEX_EDNSDATA_BEGIN
|
||||
00 0a ; Opcode 10
|
||||
00 18 ; Length 24
|
||||
31 32 33 34 35 36 37 38 ; Random bits
|
||||
02 00 00 00 ; wrong version
|
||||
00 00 00 00 ; Timestamp
|
||||
31 32 33 34 35 36 37 38 ; wrong hash
|
||||
HEX_EDNSDATA_END
|
||||
ENTRY_END
|
||||
; ... get BADCOOKIE and a new cookie
|
||||
STEP 31 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all server_cookie
|
||||
REPLY QR RD RA DO YXRRSET ; BADCOOKIE is an extended rcode
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
ENTRY_END
|
||||
|
||||
; Query with an invalid cookie from a non-cookie protected address ...
|
||||
STEP 40 QUERY ADDRESS 1.2.3.4
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
SECTION ADDITIONAL
|
||||
HEX_EDNSDATA_BEGIN
|
||||
00 0a ; Opcode 10
|
||||
00 18 ; Length 24
|
||||
31 32 33 34 35 36 37 38 ; Random bits
|
||||
02 00 00 00 ; wrong version
|
||||
00 00 00 00 ; Timestamp
|
||||
31 32 33 34 35 36 37 38 ; wrong hash
|
||||
HEX_EDNSDATA_END
|
||||
ENTRY_END
|
||||
; ... get answer and a cookie
|
||||
STEP 41 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all server_cookie
|
||||
REPLY QR RD RA AA DO NOERROR
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
SECTION ANSWER
|
||||
test. IN TXT "test"
|
||||
ENTRY_END
|
||||
|
||||
; Query with a valid cookie ...
|
||||
STEP 50 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
SECTION ADDITIONAL
|
||||
HEX_EDNSDATA_BEGIN
|
||||
00 0a ; Opcode 10
|
||||
00 18 ; Length 24
|
||||
31 32 33 34 35 36 37 38 ; Random bits
|
||||
01 00 00 00 ; wrong version
|
||||
00 00 00 00 ; Timestamp
|
||||
38 52 7b a8 c6 a4 ea 96 ; Hash
|
||||
HEX_EDNSDATA_END
|
||||
ENTRY_END
|
||||
; ... get answer and the cookie
|
||||
STEP 51 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all server_cookie
|
||||
REPLY QR RD RA AA DO NOERROR
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
SECTION ANSWER
|
||||
test. IN TXT "test"
|
||||
ENTRY_END
|
||||
|
||||
; Query with a valid >30 minutes old cookie ...
|
||||
STEP 59 TIME_PASSES ELAPSE 1801
|
||||
STEP 60 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
SECTION ADDITIONAL
|
||||
HEX_EDNSDATA_BEGIN
|
||||
00 0a ; Opcode 10
|
||||
00 18 ; Length 24
|
||||
31 32 33 34 35 36 37 38 ; Random bits
|
||||
01 00 00 00 ; Version/Reserved
|
||||
00 00 00 00 ; Timestamp
|
||||
38 52 7b a8 c6 a4 ea 96 ; Hash
|
||||
HEX_EDNSDATA_END
|
||||
ENTRY_END
|
||||
; ... Get answer and a refreshed cookie
|
||||
; (we don't check the re-freshness here; it has its own unit test)
|
||||
STEP 61 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all server_cookie
|
||||
REPLY QR RD RA AA DO NOERROR
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
SECTION ANSWER
|
||||
test. IN TXT "test"
|
||||
ENTRY_END
|
||||
|
||||
; Query with a hash-valid >60 minutes old cookie ...
|
||||
STEP 69 TIME_PASSES ELAPSE 3601
|
||||
STEP 70 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
SECTION ADDITIONAL
|
||||
HEX_EDNSDATA_BEGIN
|
||||
00 0a ; Opcode 10
|
||||
00 18 ; Length 24
|
||||
31 32 33 34 35 36 37 38 ; Random bits
|
||||
01 00 00 00 ; Version/Reserved
|
||||
00 00 07 09 ; Timestamp (1801)
|
||||
77 81 38 e3 8f aa 72 86 ; Hash
|
||||
HEX_EDNSDATA_END
|
||||
ENTRY_END
|
||||
; ... get BADCOOKIE and a new cookie
|
||||
STEP 71 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all server_cookie
|
||||
REPLY QR RD RA DO YXRRSET ; BADCOOKIE is an extended rcode
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
ENTRY_END
|
||||
|
||||
; Query with a valid future (<5 minutes) cookie ...
|
||||
STEP 80 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
SECTION ADDITIONAL
|
||||
HEX_EDNSDATA_BEGIN
|
||||
00 0a ; Opcode 10
|
||||
00 18 ; Length 24
|
||||
31 32 33 34 35 36 37 38 ; Random bits
|
||||
01 00 00 00 ; Version/Reserved
|
||||
00 00 16 45 ; Timestamp (1801 + 3601 + 299)
|
||||
4a f5 0f df f0 e8 c7 09 ; Hash
|
||||
HEX_EDNSDATA_END
|
||||
ENTRY_END
|
||||
; ... get an answer
|
||||
STEP 81 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all server_cookie
|
||||
REPLY QR RD RA AA DO NOERROR
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
SECTION ANSWER
|
||||
test. IN TXT "test"
|
||||
ENTRY_END
|
||||
|
||||
SCENARIO_END
|
Loading…
Reference in New Issue
Block a user