Add method for packet analyzers to register for protocol detection

This commit is contained in:
Tim Wojtulewicz 2021-06-10 16:31:29 -07:00
parent a7d3cb48ef
commit d4f57a6100
3 changed files with 99 additions and 18 deletions

View file

@ -77,21 +77,34 @@ bool Analyzer::ForwardPacket(size_t len, const uint8_t* data, Packet* packet,
uint32_t identifier) const
{
auto inner_analyzer = Lookup(identifier);
if ( ! inner_analyzer )
{
for ( const auto& child : analyzers_to_detect )
{
if ( child->DetectProtocol(len, data, packet) )
{
DBG_LOG(DBG_PACKET_ANALYSIS,
"Protocol detection in %s succeeded, next layer analyzer is %s",
GetAnalyzerName(), child->GetAnalyzerName());
inner_analyzer = child;
break;
}
}
}
if ( ! inner_analyzer )
inner_analyzer = default_analyzer;
if ( inner_analyzer == nullptr )
if ( ! inner_analyzer )
{
DBG_LOG(DBG_PACKET_ANALYSIS,
"Analysis in %s failed, could not find analyzer for identifier %#x.",
GetAnalyzerName(), identifier);
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;
return false;
}
DBG_LOG(DBG_PACKET_ANALYSIS, "Analysis in %s succeeded, next layer identifier is %#x.",
@ -101,16 +114,35 @@ bool Analyzer::ForwardPacket(size_t len, const uint8_t* data, Packet* packet,
bool Analyzer::ForwardPacket(size_t len, const uint8_t* data, Packet* packet) const
{
if ( default_analyzer )
return default_analyzer->AnalyzePacket(len, data, packet);
AnalyzerPtr inner_analyzer = nullptr;
DBG_LOG(DBG_PACKET_ANALYSIS, "Analysis in %s stopped, no default analyzer available.",
GetAnalyzerName());
for ( const auto& child : analyzers_to_detect )
{
if ( child->DetectProtocol(len, data, packet) )
{
DBG_LOG(DBG_PACKET_ANALYSIS,
"Protocol detection in %s succeeded, next layer analyzer is %s",
GetAnalyzerName(), child->GetAnalyzerName());
inner_analyzer = child;
break;
}
}
if ( report_unknown_protocols )
Weird("no_suitable_analyzer_found", packet);
if ( ! inner_analyzer )
inner_analyzer = default_analyzer;
return true;
if ( ! inner_analyzer )
{
DBG_LOG(DBG_PACKET_ANALYSIS, "Analysis in %s stopped, no default analyzer available.",
GetAnalyzerName());
if ( report_unknown_protocols )
Weird("no_suitable_analyzer_found", packet);
return false;
}
return inner_analyzer->AnalyzePacket(len, data, packet);
}
void Analyzer::DumpDebug() const

View file

@ -1,6 +1,8 @@
// See the file "COPYING" in the main distribution directory for copyright.
#pragma once
#include <set>
#include "zeek/Tag.h"
#include "zeek/iosource/Packet.h"
#include "zeek/packet_analysis/Manager.h"
@ -98,6 +100,32 @@ public:
*/
void RegisterProtocol(uint32_t identifier, AnalyzerPtr child);
/**
* Registers an analyzer to use for protocol detection if identifier
* matching fails. This will also be preferred over the default analyzer
* if one exists.
*
* @param child The analyzer that will be called for protocol detection.
*/
void RegisterProtocolDetection(AnalyzerPtr child) { analyzers_to_detect.insert(child); }
/**
* Detects whether the protocol for an analyzer can be found in the packet
* data. Packet analyzers can overload this method to provide any sort of
* pattern-matching or byte-value detection against the packet data to
* determine whether the packet contains the analyzer's protocol. The
* analyzer must also register for the detection in script-land using the
* PacketAnalyzer::register_protocol_detection bif method.
*
* @param len The number of bytes passed in. As we move along the chain of
* analyzers, this is the number of bytes we have left of the packet to
* process.
* @param data Pointer to the input to process.
* @param packet Object that maintains the packet's meta data.
* @return true if the protocol is detected in the packet data.
*/
virtual bool DetectProtocol(size_t len, const uint8_t* data, Packet* packet) { return false; }
protected:
friend class Manager;
@ -174,6 +202,8 @@ private:
*/
bool report_unknown_protocols = true;
std::set<AnalyzerPtr> analyzers_to_detect;
void Init(const zeek::Tag& tag);
};

View file

@ -28,8 +28,8 @@ function register_packet_analyzer%(parent: PacketAnalyzer::Tag, identifier: coun
return zeek::val_mgr->True();
%}
## Attempts to add an entry to `parent`'s dispatcher that maps a protocol/index to a next-stage `child` analyzer.
## This may fail if either of the two names does not respond to a known analyzer.
## Attempts to add an entry to `parent`'s dispatcher that maps a protocol/index to a next-stage `child`
## analyzer. This may fail if either of the two names does not respond to a known analyzer.
##
## parent: The parent analyzer being modified
## identifier: The identifier for the protocol being registered
@ -58,3 +58,22 @@ function PacketAnalyzer::__set_ignore_checksums_nets%(v: subnet_set%) : bool
zeek::packet_analysis::IP::IPBasedAnalyzer::SetIgnoreChecksumsNets(zeek::IntrusivePtr{zeek::NewRef{}, v->AsTableVal()});
return zeek::val_mgr->True();
%}
## Registers a child analyzer with a parent analyzer to perform packet detection when determining whether
## to forward from parent to child.
##
## parent: The parent analyzer being modified
## child: The analyzer that will use protocol detection
function register_protocol_detection%(parent: PacketAnalyzer::Tag, child: PacketAnalyzer::Tag%): bool
%{
packet_analysis::AnalyzerPtr parent_analyzer = packet_mgr->GetAnalyzer(parent->AsEnumVal());
if ( ! parent_analyzer )
return zeek::val_mgr->False();
packet_analysis::AnalyzerPtr child_analyzer = packet_mgr->GetAnalyzer(child->AsEnumVal());
if ( ! child_analyzer )
return zeek::val_mgr->False();
parent_analyzer->RegisterProtocolDetection(child_analyzer);
return zeek::val_mgr->True();
%}