Merge remote-tracking branch 'FlyingWithJerome/master'

* FlyingWithJerome/master:
  remove variables in netvar, use tabs in DNS.h and polish comments in dns events.
  add new line at the end of the test baseline
  add data+=option_len to skip unknown bytes
  better explanation to server cookie
  better explanation to server cookie
  add edns-cookie testcase
  remove data+=option_len error in cookie and keepalive
  add EDNS cookie parsing
  lazy commit
  lazy commit
  lazy commit
  add testcases
  add units (100ms) to comments
  initial adding EDNS TCP keepalive
This commit is contained in:
Tim Wojtulewicz 2020-08-20 10:23:29 -07:00
commit 8411adf9e1
16 changed files with 234 additions and 7 deletions

5
.gitignore vendored
View file

@ -4,4 +4,7 @@ tmp
# Configuration and build directories for CLion # Configuration and build directories for CLion
.idea .idea
cmake-build-debug cmake-build-debug
# skip DS Store for MacOS
.DS_Store

22
CHANGES
View file

@ -1,3 +1,25 @@
3.3.0-dev.135 | 2020-08-20 10:23:29 -0700
* remove variables in netvar, use tabs in DNS.h and polish comments in dns events. (FlyingWithJerome)
* add new line at the end of the test baseline (FlyingWithJerome)
* add data+=option_len to skip unknown bytes (FlyingWithJerome)
* better explanation to server cookie (FlyingWithJerome)
* add edns-cookie testcase (FlyingWithJerome)
* remove data+=option_len error in cookie and keepalive (FlyingWithJerome)
* add EDNS cookie parsing (FlyingWithJerome)
* add testcases (FlyingWithJerome)
* add units (100ms) to comments (FlyingWithJerome)
* initial adding EDNS TCP keepalive (FlyingWithJerome)
3.3.0-dev.119 | 2020-08-19 14:35:51 -0700 3.3.0-dev.119 | 2020-08-19 14:35:51 -0700
* Misc strings.bif adjustments * Misc strings.bif adjustments

2
NEWS
View file

@ -9,7 +9,7 @@ Zeek 4.0.0
New Functionality New Functionality
----------------- -----------------
TODO: nothing notable yet - Added support for EDNS0 Cookie and Keep-Alive options.
Changed Functionality Changed Functionality
--------------------- ---------------------

View file

@ -1 +1 @@
3.3.0-dev.119 3.3.0-dev.135

2
doc

@ -1 +1 @@
Subproject commit 5abdcc5614cbd87d9edb3d41ffb9abf3674ea822 Subproject commit db50308120cb39206aa0ab91c9789f87d92c7faf

View file

@ -3700,6 +3700,22 @@ type dns_edns_ecs: record {
address: string; ##< Client Subnet Address. address: string; ##< Client Subnet Address.
}; };
## An DNS EDNS TCP KEEPALIVE (TCP KEEPALIVE) record.
##
## .. zeek:see:: dns_EDNS_tcp_keepalive
type dns_edns_tcp_keepalive: record {
keepalive_timeout_omitted: bool; ##< Whether timeout value is omitted.
keepalive_timeout: count; ##< Timeout value, in 100ms.
};
## An DNS EDNS COOKIE (COOKIE) record.
##
## .. zeek:see:: dns_EDNS_cookie
type dns_edns_cookie: record {
client_cookie: string; ##< Cookie from the client (fixed 8 bytes).
server_cookie: string &default=""; ##< Cookie from the server (0 bytes if missing, or 8 to 32 bytes).
};
## An additional DNS TSIG record. ## An additional DNS TSIG record.
## ##
## .. zeek:see:: dns_TSIG_addl ## .. zeek:see:: dns_TSIG_addl

View file

@ -110,6 +110,7 @@ export {
[20] = "BADNAME", # Duplicate key name [20] = "BADNAME", # Duplicate key name
[21] = "BADALG", # Algorithm not supported [21] = "BADALG", # Algorithm not supported
[22] = "BADTRUNC", # draft-ietf-dnsext-tsig-sha-05.txt [22] = "BADTRUNC", # draft-ietf-dnsext-tsig-sha-05.txt
[23] = "BADCOOKIE", # Bad EDNS cookie value
[3842] = "BADSIG", # 16 <= number collision with EDNS(16); [3842] = "BADSIG", # 16 <= number collision with EDNS(16);
# this is a translation from TSIG(16) # this is a translation from TSIG(16)
} &default = function(n: count): string { return fmt("rcode-%d", n); }; } &default = function(n: count): string { return fmt("rcode-%d", n); };

View file

@ -700,7 +700,6 @@ bool DNS_Interpreter::ParseRR_EDNS(DNS_MsgInfo* msg,
const u_char*& data, int& len, int rdlength, const u_char*& data, int& len, int rdlength,
const u_char* msg_start) const u_char* msg_start)
{ {
if ( dns_EDNS_addl && ! msg->skip_event ) if ( dns_EDNS_addl && ! msg->skip_event )
analyzer->EnqueueConnEvent(dns_EDNS_addl, analyzer->EnqueueConnEvent(dns_EDNS_addl,
analyzer->ConnVal(), analyzer->ConnVal(),
@ -714,7 +713,7 @@ bool DNS_Interpreter::ParseRR_EDNS(DNS_MsgInfo* msg,
uint16_t option_code = ExtractShort(data, len); uint16_t option_code = ExtractShort(data, len);
int option_len = ExtractShort(data, len); int option_len = ExtractShort(data, len);
// check for invalid option length // check for invalid option length
if ( (option_len > len) || (0 == option_len) ) { if ( (option_len > len) ) {
break; break;
} }
len -= option_len; len -= option_len;
@ -783,7 +782,82 @@ bool DNS_Interpreter::ParseRR_EDNS(DNS_MsgInfo* msg,
msg->BuildEDNS_ECS_Val(&opt) msg->BuildEDNS_ECS_Val(&opt)
); );
break; break;
} } // END EDNS ECS
case TYPE_TCP_KA:
{
EDNS_TCP_KEEPALIVE edns_tcp_keepalive{
.keepalive_timeout_omitted = true,
.keepalive_timeout = 0
};
if ( option_len == 0 || option_len == 2)
{
// 0 bytes is permitted by RFC 7828, showing that the timeout value is omitted.
if (option_len == 2)
{
edns_tcp_keepalive.keepalive_timeout = ExtractShort(data, option_len);
edns_tcp_keepalive.keepalive_timeout_omitted = false;
}
if (analyzer->Conn()->ConnTransport() == TRANSPORT_UDP)
{
/*
* Based on RFC 7828 (3.2.1/3.2.2), clients and servers MUST NOT
* negotiate TCP Keepalive timeout in DNS-over-UDP.
*/
analyzer->Weird("EDNS_TCP_Keepalive_In_UDP");
}
analyzer->EnqueueConnEvent(dns_EDNS_tcp_keepalive,
analyzer->ConnVal(),
msg->BuildHdrVal(),
msg->BuildEDNS_TCP_KA_Val(&edns_tcp_keepalive)
);
}
else
{
// error. MUST BE 0 or 2 bytes. skip
data += option_len;
}
break;
} // END EDNS TCP KEEPALIVE
case TYPE_COOKIE:
{
EDNS_COOKIE cookie{};
if (option_len != 8 && ! (option_len >= 16 && option_len <= 40))
{
/*
* option length for DNS Cookie must be 8 bytes (with client cookie only)
* OR
* between 16 bytes to 40 bytes (with an 8 bytes client and an 8 to 32 bytes
* server cookie)
*/
data += option_len;
break;
}
int client_cookie_len = 8;
int server_cookie_len = option_len - client_cookie_len;
cookie.client_cookie = ExtractStream(data, client_cookie_len, client_cookie_len);
cookie.server_cookie = nullptr;
if (server_cookie_len >= 8)
{
cookie.server_cookie = ExtractStream(data, server_cookie_len, server_cookie_len);
}
analyzer->EnqueueConnEvent(dns_EDNS_cookie,
analyzer->ConnVal(),
msg->BuildHdrVal(),
msg->BuildEDNS_COOKIE_Val(&cookie)
);
break;
} // END EDNS COOKIE
default: default:
{ {
data += option_len; data += option_len;
@ -1604,6 +1678,30 @@ zeek::RecordValPtr DNS_MsgInfo::BuildEDNS_ECS_Val(struct EDNS_ECS* opt)
return r; return r;
} }
zeek::RecordValPtr DNS_MsgInfo::BuildEDNS_TCP_KA_Val(struct EDNS_TCP_KEEPALIVE* opt)
{
static auto dns_edns_tcp_keepalive = zeek::id::find_type<zeek::RecordType>("dns_edns_tcp_keepalive");
auto r = zeek::make_intrusive<zeek::RecordVal>(dns_edns_tcp_keepalive);
r->Assign(0, zeek::val_mgr->Bool(opt->keepalive_timeout_omitted));
r->Assign(1, zeek::val_mgr->Count(opt->keepalive_timeout));
return r;
}
zeek::RecordValPtr DNS_MsgInfo::BuildEDNS_COOKIE_Val(struct EDNS_COOKIE* opt)
{
static auto dns_edns_cookie = zeek::id::find_type<zeek::RecordType>("dns_edns_cookie");
auto r = zeek::make_intrusive<zeek::RecordVal>(dns_edns_cookie);
r->Assign(0, zeek::make_intrusive<zeek::StringVal>(opt->client_cookie));
if (opt->server_cookie != nullptr) {
r->Assign(1, zeek::make_intrusive<zeek::StringVal>(opt->server_cookie));
}
return r;
}
zeek::RecordValPtr DNS_MsgInfo::BuildTSIG_Val(struct TSIG_DATA* tsig) zeek::RecordValPtr DNS_MsgInfo::BuildTSIG_Val(struct TSIG_DATA* tsig)
{ {
static auto dns_tsig_additional = zeek::id::find_type<zeek::RecordType>("dns_tsig_additional"); static auto dns_tsig_additional = zeek::id::find_type<zeek::RecordType>("dns_tsig_additional");

View file

@ -92,6 +92,7 @@ typedef enum {
TYPE_N3U = 7, ///< RFC6975 TYPE_N3U = 7, ///< RFC6975
TYPE_ECS = 8, ///< RFC7871 TYPE_ECS = 8, ///< RFC7871
TYPE_EXPIRE = 9, ///< RFC7314 TYPE_EXPIRE = 9, ///< RFC7314
TYPE_COOKIE = 10, ///< RFC7873
TYPE_TCP_KA = 11, ///< RFC7828 TYPE_TCP_KA = 11, ///< RFC7828
TYPE_PAD = 12, ///< RFC7830 TYPE_PAD = 12, ///< RFC7830
TYPE_CHAIN = 13, ///< RFC7901 TYPE_CHAIN = 13, ///< RFC7901
@ -156,6 +157,16 @@ struct EDNS_ECS {
zeek::IntrusivePtr<zeek::AddrVal> ecs_addr; ///< EDNS client subnet address zeek::IntrusivePtr<zeek::AddrVal> ecs_addr; ///< EDNS client subnet address
}; };
struct EDNS_TCP_KEEPALIVE {
bool keepalive_timeout_omitted; ///< whether the keepalive timeout is omitted
uint16_t keepalive_timeout; ///< the timeout value (in 100ms) sent by the client/server
};
struct EDNS_COOKIE {
zeek::String* client_cookie; ///< cookie value sent by the client (8 bytes)
zeek::String* server_cookie; ///< cookie value sent by the server (0 or 8-32 bytes)
};
struct TSIG_DATA { struct TSIG_DATA {
zeek::String* alg_name; zeek::String* alg_name;
unsigned long time_s; unsigned long time_s;
@ -211,6 +222,8 @@ public:
zeek::RecordValPtr BuildAnswerVal(); zeek::RecordValPtr BuildAnswerVal();
zeek::RecordValPtr BuildEDNS_Val(); zeek::RecordValPtr BuildEDNS_Val();
zeek::RecordValPtr BuildEDNS_ECS_Val(struct EDNS_ECS*); zeek::RecordValPtr BuildEDNS_ECS_Val(struct EDNS_ECS*);
zeek::RecordValPtr BuildEDNS_TCP_KA_Val(struct EDNS_TCP_KEEPALIVE*);
zeek::RecordValPtr BuildEDNS_COOKIE_Val(struct EDNS_COOKIE*);
zeek::RecordValPtr BuildTSIG_Val(struct TSIG_DATA*); zeek::RecordValPtr BuildTSIG_Val(struct TSIG_DATA*);
zeek::RecordValPtr BuildRRSIG_Val(struct RRSIG_DATA*); zeek::RecordValPtr BuildRRSIG_Val(struct RRSIG_DATA*);
zeek::RecordValPtr BuildDNSKEY_Val(struct DNSKEY_DATA*); zeek::RecordValPtr BuildDNSKEY_Val(struct DNSKEY_DATA*);

View file

@ -528,6 +528,56 @@ event dns_EDNS_addl%(c: connection, msg: dns_msg, ans: dns_edns_additional%);
## dns_skip_all_addl dns_skip_all_auth dns_skip_auth ## dns_skip_all_addl dns_skip_all_auth dns_skip_auth
event dns_EDNS_ecs%(c: connection, msg: dns_msg, opt: dns_edns_ecs%); event dns_EDNS_ecs%(c: connection, msg: dns_msg, opt: dns_edns_ecs%);
## Generated for DNS replies of type *EDNS*, and an option field in this *EDNS* record has
## an opt-type of 11. For replies with multiple option fields, an individual event is
## raised for each.
##
## See `Wikipedia <http://en.wikipedia.org/wiki/Domain_Name_System>`__ for more
## information about the DNS protocol. See `RFC7828 <https://tools.ietf.org/html/rfc7828>`__ for
## more information about EDNS0 TCP keepalive. Zeek analyzes both UDP and TCP DNS
## sessions.
##
## c: The connection, which may be UDP or TCP depending on the type of the
## transport-layer session being analyzed.
##
## msg: The parsed DNS message header.
##
## opt: The parsed EDNS Keepalive option.
##
## .. zeek:see:: dns_AAAA_reply dns_A_reply dns_CNAME_reply dns_HINFO_reply dns_MX_reply
## dns_NS_reply dns_PTR_reply dns_SOA_reply dns_SRV_reply dns_TSIG_addl
## dns_TXT_reply dns_SPF_reply dns_WKS_reply dns_end dns_mapping_altered
## dns_mapping_lost_name dns_mapping_new_name dns_mapping_unverified
## dns_mapping_valid dns_message dns_query_reply dns_rejected dns_request
## dns_max_queries dns_session_timeout dns_skip_addl
## dns_skip_all_addl dns_skip_all_auth dns_skip_auth
event dns_EDNS_tcp_keepalive%(c: connection, msg: dns_msg, opt: dns_edns_tcp_keepalive%);
## Generated for DNS replies of type *EDNS*, and an option field in this *EDNS* record has
## an opt-type of 10. For replies with multiple options fields, an individual event
## is raised for each.
##
## See `Wikipedia <http://en.wikipedia.org/wiki/Domain_Name_System>`__ for more
## information about the DNS protocol. See `RFC7873 <https://tools.ietf.org/html/rfc7873>`__ for
## more information about EDNS0 cookie. Zeek analyzes both UDP and TCP DNS
## sessions.
##
## c: The connection, which may be UDP or TCP depending on the type of the
## transport-layer session being analyzed.
##
## msg: The parsed DNS message header.
##
## opt: The parsed EDNS Cookie option.
##
## .. zeek:see:: dns_AAAA_reply dns_A_reply dns_CNAME_reply dns_HINFO_reply dns_MX_reply
## dns_NS_reply dns_PTR_reply dns_SOA_reply dns_SRV_reply dns_TSIG_addl
## dns_TXT_reply dns_SPF_reply dns_WKS_reply dns_end dns_mapping_altered
## dns_mapping_lost_name dns_mapping_new_name dns_mapping_unverified
## dns_mapping_valid dns_message dns_query_reply dns_rejected dns_request
## dns_max_queries dns_session_timeout dns_skip_addl
## dns_skip_all_addl dns_skip_all_auth dns_skip_auth
event dns_EDNS_cookie%(c: connection, msg: dns_msg, opt: dns_edns_cookie%);
## Generated for DNS replies of type *TSIG*. For replies with multiple answers, ## Generated for DNS replies of type *TSIG*. For replies with multiple answers,
## an individual event of the corresponding type is raised for each. ## an individual event of the corresponding type is raised for each.
## ##

View file

@ -0,0 +1,4 @@
[client_cookie=\xc8\x14\x98Z\x92\x8acB, server_cookie=]
[client_cookie=\xc8\x14\x98Z\x92\x8acB, server_cookie==\xcd>O{\xa9$z]
[client_cookie=1;Pl\x0b\xdd\x04s, server_cookie=]
[client_cookie=1;Pl\x0b\xdd\x04s, server_cookie=\xb0\xb1.E\xbahYl]

View file

@ -0,0 +1,4 @@
[keepalive_timeout_omitted=F, keepalive_timeout=10]
[keepalive_timeout_omitted=F, keepalive_timeout=370]
[keepalive_timeout_omitted=T, keepalive_timeout=0]
[keepalive_timeout_omitted=F, keepalive_timeout=370]

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,8 @@
# @TEST-EXEC: zeek -C -r $TRACES/dns-edns-cookie.pcap %INPUT > output
# @TEST-EXEC: btest-diff output
@load policy/protocols/dns/auth-addl
event dns_EDNS_cookie(c: connection, msg: dns_msg, opt: dns_edns_cookie)
{
print opt;
}

View file

@ -0,0 +1,8 @@
# @TEST-EXEC: zeek -C -r $TRACES/dns-edns-tcp-keepalive.pcap %INPUT > output
# @TEST-EXEC: btest-diff output
@load policy/protocols/dns/auth-addl
event dns_EDNS_tcp_keepalive(c: connection, msg: dns_msg, opt: dns_edns_tcp_keepalive)
{
print opt;
}