mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
Merge remote-tracking branch 'ronwellman/parse_ecs'
* ronwellman/parse_ecs: Avoid typecast to int& in EDNS parsing. Validate option_len in EDNS packets. Adjust for zeek namespace. Implement EDNS Client Subnet Option
This commit is contained in:
commit
3eab3e600e
14 changed files with 192 additions and 11 deletions
4
CHANGES
4
CHANGES
|
@ -1,4 +1,8 @@
|
||||||
|
|
||||||
|
3.2.0-dev.979 | 2020-07-24 09:03:06 -0700
|
||||||
|
|
||||||
|
* Implement EDNS Client Subnet Option (Ron Wellman)
|
||||||
|
|
||||||
3.2.0-dev.974 | 2020-07-23 13:02:13 -0700
|
3.2.0-dev.974 | 2020-07-23 13:02:13 -0700
|
||||||
|
|
||||||
* origin/topic/jsiwek/gh-1076-fix-random:
|
* origin/topic/jsiwek/gh-1076-fix-random:
|
||||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
3.2.0-dev.974
|
3.2.0-dev.979
|
||||||
|
|
2
doc
2
doc
|
@ -1 +1 @@
|
||||||
Subproject commit 48d9a82760a1c06ba40fce4c27677d01f6c263f9
|
Subproject commit bbd144f84d41a687dc5dbf447db6626063132dd2
|
|
@ -3690,6 +3690,16 @@ type dns_edns_additional: record {
|
||||||
is_query: count; ##< TODO.
|
is_query: count; ##< TODO.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
## An DNS EDNS Client Subnet (ECS) record.
|
||||||
|
##
|
||||||
|
## .. zeek:see:: dns_EDNS_ecs
|
||||||
|
type dns_edns_ecs: record {
|
||||||
|
family: string; ##< IP Family
|
||||||
|
source_prefix_len: count; ##< Source Prefix Length.
|
||||||
|
scope_prefix_len: count; ##< Scope Prefix Length.
|
||||||
|
address: string; ##< Client Subnet Address.
|
||||||
|
};
|
||||||
|
|
||||||
## An additional DNS TSIG record.
|
## An additional DNS TSIG record.
|
||||||
##
|
##
|
||||||
## .. zeek:see:: dns_TSIG_addl
|
## .. zeek:see:: dns_TSIG_addl
|
||||||
|
|
|
@ -527,6 +527,10 @@ event dns_SRV_reply(c: connection, msg: dns_msg, ans: dns_answer, target: string
|
||||||
# {
|
# {
|
||||||
#
|
#
|
||||||
# }
|
# }
|
||||||
|
# event dns_EDNS_ecs(c: connection, msg: dns_msg, opt: dns_edns_ecs)
|
||||||
|
# {
|
||||||
|
#
|
||||||
|
# }
|
||||||
#
|
#
|
||||||
#event dns_TSIG_addl(c: connection, msg: dns_msg, ans: dns_tsig_additional)
|
#event dns_TSIG_addl(c: connection, msg: dns_msg, ans: dns_tsig_additional)
|
||||||
# {
|
# {
|
||||||
|
|
|
@ -107,6 +107,7 @@ zeek::RecordType* dns_msg;
|
||||||
zeek::RecordType* dns_answer;
|
zeek::RecordType* dns_answer;
|
||||||
zeek::RecordType* dns_soa;
|
zeek::RecordType* dns_soa;
|
||||||
zeek::RecordType* dns_edns_additional;
|
zeek::RecordType* dns_edns_additional;
|
||||||
|
zeek::RecordType* dns_edns_ecs;
|
||||||
zeek::RecordType* dns_tsig_additional;
|
zeek::RecordType* dns_tsig_additional;
|
||||||
zeek::RecordType* dns_rrsig_rr;
|
zeek::RecordType* dns_rrsig_rr;
|
||||||
zeek::RecordType* dns_dnskey_rr;
|
zeek::RecordType* dns_dnskey_rr;
|
||||||
|
|
|
@ -149,6 +149,8 @@ extern zeek::RecordType* dns_soa;
|
||||||
[[deprecated("Remove in v4.1. Perform your own lookup.")]]
|
[[deprecated("Remove in v4.1. Perform your own lookup.")]]
|
||||||
extern zeek::RecordType* dns_edns_additional;
|
extern zeek::RecordType* dns_edns_additional;
|
||||||
[[deprecated("Remove in v4.1. Perform your own lookup.")]]
|
[[deprecated("Remove in v4.1. Perform your own lookup.")]]
|
||||||
|
extern zeek::RecordType* dns_edns_ecs;
|
||||||
|
[[deprecated("Remove in v4.1. Perform your own lookup.")]]
|
||||||
extern zeek::RecordType* dns_tsig_additional;
|
extern zeek::RecordType* dns_tsig_additional;
|
||||||
[[deprecated("Remove in v4.1. Perform your own lookup.")]]
|
[[deprecated("Remove in v4.1. Perform your own lookup.")]]
|
||||||
extern zeek::RecordType* dns_rrsig_rr;
|
extern zeek::RecordType* dns_rrsig_rr;
|
||||||
|
|
|
@ -700,8 +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)
|
||||||
{
|
{
|
||||||
// We need a pair-value set mechanism here to dump useful information
|
|
||||||
// out to the policy side of the house if rdlength > 0.
|
|
||||||
|
|
||||||
if ( dns_EDNS_addl && ! msg->skip_event )
|
if ( dns_EDNS_addl && ! msg->skip_event )
|
||||||
analyzer->EnqueueConnEvent(dns_EDNS_addl,
|
analyzer->EnqueueConnEvent(dns_EDNS_addl,
|
||||||
|
@ -710,13 +708,88 @@ bool DNS_Interpreter::ParseRR_EDNS(DNS_MsgInfo* msg,
|
||||||
msg->BuildEDNS_Val()
|
msg->BuildEDNS_Val()
|
||||||
);
|
);
|
||||||
|
|
||||||
// Currently EDNS supports the movement of type:data pairs
|
// parse EDNS options
|
||||||
// in the RR_DATA section. Here's where we should put together
|
while ( len > 0 )
|
||||||
// a corresponding mechanism.
|
{
|
||||||
if ( rdlength > 0 )
|
uint16_t option_code = ExtractShort(data, len);
|
||||||
{ // deal with data
|
int option_len = ExtractShort(data, len);
|
||||||
data += rdlength;
|
// check for invalid option length
|
||||||
len -= rdlength;
|
if ( (option_len > len) || (0 == option_len) ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
len -= option_len;
|
||||||
|
|
||||||
|
// TODO: Implement additional option codes
|
||||||
|
switch ( option_code )
|
||||||
|
{
|
||||||
|
case TYPE_ECS:
|
||||||
|
{
|
||||||
|
// must be 4 bytes + variable number of octets for address
|
||||||
|
if ( option_len <= 4 ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
EDNS_ECS opt{};
|
||||||
|
uint16_t ecs_family = ExtractShort(data, option_len);
|
||||||
|
uint16_t source_scope = ExtractShort(data, option_len);
|
||||||
|
opt.ecs_src_pfx_len = (source_scope >> 8) & 0xff;
|
||||||
|
opt.ecs_scp_pfx_len = source_scope & 0xff;
|
||||||
|
|
||||||
|
// ADDRESS, variable number of octets, contains either an IPv4 or
|
||||||
|
// IPv6 address, depending on FAMILY, which MUST be truncated to the
|
||||||
|
// number of bits indicated by the SOURCE PREFIX-LENGTH field,
|
||||||
|
// padding with 0 bits to pad to the end of the last octet needed.
|
||||||
|
if ( ecs_family == L3_IPV4 )
|
||||||
|
{
|
||||||
|
opt.ecs_family = zeek::make_intrusive<zeek::StringVal>("v4");
|
||||||
|
uint32_t addr = 0;
|
||||||
|
for (uint16_t shift_factor = 3; option_len > 0; option_len--)
|
||||||
|
{
|
||||||
|
addr |= data[0] << (shift_factor * 8);
|
||||||
|
data++;
|
||||||
|
shift_factor--;
|
||||||
|
}
|
||||||
|
addr = htonl(addr);
|
||||||
|
opt.ecs_addr = zeek::make_intrusive<zeek::AddrVal>(addr);
|
||||||
|
}
|
||||||
|
else if ( ecs_family == L3_IPV6 )
|
||||||
|
{
|
||||||
|
opt.ecs_family = zeek::make_intrusive<zeek::StringVal>("v6");
|
||||||
|
uint32_t addr[4] = { 0 };
|
||||||
|
for (uint16_t i = 0, shift_factor = 15; option_len > 0; option_len--)
|
||||||
|
{
|
||||||
|
addr[i / 4] |= data[0] << ((shift_factor % 4) * 8);
|
||||||
|
data++;
|
||||||
|
i++;
|
||||||
|
shift_factor--;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
addr[i] = htonl(addr[i]);
|
||||||
|
}
|
||||||
|
opt.ecs_addr = zeek::make_intrusive<zeek::AddrVal>(addr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// non ipv4/ipv6 family address
|
||||||
|
data += option_len;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
analyzer->EnqueueConnEvent(dns_EDNS_ecs,
|
||||||
|
analyzer->ConnVal(),
|
||||||
|
msg->BuildHdrVal(),
|
||||||
|
msg->BuildEDNS_ECS_Val(&opt)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
data += option_len;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -1518,6 +1591,19 @@ zeek::RecordValPtr DNS_MsgInfo::BuildEDNS_Val()
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
zeek::RecordValPtr DNS_MsgInfo::BuildEDNS_ECS_Val(struct EDNS_ECS* opt)
|
||||||
|
{
|
||||||
|
static auto dns_edns_ecs = zeek::id::find_type<zeek::RecordType>("dns_edns_ecs");
|
||||||
|
auto r = zeek::make_intrusive<zeek::RecordVal>(dns_edns_ecs);
|
||||||
|
|
||||||
|
r->Assign(0, opt->ecs_family);
|
||||||
|
r->Assign(1, zeek::val_mgr->Count(opt->ecs_src_pfx_len));
|
||||||
|
r->Assign(2, zeek::val_mgr->Count(opt->ecs_scp_pfx_len));
|
||||||
|
r->Assign(3, opt->ecs_addr);
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
|
@ -81,6 +81,27 @@ typedef enum {
|
||||||
DNS_ADDITIONAL,
|
DNS_ADDITIONAL,
|
||||||
} DNS_AnswerType;
|
} DNS_AnswerType;
|
||||||
|
|
||||||
|
// https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml
|
||||||
|
// DNS EDNS0 Option Codes (OPT)
|
||||||
|
typedef enum {
|
||||||
|
TYPE_LLQ = 1, ///< https://www.iana.org/go/draft-sekar-dns-llq-06
|
||||||
|
TYPE_UL = 2, ///< http://files.dns-sd.org/draft-sekar-dns-ul.txt
|
||||||
|
TYPE_NSID = 3, ///< RFC5001
|
||||||
|
TYPE_DAU = 5, ///< RFC6975
|
||||||
|
TYPE_DHU = 6, ///< RFC6975
|
||||||
|
TYPE_N3U = 7, ///< RFC6975
|
||||||
|
TYPE_ECS = 8, ///< RFC7871
|
||||||
|
TYPE_EXPIRE = 9, ///< RFC7314
|
||||||
|
TYPE_TCP_KA = 11, ///< RFC7828
|
||||||
|
TYPE_PAD = 12, ///< RFC7830
|
||||||
|
TYPE_CHAIN = 13, ///< RFC7901
|
||||||
|
TYPE_KEY_TAG = 14, ///< RFC8145
|
||||||
|
TYPE_ERROR = 15, ///< https://www.iana.org/go/draft-ietf-dnsop-extended-error-16
|
||||||
|
TYPE_CLIENT_TAG = 16, ///< https://www.iana.org/go/draft-bellis-dnsop-edns-tags
|
||||||
|
TYPE_SERVER_TAG = 17, ///< https://www.iana.org/go/draft-bellis-dnsop-edns-tags
|
||||||
|
TYPE_DEVICE_ID = 26946 ///< https://docs.umbrella.com/developer/networkdevices-api/identifying-dns-traffic2
|
||||||
|
} EDNS_OPT_Type;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
reserved0 = 0,
|
reserved0 = 0,
|
||||||
RSA_MD5 = 1, ///< [RFC2537] NOT RECOMMENDED
|
RSA_MD5 = 1, ///< [RFC2537] NOT RECOMMENDED
|
||||||
|
@ -128,6 +149,13 @@ struct EDNS_ADDITIONAL { // size
|
||||||
unsigned short rdata_len; // 16
|
unsigned short rdata_len; // 16
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct EDNS_ECS {
|
||||||
|
zeek::StringValPtr ecs_family; ///< EDNS client subnet address family
|
||||||
|
uint16_t ecs_src_pfx_len; ///< EDNS client subnet source prefix length
|
||||||
|
uint16_t ecs_scp_pfx_len; ///< EDNS client subnet scope prefix length
|
||||||
|
zeek::IntrusivePtr<zeek::AddrVal> ecs_addr; ///< EDNS client subnet address
|
||||||
|
};
|
||||||
|
|
||||||
struct TSIG_DATA {
|
struct TSIG_DATA {
|
||||||
zeek::String* alg_name;
|
zeek::String* alg_name;
|
||||||
unsigned long time_s;
|
unsigned long time_s;
|
||||||
|
@ -182,6 +210,7 @@ public:
|
||||||
zeek::RecordValPtr BuildHdrVal();
|
zeek::RecordValPtr BuildHdrVal();
|
||||||
zeek::RecordValPtr BuildAnswerVal();
|
zeek::RecordValPtr BuildAnswerVal();
|
||||||
zeek::RecordValPtr BuildEDNS_Val();
|
zeek::RecordValPtr BuildEDNS_Val();
|
||||||
|
zeek::RecordValPtr BuildEDNS_ECS_Val(struct EDNS_ECS*);
|
||||||
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*);
|
||||||
|
@ -271,6 +300,9 @@ protected:
|
||||||
bool ParseRR_EDNS(DNS_MsgInfo* msg,
|
bool 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);
|
||||||
|
bool ParseRR_EDNS_ECS(DNS_MsgInfo* msg,
|
||||||
|
const u_char*& data, int& len, int rdlength,
|
||||||
|
const u_char* msg_start);
|
||||||
bool ParseRR_A(DNS_MsgInfo* msg,
|
bool ParseRR_A(DNS_MsgInfo* msg,
|
||||||
const u_char*& data, int& len, int rdlength);
|
const u_char*& data, int& len, int rdlength);
|
||||||
bool ParseRR_AAAA(DNS_MsgInfo* msg,
|
bool ParseRR_AAAA(DNS_MsgInfo* msg,
|
||||||
|
|
|
@ -505,6 +505,29 @@ event dns_unknown_reply%(c: connection, msg: dns_msg, ans: dns_answer%);
|
||||||
## 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_addl%(c: connection, msg: dns_msg, ans: dns_edns_additional%);
|
event dns_EDNS_addl%(c: connection, msg: dns_msg, ans: dns_edns_additional%);
|
||||||
|
|
||||||
|
## Generated for DNS replies of type *EDNS*. For replies with multiple options,
|
||||||
|
## an individual event is raised for each.
|
||||||
|
##
|
||||||
|
## See `Wikipedia <http://en.wikipedia.org/wiki/Domain_Name_System>`__ for more
|
||||||
|
## information about the DNS protocol. 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 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_ecs%(c: connection, msg: dns_msg, opt: dns_edns_ecs%);
|
||||||
|
|
||||||
## 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.
|
||||||
##
|
##
|
||||||
|
|
|
@ -42,6 +42,7 @@ void zeek_legacy_netvar_init()
|
||||||
::dns_answer = zeek::id::find_type("dns_answer")->AsRecordType();
|
::dns_answer = zeek::id::find_type("dns_answer")->AsRecordType();
|
||||||
::dns_soa = zeek::id::find_type("dns_soa")->AsRecordType();
|
::dns_soa = zeek::id::find_type("dns_soa")->AsRecordType();
|
||||||
::dns_edns_additional = zeek::id::find_type("dns_edns_additional")->AsRecordType();
|
::dns_edns_additional = zeek::id::find_type("dns_edns_additional")->AsRecordType();
|
||||||
|
::dns_edns_ecs = zeek::id::find_type("dns_edns_ecs")->AsRecordType();
|
||||||
::dns_tsig_additional = zeek::id::find_type("dns_tsig_additional")->AsRecordType();
|
::dns_tsig_additional = zeek::id::find_type("dns_tsig_additional")->AsRecordType();
|
||||||
::dns_rrsig_rr = zeek::id::find_type("dns_rrsig_rr")->AsRecordType();
|
::dns_rrsig_rr = zeek::id::find_type("dns_rrsig_rr")->AsRecordType();
|
||||||
::dns_dnskey_rr = zeek::id::find_type("dns_dnskey_rr")->AsRecordType();
|
::dns_dnskey_rr = zeek::id::find_type("dns_dnskey_rr")->AsRecordType();
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
[family=v4, source_prefix_len=24, scope_prefix_len=0, address=213.61.29.0]
|
||||||
|
[family=v4, source_prefix_len=24, scope_prefix_len=0, address=213.61.29.0]
|
||||||
|
[family=v6, source_prefix_len=56, scope_prefix_len=0, address=2001:470:1f0b:1600::]
|
||||||
|
[family=v6, source_prefix_len=56, scope_prefix_len=0, address=2001:470:1f0b:1600::]
|
||||||
|
[family=v6, source_prefix_len=56, scope_prefix_len=0, address=2001:470:1f0b:1600::]
|
||||||
|
[family=v6, source_prefix_len=56, scope_prefix_len=0, address=2001:470:1f0b:1600::]
|
||||||
|
[family=v6, source_prefix_len=56, scope_prefix_len=0, address=2001:470:1f0b:1600::]
|
||||||
|
[family=v6, source_prefix_len=56, scope_prefix_len=0, address=2001:470:1f0b:1600::]
|
||||||
|
[family=v6, source_prefix_len=56, scope_prefix_len=0, address=2001:470:1f0b:1600::]
|
||||||
|
[family=v6, source_prefix_len=56, scope_prefix_len=0, address=2001:470:1f0b:1600::]
|
BIN
testing/btest/Traces/dns-edns-ecs.pcap
Normal file
BIN
testing/btest/Traces/dns-edns-ecs.pcap
Normal file
Binary file not shown.
|
@ -0,0 +1,8 @@
|
||||||
|
# @TEST-EXEC: zeek -C -r $TRACES/dns-edns-ecs.pcap %INPUT > output
|
||||||
|
# @TEST-EXEC: btest-diff output
|
||||||
|
|
||||||
|
@load policy/protocols/dns/auth-addl
|
||||||
|
|
||||||
|
event dns_EDNS_ecs(c: connection, msg: dns_msg, opt: dns_edns_ecs) {
|
||||||
|
print opt;
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue