From af5a0215c09883db6ac8795a7f04a1c2d7905f54 Mon Sep 17 00:00:00 2001 From: Arne Welzel Date: Thu, 29 Sep 2022 14:36:18 +0200 Subject: [PATCH] packet_analysis: Introduce PacketAnalyzer::__disable_analyzer() This adds machinery to the packet_analysis manager for disabling and enabling packet analyzers and implements two low-level bifs to use it. Extend Analyzer::enable_analyzer() and Analyzer::disable_analyzer() to transparently work with packet analyzers, too. This also allows to add packet analyzers to Analyzer::disabled_analyzers. --- NEWS | 6 +++ scripts/base/frameworks/analyzer/main.zeek | 16 +++++--- src/packet_analysis/Analyzer.cc | 8 ++++ src/packet_analysis/Analyzer.h | 15 +++++++ src/packet_analysis/Manager.cc | 24 +++++++++++ src/packet_analysis/Manager.h | 40 +++++++++++++++++++ src/packet_analysis/packet_analysis.bif | 14 +++++++ testing/btest/Baseline/plugins.hooks/output | 15 ++++--- .../output | 11 +++++ .../output | 17 ++++++++ .../analyzer/disabled-packet-analyzers.zeek | 21 ++++++++++ .../analyzer/toggle-packet-analyzers.zeek | 30 ++++++++++++++ 12 files changed, 206 insertions(+), 11 deletions(-) create mode 100644 testing/btest/Baseline/scripts.base.frameworks.analyzer.disabled-packet-analyzers/output create mode 100644 testing/btest/Baseline/scripts.base.frameworks.analyzer.toggle-packet-analyzers/output create mode 100644 testing/btest/scripts/base/frameworks/analyzer/disabled-packet-analyzers.zeek create mode 100644 testing/btest/scripts/base/frameworks/analyzer/toggle-packet-analyzers.zeek diff --git a/NEWS b/NEWS index b4541fb3ba..d4b07aae16 100644 --- a/NEWS +++ b/NEWS @@ -22,6 +22,12 @@ New Functionality - File analyzers can now raise analyzer violations to the script-layer via the new ``AnalyzerViolation()`` method. +- Packet analyzers can now be disabled and enabled at runtime using + the ``Analyzer::enable_analyzer()`` and ``Analyzer::disable_analyzer()`` + wrappers. While initially for protocol analyzers only, these have + been extended to work for packet analyzers, too. Packet analyzers can + be added to ``Analyzer::disabled_analyzers``, too. + Changed Functionality --------------------- diff --git a/scripts/base/frameworks/analyzer/main.zeek b/scripts/base/frameworks/analyzer/main.zeek index 18a8c97c52..a484ec3963 100644 --- a/scripts/base/frameworks/analyzer/main.zeek +++ b/scripts/base/frameworks/analyzer/main.zeek @@ -33,7 +33,7 @@ export { ## tag: The tag of the analyzer to enable. ## ## Returns: True if the analyzer was successfully enabled. - global enable_analyzer: function(tag: Analyzer::Tag) : bool; + global enable_analyzer: function(tag: AllAnalyzers::Tag) : bool; ## Disables an analyzer. Once disabled, the analyzer will not be used ## further for analysis of future connections. @@ -41,7 +41,7 @@ export { ## tag: The tag of the analyzer to disable. ## ## Returns: True if the analyzer was successfully disabled. - global disable_analyzer: function(tag: Analyzer::Tag) : bool; + global disable_analyzer: function(tag: AllAnalyzers::Tag) : bool; ## Registers a set of well-known ports for an analyzer. If a future ## connection on one of these ports is seen, the analyzer will be @@ -130,7 +130,7 @@ export { ## A set of analyzers to disable by default at startup. The default set ## contains legacy analyzers that are no longer supported. - global disabled_analyzers: set[Analyzer::Tag] = { + global disabled_analyzers: set[AllAnalyzers::Tag] = { ANALYZER_TCPSTATS, } &redef; @@ -152,13 +152,19 @@ event zeek_init() &priority=5 disable_analyzer(a); } -function enable_analyzer(tag: Analyzer::Tag) : bool +function enable_analyzer(tag: AllAnalyzers::Tag) : bool { + if ( is_packet_analyzer(tag) ) + return PacketAnalyzer::__enable_analyzer(tag); + return __enable_analyzer(tag); } -function disable_analyzer(tag: Analyzer::Tag) : bool +function disable_analyzer(tag: AllAnalyzers::Tag) : bool { + if ( is_packet_analyzer(tag) ) + return PacketAnalyzer::__disable_analyzer(tag); + return __disable_analyzer(tag); } diff --git a/src/packet_analysis/Analyzer.cc b/src/packet_analysis/Analyzer.cc index 0161b26ca5..afd21ec40f 100644 --- a/src/packet_analysis/Analyzer.cc +++ b/src/packet_analysis/Analyzer.cc @@ -107,6 +107,14 @@ bool Analyzer::ForwardPacket(size_t len, const uint8_t* data, Packet* packet, return false; } + if ( ! inner_analyzer->IsEnabled() ) + { + DBG_LOG(DBG_PACKET_ANALYSIS, + "Analysis in %s found disabled next layer analyzer %s for identifier %#x", + GetAnalyzerName(), inner_analyzer->GetAnalyzerName(), identifier); + return false; + } + DBG_LOG(DBG_PACKET_ANALYSIS, "Analysis in %s succeeded, next layer identifier is %#x.", GetAnalyzerName(), identifier); return inner_analyzer->AnalyzePacket(len, data, packet); diff --git a/src/packet_analysis/Analyzer.h b/src/packet_analysis/Analyzer.h index b3b36bafc9..e3c962a94e 100644 --- a/src/packet_analysis/Analyzer.h +++ b/src/packet_analysis/Analyzer.h @@ -71,6 +71,20 @@ public: */ bool IsAnalyzer(const char* name); + /** + * Enable or disable this analyzer. + * + * @param value The new enabled value. + */ + void SetEnabled(bool value) { enabled = value; } + + /** + * Return whether this analyzer is enabled or not. + * + * @return true if the analyzer is enabled, else false. + */ + bool IsEnabled() const { return enabled; } + /** * Analyzes the given packet. A common case is that the analyzed protocol * encapsulates another protocol, which can be determined by an identifier @@ -258,6 +272,7 @@ private: zeek::Tag tag; Dispatcher dispatcher; AnalyzerPtr default_analyzer = nullptr; + bool enabled = true; /** * Flag for whether to report unknown protocols in ForwardPacket. diff --git a/src/packet_analysis/Manager.cc b/src/packet_analysis/Manager.cc index 74cb92010a..e97fa3620e 100644 --- a/src/packet_analysis/Manager.cc +++ b/src/packet_analysis/Manager.cc @@ -88,6 +88,30 @@ AnalyzerPtr Manager::GetAnalyzer(const std::string& name) return analyzer_it->second; } +bool Manager::EnableAnalyzer(EnumVal* tag) + { + Component* c = Lookup(tag); + AnalyzerPtr a = GetAnalyzer(c->Name()); + if ( ! a ) + return false; + + a->SetEnabled(true); + + return true; + } + +bool Manager::DisableAnalyzer(EnumVal* tag) + { + Component* c = Lookup(tag); + AnalyzerPtr a = GetAnalyzer(c->Name()); + if ( ! a ) + return false; + + a->SetEnabled(false); + + return true; + } + void Manager::ProcessPacket(Packet* packet) { #ifdef DEBUG diff --git a/src/packet_analysis/Manager.h b/src/packet_analysis/Manager.h index 1ae50c2ef2..10f3eee88e 100644 --- a/src/packet_analysis/Manager.h +++ b/src/packet_analysis/Manager.h @@ -82,6 +82,46 @@ public: */ AnalyzerPtr GetAnalyzer(const std::string& name); + /** + * Enables an analyzer type. Only enabled analyzers will participate + * in packet processing. + * + * @param tag The analyzer's tag. + * + * @return True if successful. + */ + bool EnableAnalyzer(zeek::EnumVal* tag); + + /** + * Enables an analyzer type. Only enabled analyzers will participate + * in packet processing. + * + * @param tag The analyzer's tag. + * + * @return True if successful. + */ + bool EnableAnalyzer(const zeek::Tag& tag) { return EnableAnalyzer(tag.AsVal().get()); } + + /** + * Disables an analyzer type. Disabled analyzers will not participate + * in packet processing. + * + * @param tag The packet analyzer's tag. + * + * @return True if successful. + */ + bool DisableAnalyzer(zeek::EnumVal* tag); + + /** + * Disables an analyzer type. Disabled analyzers will not participate + * in packet processing. + * + * @param tag The packet analyzer's tag. + * + * @return True if successful. + */ + bool DisableAnalyzer(const zeek::Tag& tag) { return DisableAnalyzer(tag.AsVal().get()); }; + /** * Processes a packet by applying the configured packet analyzers. * diff --git a/src/packet_analysis/packet_analysis.bif b/src/packet_analysis/packet_analysis.bif index c3f6e18194..c90e2665c9 100644 --- a/src/packet_analysis/packet_analysis.bif +++ b/src/packet_analysis/packet_analysis.bif @@ -77,3 +77,17 @@ function register_protocol_detection%(parent: PacketAnalyzer::Tag, child: Packet parent_analyzer->RegisterProtocolDetection(child_analyzer); return zeek::val_mgr->True(); %} + +## Internal function to disable a packet analyzer. +function PacketAnalyzer::__disable_analyzer%(id: PacketAnalyzer::Tag%) : bool + %{ + bool result = zeek::packet_mgr->DisableAnalyzer(id->AsEnumVal()); + return zeek::val_mgr->Bool(result); + %} + +## Internal function to enable a packet analyzer. +function PacketAnalyzer::__enable_analyzer%(id: PacketAnalyzer::Tag%) : bool + %{ + bool result = zeek::packet_mgr->EnableAnalyzer(id->AsEnumVal()); + return zeek::val_mgr->Bool(result); + %} diff --git a/testing/btest/Baseline/plugins.hooks/output b/testing/btest/Baseline/plugins.hooks/output index 0771edcf12..328cdbc667 100644 --- a/testing/btest/Baseline/plugins.hooks/output +++ b/testing/btest/Baseline/plugins.hooks/output @@ -1,5 +1,5 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -0.000000 MetaHookPost CallFunction(Analyzer::__disable_analyzer, , (Analyzer::ANALYZER_TCPSTATS)) -> +0.000000 MetaHookPost CallFunction(Analyzer::__disable_analyzer, , (AllAnalyzers::ANALYZER_ANALYZER_TCPSTATS)) -> 0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_DCE_RPC, 135/tcp)) -> 0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_DHCP, 4011/udp)) -> 0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_DHCP, 67/udp)) -> @@ -59,7 +59,7 @@ 0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_SYSLOG, 514/udp)) -> 0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_XMPP, 5222/tcp)) -> 0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_XMPP, 5269/tcp)) -> -0.000000 MetaHookPost CallFunction(Analyzer::disable_analyzer, , (Analyzer::ANALYZER_TCPSTATS)) -> +0.000000 MetaHookPost CallFunction(Analyzer::disable_analyzer, , (AllAnalyzers::ANALYZER_ANALYZER_TCPSTATS)) -> 0.000000 MetaHookPost CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_DCE_RPC, 135/tcp)) -> 0.000000 MetaHookPost CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_DHCP, 4011/udp)) -> 0.000000 MetaHookPost CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_DHCP, 67/udp)) -> @@ -716,6 +716,7 @@ 0.000000 MetaHookPost CallFunction(getenv, , (ZEEK_DEFAULT_LISTEN_ADDRESS)) -> 0.000000 MetaHookPost CallFunction(global_options, , ()) -> 0.000000 MetaHookPost CallFunction(gsub, ..., ...) -> +0.000000 MetaHookPost CallFunction(is_packet_analyzer, , (AllAnalyzers::ANALYZER_ANALYZER_TCPSTATS)) -> 0.000000 MetaHookPost CallFunction(lstrip, ..., ...) -> 0.000000 MetaHookPost CallFunction(network_time, , ()) -> 0.000000 MetaHookPost CallFunction(port_to_count, , (2123/udp)) -> @@ -1512,7 +1513,7 @@ 0.000000 MetaHookPost QueueEvent(NetControl::init()) -> false 0.000000 MetaHookPost QueueEvent(filter_change_tracking()) -> false 0.000000 MetaHookPost QueueEvent(zeek_init()) -> false -0.000000 MetaHookPre CallFunction(Analyzer::__disable_analyzer, , (Analyzer::ANALYZER_TCPSTATS)) +0.000000 MetaHookPre CallFunction(Analyzer::__disable_analyzer, , (AllAnalyzers::ANALYZER_ANALYZER_TCPSTATS)) 0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_DCE_RPC, 135/tcp)) 0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_DHCP, 4011/udp)) 0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_DHCP, 67/udp)) @@ -1572,7 +1573,7 @@ 0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_SYSLOG, 514/udp)) 0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_XMPP, 5222/tcp)) 0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_XMPP, 5269/tcp)) -0.000000 MetaHookPre CallFunction(Analyzer::disable_analyzer, , (Analyzer::ANALYZER_TCPSTATS)) +0.000000 MetaHookPre CallFunction(Analyzer::disable_analyzer, , (AllAnalyzers::ANALYZER_ANALYZER_TCPSTATS)) 0.000000 MetaHookPre CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_DCE_RPC, 135/tcp)) 0.000000 MetaHookPre CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_DHCP, 4011/udp)) 0.000000 MetaHookPre CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_DHCP, 67/udp)) @@ -2229,6 +2230,7 @@ 0.000000 MetaHookPre CallFunction(getenv, , (ZEEK_DEFAULT_LISTEN_ADDRESS)) 0.000000 MetaHookPre CallFunction(global_options, , ()) 0.000000 MetaHookPre CallFunction(gsub, ..., ...) +0.000000 MetaHookPre CallFunction(is_packet_analyzer, , (AllAnalyzers::ANALYZER_ANALYZER_TCPSTATS)) 0.000000 MetaHookPre CallFunction(lstrip, ..., ...) 0.000000 MetaHookPre CallFunction(network_time, , ()) 0.000000 MetaHookPre CallFunction(port_to_count, , (2123/udp)) @@ -3025,7 +3027,7 @@ 0.000000 MetaHookPre QueueEvent(NetControl::init()) 0.000000 MetaHookPre QueueEvent(filter_change_tracking()) 0.000000 MetaHookPre QueueEvent(zeek_init()) -0.000000 | HookCallFunction Analyzer::__disable_analyzer(Analyzer::ANALYZER_TCPSTATS) +0.000000 | HookCallFunction Analyzer::__disable_analyzer(AllAnalyzers::ANALYZER_ANALYZER_TCPSTATS) 0.000000 | HookCallFunction Analyzer::__register_for_port(Analyzer::ANALYZER_DCE_RPC, 135/tcp) 0.000000 | HookCallFunction Analyzer::__register_for_port(Analyzer::ANALYZER_DHCP, 4011/udp) 0.000000 | HookCallFunction Analyzer::__register_for_port(Analyzer::ANALYZER_DHCP, 67/udp) @@ -3085,7 +3087,7 @@ 0.000000 | HookCallFunction Analyzer::__register_for_port(Analyzer::ANALYZER_SYSLOG, 514/udp) 0.000000 | HookCallFunction Analyzer::__register_for_port(Analyzer::ANALYZER_XMPP, 5222/tcp) 0.000000 | HookCallFunction Analyzer::__register_for_port(Analyzer::ANALYZER_XMPP, 5269/tcp) -0.000000 | HookCallFunction Analyzer::disable_analyzer(Analyzer::ANALYZER_TCPSTATS) +0.000000 | HookCallFunction Analyzer::disable_analyzer(AllAnalyzers::ANALYZER_ANALYZER_TCPSTATS) 0.000000 | HookCallFunction Analyzer::register_for_port(Analyzer::ANALYZER_DCE_RPC, 135/tcp) 0.000000 | HookCallFunction Analyzer::register_for_port(Analyzer::ANALYZER_DHCP, 4011/udp) 0.000000 | HookCallFunction Analyzer::register_for_port(Analyzer::ANALYZER_DHCP, 67/udp) @@ -3741,6 +3743,7 @@ 0.000000 | HookCallFunction getenv(ZEEK_DEFAULT_LISTEN_ADDRESS) 0.000000 | HookCallFunction global_options() 0.000000 | HookCallFunction gsub(...) +0.000000 | HookCallFunction is_packet_analyzer(AllAnalyzers::ANALYZER_ANALYZER_TCPSTATS) 0.000000 | HookCallFunction lstrip(...) 0.000000 | HookCallFunction network_time() 0.000000 | HookCallFunction port_to_count(2123/udp) diff --git a/testing/btest/Baseline/scripts.base.frameworks.analyzer.disabled-packet-analyzers/output b/testing/btest/Baseline/scripts.base.frameworks.analyzer.disabled-packet-analyzers/output new file mode 100644 index 0000000000..c151611fd1 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.frameworks.analyzer.disabled-packet-analyzers/output @@ -0,0 +1,11 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +packet, 1 +packet, 2 +packet, 3 +packet, 4 +packet, 5 +packet, 6 +packet, 7 +packet, 8 +packet, 9 +packet, 10 diff --git a/testing/btest/Baseline/scripts.base.frameworks.analyzer.toggle-packet-analyzers/output b/testing/btest/Baseline/scripts.base.frameworks.analyzer.toggle-packet-analyzers/output new file mode 100644 index 0000000000..39cd890e18 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.frameworks.analyzer.toggle-packet-analyzers/output @@ -0,0 +1,17 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +packet, 1 +packet, 2 +vxlan_packet, C4J4Th3PJpwUYZZ6gc, inner, [hl=20, tos=0, len=84, id=12111, ttl=64, p=1, src=10.0.0.1, dst=10.0.0.2] +packet, 3 +vxlan_packet, CtPZjS20MLrsMUOJi2, inner, [hl=20, tos=0, len=84, id=36913, ttl=64, p=1, src=10.0.0.2, dst=10.0.0.1] +packet, 4 +Analyzer::disable_analyzer(PacketAnalyzer::ANALYZER_VXLAN), T +packet, 5 +packet, 6 +packet, 7 +packet, 8 +Analyzer::enable_analyzer(PacketAnalyzer::ANALYZER_VXLAN), T +vxlan_packet, C4J4Th3PJpwUYZZ6gc, inner, [hl=20, tos=0, len=84, id=12684, ttl=64, p=1, src=10.0.0.1, dst=10.0.0.2] +packet, 9 +vxlan_packet, CtPZjS20MLrsMUOJi2, inner, [hl=20, tos=0, len=84, id=37295, ttl=64, p=1, src=10.0.0.2, dst=10.0.0.1] +packet, 10 diff --git a/testing/btest/scripts/base/frameworks/analyzer/disabled-packet-analyzers.zeek b/testing/btest/scripts/base/frameworks/analyzer/disabled-packet-analyzers.zeek new file mode 100644 index 0000000000..ac7a843ac1 --- /dev/null +++ b/testing/btest/scripts/base/frameworks/analyzer/disabled-packet-analyzers.zeek @@ -0,0 +1,21 @@ +# @TEST-DOC: Add a packet analyzer to Analyzer::disabled_analyzers and ensure it does not generate events (vxlan in this case). +# @TEST-EXEC: zeek -b -r $TRACES/tunnels/vxlan.pcap %INPUT > output +# @TEST-EXEC: btest-diff output +# + +# Removing this line triggers vxlan events from all but the first two packets. +redef Analyzer::disabled_analyzers += { PacketAnalyzer::ANALYZER_VXLAN }; + +global all_packets = 0; + +event raw_packet(hdr: raw_pkt_hdr) + { + ++all_packets; + print "packet", all_packets; + } + +# Should never run. +event vxlan_packet(outer: connection, inner: pkt_hdr, vni: count) + { + print "vxlan_packet", outer$uid, "inner", inner$ip; + } diff --git a/testing/btest/scripts/base/frameworks/analyzer/toggle-packet-analyzers.zeek b/testing/btest/scripts/base/frameworks/analyzer/toggle-packet-analyzers.zeek new file mode 100644 index 0000000000..946f9e1148 --- /dev/null +++ b/testing/btest/scripts/base/frameworks/analyzer/toggle-packet-analyzers.zeek @@ -0,0 +1,30 @@ +# @TEST-DOC: Use Analyzer::disable_analyzer() and Analyzer::enable_analyzer() to disable the VXLAN packet analyzers at runtime based on total raw packet count. +# @TEST-EXEC: zeek -b -r $TRACES/tunnels/vxlan.pcap %INPUT > output +# @TEST-EXEC: btest-diff output +# + +global all_packets = 0; + +event raw_packet(hdr: raw_pkt_hdr) + { + ++all_packets; + print "packet", all_packets; + + if ( all_packets == 4 ) + { + local er = Analyzer::disable_analyzer(PacketAnalyzer::ANALYZER_VXLAN); + print "Analyzer::disable_analyzer(PacketAnalyzer::ANALYZER_VXLAN)", er; + } + # Packets 5 to 8 don't produce vxlan_packet events. + + if ( all_packets == 8 ) + { + local dr = Analyzer::enable_analyzer(PacketAnalyzer::ANALYZER_VXLAN); + print "Analyzer::enable_analyzer(PacketAnalyzer::ANALYZER_VXLAN)", dr; + } + } + +event vxlan_packet(outer: connection, inner: pkt_hdr, vni: count) + { + print "vxlan_packet", outer$uid, "inner", inner$ip; + }