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.
This commit is contained in:
Arne Welzel 2022-09-29 14:36:18 +02:00
parent 0d5c669c1c
commit af5a0215c0
12 changed files with 206 additions and 11 deletions

6
NEWS
View file

@ -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
---------------------

View file

@ -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);
}

View file

@ -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);

View file

@ -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.

View file

@ -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

View file

@ -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.
*

View file

@ -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);
%}

View file

@ -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, <frame>, (Analyzer::ANALYZER_TCPSTATS)) -> <no result>
0.000000 MetaHookPost CallFunction(Analyzer::__disable_analyzer, <frame>, (AllAnalyzers::ANALYZER_ANALYZER_TCPSTATS)) -> <no result>
0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, <frame>, (Analyzer::ANALYZER_DCE_RPC, 135/tcp)) -> <no result>
0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, <frame>, (Analyzer::ANALYZER_DHCP, 4011/udp)) -> <no result>
0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, <frame>, (Analyzer::ANALYZER_DHCP, 67/udp)) -> <no result>
@ -59,7 +59,7 @@
0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, <frame>, (Analyzer::ANALYZER_SYSLOG, 514/udp)) -> <no result>
0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, <frame>, (Analyzer::ANALYZER_XMPP, 5222/tcp)) -> <no result>
0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, <frame>, (Analyzer::ANALYZER_XMPP, 5269/tcp)) -> <no result>
0.000000 MetaHookPost CallFunction(Analyzer::disable_analyzer, <frame>, (Analyzer::ANALYZER_TCPSTATS)) -> <no result>
0.000000 MetaHookPost CallFunction(Analyzer::disable_analyzer, <frame>, (AllAnalyzers::ANALYZER_ANALYZER_TCPSTATS)) -> <no result>
0.000000 MetaHookPost CallFunction(Analyzer::register_for_port, <frame>, (Analyzer::ANALYZER_DCE_RPC, 135/tcp)) -> <no result>
0.000000 MetaHookPost CallFunction(Analyzer::register_for_port, <frame>, (Analyzer::ANALYZER_DHCP, 4011/udp)) -> <no result>
0.000000 MetaHookPost CallFunction(Analyzer::register_for_port, <frame>, (Analyzer::ANALYZER_DHCP, 67/udp)) -> <no result>
@ -716,6 +716,7 @@
0.000000 MetaHookPost CallFunction(getenv, <null>, (ZEEK_DEFAULT_LISTEN_ADDRESS)) -> <no result>
0.000000 MetaHookPost CallFunction(global_options, <frame>, ()) -> <no result>
0.000000 MetaHookPost CallFunction(gsub, ..., ...) -> <no result>
0.000000 MetaHookPost CallFunction(is_packet_analyzer, <frame>, (AllAnalyzers::ANALYZER_ANALYZER_TCPSTATS)) -> <no result>
0.000000 MetaHookPost CallFunction(lstrip, ..., ...) -> <no result>
0.000000 MetaHookPost CallFunction(network_time, <frame>, ()) -> <no result>
0.000000 MetaHookPost CallFunction(port_to_count, <frame>, (2123/udp)) -> <no result>
@ -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, <frame>, (Analyzer::ANALYZER_TCPSTATS))
0.000000 MetaHookPre CallFunction(Analyzer::__disable_analyzer, <frame>, (AllAnalyzers::ANALYZER_ANALYZER_TCPSTATS))
0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, <frame>, (Analyzer::ANALYZER_DCE_RPC, 135/tcp))
0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, <frame>, (Analyzer::ANALYZER_DHCP, 4011/udp))
0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, <frame>, (Analyzer::ANALYZER_DHCP, 67/udp))
@ -1572,7 +1573,7 @@
0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, <frame>, (Analyzer::ANALYZER_SYSLOG, 514/udp))
0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, <frame>, (Analyzer::ANALYZER_XMPP, 5222/tcp))
0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, <frame>, (Analyzer::ANALYZER_XMPP, 5269/tcp))
0.000000 MetaHookPre CallFunction(Analyzer::disable_analyzer, <frame>, (Analyzer::ANALYZER_TCPSTATS))
0.000000 MetaHookPre CallFunction(Analyzer::disable_analyzer, <frame>, (AllAnalyzers::ANALYZER_ANALYZER_TCPSTATS))
0.000000 MetaHookPre CallFunction(Analyzer::register_for_port, <frame>, (Analyzer::ANALYZER_DCE_RPC, 135/tcp))
0.000000 MetaHookPre CallFunction(Analyzer::register_for_port, <frame>, (Analyzer::ANALYZER_DHCP, 4011/udp))
0.000000 MetaHookPre CallFunction(Analyzer::register_for_port, <frame>, (Analyzer::ANALYZER_DHCP, 67/udp))
@ -2229,6 +2230,7 @@
0.000000 MetaHookPre CallFunction(getenv, <null>, (ZEEK_DEFAULT_LISTEN_ADDRESS))
0.000000 MetaHookPre CallFunction(global_options, <frame>, ())
0.000000 MetaHookPre CallFunction(gsub, ..., ...)
0.000000 MetaHookPre CallFunction(is_packet_analyzer, <frame>, (AllAnalyzers::ANALYZER_ANALYZER_TCPSTATS))
0.000000 MetaHookPre CallFunction(lstrip, ..., ...)
0.000000 MetaHookPre CallFunction(network_time, <frame>, ())
0.000000 MetaHookPre CallFunction(port_to_count, <frame>, (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)

View file

@ -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

View file

@ -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

View file

@ -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;
}

View file

@ -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;
}