From 0c3e3069d02046187c9c74caad8c85e7d7e337a1 Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Wed, 24 Feb 2021 15:04:48 -0700 Subject: [PATCH 01/10] Added skeletons for TCP/UDP/ICMP packet analysis plugins. This includes integration into the IP plugin and calling of the sessions code from each plugin. --- scripts/base/packet-protocols/__load__.zeek | 3 +++ .../base/packet-protocols/icmp/__load__.zeek | 1 + scripts/base/packet-protocols/icmp/main.zeek | 5 ++++ scripts/base/packet-protocols/ip/main.zeek | 20 +++++++++++--- .../base/packet-protocols/tcp/__load__.zeek | 1 + scripts/base/packet-protocols/tcp/main.zeek | 5 ++++ .../base/packet-protocols/udp/__load__.zeek | 1 + scripts/base/packet-protocols/udp/main.zeek | 5 ++++ src/packet_analysis/protocol/CMakeLists.txt | 3 +++ .../protocol/icmp/CMakeLists.txt | 8 ++++++ src/packet_analysis/protocol/icmp/ICMP.cc | 22 ++++++++++++++++ src/packet_analysis/protocol/icmp/ICMP.h | 26 +++++++++++++++++++ src/packet_analysis/protocol/icmp/Plugin.cc | 24 +++++++++++++++++ src/packet_analysis/protocol/ip/IP.cc | 8 ------ .../protocol/tcp/CMakeLists.txt | 8 ++++++ src/packet_analysis/protocol/tcp/Plugin.cc | 24 +++++++++++++++++ src/packet_analysis/protocol/tcp/TCP.cc | 22 ++++++++++++++++ src/packet_analysis/protocol/tcp/TCP.h | 26 +++++++++++++++++++ .../protocol/udp/CMakeLists.txt | 8 ++++++ src/packet_analysis/protocol/udp/Plugin.cc | 24 +++++++++++++++++ src/packet_analysis/protocol/udp/UDP.cc | 22 ++++++++++++++++ src/packet_analysis/protocol/udp/UDP.h | 26 +++++++++++++++++++ .../canonified_loaded_scripts.log | 6 +++++ .../canonified_loaded_scripts.log | 6 +++++ testing/btest/Baseline/plugins.hooks/output | 21 +++++++++++++++ 25 files changed, 314 insertions(+), 11 deletions(-) create mode 100644 scripts/base/packet-protocols/icmp/__load__.zeek create mode 100644 scripts/base/packet-protocols/icmp/main.zeek create mode 100644 scripts/base/packet-protocols/tcp/__load__.zeek create mode 100644 scripts/base/packet-protocols/tcp/main.zeek create mode 100644 scripts/base/packet-protocols/udp/__load__.zeek create mode 100644 scripts/base/packet-protocols/udp/main.zeek create mode 100644 src/packet_analysis/protocol/icmp/CMakeLists.txt create mode 100644 src/packet_analysis/protocol/icmp/ICMP.cc create mode 100644 src/packet_analysis/protocol/icmp/ICMP.h create mode 100644 src/packet_analysis/protocol/icmp/Plugin.cc create mode 100644 src/packet_analysis/protocol/tcp/CMakeLists.txt create mode 100644 src/packet_analysis/protocol/tcp/Plugin.cc create mode 100644 src/packet_analysis/protocol/tcp/TCP.cc create mode 100644 src/packet_analysis/protocol/tcp/TCP.h create mode 100644 src/packet_analysis/protocol/udp/CMakeLists.txt create mode 100644 src/packet_analysis/protocol/udp/Plugin.cc create mode 100644 src/packet_analysis/protocol/udp/UDP.cc create mode 100644 src/packet_analysis/protocol/udp/UDP.h diff --git a/scripts/base/packet-protocols/__load__.zeek b/scripts/base/packet-protocols/__load__.zeek index 6432eb5bd0..3a4d9209cb 100644 --- a/scripts/base/packet-protocols/__load__.zeek +++ b/scripts/base/packet-protocols/__load__.zeek @@ -15,3 +15,6 @@ @load base/packet-protocols/gre @load base/packet-protocols/iptunnel @load base/packet-protocols/vntag +@load base/packet-protocols/udp +@load base/packet-protocols/tcp +@load base/packet-protocols/icmp diff --git a/scripts/base/packet-protocols/icmp/__load__.zeek b/scripts/base/packet-protocols/icmp/__load__.zeek new file mode 100644 index 0000000000..d551be57d3 --- /dev/null +++ b/scripts/base/packet-protocols/icmp/__load__.zeek @@ -0,0 +1 @@ +@load ./main \ No newline at end of file diff --git a/scripts/base/packet-protocols/icmp/main.zeek b/scripts/base/packet-protocols/icmp/main.zeek new file mode 100644 index 0000000000..6746463e61 --- /dev/null +++ b/scripts/base/packet-protocols/icmp/main.zeek @@ -0,0 +1,5 @@ +module PacketAnalyzer::ICMP; + +#event zeek_init() &priority=20 +# { +# } diff --git a/scripts/base/packet-protocols/ip/main.zeek b/scripts/base/packet-protocols/ip/main.zeek index 1f33b6bc50..556b460a1c 100644 --- a/scripts/base/packet-protocols/ip/main.zeek +++ b/scripts/base/packet-protocols/ip/main.zeek @@ -1,8 +1,22 @@ module PacketAnalyzer::IP; +const IPPROTO_TCP : count = 6; +const IPPROTO_UDP : count = 17; +const IPPROTO_ICMP : count = 1; +const IPPROTO_ICMP6 : count = 58; + +const IPPROTO_IPIP : count = 4; +const IPPROTO_IPV6 : count = 41; +const IPPROTO_GRE : count = 47; + event zeek_init() &priority=20 { - PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, 4, PacketAnalyzer::ANALYZER_IPTUNNEL); - PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, 41, PacketAnalyzer::ANALYZER_IPTUNNEL); - PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, 47, PacketAnalyzer::ANALYZER_GRE); + PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, IPPROTO_IPIP, PacketAnalyzer::ANALYZER_IPTUNNEL); + PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, IPPROTO_IPV6, PacketAnalyzer::ANALYZER_IPTUNNEL); + PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, IPPROTO_GRE, PacketAnalyzer::ANALYZER_GRE); + + PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, IPPROTO_TCP, PacketAnalyzer::ANALYZER_TCP_PKT); + PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, IPPROTO_UDP, PacketAnalyzer::ANALYZER_UDP_PKT); + PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, IPPROTO_ICMP, PacketAnalyzer::ANALYZER_ICMP_PKT); + PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, IPPROTO_ICMP6, PacketAnalyzer::ANALYZER_ICMP_PKT); } diff --git a/scripts/base/packet-protocols/tcp/__load__.zeek b/scripts/base/packet-protocols/tcp/__load__.zeek new file mode 100644 index 0000000000..d551be57d3 --- /dev/null +++ b/scripts/base/packet-protocols/tcp/__load__.zeek @@ -0,0 +1 @@ +@load ./main \ No newline at end of file diff --git a/scripts/base/packet-protocols/tcp/main.zeek b/scripts/base/packet-protocols/tcp/main.zeek new file mode 100644 index 0000000000..ae11833950 --- /dev/null +++ b/scripts/base/packet-protocols/tcp/main.zeek @@ -0,0 +1,5 @@ +module PacketAnalyzer::TCP; + +#event zeek_init() &priority=20 +# { +# } diff --git a/scripts/base/packet-protocols/udp/__load__.zeek b/scripts/base/packet-protocols/udp/__load__.zeek new file mode 100644 index 0000000000..d551be57d3 --- /dev/null +++ b/scripts/base/packet-protocols/udp/__load__.zeek @@ -0,0 +1 @@ +@load ./main \ No newline at end of file diff --git a/scripts/base/packet-protocols/udp/main.zeek b/scripts/base/packet-protocols/udp/main.zeek new file mode 100644 index 0000000000..fe117ebf07 --- /dev/null +++ b/scripts/base/packet-protocols/udp/main.zeek @@ -0,0 +1,5 @@ +module PacketAnalyzer::UDP; + +#event zeek_init() &priority=20 +# { +# } diff --git a/src/packet_analysis/protocol/CMakeLists.txt b/src/packet_analysis/protocol/CMakeLists.txt index 62d1e1549b..9468bf2625 100644 --- a/src/packet_analysis/protocol/CMakeLists.txt +++ b/src/packet_analysis/protocol/CMakeLists.txt @@ -15,6 +15,9 @@ add_subdirectory(linux_sll) add_subdirectory(arp) add_subdirectory(ip) +add_subdirectory(udp) +add_subdirectory(tcp) +add_subdirectory(icmp) add_subdirectory(gre) add_subdirectory(iptunnel) add_subdirectory(vntag) diff --git a/src/packet_analysis/protocol/icmp/CMakeLists.txt b/src/packet_analysis/protocol/icmp/CMakeLists.txt new file mode 100644 index 0000000000..7b4eb86231 --- /dev/null +++ b/src/packet_analysis/protocol/icmp/CMakeLists.txt @@ -0,0 +1,8 @@ + +include(ZeekPlugin) + +include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) + +zeek_plugin_begin(PacketAnalyzer ICMP_PKT) +zeek_plugin_cc(ICMP.cc Plugin.cc) +zeek_plugin_end() diff --git a/src/packet_analysis/protocol/icmp/ICMP.cc b/src/packet_analysis/protocol/icmp/ICMP.cc new file mode 100644 index 0000000000..928c31db5c --- /dev/null +++ b/src/packet_analysis/protocol/icmp/ICMP.cc @@ -0,0 +1,22 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#include "zeek/packet_analysis/protocol/icmp/ICMP.h" +#include "zeek/RunState.h" +#include "zeek/session/Manager.h" + +using namespace zeek::packet_analysis::ICMP; + +ICMPAnalyzer::ICMPAnalyzer() + : zeek::packet_analysis::Analyzer("ICMP_PKT") + { + } + +ICMPAnalyzer::~ICMPAnalyzer() + { + } + +bool ICMPAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) + { + session_mgr->ProcessTransportLayer(run_state::processing_start_time, packet, len); + return true; + } diff --git a/src/packet_analysis/protocol/icmp/ICMP.h b/src/packet_analysis/protocol/icmp/ICMP.h new file mode 100644 index 0000000000..439a2740fe --- /dev/null +++ b/src/packet_analysis/protocol/icmp/ICMP.h @@ -0,0 +1,26 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#pragma once + +#include "zeek/packet_analysis/Analyzer.h" +#include "zeek/packet_analysis/Component.h" + +namespace zeek::packet_analysis::ICMP { + +class ICMPAnalyzer : public Analyzer { +public: + ICMPAnalyzer(); + ~ICMPAnalyzer() override; + + bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override; + + static zeek::packet_analysis::AnalyzerPtr Instantiate() + { + return std::make_shared(); + } + +private: + +}; + +} diff --git a/src/packet_analysis/protocol/icmp/Plugin.cc b/src/packet_analysis/protocol/icmp/Plugin.cc new file mode 100644 index 0000000000..0e339ebba1 --- /dev/null +++ b/src/packet_analysis/protocol/icmp/Plugin.cc @@ -0,0 +1,24 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#include "zeek/plugin/Plugin.h" +#include "zeek/packet_analysis/Component.h" +#include "zeek/packet_analysis/protocol/icmp/ICMP.h" + +namespace zeek::plugin::Zeek_ICMP { + +class Plugin : public zeek::plugin::Plugin { +public: + zeek::plugin::Configuration Configure() + { + AddComponent(new zeek::packet_analysis::Component("ICMP_PKT", + zeek::packet_analysis::ICMP::ICMPAnalyzer::Instantiate)); + + zeek::plugin::Configuration config; + config.name = "Zeek::ICMP_PKT"; + config.description = "Packet analyzer for ICMP"; + return config; + } + +} plugin; + +} diff --git a/src/packet_analysis/protocol/ip/IP.cc b/src/packet_analysis/protocol/ip/IP.cc index f38952bdc4..4e8f5c5766 100644 --- a/src/packet_analysis/protocol/ip/IP.cc +++ b/src/packet_analysis/protocol/ip/IP.cc @@ -235,14 +235,6 @@ bool IPAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) packet->proto = proto; switch ( proto ) { - case IPPROTO_TCP: - case IPPROTO_UDP: - case IPPROTO_ICMP: - case IPPROTO_ICMPV6: - DBG_LOG(DBG_PACKET_ANALYSIS, "Analysis in %s succeeded, next layer identifier is %#x.", - GetAnalyzerName(), proto); - session_mgr->ProcessTransportLayer(run_state::processing_start_time, packet, len); - break; case IPPROTO_NONE: // If the packet is encapsulated in Teredo, then it was a bubble and // the Teredo analyzer may have raised an event for that, else we're diff --git a/src/packet_analysis/protocol/tcp/CMakeLists.txt b/src/packet_analysis/protocol/tcp/CMakeLists.txt new file mode 100644 index 0000000000..c42cca2b25 --- /dev/null +++ b/src/packet_analysis/protocol/tcp/CMakeLists.txt @@ -0,0 +1,8 @@ + +include(ZeekPlugin) + +include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) + +zeek_plugin_begin(PacketAnalyzer TCP_PKT) +zeek_plugin_cc(TCP.cc Plugin.cc) +zeek_plugin_end() diff --git a/src/packet_analysis/protocol/tcp/Plugin.cc b/src/packet_analysis/protocol/tcp/Plugin.cc new file mode 100644 index 0000000000..cc791eedfa --- /dev/null +++ b/src/packet_analysis/protocol/tcp/Plugin.cc @@ -0,0 +1,24 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#include "zeek/plugin/Plugin.h" +#include "zeek/packet_analysis/Component.h" +#include "zeek/packet_analysis/protocol/tcp/TCP.h" + +namespace zeek::plugin::Zeek_TCP { + +class Plugin : public zeek::plugin::Plugin { +public: + zeek::plugin::Configuration Configure() + { + AddComponent(new zeek::packet_analysis::Component("TCP_PKT", + zeek::packet_analysis::TCP::TCPAnalyzer::Instantiate)); + + zeek::plugin::Configuration config; + config.name = "Zeek::TCP_PKT"; + config.description = "Packet analyzer for TCP"; + return config; + } + +} plugin; + +} diff --git a/src/packet_analysis/protocol/tcp/TCP.cc b/src/packet_analysis/protocol/tcp/TCP.cc new file mode 100644 index 0000000000..7fed612e07 --- /dev/null +++ b/src/packet_analysis/protocol/tcp/TCP.cc @@ -0,0 +1,22 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#include "zeek/packet_analysis/protocol/tcp/TCP.h" +#include "zeek/RunState.h" +#include "zeek/session/Manager.h" + +using namespace zeek::packet_analysis::TCP; + +TCPAnalyzer::TCPAnalyzer() + : zeek::packet_analysis::Analyzer("TCP_PKT") + { + } + +TCPAnalyzer::~TCPAnalyzer() + { + } + +bool TCPAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) + { + session_mgr->ProcessTransportLayer(run_state::processing_start_time, packet, len); + return true; + } diff --git a/src/packet_analysis/protocol/tcp/TCP.h b/src/packet_analysis/protocol/tcp/TCP.h new file mode 100644 index 0000000000..51f9208805 --- /dev/null +++ b/src/packet_analysis/protocol/tcp/TCP.h @@ -0,0 +1,26 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#pragma once + +#include "zeek/packet_analysis/Analyzer.h" +#include "zeek/packet_analysis/Component.h" + +namespace zeek::packet_analysis::TCP { + +class TCPAnalyzer : public Analyzer { +public: + TCPAnalyzer(); + ~TCPAnalyzer() override; + + bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override; + + static zeek::packet_analysis::AnalyzerPtr Instantiate() + { + return std::make_shared(); + } + +private: + +}; + +} diff --git a/src/packet_analysis/protocol/udp/CMakeLists.txt b/src/packet_analysis/protocol/udp/CMakeLists.txt new file mode 100644 index 0000000000..5e205c57f1 --- /dev/null +++ b/src/packet_analysis/protocol/udp/CMakeLists.txt @@ -0,0 +1,8 @@ + +include(ZeekPlugin) + +include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) + +zeek_plugin_begin(PacketAnalyzer UDP_PKT) +zeek_plugin_cc(UDP.cc Plugin.cc) +zeek_plugin_end() diff --git a/src/packet_analysis/protocol/udp/Plugin.cc b/src/packet_analysis/protocol/udp/Plugin.cc new file mode 100644 index 0000000000..f22ca797f1 --- /dev/null +++ b/src/packet_analysis/protocol/udp/Plugin.cc @@ -0,0 +1,24 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#include "zeek/plugin/Plugin.h" +#include "zeek/packet_analysis/Component.h" +#include "zeek/packet_analysis/protocol/udp/UDP.h" + +namespace zeek::plugin::Zeek_UDP { + +class Plugin : public zeek::plugin::Plugin { +public: + zeek::plugin::Configuration Configure() + { + AddComponent(new zeek::packet_analysis::Component("UDP_PKT", + zeek::packet_analysis::UDP::UDPAnalyzer::Instantiate)); + + zeek::plugin::Configuration config; + config.name = "Zeek::UDP_PKT"; + config.description = "Packet analyzer for UDP"; + return config; + } + +} plugin; + +} diff --git a/src/packet_analysis/protocol/udp/UDP.cc b/src/packet_analysis/protocol/udp/UDP.cc new file mode 100644 index 0000000000..620e7eb768 --- /dev/null +++ b/src/packet_analysis/protocol/udp/UDP.cc @@ -0,0 +1,22 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#include "zeek/packet_analysis/protocol/udp/UDP.h" +#include "zeek/RunState.h" +#include "zeek/session/Manager.h" + +using namespace zeek::packet_analysis::UDP; + +UDPAnalyzer::UDPAnalyzer() + : zeek::packet_analysis::Analyzer("UDP_PKT") + { + } + +UDPAnalyzer::~UDPAnalyzer() + { + } + +bool UDPAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) + { + session_mgr->ProcessTransportLayer(run_state::processing_start_time, packet, len); + return true; + } diff --git a/src/packet_analysis/protocol/udp/UDP.h b/src/packet_analysis/protocol/udp/UDP.h new file mode 100644 index 0000000000..0a941456a2 --- /dev/null +++ b/src/packet_analysis/protocol/udp/UDP.h @@ -0,0 +1,26 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#pragma once + +#include "zeek/packet_analysis/Analyzer.h" +#include "zeek/packet_analysis/Component.h" + +namespace zeek::packet_analysis::UDP { + +class UDPAnalyzer : public Analyzer { +public: + UDPAnalyzer(); + ~UDPAnalyzer() override; + + bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override; + + static zeek::packet_analysis::AnalyzerPtr Instantiate() + { + return std::make_shared(); + } + +private: + +}; + +} diff --git a/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log b/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log index af52d127d0..729d4b154e 100644 --- a/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log +++ b/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log @@ -57,6 +57,12 @@ scripts/base/init-bare.zeek scripts/base/packet-protocols/iptunnel/main.zeek scripts/base/packet-protocols/vntag/__load__.zeek scripts/base/packet-protocols/vntag/main.zeek + scripts/base/packet-protocols/udp/__load__.zeek + scripts/base/packet-protocols/udp/main.zeek + scripts/base/packet-protocols/tcp/__load__.zeek + scripts/base/packet-protocols/tcp/main.zeek + scripts/base/packet-protocols/icmp/__load__.zeek + scripts/base/packet-protocols/icmp/main.zeek scripts/base/init-frameworks-and-bifs.zeek scripts/base/frameworks/logging/__load__.zeek scripts/base/frameworks/logging/main.zeek diff --git a/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log b/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log index 84aa4662ee..6b5b777293 100644 --- a/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log +++ b/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log @@ -57,6 +57,12 @@ scripts/base/init-bare.zeek scripts/base/packet-protocols/iptunnel/main.zeek scripts/base/packet-protocols/vntag/__load__.zeek scripts/base/packet-protocols/vntag/main.zeek + scripts/base/packet-protocols/udp/__load__.zeek + scripts/base/packet-protocols/udp/main.zeek + scripts/base/packet-protocols/tcp/__load__.zeek + scripts/base/packet-protocols/tcp/main.zeek + scripts/base/packet-protocols/icmp/__load__.zeek + scripts/base/packet-protocols/icmp/main.zeek scripts/base/init-frameworks-and-bifs.zeek scripts/base/frameworks/logging/__load__.zeek scripts/base/frameworks/logging/main.zeek diff --git a/testing/btest/Baseline/plugins.hooks/output b/testing/btest/Baseline/plugins.hooks/output index 35ef76d80b..61bdd358ac 100644 --- a/testing/btest/Baseline/plugins.hooks/output +++ b/testing/btest/Baseline/plugins.hooks/output @@ -572,9 +572,13 @@ 0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IEEE802_11, 32821, PacketAnalyzer::ANALYZER_ARP)) -> 0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IEEE802_11, 34525, PacketAnalyzer::ANALYZER_IP)) -> 0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IEEE802_11_RADIO, 105, PacketAnalyzer::ANALYZER_IEEE802_11)) -> +0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 1, PacketAnalyzer::ANALYZER_ICMP_PKT)) -> +0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 17, PacketAnalyzer::ANALYZER_UDP_PKT)) -> 0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 4, PacketAnalyzer::ANALYZER_IPTUNNEL)) -> 0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 41, PacketAnalyzer::ANALYZER_IPTUNNEL)) -> 0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 47, PacketAnalyzer::ANALYZER_GRE)) -> +0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 58, PacketAnalyzer::ANALYZER_ICMP_PKT)) -> +0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 6, PacketAnalyzer::ANALYZER_TCP_PKT)) -> 0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_LINUXSLL, 2048, PacketAnalyzer::ANALYZER_IP)) -> 0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_LINUXSLL, 2054, PacketAnalyzer::ANALYZER_ARP)) -> 0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_LINUXSLL, 32821, PacketAnalyzer::ANALYZER_ARP)) -> @@ -915,6 +919,7 @@ 0.000000 MetaHookPost LoadFile(0, base<...>/hash, <...>/hash) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/hash_hrw, <...>/hash_hrw.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/http, <...>/http) -> -1 +0.000000 MetaHookPost LoadFile(0, base<...>/icmp, <...>/icmp) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/ieee802_11, <...>/ieee802_11) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/ieee802_11_radio, <...>/ieee802_11_radio) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/imap, <...>/imap) -> -1 @@ -979,10 +984,12 @@ 0.000000 MetaHookPost LoadFile(0, base<...>/supervisor, <...>/supervisor) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/supervisor.bif, <...>/supervisor.bif.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/syslog, <...>/syslog) -> -1 +0.000000 MetaHookPost LoadFile(0, base<...>/tcp, <...>/tcp) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/thresholds, <...>/thresholds.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/time, <...>/time.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/tunnels, <...>/tunnels) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/types.bif, <...>/types.bif.zeek) -> -1 +0.000000 MetaHookPost LoadFile(0, base<...>/udp, <...>/udp) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/urls, <...>/urls.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/utils, <...>/utils.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/version, <...>/version.zeek) -> -1 @@ -1582,9 +1589,13 @@ 0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IEEE802_11, 32821, PacketAnalyzer::ANALYZER_ARP)) 0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IEEE802_11, 34525, PacketAnalyzer::ANALYZER_IP)) 0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IEEE802_11_RADIO, 105, PacketAnalyzer::ANALYZER_IEEE802_11)) +0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 1, PacketAnalyzer::ANALYZER_ICMP_PKT)) +0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 17, PacketAnalyzer::ANALYZER_UDP_PKT)) 0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 4, PacketAnalyzer::ANALYZER_IPTUNNEL)) 0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 41, PacketAnalyzer::ANALYZER_IPTUNNEL)) 0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 47, PacketAnalyzer::ANALYZER_GRE)) +0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 58, PacketAnalyzer::ANALYZER_ICMP_PKT)) +0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 6, PacketAnalyzer::ANALYZER_TCP_PKT)) 0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_LINUXSLL, 2048, PacketAnalyzer::ANALYZER_IP)) 0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_LINUXSLL, 2054, PacketAnalyzer::ANALYZER_ARP)) 0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_LINUXSLL, 32821, PacketAnalyzer::ANALYZER_ARP)) @@ -1925,6 +1936,7 @@ 0.000000 MetaHookPre LoadFile(0, base<...>/hash, <...>/hash) 0.000000 MetaHookPre LoadFile(0, base<...>/hash_hrw, <...>/hash_hrw.zeek) 0.000000 MetaHookPre LoadFile(0, base<...>/http, <...>/http) +0.000000 MetaHookPre LoadFile(0, base<...>/icmp, <...>/icmp) 0.000000 MetaHookPre LoadFile(0, base<...>/ieee802_11, <...>/ieee802_11) 0.000000 MetaHookPre LoadFile(0, base<...>/ieee802_11_radio, <...>/ieee802_11_radio) 0.000000 MetaHookPre LoadFile(0, base<...>/imap, <...>/imap) @@ -1989,10 +2001,12 @@ 0.000000 MetaHookPre LoadFile(0, base<...>/supervisor, <...>/supervisor) 0.000000 MetaHookPre LoadFile(0, base<...>/supervisor.bif, <...>/supervisor.bif.zeek) 0.000000 MetaHookPre LoadFile(0, base<...>/syslog, <...>/syslog) +0.000000 MetaHookPre LoadFile(0, base<...>/tcp, <...>/tcp) 0.000000 MetaHookPre LoadFile(0, base<...>/thresholds, <...>/thresholds.zeek) 0.000000 MetaHookPre LoadFile(0, base<...>/time, <...>/time.zeek) 0.000000 MetaHookPre LoadFile(0, base<...>/tunnels, <...>/tunnels) 0.000000 MetaHookPre LoadFile(0, base<...>/types.bif, <...>/types.bif.zeek) +0.000000 MetaHookPre LoadFile(0, base<...>/udp, <...>/udp) 0.000000 MetaHookPre LoadFile(0, base<...>/urls, <...>/urls.zeek) 0.000000 MetaHookPre LoadFile(0, base<...>/utils, <...>/utils.zeek) 0.000000 MetaHookPre LoadFile(0, base<...>/version, <...>/version.zeek) @@ -2591,9 +2605,13 @@ 0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IEEE802_11, 32821, PacketAnalyzer::ANALYZER_ARP) 0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IEEE802_11, 34525, PacketAnalyzer::ANALYZER_IP) 0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IEEE802_11_RADIO, 105, PacketAnalyzer::ANALYZER_IEEE802_11) +0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, 1, PacketAnalyzer::ANALYZER_ICMP_PKT) +0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, 17, PacketAnalyzer::ANALYZER_UDP_PKT) 0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, 4, PacketAnalyzer::ANALYZER_IPTUNNEL) 0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, 41, PacketAnalyzer::ANALYZER_IPTUNNEL) 0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, 47, PacketAnalyzer::ANALYZER_GRE) +0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, 58, PacketAnalyzer::ANALYZER_ICMP_PKT) +0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, 6, PacketAnalyzer::ANALYZER_TCP_PKT) 0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_LINUXSLL, 2048, PacketAnalyzer::ANALYZER_IP) 0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_LINUXSLL, 2054, PacketAnalyzer::ANALYZER_ARP) 0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_LINUXSLL, 32821, PacketAnalyzer::ANALYZER_ARP) @@ -2946,6 +2964,7 @@ 0.000000 | HookLoadFile base<...>/hash <...>/hash 0.000000 | HookLoadFile base<...>/hash_hrw <...>/hash_hrw.zeek 0.000000 | HookLoadFile base<...>/http <...>/http +0.000000 | HookLoadFile base<...>/icmp <...>/icmp 0.000000 | HookLoadFile base<...>/ieee802_11 <...>/ieee802_11 0.000000 | HookLoadFile base<...>/ieee802_11_radio <...>/ieee802_11_radio 0.000000 | HookLoadFile base<...>/imap <...>/imap @@ -3010,10 +3029,12 @@ 0.000000 | HookLoadFile base<...>/supervisor <...>/supervisor 0.000000 | HookLoadFile base<...>/supervisor.bif <...>/supervisor.bif.zeek 0.000000 | HookLoadFile base<...>/syslog <...>/syslog +0.000000 | HookLoadFile base<...>/tcp <...>/tcp 0.000000 | HookLoadFile base<...>/thresholds <...>/thresholds.zeek 0.000000 | HookLoadFile base<...>/time <...>/time.zeek 0.000000 | HookLoadFile base<...>/tunnels <...>/tunnels 0.000000 | HookLoadFile base<...>/types.bif <...>/types.bif.zeek +0.000000 | HookLoadFile base<...>/udp <...>/udp 0.000000 | HookLoadFile base<...>/urls <...>/urls.zeek 0.000000 | HookLoadFile base<...>/utils <...>/utils.zeek 0.000000 | HookLoadFile base<...>/version <...>/version.zeek From 3e1692676d7dc8c7eab3603dc511accf7b73d4d1 Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Fri, 9 Apr 2021 15:46:19 -0700 Subject: [PATCH 02/10] Move SessionManager::ParseIPPacket to IP analyzer's namespace --- src/analyzer/protocol/ayiya/AYIYA.cc | 9 ++--- src/analyzer/protocol/gtpv1/GTPv1.cc | 9 ++--- src/analyzer/protocol/teredo/Teredo.cc | 10 ++--- src/analyzer/protocol/teredo/Teredo.h | 2 +- src/packet_analysis/protocol/ip/IP.cc | 38 +++++++++++++++++++ src/packet_analysis/protocol/ip/IP.h | 24 ++++++++++++ .../protocol/iptunnel/IPTunnel.cc | 13 ++----- .../protocol/iptunnel/IPTunnel.h | 2 +- src/session/Manager.cc | 37 ------------------ src/session/Manager.h | 25 ------------ 10 files changed, 78 insertions(+), 91 deletions(-) diff --git a/src/analyzer/protocol/ayiya/AYIYA.cc b/src/analyzer/protocol/ayiya/AYIYA.cc index b97a78570a..5c3812ddc6 100644 --- a/src/analyzer/protocol/ayiya/AYIYA.cc +++ b/src/analyzer/protocol/ayiya/AYIYA.cc @@ -2,9 +2,9 @@ #include "zeek/analyzer/protocol/ayiya/AYIYA.h" -#include "zeek/session/Manager.h" #include "zeek/Func.h" #include "zeek/packet_analysis/protocol/iptunnel/IPTunnel.h" +#include "zeek/packet_analysis/protocol/ip/IP.h" namespace zeek::analyzer::ayiya { @@ -46,8 +46,8 @@ void AYIYA_Analyzer::DeliverPacket(int len, const u_char* data, bool orig, uint6 caplen -= inner_packet_offset; inner_packet_offset = -1; - IP_Hdr* inner = nullptr; - int result = session_mgr->ParseIPPacket(len, data, next_header, inner); + std::unique_ptr inner; + int result = packet_analysis::IP::ParsePacket(len, data, next_header, inner); if ( result == 0 ) { @@ -66,9 +66,6 @@ void AYIYA_Analyzer::DeliverPacket(int len, const u_char* data, bool orig, uint6 else ProtocolViolation("AYIYA payload length", reinterpret_cast(data), len); - - if ( result != 0 ) - delete inner; } } // namespace zeek::analyzer::ayiya diff --git a/src/analyzer/protocol/gtpv1/GTPv1.cc b/src/analyzer/protocol/gtpv1/GTPv1.cc index 08d44171ee..f1c432d08d 100644 --- a/src/analyzer/protocol/gtpv1/GTPv1.cc +++ b/src/analyzer/protocol/gtpv1/GTPv1.cc @@ -2,8 +2,8 @@ #include "zeek/analyzer/protocol/gtpv1/GTPv1.h" #include "zeek/packet_analysis/protocol/iptunnel/IPTunnel.h" +#include "zeek/packet_analysis/protocol/ip/IP.h" -#include "zeek/session/Manager.h" #include "zeek/analyzer/protocol/gtpv1/events.bif.h" namespace zeek::analyzer::gtpv1 { @@ -47,8 +47,8 @@ void GTPv1_Analyzer::DeliverPacket(int len, const u_char* data, bool orig, uint6 caplen -= inner_packet_offset; inner_packet_offset = -1; - IP_Hdr* inner = nullptr; - int result = session_mgr->ParseIPPacket(len, data, next_header, inner); + std::unique_ptr inner = nullptr; + int result = packet_analysis::IP::ParsePacket(len, data, next_header, inner); if ( result == 0 ) { @@ -77,9 +77,6 @@ void GTPv1_Analyzer::DeliverPacket(int len, const u_char* data, bool orig, uint6 else ProtocolViolation("GTPv1 payload length", reinterpret_cast(odata), olen); - - if ( result != 0 ) - delete inner; } } // namespace zeek::analyzer::gtpv1 diff --git a/src/analyzer/protocol/teredo/Teredo.cc b/src/analyzer/protocol/teredo/Teredo.cc index f697802187..f7a8982b2f 100644 --- a/src/analyzer/protocol/teredo/Teredo.cc +++ b/src/analyzer/protocol/teredo/Teredo.cc @@ -4,10 +4,10 @@ #include "zeek/Conn.h" #include "zeek/IP.h" #include "zeek/Reporter.h" -#include "zeek/session/Manager.h" #include "zeek/ZeekString.h" #include "zeek/RunState.h" #include "zeek/packet_analysis/protocol/iptunnel/IPTunnel.h" +#include "zeek/packet_analysis/protocol/ip/IP.h" #include "zeek/analyzer/protocol/teredo/events.bif.h" @@ -94,7 +94,7 @@ bool TeredoEncapsulation::DoParse(const u_char* data, int& len, return false; } -RecordValPtr TeredoEncapsulation::BuildVal(const IP_Hdr* inner) const +RecordValPtr TeredoEncapsulation::BuildVal(const std::unique_ptr& inner) const { static auto teredo_hdr_type = id::find_type("teredo_hdr"); static auto teredo_auth_type = id::find_type("teredo_auth"); @@ -164,8 +164,8 @@ void Teredo_Analyzer::DeliverPacket(int len, const u_char* data, bool orig, return; } - IP_Hdr* inner = nullptr; - int rslt = session_mgr->ParseIPPacket(len, te.InnerIP(), IPPROTO_IPV6, inner); + std::unique_ptr inner = nullptr; + int rslt = packet_analysis::IP::ParsePacket(len, te.InnerIP(), IPPROTO_IPV6, inner); if ( rslt > 0 ) { @@ -175,7 +175,6 @@ void Teredo_Analyzer::DeliverPacket(int len, const u_char* data, bool orig, Weird("Teredo_bubble_with_payload", true); else { - delete inner; ProtocolViolation("Teredo payload length", (const char*) data, len); return; } @@ -193,7 +192,6 @@ void Teredo_Analyzer::DeliverPacket(int len, const u_char* data, bool orig, else { - delete inner; ProtocolViolation("Truncated Teredo or invalid inner IP version", (const char*) data, len); return; } diff --git a/src/analyzer/protocol/teredo/Teredo.h b/src/analyzer/protocol/teredo/Teredo.h index d2d87f7319..f6f377d056 100644 --- a/src/analyzer/protocol/teredo/Teredo.h +++ b/src/analyzer/protocol/teredo/Teredo.h @@ -74,7 +74,7 @@ public: const u_char* Authentication() const { return auth; } - RecordValPtr BuildVal(const IP_Hdr* inner) const; + RecordValPtr BuildVal(const std::unique_ptr& inner) const; protected: bool DoParse(const u_char* data, int& len, bool found_orig, bool found_au); diff --git a/src/packet_analysis/protocol/ip/IP.cc b/src/packet_analysis/protocol/ip/IP.cc index 4e8f5c5766..4d05600e6a 100644 --- a/src/packet_analysis/protocol/ip/IP.cc +++ b/src/packet_analysis/protocol/ip/IP.cc @@ -10,6 +10,7 @@ #include "zeek/Frag.h" #include "zeek/Event.h" #include "zeek/TunnelEncapsulation.h" +#include "zeek/IPAddr.h" using namespace zeek::packet_analysis::IP; @@ -260,3 +261,40 @@ bool IPAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) return return_val; } + +int zeek::packet_analysis::IP::ParsePacket(int caplen, const u_char* const pkt, int proto, + std::unique_ptr& inner) + { + if ( proto == IPPROTO_IPV6 ) + { + if ( caplen < (int)sizeof(struct ip6_hdr) ) + return -1; + + const struct ip6_hdr* ip6 = (const struct ip6_hdr*) pkt; + inner = std::make_unique(ip6, false, caplen); + if ( ( ip6->ip6_ctlun.ip6_un2_vfc & 0xF0 ) != 0x60 ) + return -2; + } + + else if ( proto == IPPROTO_IPV4 ) + { + if ( caplen < (int)sizeof(struct ip) ) + return -1; + + const struct ip* ip4 = (const struct ip*) pkt; + inner = std::make_unique(ip4, false); + if ( ip4->ip_v != 4 ) + return -2; + } + + else + { + zeek::reporter->InternalWarning("Bad IP protocol version in IP::ParsePacket"); + return -1; + } + + if ( (uint32_t)caplen != inner->TotalLen() ) + return (uint32_t)caplen < inner->TotalLen() ? -1 : 1; + + return 0; + } diff --git a/src/packet_analysis/protocol/ip/IP.h b/src/packet_analysis/protocol/ip/IP.h index e24f842283..5baec822c1 100644 --- a/src/packet_analysis/protocol/ip/IP.h +++ b/src/packet_analysis/protocol/ip/IP.h @@ -32,4 +32,28 @@ private: zeek::detail::Discarder* discarder = nullptr; }; +/** + * Returns a wrapper IP_Hdr object if \a pkt appears to be a valid IPv4 + * or IPv6 header based on whether it's long enough to contain such a header, + * if version given in the header matches the proto argument, and also checks + * that the payload length field of that header matches the actual + * length of \a pkt given by \a caplen. + * + * @param caplen The length of \a pkt in bytes. + * @param pkt The inner IP packet data. + * @param proto Either IPPROTO_IPV6 or IPPROTO_IPV4 to indicate which IP + * protocol \a pkt corresponds to. + * @param inner The inner IP packet wrapper pointer to be allocated/assigned + * if \a pkt looks like a valid IP packet or at least long enough + * to hold an IP header. + * @return 0 If the inner IP packet appeared valid, else -1 if \a caplen + * is greater than the supposed IP packet's payload length field, -2 + * if the version of the inner header does not match proto or + * 1 if \a caplen is less than the supposed packet's payload length. + * In the -1 case, \a inner may still be non-null if \a caplen was + * long enough to be an IP header, and \a inner is always non-null + * for other return values. + */ +int ParsePacket(int caplen, const u_char* const pkt, int proto, + std::unique_ptr& inner); } diff --git a/src/packet_analysis/protocol/iptunnel/IPTunnel.cc b/src/packet_analysis/protocol/iptunnel/IPTunnel.cc index 1131b2bce7..f6b9f07b12 100644 --- a/src/packet_analysis/protocol/iptunnel/IPTunnel.cc +++ b/src/packet_analysis/protocol/iptunnel/IPTunnel.cc @@ -4,10 +4,10 @@ #include // For DLT_ constants -#include "zeek/session/Manager.h" #include "zeek/RunState.h" #include "zeek/IP.h" #include "zeek/TunnelEncapsulation.h" +#include "zeek/packet_analysis/protocol/ip/IP.h" namespace zeek::packet_analysis::IPTunnel { @@ -45,12 +45,12 @@ bool IPTunnelAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* pa BifEnum::Tunnel::Type tunnel_type = packet->tunnel_type; int gre_link_type = packet->gre_link_type; - IP_Hdr* inner = nullptr; + std::unique_ptr inner = nullptr; if ( gre_version != 0 ) { // Check for a valid inner packet first. - int result = session_mgr->ParseIPPacket(len, data, proto, inner); + int result = packet_analysis::IP::ParsePacket(len, data, proto, inner); if ( result == -2 ) Weird("invalid_inner_IP_version", packet); else if ( result < 0 ) @@ -59,10 +59,7 @@ bool IPTunnelAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* pa Weird("inner_IP_payload_length_mismatch", packet); if ( result != 0 ) - { - delete inner; return false; - } } // Look up to see if we've already seen this IP tunnel, identified @@ -100,7 +97,7 @@ bool IPTunnelAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* pa * Handles a packet that contains an IP header directly after the tunnel header. */ bool IPTunnelAnalyzer::ProcessEncapsulatedPacket(double t, const Packet* pkt, - const IP_Hdr* inner, + const std::unique_ptr& inner, std::shared_ptr prev, const EncapsulatingConn& ec) { @@ -138,8 +135,6 @@ bool IPTunnelAnalyzer::ProcessEncapsulatedPacket(double t, const Packet* pkt, // Forward the packet back to the IP analyzer. bool return_val = ForwardPacket(len, data, &p); - delete inner; - return return_val; } diff --git a/src/packet_analysis/protocol/iptunnel/IPTunnel.h b/src/packet_analysis/protocol/iptunnel/IPTunnel.h index ddc8e04466..4e8242b17d 100644 --- a/src/packet_analysis/protocol/iptunnel/IPTunnel.h +++ b/src/packet_analysis/protocol/iptunnel/IPTunnel.h @@ -40,7 +40,7 @@ public: * @param ec The most-recently found depth of encapsulation. */ bool ProcessEncapsulatedPacket(double t, const Packet *pkt, - const IP_Hdr* inner, + const std::unique_ptr& inner, std::shared_ptr prev, const EncapsulatingConn& ec); diff --git a/src/session/Manager.cc b/src/session/Manager.cc index 0076cf1305..746fd14ac0 100644 --- a/src/session/Manager.cc +++ b/src/session/Manager.cc @@ -264,43 +264,6 @@ void Manager::ProcessTransportLayer(double t, const Packet* pkt, size_t remainin } } -int Manager::ParseIPPacket(int caplen, const u_char* const pkt, int proto, - IP_Hdr*& inner) - { - if ( proto == IPPROTO_IPV6 ) - { - if ( caplen < (int)sizeof(struct ip6_hdr) ) - return -1; - - const struct ip6_hdr* ip6 = (const struct ip6_hdr*) pkt; - inner = new IP_Hdr(ip6, false, caplen); - if ( ( ip6->ip6_ctlun.ip6_un2_vfc & 0xF0 ) != 0x60 ) - return -2; - } - - else if ( proto == IPPROTO_IPV4 ) - { - if ( caplen < (int)sizeof(struct ip) ) - return -1; - - const struct ip* ip4 = (const struct ip*) pkt; - inner = new IP_Hdr(ip4, false); - if ( ip4->ip_v != 4 ) - return -2; - } - - else - { - reporter->InternalWarning("Bad IP protocol version in ParseIPPacket"); - return -1; - } - - if ( (uint32_t)caplen != inner->TotalLen() ) - return (uint32_t)caplen < inner->TotalLen() ? -1 : 1; - - return 0; - } - bool Manager::CheckHeaderTrunc(int proto, uint32_t len, uint32_t caplen, const Packet* p) { diff --git a/src/session/Manager.h b/src/session/Manager.h index b65b245203..b798c7f9d4 100644 --- a/src/session/Manager.h +++ b/src/session/Manager.h @@ -106,31 +106,6 @@ public: */ void ProcessTransportLayer(double t, const Packet *pkt, size_t len); - /** - * Returns a wrapper IP_Hdr object if \a pkt appears to be a valid IPv4 - * or IPv6 header based on whether it's long enough to contain such a header, - * if version given in the header matches the proto argument, and also checks - * that the payload length field of that header matches the actual - * length of \a pkt given by \a caplen. - * - * @param caplen The length of \a pkt in bytes. - * @param pkt The inner IP packet data. - * @param proto Either IPPROTO_IPV6 or IPPROTO_IPV4 to indicate which IP - * protocol \a pkt corresponds to. - * @param inner The inner IP packet wrapper pointer to be allocated/assigned - * if \a pkt looks like a valid IP packet or at least long enough - * to hold an IP header. - * @return 0 If the inner IP packet appeared valid, else -1 if \a caplen - * is greater than the supposed IP packet's payload length field, -2 - * if the version of the inner header does not match proto or - * 1 if \a caplen is less than the supposed packet's payload length. - * In the -1 case, \a inner may still be non-null if \a caplen was - * long enough to be an IP header, and \a inner is always non-null - * for other return values. - */ - int ParseIPPacket(int caplen, const u_char* const pkt, int proto, - IP_Hdr*& inner); - unsigned int SessionMemoryUsage(); unsigned int SessionMemoryUsageVals(); From c1f0d312b5da13bc19b73a426f1d45e04f372ced Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Tue, 13 Apr 2021 15:36:31 -0700 Subject: [PATCH 03/10] Add base class for IP-based packet analyzers --- scripts/base/packet-protocols/ip/main.zeek | 8 +- src/analyzer/Manager.cc | 52 +++ src/analyzer/Manager.h | 19 +- src/iosource/Packet.h | 7 + src/packet_analysis/Analyzer.cc | 20 +- src/packet_analysis/Analyzer.h | 10 +- src/packet_analysis/Manager.cc | 4 +- src/packet_analysis/protocol/icmp/ICMP.cc | 99 ++++- src/packet_analysis/protocol/icmp/ICMP.h | 16 +- src/packet_analysis/protocol/icmp/Plugin.cc | 2 +- .../protocol/ip/CMakeLists.txt | 2 +- .../protocol/ip/IPBasedAnalyzer.cc | 209 +++++++++++ .../protocol/ip/IPBasedAnalyzer.h | 182 +++++++++ src/packet_analysis/protocol/tcp/Plugin.cc | 2 +- src/packet_analysis/protocol/tcp/TCP.cc | 69 +++- src/packet_analysis/protocol/tcp/TCP.h | 22 +- src/packet_analysis/protocol/udp/Plugin.cc | 2 +- src/packet_analysis/protocol/udp/UDP.cc | 32 +- src/packet_analysis/protocol/udp/UDP.h | 22 +- src/session/Manager.cc | 350 +----------------- src/session/Manager.h | 45 +-- testing/btest/Baseline/core.truncation/output | 4 +- testing/btest/Baseline/plugins.hooks/output | 24 +- 23 files changed, 781 insertions(+), 421 deletions(-) create mode 100644 src/packet_analysis/protocol/ip/IPBasedAnalyzer.cc create mode 100644 src/packet_analysis/protocol/ip/IPBasedAnalyzer.h diff --git a/scripts/base/packet-protocols/ip/main.zeek b/scripts/base/packet-protocols/ip/main.zeek index 556b460a1c..0e1c506bcb 100644 --- a/scripts/base/packet-protocols/ip/main.zeek +++ b/scripts/base/packet-protocols/ip/main.zeek @@ -15,8 +15,8 @@ event zeek_init() &priority=20 PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, IPPROTO_IPV6, PacketAnalyzer::ANALYZER_IPTUNNEL); PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, IPPROTO_GRE, PacketAnalyzer::ANALYZER_GRE); - PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, IPPROTO_TCP, PacketAnalyzer::ANALYZER_TCP_PKT); - PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, IPPROTO_UDP, PacketAnalyzer::ANALYZER_UDP_PKT); - PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, IPPROTO_ICMP, PacketAnalyzer::ANALYZER_ICMP_PKT); - PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, IPPROTO_ICMP6, PacketAnalyzer::ANALYZER_ICMP_PKT); + PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, IPPROTO_TCP, PacketAnalyzer::ANALYZER_TCP); + PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, IPPROTO_UDP, PacketAnalyzer::ANALYZER_UDP); + PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, IPPROTO_ICMP, PacketAnalyzer::ANALYZER_ICMP); + PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, IPPROTO_ICMP6, PacketAnalyzer::ANALYZER_ICMP); } diff --git a/src/analyzer/Manager.cc b/src/analyzer/Manager.cc index 7efb0ac3fe..3d44017d97 100644 --- a/src/analyzer/Manager.cc +++ b/src/analyzer/Manager.cc @@ -13,6 +13,7 @@ #include "zeek/analyzer/protocol/stepping-stone/SteppingStone.h" #include "zeek/analyzer/protocol/tcp/TCP.h" #include "zeek/analyzer/protocol/udp/UDP.h" +#include "zeek/packet_analysis/protocol/ip/IPBasedAnalyzer.h" #include "zeek/plugin/Manager.h" @@ -498,6 +499,57 @@ bool Manager::BuildInitialAnalyzerTree(Connection* conn) return true; } +bool Manager::BuildSessionAnalyzerTree(Connection* conn, packet_analysis::IP::IPBasedAnalyzer* analyzer) + { + packet_analysis::IP::IPBasedTransportAnalyzer* root = nullptr; + analyzer::pia::PIA* pia = nullptr; + bool check_port = false; + + analyzer->CreateTransportAnalyzer(conn, root, pia, check_port); + + bool scheduled = ApplyScheduledAnalyzers(conn, false, root); + + // Hmm... Do we want *just* the expected analyzer, or all + // other potential analyzers as well? For now we only take + // the scheduled ones. + if ( ! scheduled ) + { // Let's see if it's a port we know. + if ( check_port && ! zeek::detail::dpd_ignore_ports ) + { + int resp_port = ntohs(conn->RespPort()); + tag_set* ports = LookupPort(conn->ConnTransport(), resp_port, false); + + if ( ports ) + { + for ( tag_set::const_iterator j = ports->begin(); j != ports->end(); ++j ) + { + Analyzer* analyzer = analyzer_mgr->InstantiateAnalyzer(*j, conn); + + if ( ! analyzer ) + continue; + + root->AddChildAnalyzer(analyzer, false); + DBG_ANALYZER_ARGS(conn, "activated %s analyzer due to port %d", + analyzer_mgr->GetComponentName(*j).c_str(), resp_port); + } + } + } + } + + root->AddExtraAnalyzers(conn); + + if ( pia ) + root->AddChildAnalyzer(pia->AsAnalyzer()); + + conn->SetRootAnalyzer(root, pia); + root->Init(); + root->InitChildren(); + + PLUGIN_HOOK_VOID(HOOK_SETUP_ANALYZER_TREE, HookSetupAnalyzerTree(conn)); + + return true; + } + void Manager::ExpireScheduledAnalyzers() { if ( ! run_state::network_time ) diff --git a/src/analyzer/Manager.h b/src/analyzer/Manager.h index 7137a57390..0899110663 100644 --- a/src/analyzer/Manager.h +++ b/src/analyzer/Manager.h @@ -35,6 +35,9 @@ #include "zeek/analyzer/analyzer.bif.h" namespace zeek { + +namespace packet_analysis::IP { class IPBasedAnalyzer; } + namespace analyzer { /** @@ -244,11 +247,23 @@ public: * * @param conn The connection to add the initial set of analyzers to. * - * @return False if the tree cannot be build; that's usually an - * internally error. + * @return False if the tree cannot be built; that's usually an + * internal error. */ bool BuildInitialAnalyzerTree(Connection* conn); + /** + * Builds the analyzer tree used by transport-layer analyzers in the + * packet analysis framework. + * + * @param conn The connection to add the initial set of analyzers to. + * @param analyzer The packet analyzer requesting the tree. + * @return False if the tree cannot be built; that's usually an + * internal error. + */ + bool BuildSessionAnalyzerTree(Connection* conn, + packet_analysis::IP::IPBasedAnalyzer* analyzer); + /** * Schedules a particular analyzer for an upcoming connection. Once * the connection is seen, BuildInitAnalyzerTree() will add the diff --git a/src/iosource/Packet.h b/src/iosource/Packet.h index 20469b3105..dfd0ec356c 100644 --- a/src/iosource/Packet.h +++ b/src/iosource/Packet.h @@ -189,6 +189,13 @@ public: */ mutable bool dump_packet; + /** + * Indicates the amount of data to be dumped. If only a header is needed, + * set this to the size of the header. Setting it to zero will dump the + * entire packet. + */ + mutable int dump_size = 0; + // These are fields passed between various packet analyzers. They're best // stored with the packet so they stay available as the packet is passed // around. diff --git a/src/packet_analysis/Analyzer.cc b/src/packet_analysis/Analyzer.cc index 45b90a52fc..79b8f94602 100644 --- a/src/packet_analysis/Analyzer.cc +++ b/src/packet_analysis/Analyzer.cc @@ -10,7 +10,8 @@ namespace zeek::packet_analysis { -Analyzer::Analyzer(std::string name) +Analyzer::Analyzer(std::string name, bool report_unknown_protocols) : + report_unknown_protocols(report_unknown_protocols) { Tag t = packet_mgr->GetComponentTag(name); @@ -80,10 +81,15 @@ bool Analyzer::ForwardPacket(size_t len, const uint8_t* data, Packet* packet, if ( inner_analyzer == nullptr ) { - DBG_LOG(DBG_PACKET_ANALYSIS, "Analysis in %s failed, could not find analyzer for identifier %#x.", - GetAnalyzerName(), identifier); - packet_mgr->ReportUnknownProtocol(GetAnalyzerName(), identifier, data, len); - return false; + if ( report_unknown_protocols ) + { + DBG_LOG(DBG_PACKET_ANALYSIS, "Analysis in %s failed, could not find analyzer for identifier %#x.", + GetAnalyzerName(), identifier); + packet_mgr->ReportUnknownProtocol(GetAnalyzerName(), identifier, data, len); + return false; + } + else + return true; } DBG_LOG(DBG_PACKET_ANALYSIS, "Analysis in %s succeeded, next layer identifier is %#x.", @@ -99,7 +105,9 @@ bool Analyzer::ForwardPacket(size_t len, const uint8_t* data, Packet* packet) co DBG_LOG(DBG_PACKET_ANALYSIS, "Analysis in %s stopped, no default analyzer available.", GetAnalyzerName()); - Weird("no_suitable_analyzer_found", packet); + if ( report_unknown_protocols ) + Weird("no_suitable_analyzer_found", packet); + return true; } diff --git a/src/packet_analysis/Analyzer.h b/src/packet_analysis/Analyzer.h index 90a3508aca..eeaf36edf7 100644 --- a/src/packet_analysis/Analyzer.h +++ b/src/packet_analysis/Analyzer.h @@ -17,8 +17,11 @@ public: * * @param name The name for the type of analyzer. The name must match * the one the corresponding Component registers. + * @param report_unknown_protocols Flag for whether to report unknown + * protocols during packet forwarding. This should generally always be + * set to true. */ - explicit Analyzer(std::string name); + explicit Analyzer(std::string name, bool report_unknown_protocols=true); /** * Constructor. @@ -165,6 +168,11 @@ private: Dispatcher dispatcher; AnalyzerPtr default_analyzer = nullptr; + /** + * Flag for whether to report unknown protocols in ForwardPacket. + */ + bool report_unknown_protocols = true; + void Init(const Tag& tag); }; diff --git a/src/packet_analysis/Manager.cc b/src/packet_analysis/Manager.cc index 0bf4252ec8..c307823c76 100644 --- a/src/packet_analysis/Manager.cc +++ b/src/packet_analysis/Manager.cc @@ -101,7 +101,7 @@ void Manager::ProcessPacket(Packet* packet) bool dumped_packet = false; if ( packet->dump_packet || zeek::detail::record_all_packets ) { - DumpPacket(packet); + DumpPacket(packet, packet->dump_size); dumped_packet = true; } @@ -114,7 +114,7 @@ void Manager::ProcessPacket(Packet* packet) // Check whether packet should be recorded based on session analysis if ( packet->dump_packet && ! dumped_packet ) - DumpPacket(packet); + DumpPacket(packet, packet->dump_size); } bool Manager::ProcessInnerPacket(Packet* packet) diff --git a/src/packet_analysis/protocol/icmp/ICMP.cc b/src/packet_analysis/protocol/icmp/ICMP.cc index 928c31db5c..2eaf18b621 100644 --- a/src/packet_analysis/protocol/icmp/ICMP.cc +++ b/src/packet_analysis/protocol/icmp/ICMP.cc @@ -1,13 +1,16 @@ // See the file "COPYING" in the main distribution directory for copyright. #include "zeek/packet_analysis/protocol/icmp/ICMP.h" + +#include + #include "zeek/RunState.h" #include "zeek/session/Manager.h" using namespace zeek::packet_analysis::ICMP; +using namespace zeek::packet_analysis::IP; -ICMPAnalyzer::ICMPAnalyzer() - : zeek::packet_analysis::Analyzer("ICMP_PKT") +ICMPAnalyzer::ICMPAnalyzer() : IPBasedAnalyzer("ICMP", TRANSPORT_ICMP, ICMP_PORT_MASK, false) { } @@ -17,6 +20,96 @@ ICMPAnalyzer::~ICMPAnalyzer() bool ICMPAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) { - session_mgr->ProcessTransportLayer(run_state::processing_start_time, packet, len); + if ( ! CheckHeaderTrunc(ICMP_MINLEN, len, packet) ) + return false; + + ConnTuple id; + id.src_addr = packet->ip_hdr->SrcAddr(); + id.dst_addr = packet->ip_hdr->DstAddr(); + id.proto = TRANSPORT_ICMP; + + const struct icmp* icmpp = (const struct icmp *) data; + id.src_port = htons(icmpp->icmp_type); + + if ( packet->proto == IPPROTO_ICMP ) + id.dst_port = htons(ICMP4_counterpart(icmpp->icmp_type, icmpp->icmp_code, id.is_one_way)); + else if ( packet->proto == IPPROTO_ICMPV6 ) + id.dst_port = htons(ICMP6_counterpart(icmpp->icmp_type, icmpp->icmp_code, id.is_one_way)); + else + reporter->InternalError("Reached ICMP packet analyzer with unknown packet protocol %x", + packet->proto); + + ProcessConnection(id, packet, len); + return true; } + +void ICMPAnalyzer::ContinueProcessing(Connection* c, double t, bool is_orig, int remaining, Packet* pkt) + { + } + +void ICMPAnalyzer::CreateTransportAnalyzer(Connection* conn, IPBasedTransportAnalyzer*& root, + analyzer::pia::PIA*& pia, bool& check_port) + { + } + + +int ICMPAnalyzer::ICMP4_counterpart(int icmp_type, int icmp_code, bool& is_one_way) + { + is_one_way = false; + + // Return the counterpart type if one exists. This allows us + // to track corresponding ICMP requests/replies. + // Note that for the two-way ICMP messages, icmp_code is + // always 0 (RFC 792). + switch ( icmp_type ) { + case ICMP_ECHO: return ICMP_ECHOREPLY; + case ICMP_ECHOREPLY: return ICMP_ECHO; + + case ICMP_TSTAMP: return ICMP_TSTAMPREPLY; + case ICMP_TSTAMPREPLY: return ICMP_TSTAMP; + + case ICMP_IREQ: return ICMP_IREQREPLY; + case ICMP_IREQREPLY: return ICMP_IREQ; + + case ICMP_ROUTERSOLICIT: return ICMP_ROUTERADVERT; + case ICMP_ROUTERADVERT: return ICMP_ROUTERSOLICIT; + + case ICMP_MASKREQ: return ICMP_MASKREPLY; + case ICMP_MASKREPLY: return ICMP_MASKREQ; + + default: is_one_way = true; return icmp_code; + } + } + +int ICMPAnalyzer::ICMP6_counterpart(int icmp_type, int icmp_code, bool& is_one_way) + { + is_one_way = false; + + switch ( icmp_type ) { + case ICMP6_ECHO_REQUEST: return ICMP6_ECHO_REPLY; + case ICMP6_ECHO_REPLY: return ICMP6_ECHO_REQUEST; + + case ND_ROUTER_SOLICIT: return ND_ROUTER_ADVERT; + case ND_ROUTER_ADVERT: return ND_ROUTER_SOLICIT; + + case ND_NEIGHBOR_SOLICIT: return ND_NEIGHBOR_ADVERT; + case ND_NEIGHBOR_ADVERT: return ND_NEIGHBOR_SOLICIT; + + case MLD_LISTENER_QUERY: return MLD_LISTENER_REPORT; + case MLD_LISTENER_REPORT: return MLD_LISTENER_QUERY; + + // ICMP node information query and response respectively (not defined in + // icmp6.h) + case 139: return 140; + case 140: return 139; + + // Home Agent Address Discovery Request Message and reply + case 144: return 145; + case 145: return 144; + + // TODO: Add further counterparts. + + default: is_one_way = true; return icmp_code; + } + } diff --git a/src/packet_analysis/protocol/icmp/ICMP.h b/src/packet_analysis/protocol/icmp/ICMP.h index 439a2740fe..c0acc8d6f0 100644 --- a/src/packet_analysis/protocol/icmp/ICMP.h +++ b/src/packet_analysis/protocol/icmp/ICMP.h @@ -4,10 +4,11 @@ #include "zeek/packet_analysis/Analyzer.h" #include "zeek/packet_analysis/Component.h" +#include "zeek/packet_analysis/protocol/ip/IPBasedAnalyzer.h" namespace zeek::packet_analysis::ICMP { -class ICMPAnalyzer : public Analyzer { +class ICMPAnalyzer final : public IP::IPBasedAnalyzer { public: ICMPAnalyzer(); ~ICMPAnalyzer() override; @@ -19,8 +20,21 @@ public: return std::make_shared(); } + void CreateTransportAnalyzer(Connection* conn, IP::IPBasedTransportAnalyzer*& root, + analyzer::pia::PIA*& pia, bool& check_port) override; + +protected: + + void ContinueProcessing(Connection* c, double t, bool is_orig, int remaining, + Packet* pkt) override; + private: + // Returns the counterpart type to the given type (e.g., the counterpart + // to ICMP_ECHOREPLY is ICMP_ECHO). + int ICMP4_counterpart(int icmp_type, int icmp_code, bool& is_one_way); + int ICMP6_counterpart(int icmp_type, int icmp_code, bool& is_one_way); + }; } diff --git a/src/packet_analysis/protocol/icmp/Plugin.cc b/src/packet_analysis/protocol/icmp/Plugin.cc index 0e339ebba1..b16205e78a 100644 --- a/src/packet_analysis/protocol/icmp/Plugin.cc +++ b/src/packet_analysis/protocol/icmp/Plugin.cc @@ -10,7 +10,7 @@ class Plugin : public zeek::plugin::Plugin { public: zeek::plugin::Configuration Configure() { - AddComponent(new zeek::packet_analysis::Component("ICMP_PKT", + AddComponent(new zeek::packet_analysis::Component("ICMP", zeek::packet_analysis::ICMP::ICMPAnalyzer::Instantiate)); zeek::plugin::Configuration config; diff --git a/src/packet_analysis/protocol/ip/CMakeLists.txt b/src/packet_analysis/protocol/ip/CMakeLists.txt index 3be79005d9..89971b9334 100644 --- a/src/packet_analysis/protocol/ip/CMakeLists.txt +++ b/src/packet_analysis/protocol/ip/CMakeLists.txt @@ -4,5 +4,5 @@ include(ZeekPlugin) include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) zeek_plugin_begin(PacketAnalyzer IP) -zeek_plugin_cc(IP.cc Plugin.cc) +zeek_plugin_cc(IP.cc IPBasedAnalyzer.cc Plugin.cc) zeek_plugin_end() diff --git a/src/packet_analysis/protocol/ip/IPBasedAnalyzer.cc b/src/packet_analysis/protocol/ip/IPBasedAnalyzer.cc new file mode 100644 index 0000000000..877c9b17e0 --- /dev/null +++ b/src/packet_analysis/protocol/ip/IPBasedAnalyzer.cc @@ -0,0 +1,209 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#include "zeek/packet_analysis/protocol/ip/IPBasedAnalyzer.h" + +#include "zeek/RunState.h" +#include "zeek/Conn.h" +#include "zeek/Val.h" +#include "zeek/session/Manager.h" +#include "zeek/analyzer/Manager.h" + +using namespace zeek; +using namespace zeek::packet_analysis::IP; + +IPBasedAnalyzer::IPBasedAnalyzer(const char* name, TransportProto proto, uint32_t mask, + bool report_unknown_protocols) + : zeek::packet_analysis::Analyzer(name, report_unknown_protocols), + transport(proto), server_port_mask(mask) + { + } + +IPBasedAnalyzer::~IPBasedAnalyzer() + { + } + +void IPBasedAnalyzer::ProcessConnection(const ConnTuple& conn_id, Packet* pkt, size_t remaining) + { + const std::unique_ptr& ip_hdr = pkt->ip_hdr; + detail::ConnKey key(conn_id); + + Connection* conn = session_mgr->FindConnection(key); + + if ( ! conn ) + { + conn = NewConn(&conn_id, key, pkt); + if ( conn ) + session_mgr->Insert(conn, false); + } + else + { + if ( conn->IsReuse(run_state::processing_start_time, ip_hdr->Payload()) ) + { + conn->Event(connection_reused, nullptr); + + session_mgr->Remove(conn); + conn = NewConn(&conn_id, key, pkt); + if ( conn ) + session_mgr->Insert(conn, false); + } + else + { + conn->CheckEncapsulation(pkt->encap); + } + } + + if ( ! conn ) + return; + + bool is_orig = (conn_id.src_addr == conn->OrigAddr()) && + (conn_id.src_port == conn->OrigPort()); + + conn->CheckFlowLabel(is_orig, ip_hdr->FlowLabel()); + + zeek::ValPtr pkt_hdr_val; + + if ( ipv6_ext_headers && ip_hdr->NumHeaders() > 1 ) + { + pkt_hdr_val = ip_hdr->ToPktHdrVal(); + conn->EnqueueEvent(ipv6_ext_headers, nullptr, conn->GetVal(), + pkt_hdr_val); + } + + if ( new_packet ) + conn->EnqueueEvent(new_packet, nullptr, conn->GetVal(), + pkt_hdr_val ? std::move(pkt_hdr_val) : ip_hdr->ToPktHdrVal()); + + if ( new_plugin ) + { + conn->SetRecordPackets(true); + conn->SetRecordContents(true); + + const u_char* data = pkt->ip_hdr->Payload(); + + run_state::current_timestamp = run_state::processing_start_time; + run_state::current_pkt = pkt; + + // TODO: Does this actually mean anything? + if ( conn->Skipping() ) + return; + + ContinueProcessing(conn, run_state::processing_start_time, is_orig, remaining, pkt); + + run_state::current_timestamp = 0; + run_state::current_pkt = nullptr; + + // If the packet is reassembled, disable packet dumping because the + // pointer math to dump the data wouldn't work. + if ( pkt->ip_hdr->reassembled ) + pkt->dump_packet = false; + else if ( conn->RecordPackets() ) + { + pkt->dump_packet = true; + + // If we don't want the content, set the dump size to include just + // the header. + if ( ! conn->RecordContents() ) + pkt->dump_size = data - pkt->data; + } + } + else + { + int record_packet = 1; // whether to record the packet at all + int record_content = 1; // whether to record its data + + const u_char* data = pkt->ip_hdr->Payload(); + + conn->NextPacket(run_state::processing_start_time, is_orig, ip_hdr.get(), ip_hdr->PayloadLen(), + remaining, data, record_packet, record_content, pkt); + + // If the packet is reassembled, disable packet dumping because the + // pointer math to dump the data wouldn't work. + if ( ip_hdr->reassembled ) + pkt->dump_packet = false; + else if ( record_packet ) + { + pkt->dump_packet = true; + + // If we don't want the content, set the dump size to include just + // the header. + if ( ! record_content ) + pkt->dump_size = data - pkt->data; + } + } + } + +bool IPBasedAnalyzer::CheckHeaderTrunc(size_t min_hdr_len, size_t remaining, Packet* packet) + { + if ( packet->ip_hdr->PayloadLen() < min_hdr_len ) + { + Weird("truncated_header", packet); + return false; + } + else if ( remaining < min_hdr_len ) + { + Weird("internally_truncated_header", packet); + return false; + } + + return true; + } + +bool IPBasedAnalyzer::IsLikelyServerPort(uint32_t port) const + { + // We keep a cached in-core version of the table to speed up the lookup. + static std::set port_cache; + static bool have_cache = false; + + if ( ! have_cache ) + { + auto likely_server_ports = id::find_val("likely_server_ports"); + auto lv = likely_server_ports->ToPureListVal(); + for ( int i = 0; i < lv->Length(); i++ ) + port_cache.insert(lv->Idx(i)->InternalUnsigned()); + have_cache = true; + } + + // We exploit our knowledge of PortVal's internal storage mechanism here. + port |= server_port_mask; + + return port_cache.find(port) != port_cache.end(); + } + +zeek::Connection* IPBasedAnalyzer::NewConn(const ConnTuple* id, const detail::ConnKey& key, + const Packet* pkt) + { + int src_h = ntohs(id->src_port); + int dst_h = ntohs(id->dst_port); + bool flip = false; + + if ( ! WantConnection(src_h, dst_h, pkt->ip_hdr->Payload(), flip) ) + return nullptr; + + Connection* conn = new Connection(key, run_state::processing_start_time, + id, pkt->ip_hdr->FlowLabel(), pkt); + conn->SetTransport(transport); + + if ( flip ) + conn->FlipRoles(); + + if ( ! new_plugin ) + { + if ( ! analyzer_mgr->BuildInitialAnalyzerTree(conn) ) + { + conn->Done(); + Unref(conn); + return nullptr; + } + } + else if ( ! analyzer_mgr->BuildSessionAnalyzerTree(conn, this) ) + { + conn->Done(); + Unref(conn); + return nullptr; + } + + if ( new_connection ) + conn->Event(new_connection, nullptr); + + return conn; + } diff --git a/src/packet_analysis/protocol/ip/IPBasedAnalyzer.h b/src/packet_analysis/protocol/ip/IPBasedAnalyzer.h new file mode 100644 index 0000000000..129a098720 --- /dev/null +++ b/src/packet_analysis/protocol/ip/IPBasedAnalyzer.h @@ -0,0 +1,182 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#pragma once + +#include "zeek/packet_analysis/Analyzer.h" +#include "zeek/packet_analysis/Component.h" +#include "zeek/analyzer/Analyzer.h" +#include "zeek/analyzer/Manager.h" + +namespace zeek::analyzer::pia { class PIA; } + +namespace zeek::packet_analysis::IP { + +class IPBasedTransportAnalyzer; + +/** + * A base class for any packet analyzer based on IP. This is used by default by + * the TCP, UDP, and ICMP analyzers to reduce a large amount of duplicated code + * that those plugins have in common. + */ +class IPBasedAnalyzer : public Analyzer { +public: + ~IPBasedAnalyzer() override; + + /** + * Returns true if the analyzer determines that in fact a new + * connection has started without the connection statement having + * terminated the previous one, i.e., the new data is arriving at + * what's the analyzer for the previous instance. This is used only + * for TCP. + */ + virtual bool IsReuse(double t, const u_char* pkt) { return false; } + + /** + * TODO: comment + */ + virtual void CreateTransportAnalyzer(Connection* conn, IPBasedTransportAnalyzer*& root, + analyzer::pia::PIA*& pia, bool& check_port) = 0; + +protected: + + /** + * Construct a new IP-based analyzer. + * + * @param name The name for the type of analyzer. The name must match + * the one the corresponding Component registers. + * @param proto The transport protocol implemented by this analyzer. + * @param mask The mask used to determine if a port is a server port + * for this protocol. This is used by IsLikelyServerPort(). + * @param report_unknown_protocols Flag for whether to report unknown + * protocols during packet forwarding. This is typically false for IP + * protocols since packets may go into the session analysis framework + * as well. + */ + IPBasedAnalyzer(const char* name, TransportProto proto, uint32_t mask, + bool report_unknown_protocols); + + /** + * Entry point for child classes to call to do the actual heavy lifting for + * processing a packet and extracting a connection out of it. + * + * @param conn_id The connection ID generated by the child class. + * @param pkt The packet being processed. + * @param remaining The number of bytes remaining to be processed in the packet. + */ + void ProcessConnection(const ConnTuple& conn_id, Packet* pkt, size_t remaining); + + /** + * Verifies that there is enough data in the packet to process the header + * length requested. + * + * @param min_hdr_len The minimum data in bytes that needs to exist. + * @param remaining The remaining number of bytes in the packet reported by + * previous analyzer. + * @param packet The packet being processed. This will be used to pull out the + * number of bytes the IP header says we have remaining. + */ + bool CheckHeaderTrunc(size_t min_hdr_len, size_t remaining, Packet* packet); + + /** + * Upon seeing the first packet of a connection, checks whether we want + * to analyze it (e.g. we may not want to look at partial connections) + * and, if yes, whether we should flip the roles of originator and + * responder based on known ports and such. + * + * @param src_port The source port of the connection. + * @param dst_port The destination port of the connection. + * @param data The payload data for the packet being processed. + * @param flip_roles Return value if the roles should be flipped. + * @return True if the connection is wanted. False otherwise. + */ + virtual bool WantConnection(uint16_t src_port, uint16_t dst_port, + const u_char* data, bool& flip_roles) const + { + flip_roles = false; + return true; + } + + /** + * Returns true if the port corresponds to an application for which there + * is a Zeek analyzer (even if it might not be used by the present policy + * script) or if it's generally a likely server port. + * + * @param port The port number to check, in host order. + */ + bool IsLikelyServerPort(uint32_t port) const; + + /** + * Continues process of packet after the connection has been inserted into the + * session manager. This should be implemented by all child classes. + * + * @param conn The connection currently being processed. + * @param t The timestamp for the current packet. + * @param is_orig Flag denoting whether this packet is from the originator of + * the connection. + * @param remaining The remaining about of data in the packet. + * @param pkt The packet being processed. + */ + virtual void ContinueProcessing(Connection* conn, double t, bool is_orig, int remaining, + Packet* pkt) {} + + // TODO: temporary, until all of the plugins are implemented + bool new_plugin = false; + +private: + + /** + * Creates a new Connection object from data gleaned from the current packet. + * + * @param id A connection ID generated from the packet data. This should have been + * passed in from a child analyzer. + * @param key A connection ID key generated from the ID. + * @param pkt The packet associated with the new connection. + */ + zeek::Connection* NewConn(const ConnTuple* id, const detail::ConnKey& key, + const Packet* pkt); + + TransportProto transport; + uint32_t server_port_mask; +}; + +/** + * This class represents the interface between the packet analysis framework and + * the session analysis framework. One of these should be implemented for each + * packet analyzer that intends to forward into the session analysis. + */ +class IPBasedTransportAnalyzer : public zeek::analyzer::TransportLayerAnalyzer { + +public: + + IPBasedTransportAnalyzer(const char* name, Connection* conn) + : TransportLayerAnalyzer(name, conn) { } + + /** + * Sets the parent packet analyzer for this transport analyzer. This can't be passed to + * the constructor due to the way that TransportLayerAnalyzer gets instantiated. + * + * @param p The parent packet analyzer to store + */ + void SetParent(IPBasedAnalyzer* p) { parent = p; } + + /** + * Returns true if the analyzer determines that in fact a new connection has started + * without the connection statement having terminated the previous one, i.e., the new + * data is arriving at what's the analyzer for the previous instance. This is used only + * for TCP. + */ + bool IsReuse(double t, const u_char* pkt) override { return parent->IsReuse(t, pkt); } + + /** + * Pure virtual method to allow extra session analzyers to be added to this analyzer's + * tree of children. This is used by analyzer::Manager when creating the session analyzer + * tree. + */ + virtual void AddExtraAnalyzers(Connection* conn) = 0; + +protected: + + IPBasedAnalyzer* parent; +}; + +} diff --git a/src/packet_analysis/protocol/tcp/Plugin.cc b/src/packet_analysis/protocol/tcp/Plugin.cc index cc791eedfa..45b41c3884 100644 --- a/src/packet_analysis/protocol/tcp/Plugin.cc +++ b/src/packet_analysis/protocol/tcp/Plugin.cc @@ -10,7 +10,7 @@ class Plugin : public zeek::plugin::Plugin { public: zeek::plugin::Configuration Configure() { - AddComponent(new zeek::packet_analysis::Component("TCP_PKT", + AddComponent(new zeek::packet_analysis::Component("TCP", zeek::packet_analysis::TCP::TCPAnalyzer::Instantiate)); zeek::plugin::Configuration config; diff --git a/src/packet_analysis/protocol/tcp/TCP.cc b/src/packet_analysis/protocol/tcp/TCP.cc index 7fed612e07..0abf645357 100644 --- a/src/packet_analysis/protocol/tcp/TCP.cc +++ b/src/packet_analysis/protocol/tcp/TCP.cc @@ -2,12 +2,11 @@ #include "zeek/packet_analysis/protocol/tcp/TCP.h" #include "zeek/RunState.h" -#include "zeek/session/Manager.h" using namespace zeek::packet_analysis::TCP; +using namespace zeek::packet_analysis::IP; -TCPAnalyzer::TCPAnalyzer() - : zeek::packet_analysis::Analyzer("TCP_PKT") +TCPAnalyzer::TCPAnalyzer() : IPBasedAnalyzer("TCP", TRANSPORT_TCP, TCP_PORT_MASK, false) { } @@ -17,6 +16,68 @@ TCPAnalyzer::~TCPAnalyzer() bool TCPAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) { - session_mgr->ProcessTransportLayer(run_state::processing_start_time, packet, len); + uint32_t min_hdr_len = sizeof(struct tcphdr); + if ( ! CheckHeaderTrunc(min_hdr_len, len, packet) ) + return false; + + ConnTuple id; + id.src_addr = packet->ip_hdr->SrcAddr(); + id.dst_addr = packet->ip_hdr->DstAddr(); + + data = packet->ip_hdr->Payload(); + + const struct tcphdr* tp = (const struct tcphdr *) data; + id.src_port = tp->th_sport; + id.dst_port = tp->th_dport; + id.is_one_way = false; + id.proto = TRANSPORT_TCP; + + ProcessConnection(id, packet, len); + return true; } + +bool TCPAnalyzer::WantConnection(uint16_t src_port, uint16_t dst_port, + const u_char* data, bool& flip_roles) const + { + flip_roles = false; + const struct tcphdr* tp = (const struct tcphdr*) data; + uint8_t tcp_flags = tp->th_flags; + + if ( ! (tcp_flags & TH_SYN) || (tcp_flags & TH_ACK) ) + { + // The new connection is starting either without a SYN, + // or with a SYN ack. This means it's a partial connection. + if ( ! zeek::detail::partial_connection_ok ) + return false; + + if ( tcp_flags & TH_SYN && ! zeek::detail::tcp_SYN_ack_ok ) + return false; + + // Try to guess true responder by the port numbers. + // (We might also think that for SYN acks we could + // safely flip the roles, but that doesn't work + // for stealth scans.) + if ( IsLikelyServerPort(src_port) ) + { // connection is a candidate for flipping + if ( IsLikelyServerPort(dst_port) ) + // Hmmm, both source and destination + // are plausible. Heuristic: flip only + // if (1) this isn't a SYN ACK (to avoid + // confusing stealth scans) and + // (2) dest port > src port (to favor + // more plausible servers). + flip_roles = ! (tcp_flags & TH_SYN) && src_port < dst_port; + else + // Source is plausible, destination isn't. + flip_roles = true; + } + } + + return true; + } + +void TCPAnalyzer::CreateTransportAnalyzer(Connection* conn, IPBasedTransportAnalyzer*& root, + analyzer::pia::PIA*& pia, bool& check_port) + { + } diff --git a/src/packet_analysis/protocol/tcp/TCP.h b/src/packet_analysis/protocol/tcp/TCP.h index 51f9208805..d836451945 100644 --- a/src/packet_analysis/protocol/tcp/TCP.h +++ b/src/packet_analysis/protocol/tcp/TCP.h @@ -4,10 +4,11 @@ #include "zeek/packet_analysis/Analyzer.h" #include "zeek/packet_analysis/Component.h" +#include "zeek/packet_analysis/protocol/ip/IPBasedAnalyzer.h" namespace zeek::packet_analysis::TCP { -class TCPAnalyzer : public Analyzer { +class TCPAnalyzer final : public IP::IPBasedAnalyzer { public: TCPAnalyzer(); ~TCPAnalyzer() override; @@ -19,8 +20,25 @@ public: return std::make_shared(); } -private: + void CreateTransportAnalyzer(Connection* conn, IP::IPBasedTransportAnalyzer*& root, + analyzer::pia::PIA*& pia, bool& check_port) override; +protected: + + /** + * Upon seeing the first packet of a connection, checks whether we want + * to analyze it (e.g. we may not want to look at partial connections) + * and, if yes, whether we should flip the roles of originator and + * responder based on known ports and such. + * + * @param src_port The source port of the connection. + * @param dst_port The destination port of the connection. + * @param data The payload data for the packet being processed. + * @param flip_roles Return value if the roles should be flipped. + * @return True if the connection is wanted. False otherwise. + */ + bool WantConnection(uint16_t src_port, uint16_t dst_port, + const u_char* data, bool& flip_roles) const override; }; } diff --git a/src/packet_analysis/protocol/udp/Plugin.cc b/src/packet_analysis/protocol/udp/Plugin.cc index f22ca797f1..4bbe7d737d 100644 --- a/src/packet_analysis/protocol/udp/Plugin.cc +++ b/src/packet_analysis/protocol/udp/Plugin.cc @@ -10,7 +10,7 @@ class Plugin : public zeek::plugin::Plugin { public: zeek::plugin::Configuration Configure() { - AddComponent(new zeek::packet_analysis::Component("UDP_PKT", + AddComponent(new zeek::packet_analysis::Component("UDP", zeek::packet_analysis::UDP::UDPAnalyzer::Instantiate)); zeek::plugin::Configuration config; diff --git a/src/packet_analysis/protocol/udp/UDP.cc b/src/packet_analysis/protocol/udp/UDP.cc index 620e7eb768..f17e1280dd 100644 --- a/src/packet_analysis/protocol/udp/UDP.cc +++ b/src/packet_analysis/protocol/udp/UDP.cc @@ -2,12 +2,11 @@ #include "zeek/packet_analysis/protocol/udp/UDP.h" #include "zeek/RunState.h" -#include "zeek/session/Manager.h" using namespace zeek::packet_analysis::UDP; +using namespace zeek::packet_analysis::IP; -UDPAnalyzer::UDPAnalyzer() - : zeek::packet_analysis::Analyzer("UDP_PKT") +UDPAnalyzer::UDPAnalyzer() : IPBasedAnalyzer("UDP", TRANSPORT_UDP, UDP_PORT_MASK, false) { } @@ -17,6 +16,31 @@ UDPAnalyzer::~UDPAnalyzer() bool UDPAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) { - session_mgr->ProcessTransportLayer(run_state::processing_start_time, packet, len); + uint32_t min_hdr_len = sizeof(struct udphdr); + if ( ! CheckHeaderTrunc(min_hdr_len, len, packet) ) + return false; + + ConnTuple id; + id.src_addr = packet->ip_hdr->SrcAddr(); + id.dst_addr = packet->ip_hdr->DstAddr(); + const struct udphdr* up = (const struct udphdr *) packet->ip_hdr->Payload(); + id.src_port = up->uh_sport; + id.dst_port = up->uh_dport; + id.is_one_way = false; + id.proto = TRANSPORT_UDP; + + ProcessConnection(id, packet, len); + + return true; + } +void UDPAnalyzer::CreateTransportAnalyzer(Connection* conn, IPBasedTransportAnalyzer*& root, + analyzer::pia::PIA*& pia, bool& check_port) + { + } + +bool UDPAnalyzer::WantConnection(uint16_t src_port, uint16_t dst_port, + const u_char* data, bool& flip_roles) const + { + flip_roles = IsLikelyServerPort(src_port) && ! IsLikelyServerPort(dst_port); return true; } diff --git a/src/packet_analysis/protocol/udp/UDP.h b/src/packet_analysis/protocol/udp/UDP.h index 0a941456a2..2730ece1dd 100644 --- a/src/packet_analysis/protocol/udp/UDP.h +++ b/src/packet_analysis/protocol/udp/UDP.h @@ -4,10 +4,11 @@ #include "zeek/packet_analysis/Analyzer.h" #include "zeek/packet_analysis/Component.h" +#include "zeek/packet_analysis/protocol/ip/IPBasedAnalyzer.h" namespace zeek::packet_analysis::UDP { -class UDPAnalyzer : public Analyzer { +class UDPAnalyzer : public IP::IPBasedAnalyzer { public: UDPAnalyzer(); ~UDPAnalyzer() override; @@ -19,8 +20,25 @@ public: return std::make_shared(); } -private: + void CreateTransportAnalyzer(Connection* conn, IP::IPBasedTransportAnalyzer*& root, + analyzer::pia::PIA*& pia, bool& check_port) override; +protected: + + /** + * Upon seeing the first packet of a connection, checks whether we want + * to analyze it (e.g. we may not want to look at partial connections) + * and, if yes, whether we should flip the roles of originator and + * responder based on known ports and such. + * + * @param src_port The source port of the connection. + * @param dst_port The destination port of the connection. + * @param data The payload data for the packet being processed. + * @param flip_roles Return value if the roles should be flipped. + * @return True if the connection is wanted. False otherwise. + */ + bool WantConnection(uint16_t src_port, uint16_t dst_port, + const u_char* data, bool& flip_roles) const override; }; } diff --git a/src/session/Manager.cc b/src/session/Manager.cc index 746fd14ac0..b7e0cddf71 100644 --- a/src/session/Manager.cc +++ b/src/session/Manager.cc @@ -107,197 +107,6 @@ void Manager::Done() { } -void Manager::ProcessTransportLayer(double t, const Packet* pkt, size_t remaining) - { - const std::unique_ptr& ip_hdr = pkt->ip_hdr; - - uint32_t len = ip_hdr->TotalLen(); - uint16_t ip_hdr_len = ip_hdr->HdrLen(); - - if ( len < ip_hdr_len ) - { - session_mgr->Weird("bogus_IP_header_lengths", pkt); - return; - } - - len -= ip_hdr_len; // remove IP header - - int proto = ip_hdr->NextProto(); - - if ( CheckHeaderTrunc(proto, len, remaining, pkt) ) - return; - - const u_char* data = ip_hdr->Payload(); - - ConnTuple id; - id.src_addr = ip_hdr->SrcAddr(); - id.dst_addr = ip_hdr->DstAddr(); - BifEnum::Tunnel::Type tunnel_type = BifEnum::Tunnel::IP; - - switch ( proto ) { - case IPPROTO_TCP: - { - const struct tcphdr* tp = (const struct tcphdr *) data; - id.src_port = tp->th_sport; - id.dst_port = tp->th_dport; - id.is_one_way = false; - id.proto = TRANSPORT_TCP; - break; - } - - case IPPROTO_UDP: - { - const struct udphdr* up = (const struct udphdr *) data; - id.src_port = up->uh_sport; - id.dst_port = up->uh_dport; - id.is_one_way = false; - id.proto = TRANSPORT_UDP; - break; - } - - case IPPROTO_ICMP: - { - const struct icmp* icmpp = (const struct icmp *) data; - - id.src_port = icmpp->icmp_type; - id.dst_port = analyzer::icmp::ICMP4_counterpart(icmpp->icmp_type, - icmpp->icmp_code, - id.is_one_way); - id.src_port = htons(id.src_port); - id.dst_port = htons(id.dst_port); - id.proto = TRANSPORT_ICMP; - break; - } - - case IPPROTO_ICMPV6: - { - const struct icmp* icmpp = (const struct icmp *) data; - - id.src_port = icmpp->icmp_type; - id.dst_port = analyzer::icmp::ICMP6_counterpart(icmpp->icmp_type, - icmpp->icmp_code, - id.is_one_way); - id.src_port = htons(id.src_port); - id.dst_port = htons(id.dst_port); - id.proto = TRANSPORT_ICMP; - break; - } - - default: - Weird("unknown_protocol", pkt, util::fmt("%d", proto)); - return; - } - - zeek::detail::ConnKey conn_key(id); - detail::Key key(&conn_key, sizeof(conn_key), false); - Connection* conn = nullptr; - - // FIXME: The following is getting pretty complex. Need to split up - // into separate functions. - auto it = session_map.find(key); - if (it != session_map.end() ) - conn = static_cast(it->second); - - if ( ! conn ) - { - conn = NewConn(conn_key, t, &id, data, proto, ip_hdr->FlowLabel(), pkt); - if ( conn ) - InsertSession(std::move(key), conn); - } - else - { - // We already know that connection. - if ( conn->IsReuse(t, data) ) - { - conn->Event(connection_reused, nullptr); - - Remove(conn); - conn = NewConn(conn_key, t, &id, data, proto, ip_hdr->FlowLabel(), pkt); - if ( conn ) - InsertSession(std::move(key), conn); - } - else - { - conn->CheckEncapsulation(pkt->encap); - } - } - - if ( ! conn ) - return; - - int record_packet = 1; // whether to record the packet at all - int record_content = 1; // whether to record its data - - bool is_orig = (id.src_addr == conn->OrigAddr()) && - (id.src_port == conn->OrigPort()); - - conn->CheckFlowLabel(is_orig, ip_hdr->FlowLabel()); - - ValPtr pkt_hdr_val; - - if ( ipv6_ext_headers && ip_hdr->NumHeaders() > 1 ) - { - pkt_hdr_val = ip_hdr->ToPktHdrVal(); - conn->EnqueueEvent(ipv6_ext_headers, nullptr, conn->GetVal(), - pkt_hdr_val); - } - - if ( new_packet ) - conn->EnqueueEvent(new_packet, nullptr, conn->GetVal(), pkt_hdr_val ? - std::move(pkt_hdr_val) : ip_hdr->ToPktHdrVal()); - - conn->NextPacket(t, is_orig, ip_hdr.get(), len, remaining, data, - record_packet, record_content, pkt); - - // We skip this block for reassembled packets because the pointer - // math wouldn't work. - if ( ! ip_hdr->reassembled && record_packet ) - { - if ( record_content ) - pkt->dump_packet = true; // save the whole thing - - else - { - int hdr_len = data - pkt->data; - packet_mgr->DumpPacket(pkt, hdr_len); // just save the header - } - } - } - -bool Manager::CheckHeaderTrunc(int proto, uint32_t len, uint32_t caplen, - const Packet* p) - { - uint32_t min_hdr_len = 0; - switch ( proto ) { - case IPPROTO_TCP: - min_hdr_len = sizeof(struct tcphdr); - break; - case IPPROTO_UDP: - min_hdr_len = sizeof(struct udphdr); - break; - case IPPROTO_ICMP: - case IPPROTO_ICMPV6: - default: - // Use for all other packets. - min_hdr_len = ICMP_MINLEN; - break; - } - - if ( len < min_hdr_len ) - { - Weird("truncated_header", p); - return true; - } - - if ( caplen < min_hdr_len ) - { - Weird("internally_truncated_header", p); - return true; - } - - return false; - } - Connection* Manager::FindConnection(Val* v) { const auto& vt = v->GetType(); @@ -353,6 +162,17 @@ Connection* Manager::FindConnection(Val* v) return conn; } +Connection* Manager::FindConnection(const zeek::detail::ConnKey& conn_key) + { + detail::Key key(&conn_key, sizeof(conn_key), false); + + auto it = session_map.find(key); + if ( it != session_map.end() ) + return dynamic_cast(it->second); + + return nullptr; + } + void Manager::Remove(Session* s) { if ( s->IsInSessionTable() ) @@ -381,16 +201,20 @@ void Manager::Remove(Session* s) } } -void Manager::Insert(Session* s) +void Manager::Insert(Session* s, bool remove_existing) { Session* old = nullptr; detail::Key key = s->SessionKey(true); - auto it = session_map.find(key); - if ( it != session_map.end() ) - old = it->second; + if ( remove_existing ) + { + auto it = session_map.find(key); + if ( it != session_map.end() ) + old = it->second; + + session_map.erase(key); + } - session_map.erase(key); InsertSession(std::move(key), s); if ( old && old != s ) @@ -445,140 +269,6 @@ void Manager::GetStats(Stats& s) s.num_packets = packet_mgr->PacketsProcessed(); } -Connection* Manager::NewConn(const zeek::detail::ConnKey& k, double t, const ConnTuple* id, - const u_char* data, int proto, uint32_t flow_label, - const Packet* pkt) - { - // FIXME: This should be cleaned up a bit, it's too protocol-specific. - // But I'm not yet sure what the right abstraction for these things is. - int src_h = ntohs(id->src_port); - int dst_h = ntohs(id->dst_port); - int flags = 0; - - // Hmm... This is not great. - TransportProto tproto = TRANSPORT_UNKNOWN; - switch ( proto ) { - case IPPROTO_ICMP: - tproto = TRANSPORT_ICMP; - break; - case IPPROTO_TCP: - tproto = TRANSPORT_TCP; - break; - case IPPROTO_UDP: - tproto = TRANSPORT_UDP; - break; - case IPPROTO_ICMPV6: - tproto = TRANSPORT_ICMP; - break; - default: - reporter->InternalWarning("unknown transport protocol"); - return nullptr; - }; - - if ( tproto == TRANSPORT_TCP ) - { - const struct tcphdr* tp = (const struct tcphdr*) data; - flags = tp->th_flags; - } - - bool flip = false; - - if ( ! WantConnection(src_h, dst_h, tproto, flags, flip) ) - return nullptr; - - Connection* conn = new Connection(k, t, id, flow_label, pkt); - conn->SetTransport(tproto); - - if ( flip ) - conn->FlipRoles(); - - if ( ! analyzer_mgr->BuildInitialAnalyzerTree(conn) ) - { - conn->Done(); - Unref(conn); - return nullptr; - } - - if ( new_connection ) - conn->Event(new_connection, nullptr); - - return conn; - } - -bool Manager::IsLikelyServerPort(uint32_t port, TransportProto proto) const - { - // We keep a cached in-core version of the table to speed up the lookup. - static std::set port_cache; - static bool have_cache = false; - - if ( ! have_cache ) - { - auto likely_server_ports = id::find_val("likely_server_ports"); - auto lv = likely_server_ports->ToPureListVal(); - for ( int i = 0; i < lv->Length(); i++ ) - port_cache.insert(lv->Idx(i)->InternalUnsigned()); - have_cache = true; - } - - // We exploit our knowledge of PortVal's internal storage mechanism - // here. - if ( proto == TRANSPORT_TCP ) - port |= TCP_PORT_MASK; - else if ( proto == TRANSPORT_UDP ) - port |= UDP_PORT_MASK; - else if ( proto == TRANSPORT_ICMP ) - port |= ICMP_PORT_MASK; - - return port_cache.find(port) != port_cache.end(); - } - -bool Manager::WantConnection(uint16_t src_port, uint16_t dst_port, - TransportProto transport_proto, - uint8_t tcp_flags, bool& flip_roles) - { - flip_roles = false; - - if ( transport_proto == TRANSPORT_TCP ) - { - if ( ! (tcp_flags & TH_SYN) || (tcp_flags & TH_ACK) ) - { - // The new connection is starting either without a SYN, - // or with a SYN ack. This means it's a partial connection. - if ( ! zeek::detail::partial_connection_ok ) - return false; - - if ( tcp_flags & TH_SYN && ! zeek::detail::tcp_SYN_ack_ok ) - return false; - - // Try to guess true responder by the port numbers. - // (We might also think that for SYN acks we could - // safely flip the roles, but that doesn't work - // for stealth scans.) - if ( IsLikelyServerPort(src_port, TRANSPORT_TCP) ) - { // connection is a candidate for flipping - if ( IsLikelyServerPort(dst_port, TRANSPORT_TCP) ) - // Hmmm, both source and destination - // are plausible. Heuristic: flip only - // if (1) this isn't a SYN ACK (to avoid - // confusing stealth scans) and - // (2) dest port > src port (to favor - // more plausible servers). - flip_roles = ! (tcp_flags & TH_SYN) && src_port < dst_port; - else - // Source is plausible, destination isn't. - flip_roles = true; - } - } - } - - else if ( transport_proto == TRANSPORT_UDP ) - flip_roles = - IsLikelyServerPort(src_port, TRANSPORT_UDP) && - ! IsLikelyServerPort(dst_port, TRANSPORT_UDP); - - return true; - } - void Manager::Weird(const char* name, const Packet* pkt, const char* addl, const char* source) { const char* weird_name = name; diff --git a/src/session/Manager.h b/src/session/Manager.h index b798c7f9d4..0b108adfaa 100644 --- a/src/session/Manager.h +++ b/src/session/Manager.h @@ -60,14 +60,13 @@ public: /** * Looks up the connection referred to by a given key. * - * @param key The key for the connection to search for. - * @param proto The transport protocol for the connection. + * @param conn_key The key for the connection to search for. * @return The connection, or nullptr if one doesn't exist. */ - Connection* FindConnection(const zeek::detail::ConnKey& key, TransportProto proto); + Connection* FindConnection(const zeek::detail::ConnKey& conn_key); void Remove(Session* s); - void Insert(Session* c); + void Insert(Session* c, bool remove_existing=true); // Generating connection_pending events for all connections // that are still active. @@ -94,18 +93,6 @@ public: [[deprecated("Remove in v5.1. Use CurrentSessions().")]] unsigned int CurrentConnections() { return CurrentSessions(); } - /** - * Main entry point for processing packets destined for session analyzers. This - * method is called by the packet analysis manager when after it has processed - * an IP-based packet, and shouldn't be called directly from other places. - * - * @param t The timestamp for this packet. - * @param pkt The packet being processed. - * @param len The number of bytes that haven't been processed yet by packet - * analysis. - */ - void ProcessTransportLayer(double t, const Packet *pkt, size_t len); - unsigned int SessionMemoryUsage(); unsigned int SessionMemoryUsageVals(); @@ -123,32 +110,6 @@ private: using SessionMap = std::map; - Connection* NewConn(const zeek::detail::ConnKey& k, double t, const ConnTuple* id, - const u_char* data, int proto, uint32_t flow_label, - const Packet* pkt); - - // Returns true if the port corresonds to an application - // for which there's a Bro analyzer (even if it might not - // be used by the present policy script), or it's more - // generally a likely server port, false otherwise. - // - // Note, port is in host order. - bool IsLikelyServerPort(uint32_t port, TransportProto transport_proto) const; - - // Upon seeing the first packet of a connection, checks whether - // we want to analyze it (e.g., we may not want to look at partial - // connections), and, if yes, whether we should flip the roles of - // originator and responder (based on known ports or such). - // Use tcp_flags=0 for non-TCP. - bool WantConnection(uint16_t src_port, uint16_t dest_port, - TransportProto transport_proto, - uint8_t tcp_flags, bool& flip_roles); - - // For a given protocol, checks whether the header's length as derived - // from lower-level headers or the length actually captured is less - // than that protocol's minimum header size. - bool CheckHeaderTrunc(int proto, uint32_t len, uint32_t caplen, const Packet *pkt); - // Inserts a new connection into the sessions map. If a connection with // the same key already exists in the map, it will be overwritten by // the new one. Connection count stats get updated either way (so most diff --git a/testing/btest/Baseline/core.truncation/output b/testing/btest/Baseline/core.truncation/output index 882692db5e..d9a595ca2e 100644 --- a/testing/btest/Baseline/core.truncation/output +++ b/testing/btest/Baseline/core.truncation/output @@ -37,8 +37,8 @@ XXXXXXXXXX.XXXXXX - 2001:4f8:4:7:2e0:81ff:fe52:ffff 0 2001:4f8:4:7:2e0:81ff:fe52 #open XXXX-XX-XX-XX-XX-XX #fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p name addl notice peer source #types time string addr port addr port string string bool string string -XXXXXXXXXX.XXXXXX - 10.0.0.1 0 192.0.43.10 0 internally_truncated_header - F zeek - -XXXXXXXXXX.XXXXXX - 192.0.43.10 0 10.0.0.1 0 internally_truncated_header - F zeek - +XXXXXXXXXX.XXXXXX - 10.0.0.1 0 192.0.43.10 0 internally_truncated_header - F zeek ICMP +XXXXXXXXXX.XXXXXX - 192.0.43.10 0 10.0.0.1 0 internally_truncated_header - F zeek ICMP #close XXXX-XX-XX-XX-XX-XX #separator \x09 #set_separator , diff --git a/testing/btest/Baseline/plugins.hooks/output b/testing/btest/Baseline/plugins.hooks/output index 61bdd358ac..2074af1a3a 100644 --- a/testing/btest/Baseline/plugins.hooks/output +++ b/testing/btest/Baseline/plugins.hooks/output @@ -572,13 +572,13 @@ 0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IEEE802_11, 32821, PacketAnalyzer::ANALYZER_ARP)) -> 0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IEEE802_11, 34525, PacketAnalyzer::ANALYZER_IP)) -> 0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IEEE802_11_RADIO, 105, PacketAnalyzer::ANALYZER_IEEE802_11)) -> -0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 1, PacketAnalyzer::ANALYZER_ICMP_PKT)) -> -0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 17, PacketAnalyzer::ANALYZER_UDP_PKT)) -> +0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 1, PacketAnalyzer::ANALYZER_ICMP)) -> +0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 17, PacketAnalyzer::ANALYZER_UDP)) -> 0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 4, PacketAnalyzer::ANALYZER_IPTUNNEL)) -> 0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 41, PacketAnalyzer::ANALYZER_IPTUNNEL)) -> 0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 47, PacketAnalyzer::ANALYZER_GRE)) -> -0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 58, PacketAnalyzer::ANALYZER_ICMP_PKT)) -> -0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 6, PacketAnalyzer::ANALYZER_TCP_PKT)) -> +0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 58, PacketAnalyzer::ANALYZER_ICMP)) -> +0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 6, PacketAnalyzer::ANALYZER_TCP)) -> 0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_LINUXSLL, 2048, PacketAnalyzer::ANALYZER_IP)) -> 0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_LINUXSLL, 2054, PacketAnalyzer::ANALYZER_ARP)) -> 0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_LINUXSLL, 32821, PacketAnalyzer::ANALYZER_ARP)) -> @@ -1589,13 +1589,13 @@ 0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IEEE802_11, 32821, PacketAnalyzer::ANALYZER_ARP)) 0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IEEE802_11, 34525, PacketAnalyzer::ANALYZER_IP)) 0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IEEE802_11_RADIO, 105, PacketAnalyzer::ANALYZER_IEEE802_11)) -0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 1, PacketAnalyzer::ANALYZER_ICMP_PKT)) -0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 17, PacketAnalyzer::ANALYZER_UDP_PKT)) +0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 1, PacketAnalyzer::ANALYZER_ICMP)) +0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 17, PacketAnalyzer::ANALYZER_UDP)) 0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 4, PacketAnalyzer::ANALYZER_IPTUNNEL)) 0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 41, PacketAnalyzer::ANALYZER_IPTUNNEL)) 0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 47, PacketAnalyzer::ANALYZER_GRE)) -0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 58, PacketAnalyzer::ANALYZER_ICMP_PKT)) -0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 6, PacketAnalyzer::ANALYZER_TCP_PKT)) +0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 58, PacketAnalyzer::ANALYZER_ICMP)) +0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 6, PacketAnalyzer::ANALYZER_TCP)) 0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_LINUXSLL, 2048, PacketAnalyzer::ANALYZER_IP)) 0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_LINUXSLL, 2054, PacketAnalyzer::ANALYZER_ARP)) 0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_LINUXSLL, 32821, PacketAnalyzer::ANALYZER_ARP)) @@ -2605,13 +2605,13 @@ 0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IEEE802_11, 32821, PacketAnalyzer::ANALYZER_ARP) 0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IEEE802_11, 34525, PacketAnalyzer::ANALYZER_IP) 0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IEEE802_11_RADIO, 105, PacketAnalyzer::ANALYZER_IEEE802_11) -0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, 1, PacketAnalyzer::ANALYZER_ICMP_PKT) -0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, 17, PacketAnalyzer::ANALYZER_UDP_PKT) +0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, 1, PacketAnalyzer::ANALYZER_ICMP) +0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, 17, PacketAnalyzer::ANALYZER_UDP) 0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, 4, PacketAnalyzer::ANALYZER_IPTUNNEL) 0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, 41, PacketAnalyzer::ANALYZER_IPTUNNEL) 0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, 47, PacketAnalyzer::ANALYZER_GRE) -0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, 58, PacketAnalyzer::ANALYZER_ICMP_PKT) -0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, 6, PacketAnalyzer::ANALYZER_TCP_PKT) +0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, 58, PacketAnalyzer::ANALYZER_ICMP) +0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, 6, PacketAnalyzer::ANALYZER_TCP) 0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_LINUXSLL, 2048, PacketAnalyzer::ANALYZER_IP) 0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_LINUXSLL, 2054, PacketAnalyzer::ANALYZER_ARP) 0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_LINUXSLL, 32821, PacketAnalyzer::ANALYZER_ARP) From d8adfaef65a4612bbc7b782334680b4ff30dee4d Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Wed, 14 Apr 2021 09:43:59 -0700 Subject: [PATCH 04/10] Add new ICMP packet analyzer, remove old one --- src/analyzer/Manager.cc | 7 - src/analyzer/protocol/CMakeLists.txt | 1 - src/analyzer/protocol/icmp/CMakeLists.txt | 9 - src/analyzer/protocol/icmp/ICMP.cc | 908 ------------------ src/analyzer/protocol/icmp/ICMP.h | 99 -- src/analyzer/protocol/icmp/Plugin.cc | 22 - .../protocol/icmp/CMakeLists.txt | 3 +- src/packet_analysis/protocol/icmp/ICMP.cc | 831 +++++++++++++++- src/packet_analysis/protocol/icmp/ICMP.h | 99 +- src/packet_analysis/protocol/icmp/Plugin.cc | 4 +- .../protocol/icmp/events.bif | 0 src/session/Manager.cc | 3 - .../canonified_loaded_scripts.log | 2 +- .../canonified_loaded_scripts.log | 2 +- 14 files changed, 933 insertions(+), 1057 deletions(-) delete mode 100644 src/analyzer/protocol/icmp/CMakeLists.txt delete mode 100644 src/analyzer/protocol/icmp/ICMP.cc delete mode 100644 src/analyzer/protocol/icmp/ICMP.h delete mode 100644 src/analyzer/protocol/icmp/Plugin.cc rename src/{analyzer => packet_analysis}/protocol/icmp/events.bif (100%) diff --git a/src/analyzer/Manager.cc b/src/analyzer/Manager.cc index 3d44017d97..a111d36c4f 100644 --- a/src/analyzer/Manager.cc +++ b/src/analyzer/Manager.cc @@ -8,7 +8,6 @@ #include "zeek/RunState.h" #include "zeek/analyzer/protocol/conn-size/ConnSize.h" -#include "zeek/analyzer/protocol/icmp/ICMP.h" #include "zeek/analyzer/protocol/pia/PIA.h" #include "zeek/analyzer/protocol/stepping-stone/SteppingStone.h" #include "zeek/analyzer/protocol/tcp/TCP.h" @@ -383,12 +382,6 @@ bool Manager::BuildInitialAnalyzerTree(Connection* conn) DBG_ANALYZER(conn, "activated UDP analyzer"); break; - case TRANSPORT_ICMP: { - root = new analyzer::icmp::ICMP_Analyzer(conn); - DBG_ANALYZER(conn, "activated ICMP analyzer"); - break; - } - default: reporter->InternalWarning("unknown protocol can't build analyzer tree"); return false; diff --git a/src/analyzer/protocol/CMakeLists.txt b/src/analyzer/protocol/CMakeLists.txt index 49dde00190..1a6e241ece 100644 --- a/src/analyzer/protocol/CMakeLists.txt +++ b/src/analyzer/protocol/CMakeLists.txt @@ -14,7 +14,6 @@ add_subdirectory(gnutella) add_subdirectory(gssapi) add_subdirectory(gtpv1) add_subdirectory(http) -add_subdirectory(icmp) add_subdirectory(ident) add_subdirectory(imap) add_subdirectory(irc) diff --git a/src/analyzer/protocol/icmp/CMakeLists.txt b/src/analyzer/protocol/icmp/CMakeLists.txt deleted file mode 100644 index 875b3597ec..0000000000 --- a/src/analyzer/protocol/icmp/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ - -include(ZeekPlugin) - -include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) - -zeek_plugin_begin(Zeek ICMP) -zeek_plugin_cc(ICMP.cc Plugin.cc) -zeek_plugin_bif(events.bif) -zeek_plugin_end() diff --git a/src/analyzer/protocol/icmp/ICMP.cc b/src/analyzer/protocol/icmp/ICMP.cc deleted file mode 100644 index 4abcca8f62..0000000000 --- a/src/analyzer/protocol/icmp/ICMP.cc +++ /dev/null @@ -1,908 +0,0 @@ -// See the file "COPYING" in the main distribution directory for copyright. - -#include "zeek/zeek-config.h" -#include "zeek/analyzer/protocol/icmp/ICMP.h" - -#include -#include - -#include "zeek/IP.h" -#include "zeek/RunState.h" -#include "zeek/NetVar.h" -#include "zeek/Event.h" -#include "zeek/Conn.h" -#include "zeek/Desc.h" -#include "zeek/Reporter.h" - -#include "zeek/analyzer/protocol/icmp/events.bif.h" - -namespace zeek::analyzer::icmp { - -ICMP_Analyzer::ICMP_Analyzer(Connection* c) - : TransportLayerAnalyzer("ICMP", c), - icmp_conn_val(), type(), code(), request_len(-1), reply_len(-1) - { - c->SetInactivityTimeout(zeek::detail::icmp_inactivity_timeout); - } - -void ICMP_Analyzer::Done() - { - TransportLayerAnalyzer::Done(); - icmp_conn_val = nullptr; - matcher_state.FinishEndpointMatcher(); - } - -void ICMP_Analyzer::DeliverPacket(int len, const u_char* data, - bool is_orig, uint64_t seq, const IP_Hdr* ip, int caplen) - { - assert(ip); - - TransportLayerAnalyzer::DeliverPacket(len, data, is_orig, seq, ip, caplen); - - // We need the min() here because Ethernet frame padding can lead to - // caplen > len. - if ( packet_contents ) - // Subtract off the common part of ICMP header. - PacketContents(data + 8, std::min(len, caplen) - 8); - - const struct icmp* icmpp = (const struct icmp*) data; - - if ( ! zeek::detail::ignore_checksums && - ! zeek::id::find_val("ignore_checksums_nets")->Contains(ip->IPHeaderSrcAddr()) && - caplen >= len ) - { - int chksum = 0; - - switch ( ip->NextProto() ) - { - case IPPROTO_ICMP: - chksum = icmp_checksum(icmpp, len); - break; - - case IPPROTO_ICMPV6: - chksum = icmp6_checksum(icmpp, ip, len); - break; - - default: - reporter->AnalyzerError( - this, "unexpected IP proto in ICMP analyzer: %d", ip->NextProto()); - return; - } - - if ( chksum != 0xffff ) - { - Weird("bad_ICMP_checksum"); - return; - } - } - - Conn()->SetLastTime(run_state::current_timestamp); - - if ( zeek::detail::rule_matcher ) - { - if ( ! matcher_state.MatcherInitialized(is_orig) ) - matcher_state.InitEndpointMatcher(this, ip, len, is_orig, nullptr); - } - - type = icmpp->icmp_type; - code = icmpp->icmp_code; - - // Move past common portion of ICMP header. - data += 8; - caplen -= 8; - len -= 8; - - int& len_stat = is_orig ? request_len : reply_len; - if ( len_stat < 0 ) - len_stat = len; - else - len_stat += len; - - if ( ip->NextProto() == IPPROTO_ICMP ) - NextICMP4(run_state::current_timestamp, icmpp, len, caplen, data, ip); - else if ( ip->NextProto() == IPPROTO_ICMPV6 ) - NextICMP6(run_state::current_timestamp, icmpp, len, caplen, data, ip); - else - { - reporter->AnalyzerError( - this, "expected ICMP as IP packet's protocol, got %d", ip->NextProto()); - return; - } - - - if ( caplen >= len ) - ForwardPacket(len, data, is_orig, seq, ip, caplen); - - if ( zeek::detail::rule_matcher ) - matcher_state.Match(zeek::detail::Rule::PAYLOAD, data, len, is_orig, - false, false, true); - } - -void ICMP_Analyzer::NextICMP4(double t, const struct icmp* icmpp, int len, int caplen, - const u_char*& data, const IP_Hdr* ip_hdr ) - { - switch ( icmpp->icmp_type ) - { - case ICMP_ECHO: - case ICMP_ECHOREPLY: - Echo(t, icmpp, len, caplen, data, ip_hdr); - break; - - case ICMP_UNREACH: - case ICMP_TIMXCEED: - Context4(t, icmpp, len, caplen, data, ip_hdr); - break; - - default: - ICMP_Sent(icmpp, len, caplen, 0, data, ip_hdr); - break; - } - } - -void ICMP_Analyzer::NextICMP6(double t, const struct icmp* icmpp, int len, int caplen, - const u_char*& data, const IP_Hdr* ip_hdr ) - { - switch ( icmpp->icmp_type ) - { - // Echo types. - case ICMP6_ECHO_REQUEST: - case ICMP6_ECHO_REPLY: - Echo(t, icmpp, len, caplen, data, ip_hdr); - break; - - // Error messages all have the same structure for their context, - // and are handled by the same function. - case ICMP6_PARAM_PROB: - case ICMP6_TIME_EXCEEDED: - case ICMP6_PACKET_TOO_BIG: - case ICMP6_DST_UNREACH: - Context6(t, icmpp, len, caplen, data, ip_hdr); - break; - - // Router related messages. - case ND_REDIRECT: - Redirect(t, icmpp, len, caplen, data, ip_hdr); - break; - case ND_ROUTER_ADVERT: - RouterAdvert(t, icmpp, len, caplen, data, ip_hdr); - break; - case ND_NEIGHBOR_ADVERT: - NeighborAdvert(t, icmpp, len, caplen, data, ip_hdr); - break; - case ND_NEIGHBOR_SOLICIT: - NeighborSolicit(t, icmpp, len, caplen, data, ip_hdr); - break; - case ND_ROUTER_SOLICIT: - RouterSolicit(t, icmpp, len, caplen, data, ip_hdr); - break; - case ICMP6_ROUTER_RENUMBERING: - ICMP_Sent(icmpp, len, caplen, 1, data, ip_hdr); - break; - -#if 0 - // Currently not specifically implemented. - case MLD_LISTENER_QUERY: - case MLD_LISTENER_REPORT: - case MLD_LISTENER_REDUCTION: -#endif - default: - // Error messages (i.e., ICMPv6 type < 128) all have - // the same structure for their context, and are - // handled by the same function. - if ( icmpp->icmp_type < 128 ) - Context6(t, icmpp, len, caplen, data, ip_hdr); - else - ICMP_Sent(icmpp, len, caplen, 1, data, ip_hdr); - break; - } - } - -void ICMP_Analyzer::ICMP_Sent(const struct icmp* icmpp, int len, int caplen, - int icmpv6, const u_char* data, - const IP_Hdr* ip_hdr) - { - if ( icmp_sent ) - EnqueueConnEvent(icmp_sent, - ConnVal(), - BuildInfo(icmpp, len, icmpv6, ip_hdr) - ); - - if ( icmp_sent_payload ) - { - String* payload = new String(data, std::min(len, caplen), false); - - EnqueueConnEvent(icmp_sent_payload, - ConnVal(), - BuildInfo(icmpp, len, icmpv6, ip_hdr), - make_intrusive(payload) - ); - } - } - -RecordValPtr ICMP_Analyzer::BuildInfo(const struct icmp* icmpp, int len, - bool icmpv6, const IP_Hdr* ip_hdr) - { - static auto icmp_info = id::find_type("icmp_info"); - auto rval = make_intrusive(icmp_info); - rval->Assign(0, static_cast(icmpv6)); - rval->Assign(1, icmpp->icmp_type); - rval->Assign(2, icmpp->icmp_code); - rval->Assign(3, len); - rval->Assign(4, ip_hdr->TTL()); - return rval; - } - -TransportProto ICMP_Analyzer::GetContextProtocol(const IP_Hdr* ip_hdr, uint32_t* src_port, uint32_t* dst_port) - { - const u_char* transport_hdr; - uint32_t ip_hdr_len = ip_hdr->HdrLen(); - bool ip4 = ip_hdr->IP4_Hdr(); - - if ( ip4 ) - transport_hdr = ((u_char *) ip_hdr->IP4_Hdr() + ip_hdr_len); - else - transport_hdr = ((u_char *) ip_hdr->IP6_Hdr() + ip_hdr_len); - - TransportProto proto; - - switch ( ip_hdr->NextProto() ) { - case 1: proto = TRANSPORT_ICMP; break; - case 6: proto = TRANSPORT_TCP; break; - case 17: proto = TRANSPORT_UDP; break; - case 58: proto = TRANSPORT_ICMP; break; - default: proto = TRANSPORT_UNKNOWN; break; - } - - switch ( proto ) { - case TRANSPORT_ICMP: - { - const struct icmp* icmpp = - (const struct icmp *) transport_hdr; - bool is_one_way; // dummy - *src_port = ntohs(icmpp->icmp_type); - - if ( ip4 ) - *dst_port = ntohs(ICMP4_counterpart(icmpp->icmp_type, - icmpp->icmp_code, is_one_way)); - else - *dst_port = ntohs(ICMP6_counterpart(icmpp->icmp_type, - icmpp->icmp_code, is_one_way)); - - break; - } - - case TRANSPORT_TCP: - { - const struct tcphdr* tp = - (const struct tcphdr *) transport_hdr; - *src_port = ntohs(tp->th_sport); - *dst_port = ntohs(tp->th_dport); - break; - } - - case TRANSPORT_UDP: - { - const struct udphdr* up = - (const struct udphdr *) transport_hdr; - *src_port = ntohs(up->uh_sport); - *dst_port = ntohs(up->uh_dport); - break; - } - - default: - *src_port = *dst_port = ntohs(0); - break; - } - - return proto; - } - -RecordValPtr ICMP_Analyzer::ExtractICMP4Context(int len, const u_char*& data) - { - const IP_Hdr ip_hdr_data((const struct ip*) data, false); - const IP_Hdr* ip_hdr = &ip_hdr_data; - - uint32_t ip_hdr_len = ip_hdr->HdrLen(); - - uint32_t ip_len, frag_offset; - TransportProto proto = TRANSPORT_UNKNOWN; - int DF, MF, bad_hdr_len, bad_checksum; - IPAddr src_addr, dst_addr; - uint32_t src_port, dst_port; - - if ( len < (int)sizeof(struct ip) || ip_hdr_len > uint32_t(len) ) - { - // We don't have an entire IP header. - bad_hdr_len = 1; - ip_len = frag_offset = 0; - DF = MF = bad_checksum = 0; - src_port = dst_port = 0; - } - - else - { - bad_hdr_len = 0; - ip_len = ip_hdr->TotalLen(); - bad_checksum = ! run_state::current_pkt->l3_checksummed && - (detail::in_cksum(reinterpret_cast(ip_hdr->IP4_Hdr()), - ip_hdr_len) != 0xffff); - - src_addr = ip_hdr->SrcAddr(); - dst_addr = ip_hdr->DstAddr(); - - DF = ip_hdr->DF(); - MF = ip_hdr->MF(); - frag_offset = ip_hdr->FragOffset(); - - if ( uint32_t(len) >= ip_hdr_len + 4 ) - proto = GetContextProtocol(ip_hdr, &src_port, &dst_port); - else - { - // 4 above is the magic number meaning that both - // port numbers are included in the ICMP. - src_port = dst_port = 0; - bad_hdr_len = 1; - } - } - - static auto icmp_context = id::find_type("icmp_context"); - auto iprec = make_intrusive(icmp_context); - auto id_val = make_intrusive(id::conn_id); - - id_val->Assign(0, make_intrusive(src_addr)); - id_val->Assign(1, val_mgr->Port(src_port, proto)); - id_val->Assign(2, make_intrusive(dst_addr)); - id_val->Assign(3, val_mgr->Port(dst_port, proto)); - - iprec->Assign(0, std::move(id_val)); - iprec->Assign(1, ip_len); - iprec->Assign(2, proto); - iprec->Assign(3, frag_offset); - iprec->Assign(4, static_cast(bad_hdr_len)); - iprec->Assign(5, static_cast(bad_checksum)); - iprec->Assign(6, static_cast(MF)); - iprec->Assign(7, static_cast(DF)); - - return iprec; - } - -RecordValPtr ICMP_Analyzer::ExtractICMP6Context(int len, const u_char*& data) - { - int DF = 0, MF = 0, bad_hdr_len = 0; - TransportProto proto = TRANSPORT_UNKNOWN; - - IPAddr src_addr; - IPAddr dst_addr; - uint32_t ip_len, frag_offset = 0; - uint32_t src_port, dst_port; - - if ( len < (int)sizeof(struct ip6_hdr) ) - { - bad_hdr_len = 1; - ip_len = 0; - src_port = dst_port = 0; - } - else - { - const IP_Hdr ip_hdr_data((const struct ip6_hdr*) data, false, len); - const IP_Hdr* ip_hdr = &ip_hdr_data; - - ip_len = ip_hdr->TotalLen(); - src_addr = ip_hdr->SrcAddr(); - dst_addr = ip_hdr->DstAddr(); - frag_offset = ip_hdr->FragOffset(); - MF = ip_hdr->MF(); - DF = ip_hdr->DF(); - - if ( uint32_t(len) >= uint32_t(ip_hdr->HdrLen() + 4) ) - proto = GetContextProtocol(ip_hdr, &src_port, &dst_port); - else - { - // 4 above is the magic number meaning that both - // port numbers are included in the ICMP. - src_port = dst_port = 0; - bad_hdr_len = 1; - } - } - - static auto icmp_context = id::find_type("icmp_context"); - auto iprec = make_intrusive(icmp_context); - auto id_val = make_intrusive(id::conn_id); - - id_val->Assign(0, make_intrusive(src_addr)); - id_val->Assign(1, val_mgr->Port(src_port, proto)); - id_val->Assign(2, make_intrusive(dst_addr)); - id_val->Assign(3, val_mgr->Port(dst_port, proto)); - - iprec->Assign(0, std::move(id_val)); - iprec->Assign(1, ip_len); - iprec->Assign(2, proto); - iprec->Assign(3, frag_offset); - iprec->Assign(4, static_cast(bad_hdr_len)); - // bad_checksum is always false since IPv6 layer doesn't have a checksum. - iprec->Assign(5, false); - iprec->Assign(6, static_cast(MF)); - iprec->Assign(7, static_cast(DF)); - - return iprec; - } - -bool ICMP_Analyzer::IsReuse(double /* t */, const u_char* /* pkt */) - { - return false; - } - -void ICMP_Analyzer::Describe(ODesc* d) const - { - d->Add(Conn()->StartTime()); - d->Add("("); - d->Add(Conn()->LastTime()); - d->AddSP(")"); - - d->Add(Conn()->OrigAddr()); - d->Add("."); - d->Add(type); - d->Add("."); - d->Add(code); - - d->SP(); - d->AddSP("->"); - - d->Add(Conn()->RespAddr()); - } - -void ICMP_Analyzer::UpdateConnVal(RecordVal *conn_val) - { - const auto& orig_endp = conn_val->GetField("orig"); - const auto& resp_endp = conn_val->GetField("resp"); - - UpdateEndpointVal(orig_endp, true); - UpdateEndpointVal(resp_endp, false); - - // Call children's UpdateConnVal - Analyzer::UpdateConnVal(conn_val); - } - -void ICMP_Analyzer::UpdateEndpointVal(const ValPtr& endp_arg, bool is_orig) - { - Conn()->EnableStatusUpdateTimer(); - - int size = is_orig ? request_len : reply_len; - auto endp = endp_arg->AsRecordVal(); - - if ( size < 0 ) - { - endp->Assign(0, 0); - endp->Assign(1, ICMP_INACTIVE); - } - - else - { - endp->Assign(0, size); - endp->Assign(1, ICMP_ACTIVE); - } - } - -unsigned int ICMP_Analyzer::MemoryAllocation() const - { - return Analyzer::MemoryAllocation() - + padded_sizeof(*this) - padded_sizeof(Connection) - + (icmp_conn_val ? icmp_conn_val->MemoryAllocation() : 0); - } - - -void ICMP_Analyzer::Echo(double t, const struct icmp* icmpp, int len, - int caplen, const u_char*& data, const IP_Hdr* ip_hdr) - { - // For handling all Echo related ICMP messages - EventHandlerPtr f = nullptr; - - if ( ip_hdr->NextProto() == IPPROTO_ICMPV6 ) - f = (icmpp->icmp_type == ICMP6_ECHO_REQUEST) - ? icmp_echo_request : icmp_echo_reply; - else - f = (icmpp->icmp_type == ICMP_ECHO) - ? icmp_echo_request : icmp_echo_reply; - - if ( ! f ) - return; - - int iid = ntohs(icmpp->icmp_hun.ih_idseq.icd_id); - int iseq = ntohs(icmpp->icmp_hun.ih_idseq.icd_seq); - - String* payload = new String(data, caplen, false); - - EnqueueConnEvent(f, - ConnVal(), - BuildInfo(icmpp, len, ip_hdr->NextProto() != IPPROTO_ICMP, ip_hdr), - val_mgr->Count(iid), - val_mgr->Count(iseq), - make_intrusive(payload) - ); - } - - -void ICMP_Analyzer::RouterAdvert(double t, const struct icmp* icmpp, int len, - int caplen, const u_char*& data, const IP_Hdr* ip_hdr) - { - EventHandlerPtr f = icmp_router_advertisement; - - if ( ! f ) - return; - - uint32_t reachable = 0, retrans = 0; - - if ( caplen >= (int)sizeof(reachable) ) - memcpy(&reachable, data, sizeof(reachable)); - - if ( caplen >= (int)sizeof(reachable) + (int)sizeof(retrans) ) - memcpy(&retrans, data + sizeof(reachable), sizeof(retrans)); - - int opt_offset = sizeof(reachable) + sizeof(retrans); - - EnqueueConnEvent(f, - ConnVal(), - BuildInfo(icmpp, len, 1, ip_hdr), - val_mgr->Count(icmpp->icmp_num_addrs), // Cur Hop Limit - val_mgr->Bool(icmpp->icmp_wpa & 0x80), // Managed - val_mgr->Bool(icmpp->icmp_wpa & 0x40), // Other - val_mgr->Bool(icmpp->icmp_wpa & 0x20), // Home Agent - val_mgr->Count((icmpp->icmp_wpa & 0x18)>>3), // Pref - val_mgr->Bool(icmpp->icmp_wpa & 0x04), // Proxy - val_mgr->Count(icmpp->icmp_wpa & 0x02), // Reserved - make_intrusive((double)ntohs(icmpp->icmp_lifetime), Seconds), - make_intrusive((double)ntohl(reachable), Milliseconds), - make_intrusive((double)ntohl(retrans), Milliseconds), - BuildNDOptionsVal(caplen - opt_offset, data + opt_offset) - ); - } - - -void ICMP_Analyzer::NeighborAdvert(double t, const struct icmp* icmpp, int len, - int caplen, const u_char*& data, const IP_Hdr* ip_hdr) - { - EventHandlerPtr f = icmp_neighbor_advertisement; - - if ( ! f ) - return; - - IPAddr tgtaddr; - - if ( caplen >= (int)sizeof(in6_addr) ) - tgtaddr = IPAddr(*((const in6_addr*)data)); - - int opt_offset = sizeof(in6_addr); - - EnqueueConnEvent(f, - ConnVal(), - BuildInfo(icmpp, len, 1, ip_hdr), - val_mgr->Bool(icmpp->icmp_num_addrs & 0x80), // Router - val_mgr->Bool(icmpp->icmp_num_addrs & 0x40), // Solicited - val_mgr->Bool(icmpp->icmp_num_addrs & 0x20), // Override - make_intrusive(tgtaddr), - BuildNDOptionsVal(caplen - opt_offset, data + opt_offset) - ); - } - - -void ICMP_Analyzer::NeighborSolicit(double t, const struct icmp* icmpp, int len, - int caplen, const u_char*& data, const IP_Hdr* ip_hdr) - { - EventHandlerPtr f = icmp_neighbor_solicitation; - - if ( ! f ) - return; - - IPAddr tgtaddr; - - if ( caplen >= (int)sizeof(in6_addr) ) - tgtaddr = IPAddr(*((const in6_addr*)data)); - - int opt_offset = sizeof(in6_addr); - - EnqueueConnEvent(f, - ConnVal(), - BuildInfo(icmpp, len, 1, ip_hdr), - make_intrusive(tgtaddr), - BuildNDOptionsVal(caplen - opt_offset, data + opt_offset) - ); - } - - -void ICMP_Analyzer::Redirect(double t, const struct icmp* icmpp, int len, - int caplen, const u_char*& data, const IP_Hdr* ip_hdr) - { - EventHandlerPtr f = icmp_redirect; - - if ( ! f ) - return; - - IPAddr tgtaddr, dstaddr; - - if ( caplen >= (int)sizeof(in6_addr) ) - tgtaddr = IPAddr(*((const in6_addr*)data)); - - if ( caplen >= 2 * (int)sizeof(in6_addr) ) - dstaddr = IPAddr(*((const in6_addr*)(data + sizeof(in6_addr)))); - - int opt_offset = 2 * sizeof(in6_addr); - - EnqueueConnEvent(f, - ConnVal(), - BuildInfo(icmpp, len, 1, ip_hdr), - make_intrusive(tgtaddr), - make_intrusive(dstaddr), - BuildNDOptionsVal(caplen - opt_offset, data + opt_offset) - ); - } - - -void ICMP_Analyzer::RouterSolicit(double t, const struct icmp* icmpp, int len, - int caplen, const u_char*& data, const IP_Hdr* ip_hdr) - { - EventHandlerPtr f = icmp_router_solicitation; - - if ( ! f ) - return; - - EnqueueConnEvent(f, - ConnVal(), - BuildInfo(icmpp, len, 1, ip_hdr), - BuildNDOptionsVal(caplen, data) - ); - } - - -void ICMP_Analyzer::Context4(double t, const struct icmp* icmpp, - int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr) - { - EventHandlerPtr f = nullptr; - - switch ( icmpp->icmp_type ) - { - case ICMP_UNREACH: - f = icmp_unreachable; - break; - - case ICMP_TIMXCEED: - f = icmp_time_exceeded; - break; - } - - if ( f ) - EnqueueConnEvent(f, - ConnVal(), - BuildInfo(icmpp, len, 0, ip_hdr), - val_mgr->Count(icmpp->icmp_code), - ExtractICMP4Context(caplen, data) - ); - } - - -void ICMP_Analyzer::Context6(double t, const struct icmp* icmpp, - int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr) - { - EventHandlerPtr f = nullptr; - - switch ( icmpp->icmp_type ) - { - case ICMP6_DST_UNREACH: - f = icmp_unreachable; - break; - - case ICMP6_PARAM_PROB: - f = icmp_parameter_problem; - break; - - case ICMP6_TIME_EXCEEDED: - f = icmp_time_exceeded; - break; - - case ICMP6_PACKET_TOO_BIG: - f = icmp_packet_too_big; - break; - - default: - f = icmp_error_message; - break; - } - - if ( f ) - EnqueueConnEvent(f, - ConnVal(), - BuildInfo(icmpp, len, 1, ip_hdr), - val_mgr->Count(icmpp->icmp_code), - ExtractICMP6Context(caplen, data) - ); - } - -VectorValPtr ICMP_Analyzer::BuildNDOptionsVal(int caplen, const u_char* data) - { - static auto icmp6_nd_option_type = id::find_type("icmp6_nd_option"); - static auto icmp6_nd_prefix_info_type = id::find_type("icmp6_nd_prefix_info"); - - auto vv = make_intrusive( - id::find_type("icmp6_nd_options")); - - while ( caplen > 0 ) - { - // Must have at least type & length to continue parsing options. - if ( caplen < 2 ) - { - Weird("truncated_ICMPv6_ND_options"); - break; - } - - uint8_t type = *((const uint8_t*)data); - uint16_t length = *((const uint8_t*)(data + 1)); - - if ( length == 0 ) - { - Weird("zero_length_ICMPv6_ND_option"); - break; - } - - auto rv = make_intrusive(icmp6_nd_option_type); - rv->Assign(0, type); - rv->Assign(1, length); - - // Adjust length to be in units of bytes, exclude type/length fields. - length = length * 8 - 2; - - data += 2; - caplen -= 2; - - bool set_payload_field = false; - - // Only parse out known options that are there in full. - switch ( type ) { - case 1: - case 2: - // Source/Target Link-layer Address option - { - if ( caplen >= length ) - { - String* link_addr = new String(data, length, false); - rv->Assign(2, link_addr); - } - else - set_payload_field = true; - - break; - } - - case 3: - // Prefix Information option - { - if ( caplen >= 30 ) - { - auto info = make_intrusive(icmp6_nd_prefix_info_type); - uint8_t prefix_len = *((const uint8_t*)(data)); - bool L_flag = (*((const uint8_t*)(data + 1)) & 0x80) != 0; - bool A_flag = (*((const uint8_t*)(data + 1)) & 0x40) != 0; - uint32_t valid_life = *((const uint32_t*)(data + 2)); - uint32_t prefer_life = *((const uint32_t*)(data + 6)); - in6_addr prefix = *((const in6_addr*)(data + 14)); - info->Assign(0, prefix_len); - info->Assign(1, L_flag); - info->Assign(2, A_flag); - info->AssignInterval(3, double(ntohl(valid_life))); - info->AssignInterval(4, double(ntohl(prefer_life))); - info->Assign(5, make_intrusive(IPAddr(prefix))); - rv->Assign(3, std::move(info)); - } - - else - set_payload_field = true; - break; - } - - case 4: - // Redirected Header option - { - if ( caplen >= length ) - { - const u_char* hdr = data + 6; - rv->Assign(4, ExtractICMP6Context(length - 6, hdr)); - } - - else - set_payload_field = true; - - break; - } - - case 5: - // MTU option - { - if ( caplen >= 6 ) - rv->Assign(5, ntohl(*((const uint32_t*)(data + 2)))); - else - set_payload_field = true; - - break; - } - - default: - { - set_payload_field = true; - break; - } - } - - if ( set_payload_field ) - { - String* payload = new String(data, std::min((int)length, caplen), false); - rv->Assign(6, payload); - } - - data += length; - caplen -= length; - - vv->Assign(vv->Size(), std::move(rv)); - } - - return vv; - } - -int ICMP4_counterpart(int icmp_type, int icmp_code, bool& is_one_way) - { - is_one_way = false; - - // Return the counterpart type if one exists. This allows us - // to track corresponding ICMP requests/replies. - // Note that for the two-way ICMP messages, icmp_code is - // always 0 (RFC 792). - switch ( icmp_type ) { - case ICMP_ECHO: return ICMP_ECHOREPLY; - case ICMP_ECHOREPLY: return ICMP_ECHO; - - case ICMP_TSTAMP: return ICMP_TSTAMPREPLY; - case ICMP_TSTAMPREPLY: return ICMP_TSTAMP; - - case ICMP_IREQ: return ICMP_IREQREPLY; - case ICMP_IREQREPLY: return ICMP_IREQ; - - case ICMP_ROUTERSOLICIT: return ICMP_ROUTERADVERT; - case ICMP_ROUTERADVERT: return ICMP_ROUTERSOLICIT; - - case ICMP_MASKREQ: return ICMP_MASKREPLY; - case ICMP_MASKREPLY: return ICMP_MASKREQ; - - default: is_one_way = true; return icmp_code; - } - } - -int ICMP6_counterpart(int icmp_type, int icmp_code, bool& is_one_way) - { - is_one_way = false; - - switch ( icmp_type ) { - case ICMP6_ECHO_REQUEST: return ICMP6_ECHO_REPLY; - case ICMP6_ECHO_REPLY: return ICMP6_ECHO_REQUEST; - - case ND_ROUTER_SOLICIT: return ND_ROUTER_ADVERT; - case ND_ROUTER_ADVERT: return ND_ROUTER_SOLICIT; - - case ND_NEIGHBOR_SOLICIT: return ND_NEIGHBOR_ADVERT; - case ND_NEIGHBOR_ADVERT: return ND_NEIGHBOR_SOLICIT; - - case MLD_LISTENER_QUERY: return MLD_LISTENER_REPORT; - case MLD_LISTENER_REPORT: return MLD_LISTENER_QUERY; - - // ICMP node information query and response respectively (not defined in - // icmp6.h) - case 139: return 140; - case 140: return 139; - - // Home Agent Address Discovery Request Message and reply - case 144: return 145; - case 145: return 144; - - // TODO: Add further counterparts. - - default: is_one_way = true; return icmp_code; - } - } - -} // namespace zeek::analyzer::icmp diff --git a/src/analyzer/protocol/icmp/ICMP.h b/src/analyzer/protocol/icmp/ICMP.h deleted file mode 100644 index ef9aeddf92..0000000000 --- a/src/analyzer/protocol/icmp/ICMP.h +++ /dev/null @@ -1,99 +0,0 @@ -// See the file "COPYING" in the main distribution directory for copyright. - -#pragma once - -#include "zeek/RuleMatcher.h" -#include "zeek/analyzer/Analyzer.h" -#include "zeek/net_util.h" - -namespace zeek { - -class VectorVal; -using VectorValPtr = IntrusivePtr; - -namespace analyzer::icmp { - -enum ICMP_EndpointState { - ICMP_INACTIVE, // no packet seen - ICMP_ACTIVE, // packets seen -}; - -// We do not have an PIA for ICMP (yet) and therefore derive from -// RuleMatcherState to perform our own matching. -class ICMP_Analyzer final : public analyzer::TransportLayerAnalyzer { -public: - explicit ICMP_Analyzer(Connection* conn); - - void UpdateConnVal(RecordVal *conn_val) override; - - static analyzer::Analyzer* Instantiate(Connection* conn) - { return new ICMP_Analyzer(conn); } - -protected: - void Done() override; - void DeliverPacket(int len, const u_char* data, bool orig, - uint64_t seq, const IP_Hdr* ip, int caplen) override; - bool IsReuse(double t, const u_char* pkt) override; - unsigned int MemoryAllocation() const override; - - void ICMP_Sent(const struct icmp* icmpp, int len, int caplen, int icmpv6, - const u_char* data, const IP_Hdr* ip_hdr); - - void Echo(double t, const struct icmp* icmpp, int len, - int caplen, const u_char*& data, const IP_Hdr* ip_hdr); - void Redirect(double t, const struct icmp* icmpp, int len, - int caplen, const u_char*& data, const IP_Hdr* ip_hdr); - void RouterAdvert(double t, const struct icmp* icmpp, int len, - int caplen, const u_char*& data, const IP_Hdr* ip_hdr); - void NeighborAdvert(double t, const struct icmp* icmpp, int len, - int caplen, const u_char*& data, const IP_Hdr* ip_hdr); - void NeighborSolicit(double t, const struct icmp* icmpp, int len, - int caplen, const u_char*& data, const IP_Hdr* ip_hdr); - void RouterSolicit(double t, const struct icmp* icmpp, int len, - int caplen, const u_char*& data, const IP_Hdr* ip_hdr); - - void Describe(ODesc* d) const; - - RecordValPtr BuildInfo(const struct icmp* icmpp, int len, - bool icmpv6, const IP_Hdr* ip_hdr); - - void NextICMP4(double t, const struct icmp* icmpp, int len, int caplen, - const u_char*& data, const IP_Hdr* ip_hdr ); - - RecordValPtr ExtractICMP4Context(int len, const u_char*& data); - - void Context4(double t, const struct icmp* icmpp, int len, int caplen, - const u_char*& data, const IP_Hdr* ip_hdr); - - TransportProto GetContextProtocol(const IP_Hdr* ip_hdr, uint32_t* src_port, - uint32_t* dst_port); - - void NextICMP6(double t, const struct icmp* icmpp, int len, int caplen, - const u_char*& data, const IP_Hdr* ip_hdr ); - - RecordValPtr ExtractICMP6Context(int len, const u_char*& data); - - void Context6(double t, const struct icmp* icmpp, int len, int caplen, - const u_char*& data, const IP_Hdr* ip_hdr); - - // RFC 4861 Neighbor Discover message options - VectorValPtr BuildNDOptionsVal(int caplen, const u_char* data); - - RecordValPtr icmp_conn_val; - int type; - int code; - int request_len, reply_len; - - detail::RuleMatcherState matcher_state; - -private: - void UpdateEndpointVal(const ValPtr& endp, bool is_orig); -}; - -// Returns the counterpart type to the given type (e.g., the counterpart -// to ICMP_ECHOREPLY is ICMP_ECHO). -extern int ICMP4_counterpart(int icmp_type, int icmp_code, bool& is_one_way); -extern int ICMP6_counterpart(int icmp_type, int icmp_code, bool& is_one_way); - -} // namespace analyzer::icmp -} // namespace zeek diff --git a/src/analyzer/protocol/icmp/Plugin.cc b/src/analyzer/protocol/icmp/Plugin.cc deleted file mode 100644 index 7326604034..0000000000 --- a/src/analyzer/protocol/icmp/Plugin.cc +++ /dev/null @@ -1,22 +0,0 @@ -// See the file in the main distribution directory for copyright. - -#include "zeek/plugin/Plugin.h" -#include "zeek/analyzer/Component.h" -#include "zeek/analyzer/protocol/icmp/ICMP.h" - -namespace zeek::plugin::detail::Zeek_ICMP { - -class Plugin : public zeek::plugin::Plugin { -public: - zeek::plugin::Configuration Configure() override - { - AddComponent(new zeek::analyzer::Component("ICMP", zeek::analyzer::icmp::ICMP_Analyzer::Instantiate)); - - zeek::plugin::Configuration config; - config.name = "Zeek::ICMP"; - config.description = "ICMP analyzer"; - return config; - } -} plugin; - -} // namespace zeek::plugin::detail::Zeek_ICMP diff --git a/src/packet_analysis/protocol/icmp/CMakeLists.txt b/src/packet_analysis/protocol/icmp/CMakeLists.txt index 7b4eb86231..875b3597ec 100644 --- a/src/packet_analysis/protocol/icmp/CMakeLists.txt +++ b/src/packet_analysis/protocol/icmp/CMakeLists.txt @@ -3,6 +3,7 @@ include(ZeekPlugin) include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) -zeek_plugin_begin(PacketAnalyzer ICMP_PKT) +zeek_plugin_begin(Zeek ICMP) zeek_plugin_cc(ICMP.cc Plugin.cc) +zeek_plugin_bif(events.bif) zeek_plugin_end() diff --git a/src/packet_analysis/protocol/icmp/ICMP.cc b/src/packet_analysis/protocol/icmp/ICMP.cc index 2eaf18b621..30b929e621 100644 --- a/src/packet_analysis/protocol/icmp/ICMP.cc +++ b/src/packet_analysis/protocol/icmp/ICMP.cc @@ -5,13 +5,30 @@ #include #include "zeek/RunState.h" +#include "zeek/Conn.h" +#include "zeek/Reporter.h" +#include "zeek/Desc.h" +#include "zeek/Val.h" +#include "zeek/analyzer/Manager.h" #include "zeek/session/Manager.h" +#include "zeek/analyzer/protocol/conn-size/ConnSize.h" + +#include "zeek/ZeekString.h" + +#include "zeek/packet_analysis/protocol/icmp/events.bif.h" + +enum ICMP_EndpointState { + ICMP_INACTIVE, // no packet seen + ICMP_ACTIVE, // packets seen +}; using namespace zeek::packet_analysis::ICMP; using namespace zeek::packet_analysis::IP; ICMPAnalyzer::ICMPAnalyzer() : IPBasedAnalyzer("ICMP", TRANSPORT_ICMP, ICMP_PORT_MASK, false) { + // TODO: remove once the other plugins are done + new_plugin = true; } ICMPAnalyzer::~ICMPAnalyzer() @@ -46,13 +63,742 @@ bool ICMPAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet void ICMPAnalyzer::ContinueProcessing(Connection* c, double t, bool is_orig, int remaining, Packet* pkt) { + auto* ta = static_cast(c->GetRootAnalyzer()); + + const u_char* data = pkt->ip_hdr->Payload(); + int len = pkt->ip_hdr->PayloadLen(); + + if ( packet_contents && len > 0 ) + ta->PacketContents(data + 8, std::min(len, remaining) - 8); + + const struct icmp* icmpp = (const struct icmp*) data; + const std::unique_ptr& ip = pkt->ip_hdr; + + if ( ! zeek::detail::ignore_checksums && + ! zeek::id::find_val("ignore_checksums_nets")->Contains(ip->IPHeaderSrcAddr()) && + remaining >= len ) + { + int chksum = 0; + + switch ( ip->NextProto() ) + { + case IPPROTO_ICMP: + chksum = icmp_checksum(icmpp, len); + break; + + case IPPROTO_ICMPV6: + chksum = icmp6_checksum(icmpp, ip.get(), len); + break; + + default: + reporter->Error("unexpected IP proto in ICMP analyzer: %d", ip->NextProto()); + return; + } + + if ( chksum != 0xffff ) + { + ta->Weird("bad_ICMP_checksum"); + return; + } + } + + c->SetLastTime(run_state::current_timestamp); + ta->InitEndpointMatcher(ip.get(), len, is_orig); + + // Move past common portion of ICMP header. + data += 8; + remaining -= 8; + len -= 8; + + ta->UpdateLength(is_orig, len); + + if ( ip->NextProto() == IPPROTO_ICMP ) + NextICMP4(run_state::current_timestamp, icmpp, len, remaining, data, ip.get(), ta); + else if ( ip->NextProto() == IPPROTO_ICMPV6 ) + NextICMP6(run_state::current_timestamp, icmpp, len, remaining, data, ip.get(), ta); + else + { + reporter->Error("expected ICMP as IP packet's protocol, got %d", ip->NextProto()); + return; + } + + ForwardPacket(len, data, pkt); + + if ( remaining >= len ) + ta->ForwardPacket(len, data, is_orig, -1, ip.get(), remaining); + + ta->MatchEndpoint(data, len, is_orig); } -void ICMPAnalyzer::CreateTransportAnalyzer(Connection* conn, IPBasedTransportAnalyzer*& root, - analyzer::pia::PIA*& pia, bool& check_port) +void ICMPAnalyzer::NextICMP4(double t, const struct icmp* icmpp, int len, int caplen, + const u_char*& data, const IP_Hdr* ip_hdr, + ICMPTransportAnalyzer* analyzer) { + switch ( icmpp->icmp_type ) + { + case ICMP_ECHO: + case ICMP_ECHOREPLY: + Echo(t, icmpp, len, caplen, data, ip_hdr, analyzer); + break; + + case ICMP_UNREACH: + case ICMP_TIMXCEED: + Context4(t, icmpp, len, caplen, data, ip_hdr, analyzer); + break; + + default: + ICMP_Sent(icmpp, len, caplen, 0, data, ip_hdr, analyzer); + break; + } } +void ICMPAnalyzer::NextICMP6(double t, const struct icmp* icmpp, int len, int caplen, + const u_char*& data, const IP_Hdr* ip_hdr, + ICMPTransportAnalyzer* analyzer) + { + switch ( icmpp->icmp_type ) + { + // Echo types. + case ICMP6_ECHO_REQUEST: + case ICMP6_ECHO_REPLY: + Echo(t, icmpp, len, caplen, data, ip_hdr, analyzer); + break; + + // Error messages all have the same structure for their context, + // and are handled by the same function. + case ICMP6_PARAM_PROB: + case ICMP6_TIME_EXCEEDED: + case ICMP6_PACKET_TOO_BIG: + case ICMP6_DST_UNREACH: + Context6(t, icmpp, len, caplen, data, ip_hdr, analyzer); + break; + + // Router related messages. + case ND_REDIRECT: + Redirect(t, icmpp, len, caplen, data, ip_hdr, analyzer); + break; + case ND_ROUTER_ADVERT: + RouterAdvert(t, icmpp, len, caplen, data, ip_hdr, analyzer); + break; + case ND_NEIGHBOR_ADVERT: + NeighborAdvert(t, icmpp, len, caplen, data, ip_hdr, analyzer); + break; + case ND_NEIGHBOR_SOLICIT: + NeighborSolicit(t, icmpp, len, caplen, data, ip_hdr, analyzer); + break; + case ND_ROUTER_SOLICIT: + RouterSolicit(t, icmpp, len, caplen, data, ip_hdr, analyzer); + break; + case ICMP6_ROUTER_RENUMBERING: + ICMP_Sent(icmpp, len, caplen, 1, data, ip_hdr, analyzer); + break; + +#if 0 + // Currently not specifically implemented. + case MLD_LISTENER_QUERY: + case MLD_LISTENER_REPORT: + case MLD_LISTENER_REDUCTION: +#endif + default: + // Error messages (i.e., ICMPv6 type < 128) all have + // the same structure for their context, and are + // handled by the same function. + if ( icmpp->icmp_type < 128 ) + Context6(t, icmpp, len, caplen, data, ip_hdr, analyzer); + else + ICMP_Sent(icmpp, len, caplen, 1, data, ip_hdr, analyzer); + break; + } + } + +void ICMPAnalyzer::ICMP_Sent(const struct icmp* icmpp, int len, int caplen, + int icmpv6, const u_char* data, const IP_Hdr* ip_hdr, + ICMPTransportAnalyzer* analyzer) + { + if ( icmp_sent ) + analyzer->EnqueueConnEvent(icmp_sent, analyzer->ConnVal(), + BuildInfo(icmpp, len, icmpv6, ip_hdr)); + + if ( icmp_sent_payload ) + { + String* payload = new String(data, std::min(len, caplen), false); + + analyzer->EnqueueConnEvent(icmp_sent_payload, analyzer->ConnVal(), + BuildInfo(icmpp, len, icmpv6, ip_hdr), + make_intrusive(payload)); + } + } + +zeek::RecordValPtr ICMPAnalyzer::BuildInfo(const struct icmp* icmpp, int len, + bool icmpv6, const IP_Hdr* ip_hdr) + { + static auto icmp_info = id::find_type("icmp_info"); + auto rval = make_intrusive(icmp_info); + rval->Assign(0, val_mgr->Bool(icmpv6)); + rval->Assign(1, val_mgr->Count(icmpp->icmp_type)); + rval->Assign(2, val_mgr->Count(icmpp->icmp_code)); + rval->Assign(3, val_mgr->Count(len)); + rval->Assign(4, val_mgr->Count(ip_hdr->TTL())); + return rval; + } + +TransportProto ICMPAnalyzer::GetContextProtocol(const IP_Hdr* ip_hdr, uint32_t* src_port, uint32_t* dst_port) + { + const u_char* transport_hdr; + uint32_t ip_hdr_len = ip_hdr->HdrLen(); + bool ip4 = ip_hdr->IP4_Hdr(); + + if ( ip4 ) + transport_hdr = ((u_char *) ip_hdr->IP4_Hdr() + ip_hdr_len); + else + transport_hdr = ((u_char *) ip_hdr->IP6_Hdr() + ip_hdr_len); + + TransportProto proto; + + switch ( ip_hdr->NextProto() ) { + case 1: proto = TRANSPORT_ICMP; break; + case 6: proto = TRANSPORT_TCP; break; + case 17: proto = TRANSPORT_UDP; break; + case 58: proto = TRANSPORT_ICMP; break; + default: proto = TRANSPORT_UNKNOWN; break; + } + + switch ( proto ) { + case TRANSPORT_ICMP: + { + const struct icmp* icmpp = + (const struct icmp *) transport_hdr; + bool is_one_way; // dummy + *src_port = ntohs(icmpp->icmp_type); + + if ( ip4 ) + *dst_port = ntohs(ICMP4_counterpart(icmpp->icmp_type, + icmpp->icmp_code, is_one_way)); + else + *dst_port = ntohs(ICMP6_counterpart(icmpp->icmp_type, + icmpp->icmp_code, is_one_way)); + + break; + } + + case TRANSPORT_TCP: + { + const struct tcphdr* tp = + (const struct tcphdr *) transport_hdr; + *src_port = ntohs(tp->th_sport); + *dst_port = ntohs(tp->th_dport); + break; + } + + case TRANSPORT_UDP: + { + const struct udphdr* up = + (const struct udphdr *) transport_hdr; + *src_port = ntohs(up->uh_sport); + *dst_port = ntohs(up->uh_dport); + break; + } + + default: + *src_port = *dst_port = ntohs(0); + break; + } + + return proto; + } + +zeek::RecordValPtr ICMPAnalyzer::ExtractICMP4Context(int len, const u_char*& data) + { + const IP_Hdr ip_hdr_data((const struct ip*) data, false); + const IP_Hdr* ip_hdr = &ip_hdr_data; + + uint32_t ip_hdr_len = ip_hdr->HdrLen(); + + uint32_t ip_len, frag_offset; + TransportProto proto = TRANSPORT_UNKNOWN; + int DF, MF, bad_hdr_len, bad_checksum; + IPAddr src_addr, dst_addr; + uint32_t src_port, dst_port; + + if ( len < (int)sizeof(struct ip) || ip_hdr_len > uint32_t(len) ) + { + // We don't have an entire IP header. + bad_hdr_len = 1; + ip_len = frag_offset = 0; + DF = MF = bad_checksum = 0; + src_port = dst_port = 0; + } + + else + { + bad_hdr_len = 0; + ip_len = ip_hdr->TotalLen(); + bad_checksum = ! run_state::current_pkt->l3_checksummed && + (detail::in_cksum(reinterpret_cast(ip_hdr->IP4_Hdr()), + ip_hdr_len) != 0xffff); + + src_addr = ip_hdr->SrcAddr(); + dst_addr = ip_hdr->DstAddr(); + + DF = ip_hdr->DF(); + MF = ip_hdr->MF(); + frag_offset = ip_hdr->FragOffset(); + + if ( uint32_t(len) >= ip_hdr_len + 4 ) + proto = GetContextProtocol(ip_hdr, &src_port, &dst_port); + else + { + // 4 above is the magic number meaning that both + // port numbers are included in the ICMP. + src_port = dst_port = 0; + bad_hdr_len = 1; + } + } + + static auto icmp_context = id::find_type("icmp_context"); + auto iprec = make_intrusive(icmp_context); + auto id_val = make_intrusive(id::conn_id); + + id_val->Assign(0, make_intrusive(src_addr)); + id_val->Assign(1, val_mgr->Port(src_port, proto)); + id_val->Assign(2, make_intrusive(dst_addr)); + id_val->Assign(3, val_mgr->Port(dst_port, proto)); + + iprec->Assign(0, std::move(id_val)); + iprec->Assign(1, val_mgr->Count(ip_len)); + iprec->Assign(2, val_mgr->Count(proto)); + iprec->Assign(3, val_mgr->Count(frag_offset)); + iprec->Assign(4, val_mgr->Bool(bad_hdr_len)); + iprec->Assign(5, val_mgr->Bool(bad_checksum)); + iprec->Assign(6, val_mgr->Bool(MF)); + iprec->Assign(7, val_mgr->Bool(DF)); + + return iprec; + } + +zeek::RecordValPtr ICMPAnalyzer::ExtractICMP6Context(int len, const u_char*& data) + { + int DF = 0, MF = 0, bad_hdr_len = 0; + TransportProto proto = TRANSPORT_UNKNOWN; + + IPAddr src_addr; + IPAddr dst_addr; + uint32_t ip_len, frag_offset = 0; + uint32_t src_port, dst_port; + + if ( len < (int)sizeof(struct ip6_hdr) ) + { + bad_hdr_len = 1; + ip_len = 0; + src_port = dst_port = 0; + } + else + { + const IP_Hdr ip_hdr_data((const struct ip6_hdr*) data, false, len); + const IP_Hdr* ip_hdr = &ip_hdr_data; + + ip_len = ip_hdr->TotalLen(); + src_addr = ip_hdr->SrcAddr(); + dst_addr = ip_hdr->DstAddr(); + frag_offset = ip_hdr->FragOffset(); + MF = ip_hdr->MF(); + DF = ip_hdr->DF(); + + if ( uint32_t(len) >= uint32_t(ip_hdr->HdrLen() + 4) ) + proto = GetContextProtocol(ip_hdr, &src_port, &dst_port); + else + { + // 4 above is the magic number meaning that both + // port numbers are included in the ICMP. + src_port = dst_port = 0; + bad_hdr_len = 1; + } + } + + static auto icmp_context = id::find_type("icmp_context"); + auto iprec = make_intrusive(icmp_context); + auto id_val = make_intrusive(id::conn_id); + + id_val->Assign(0, make_intrusive(src_addr)); + id_val->Assign(1, val_mgr->Port(src_port, proto)); + id_val->Assign(2, make_intrusive(dst_addr)); + id_val->Assign(3, val_mgr->Port(dst_port, proto)); + + iprec->Assign(0, std::move(id_val)); + iprec->Assign(1, val_mgr->Count(ip_len)); + iprec->Assign(2, val_mgr->Count(proto)); + iprec->Assign(3, val_mgr->Count(frag_offset)); + iprec->Assign(4, val_mgr->Bool(bad_hdr_len)); + // bad_checksum is always false since IPv6 layer doesn't have a checksum. + iprec->Assign(5, val_mgr->False()); + iprec->Assign(6, val_mgr->Bool(MF)); + iprec->Assign(7, val_mgr->Bool(DF)); + + return iprec; + } + +void ICMPAnalyzer::Echo(double t, const struct icmp* icmpp, int len, + int caplen, const u_char*& data, const IP_Hdr* ip_hdr, + ICMPTransportAnalyzer* analyzer) + { + // For handling all Echo related ICMP messages + EventHandlerPtr f = nullptr; + + if ( ip_hdr->NextProto() == IPPROTO_ICMPV6 ) + f = (icmpp->icmp_type == ICMP6_ECHO_REQUEST) + ? icmp_echo_request : icmp_echo_reply; + else + f = (icmpp->icmp_type == ICMP_ECHO) + ? icmp_echo_request : icmp_echo_reply; + + if ( ! f ) + return; + + int iid = ntohs(icmpp->icmp_hun.ih_idseq.icd_id); + int iseq = ntohs(icmpp->icmp_hun.ih_idseq.icd_seq); + + String* payload = new String(data, caplen, false); + + analyzer->EnqueueConnEvent(f, + analyzer->ConnVal(), + BuildInfo(icmpp, len, ip_hdr->NextProto() != IPPROTO_ICMP, ip_hdr), + val_mgr->Count(iid), + val_mgr->Count(iseq), + make_intrusive(payload) + ); + } + + +void ICMPAnalyzer::RouterAdvert(double t, const struct icmp* icmpp, int len, + int caplen, const u_char*& data, const IP_Hdr* ip_hdr, + ICMPTransportAnalyzer* analyzer) + { + EventHandlerPtr f = icmp_router_advertisement; + + if ( ! f ) + return; + + uint32_t reachable = 0, retrans = 0; + + if ( caplen >= (int)sizeof(reachable) ) + memcpy(&reachable, data, sizeof(reachable)); + + if ( caplen >= (int)sizeof(reachable) + (int)sizeof(retrans) ) + memcpy(&retrans, data + sizeof(reachable), sizeof(retrans)); + + int opt_offset = sizeof(reachable) + sizeof(retrans); + + analyzer->EnqueueConnEvent(f, + analyzer->ConnVal(), + BuildInfo(icmpp, len, 1, ip_hdr), + val_mgr->Count(icmpp->icmp_num_addrs), // Cur Hop Limit + val_mgr->Bool(icmpp->icmp_wpa & 0x80), // Managed + val_mgr->Bool(icmpp->icmp_wpa & 0x40), // Other + val_mgr->Bool(icmpp->icmp_wpa & 0x20), // Home Agent + val_mgr->Count((icmpp->icmp_wpa & 0x18)>>3), // Pref + val_mgr->Bool(icmpp->icmp_wpa & 0x04), // Proxy + val_mgr->Count(icmpp->icmp_wpa & 0x02), // Reserved + make_intrusive((double)ntohs(icmpp->icmp_lifetime), Seconds), + make_intrusive((double)ntohl(reachable), Milliseconds), + make_intrusive((double)ntohl(retrans), Milliseconds), + BuildNDOptionsVal(caplen - opt_offset, data + opt_offset, analyzer) + ); + } + + +void ICMPAnalyzer::NeighborAdvert(double t, const struct icmp* icmpp, int len, + int caplen, const u_char*& data, const IP_Hdr* ip_hdr, + ICMPTransportAnalyzer* analyzer) + { + EventHandlerPtr f = icmp_neighbor_advertisement; + + if ( ! f ) + return; + + IPAddr tgtaddr; + + if ( caplen >= (int)sizeof(in6_addr) ) + tgtaddr = IPAddr(*((const in6_addr*)data)); + + int opt_offset = sizeof(in6_addr); + + analyzer->EnqueueConnEvent(f, + analyzer->ConnVal(), + BuildInfo(icmpp, len, 1, ip_hdr), + val_mgr->Bool(icmpp->icmp_num_addrs & 0x80), // Router + val_mgr->Bool(icmpp->icmp_num_addrs & 0x40), // Solicited + val_mgr->Bool(icmpp->icmp_num_addrs & 0x20), // Override + make_intrusive(tgtaddr), + BuildNDOptionsVal(caplen - opt_offset, data + opt_offset, analyzer) + ); + } + + +void ICMPAnalyzer::NeighborSolicit(double t, const struct icmp* icmpp, int len, + int caplen, const u_char*& data, const IP_Hdr* ip_hdr, + ICMPTransportAnalyzer* analyzer) + { + EventHandlerPtr f = icmp_neighbor_solicitation; + + if ( ! f ) + return; + + IPAddr tgtaddr; + + if ( caplen >= (int)sizeof(in6_addr) ) + tgtaddr = IPAddr(*((const in6_addr*)data)); + + int opt_offset = sizeof(in6_addr); + + analyzer->EnqueueConnEvent(f, + analyzer->ConnVal(), + BuildInfo(icmpp, len, 1, ip_hdr), + make_intrusive(tgtaddr), + BuildNDOptionsVal(caplen - opt_offset, data + opt_offset, analyzer) + ); + } + + +void ICMPAnalyzer::Redirect(double t, const struct icmp* icmpp, int len, + int caplen, const u_char*& data, const IP_Hdr* ip_hdr, + ICMPTransportAnalyzer* analyzer) + { + EventHandlerPtr f = icmp_redirect; + + if ( ! f ) + return; + + IPAddr tgtaddr, dstaddr; + + if ( caplen >= (int)sizeof(in6_addr) ) + tgtaddr = IPAddr(*((const in6_addr*)data)); + + if ( caplen >= 2 * (int)sizeof(in6_addr) ) + dstaddr = IPAddr(*((const in6_addr*)(data + sizeof(in6_addr)))); + + int opt_offset = 2 * sizeof(in6_addr); + + analyzer->EnqueueConnEvent(f, + analyzer->ConnVal(), + BuildInfo(icmpp, len, 1, ip_hdr), + make_intrusive(tgtaddr), + make_intrusive(dstaddr), + BuildNDOptionsVal(caplen - opt_offset, data + opt_offset, analyzer) + ); + } + + +void ICMPAnalyzer::RouterSolicit(double t, const struct icmp* icmpp, int len, + int caplen, const u_char*& data, const IP_Hdr* ip_hdr, + ICMPTransportAnalyzer* analyzer) + { + EventHandlerPtr f = icmp_router_solicitation; + + if ( ! f ) + return; + + analyzer->EnqueueConnEvent(f, + analyzer->ConnVal(), + BuildInfo(icmpp, len, 1, ip_hdr), + BuildNDOptionsVal(caplen, data, analyzer) + ); + } + + +void ICMPAnalyzer::Context4(double t, const struct icmp* icmpp, int len, + int caplen, const u_char*& data, const IP_Hdr* ip_hdr, + ICMPTransportAnalyzer* analyzer) + { + EventHandlerPtr f = nullptr; + + switch ( icmpp->icmp_type ) + { + case ICMP_UNREACH: + f = icmp_unreachable; + break; + + case ICMP_TIMXCEED: + f = icmp_time_exceeded; + break; + } + + if ( f ) + analyzer->EnqueueConnEvent(f, + analyzer->ConnVal(), + BuildInfo(icmpp, len, 0, ip_hdr), + val_mgr->Count(icmpp->icmp_code), + ExtractICMP4Context(caplen, data) + ); + } + + +void ICMPAnalyzer::Context6(double t, const struct icmp* icmpp, int len, + int caplen, const u_char*& data, const IP_Hdr* ip_hdr, + ICMPTransportAnalyzer* analyzer) + { + EventHandlerPtr f = nullptr; + + switch ( icmpp->icmp_type ) + { + case ICMP6_DST_UNREACH: + f = icmp_unreachable; + break; + + case ICMP6_PARAM_PROB: + f = icmp_parameter_problem; + break; + + case ICMP6_TIME_EXCEEDED: + f = icmp_time_exceeded; + break; + + case ICMP6_PACKET_TOO_BIG: + f = icmp_packet_too_big; + break; + + default: + f = icmp_error_message; + break; + } + + if ( f ) + analyzer->EnqueueConnEvent(f, + analyzer->ConnVal(), + BuildInfo(icmpp, len, 1, ip_hdr), + val_mgr->Count(icmpp->icmp_code), + ExtractICMP6Context(caplen, data) + ); + } + +zeek::VectorValPtr ICMPAnalyzer::BuildNDOptionsVal(int caplen, const u_char* data, + ICMPTransportAnalyzer* analyzer) + { + static auto icmp6_nd_option_type = id::find_type("icmp6_nd_option"); + static auto icmp6_nd_prefix_info_type = id::find_type("icmp6_nd_prefix_info"); + + auto vv = make_intrusive( + id::find_type("icmp6_nd_options")); + + while ( caplen > 0 ) + { + // Must have at least type & length to continue parsing options. + if ( caplen < 2 ) + { + analyzer->Weird("truncated_ICMPv6_ND_options"); + break; + } + + uint8_t type = *((const uint8_t*)data); + uint16_t length = *((const uint8_t*)(data + 1)); + + if ( length == 0 ) + { + analyzer->Weird("zero_length_ICMPv6_ND_option"); + break; + } + + auto rv = make_intrusive(icmp6_nd_option_type); + rv->Assign(0, val_mgr->Count(type)); + rv->Assign(1, val_mgr->Count(length)); + + // Adjust length to be in units of bytes, exclude type/length fields. + length = length * 8 - 2; + + data += 2; + caplen -= 2; + + bool set_payload_field = false; + + // Only parse out known options that are there in full. + switch ( type ) { + case 1: + case 2: + // Source/Target Link-layer Address option + { + if ( caplen >= length ) + { + String* link_addr = new String(data, length, false); + rv->Assign(2, make_intrusive(link_addr)); + } + else + set_payload_field = true; + + break; + } + + case 3: + // Prefix Information option + { + if ( caplen >= 30 ) + { + auto info = make_intrusive(icmp6_nd_prefix_info_type); + uint8_t prefix_len = *((const uint8_t*)(data)); + bool L_flag = (*((const uint8_t*)(data + 1)) & 0x80) != 0; + bool A_flag = (*((const uint8_t*)(data + 1)) & 0x40) != 0; + uint32_t valid_life = *((const uint32_t*)(data + 2)); + uint32_t prefer_life = *((const uint32_t*)(data + 6)); + in6_addr prefix = *((const in6_addr*)(data + 14)); + info->Assign(0, val_mgr->Count(prefix_len)); + info->Assign(1, val_mgr->Bool(L_flag)); + info->Assign(2, val_mgr->Bool(A_flag)); + info->Assign(3, make_intrusive((double)ntohl(valid_life), Seconds)); + info->Assign(4, make_intrusive((double)ntohl(prefer_life), Seconds)); + info->Assign(5, make_intrusive(IPAddr(prefix))); + rv->Assign(3, std::move(info)); + } + + else + set_payload_field = true; + break; + } + + case 4: + // Redirected Header option + { + if ( caplen >= length ) + { + const u_char* hdr = data + 6; + rv->Assign(4, ExtractICMP6Context(length - 6, hdr)); + } + + else + set_payload_field = true; + + break; + } + + case 5: + // MTU option + { + if ( caplen >= 6 ) + rv->Assign(5, val_mgr->Count(ntohl(*((const uint32_t*)(data + 2))))); + else + set_payload_field = true; + + break; + } + + default: + { + set_payload_field = true; + break; + } + } + + if ( set_payload_field ) + { + String* payload = new String(data, std::min((int)length, caplen), false); + rv->Assign(6, make_intrusive(payload)); + } + + data += length; + caplen -= length; + + vv->Assign(vv->Size(), std::move(rv)); + } + + return vv; + } int ICMPAnalyzer::ICMP4_counterpart(int icmp_type, int icmp_code, bool& is_one_way) { @@ -113,3 +859,84 @@ int ICMPAnalyzer::ICMP6_counterpart(int icmp_type, int icmp_code, bool& is_one_w default: is_one_way = true; return icmp_code; } } + +void ICMPAnalyzer::CreateTransportAnalyzer(Connection* conn, IPBasedTransportAnalyzer*& root, + analyzer::pia::PIA*& pia, bool& check_port) + { + root = new ICMPTransportAnalyzer(conn); + root->SetParent(this); + conn->SetInactivityTimeout(zeek::detail::icmp_inactivity_timeout); + + pia = nullptr; + check_port = false; + } + +void ICMPTransportAnalyzer::AddExtraAnalyzers(Connection* conn) + { + static analyzer::Tag analyzer_connsize = analyzer_mgr->GetComponentTag("CONNSIZE"); + + if ( analyzer_mgr->IsEnabled(analyzer_connsize) ) + // Add ConnSize analyzer. Needs to see packets, not stream. + AddChildAnalyzer(new analyzer::conn_size::ConnSize_Analyzer(conn)); + } + +void ICMPTransportAnalyzer::UpdateConnVal(zeek::RecordVal* conn_val) + { + const auto& orig_endp = conn_val->GetField("orig"); + const auto& resp_endp = conn_val->GetField("resp"); + + UpdateEndpointVal(orig_endp, true); + UpdateEndpointVal(resp_endp, false); + + analyzer::Analyzer::UpdateConnVal(conn_val); + } + +void ICMPTransportAnalyzer::UpdateEndpointVal(const ValPtr& endp_arg, bool is_orig) + { + Conn()->EnableStatusUpdateTimer(); + + int size = is_orig ? request_len : reply_len; + auto endp = endp_arg->AsRecordVal(); + + if ( size < 0 ) + { + endp->Assign(0, val_mgr->Count(0)); + endp->Assign(1, val_mgr->Count(int(ICMP_INACTIVE))); + } + else + { + endp->Assign(0, val_mgr->Count(size)); + endp->Assign(1, val_mgr->Count(int(ICMP_ACTIVE))); + } + } + +void ICMPTransportAnalyzer::UpdateLength(bool is_orig, int len) + { + int& len_stat = is_orig ? request_len : reply_len; + if ( len_stat < 0 ) + len_stat = len; + else + len_stat += len; + } + +void ICMPTransportAnalyzer::InitEndpointMatcher(const IP_Hdr* ip_hdr, int len, bool is_orig) + { + if ( zeek::detail::rule_matcher ) + { + if ( ! matcher_state.MatcherInitialized(is_orig) ) + matcher_state.InitEndpointMatcher(this, ip_hdr, len, is_orig, nullptr); + } + } + +void ICMPTransportAnalyzer::MatchEndpoint(const u_char* data, int len, bool is_orig) + { + if ( zeek::detail::rule_matcher ) + matcher_state.Match(zeek::detail::Rule::PAYLOAD, data, len, is_orig, + false, false, true); + } + +void ICMPTransportAnalyzer::Done() + { + TransportLayerAnalyzer::Done(); + matcher_state.FinishEndpointMatcher(); + } diff --git a/src/packet_analysis/protocol/icmp/ICMP.h b/src/packet_analysis/protocol/icmp/ICMP.h index c0acc8d6f0..9b1835311a 100644 --- a/src/packet_analysis/protocol/icmp/ICMP.h +++ b/src/packet_analysis/protocol/icmp/ICMP.h @@ -5,8 +5,19 @@ #include "zeek/packet_analysis/Analyzer.h" #include "zeek/packet_analysis/Component.h" #include "zeek/packet_analysis/protocol/ip/IPBasedAnalyzer.h" +#include "zeek/analyzer/Analyzer.h" +#include "zeek/RuleMatcher.h" -namespace zeek::packet_analysis::ICMP { +namespace zeek { + +class VectorVal; +using VectorValPtr = IntrusivePtr; +class RecordVal; +using RecordValPtr = IntrusivePtr; + +namespace packet_analysis::ICMP { + +class ICMPTransportAnalyzer; class ICMPAnalyzer final : public IP::IPBasedAnalyzer { public: @@ -30,11 +41,95 @@ protected: private: + void NextICMP4(double t, const struct icmp* icmpp, int len, int caplen, + const u_char*& data, const IP_Hdr* ip_hdr, + ICMPTransportAnalyzer* analyzer); + + void NextICMP6(double t, const struct icmp* icmpp, int len, int caplen, + const u_char*& data, const IP_Hdr* ip_hdr, + ICMPTransportAnalyzer* analyzer); + + void ICMP_Sent(const struct icmp* icmpp, int len, int caplen, int icmpv6, + const u_char* data, const IP_Hdr* ip_hdr, + ICMPTransportAnalyzer* analyzer); + + void Echo(double t, const struct icmp* icmpp, int len, + int caplen, const u_char*& data, const IP_Hdr* ip_hdr, + ICMPTransportAnalyzer* analyzer); + void Redirect(double t, const struct icmp* icmpp, int len, + int caplen, const u_char*& data, const IP_Hdr* ip_hdr, + ICMPTransportAnalyzer* analyzer); + void RouterAdvert(double t, const struct icmp* icmpp, int len, + int caplen, const u_char*& data, const IP_Hdr* ip_hdr, + ICMPTransportAnalyzer* analyzer); + void NeighborAdvert(double t, const struct icmp* icmpp, int len, + int caplen, const u_char*& data, const IP_Hdr* ip_hdr, + ICMPTransportAnalyzer* analyzer); + void NeighborSolicit(double t, const struct icmp* icmpp, int len, + int caplen, const u_char*& data, const IP_Hdr* ip_hdr, + ICMPTransportAnalyzer* analyzer); + void RouterSolicit(double t, const struct icmp* icmpp, int len, + int caplen, const u_char*& data, const IP_Hdr* ip_hdr, + ICMPTransportAnalyzer* analyzer); + + RecordValPtr BuildInfo(const struct icmp* icmpp, int len, + bool icmpv6, const IP_Hdr* ip_hdr); + + RecordValPtr ExtractICMP4Context(int len, const u_char*& data); + + void Context4(double t, const struct icmp* icmpp, int len, int caplen, + const u_char*& data, const IP_Hdr* ip_hdr, + ICMPTransportAnalyzer* analyzer); + + TransportProto GetContextProtocol(const IP_Hdr* ip_hdr, uint32_t* src_port, + uint32_t* dst_port); + + RecordValPtr ExtractICMP6Context(int len, const u_char*& data); + + void Context6(double t, const struct icmp* icmpp, int len, int caplen, + const u_char*& data, const IP_Hdr* ip_hdr, + ICMPTransportAnalyzer* analyzer); + + // RFC 4861 Neighbor Discover message options + VectorValPtr BuildNDOptionsVal(int caplen, const u_char* data, + ICMPTransportAnalyzer* analyzer); + + void UpdateEndpointVal(const ValPtr& endp, bool is_orig); + // Returns the counterpart type to the given type (e.g., the counterpart // to ICMP_ECHOREPLY is ICMP_ECHO). int ICMP4_counterpart(int icmp_type, int icmp_code, bool& is_one_way); int ICMP6_counterpart(int icmp_type, int icmp_code, bool& is_one_way); + }; +class ICMPTransportAnalyzer final : public IP::IPBasedTransportAnalyzer { + +public: + + ICMPTransportAnalyzer(Connection* conn) : + IP::IPBasedTransportAnalyzer("ICMP", conn) { } + + static zeek::analyzer::Analyzer* Instantiate(Connection* conn) + { + return new ICMPTransportAnalyzer(conn); + } + + void AddExtraAnalyzers(Connection* conn) override; + void UpdateConnVal(RecordVal* conn_val) override; + void UpdateEndpointVal(const ValPtr& endp, bool is_orig); + + void UpdateLength(bool is_orig, int len); + void Done() override; + + void InitEndpointMatcher(const IP_Hdr* ip_hdr, int len, bool is_orig); + void MatchEndpoint(const u_char* data, int len, bool is_orig); + +private: + + detail::RuleMatcherState matcher_state; + int request_len = -1; + int reply_len = -1; }; -} +} // namespace packet_analysis::ICMP +} // namespace zeek diff --git a/src/packet_analysis/protocol/icmp/Plugin.cc b/src/packet_analysis/protocol/icmp/Plugin.cc index b16205e78a..944ca38d02 100644 --- a/src/packet_analysis/protocol/icmp/Plugin.cc +++ b/src/packet_analysis/protocol/icmp/Plugin.cc @@ -12,9 +12,11 @@ public: { AddComponent(new zeek::packet_analysis::Component("ICMP", zeek::packet_analysis::ICMP::ICMPAnalyzer::Instantiate)); + AddComponent(new zeek::analyzer::Component("ICMP", + zeek::packet_analysis::ICMP::ICMPTransportAnalyzer::Instantiate)); zeek::plugin::Configuration config; - config.name = "Zeek::ICMP_PKT"; + config.name = "Zeek::ICMP"; config.description = "Packet analyzer for ICMP"; return config; } diff --git a/src/analyzer/protocol/icmp/events.bif b/src/packet_analysis/protocol/icmp/events.bif similarity index 100% rename from src/analyzer/protocol/icmp/events.bif rename to src/packet_analysis/protocol/icmp/events.bif diff --git a/src/session/Manager.cc b/src/session/Manager.cc index b7e0cddf71..df027c82cf 100644 --- a/src/session/Manager.cc +++ b/src/session/Manager.cc @@ -21,9 +21,6 @@ #include "zeek/session/Session.h" #include "zeek/TunnelEncapsulation.h" #include "zeek/telemetry/Manager.h" - -#include "zeek/analyzer/protocol/icmp/ICMP.h" -#include "zeek/analyzer/protocol/udp/UDP.h" #include "zeek/analyzer/Manager.h" #include "zeek/iosource/IOSource.h" diff --git a/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log b/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log index 729d4b154e..adcb56753d 100644 --- a/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log +++ b/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log @@ -131,7 +131,6 @@ scripts/base/init-frameworks-and-bifs.zeek build/scripts/base/bif/plugins/Zeek_GTPv1.events.bif.zeek build/scripts/base/bif/plugins/Zeek_HTTP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_HTTP.functions.bif.zeek - build/scripts/base/bif/plugins/Zeek_ICMP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_Ident.events.bif.zeek build/scripts/base/bif/plugins/Zeek_IMAP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_IRC.events.bif.zeek @@ -211,6 +210,7 @@ scripts/base/init-frameworks-and-bifs.zeek build/scripts/base/bif/plugins/Zeek_VXLAN.events.bif.zeek build/scripts/base/bif/plugins/Zeek_XMPP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_ARP.events.bif.zeek + build/scripts/base/bif/plugins/Zeek_ICMP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_FileEntropy.events.bif.zeek build/scripts/base/bif/plugins/Zeek_FileExtract.events.bif.zeek build/scripts/base/bif/plugins/Zeek_FileExtract.functions.bif.zeek diff --git a/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log b/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log index 6b5b777293..0ad2f4a685 100644 --- a/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log +++ b/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log @@ -131,7 +131,6 @@ scripts/base/init-frameworks-and-bifs.zeek build/scripts/base/bif/plugins/Zeek_GTPv1.events.bif.zeek build/scripts/base/bif/plugins/Zeek_HTTP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_HTTP.functions.bif.zeek - build/scripts/base/bif/plugins/Zeek_ICMP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_Ident.events.bif.zeek build/scripts/base/bif/plugins/Zeek_IMAP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_IRC.events.bif.zeek @@ -211,6 +210,7 @@ scripts/base/init-frameworks-and-bifs.zeek build/scripts/base/bif/plugins/Zeek_VXLAN.events.bif.zeek build/scripts/base/bif/plugins/Zeek_XMPP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_ARP.events.bif.zeek + build/scripts/base/bif/plugins/Zeek_ICMP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_FileEntropy.events.bif.zeek build/scripts/base/bif/plugins/Zeek_FileExtract.events.bif.zeek build/scripts/base/bif/plugins/Zeek_FileExtract.functions.bif.zeek From c21af39a30e4311b8c8c19e03a312a423dd20177 Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Wed, 14 Apr 2021 10:44:51 -0700 Subject: [PATCH 05/10] Add new UDP packet analyzer, remove old one --- src/analyzer/Manager.cc | 8 - src/analyzer/protocol/CMakeLists.txt | 1 - src/analyzer/protocol/dhcp/DHCP.h | 2 - src/analyzer/protocol/dnp3/DNP3.h | 1 - src/analyzer/protocol/netbios/NetbiosSSN.h | 1 - src/analyzer/protocol/ntp/NTP.h | 2 - src/analyzer/protocol/radius/RADIUS.h | 2 - src/analyzer/protocol/rdp/RDPEUDP.h | 2 - src/analyzer/protocol/sip/SIP.h | 2 - src/analyzer/protocol/ssl/DTLS.h | 2 - src/analyzer/protocol/syslog/Syslog.h | 1 - src/analyzer/protocol/udp/CMakeLists.txt | 9 - src/analyzer/protocol/udp/Plugin.cc | 22 -- src/analyzer/protocol/udp/UDP.cc | 275 ---------------- src/analyzer/protocol/udp/UDP.h | 57 ---- .../protocol/udp/CMakeLists.txt | 3 +- src/packet_analysis/protocol/udp/Plugin.cc | 4 +- src/packet_analysis/protocol/udp/UDP.cc | 294 ++++++++++++++++++ src/packet_analysis/protocol/udp/UDP.h | 57 +++- .../protocol/udp/events.bif | 0 .../canonified_loaded_scripts.log | 2 +- .../canonified_loaded_scripts.log | 2 +- 22 files changed, 357 insertions(+), 392 deletions(-) delete mode 100644 src/analyzer/protocol/udp/CMakeLists.txt delete mode 100644 src/analyzer/protocol/udp/Plugin.cc delete mode 100644 src/analyzer/protocol/udp/UDP.cc delete mode 100644 src/analyzer/protocol/udp/UDP.h rename src/{analyzer => packet_analysis}/protocol/udp/events.bif (100%) diff --git a/src/analyzer/Manager.cc b/src/analyzer/Manager.cc index a111d36c4f..1d86a7bed8 100644 --- a/src/analyzer/Manager.cc +++ b/src/analyzer/Manager.cc @@ -11,7 +11,6 @@ #include "zeek/analyzer/protocol/pia/PIA.h" #include "zeek/analyzer/protocol/stepping-stone/SteppingStone.h" #include "zeek/analyzer/protocol/tcp/TCP.h" -#include "zeek/analyzer/protocol/udp/UDP.h" #include "zeek/packet_analysis/protocol/ip/IPBasedAnalyzer.h" #include "zeek/plugin/Manager.h" @@ -375,13 +374,6 @@ bool Manager::BuildInitialAnalyzerTree(Connection* conn) DBG_ANALYZER(conn, "activated TCP analyzer"); break; - case TRANSPORT_UDP: - root = new analyzer::udp::UDP_Analyzer(conn); - pia = new analyzer::pia::PIA_UDP(conn); - check_port = true; - DBG_ANALYZER(conn, "activated UDP analyzer"); - break; - default: reporter->InternalWarning("unknown protocol can't build analyzer tree"); return false; diff --git a/src/analyzer/protocol/CMakeLists.txt b/src/analyzer/protocol/CMakeLists.txt index 1a6e241ece..0d628ded1d 100644 --- a/src/analyzer/protocol/CMakeLists.txt +++ b/src/analyzer/protocol/CMakeLists.txt @@ -44,7 +44,6 @@ add_subdirectory(stepping-stone) add_subdirectory(syslog) add_subdirectory(tcp) add_subdirectory(teredo) -add_subdirectory(udp) add_subdirectory(vxlan) add_subdirectory(xmpp) add_subdirectory(zip) diff --git a/src/analyzer/protocol/dhcp/DHCP.h b/src/analyzer/protocol/dhcp/DHCP.h index dbe13d4df7..8ae911ae44 100644 --- a/src/analyzer/protocol/dhcp/DHCP.h +++ b/src/analyzer/protocol/dhcp/DHCP.h @@ -1,7 +1,5 @@ #pragma once -#include "zeek/analyzer/protocol/udp/UDP.h" - #include "analyzer/protocol/dhcp/dhcp_pac.h" namespace zeek::analyzer::dhcp { diff --git a/src/analyzer/protocol/dnp3/DNP3.h b/src/analyzer/protocol/dnp3/DNP3.h index 3fe5d1e9f0..6540be39d6 100644 --- a/src/analyzer/protocol/dnp3/DNP3.h +++ b/src/analyzer/protocol/dnp3/DNP3.h @@ -1,7 +1,6 @@ #pragma once #include "zeek/analyzer/protocol/tcp/TCP.h" -#include "zeek/analyzer/protocol/udp/UDP.h" #include "analyzer/protocol/dnp3/dnp3_pac.h" diff --git a/src/analyzer/protocol/netbios/NetbiosSSN.h b/src/analyzer/protocol/netbios/NetbiosSSN.h index f73631f435..a3a97728e2 100644 --- a/src/analyzer/protocol/netbios/NetbiosSSN.h +++ b/src/analyzer/protocol/netbios/NetbiosSSN.h @@ -2,7 +2,6 @@ #pragma once -#include "zeek/analyzer/protocol/udp/UDP.h" #include "zeek/analyzer/protocol/tcp/TCP.h" namespace zeek::analyzer::netbios_ssn { diff --git a/src/analyzer/protocol/ntp/NTP.h b/src/analyzer/protocol/ntp/NTP.h index 0e829f9288..9d2fcb07b1 100644 --- a/src/analyzer/protocol/ntp/NTP.h +++ b/src/analyzer/protocol/ntp/NTP.h @@ -1,7 +1,5 @@ #pragma once -#include "zeek/analyzer/protocol/udp/UDP.h" - #include "zeek/analyzer/protocol/ntp/events.bif.h" #include "zeek/analyzer/protocol/ntp/types.bif.h" #include "zeek/analyzer/protocol/ntp/ntp_pac.h" diff --git a/src/analyzer/protocol/radius/RADIUS.h b/src/analyzer/protocol/radius/RADIUS.h index 1e1648c84f..7ab093e073 100644 --- a/src/analyzer/protocol/radius/RADIUS.h +++ b/src/analyzer/protocol/radius/RADIUS.h @@ -1,7 +1,5 @@ #pragma once -#include "zeek/analyzer/protocol/udp/UDP.h" - #include "zeek/analyzer/protocol/radius/events.bif.h" #include "zeek/analyzer/protocol/radius/radius_pac.h" diff --git a/src/analyzer/protocol/rdp/RDPEUDP.h b/src/analyzer/protocol/rdp/RDPEUDP.h index 13c5651633..01f2326adb 100644 --- a/src/analyzer/protocol/rdp/RDPEUDP.h +++ b/src/analyzer/protocol/rdp/RDPEUDP.h @@ -1,7 +1,5 @@ #pragma once -#include "zeek/analyzer/protocol/udp/UDP.h" - #include "zeek/analyzer/protocol/rdp/events.bif.h" #include "zeek/analyzer/protocol/rdp/rdpeudp_pac.h" diff --git a/src/analyzer/protocol/sip/SIP.h b/src/analyzer/protocol/sip/SIP.h index 18ec010a8b..15fe1371f3 100644 --- a/src/analyzer/protocol/sip/SIP.h +++ b/src/analyzer/protocol/sip/SIP.h @@ -1,7 +1,5 @@ #pragma once -#include "zeek/analyzer/protocol/udp/UDP.h" - #include "zeek/analyzer/protocol/sip/events.bif.h" #include "zeek/analyzer/protocol/sip/sip_pac.h" diff --git a/src/analyzer/protocol/ssl/DTLS.h b/src/analyzer/protocol/ssl/DTLS.h index 1554c1bb6e..121af08cde 100644 --- a/src/analyzer/protocol/ssl/DTLS.h +++ b/src/analyzer/protocol/ssl/DTLS.h @@ -1,7 +1,5 @@ #pragma once -#include "zeek/analyzer/protocol/udp/UDP.h" - #include "zeek/analyzer/protocol/ssl/events.bif.h" namespace binpac { namespace DTLS { class SSL_Conn; } } diff --git a/src/analyzer/protocol/syslog/Syslog.h b/src/analyzer/protocol/syslog/Syslog.h index d1aea12d05..941492a96c 100644 --- a/src/analyzer/protocol/syslog/Syslog.h +++ b/src/analyzer/protocol/syslog/Syslog.h @@ -1,6 +1,5 @@ #pragma once -#include "zeek/analyzer/protocol/udp/UDP.h" #include "zeek/analyzer/protocol/tcp/TCP.h" #include "analyzer/protocol/syslog/syslog_pac.h" diff --git a/src/analyzer/protocol/udp/CMakeLists.txt b/src/analyzer/protocol/udp/CMakeLists.txt deleted file mode 100644 index 47140a9df2..0000000000 --- a/src/analyzer/protocol/udp/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ - -include(ZeekPlugin) - -include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) - -zeek_plugin_begin(Zeek UDP) -zeek_plugin_cc(UDP.cc Plugin.cc) -zeek_plugin_bif(events.bif) -zeek_plugin_end() diff --git a/src/analyzer/protocol/udp/Plugin.cc b/src/analyzer/protocol/udp/Plugin.cc deleted file mode 100644 index fc08de2eb3..0000000000 --- a/src/analyzer/protocol/udp/Plugin.cc +++ /dev/null @@ -1,22 +0,0 @@ -// See the file in the main distribution directory for copyright. - -#include "zeek/plugin/Plugin.h" -#include "zeek/analyzer/Component.h" -#include "zeek/analyzer/protocol/udp/UDP.h" - -namespace zeek::plugin::detail::Zeek_UDP { - -class Plugin : public zeek::plugin::Plugin { -public: - zeek::plugin::Configuration Configure() override - { - AddComponent(new zeek::analyzer::Component("UDP", zeek::analyzer::udp::UDP_Analyzer::Instantiate)); - - zeek::plugin::Configuration config; - config.name = "Zeek::UDP"; - config.description = "UDP Analyzer"; - return config; - } -} plugin; - -} // namespace zeek::plugin::detail::Zeek_UDP diff --git a/src/analyzer/protocol/udp/UDP.cc b/src/analyzer/protocol/udp/UDP.cc deleted file mode 100644 index e29f14d251..0000000000 --- a/src/analyzer/protocol/udp/UDP.cc +++ /dev/null @@ -1,275 +0,0 @@ -// See the file "COPYING" in the main distribution directory for copyright. - -#include "zeek/zeek-config.h" -#include "zeek/analyzer/protocol/udp/UDP.h" - -#include - -#include "zeek/RunState.h" -#include "zeek/NetVar.h" -#include "zeek/analyzer/Manager.h" -#include "zeek/Reporter.h" -#include "zeek/Conn.h" - -#include "zeek/analyzer/protocol/udp/events.bif.h" - -namespace zeek::analyzer::udp { - -UDP_Analyzer::UDP_Analyzer(Connection* conn) - : analyzer::TransportLayerAnalyzer("UDP", conn) - { - conn->EnableStatusUpdateTimer(); - conn->SetInactivityTimeout(zeek::detail::udp_inactivity_timeout); - request_len = reply_len = -1; // -1 means "haven't seen any activity" - - req_chk_cnt = rep_chk_cnt = 0; - req_chk_thresh = rep_chk_thresh = 1; - } - -UDP_Analyzer::~UDP_Analyzer() - { - // XXX: need to implement this! - // delete src_pkt_writer; - } - -void UDP_Analyzer::Init() - { - } - -void UDP_Analyzer::Done() - { - Analyzer::Done(); - } - -void UDP_Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig, - uint64_t seq, const IP_Hdr* ip, int caplen) - { - assert(ip); - - Analyzer::DeliverPacket(len, data, is_orig, seq, ip, caplen); - - const struct udphdr* up = (const struct udphdr*) data; - - // Increment data before checksum check so that data will - // point to UDP payload even if checksum fails. Particularly, - // it allows event packet_contents to get to the data. - data += sizeof(struct udphdr); - - // We need the min() here because Ethernet frame padding can lead to - // caplen > len. - if ( packet_contents ) - PacketContents(data, std::min(len, caplen) - sizeof(struct udphdr)); - - int chksum = up->uh_sum; - - 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; - - if ( validate_checksum && - len > ((int)sizeof(struct udphdr) + vxlan_len + eth_len) && - (data[0] & 0x08) == 0x08 ) - { - auto& vxlan_ports = analyzer_mgr->GetVxlanPorts(); - - if ( std::find(vxlan_ports.begin(), vxlan_ports.end(), - ntohs(up->uh_dport)) != vxlan_ports.end() ) - { - // Looks like VXLAN on a well-known port, so the checksum should be - // transmitted as zero, and we should accept that. If not - // transmitted as zero, then validating the checksum is optional. - if ( chksum == 0 ) - validate_checksum = false; - else - validate_checksum = BifConst::Tunnel::validate_vxlan_checksums; - } - } - - if ( validate_checksum ) - { - bool bad = false; - - if ( ip->IP4_Hdr() ) - { - if ( chksum && ! ValidateChecksum(ip, up, len) ) - bad = true; - } - - /* checksum is not optional for IPv6 */ - else if ( ! ValidateChecksum(ip, up, len) ) - bad = true; - - if ( bad ) - { - Weird("bad_UDP_checksum"); - - if ( is_orig ) - { - uint32_t t = req_chk_thresh; - if ( Conn()->ScaledHistoryEntry('C', req_chk_cnt, - req_chk_thresh) ) - ChecksumEvent(is_orig, t); - } - else - { - uint32_t t = rep_chk_thresh; - if ( Conn()->ScaledHistoryEntry('c', rep_chk_cnt, - rep_chk_thresh) ) - ChecksumEvent(is_orig, t); - } - - return; - } - } - - int ulen = ntohs(up->uh_ulen); - if ( ulen != len ) - Weird("UDP_datagram_length_mismatch", util::fmt("%d != %d", ulen, len)); - - len -= sizeof(struct udphdr); - ulen -= sizeof(struct udphdr); - caplen -= sizeof(struct udphdr); - - Conn()->SetLastTime(run_state::current_timestamp); - - if ( udp_contents ) - { - static auto udp_content_ports = id::find_val("udp_content_ports"); - static auto udp_content_delivery_ports_orig = id::find_val("udp_content_delivery_ports_orig"); - static auto udp_content_delivery_ports_resp = id::find_val("udp_content_delivery_ports_resp"); - bool do_udp_contents = false; - const auto& sport_val = val_mgr->Port(ntohs(up->uh_sport), TRANSPORT_UDP); - const auto& dport_val = val_mgr->Port(ntohs(up->uh_dport), TRANSPORT_UDP); - - if ( udp_content_ports->FindOrDefault(dport_val) || - udp_content_ports->FindOrDefault(sport_val) ) - do_udp_contents = true; - else - { - uint16_t p = zeek::detail::udp_content_delivery_ports_use_resp ? Conn()->RespPort() - : up->uh_dport; - const auto& port_val = zeek::val_mgr->Port(ntohs(p), TRANSPORT_UDP); - - if ( is_orig ) - { - auto result = udp_content_delivery_ports_orig->FindOrDefault(port_val); - - if ( zeek::detail::udp_content_deliver_all_orig || (result && result->AsBool()) ) - do_udp_contents = true; - } - else - { - auto result = udp_content_delivery_ports_resp->FindOrDefault(port_val); - - if ( zeek::detail::udp_content_deliver_all_resp || (result && result->AsBool()) ) - do_udp_contents = true; - } - } - - if ( do_udp_contents ) - EnqueueConnEvent(udp_contents, - ConnVal(), - val_mgr->Bool(is_orig), - make_intrusive(len, (const char*) data)); - } - - if ( is_orig ) - { - Conn()->CheckHistory(HIST_ORIG_DATA_PKT, 'D'); - - if ( request_len < 0 ) - request_len = ulen; - else - { - request_len += ulen; -#ifdef DEBUG - if ( request_len < 0 ) - reporter->Warning("wrapping around for UDP request length"); -#endif - } - - Event(udp_request); - } - - else - { - Conn()->CheckHistory(HIST_RESP_DATA_PKT, 'd'); - - if ( reply_len < 0 ) - reply_len = ulen; - else - { - reply_len += ulen; -#ifdef DEBUG - if ( reply_len < 0 ) - reporter->Warning("wrapping around for UDP reply length"); -#endif - } - - Event(udp_reply); - } - - if ( caplen >= len ) - ForwardPacket(len, data, is_orig, seq, ip, caplen); - } - -void UDP_Analyzer::UpdateConnVal(RecordVal* conn_val) - { - auto orig_endp = conn_val->GetFieldAs("orig"); - auto resp_endp = conn_val->GetFieldAs("resp"); - - UpdateEndpointVal(orig_endp, true); - UpdateEndpointVal(resp_endp, false); - - // Call children's UpdateConnVal - Analyzer::UpdateConnVal(conn_val); - } - -void UDP_Analyzer::UpdateEndpointVal(RecordVal* endp, bool is_orig) - { - bro_int_t size = is_orig ? request_len : reply_len; - if ( size < 0 ) - { - endp->Assign(0, 0); - endp->Assign(1, UDP_INACTIVE); - } - - else - { - endp->Assign(0, static_cast(size)); - endp->Assign(1, UDP_ACTIVE); - } - } - -bool UDP_Analyzer::IsReuse(double /* t */, const u_char* /* pkt */) - { - return false; - } - -unsigned int UDP_Analyzer::MemoryAllocation() const - { - // A rather low lower bound.... - return Analyzer::MemoryAllocation() + padded_sizeof(*this) - 24; - } - -void UDP_Analyzer::ChecksumEvent(bool is_orig, uint32_t threshold) - { - Conn()->HistoryThresholdEvent(udp_multiple_checksum_errors, - is_orig, threshold); - } - -bool UDP_Analyzer::ValidateChecksum(const IP_Hdr* ip, const udphdr* up, int len) - { - auto sum = detail::ip_in_cksum(ip->IP4_Hdr(), ip->SrcAddr(), ip->DstAddr(), - IPPROTO_UDP, - reinterpret_cast(up), len); - - return sum == 0xffff; - } - -} // namespace zeek::analyzer::udp diff --git a/src/analyzer/protocol/udp/UDP.h b/src/analyzer/protocol/udp/UDP.h deleted file mode 100644 index 1a1ef94e62..0000000000 --- a/src/analyzer/protocol/udp/UDP.h +++ /dev/null @@ -1,57 +0,0 @@ -// See the file "COPYING" in the main distribution directory for copyright. - -#pragma once - -// This will include netinet/udp.h for us, plus set up some defines that make it work on all -// of the CI platforms. -#include "zeek/net_util.h" - -#include "zeek/analyzer/Analyzer.h" - -namespace zeek::analyzer::udp { - -enum UDP_EndpointState { - UDP_INACTIVE, // no packet seen - UDP_ACTIVE, // packets seen -}; - -class UDP_Analyzer final : public analyzer::TransportLayerAnalyzer { -public: - explicit UDP_Analyzer(Connection* conn); - ~UDP_Analyzer() override; - - void Init() override; - void UpdateConnVal(RecordVal *conn_val) override; - - static analyzer::Analyzer* Instantiate(Connection* conn) - { return new UDP_Analyzer(conn); } - -protected: - void Done() override; - void DeliverPacket(int len, const u_char* data, bool orig, - uint64_t seq, const IP_Hdr* ip, int caplen) override; - bool IsReuse(double t, const u_char* pkt) override; - unsigned int MemoryAllocation() const override; - - void ChecksumEvent(bool is_orig, uint32_t threshold); - - // Returns true if the checksum is valid, false if not - static bool ValidateChecksum(const IP_Hdr* ip, const struct udphdr* up, - int len); - - bro_int_t request_len, reply_len; - -private: - void UpdateEndpointVal(RecordVal* endp, bool is_orig); - -#define HIST_ORIG_DATA_PKT 0x1 -#define HIST_RESP_DATA_PKT 0x2 -#define HIST_ORIG_CORRUPT_PKT 0x4 -#define HIST_RESP_CORRUPT_PKT 0x8 - - // For tracking checksum history. - uint32_t req_chk_cnt, req_chk_thresh; - uint32_t rep_chk_cnt, rep_chk_thresh; -}; - -} // namespace zeek::analyzer::udp diff --git a/src/packet_analysis/protocol/udp/CMakeLists.txt b/src/packet_analysis/protocol/udp/CMakeLists.txt index 5e205c57f1..47140a9df2 100644 --- a/src/packet_analysis/protocol/udp/CMakeLists.txt +++ b/src/packet_analysis/protocol/udp/CMakeLists.txt @@ -3,6 +3,7 @@ include(ZeekPlugin) include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) -zeek_plugin_begin(PacketAnalyzer UDP_PKT) +zeek_plugin_begin(Zeek UDP) zeek_plugin_cc(UDP.cc Plugin.cc) +zeek_plugin_bif(events.bif) zeek_plugin_end() diff --git a/src/packet_analysis/protocol/udp/Plugin.cc b/src/packet_analysis/protocol/udp/Plugin.cc index 4bbe7d737d..7c77be6fc5 100644 --- a/src/packet_analysis/protocol/udp/Plugin.cc +++ b/src/packet_analysis/protocol/udp/Plugin.cc @@ -12,9 +12,11 @@ public: { AddComponent(new zeek::packet_analysis::Component("UDP", zeek::packet_analysis::UDP::UDPAnalyzer::Instantiate)); + AddComponent(new zeek::analyzer::Component("UDP", + zeek::packet_analysis::UDP::UDPTransportAnalyzer::Instantiate)); zeek::plugin::Configuration config; - config.name = "Zeek::UDP_PKT"; + config.name = "Zeek::UDP"; config.description = "Packet analyzer for UDP"; return config; } diff --git a/src/packet_analysis/protocol/udp/UDP.cc b/src/packet_analysis/protocol/udp/UDP.cc index f17e1280dd..d7d5cbe6e5 100644 --- a/src/packet_analysis/protocol/udp/UDP.cc +++ b/src/packet_analysis/protocol/udp/UDP.cc @@ -2,12 +2,31 @@ #include "zeek/packet_analysis/protocol/udp/UDP.h" #include "zeek/RunState.h" +#include "zeek/Conn.h" +#include "zeek/session/Manager.h" +#include "zeek/analyzer/Manager.h" +#include "zeek/analyzer/protocol/pia/PIA.h" +#include "zeek/analyzer/protocol/conn-size/ConnSize.h" + +#include "zeek/packet_analysis/protocol/udp/events.bif.h" using namespace zeek::packet_analysis::UDP; using namespace zeek::packet_analysis::IP; +constexpr uint32_t HIST_ORIG_DATA_PKT = 0x1; +constexpr uint32_t HIST_RESP_DATA_PKT = 0x2; +constexpr uint32_t HIST_ORIG_CORRUPT_PKT = 0x4; +constexpr uint32_t HIST_RESP_CORRUPT_PKT = 0x8; + +enum UDP_EndpointState { + UDP_INACTIVE, // no packet seen + UDP_ACTIVE, // packets seen +}; + UDPAnalyzer::UDPAnalyzer() : IPBasedAnalyzer("UDP", TRANSPORT_UDP, UDP_PORT_MASK, false) { + // TODO: remove once the other plugins are done + new_plugin = true; } UDPAnalyzer::~UDPAnalyzer() @@ -33,9 +52,34 @@ bool UDPAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) return true; } + void UDPAnalyzer::CreateTransportAnalyzer(Connection* conn, IPBasedTransportAnalyzer*& root, analyzer::pia::PIA*& pia, bool& check_port) { + root = new UDPTransportAnalyzer(conn); + root->SetParent(this); + + conn->EnableStatusUpdateTimer(); + conn->SetInactivityTimeout(zeek::detail::udp_inactivity_timeout); + + pia = new analyzer::pia::PIA_UDP(conn); + check_port = true; + } + +void UDPAnalyzer::Initialize() + { + IPBasedAnalyzer::Initialize(); + + const auto& id = detail::global_scope()->Find("Tunnel::vxlan_ports"); + + if ( ! (id && id->GetVal()) ) + reporter->FatalError("Tunnel::vxlan_ports not defined"); + + auto table_val = id->GetVal()->AsTableVal(); + auto port_list = table_val->ToPureListVal(); + + for ( auto i = 0; i < port_list->Length(); ++i ) + vxlan_ports.emplace_back(port_list->Idx(i)->AsPortVal()->Port()); } bool UDPAnalyzer::WantConnection(uint16_t src_port, uint16_t dst_port, @@ -44,3 +88,253 @@ bool UDPAnalyzer::WantConnection(uint16_t src_port, uint16_t dst_port, flip_roles = IsLikelyServerPort(src_port) && ! IsLikelyServerPort(dst_port); return true; } + +void UDPAnalyzer::ContinueProcessing(Connection* c, double t, bool is_orig, int remaining, Packet* pkt) + { + conn = c; + + auto* ta = static_cast(conn->GetRootAnalyzer()); + + const u_char* data = pkt->ip_hdr->Payload(); + int len = pkt->ip_hdr->PayloadLen(); + + const struct udphdr* up = (const struct udphdr*) data; + const std::unique_ptr& ip = pkt->ip_hdr; + + ta->DeliverPacket(len, data, is_orig, -1, ip.get(), remaining); + + // Increment data before checksum check so that data will + // point to UDP payload even if checksum fails. Particularly, + // it allows event packet_contents to get to the data. + data += sizeof(struct udphdr); + + // We need the min() here because Ethernet frame padding can lead to + // remaining > len. + if ( packet_contents ) + ta->PacketContents(data, std::min(len, remaining) - sizeof(struct udphdr)); + + int chksum = up->uh_sum; + + auto validate_checksum = + ! run_state::current_pkt->l3_checksummed && + ! zeek::detail::ignore_checksums && + ! zeek::id::find_val("ignore_checksums_nets")->Contains(ip->IPHeaderSrcAddr()) && + remaining >=len; + + constexpr auto vxlan_len = 8; + constexpr auto eth_len = 14; + + if ( validate_checksum && + len > ((int)sizeof(struct udphdr) + vxlan_len + eth_len) && + (data[0] & 0x08) == 0x08 ) + { + if ( std::find(vxlan_ports.begin(), vxlan_ports.end(), + ntohs(up->uh_dport)) != vxlan_ports.end() ) + { + // Looks like VXLAN on a well-known port, so the checksum should be + // transmitted as zero, and we should accept that. If not + // transmitted as zero, then validating the checksum is optional. + if ( chksum == 0 ) + validate_checksum = false; + else + validate_checksum = BifConst::Tunnel::validate_vxlan_checksums; + } + } + + if ( validate_checksum ) + { + bool bad = false; + + if ( ip->IP4_Hdr() ) + { + if ( chksum && ! ValidateChecksum(ip.get(), up, len) ) + bad = true; + } + + /* checksum is not optional for IPv6 */ + else if ( ! ValidateChecksum(ip.get(), up, len) ) + bad = true; + + if ( bad ) + { + ta->Weird("bad_UDP_checksum"); + + if ( is_orig ) + { + uint32_t t = ta->req_chk_thresh; + + if ( conn->ScaledHistoryEntry('C', + ta->req_chk_cnt, + ta->req_chk_thresh) ) + ChecksumEvent(is_orig, t); + } + else + { + uint32_t t = ta->rep_chk_thresh; + + if ( conn->ScaledHistoryEntry('c', + ta->rep_chk_cnt, + ta->rep_chk_thresh) ) + ChecksumEvent(is_orig, t); + } + + return; + } + } + + int ulen = ntohs(up->uh_ulen); + if ( ulen != len ) + ta->Weird("UDP_datagram_length_mismatch", util::fmt("%d != %d", ulen, len)); + + len -= sizeof(struct udphdr); + ulen -= sizeof(struct udphdr); + remaining -= sizeof(struct udphdr); + + conn->SetLastTime(run_state::current_timestamp); + + if ( udp_contents ) + { + static auto udp_content_ports = id::find_val("udp_content_ports"); + static auto udp_content_delivery_ports_orig = id::find_val("udp_content_delivery_ports_orig"); + static auto udp_content_delivery_ports_resp = id::find_val("udp_content_delivery_ports_resp"); + bool do_udp_contents = false; + const auto& sport_val = val_mgr->Port(ntohs(up->uh_sport), TRANSPORT_UDP); + const auto& dport_val = val_mgr->Port(ntohs(up->uh_dport), TRANSPORT_UDP); + + if ( udp_content_ports->FindOrDefault(dport_val) || + udp_content_ports->FindOrDefault(sport_val) ) + do_udp_contents = true; + else + { + uint16_t p = zeek::detail::udp_content_delivery_ports_use_resp ? conn->RespPort() + : up->uh_dport; + const auto& port_val = zeek::val_mgr->Port(ntohs(p), TRANSPORT_UDP); + + if ( is_orig ) + { + auto result = udp_content_delivery_ports_orig->FindOrDefault(port_val); + + if ( zeek::detail::udp_content_deliver_all_orig || (result && result->AsBool()) ) + do_udp_contents = true; + } + else + { + auto result = udp_content_delivery_ports_resp->FindOrDefault(port_val); + + if ( zeek::detail::udp_content_deliver_all_resp || (result && result->AsBool()) ) + do_udp_contents = true; + } + } + + if ( do_udp_contents ) + ta->EnqueueConnEvent(udp_contents, + ta->ConnVal(), + val_mgr->Bool(is_orig), + make_intrusive(len, (const char*) data)); + } + + if ( is_orig ) + { + conn->CheckHistory(HIST_ORIG_DATA_PKT, 'D'); + ta->UpdateLength(is_orig, ulen); + ta->Event(udp_request); + } + else + { + conn->CheckHistory(HIST_RESP_DATA_PKT, 'd'); + ta->UpdateLength(is_orig, ulen); + ta->Event(udp_reply); + } + + // Send the packet back into the packet analysis framework. + ForwardPacket(len, data, pkt); + + // Also try sending it into session analysis. + if ( remaining >= len ) + ta->ForwardPacket(len, data, is_orig, -1, ip.get(), remaining); + + conn = nullptr; + } + +bool UDPAnalyzer::ValidateChecksum(const IP_Hdr* ip, const udphdr* up, int len) + { + auto sum = detail::ip_in_cksum(ip->IP4_Hdr(), ip->SrcAddr(), ip->DstAddr(), + IPPROTO_UDP, + reinterpret_cast(up), len); + + return sum == 0xffff; + } + +void UDPAnalyzer::ChecksumEvent(bool is_orig, uint32_t threshold) + { + conn->HistoryThresholdEvent(udp_multiple_checksum_errors, is_orig, threshold); + } + +void UDPTransportAnalyzer::AddExtraAnalyzers(Connection* conn) + { + static analyzer::Tag analyzer_connsize = analyzer_mgr->GetComponentTag("CONNSIZE"); + + if ( analyzer_mgr->IsEnabled(analyzer_connsize) ) + // Add ConnSize analyzer. Needs to see packets, not stream. + AddChildAnalyzer(new analyzer::conn_size::ConnSize_Analyzer(conn)); + } + +void UDPTransportAnalyzer::UpdateConnVal(RecordVal* conn_val) + { + auto orig_endp = conn_val->GetField("orig"); + auto resp_endp = conn_val->GetField("resp"); + + UpdateEndpointVal(orig_endp, true); + UpdateEndpointVal(resp_endp, false); + + // Call children's UpdateConnVal + Analyzer::UpdateConnVal(conn_val); + } + +void UDPTransportAnalyzer::UpdateEndpointVal(const ValPtr& endp_arg, bool is_orig) + { + bro_int_t size = is_orig ? request_len : reply_len; + auto endp = endp_arg->AsRecordVal(); + + if ( size < 0 ) + { + endp->Assign(0, val_mgr->Count(0)); + endp->Assign(1, UDP_INACTIVE); + } + + else + { + endp->Assign(0, static_cast(size)); + endp->Assign(1, UDP_ACTIVE); + } + } + +void UDPTransportAnalyzer::UpdateLength(bool is_orig, int len) + { + if ( is_orig ) + { + if ( request_len < 0 ) + request_len = len; + else + { + request_len += len; +#ifdef DEBUG + if ( request_len < 0 ) + reporter->Warning("wrapping around for UDP request length"); +#endif + } + } + else + { + if ( reply_len < 0 ) + reply_len = len; + else + { + reply_len += len; +#ifdef DEBUG + if ( reply_len < 0 ) + reporter->Warning("wrapping around for UDP reply length"); +#endif + } + } + } diff --git a/src/packet_analysis/protocol/udp/UDP.h b/src/packet_analysis/protocol/udp/UDP.h index 2730ece1dd..b8c3a2ae18 100644 --- a/src/packet_analysis/protocol/udp/UDP.h +++ b/src/packet_analysis/protocol/udp/UDP.h @@ -8,7 +8,7 @@ namespace zeek::packet_analysis::UDP { -class UDPAnalyzer : public IP::IPBasedAnalyzer { +class UDPAnalyzer final : public IP::IPBasedAnalyzer { public: UDPAnalyzer(); ~UDPAnalyzer() override; @@ -23,6 +23,13 @@ public: void CreateTransportAnalyzer(Connection* conn, IP::IPBasedTransportAnalyzer*& root, analyzer::pia::PIA*& pia, bool& check_port) override; + /** + * Initialize the analyzer. This method is called after the configuration + * was read. Derived classes can override this method to implement custom + * initialization. + */ + void Initialize() override; + protected: /** @@ -39,6 +46,54 @@ protected: */ bool WantConnection(uint16_t src_port, uint16_t dst_port, const u_char* data, bool& flip_roles) const override; + + void ContinueProcessing(Connection* c, double t, bool is_orig, int remaining, + Packet* pkt) override; + +private: + + // Returns true if the checksum is valid, false if not + static bool ValidateChecksum(const IP_Hdr* ip, const struct udphdr* up, + int len); + + void ChecksumEvent(bool is_orig, uint32_t threshold); + + Connection* conn; + + std::vector vxlan_ports; +}; + +class UDPTransportAnalyzer final : public IP::IPBasedTransportAnalyzer { + +public: + + UDPTransportAnalyzer(Connection* conn) : + IP::IPBasedTransportAnalyzer("UDP", conn) { } + + static zeek::analyzer::Analyzer* Instantiate(Connection* conn) + { + return new UDPTransportAnalyzer(conn); + } + + void AddExtraAnalyzers(Connection* conn) override; + void UpdateConnVal(RecordVal* conn_val) override; + + void UpdateLength(bool is_orig, int len); + + // For tracking checksum history. These are connection-specific so they + // need to be stored in the transport analyzer created for each + // connection. + uint32_t req_chk_cnt = 0; + uint32_t req_chk_thresh = 1; + uint32_t rep_chk_cnt = 0; + uint32_t rep_chk_thresh = 1; + +private: + + void UpdateEndpointVal(const ValPtr& endp_arg, bool is_orig); + + bro_int_t request_len = -1; + bro_int_t reply_len = -1; }; } diff --git a/src/analyzer/protocol/udp/events.bif b/src/packet_analysis/protocol/udp/events.bif similarity index 100% rename from src/analyzer/protocol/udp/events.bif rename to src/packet_analysis/protocol/udp/events.bif diff --git a/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log b/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log index adcb56753d..95228fc7ea 100644 --- a/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log +++ b/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log @@ -206,10 +206,10 @@ scripts/base/init-frameworks-and-bifs.zeek build/scripts/base/bif/plugins/Zeek_TCP.types.bif.zeek build/scripts/base/bif/plugins/Zeek_TCP.functions.bif.zeek build/scripts/base/bif/plugins/Zeek_Teredo.events.bif.zeek - build/scripts/base/bif/plugins/Zeek_UDP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_VXLAN.events.bif.zeek build/scripts/base/bif/plugins/Zeek_XMPP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_ARP.events.bif.zeek + build/scripts/base/bif/plugins/Zeek_UDP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_ICMP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_FileEntropy.events.bif.zeek build/scripts/base/bif/plugins/Zeek_FileExtract.events.bif.zeek diff --git a/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log b/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log index 0ad2f4a685..4ebc37ef20 100644 --- a/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log +++ b/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log @@ -206,10 +206,10 @@ scripts/base/init-frameworks-and-bifs.zeek build/scripts/base/bif/plugins/Zeek_TCP.types.bif.zeek build/scripts/base/bif/plugins/Zeek_TCP.functions.bif.zeek build/scripts/base/bif/plugins/Zeek_Teredo.events.bif.zeek - build/scripts/base/bif/plugins/Zeek_UDP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_VXLAN.events.bif.zeek build/scripts/base/bif/plugins/Zeek_XMPP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_ARP.events.bif.zeek + build/scripts/base/bif/plugins/Zeek_UDP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_ICMP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_FileEntropy.events.bif.zeek build/scripts/base/bif/plugins/Zeek_FileExtract.events.bif.zeek From 7dc803f7bb9522c5468442e81aedcd069387ce89 Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Thu, 6 May 2021 13:48:45 -0700 Subject: [PATCH 06/10] Rework the packet flow through the IP-based analyzers --- src/packet_analysis/protocol/icmp/ICMP.cc | 20 +++---- src/packet_analysis/protocol/icmp/ICMP.h | 10 +++- .../protocol/ip/IPBasedAnalyzer.cc | 26 +++++---- .../protocol/ip/IPBasedAnalyzer.h | 55 +++++++++---------- src/packet_analysis/protocol/tcp/TCP.cc | 18 +++--- src/packet_analysis/protocol/tcp/TCP.h | 8 ++- src/packet_analysis/protocol/udp/UDP.cc | 41 +++++++------- src/packet_analysis/protocol/udp/UDP.h | 14 +++-- 8 files changed, 102 insertions(+), 90 deletions(-) diff --git a/src/packet_analysis/protocol/icmp/ICMP.cc b/src/packet_analysis/protocol/icmp/ICMP.cc index 30b929e621..1c3da3e1e1 100644 --- a/src/packet_analysis/protocol/icmp/ICMP.cc +++ b/src/packet_analysis/protocol/icmp/ICMP.cc @@ -35,33 +35,31 @@ ICMPAnalyzer::~ICMPAnalyzer() { } -bool ICMPAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) +bool ICMPAnalyzer::BuildConnTuple(size_t len, const uint8_t* data, Packet* packet, + ConnTuple& tuple) { if ( ! CheckHeaderTrunc(ICMP_MINLEN, len, packet) ) return false; - ConnTuple id; - id.src_addr = packet->ip_hdr->SrcAddr(); - id.dst_addr = packet->ip_hdr->DstAddr(); - id.proto = TRANSPORT_ICMP; + tuple.src_addr = packet->ip_hdr->SrcAddr(); + tuple.dst_addr = packet->ip_hdr->DstAddr(); + tuple.proto = TRANSPORT_ICMP; const struct icmp* icmpp = (const struct icmp *) data; - id.src_port = htons(icmpp->icmp_type); + tuple.src_port = htons(icmpp->icmp_type); if ( packet->proto == IPPROTO_ICMP ) - id.dst_port = htons(ICMP4_counterpart(icmpp->icmp_type, icmpp->icmp_code, id.is_one_way)); + tuple.dst_port = htons(ICMP4_counterpart(icmpp->icmp_type, icmpp->icmp_code, tuple.is_one_way)); else if ( packet->proto == IPPROTO_ICMPV6 ) - id.dst_port = htons(ICMP6_counterpart(icmpp->icmp_type, icmpp->icmp_code, id.is_one_way)); + tuple.dst_port = htons(ICMP6_counterpart(icmpp->icmp_type, icmpp->icmp_code, tuple.is_one_way)); else reporter->InternalError("Reached ICMP packet analyzer with unknown packet protocol %x", packet->proto); - ProcessConnection(id, packet, len); - return true; } -void ICMPAnalyzer::ContinueProcessing(Connection* c, double t, bool is_orig, int remaining, Packet* pkt) +void ICMPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int remaining, Packet* pkt) { auto* ta = static_cast(c->GetRootAnalyzer()); diff --git a/src/packet_analysis/protocol/icmp/ICMP.h b/src/packet_analysis/protocol/icmp/ICMP.h index 9b1835311a..291321f42b 100644 --- a/src/packet_analysis/protocol/icmp/ICMP.h +++ b/src/packet_analysis/protocol/icmp/ICMP.h @@ -24,8 +24,6 @@ public: ICMPAnalyzer(); ~ICMPAnalyzer() override; - bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override; - static zeek::packet_analysis::AnalyzerPtr Instantiate() { return std::make_shared(); @@ -36,7 +34,13 @@ public: protected: - void ContinueProcessing(Connection* c, double t, bool is_orig, int remaining, + /** + * Parse the header from the packet into a ConnTuple object. + */ + bool BuildConnTuple(size_t len, const uint8_t* data, Packet* packet, + ConnTuple& tuple) override; + + void DeliverPacket(Connection* c, double t, bool is_orig, int remaining, Packet* pkt) override; private: diff --git a/src/packet_analysis/protocol/ip/IPBasedAnalyzer.cc b/src/packet_analysis/protocol/ip/IPBasedAnalyzer.cc index 877c9b17e0..7af3ffda34 100644 --- a/src/packet_analysis/protocol/ip/IPBasedAnalyzer.cc +++ b/src/packet_analysis/protocol/ip/IPBasedAnalyzer.cc @@ -22,16 +22,20 @@ IPBasedAnalyzer::~IPBasedAnalyzer() { } -void IPBasedAnalyzer::ProcessConnection(const ConnTuple& conn_id, Packet* pkt, size_t remaining) +bool IPBasedAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* pkt) { + ConnTuple tuple; + if ( ! BuildConnTuple(len, data, pkt, tuple) ) + return false; + const std::unique_ptr& ip_hdr = pkt->ip_hdr; - detail::ConnKey key(conn_id); + detail::ConnKey key(tuple); Connection* conn = session_mgr->FindConnection(key); if ( ! conn ) { - conn = NewConn(&conn_id, key, pkt); + conn = NewConn(&tuple, key, pkt); if ( conn ) session_mgr->Insert(conn, false); } @@ -42,7 +46,7 @@ void IPBasedAnalyzer::ProcessConnection(const ConnTuple& conn_id, Packet* pkt, s conn->Event(connection_reused, nullptr); session_mgr->Remove(conn); - conn = NewConn(&conn_id, key, pkt); + conn = NewConn(&tuple, key, pkt); if ( conn ) session_mgr->Insert(conn, false); } @@ -53,10 +57,10 @@ void IPBasedAnalyzer::ProcessConnection(const ConnTuple& conn_id, Packet* pkt, s } if ( ! conn ) - return; + return false; - bool is_orig = (conn_id.src_addr == conn->OrigAddr()) && - (conn_id.src_port == conn->OrigPort()); + bool is_orig = (tuple.src_addr == conn->OrigAddr()) && + (tuple.src_port == conn->OrigPort()); conn->CheckFlowLabel(is_orig, ip_hdr->FlowLabel()); @@ -85,9 +89,9 @@ void IPBasedAnalyzer::ProcessConnection(const ConnTuple& conn_id, Packet* pkt, s // TODO: Does this actually mean anything? if ( conn->Skipping() ) - return; + return true; - ContinueProcessing(conn, run_state::processing_start_time, is_orig, remaining, pkt); + DeliverPacket(conn, run_state::processing_start_time, is_orig, len, pkt); run_state::current_timestamp = 0; run_state::current_pkt = nullptr; @@ -114,7 +118,7 @@ void IPBasedAnalyzer::ProcessConnection(const ConnTuple& conn_id, Packet* pkt, s const u_char* data = pkt->ip_hdr->Payload(); conn->NextPacket(run_state::processing_start_time, is_orig, ip_hdr.get(), ip_hdr->PayloadLen(), - remaining, data, record_packet, record_content, pkt); + len, data, record_packet, record_content, pkt); // If the packet is reassembled, disable packet dumping because the // pointer math to dump the data wouldn't work. @@ -130,6 +134,8 @@ void IPBasedAnalyzer::ProcessConnection(const ConnTuple& conn_id, Packet* pkt, s pkt->dump_size = data - pkt->data; } } + + return true; } bool IPBasedAnalyzer::CheckHeaderTrunc(size_t min_hdr_len, size_t remaining, Packet* packet) diff --git a/src/packet_analysis/protocol/ip/IPBasedAnalyzer.h b/src/packet_analysis/protocol/ip/IPBasedAnalyzer.h index 129a098720..751860cb76 100644 --- a/src/packet_analysis/protocol/ip/IPBasedAnalyzer.h +++ b/src/packet_analysis/protocol/ip/IPBasedAnalyzer.h @@ -22,6 +22,8 @@ class IPBasedAnalyzer : public Analyzer { public: ~IPBasedAnalyzer() override; + bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override; + /** * Returns true if the analyzer determines that in fact a new * connection has started without the connection statement having @@ -56,26 +58,24 @@ protected: bool report_unknown_protocols); /** - * Entry point for child classes to call to do the actual heavy lifting for - * processing a packet and extracting a connection out of it. - * - * @param conn_id The connection ID generated by the child class. - * @param pkt The packet being processed. - * @param remaining The number of bytes remaining to be processed in the packet. + * Parse the header from the packet into a ConnTuple object. */ - void ProcessConnection(const ConnTuple& conn_id, Packet* pkt, size_t remaining); + virtual bool BuildConnTuple(size_t len, const uint8_t* data, Packet* packet, + ConnTuple& tuple) = 0; /** - * Verifies that there is enough data in the packet to process the header - * length requested. + * Continues process of packet after the connection has been inserted into the + * session manager. This should be implemented by all child classes. * - * @param min_hdr_len The minimum data in bytes that needs to exist. - * @param remaining The remaining number of bytes in the packet reported by - * previous analyzer. - * @param packet The packet being processed. This will be used to pull out the - * number of bytes the IP header says we have remaining. + * @param conn The connection currently being processed. + * @param t The timestamp for the current packet. + * @param is_orig Flag denoting whether this packet is from the originator of + * the connection. + * @param remaining The remaining about of data in the packet. + * @param pkt The packet being processed. */ - bool CheckHeaderTrunc(size_t min_hdr_len, size_t remaining, Packet* packet); + virtual void DeliverPacket(Connection* conn, double t, bool is_orig, int remaining, + Packet* pkt) {} /** * Upon seeing the first packet of a connection, checks whether we want @@ -96,6 +96,18 @@ protected: return true; } + /** + * Verifies that there is enough data in the packet to process the header + * length requested. + * + * @param min_hdr_len The minimum data in bytes that needs to exist. + * @param remaining The remaining number of bytes in the packet reported by + * previous analyzer. + * @param packet The packet being processed. This will be used to pull out the + * number of bytes the IP header says we have remaining. + */ + bool CheckHeaderTrunc(size_t min_hdr_len, size_t remaining, Packet* packet); + /** * Returns true if the port corresponds to an application for which there * is a Zeek analyzer (even if it might not be used by the present policy @@ -105,19 +117,6 @@ protected: */ bool IsLikelyServerPort(uint32_t port) const; - /** - * Continues process of packet after the connection has been inserted into the - * session manager. This should be implemented by all child classes. - * - * @param conn The connection currently being processed. - * @param t The timestamp for the current packet. - * @param is_orig Flag denoting whether this packet is from the originator of - * the connection. - * @param remaining The remaining about of data in the packet. - * @param pkt The packet being processed. - */ - virtual void ContinueProcessing(Connection* conn, double t, bool is_orig, int remaining, - Packet* pkt) {} // TODO: temporary, until all of the plugins are implemented bool new_plugin = false; diff --git a/src/packet_analysis/protocol/tcp/TCP.cc b/src/packet_analysis/protocol/tcp/TCP.cc index 0abf645357..ff88b7f455 100644 --- a/src/packet_analysis/protocol/tcp/TCP.cc +++ b/src/packet_analysis/protocol/tcp/TCP.cc @@ -14,25 +14,23 @@ TCPAnalyzer::~TCPAnalyzer() { } -bool TCPAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) +bool TCPAnalyzer::BuildConnTuple(size_t len, const uint8_t* data, Packet* packet, + ConnTuple& tuple) { uint32_t min_hdr_len = sizeof(struct tcphdr); if ( ! CheckHeaderTrunc(min_hdr_len, len, packet) ) return false; - ConnTuple id; - id.src_addr = packet->ip_hdr->SrcAddr(); - id.dst_addr = packet->ip_hdr->DstAddr(); + tuple.src_addr = packet->ip_hdr->SrcAddr(); + tuple.dst_addr = packet->ip_hdr->DstAddr(); data = packet->ip_hdr->Payload(); const struct tcphdr* tp = (const struct tcphdr *) data; - id.src_port = tp->th_sport; - id.dst_port = tp->th_dport; - id.is_one_way = false; - id.proto = TRANSPORT_TCP; - - ProcessConnection(id, packet, len); + tuple.src_port = tp->th_sport; + tuple.dst_port = tp->th_dport; + tuple.is_one_way = false; + tuple.proto = TRANSPORT_TCP; return true; } diff --git a/src/packet_analysis/protocol/tcp/TCP.h b/src/packet_analysis/protocol/tcp/TCP.h index d836451945..06b9d46ee0 100644 --- a/src/packet_analysis/protocol/tcp/TCP.h +++ b/src/packet_analysis/protocol/tcp/TCP.h @@ -13,8 +13,6 @@ public: TCPAnalyzer(); ~TCPAnalyzer() override; - bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override; - static zeek::packet_analysis::AnalyzerPtr Instantiate() { return std::make_shared(); @@ -25,6 +23,12 @@ public: protected: + /** + * Parse the header from the packet into a ConnTuple object. + */ + bool BuildConnTuple(size_t len, const uint8_t* data, Packet* packet, + ConnTuple& tuple) override; + /** * Upon seeing the first packet of a connection, checks whether we want * to analyze it (e.g. we may not want to look at partial connections) diff --git a/src/packet_analysis/protocol/udp/UDP.cc b/src/packet_analysis/protocol/udp/UDP.cc index d7d5cbe6e5..2c633c9d49 100644 --- a/src/packet_analysis/protocol/udp/UDP.cc +++ b/src/packet_analysis/protocol/udp/UDP.cc @@ -33,26 +33,6 @@ UDPAnalyzer::~UDPAnalyzer() { } -bool UDPAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) - { - uint32_t min_hdr_len = sizeof(struct udphdr); - if ( ! CheckHeaderTrunc(min_hdr_len, len, packet) ) - return false; - - ConnTuple id; - id.src_addr = packet->ip_hdr->SrcAddr(); - id.dst_addr = packet->ip_hdr->DstAddr(); - const struct udphdr* up = (const struct udphdr *) packet->ip_hdr->Payload(); - id.src_port = up->uh_sport; - id.dst_port = up->uh_dport; - id.is_one_way = false; - id.proto = TRANSPORT_UDP; - - ProcessConnection(id, packet, len); - - return true; - } - void UDPAnalyzer::CreateTransportAnalyzer(Connection* conn, IPBasedTransportAnalyzer*& root, analyzer::pia::PIA*& pia, bool& check_port) { @@ -89,7 +69,26 @@ bool UDPAnalyzer::WantConnection(uint16_t src_port, uint16_t dst_port, return true; } -void UDPAnalyzer::ContinueProcessing(Connection* c, double t, bool is_orig, int remaining, Packet* pkt) +bool UDPAnalyzer::BuildConnTuple(size_t len, const uint8_t* data, Packet* packet, + ConnTuple& tuple) + { + uint32_t min_hdr_len = sizeof(struct udphdr); + if ( ! CheckHeaderTrunc(min_hdr_len, len, packet) ) + return false; + + tuple.src_addr = packet->ip_hdr->SrcAddr(); + tuple.dst_addr = packet->ip_hdr->DstAddr(); + + const struct udphdr* up = (const struct udphdr *) packet->ip_hdr->Payload(); + tuple.src_port = up->uh_sport; + tuple.dst_port = up->uh_dport; + tuple.is_one_way = false; + tuple.proto = TRANSPORT_UDP; + + return true; + } + +void UDPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int remaining, Packet* pkt) { conn = c; diff --git a/src/packet_analysis/protocol/udp/UDP.h b/src/packet_analysis/protocol/udp/UDP.h index b8c3a2ae18..3dd3c5323d 100644 --- a/src/packet_analysis/protocol/udp/UDP.h +++ b/src/packet_analysis/protocol/udp/UDP.h @@ -13,8 +13,6 @@ public: UDPAnalyzer(); ~UDPAnalyzer() override; - bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override; - static zeek::packet_analysis::AnalyzerPtr Instantiate() { return std::make_shared(); @@ -32,6 +30,15 @@ public: protected: + /** + * Parse the header from the packet into a ConnTuple object. + */ + bool BuildConnTuple(size_t len, const uint8_t* data, Packet* packet, + ConnTuple& tuple) override; + + void DeliverPacket(Connection* c, double t, bool is_orig, int remaining, + Packet* pkt) override; + /** * Upon seeing the first packet of a connection, checks whether we want * to analyze it (e.g. we may not want to look at partial connections) @@ -47,9 +54,6 @@ protected: bool WantConnection(uint16_t src_port, uint16_t dst_port, const u_char* data, bool& flip_roles) const override; - void ContinueProcessing(Connection* c, double t, bool is_orig, int remaining, - Packet* pkt) override; - private: // Returns true if the checksum is valid, false if not From c56fb3e8e422d2aa9b15326eb0b2a7a2a8af54e2 Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Fri, 7 May 2021 14:02:00 -0700 Subject: [PATCH 07/10] Move building session analyzer tree out of analyzer::Manager --- src/Dict.h | 1 + src/analyzer/Analyzer.h | 2 + src/analyzer/Manager.cc | 56 ----------------- src/analyzer/Manager.h | 15 +---- src/packet_analysis/protocol/icmp/ICMP.cc | 20 +++---- src/packet_analysis/protocol/icmp/ICMP.h | 3 +- .../protocol/ip/IPBasedAnalyzer.cc | 60 ++++++++++++++++++- .../protocol/ip/IPBasedAnalyzer.h | 19 ++++-- src/packet_analysis/protocol/tcp/TCP.cc | 5 -- src/packet_analysis/protocol/tcp/TCP.h | 3 - src/packet_analysis/protocol/udp/UDP.cc | 13 ++-- src/packet_analysis/protocol/udp/UDP.h | 6 +- 12 files changed, 98 insertions(+), 105 deletions(-) diff --git a/src/Dict.h b/src/Dict.h index c1a2b0cfa1..6204a0bcc8 100644 --- a/src/Dict.h +++ b/src/Dict.h @@ -177,6 +177,7 @@ public: bool operator!=( const DictIterator& that ) const { return !(*this == that); } private: + friend class Dictionary; DictIterator(const Dictionary* d, detail::DictEntry* begin, detail::DictEntry* end); diff --git a/src/analyzer/Analyzer.h b/src/analyzer/Analyzer.h index 5999063fe6..415086b13e 100644 --- a/src/analyzer/Analyzer.h +++ b/src/analyzer/Analyzer.h @@ -25,6 +25,7 @@ using FilePtr = zeek::IntrusivePtr; using RecordValPtr = zeek::IntrusivePtr; namespace detail { class Rule; } +namespace packet_analysis::IP { class IPBasedAnalyzer; } } // namespace zeek @@ -601,6 +602,7 @@ protected: friend class Manager; friend class zeek::Connection; friend class zeek::analyzer::tcp::TCP_ApplicationAnalyzer; + friend class zeek::packet_analysis::IP::IPBasedAnalyzer; /** * Return a string represantation of an analyzer, containing its name diff --git a/src/analyzer/Manager.cc b/src/analyzer/Manager.cc index 1d86a7bed8..91ae7c3bc7 100644 --- a/src/analyzer/Manager.cc +++ b/src/analyzer/Manager.cc @@ -353,11 +353,6 @@ Manager::tag_set* Manager::LookupPort(TransportProto proto, uint32_t port, bool return l; } -Manager::tag_set* Manager::LookupPort(PortVal* val, bool add_if_not_found) - { - return LookupPort(val->PortType(), val->Port(), add_if_not_found); - } - bool Manager::BuildInitialAnalyzerTree(Connection* conn) { analyzer::tcp::TCP_Analyzer* tcp = nullptr; @@ -484,57 +479,6 @@ bool Manager::BuildInitialAnalyzerTree(Connection* conn) return true; } -bool Manager::BuildSessionAnalyzerTree(Connection* conn, packet_analysis::IP::IPBasedAnalyzer* analyzer) - { - packet_analysis::IP::IPBasedTransportAnalyzer* root = nullptr; - analyzer::pia::PIA* pia = nullptr; - bool check_port = false; - - analyzer->CreateTransportAnalyzer(conn, root, pia, check_port); - - bool scheduled = ApplyScheduledAnalyzers(conn, false, root); - - // Hmm... Do we want *just* the expected analyzer, or all - // other potential analyzers as well? For now we only take - // the scheduled ones. - if ( ! scheduled ) - { // Let's see if it's a port we know. - if ( check_port && ! zeek::detail::dpd_ignore_ports ) - { - int resp_port = ntohs(conn->RespPort()); - tag_set* ports = LookupPort(conn->ConnTransport(), resp_port, false); - - if ( ports ) - { - for ( tag_set::const_iterator j = ports->begin(); j != ports->end(); ++j ) - { - Analyzer* analyzer = analyzer_mgr->InstantiateAnalyzer(*j, conn); - - if ( ! analyzer ) - continue; - - root->AddChildAnalyzer(analyzer, false); - DBG_ANALYZER_ARGS(conn, "activated %s analyzer due to port %d", - analyzer_mgr->GetComponentName(*j).c_str(), resp_port); - } - } - } - } - - root->AddExtraAnalyzers(conn); - - if ( pia ) - root->AddChildAnalyzer(pia->AsAnalyzer()); - - conn->SetRootAnalyzer(root, pia); - root->Init(); - root->InitChildren(); - - PLUGIN_HOOK_VOID(HOOK_SETUP_ANALYZER_TREE, HookSetupAnalyzerTree(conn)); - - return true; - } - void Manager::ExpireScheduledAnalyzers() { if ( ! run_state::network_time ) diff --git a/src/analyzer/Manager.h b/src/analyzer/Manager.h index 0899110663..ed9fa51ea4 100644 --- a/src/analyzer/Manager.h +++ b/src/analyzer/Manager.h @@ -252,18 +252,6 @@ public: */ bool BuildInitialAnalyzerTree(Connection* conn); - /** - * Builds the analyzer tree used by transport-layer analyzers in the - * packet analysis framework. - * - * @param conn The connection to add the initial set of analyzers to. - * @param analyzer The packet analyzer requesting the tree. - * @return False if the tree cannot be built; that's usually an - * internal error. - */ - bool BuildSessionAnalyzerTree(Connection* conn, - packet_analysis::IP::IPBasedAnalyzer* analyzer); - /** * Schedules a particular analyzer for an upcoming connection. Once * the connection is seen, BuildInitAnalyzerTree() will add the @@ -360,10 +348,11 @@ public: private: + friend class packet_analysis::IP::IPBasedAnalyzer; + using tag_set = std::set; using analyzer_map_by_port = std::map; - tag_set* LookupPort(PortVal* val, bool add_if_not_found); tag_set* LookupPort(TransportProto proto, uint32_t port, bool add_if_not_found); tag_set GetScheduled(const Connection* conn); diff --git a/src/packet_analysis/protocol/icmp/ICMP.cc b/src/packet_analysis/protocol/icmp/ICMP.cc index 1c3da3e1e1..ad04eef8f6 100644 --- a/src/packet_analysis/protocol/icmp/ICMP.cc +++ b/src/packet_analysis/protocol/icmp/ICMP.cc @@ -35,6 +35,15 @@ ICMPAnalyzer::~ICMPAnalyzer() { } +IPBasedTransportAnalyzer* ICMPAnalyzer::MakeTransportAnalyzer(Connection* conn) + { + auto* root = new ICMPTransportAnalyzer(conn); + root->SetParent(this); + conn->SetInactivityTimeout(zeek::detail::icmp_inactivity_timeout); + + return root; + } + bool ICMPAnalyzer::BuildConnTuple(size_t len, const uint8_t* data, Packet* packet, ConnTuple& tuple) { @@ -858,17 +867,6 @@ int ICMPAnalyzer::ICMP6_counterpart(int icmp_type, int icmp_code, bool& is_one_w } } -void ICMPAnalyzer::CreateTransportAnalyzer(Connection* conn, IPBasedTransportAnalyzer*& root, - analyzer::pia::PIA*& pia, bool& check_port) - { - root = new ICMPTransportAnalyzer(conn); - root->SetParent(this); - conn->SetInactivityTimeout(zeek::detail::icmp_inactivity_timeout); - - pia = nullptr; - check_port = false; - } - void ICMPTransportAnalyzer::AddExtraAnalyzers(Connection* conn) { static analyzer::Tag analyzer_connsize = analyzer_mgr->GetComponentTag("CONNSIZE"); diff --git a/src/packet_analysis/protocol/icmp/ICMP.h b/src/packet_analysis/protocol/icmp/ICMP.h index 291321f42b..d77b778168 100644 --- a/src/packet_analysis/protocol/icmp/ICMP.h +++ b/src/packet_analysis/protocol/icmp/ICMP.h @@ -29,8 +29,7 @@ public: return std::make_shared(); } - void CreateTransportAnalyzer(Connection* conn, IP::IPBasedTransportAnalyzer*& root, - analyzer::pia::PIA*& pia, bool& check_port) override; + packet_analysis::IP::IPBasedTransportAnalyzer* MakeTransportAnalyzer(Connection* conn) override; protected: diff --git a/src/packet_analysis/protocol/ip/IPBasedAnalyzer.cc b/src/packet_analysis/protocol/ip/IPBasedAnalyzer.cc index 7af3ffda34..53a23adcb0 100644 --- a/src/packet_analysis/protocol/ip/IPBasedAnalyzer.cc +++ b/src/packet_analysis/protocol/ip/IPBasedAnalyzer.cc @@ -7,6 +7,8 @@ #include "zeek/Val.h" #include "zeek/session/Manager.h" #include "zeek/analyzer/Manager.h" +#include "zeek/analyzer/protocol/pia/PIA.h" +#include "zeek/plugin/Manager.h" using namespace zeek; using namespace zeek::packet_analysis::IP; @@ -201,7 +203,7 @@ zeek::Connection* IPBasedAnalyzer::NewConn(const ConnTuple* id, const detail::Co return nullptr; } } - else if ( ! analyzer_mgr->BuildSessionAnalyzerTree(conn, this) ) + else if ( ! BuildSessionAnalyzerTree(conn) ) { conn->Done(); Unref(conn); @@ -213,3 +215,59 @@ zeek::Connection* IPBasedAnalyzer::NewConn(const ConnTuple* id, const detail::Co return conn; } + +bool IPBasedAnalyzer::BuildSessionAnalyzerTree(Connection* conn) + { + packet_analysis::IP::IPBasedTransportAnalyzer* root = MakeTransportAnalyzer(conn); + analyzer::pia::PIA* pia = MakePIA(conn); + + // TODO: temporary, can be replaced when the port lookup stuff is moved from analyzer_mgr + bool check_port = conn->ConnTransport() != TRANSPORT_ICMP; + + bool scheduled = analyzer_mgr->ApplyScheduledAnalyzers(conn, false, root); + + // Hmm... Do we want *just* the expected analyzer, or all + // other potential analyzers as well? For now we only take + // the scheduled ones. + if ( ! scheduled ) + { // Let's see if it's a port we know. + if ( check_port && ! zeek::detail::dpd_ignore_ports ) + { + // TODO: ideally this lookup would be local to the packet analyzer instead of + // calling out to the analyzer manager. This code can move once the TCP work + // is in progress so that it doesn't have to be done piecemeal. + // + int resp_port = ntohs(conn->RespPort()); + std::set* ports = analyzer_mgr->LookupPort(conn->ConnTransport(), resp_port, false); + + if ( ports ) + { + for ( const auto& port : *ports ) + { + analyzer::Analyzer* analyzer = analyzer_mgr->InstantiateAnalyzer(port, conn); + + if ( ! analyzer ) + continue; + + root->AddChildAnalyzer(analyzer, false); + DBG_ANALYZER_ARGS(conn, "activated %s analyzer due to port %d", + analyzer_mgr->GetComponentName(port).c_str(), resp_port); + } + } + } + } + + root->AddExtraAnalyzers(conn); + + if ( pia ) + root->AddChildAnalyzer(pia->AsAnalyzer()); + + conn->SetRootAnalyzer(root, pia); + root->Init(); + root->InitChildren(); + + PLUGIN_HOOK_VOID(HOOK_SETUP_ANALYZER_TREE, HookSetupAnalyzerTree(conn)); + + // TODO: temporary + return true; + } diff --git a/src/packet_analysis/protocol/ip/IPBasedAnalyzer.h b/src/packet_analysis/protocol/ip/IPBasedAnalyzer.h index 751860cb76..c507968564 100644 --- a/src/packet_analysis/protocol/ip/IPBasedAnalyzer.h +++ b/src/packet_analysis/protocol/ip/IPBasedAnalyzer.h @@ -33,12 +33,6 @@ public: */ virtual bool IsReuse(double t, const u_char* pkt) { return false; } - /** - * TODO: comment - */ - virtual void CreateTransportAnalyzer(Connection* conn, IPBasedTransportAnalyzer*& root, - analyzer::pia::PIA*& pia, bool& check_port) = 0; - protected: /** @@ -96,6 +90,17 @@ protected: return true; } + /** + * Returns a transport analyzer appropriate for this IP-based analyzer. This + * can also be used to do any extra initialization of connection timers, etc. + */ + virtual IPBasedTransportAnalyzer* MakeTransportAnalyzer(Connection* conn) { return nullptr; } + + /** + * Returns a PIA appropriate for this IP-based analyzer. + */ + virtual analyzer::pia::PIA* MakePIA(Connection* conn) { return nullptr; } + /** * Verifies that there is enough data in the packet to process the header * length requested. @@ -134,6 +139,8 @@ private: zeek::Connection* NewConn(const ConnTuple* id, const detail::ConnKey& key, const Packet* pkt); + bool BuildSessionAnalyzerTree(Connection* conn); + TransportProto transport; uint32_t server_port_mask; }; diff --git a/src/packet_analysis/protocol/tcp/TCP.cc b/src/packet_analysis/protocol/tcp/TCP.cc index ff88b7f455..e373d7b48c 100644 --- a/src/packet_analysis/protocol/tcp/TCP.cc +++ b/src/packet_analysis/protocol/tcp/TCP.cc @@ -74,8 +74,3 @@ bool TCPAnalyzer::WantConnection(uint16_t src_port, uint16_t dst_port, return true; } - -void TCPAnalyzer::CreateTransportAnalyzer(Connection* conn, IPBasedTransportAnalyzer*& root, - analyzer::pia::PIA*& pia, bool& check_port) - { - } diff --git a/src/packet_analysis/protocol/tcp/TCP.h b/src/packet_analysis/protocol/tcp/TCP.h index 06b9d46ee0..88f6d4dd47 100644 --- a/src/packet_analysis/protocol/tcp/TCP.h +++ b/src/packet_analysis/protocol/tcp/TCP.h @@ -18,9 +18,6 @@ public: return std::make_shared(); } - void CreateTransportAnalyzer(Connection* conn, IP::IPBasedTransportAnalyzer*& root, - analyzer::pia::PIA*& pia, bool& check_port) override; - protected: /** diff --git a/src/packet_analysis/protocol/udp/UDP.cc b/src/packet_analysis/protocol/udp/UDP.cc index 2c633c9d49..749ed1c661 100644 --- a/src/packet_analysis/protocol/udp/UDP.cc +++ b/src/packet_analysis/protocol/udp/UDP.cc @@ -33,17 +33,20 @@ UDPAnalyzer::~UDPAnalyzer() { } -void UDPAnalyzer::CreateTransportAnalyzer(Connection* conn, IPBasedTransportAnalyzer*& root, - analyzer::pia::PIA*& pia, bool& check_port) +IPBasedTransportAnalyzer* UDPAnalyzer::MakeTransportAnalyzer(Connection* conn) { - root = new UDPTransportAnalyzer(conn); + auto* root = new UDPTransportAnalyzer(conn); root->SetParent(this); conn->EnableStatusUpdateTimer(); conn->SetInactivityTimeout(zeek::detail::udp_inactivity_timeout); - pia = new analyzer::pia::PIA_UDP(conn); - check_port = true; + return root; + } + +zeek::analyzer::pia::PIA* UDPAnalyzer::MakePIA(Connection* conn) + { + return new analyzer::pia::PIA_UDP(conn); } void UDPAnalyzer::Initialize() diff --git a/src/packet_analysis/protocol/udp/UDP.h b/src/packet_analysis/protocol/udp/UDP.h index 3dd3c5323d..78657d8173 100644 --- a/src/packet_analysis/protocol/udp/UDP.h +++ b/src/packet_analysis/protocol/udp/UDP.h @@ -18,9 +18,6 @@ public: return std::make_shared(); } - void CreateTransportAnalyzer(Connection* conn, IP::IPBasedTransportAnalyzer*& root, - analyzer::pia::PIA*& pia, bool& check_port) override; - /** * Initialize the analyzer. This method is called after the configuration * was read. Derived classes can override this method to implement custom @@ -54,6 +51,9 @@ protected: bool WantConnection(uint16_t src_port, uint16_t dst_port, const u_char* data, bool& flip_roles) const override; + packet_analysis::IP::IPBasedTransportAnalyzer* MakeTransportAnalyzer(Connection* conn) override; + analyzer::pia::PIA* MakePIA(Connection* conn) override; + private: // Returns true if the checksum is valid, false if not From b22ce6848f29d89d0dc5fcaac9de85edcb9d01b2 Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Tue, 11 May 2021 13:30:57 -0700 Subject: [PATCH 08/10] Rename IPBasedTransportAnalyzer to SessionAdapter This also also combines the old TransportLayerAnalyzer class into SessionAdapter, and removes the old class. This requires naming changes in a few places but no functionality changes. --- src/Conn.cc | 39 ++--- src/Conn.h | 14 +- src/RuleCondition.cc | 10 +- src/analyzer/Analyzer.cc | 27 ---- src/analyzer/Analyzer.h | 79 ---------- src/analyzer/Manager.cc | 10 +- src/analyzer/Manager.h | 9 +- src/analyzer/protocol/gnutella/Gnutella.cc | 2 +- src/analyzer/protocol/tcp/TCP.cc | 10 +- src/analyzer/protocol/tcp/TCP.h | 5 +- src/analyzer/protocol/tcp/functions.bif | 4 +- src/fuzzers/pop3-fuzzer.cc | 2 +- src/packet_analysis/protocol/icmp/ICMP.cc | 144 +++++++++--------- src/packet_analysis/protocol/icmp/ICMP.h | 36 ++--- src/packet_analysis/protocol/icmp/Plugin.cc | 2 +- .../protocol/ip/CMakeLists.txt | 2 +- .../protocol/ip/IPBasedAnalyzer.cc | 4 +- .../protocol/ip/IPBasedAnalyzer.h | 57 ++----- .../protocol/ip/SessionAdapter.cc | 39 +++++ .../protocol/ip/SessionAdapter.h | 102 +++++++++++++ src/packet_analysis/protocol/tcp/TCP.h | 9 ++ src/packet_analysis/protocol/udp/Plugin.cc | 2 +- src/packet_analysis/protocol/udp/UDP.cc | 48 +++--- src/packet_analysis/protocol/udp/UDP.h | 13 +- 24 files changed, 340 insertions(+), 329 deletions(-) create mode 100644 src/packet_analysis/protocol/ip/SessionAdapter.cc create mode 100644 src/packet_analysis/protocol/ip/SessionAdapter.h diff --git a/src/Conn.cc b/src/Conn.cc index da76dc509c..d2d8d0f3da 100644 --- a/src/Conn.cc +++ b/src/Conn.cc @@ -19,6 +19,7 @@ #include "zeek/analyzer/Analyzer.h" #include "zeek/analyzer/Manager.h" #include "zeek/iosource/IOSource.h" +#include "zeek/packet_analysis/protocol/ip/SessionAdapter.h" namespace zeek { @@ -64,7 +65,7 @@ Connection::Connection(const detail::ConnKey& k, double t, hist_seen = 0; history = ""; - root_analyzer = nullptr; + adapter = nullptr; primary_PIA = nullptr; ++current_connections; @@ -83,7 +84,7 @@ Connection::~Connection() if ( conn_val ) conn_val->SetOrigin(nullptr); - delete root_analyzer; + delete adapter; --current_connections; } @@ -129,7 +130,7 @@ void Connection::Done() // somewhere, but it's session-related, so maybe not? if ( ConnTransport() == TRANSPORT_TCP ) { - auto ta = static_cast(GetRootAnalyzer()); + auto ta = static_cast(adapter); assert(ta->IsAnalyzer("TCP")); analyzer::tcp::TCP_Endpoint* to = ta->Orig(); analyzer::tcp::TCP_Endpoint* tr = ta->Resp(); @@ -139,8 +140,8 @@ void Connection::Done() finished = 1; - if ( root_analyzer && ! root_analyzer->IsFinished() ) - root_analyzer->Done(); + if ( adapter && ! adapter->IsFinished() ) + adapter->Done(); } void Connection::NextPacket(double t, bool is_orig, @@ -156,11 +157,11 @@ void Connection::NextPacket(double t, bool is_orig, if ( Skipping() ) return; - if ( root_analyzer ) + if ( adapter ) { record_current_packet = record_packet; record_current_content = record_content; - root_analyzer->NextPacket(len, data, is_orig, -1, ip, caplen); + adapter->NextPacket(len, data, is_orig, -1, ip, caplen); record_packet = record_current_packet; record_content = record_current_content; } @@ -173,7 +174,7 @@ void Connection::NextPacket(double t, bool is_orig, bool Connection::IsReuse(double t, const u_char* pkt) { - return root_analyzer && root_analyzer->IsReuse(t, pkt); + return adapter && adapter->IsReuse(t, pkt); } bool Connection::ScaledHistoryEntry(char code, uint32_t& counter, @@ -275,8 +276,8 @@ const RecordValPtr& Connection::GetVal() } - if ( root_analyzer ) - root_analyzer->UpdateConnVal(conn_val.get()); + if ( adapter ) + adapter->UpdateConnVal(conn_val.get()); conn_val->AssignTime(3, start_time); // ### conn_val->AssignInterval(4, last_time - start_time); @@ -289,17 +290,17 @@ const RecordValPtr& Connection::GetVal() analyzer::Analyzer* Connection::FindAnalyzer(analyzer::ID id) { - return root_analyzer ? root_analyzer->FindChild(id) : nullptr; + return adapter ? adapter->FindChild(id) : nullptr; } analyzer::Analyzer* Connection::FindAnalyzer(const analyzer::Tag& tag) { - return root_analyzer ? root_analyzer->FindChild(tag) : nullptr; + return adapter ? adapter->FindChild(tag) : nullptr; } analyzer::Analyzer* Connection::FindAnalyzer(const char* name) { - return root_analyzer->FindChild(name); + return adapter->FindChild(name); } void Connection::AppendAddl(const char* str) @@ -370,8 +371,8 @@ void Connection::FlipRoles() conn_val = nullptr; - if ( root_analyzer ) - root_analyzer->FlipRoles(); + if ( adapter ) + adapter->FlipRoles(); analyzer_mgr->ApplyScheduledAnalyzers(this); @@ -383,7 +384,7 @@ unsigned int Connection::MemoryAllocation() const return session::Session::MemoryAllocation() + padded_sizeof(*this) + (timers.MemoryAllocation() - padded_sizeof(timers)) + (conn_val ? conn_val->MemoryAllocation() : 0) - + (root_analyzer ? root_analyzer->MemoryAllocation(): 0) + + (adapter ? adapter->MemoryAllocation(): 0) // primary_PIA is already contained in the analyzer tree. ; } @@ -448,10 +449,10 @@ void Connection::IDString(ODesc* d) const d->Add(ntohs(resp_port)); } -void Connection::SetRootAnalyzer(analyzer::TransportLayerAnalyzer* analyzer, - analyzer::pia::PIA* pia) +void Connection::SetSessionAdapter(packet_analysis::IP::SessionAdapter* aa, + analyzer::pia::PIA* pia) { - root_analyzer = analyzer; + adapter = aa; primary_PIA = pia; } diff --git a/src/Conn.h b/src/Conn.h index d6ca89a27b..20a5b138c4 100644 --- a/src/Conn.h +++ b/src/Conn.h @@ -41,12 +41,8 @@ class RuleHdrTest; } // namespace detail -namespace analyzer { - -class TransportLayerAnalyzer; -class Analyzer; - -} // namespace analyzer +namespace analyzer { class Analyzer; } +namespace packet_analysis::IP { class SessionAdapter; } enum ConnEventToFlag { NUL_IN_LINE, @@ -231,8 +227,8 @@ public: void AddHistory(char code) { history += code; } // Sets the root of the analyzer tree as well as the primary PIA. - void SetRootAnalyzer(analyzer::TransportLayerAnalyzer* analyzer, analyzer::pia::PIA* pia); - analyzer::TransportLayerAnalyzer* GetRootAnalyzer() { return root_analyzer; } + void SetSessionAdapter(packet_analysis::IP::SessionAdapter* aa, analyzer::pia::PIA* pia); + packet_analysis::IP::SessionAdapter* GetSessionAdapter() { return adapter; } analyzer::pia::PIA* GetPrimaryPIA() { return primary_PIA; } // Sets the transport protocol in use. @@ -279,7 +275,7 @@ private: uint32_t hist_seen; std::string history; - analyzer::TransportLayerAnalyzer* root_analyzer; + packet_analysis::IP::SessionAdapter* adapter; analyzer::pia::PIA* primary_PIA; UID uid; // Globally unique connection ID. diff --git a/src/RuleCondition.cc b/src/RuleCondition.cc index 33de7f86fc..b765cbaded 100644 --- a/src/RuleCondition.cc +++ b/src/RuleCondition.cc @@ -25,12 +25,12 @@ namespace zeek::detail { bool RuleConditionTCPState::DoMatch(Rule* rule, RuleEndpointState* state, const u_char* data, int len) { - analyzer::Analyzer* root = state->GetAnalyzer()->Conn()->GetRootAnalyzer(); + auto* adapter = state->GetAnalyzer()->Conn()->GetSessionAdapter(); - if ( ! root || ! root->IsAnalyzer("TCP") ) + if ( ! adapter || ! adapter->IsAnalyzer("TCP") ) return false; - auto* ta = static_cast(root); + auto* ta = static_cast(adapter); if ( tcpstates & RULE_STATE_STATELESS ) return true; @@ -57,9 +57,9 @@ void RuleConditionTCPState::PrintDebug() bool RuleConditionUDPState::DoMatch(Rule* rule, RuleEndpointState* state, const u_char* data, int len) { - analyzer::Analyzer* root = state->GetAnalyzer()->Conn()->GetRootAnalyzer(); + auto* adapter = state->GetAnalyzer()->Conn()->GetSessionAdapter(); - if ( ! root || ! root->IsAnalyzer("UDP") ) + if ( ! adapter || ! adapter->IsAnalyzer("UDP") ) return false; if ( states & RULE_STATE_STATELESS ) diff --git a/src/analyzer/Analyzer.cc b/src/analyzer/Analyzer.cc index 2f3bb22fcc..074e7407ab 100644 --- a/src/analyzer/Analyzer.cc +++ b/src/analyzer/Analyzer.cc @@ -880,31 +880,4 @@ void SupportAnalyzer::ForwardUndelivered(uint64_t seq, int len, bool is_orig) } -void TransportLayerAnalyzer::Done() - { - Analyzer::Done(); - } - -void TransportLayerAnalyzer::SetContentsFile(unsigned int /* direction */, - FilePtr /* f */) - { - reporter->Error("analyzer type does not support writing to a contents file"); - } - -FilePtr TransportLayerAnalyzer::GetContentsFile(unsigned int /* direction */) const - { - reporter->Error("analyzer type does not support writing to a contents file"); - return nullptr; - } - -void TransportLayerAnalyzer::PacketContents(const u_char* data, int len) - { - if ( packet_contents && len > 0 ) - { - String* cbs = new String(data, len, true); - auto contents = make_intrusive(cbs); - EnqueueConnEvent(packet_contents, ConnVal(), std::move(contents)); - } - } - } // namespace zeek::analyzer diff --git a/src/analyzer/Analyzer.h b/src/analyzer/Analyzer.h index 415086b13e..c4505051a1 100644 --- a/src/analyzer/Analyzer.h +++ b/src/analyzer/Analyzer.h @@ -846,83 +846,4 @@ private: #define CONTENTS_RESP 2 #define CONTENTS_BOTH 3 -/** - * Base class for analyzers parsing transport-layer protocols. - */ -class TransportLayerAnalyzer : public Analyzer { -public: - /** - * Constructor. - * - * @param name A name for the protocol the analyzer is parsing. The - * name must match the one the corresponding Component registers. - * - * @param conn The connection the analyzer is associated with. - */ - TransportLayerAnalyzer(const char* name, Connection* conn) - : Analyzer(name, conn) { pia = nullptr; } - - /** - * Overridden from parent class. - */ - void Done() override; - - /** - * Returns true if the analyzer determines that in fact a new - * connection has started without the connection statement having - * terminated the previous one, i.e., the new data is arriving at - * what's the analyzer for the previous instance. This is used only - * for TCP. - */ - virtual bool IsReuse(double t, const u_char* pkt) = 0; - - /** - * Associates a file with the analyzer in which to record all - * analyzed input. This must only be called with derived classes that - * overide the method; the default implementation will abort. - * - * @param direction One of the CONTENTS_* constants indicating which - * direction of the input stream is to be recorded. - * - * @param f The file to record to. - * - */ - virtual void SetContentsFile(unsigned int direction, FilePtr f); - - /** - * Returns an associated contents file, if any. This must only be - * called with derived classes that overide the method; the default - * implementation will abort. - * - * @param direction One of the CONTENTS_* constants indicating which - * direction the query is for. - */ - virtual FilePtr GetContentsFile(unsigned int direction) const; - - /** - * Associates a PIA with this analyzer. A PIA takes the - * transport-layer input and determine which protocol analyzer(s) to - * use for parsing it. - */ - void SetPIA(analyzer::pia::PIA* arg_PIA) { pia = arg_PIA; } - - /** - * Returns the associated PIA, or null of none. Does not take - * ownership. - */ - analyzer::pia::PIA* GetPIA() const { return pia; } - - /** - * Helper to raise a \c packet_contents event. - * - * @param data The dass to pass to the event. - * - * @param len The length of \a data. - */ - void PacketContents(const u_char* data, int len); - -private: - analyzer::pia::PIA* pia; -}; - } // namespace zeek::analyzer diff --git a/src/analyzer/Manager.cc b/src/analyzer/Manager.cc index 91ae7c3bc7..27b0621b31 100644 --- a/src/analyzer/Manager.cc +++ b/src/analyzer/Manager.cc @@ -12,6 +12,7 @@ #include "zeek/analyzer/protocol/stepping-stone/SteppingStone.h" #include "zeek/analyzer/protocol/tcp/TCP.h" #include "zeek/packet_analysis/protocol/ip/IPBasedAnalyzer.h" +#include "zeek/packet_analysis/protocol/ip/SessionAdapter.h" #include "zeek/plugin/Manager.h" @@ -356,7 +357,7 @@ Manager::tag_set* Manager::LookupPort(TransportProto proto, uint32_t port, bool bool Manager::BuildInitialAnalyzerTree(Connection* conn) { analyzer::tcp::TCP_Analyzer* tcp = nullptr; - TransportLayerAnalyzer* root = nullptr; + packet_analysis::IP::SessionAdapter* root = nullptr; analyzer::pia::PIA* pia = nullptr; bool check_port = false; @@ -470,7 +471,7 @@ bool Manager::BuildInitialAnalyzerTree(Connection* conn) if ( pia ) root->AddChildAnalyzer(pia->AsAnalyzer()); - conn->SetRootAnalyzer(root, pia); + conn->SetSessionAdapter(root, pia); root->Init(); root->InitChildren(); @@ -588,10 +589,11 @@ Manager::tag_set Manager::GetScheduled(const Connection* conn) return result; } -bool Manager::ApplyScheduledAnalyzers(Connection* conn, bool init, TransportLayerAnalyzer* parent) +bool Manager::ApplyScheduledAnalyzers(Connection* conn, bool init, + packet_analysis::IP::SessionAdapter* parent) { if ( ! parent ) - parent = conn->GetRootAnalyzer(); + parent = conn->GetSessionAdapter(); if ( ! parent ) return false; diff --git a/src/analyzer/Manager.h b/src/analyzer/Manager.h index ed9fa51ea4..65c38a6fbf 100644 --- a/src/analyzer/Manager.h +++ b/src/analyzer/Manager.h @@ -36,7 +36,12 @@ namespace zeek { -namespace packet_analysis::IP { class IPBasedAnalyzer; } +namespace packet_analysis::IP { + +class IPBasedAnalyzer; +class SessionAdapter; + +} // namespace packet_analysis::IP namespace analyzer { @@ -316,7 +321,7 @@ public: * @return True if at least one scheduled analyzer was found. */ bool ApplyScheduledAnalyzers(Connection* conn, bool init_and_event = true, - TransportLayerAnalyzer* parent = nullptr); + packet_analysis::IP::SessionAdapter* parent = nullptr); /** * Schedules a particular analyzer for an upcoming connection. Once diff --git a/src/analyzer/protocol/gnutella/Gnutella.cc b/src/analyzer/protocol/gnutella/Gnutella.cc index 661863c33d..610e8b0a5b 100644 --- a/src/analyzer/protocol/gnutella/Gnutella.cc +++ b/src/analyzer/protocol/gnutella/Gnutella.cc @@ -129,7 +129,7 @@ bool Gnutella_Analyzer::IsHTTP(std::string header) if ( Parent()->IsAnalyzer("TCP") ) { // Replay buffered data. - analyzer::pia::PIA* pia = static_cast(Parent())->GetPIA(); + analyzer::pia::PIA* pia = static_cast(Parent())->GetPIA(); if ( pia ) static_cast(pia)->ReplayStreamBuffer(a); } diff --git a/src/analyzer/protocol/tcp/TCP.cc b/src/analyzer/protocol/tcp/TCP.cc index f4a5d3b4bd..8dd7479df1 100644 --- a/src/analyzer/protocol/tcp/TCP.cc +++ b/src/analyzer/protocol/tcp/TCP.cc @@ -123,7 +123,7 @@ static RecordVal* build_syn_packet_val(bool is_orig, const IP_Hdr* ip, TCP_Analyzer::TCP_Analyzer(Connection* conn) -: TransportLayerAnalyzer("TCP", conn) + : packet_analysis::IP::SessionAdapter("TCP", conn) { // Set a timer to eventually time out this connection. ADD_ANALYZER_TIMER(&TCP_Analyzer::ExpireTimer, @@ -180,7 +180,7 @@ void TCP_Analyzer::Done() analyzer::Analyzer* TCP_Analyzer::FindChild(analyzer::ID arg_id) { - analyzer::Analyzer* child = analyzer::TransportLayerAnalyzer::FindChild(arg_id); + analyzer::Analyzer* child = packet_analysis::IP::SessionAdapter::FindChild(arg_id); if ( child ) return child; @@ -197,7 +197,7 @@ analyzer::Analyzer* TCP_Analyzer::FindChild(analyzer::ID arg_id) analyzer::Analyzer* TCP_Analyzer::FindChild(analyzer::Tag arg_tag) { - analyzer::Analyzer* child = analyzer::TransportLayerAnalyzer::FindChild(arg_tag); + analyzer::Analyzer* child = packet_analysis::IP::SessionAdapter::FindChild(arg_tag); if ( child ) return child; @@ -214,7 +214,7 @@ analyzer::Analyzer* TCP_Analyzer::FindChild(analyzer::Tag arg_tag) bool TCP_Analyzer::RemoveChildAnalyzer(analyzer::ID id) { - auto rval = analyzer::TransportLayerAnalyzer::RemoveChildAnalyzer(id); + auto rval = packet_analysis::IP::SessionAdapter::RemoveChildAnalyzer(id); if ( rval ) return rval; @@ -1048,7 +1048,7 @@ static int32_t update_last_seq(TCP_Endpoint* endpoint, uint32_t last_seq, void TCP_Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig, uint64_t seq, const IP_Hdr* ip, int caplen) { - TransportLayerAnalyzer::DeliverPacket(len, data, orig, seq, ip, caplen); + packet_analysis::IP::SessionAdapter::DeliverPacket(len, data, orig, seq, ip, caplen); const struct tcphdr* tp = ExtractTCP_Header(data, len, caplen); if ( ! tp ) diff --git a/src/analyzer/protocol/tcp/TCP.h b/src/analyzer/protocol/tcp/TCP.h index 27e42e7e91..d03920d031 100644 --- a/src/analyzer/protocol/tcp/TCP.h +++ b/src/analyzer/protocol/tcp/TCP.h @@ -6,6 +6,7 @@ #include "zeek/IPAddr.h" #include "zeek/analyzer/protocol/tcp/TCP_Endpoint.h" #include "zeek/analyzer/protocol/tcp/TCP_Flags.h" +#include "zeek/packet_analysis/protocol/ip/SessionAdapter.h" #include "zeek/Conn.h" // We define two classes here: @@ -22,7 +23,7 @@ class TCP_Endpoint; class TCP_Reassembler; class TCP_ApplicationAnalyzer; -class TCP_Analyzer final : public analyzer::TransportLayerAnalyzer { +class TCP_Analyzer final : public packet_analysis::IP::SessionAdapter { public: explicit TCP_Analyzer(Connection* conn); ~TCP_Analyzer() override; @@ -72,6 +73,8 @@ public: static analyzer::Analyzer* Instantiate(Connection* conn) { return new TCP_Analyzer(conn); } + void AddExtraAnalyzers(Connection* conn) override {} + protected: friend class TCP_ApplicationAnalyzer; friend class TCP_Reassembler; diff --git a/src/analyzer/protocol/tcp/functions.bif b/src/analyzer/protocol/tcp/functions.bif index ffdc542893..65669e524a 100644 --- a/src/analyzer/protocol/tcp/functions.bif +++ b/src/analyzer/protocol/tcp/functions.bif @@ -101,7 +101,7 @@ function set_contents_file%(cid: conn_id, direction: count, f: file%): bool if ( ! c ) return zeek::val_mgr->False(); - c->GetRootAnalyzer()->SetContentsFile(direction, {zeek::NewRef{}, f}); + c->GetSessionAdapter()->SetContentsFile(direction, {zeek::NewRef{}, f}); return zeek::val_mgr->True(); %} @@ -124,7 +124,7 @@ function get_contents_file%(cid: conn_id, direction: count%): file if ( c ) { - auto cf = c->GetRootAnalyzer()->GetContentsFile(direction); + auto cf = c->GetSessionAdapter()->GetContentsFile(direction); if ( cf ) return zeek::make_intrusive(std::move(cf)); diff --git a/src/fuzzers/pop3-fuzzer.cc b/src/fuzzers/pop3-fuzzer.cc index c5d2b8e2c0..7bd036af89 100644 --- a/src/fuzzers/pop3-fuzzer.cc +++ b/src/fuzzers/pop3-fuzzer.cc @@ -41,7 +41,7 @@ static zeek::analyzer::Analyzer* add_analyzer(zeek::Connection* conn) auto a = zeek::analyzer_mgr->InstantiateAnalyzer(ZEEK_FUZZ_ANALYZER, conn); tcp->AddChildAnalyzer(a); tcp->AddChildAnalyzer(pia->AsAnalyzer()); - conn->SetRootAnalyzer(tcp, pia); + conn->SetSessionAdapter(tcp, pia); return a; } diff --git a/src/packet_analysis/protocol/icmp/ICMP.cc b/src/packet_analysis/protocol/icmp/ICMP.cc index ad04eef8f6..8ceba9cf3a 100644 --- a/src/packet_analysis/protocol/icmp/ICMP.cc +++ b/src/packet_analysis/protocol/icmp/ICMP.cc @@ -35,9 +35,9 @@ ICMPAnalyzer::~ICMPAnalyzer() { } -IPBasedTransportAnalyzer* ICMPAnalyzer::MakeTransportAnalyzer(Connection* conn) +SessionAdapter* ICMPAnalyzer::MakeSessionAdapter(Connection* conn) { - auto* root = new ICMPTransportAnalyzer(conn); + auto* root = new ICMPSessionAdapter(conn); root->SetParent(this); conn->SetInactivityTimeout(zeek::detail::icmp_inactivity_timeout); @@ -70,13 +70,13 @@ bool ICMPAnalyzer::BuildConnTuple(size_t len, const uint8_t* data, Packet* packe void ICMPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int remaining, Packet* pkt) { - auto* ta = static_cast(c->GetRootAnalyzer()); + auto* adapter = static_cast(c->GetSessionAdapter()); const u_char* data = pkt->ip_hdr->Payload(); int len = pkt->ip_hdr->PayloadLen(); if ( packet_contents && len > 0 ) - ta->PacketContents(data + 8, std::min(len, remaining) - 8); + adapter->PacketContents(data + 8, std::min(len, remaining) - 8); const struct icmp* icmpp = (const struct icmp*) data; const std::unique_ptr& ip = pkt->ip_hdr; @@ -104,25 +104,25 @@ void ICMPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int rema if ( chksum != 0xffff ) { - ta->Weird("bad_ICMP_checksum"); + adapter->Weird("bad_ICMP_checksum"); return; } } c->SetLastTime(run_state::current_timestamp); - ta->InitEndpointMatcher(ip.get(), len, is_orig); + adapter->InitEndpointMatcher(ip.get(), len, is_orig); // Move past common portion of ICMP header. data += 8; remaining -= 8; len -= 8; - ta->UpdateLength(is_orig, len); + adapter->UpdateLength(is_orig, len); if ( ip->NextProto() == IPPROTO_ICMP ) - NextICMP4(run_state::current_timestamp, icmpp, len, remaining, data, ip.get(), ta); + NextICMP4(run_state::current_timestamp, icmpp, len, remaining, data, ip.get(), adapter); else if ( ip->NextProto() == IPPROTO_ICMPV6 ) - NextICMP6(run_state::current_timestamp, icmpp, len, remaining, data, ip.get(), ta); + NextICMP6(run_state::current_timestamp, icmpp, len, remaining, data, ip.get(), adapter); else { reporter->Error("expected ICMP as IP packet's protocol, got %d", ip->NextProto()); @@ -132,43 +132,43 @@ void ICMPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int rema ForwardPacket(len, data, pkt); if ( remaining >= len ) - ta->ForwardPacket(len, data, is_orig, -1, ip.get(), remaining); + adapter->ForwardPacket(len, data, is_orig, -1, ip.get(), remaining); - ta->MatchEndpoint(data, len, is_orig); + adapter->MatchEndpoint(data, len, is_orig); } void ICMPAnalyzer::NextICMP4(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr, - ICMPTransportAnalyzer* analyzer) + ICMPSessionAdapter* adapter) { switch ( icmpp->icmp_type ) { case ICMP_ECHO: case ICMP_ECHOREPLY: - Echo(t, icmpp, len, caplen, data, ip_hdr, analyzer); + Echo(t, icmpp, len, caplen, data, ip_hdr, adapter); break; case ICMP_UNREACH: case ICMP_TIMXCEED: - Context4(t, icmpp, len, caplen, data, ip_hdr, analyzer); + Context4(t, icmpp, len, caplen, data, ip_hdr, adapter); break; default: - ICMP_Sent(icmpp, len, caplen, 0, data, ip_hdr, analyzer); + ICMP_Sent(icmpp, len, caplen, 0, data, ip_hdr, adapter); break; } } void ICMPAnalyzer::NextICMP6(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr, - ICMPTransportAnalyzer* analyzer) + ICMPSessionAdapter* adapter) { switch ( icmpp->icmp_type ) { // Echo types. case ICMP6_ECHO_REQUEST: case ICMP6_ECHO_REPLY: - Echo(t, icmpp, len, caplen, data, ip_hdr, analyzer); + Echo(t, icmpp, len, caplen, data, ip_hdr, adapter); break; // Error messages all have the same structure for their context, @@ -177,27 +177,27 @@ void ICMPAnalyzer::NextICMP6(double t, const struct icmp* icmpp, int len, int ca case ICMP6_TIME_EXCEEDED: case ICMP6_PACKET_TOO_BIG: case ICMP6_DST_UNREACH: - Context6(t, icmpp, len, caplen, data, ip_hdr, analyzer); + Context6(t, icmpp, len, caplen, data, ip_hdr, adapter); break; // Router related messages. case ND_REDIRECT: - Redirect(t, icmpp, len, caplen, data, ip_hdr, analyzer); + Redirect(t, icmpp, len, caplen, data, ip_hdr, adapter); break; case ND_ROUTER_ADVERT: - RouterAdvert(t, icmpp, len, caplen, data, ip_hdr, analyzer); + RouterAdvert(t, icmpp, len, caplen, data, ip_hdr, adapter); break; case ND_NEIGHBOR_ADVERT: - NeighborAdvert(t, icmpp, len, caplen, data, ip_hdr, analyzer); + NeighborAdvert(t, icmpp, len, caplen, data, ip_hdr, adapter); break; case ND_NEIGHBOR_SOLICIT: - NeighborSolicit(t, icmpp, len, caplen, data, ip_hdr, analyzer); + NeighborSolicit(t, icmpp, len, caplen, data, ip_hdr, adapter); break; case ND_ROUTER_SOLICIT: - RouterSolicit(t, icmpp, len, caplen, data, ip_hdr, analyzer); + RouterSolicit(t, icmpp, len, caplen, data, ip_hdr, adapter); break; case ICMP6_ROUTER_RENUMBERING: - ICMP_Sent(icmpp, len, caplen, 1, data, ip_hdr, analyzer); + ICMP_Sent(icmpp, len, caplen, 1, data, ip_hdr, adapter); break; #if 0 @@ -211,28 +211,28 @@ void ICMPAnalyzer::NextICMP6(double t, const struct icmp* icmpp, int len, int ca // the same structure for their context, and are // handled by the same function. if ( icmpp->icmp_type < 128 ) - Context6(t, icmpp, len, caplen, data, ip_hdr, analyzer); + Context6(t, icmpp, len, caplen, data, ip_hdr, adapter); else - ICMP_Sent(icmpp, len, caplen, 1, data, ip_hdr, analyzer); + ICMP_Sent(icmpp, len, caplen, 1, data, ip_hdr, adapter); break; } } void ICMPAnalyzer::ICMP_Sent(const struct icmp* icmpp, int len, int caplen, int icmpv6, const u_char* data, const IP_Hdr* ip_hdr, - ICMPTransportAnalyzer* analyzer) + ICMPSessionAdapter* adapter) { if ( icmp_sent ) - analyzer->EnqueueConnEvent(icmp_sent, analyzer->ConnVal(), - BuildInfo(icmpp, len, icmpv6, ip_hdr)); + adapter->EnqueueConnEvent(icmp_sent, adapter->ConnVal(), + BuildInfo(icmpp, len, icmpv6, ip_hdr)); if ( icmp_sent_payload ) { String* payload = new String(data, std::min(len, caplen), false); - analyzer->EnqueueConnEvent(icmp_sent_payload, analyzer->ConnVal(), - BuildInfo(icmpp, len, icmpv6, ip_hdr), - make_intrusive(payload)); + adapter->EnqueueConnEvent(icmp_sent_payload, adapter->ConnVal(), + BuildInfo(icmpp, len, icmpv6, ip_hdr), + make_intrusive(payload)); } } @@ -446,7 +446,7 @@ zeek::RecordValPtr ICMPAnalyzer::ExtractICMP6Context(int len, const u_char*& dat void ICMPAnalyzer::Echo(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr, - ICMPTransportAnalyzer* analyzer) + ICMPSessionAdapter* adapter) { // For handling all Echo related ICMP messages EventHandlerPtr f = nullptr; @@ -466,8 +466,8 @@ void ICMPAnalyzer::Echo(double t, const struct icmp* icmpp, int len, String* payload = new String(data, caplen, false); - analyzer->EnqueueConnEvent(f, - analyzer->ConnVal(), + adapter->EnqueueConnEvent(f, + adapter->ConnVal(), BuildInfo(icmpp, len, ip_hdr->NextProto() != IPPROTO_ICMP, ip_hdr), val_mgr->Count(iid), val_mgr->Count(iseq), @@ -478,7 +478,7 @@ void ICMPAnalyzer::Echo(double t, const struct icmp* icmpp, int len, void ICMPAnalyzer::RouterAdvert(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr, - ICMPTransportAnalyzer* analyzer) + ICMPSessionAdapter* adapter) { EventHandlerPtr f = icmp_router_advertisement; @@ -495,8 +495,8 @@ void ICMPAnalyzer::RouterAdvert(double t, const struct icmp* icmpp, int len, int opt_offset = sizeof(reachable) + sizeof(retrans); - analyzer->EnqueueConnEvent(f, - analyzer->ConnVal(), + adapter->EnqueueConnEvent(f, + adapter->ConnVal(), BuildInfo(icmpp, len, 1, ip_hdr), val_mgr->Count(icmpp->icmp_num_addrs), // Cur Hop Limit val_mgr->Bool(icmpp->icmp_wpa & 0x80), // Managed @@ -508,14 +508,14 @@ void ICMPAnalyzer::RouterAdvert(double t, const struct icmp* icmpp, int len, make_intrusive((double)ntohs(icmpp->icmp_lifetime), Seconds), make_intrusive((double)ntohl(reachable), Milliseconds), make_intrusive((double)ntohl(retrans), Milliseconds), - BuildNDOptionsVal(caplen - opt_offset, data + opt_offset, analyzer) + BuildNDOptionsVal(caplen - opt_offset, data + opt_offset, adapter) ); } void ICMPAnalyzer::NeighborAdvert(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr, - ICMPTransportAnalyzer* analyzer) + ICMPSessionAdapter* adapter) { EventHandlerPtr f = icmp_neighbor_advertisement; @@ -529,21 +529,21 @@ void ICMPAnalyzer::NeighborAdvert(double t, const struct icmp* icmpp, int len, int opt_offset = sizeof(in6_addr); - analyzer->EnqueueConnEvent(f, - analyzer->ConnVal(), + adapter->EnqueueConnEvent(f, + adapter->ConnVal(), BuildInfo(icmpp, len, 1, ip_hdr), val_mgr->Bool(icmpp->icmp_num_addrs & 0x80), // Router val_mgr->Bool(icmpp->icmp_num_addrs & 0x40), // Solicited val_mgr->Bool(icmpp->icmp_num_addrs & 0x20), // Override make_intrusive(tgtaddr), - BuildNDOptionsVal(caplen - opt_offset, data + opt_offset, analyzer) + BuildNDOptionsVal(caplen - opt_offset, data + opt_offset, adapter) ); } void ICMPAnalyzer::NeighborSolicit(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr, - ICMPTransportAnalyzer* analyzer) + ICMPSessionAdapter* adapter) { EventHandlerPtr f = icmp_neighbor_solicitation; @@ -557,18 +557,18 @@ void ICMPAnalyzer::NeighborSolicit(double t, const struct icmp* icmpp, int len, int opt_offset = sizeof(in6_addr); - analyzer->EnqueueConnEvent(f, - analyzer->ConnVal(), + adapter->EnqueueConnEvent(f, + adapter->ConnVal(), BuildInfo(icmpp, len, 1, ip_hdr), make_intrusive(tgtaddr), - BuildNDOptionsVal(caplen - opt_offset, data + opt_offset, analyzer) + BuildNDOptionsVal(caplen - opt_offset, data + opt_offset, adapter) ); } void ICMPAnalyzer::Redirect(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr, - ICMPTransportAnalyzer* analyzer) + ICMPSessionAdapter* adapter) { EventHandlerPtr f = icmp_redirect; @@ -585,36 +585,36 @@ void ICMPAnalyzer::Redirect(double t, const struct icmp* icmpp, int len, int opt_offset = 2 * sizeof(in6_addr); - analyzer->EnqueueConnEvent(f, - analyzer->ConnVal(), + adapter->EnqueueConnEvent(f, + adapter->ConnVal(), BuildInfo(icmpp, len, 1, ip_hdr), make_intrusive(tgtaddr), make_intrusive(dstaddr), - BuildNDOptionsVal(caplen - opt_offset, data + opt_offset, analyzer) + BuildNDOptionsVal(caplen - opt_offset, data + opt_offset, adapter) ); } void ICMPAnalyzer::RouterSolicit(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr, - ICMPTransportAnalyzer* analyzer) + ICMPSessionAdapter* adapter) { EventHandlerPtr f = icmp_router_solicitation; if ( ! f ) return; - analyzer->EnqueueConnEvent(f, - analyzer->ConnVal(), + adapter->EnqueueConnEvent(f, + adapter->ConnVal(), BuildInfo(icmpp, len, 1, ip_hdr), - BuildNDOptionsVal(caplen, data, analyzer) + BuildNDOptionsVal(caplen, data, adapter) ); } void ICMPAnalyzer::Context4(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr, - ICMPTransportAnalyzer* analyzer) + ICMPSessionAdapter* adapter) { EventHandlerPtr f = nullptr; @@ -630,8 +630,8 @@ void ICMPAnalyzer::Context4(double t, const struct icmp* icmpp, int len, } if ( f ) - analyzer->EnqueueConnEvent(f, - analyzer->ConnVal(), + adapter->EnqueueConnEvent(f, + adapter->ConnVal(), BuildInfo(icmpp, len, 0, ip_hdr), val_mgr->Count(icmpp->icmp_code), ExtractICMP4Context(caplen, data) @@ -641,7 +641,7 @@ void ICMPAnalyzer::Context4(double t, const struct icmp* icmpp, int len, void ICMPAnalyzer::Context6(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr, - ICMPTransportAnalyzer* analyzer) + ICMPSessionAdapter* adapter) { EventHandlerPtr f = nullptr; @@ -669,8 +669,8 @@ void ICMPAnalyzer::Context6(double t, const struct icmp* icmpp, int len, } if ( f ) - analyzer->EnqueueConnEvent(f, - analyzer->ConnVal(), + adapter->EnqueueConnEvent(f, + adapter->ConnVal(), BuildInfo(icmpp, len, 1, ip_hdr), val_mgr->Count(icmpp->icmp_code), ExtractICMP6Context(caplen, data) @@ -678,7 +678,7 @@ void ICMPAnalyzer::Context6(double t, const struct icmp* icmpp, int len, } zeek::VectorValPtr ICMPAnalyzer::BuildNDOptionsVal(int caplen, const u_char* data, - ICMPTransportAnalyzer* analyzer) + ICMPSessionAdapter* adapter) { static auto icmp6_nd_option_type = id::find_type("icmp6_nd_option"); static auto icmp6_nd_prefix_info_type = id::find_type("icmp6_nd_prefix_info"); @@ -691,7 +691,7 @@ zeek::VectorValPtr ICMPAnalyzer::BuildNDOptionsVal(int caplen, const u_char* dat // Must have at least type & length to continue parsing options. if ( caplen < 2 ) { - analyzer->Weird("truncated_ICMPv6_ND_options"); + adapter->Weird("truncated_ICMPv6_ND_options"); break; } @@ -700,7 +700,7 @@ zeek::VectorValPtr ICMPAnalyzer::BuildNDOptionsVal(int caplen, const u_char* dat if ( length == 0 ) { - analyzer->Weird("zero_length_ICMPv6_ND_option"); + adapter->Weird("zero_length_ICMPv6_ND_option"); break; } @@ -867,7 +867,7 @@ int ICMPAnalyzer::ICMP6_counterpart(int icmp_type, int icmp_code, bool& is_one_w } } -void ICMPTransportAnalyzer::AddExtraAnalyzers(Connection* conn) +void ICMPSessionAdapter::AddExtraAnalyzers(Connection* conn) { static analyzer::Tag analyzer_connsize = analyzer_mgr->GetComponentTag("CONNSIZE"); @@ -876,7 +876,7 @@ void ICMPTransportAnalyzer::AddExtraAnalyzers(Connection* conn) AddChildAnalyzer(new analyzer::conn_size::ConnSize_Analyzer(conn)); } -void ICMPTransportAnalyzer::UpdateConnVal(zeek::RecordVal* conn_val) +void ICMPSessionAdapter::UpdateConnVal(zeek::RecordVal* conn_val) { const auto& orig_endp = conn_val->GetField("orig"); const auto& resp_endp = conn_val->GetField("resp"); @@ -887,7 +887,7 @@ void ICMPTransportAnalyzer::UpdateConnVal(zeek::RecordVal* conn_val) analyzer::Analyzer::UpdateConnVal(conn_val); } -void ICMPTransportAnalyzer::UpdateEndpointVal(const ValPtr& endp_arg, bool is_orig) +void ICMPSessionAdapter::UpdateEndpointVal(const ValPtr& endp_arg, bool is_orig) { Conn()->EnableStatusUpdateTimer(); @@ -906,7 +906,7 @@ void ICMPTransportAnalyzer::UpdateEndpointVal(const ValPtr& endp_arg, bool is_or } } -void ICMPTransportAnalyzer::UpdateLength(bool is_orig, int len) +void ICMPSessionAdapter::UpdateLength(bool is_orig, int len) { int& len_stat = is_orig ? request_len : reply_len; if ( len_stat < 0 ) @@ -915,7 +915,7 @@ void ICMPTransportAnalyzer::UpdateLength(bool is_orig, int len) len_stat += len; } -void ICMPTransportAnalyzer::InitEndpointMatcher(const IP_Hdr* ip_hdr, int len, bool is_orig) +void ICMPSessionAdapter::InitEndpointMatcher(const IP_Hdr* ip_hdr, int len, bool is_orig) { if ( zeek::detail::rule_matcher ) { @@ -924,15 +924,15 @@ void ICMPTransportAnalyzer::InitEndpointMatcher(const IP_Hdr* ip_hdr, int len, b } } -void ICMPTransportAnalyzer::MatchEndpoint(const u_char* data, int len, bool is_orig) +void ICMPSessionAdapter::MatchEndpoint(const u_char* data, int len, bool is_orig) { if ( zeek::detail::rule_matcher ) matcher_state.Match(zeek::detail::Rule::PAYLOAD, data, len, is_orig, false, false, true); } -void ICMPTransportAnalyzer::Done() +void ICMPSessionAdapter::Done() { - TransportLayerAnalyzer::Done(); + SessionAdapter::Done(); matcher_state.FinishEndpointMatcher(); } diff --git a/src/packet_analysis/protocol/icmp/ICMP.h b/src/packet_analysis/protocol/icmp/ICMP.h index d77b778168..6d930a98e9 100644 --- a/src/packet_analysis/protocol/icmp/ICMP.h +++ b/src/packet_analysis/protocol/icmp/ICMP.h @@ -17,7 +17,7 @@ using RecordValPtr = IntrusivePtr; namespace packet_analysis::ICMP { -class ICMPTransportAnalyzer; +class ICMPSessionAdapter; class ICMPAnalyzer final : public IP::IPBasedAnalyzer { public: @@ -29,7 +29,7 @@ public: return std::make_shared(); } - packet_analysis::IP::IPBasedTransportAnalyzer* MakeTransportAnalyzer(Connection* conn) override; + packet_analysis::IP::SessionAdapter* MakeSessionAdapter(Connection* conn) override; protected: @@ -46,34 +46,34 @@ private: void NextICMP4(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr, - ICMPTransportAnalyzer* analyzer); + ICMPSessionAdapter* adapter); void NextICMP6(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr, - ICMPTransportAnalyzer* analyzer); + ICMPSessionAdapter* adapter); void ICMP_Sent(const struct icmp* icmpp, int len, int caplen, int icmpv6, const u_char* data, const IP_Hdr* ip_hdr, - ICMPTransportAnalyzer* analyzer); + ICMPSessionAdapter* adapter); void Echo(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr, - ICMPTransportAnalyzer* analyzer); + ICMPSessionAdapter* adapter); void Redirect(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr, - ICMPTransportAnalyzer* analyzer); + ICMPSessionAdapter* adapter); void RouterAdvert(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr, - ICMPTransportAnalyzer* analyzer); + ICMPSessionAdapter* adapter); void NeighborAdvert(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr, - ICMPTransportAnalyzer* analyzer); + ICMPSessionAdapter* adapter); void NeighborSolicit(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr, - ICMPTransportAnalyzer* analyzer); + ICMPSessionAdapter* adapter); void RouterSolicit(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr, - ICMPTransportAnalyzer* analyzer); + ICMPSessionAdapter* adapter); RecordValPtr BuildInfo(const struct icmp* icmpp, int len, bool icmpv6, const IP_Hdr* ip_hdr); @@ -82,7 +82,7 @@ private: void Context4(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr, - ICMPTransportAnalyzer* analyzer); + ICMPSessionAdapter* adapter); TransportProto GetContextProtocol(const IP_Hdr* ip_hdr, uint32_t* src_port, uint32_t* dst_port); @@ -91,11 +91,11 @@ private: void Context6(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr, - ICMPTransportAnalyzer* analyzer); + ICMPSessionAdapter* adapter); // RFC 4861 Neighbor Discover message options VectorValPtr BuildNDOptionsVal(int caplen, const u_char* data, - ICMPTransportAnalyzer* analyzer); + ICMPSessionAdapter* adapter); void UpdateEndpointVal(const ValPtr& endp, bool is_orig); @@ -105,16 +105,16 @@ private: int ICMP6_counterpart(int icmp_type, int icmp_code, bool& is_one_way); }; -class ICMPTransportAnalyzer final : public IP::IPBasedTransportAnalyzer { +class ICMPSessionAdapter final : public IP::SessionAdapter { public: - ICMPTransportAnalyzer(Connection* conn) : - IP::IPBasedTransportAnalyzer("ICMP", conn) { } + ICMPSessionAdapter(Connection* conn) : + IP::SessionAdapter("ICMP", conn) { } static zeek::analyzer::Analyzer* Instantiate(Connection* conn) { - return new ICMPTransportAnalyzer(conn); + return new ICMPSessionAdapter(conn); } void AddExtraAnalyzers(Connection* conn) override; diff --git a/src/packet_analysis/protocol/icmp/Plugin.cc b/src/packet_analysis/protocol/icmp/Plugin.cc index 944ca38d02..d4aa34a7c3 100644 --- a/src/packet_analysis/protocol/icmp/Plugin.cc +++ b/src/packet_analysis/protocol/icmp/Plugin.cc @@ -13,7 +13,7 @@ public: AddComponent(new zeek::packet_analysis::Component("ICMP", zeek::packet_analysis::ICMP::ICMPAnalyzer::Instantiate)); AddComponent(new zeek::analyzer::Component("ICMP", - zeek::packet_analysis::ICMP::ICMPTransportAnalyzer::Instantiate)); + zeek::packet_analysis::ICMP::ICMPSessionAdapter::Instantiate)); zeek::plugin::Configuration config; config.name = "Zeek::ICMP"; diff --git a/src/packet_analysis/protocol/ip/CMakeLists.txt b/src/packet_analysis/protocol/ip/CMakeLists.txt index 89971b9334..fb851f552e 100644 --- a/src/packet_analysis/protocol/ip/CMakeLists.txt +++ b/src/packet_analysis/protocol/ip/CMakeLists.txt @@ -4,5 +4,5 @@ include(ZeekPlugin) include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) zeek_plugin_begin(PacketAnalyzer IP) -zeek_plugin_cc(IP.cc IPBasedAnalyzer.cc Plugin.cc) +zeek_plugin_cc(IP.cc IPBasedAnalyzer.cc SessionAdapter.cc Plugin.cc) zeek_plugin_end() diff --git a/src/packet_analysis/protocol/ip/IPBasedAnalyzer.cc b/src/packet_analysis/protocol/ip/IPBasedAnalyzer.cc index 53a23adcb0..660d238366 100644 --- a/src/packet_analysis/protocol/ip/IPBasedAnalyzer.cc +++ b/src/packet_analysis/protocol/ip/IPBasedAnalyzer.cc @@ -218,7 +218,7 @@ zeek::Connection* IPBasedAnalyzer::NewConn(const ConnTuple* id, const detail::Co bool IPBasedAnalyzer::BuildSessionAnalyzerTree(Connection* conn) { - packet_analysis::IP::IPBasedTransportAnalyzer* root = MakeTransportAnalyzer(conn); + SessionAdapter* root = MakeSessionAdapter(conn); analyzer::pia::PIA* pia = MakePIA(conn); // TODO: temporary, can be replaced when the port lookup stuff is moved from analyzer_mgr @@ -262,7 +262,7 @@ bool IPBasedAnalyzer::BuildSessionAnalyzerTree(Connection* conn) if ( pia ) root->AddChildAnalyzer(pia->AsAnalyzer()); - conn->SetRootAnalyzer(root, pia); + conn->SetSessionAdapter(root, pia); root->Init(); root->InitChildren(); diff --git a/src/packet_analysis/protocol/ip/IPBasedAnalyzer.h b/src/packet_analysis/protocol/ip/IPBasedAnalyzer.h index c507968564..425b541377 100644 --- a/src/packet_analysis/protocol/ip/IPBasedAnalyzer.h +++ b/src/packet_analysis/protocol/ip/IPBasedAnalyzer.h @@ -4,6 +4,7 @@ #include "zeek/packet_analysis/Analyzer.h" #include "zeek/packet_analysis/Component.h" +#include "zeek/packet_analysis/protocol/ip/SessionAdapter.h" #include "zeek/analyzer/Analyzer.h" #include "zeek/analyzer/Manager.h" @@ -11,11 +12,9 @@ namespace zeek::analyzer::pia { class PIA; } namespace zeek::packet_analysis::IP { -class IPBasedTransportAnalyzer; - /** - * A base class for any packet analyzer based on IP. This is used by default by - * the TCP, UDP, and ICMP analyzers to reduce a large amount of duplicated code + * A base class for reuse by packet analyzers based on IP. This is used by default + * by the TCP, UDP, and ICMP analyzers to reduce a large amount of duplicated code * that those plugins have in common. */ class IPBasedAnalyzer : public Analyzer { @@ -91,13 +90,15 @@ protected: } /** - * Returns a transport analyzer appropriate for this IP-based analyzer. This - * can also be used to do any extra initialization of connection timers, etc. + * Returns an analyzer adapter appropriate for this IP-based analyzer. This adapter + * is used to hook into the session analyzer framework. This function can also be used + * to do any extra initialization of connection timers, etc. */ - virtual IPBasedTransportAnalyzer* MakeTransportAnalyzer(Connection* conn) { return nullptr; } + virtual SessionAdapter* MakeSessionAdapter(Connection* conn) = 0; /** - * Returns a PIA appropriate for this IP-based analyzer. + * Returns a PIA appropriate for this IP-based analyzer. This method is optional to + * override in child classes, as not all analyzers need a PIA. */ virtual analyzer::pia::PIA* MakePIA(Connection* conn) { return nullptr; } @@ -145,44 +146,4 @@ private: uint32_t server_port_mask; }; -/** - * This class represents the interface between the packet analysis framework and - * the session analysis framework. One of these should be implemented for each - * packet analyzer that intends to forward into the session analysis. - */ -class IPBasedTransportAnalyzer : public zeek::analyzer::TransportLayerAnalyzer { - -public: - - IPBasedTransportAnalyzer(const char* name, Connection* conn) - : TransportLayerAnalyzer(name, conn) { } - - /** - * Sets the parent packet analyzer for this transport analyzer. This can't be passed to - * the constructor due to the way that TransportLayerAnalyzer gets instantiated. - * - * @param p The parent packet analyzer to store - */ - void SetParent(IPBasedAnalyzer* p) { parent = p; } - - /** - * Returns true if the analyzer determines that in fact a new connection has started - * without the connection statement having terminated the previous one, i.e., the new - * data is arriving at what's the analyzer for the previous instance. This is used only - * for TCP. - */ - bool IsReuse(double t, const u_char* pkt) override { return parent->IsReuse(t, pkt); } - - /** - * Pure virtual method to allow extra session analzyers to be added to this analyzer's - * tree of children. This is used by analyzer::Manager when creating the session analyzer - * tree. - */ - virtual void AddExtraAnalyzers(Connection* conn) = 0; - -protected: - - IPBasedAnalyzer* parent; -}; - } diff --git a/src/packet_analysis/protocol/ip/SessionAdapter.cc b/src/packet_analysis/protocol/ip/SessionAdapter.cc new file mode 100644 index 0000000000..15210328eb --- /dev/null +++ b/src/packet_analysis/protocol/ip/SessionAdapter.cc @@ -0,0 +1,39 @@ +#include "zeek/packet_analysis/protocol/ip/SessionAdapter.h" + +#include "zeek/File.h" +#include "zeek/ZeekString.h" +#include "zeek/packet_analysis/protocol/ip/IPBasedAnalyzer.h" + +using namespace zeek::packet_analysis::IP; + +void SessionAdapter::Done() + { + Analyzer::Done(); + } + +bool SessionAdapter::IsReuse(double t, const u_char* pkt) + { + return parent->IsReuse(t, pkt); + } + +void SessionAdapter::SetContentsFile(unsigned int /* direction */, + FilePtr /* f */) + { + reporter->Error("analyzer type does not support writing to a contents file"); + } + +zeek::FilePtr SessionAdapter::GetContentsFile(unsigned int /* direction */) const + { + reporter->Error("analyzer type does not support writing to a contents file"); + return nullptr; + } + +void SessionAdapter::PacketContents(const u_char* data, int len) + { + if ( packet_contents && len > 0 ) + { + zeek::String* cbs = new zeek::String(data, len, true); + auto contents = make_intrusive(cbs); + EnqueueConnEvent(packet_contents, ConnVal(), std::move(contents)); + } + } diff --git a/src/packet_analysis/protocol/ip/SessionAdapter.h b/src/packet_analysis/protocol/ip/SessionAdapter.h new file mode 100644 index 0000000000..71c9a58016 --- /dev/null +++ b/src/packet_analysis/protocol/ip/SessionAdapter.h @@ -0,0 +1,102 @@ +#pragma once + +#include "zeek/analyzer/Analyzer.h" + +namespace zeek::analyzer::pia { class PIA; } + +namespace zeek::packet_analysis::IP { + +class IPBasedAnalyzer; + +/** + * This class represents the interface between the packet analysis framework and + * the session analysis framework. One of these should be implemented for each + * packet analyzer that intends to forward into the session analysis. + */ +class SessionAdapter : public analyzer::Analyzer { + +public: + + SessionAdapter(const char* name, Connection* conn) + : analyzer::Analyzer(name, conn) { } + + /** + * Overridden from parent class. + */ + virtual void Done() override; + + /** + * Sets the parent packet analyzer for this session adapter. This can't be passed to + * the constructor due to the way that SessionAdapter gets instantiated. + * + * @param p The parent packet analyzer to store + */ + void SetParent(IPBasedAnalyzer* p) { parent = p; } + + /** + * Returns true if the analyzer determines that in fact a new connection has started + * without the connection statement having terminated the previous one, i.e., the new + * data is arriving at what's the analyzer for the previous instance. This is used only + * for TCP. + */ + virtual bool IsReuse(double t, const u_char* pkt); + + /** + * Pure virtual method to allow extra session analzyers to be added to this analyzer's + * tree of children. This is used by analyzer::Manager when creating the session analyzer + * tree. + */ + virtual void AddExtraAnalyzers(Connection* conn) = 0; + + /** + * Associates a file with the analyzer in which to record all + * analyzed input. This must only be called with derived classes that + * overide the method; the default implementation will abort. + * + * @param direction One of the CONTENTS_* constants indicating which + * direction of the input stream is to be recorded. + * + * @param f The file to record to. + * + */ + virtual void SetContentsFile(unsigned int direction, FilePtr f); + + /** + * Returns an associated contents file, if any. This must only be + * called with derived classes that overide the method; the default + * implementation will abort. + * + * @param direction One of the CONTENTS_* constants indicating which + * direction the query is for. + */ + virtual FilePtr GetContentsFile(unsigned int direction) const; + + /** + * Associates a PIA with this analyzer. A PIA takes the + * transport-layer input and determine which protocol analyzer(s) to + * use for parsing it. + */ + void SetPIA(analyzer::pia::PIA* arg_PIA) { pia = arg_PIA; } + + /** + * Returns the associated PIA, or null of none. Does not take + * ownership. + */ + analyzer::pia::PIA* GetPIA() const { return pia; } + + /** + * Helper to raise a \c packet_contents event. + * + * @param data The dass to pass to the event. + * + * @param len The length of \a data. + */ + void PacketContents(const u_char* data, int len); + +protected: + + IPBasedAnalyzer* parent; + analyzer::pia::PIA* pia; +}; + +} // namespace zeek::packet_analysis::IP diff --git a/src/packet_analysis/protocol/tcp/TCP.h b/src/packet_analysis/protocol/tcp/TCP.h index 88f6d4dd47..cb5ec8e214 100644 --- a/src/packet_analysis/protocol/tcp/TCP.h +++ b/src/packet_analysis/protocol/tcp/TCP.h @@ -18,6 +18,15 @@ public: return std::make_shared(); } + /** + * Returns an adapter appropriate for this IP-based analyzer. This adapter is used to + * hook into the session analyzer framework. This function can also be used to do any + * extra initialization of connection timers, etc. + * + * TODO: this is a stub until the TCP analyzer moves to the packet analysis framework. + */ + IP::SessionAdapter* MakeSessionAdapter(Connection* conn) override { return nullptr; } + protected: /** diff --git a/src/packet_analysis/protocol/udp/Plugin.cc b/src/packet_analysis/protocol/udp/Plugin.cc index 7c77be6fc5..3ccab7b7d4 100644 --- a/src/packet_analysis/protocol/udp/Plugin.cc +++ b/src/packet_analysis/protocol/udp/Plugin.cc @@ -13,7 +13,7 @@ public: AddComponent(new zeek::packet_analysis::Component("UDP", zeek::packet_analysis::UDP::UDPAnalyzer::Instantiate)); AddComponent(new zeek::analyzer::Component("UDP", - zeek::packet_analysis::UDP::UDPTransportAnalyzer::Instantiate)); + zeek::packet_analysis::UDP::UDPSessionAdapter::Instantiate)); zeek::plugin::Configuration config; config.name = "Zeek::UDP"; diff --git a/src/packet_analysis/protocol/udp/UDP.cc b/src/packet_analysis/protocol/udp/UDP.cc index 749ed1c661..30c038c9e6 100644 --- a/src/packet_analysis/protocol/udp/UDP.cc +++ b/src/packet_analysis/protocol/udp/UDP.cc @@ -33,9 +33,9 @@ UDPAnalyzer::~UDPAnalyzer() { } -IPBasedTransportAnalyzer* UDPAnalyzer::MakeTransportAnalyzer(Connection* conn) +SessionAdapter* UDPAnalyzer::MakeSessionAdapter(Connection* conn) { - auto* root = new UDPTransportAnalyzer(conn); + auto* root = new UDPSessionAdapter(conn); root->SetParent(this); conn->EnableStatusUpdateTimer(); @@ -95,7 +95,7 @@ void UDPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int remai { conn = c; - auto* ta = static_cast(conn->GetRootAnalyzer()); + auto* adapter = static_cast(conn->GetSessionAdapter()); const u_char* data = pkt->ip_hdr->Payload(); int len = pkt->ip_hdr->PayloadLen(); @@ -103,7 +103,7 @@ void UDPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int remai const struct udphdr* up = (const struct udphdr*) data; const std::unique_ptr& ip = pkt->ip_hdr; - ta->DeliverPacket(len, data, is_orig, -1, ip.get(), remaining); + adapter->DeliverPacket(len, data, is_orig, -1, ip.get(), remaining); // Increment data before checksum check so that data will // point to UDP payload even if checksum fails. Particularly, @@ -113,7 +113,7 @@ void UDPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int remai // We need the min() here because Ethernet frame padding can lead to // remaining > len. if ( packet_contents ) - ta->PacketContents(data, std::min(len, remaining) - sizeof(struct udphdr)); + adapter->PacketContents(data, std::min(len, remaining) - sizeof(struct udphdr)); int chksum = up->uh_sum; @@ -159,24 +159,24 @@ void UDPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int remai if ( bad ) { - ta->Weird("bad_UDP_checksum"); + adapter->Weird("bad_UDP_checksum"); if ( is_orig ) { - uint32_t t = ta->req_chk_thresh; + uint32_t t = adapter->req_chk_thresh; if ( conn->ScaledHistoryEntry('C', - ta->req_chk_cnt, - ta->req_chk_thresh) ) + adapter->req_chk_cnt, + adapter->req_chk_thresh) ) ChecksumEvent(is_orig, t); } else { - uint32_t t = ta->rep_chk_thresh; + uint32_t t = adapter->rep_chk_thresh; if ( conn->ScaledHistoryEntry('c', - ta->rep_chk_cnt, - ta->rep_chk_thresh) ) + adapter->rep_chk_cnt, + adapter->rep_chk_thresh) ) ChecksumEvent(is_orig, t); } @@ -186,7 +186,7 @@ void UDPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int remai int ulen = ntohs(up->uh_ulen); if ( ulen != len ) - ta->Weird("UDP_datagram_length_mismatch", util::fmt("%d != %d", ulen, len)); + adapter->Weird("UDP_datagram_length_mismatch", util::fmt("%d != %d", ulen, len)); len -= sizeof(struct udphdr); ulen -= sizeof(struct udphdr); @@ -229,8 +229,8 @@ void UDPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int remai } if ( do_udp_contents ) - ta->EnqueueConnEvent(udp_contents, - ta->ConnVal(), + adapter->EnqueueConnEvent(udp_contents, + adapter->ConnVal(), val_mgr->Bool(is_orig), make_intrusive(len, (const char*) data)); } @@ -238,14 +238,14 @@ void UDPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int remai if ( is_orig ) { conn->CheckHistory(HIST_ORIG_DATA_PKT, 'D'); - ta->UpdateLength(is_orig, ulen); - ta->Event(udp_request); + adapter->UpdateLength(is_orig, ulen); + adapter->Event(udp_request); } else { conn->CheckHistory(HIST_RESP_DATA_PKT, 'd'); - ta->UpdateLength(is_orig, ulen); - ta->Event(udp_reply); + adapter->UpdateLength(is_orig, ulen); + adapter->Event(udp_reply); } // Send the packet back into the packet analysis framework. @@ -253,7 +253,7 @@ void UDPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int remai // Also try sending it into session analysis. if ( remaining >= len ) - ta->ForwardPacket(len, data, is_orig, -1, ip.get(), remaining); + adapter->ForwardPacket(len, data, is_orig, -1, ip.get(), remaining); conn = nullptr; } @@ -272,7 +272,7 @@ void UDPAnalyzer::ChecksumEvent(bool is_orig, uint32_t threshold) conn->HistoryThresholdEvent(udp_multiple_checksum_errors, is_orig, threshold); } -void UDPTransportAnalyzer::AddExtraAnalyzers(Connection* conn) +void UDPSessionAdapter::AddExtraAnalyzers(Connection* conn) { static analyzer::Tag analyzer_connsize = analyzer_mgr->GetComponentTag("CONNSIZE"); @@ -281,7 +281,7 @@ void UDPTransportAnalyzer::AddExtraAnalyzers(Connection* conn) AddChildAnalyzer(new analyzer::conn_size::ConnSize_Analyzer(conn)); } -void UDPTransportAnalyzer::UpdateConnVal(RecordVal* conn_val) +void UDPSessionAdapter::UpdateConnVal(RecordVal* conn_val) { auto orig_endp = conn_val->GetField("orig"); auto resp_endp = conn_val->GetField("resp"); @@ -293,7 +293,7 @@ void UDPTransportAnalyzer::UpdateConnVal(RecordVal* conn_val) Analyzer::UpdateConnVal(conn_val); } -void UDPTransportAnalyzer::UpdateEndpointVal(const ValPtr& endp_arg, bool is_orig) +void UDPSessionAdapter::UpdateEndpointVal(const ValPtr& endp_arg, bool is_orig) { bro_int_t size = is_orig ? request_len : reply_len; auto endp = endp_arg->AsRecordVal(); @@ -311,7 +311,7 @@ void UDPTransportAnalyzer::UpdateEndpointVal(const ValPtr& endp_arg, bool is_ori } } -void UDPTransportAnalyzer::UpdateLength(bool is_orig, int len) +void UDPSessionAdapter::UpdateLength(bool is_orig, int len) { if ( is_orig ) { diff --git a/src/packet_analysis/protocol/udp/UDP.h b/src/packet_analysis/protocol/udp/UDP.h index 78657d8173..45a4f9ef65 100644 --- a/src/packet_analysis/protocol/udp/UDP.h +++ b/src/packet_analysis/protocol/udp/UDP.h @@ -51,7 +51,7 @@ protected: bool WantConnection(uint16_t src_port, uint16_t dst_port, const u_char* data, bool& flip_roles) const override; - packet_analysis::IP::IPBasedTransportAnalyzer* MakeTransportAnalyzer(Connection* conn) override; + packet_analysis::IP::SessionAdapter* MakeSessionAdapter(Connection* conn) override; analyzer::pia::PIA* MakePIA(Connection* conn) override; private: @@ -67,16 +67,16 @@ private: std::vector vxlan_ports; }; -class UDPTransportAnalyzer final : public IP::IPBasedTransportAnalyzer { +class UDPSessionAdapter final : public IP::SessionAdapter { public: - UDPTransportAnalyzer(Connection* conn) : - IP::IPBasedTransportAnalyzer("UDP", conn) { } + UDPSessionAdapter(Connection* conn) : + IP::SessionAdapter("UDP", conn) { } static zeek::analyzer::Analyzer* Instantiate(Connection* conn) { - return new UDPTransportAnalyzer(conn); + return new UDPSessionAdapter(conn); } void AddExtraAnalyzers(Connection* conn) override; @@ -85,8 +85,7 @@ public: void UpdateLength(bool is_orig, int len); // For tracking checksum history. These are connection-specific so they - // need to be stored in the transport analyzer created for each - // connection. + // need to be stored in the session adapter created for each connection. uint32_t req_chk_cnt = 0; uint32_t req_chk_thresh = 1; uint32_t rep_chk_cnt = 0; From 30ab914cd878b3fb9c2672ce763da0e54e055190 Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Tue, 18 May 2021 12:10:38 -0700 Subject: [PATCH 09/10] Move bad UDP checksum handling into adapter object --- src/packet_analysis/protocol/udp/UDP.cc | 66 ++++++++++++------------- src/packet_analysis/protocol/udp/UDP.h | 6 +-- 2 files changed, 33 insertions(+), 39 deletions(-) diff --git a/src/packet_analysis/protocol/udp/UDP.cc b/src/packet_analysis/protocol/udp/UDP.cc index 30c038c9e6..ffb2693e9d 100644 --- a/src/packet_analysis/protocol/udp/UDP.cc +++ b/src/packet_analysis/protocol/udp/UDP.cc @@ -93,9 +93,7 @@ bool UDPAnalyzer::BuildConnTuple(size_t len, const uint8_t* data, Packet* packet void UDPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int remaining, Packet* pkt) { - conn = c; - - auto* adapter = static_cast(conn->GetSessionAdapter()); + auto* adapter = static_cast(c->GetSessionAdapter()); const u_char* data = pkt->ip_hdr->Payload(); int len = pkt->ip_hdr->PayloadLen(); @@ -159,27 +157,7 @@ void UDPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int remai if ( bad ) { - adapter->Weird("bad_UDP_checksum"); - - if ( is_orig ) - { - uint32_t t = adapter->req_chk_thresh; - - if ( conn->ScaledHistoryEntry('C', - adapter->req_chk_cnt, - adapter->req_chk_thresh) ) - ChecksumEvent(is_orig, t); - } - else - { - uint32_t t = adapter->rep_chk_thresh; - - if ( conn->ScaledHistoryEntry('c', - adapter->rep_chk_cnt, - adapter->rep_chk_thresh) ) - ChecksumEvent(is_orig, t); - } - + adapter->HandleBadChecksum(is_orig); return; } } @@ -192,7 +170,7 @@ void UDPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int remai ulen -= sizeof(struct udphdr); remaining -= sizeof(struct udphdr); - conn->SetLastTime(run_state::current_timestamp); + c->SetLastTime(run_state::current_timestamp); if ( udp_contents ) { @@ -208,7 +186,7 @@ void UDPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int remai do_udp_contents = true; else { - uint16_t p = zeek::detail::udp_content_delivery_ports_use_resp ? conn->RespPort() + uint16_t p = zeek::detail::udp_content_delivery_ports_use_resp ? c->RespPort() : up->uh_dport; const auto& port_val = zeek::val_mgr->Port(ntohs(p), TRANSPORT_UDP); @@ -237,13 +215,13 @@ void UDPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int remai if ( is_orig ) { - conn->CheckHistory(HIST_ORIG_DATA_PKT, 'D'); + c->CheckHistory(HIST_ORIG_DATA_PKT, 'D'); adapter->UpdateLength(is_orig, ulen); adapter->Event(udp_request); } else { - conn->CheckHistory(HIST_RESP_DATA_PKT, 'd'); + c->CheckHistory(HIST_RESP_DATA_PKT, 'd'); adapter->UpdateLength(is_orig, ulen); adapter->Event(udp_reply); } @@ -254,8 +232,6 @@ void UDPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int remai // Also try sending it into session analysis. if ( remaining >= len ) adapter->ForwardPacket(len, data, is_orig, -1, ip.get(), remaining); - - conn = nullptr; } bool UDPAnalyzer::ValidateChecksum(const IP_Hdr* ip, const udphdr* up, int len) @@ -267,11 +243,6 @@ bool UDPAnalyzer::ValidateChecksum(const IP_Hdr* ip, const udphdr* up, int len) return sum == 0xffff; } -void UDPAnalyzer::ChecksumEvent(bool is_orig, uint32_t threshold) - { - conn->HistoryThresholdEvent(udp_multiple_checksum_errors, is_orig, threshold); - } - void UDPSessionAdapter::AddExtraAnalyzers(Connection* conn) { static analyzer::Tag analyzer_connsize = analyzer_mgr->GetComponentTag("CONNSIZE"); @@ -340,3 +311,28 @@ void UDPSessionAdapter::UpdateLength(bool is_orig, int len) } } } + +void UDPSessionAdapter::HandleBadChecksum(bool is_orig) + { + Weird("bad_UDP_checksum"); + + if ( is_orig ) + { + uint32_t t = req_chk_thresh; + + if ( Conn()->ScaledHistoryEntry('C', req_chk_cnt, req_chk_thresh) ) + ChecksumEvent(is_orig, t); + } + else + { + uint32_t t = rep_chk_thresh; + + if ( Conn()->ScaledHistoryEntry('c', rep_chk_cnt, rep_chk_thresh) ) + ChecksumEvent(is_orig, t); + } + } + +void UDPSessionAdapter::ChecksumEvent(bool is_orig, uint32_t threshold) + { + Conn()->HistoryThresholdEvent(udp_multiple_checksum_errors, is_orig, threshold); + } diff --git a/src/packet_analysis/protocol/udp/UDP.h b/src/packet_analysis/protocol/udp/UDP.h index 45a4f9ef65..78fd0ce481 100644 --- a/src/packet_analysis/protocol/udp/UDP.h +++ b/src/packet_analysis/protocol/udp/UDP.h @@ -60,10 +60,6 @@ private: static bool ValidateChecksum(const IP_Hdr* ip, const struct udphdr* up, int len); - void ChecksumEvent(bool is_orig, uint32_t threshold); - - Connection* conn; - std::vector vxlan_ports; }; @@ -83,6 +79,7 @@ public: void UpdateConnVal(RecordVal* conn_val) override; void UpdateLength(bool is_orig, int len); + void HandleBadChecksum(bool is_orig); // For tracking checksum history. These are connection-specific so they // need to be stored in the session adapter created for each connection. @@ -94,6 +91,7 @@ public: private: void UpdateEndpointVal(const ValPtr& endp_arg, bool is_orig); + void ChecksumEvent(bool is_orig, uint32_t threshold); bro_int_t request_len = -1; bro_int_t reply_len = -1; From 3a8047f5356bbd73ec2036df254837eabdafc821 Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Thu, 20 May 2021 11:00:11 -0700 Subject: [PATCH 10/10] Add type field to session::Key to help avoid collisions in map --- src/Conn.h | 5 ++++- src/session/Key.cc | 5 ++++- src/session/Key.h | 9 ++++++++- src/session/Manager.cc | 14 ++++---------- 4 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/Conn.h b/src/Conn.h index 20a5b138c4..19d5d943d3 100644 --- a/src/Conn.h +++ b/src/Conn.h @@ -113,7 +113,10 @@ public: // should be marked invalid. const detail::ConnKey& Key() const { return key; } session::detail::Key SessionKey(bool copy) const override - { return session::detail::Key{&key, sizeof(key), copy}; } + { + return session::detail::Key{ + &key, sizeof(key), session::detail::Key::CONNECTION_KEY_TYPE, copy}; + } const IPAddr& OrigAddr() const { return orig_addr; } const IPAddr& RespAddr() const { return resp_addr; } diff --git a/src/session/Key.cc b/src/session/Key.cc index 6044f493f8..5c7317505c 100644 --- a/src/session/Key.cc +++ b/src/session/Key.cc @@ -4,7 +4,8 @@ namespace zeek::session::detail { -Key::Key(const void* session, size_t size, bool copy) : size(size) +Key::Key(const void* session, size_t size, size_t type, bool copy) : + size(size), type(type) { data = reinterpret_cast(session); @@ -63,6 +64,8 @@ bool Key::operator<(const Key& rhs) const { if ( size != rhs.size ) return size < rhs.size; + else if ( type != rhs.type ) + return type < rhs.type; return memcmp(data, rhs.data, size) < 0; } diff --git a/src/session/Key.h b/src/session/Key.h index f07ec8996b..7201fbcaa5 100644 --- a/src/session/Key.h +++ b/src/session/Key.h @@ -20,16 +20,22 @@ namespace zeek::session::detail { class Key final { public: + const static size_t CONNECTION_KEY_TYPE=0; + /** * Create a new session key from a data pointer. * * @param session A pointer to the data for the key. * @param size The size of the key data, in bytes. + * @param type An identifier for the type of this key. The value used should be + * unique across all types of session keys. CONNECTION_KEY_TYPE (0) is used by + * Connection sessions and is reserved. This value is used to avoid collisions + * when doing comparisons of the memory stored by keys. * @param copy Flag for whether the data should be copied into the Key * during construction. This defaults to false because normally the only time * data is copied into the key is when it's inserted into the session map. */ - Key(const void* key_data, size_t size, bool copy=false); + Key(const void* key_data, size_t size, size_t type, bool copy=false); ~Key(); @@ -55,6 +61,7 @@ public: private: const uint8_t* data = nullptr; size_t size = 0; + size_t type = CONNECTION_KEY_TYPE; bool copied = false; }; diff --git a/src/session/Manager.cc b/src/session/Manager.cc index df027c82cf..82ee11b217 100644 --- a/src/session/Manager.cc +++ b/src/session/Manager.cc @@ -149,23 +149,17 @@ Connection* Manager::FindConnection(Val* v) htons((unsigned short) resp_portv->Port()), orig_portv->PortType(), false); - detail::Key key(&conn_key, sizeof(conn_key), false); - - Connection* conn = nullptr; - auto it = session_map.find(key); - if ( it != session_map.end() ) - conn = static_cast(it->second); - - return conn; + return FindConnection(conn_key); } Connection* Manager::FindConnection(const zeek::detail::ConnKey& conn_key) { - detail::Key key(&conn_key, sizeof(conn_key), false); + detail::Key key(&conn_key, sizeof(conn_key), + detail::Key::CONNECTION_KEY_TYPE, false); auto it = session_map.find(key); if ( it != session_map.end() ) - return dynamic_cast(it->second); + return static_cast(it->second); return nullptr; }