diff --git a/scripts/base/init-bare.zeek b/scripts/base/init-bare.zeek index 635dec2cd2..9045370db9 100644 --- a/scripts/base/init-bare.zeek +++ b/scripts/base/init-bare.zeek @@ -995,6 +995,13 @@ const UDP_ACTIVE = 1; ##< Endpoint has sent something. ## variable. const ignore_checksums = F &redef; +## Checksums are ignored for all packets with a src address within this set of +## addresses. Useful for cases where a host might be seeing packets collected +## from local hosts before checksums were applied by hardware. This frequently +## manifests when sniffing a local management interface on a host and Zeek sees +## packets before the hardware has had a chance to apply the checksums. +option ignore_checksums_nets: set[subnet] = set(); + ## If true, instantiate connection state when a partial connection ## (one missing its initial establishment negotiation) is seen. const partial_connection_ok = T &redef; diff --git a/src/Val.cc b/src/Val.cc index fe479a6ad6..87f6e08e1d 100644 --- a/src/Val.cc +++ b/src/Val.cc @@ -1991,6 +1991,11 @@ ValPtr TableVal::FindOrDefault(const ValPtr& index) return Default(index); } +bool TableVal::Contains(const IPAddr& addr) + { + return subnets ? subnets->Lookup(addr, true) : false; + } + Val* TableVal::Lookup(Val* index, bool use_default_val) { static ValPtr last_default; diff --git a/src/Val.h b/src/Val.h index d634f0ee84..a38aae2c08 100644 --- a/src/Val.h +++ b/src/Val.h @@ -906,6 +906,10 @@ public: [[deprecated("Remove in v4.1. Use Find() or FindOrDefault().")]] Val* Lookup(Val* index, bool use_default_val = true); + // Returns true if this is a table[subnet]/set[subnet] and the + // given address was found in the table. Otherwise returns false. + bool Contains(const IPAddr& addr); + // For a table[subnet]/set[subnet], return all subnets that cover // the given subnet. // Causes an internal error if called for any other kind of table. diff --git a/src/analyzer/protocol/icmp/ICMP.cc b/src/analyzer/protocol/icmp/ICMP.cc index 3c8fbe1a35..49e8083574 100644 --- a/src/analyzer/protocol/icmp/ICMP.cc +++ b/src/analyzer/protocol/icmp/ICMP.cc @@ -49,7 +49,9 @@ void ICMP_Analyzer::DeliverPacket(int len, const u_char* data, const struct icmp* icmpp = (const struct icmp*) data; - if ( ! zeek::detail::ignore_checksums && caplen >= len ) + if ( ! zeek::detail::ignore_checksums && + ! zeek::id::find_val("ignore_checksums_nets")->Contains(ip->IPHeaderSrcAddr()) && + !caplen >= len ) { int chksum = 0; diff --git a/src/analyzer/protocol/tcp/TCP.cc b/src/analyzer/protocol/tcp/TCP.cc index b334541c01..c85d07ea23 100644 --- a/src/analyzer/protocol/tcp/TCP.cc +++ b/src/analyzer/protocol/tcp/TCP.cc @@ -272,11 +272,13 @@ const struct tcphdr* TCP_Analyzer::ExtractTCP_Header(const u_char*& data, return tp; } -bool TCP_Analyzer::ValidateChecksum(const struct tcphdr* tp, - TCP_Endpoint* endpoint, int len, int caplen, bool ipv4) +bool TCP_Analyzer::ValidateChecksum(const IP_Hdr* ip, const struct tcphdr* tp, + TCP_Endpoint* endpoint, int len, int caplen) { - if ( ! run_state::current_pkt->l3_checksummed && ! detail::ignore_checksums && caplen >= len && - ! endpoint->ValidChecksum(tp, len, ipv4) ) + if ( ! run_state::current_pkt->l3_checksummed && + ! detail::ignore_checksums && + ! zeek::id::find_val("ignore_checksums_nets")->Contains(ip->IPHeaderSrcAddr()) && + caplen >= len && ! endpoint->ValidChecksum(tp, len, ip->IP4_Hdr()) ) { Weird("bad_TCP_checksum"); endpoint->ChecksumError(); @@ -1060,7 +1062,7 @@ void TCP_Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig, TCP_Endpoint* endpoint = is_orig ? orig : resp; TCP_Endpoint* peer = endpoint->peer; - if ( ! ValidateChecksum(tp, endpoint, len, caplen, ip->IP4_Hdr()) ) + if ( ! ValidateChecksum(ip, tp, endpoint, len, caplen) ) return; uint32_t tcp_hdr_len = data - (const u_char*) tp; diff --git a/src/analyzer/protocol/tcp/TCP.h b/src/analyzer/protocol/tcp/TCP.h index 88be613af6..609afadbcc 100644 --- a/src/analyzer/protocol/tcp/TCP.h +++ b/src/analyzer/protocol/tcp/TCP.h @@ -94,8 +94,8 @@ protected: // Returns true if the checksum is valid, false if not (and in which // case also updates the status history of the endpoint). - bool ValidateChecksum(const struct tcphdr* tp, TCP_Endpoint* endpoint, - int len, int caplen, bool ipv4); + bool ValidateChecksum(const IP_Hdr* ip, const struct tcphdr* tp, TCP_Endpoint* endpoint, + int len, int caplen); void SetPartialStatus(TCP_Flags flags, bool is_orig); diff --git a/src/analyzer/protocol/udp/UDP.cc b/src/analyzer/protocol/udp/UDP.cc index 6208e73284..268aedd0ac 100644 --- a/src/analyzer/protocol/udp/UDP.cc +++ b/src/analyzer/protocol/udp/UDP.cc @@ -62,7 +62,12 @@ void UDP_Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig, int chksum = up->uh_sum; - auto validate_checksum = ! run_state::current_pkt->l3_checksummed && ! zeek::detail::ignore_checksums && caplen >=len; + auto validate_checksum = + ! run_state::current_pkt->l3_checksummed && + ! zeek::detail::ignore_checksums && + ! zeek::id::find_val("ignore_checksums_nets")->Contains(ip->IPHeaderSrcAddr()) && + caplen >=len; + constexpr auto vxlan_len = 8; constexpr auto eth_len = 14; diff --git a/src/packet_analysis/protocol/ip/IP.cc b/src/packet_analysis/protocol/ip/IP.cc index aff4f5606d..2978db9420 100644 --- a/src/packet_analysis/protocol/ip/IP.cc +++ b/src/packet_analysis/protocol/ip/IP.cc @@ -129,6 +129,7 @@ bool IPAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) return false; if ( ! packet->l2_checksummed && ! detail::ignore_checksums && ip4 && + ! zeek::id::find_val("ignore_checksums_nets")->Contains(packet->ip_hdr->IPHeaderSrcAddr()) && detail::in_cksum(reinterpret_cast(ip4), ip_hdr_len) != 0xffff ) { sessions->Weird("bad_IP_checksum", packet); diff --git a/testing/btest/Baseline/core.checksums_ignore_nets/conn-failed.log b/testing/btest/Baseline/core.checksums_ignore_nets/conn-failed.log new file mode 100644 index 0000000000..5aed1b62b1 --- /dev/null +++ b/testing/btest/Baseline/core.checksums_ignore_nets/conn-failed.log @@ -0,0 +1,11 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path conn +#open 2020-10-14-20-49-58 +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state local_orig local_resp missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes tunnel_parents +#types time string addr port addr port enum string interval count count string bool bool count string count count count count set[string] +1602707363.476578 CHhAvVGS1DHFjwGM9 192.168.1.28 53246 35.221.46.9 80 tcp - - - - OTH - - 0 C 0 0 0 0 - +1602707363.504737 ClEkJM2Vm5giqnMf4h 35.221.46.9 80 192.168.1.28 53246 tcp - 0.063810 432 0 SH - - 0 HcADF 4 604 0 0 - +#close 2020-10-14-20-49-58 diff --git a/testing/btest/Baseline/core.checksums_ignore_nets/conn-worked.log b/testing/btest/Baseline/core.checksums_ignore_nets/conn-worked.log new file mode 100644 index 0000000000..beeb9e46e1 --- /dev/null +++ b/testing/btest/Baseline/core.checksums_ignore_nets/conn-worked.log @@ -0,0 +1,10 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path conn +#open 2020-10-14-20-49-58 +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state local_orig local_resp missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes tunnel_parents +#types time string addr port addr port enum string interval count count string bool bool count string count count count count set[string] +1602707363.476578 CHhAvVGS1DHFjwGM9 192.168.1.28 53246 35.221.46.9 80 tcp - 0.091969 74 432 SF - - 0 ShADadFf 6 338 4 604 - +#close 2020-10-14-20-49-58 diff --git a/testing/btest/Traces/chksums/localhost-bad-chksum.pcap b/testing/btest/Traces/chksums/localhost-bad-chksum.pcap new file mode 100644 index 0000000000..1200e9c19a Binary files /dev/null and b/testing/btest/Traces/chksums/localhost-bad-chksum.pcap differ diff --git a/testing/btest/core/checksums_ignore_nets.test b/testing/btest/core/checksums_ignore_nets.test new file mode 100644 index 0000000000..89b21a502a --- /dev/null +++ b/testing/btest/core/checksums_ignore_nets.test @@ -0,0 +1,7 @@ +# @TEST-EXEC: zeek -b -r $TRACES/chksums/localhost-bad-chksum.pcap "ignore_checksums_nets += {192.168.0.0/16}" %INPUT && mv conn.log conn-worked.log +# @TEST-EXEC: zeek -b -r $TRACES/chksums/localhost-bad-chksum.pcap %INPUT && mv conn.log conn-failed.log + +# @TEST-EXEC: btest-diff conn-worked.log +# @TEST-EXEC: btest-diff conn-failed.log + +@load base/protocols/conn