mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-09-08 19:07:41 +02:00
- For #762: Introduce rpl testing for DNS Cookies.
This commit is contained in:
+62
-11
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user