mirror of
https://github.com/zeek/zeek.git
synced 2025-10-04 07:38:19 +00:00
Reformat Zeek in Spicy style
This largely copies over Spicy's `.clang-format` configuration file. The one place where we deviate is header include order since Zeek depends on headers being included in a certain order.
This commit is contained in:
parent
7b8e7ed72c
commit
f5a76c1aed
786 changed files with 131714 additions and 153609 deletions
|
@ -8,235 +8,194 @@
|
|||
#include "zeek/session/Manager.h"
|
||||
#include "zeek/util.h"
|
||||
|
||||
namespace zeek::packet_analysis
|
||||
{
|
||||
namespace zeek::packet_analysis {
|
||||
|
||||
Analyzer::Analyzer(std::string name, bool report_unknown_protocols)
|
||||
: report_unknown_protocols(report_unknown_protocols)
|
||||
{
|
||||
Tag t = packet_mgr->GetComponentTag(name);
|
||||
: report_unknown_protocols(report_unknown_protocols) {
|
||||
Tag t = packet_mgr->GetComponentTag(name);
|
||||
|
||||
if ( ! t )
|
||||
reporter->InternalError("unknown packet_analysis name %s", name.c_str());
|
||||
if ( ! t )
|
||||
reporter->InternalError("unknown packet_analysis name %s", name.c_str());
|
||||
|
||||
Init(t);
|
||||
}
|
||||
Init(t);
|
||||
}
|
||||
|
||||
Analyzer::Analyzer(const Tag& tag)
|
||||
{
|
||||
Init(tag);
|
||||
}
|
||||
Analyzer::Analyzer(const Tag& tag) { Init(tag); }
|
||||
|
||||
void Analyzer::Init(const Tag& _tag)
|
||||
{
|
||||
tag = _tag;
|
||||
}
|
||||
void Analyzer::Init(const Tag& _tag) { tag = _tag; }
|
||||
|
||||
void Analyzer::Initialize()
|
||||
{
|
||||
default_analyzer = LoadAnalyzer("default_analyzer");
|
||||
}
|
||||
void Analyzer::Initialize() { default_analyzer = LoadAnalyzer("default_analyzer"); }
|
||||
|
||||
zeek::packet_analysis::AnalyzerPtr Analyzer::LoadAnalyzer(const std::string& name)
|
||||
{
|
||||
auto& analyzer = zeek::id::find(GetModuleName() + name);
|
||||
if ( ! analyzer )
|
||||
return nullptr;
|
||||
zeek::packet_analysis::AnalyzerPtr Analyzer::LoadAnalyzer(const std::string& name) {
|
||||
auto& analyzer = zeek::id::find(GetModuleName() + name);
|
||||
if ( ! analyzer )
|
||||
return nullptr;
|
||||
|
||||
auto& analyzer_val = analyzer->GetVal();
|
||||
if ( ! analyzer_val )
|
||||
return nullptr;
|
||||
auto& analyzer_val = analyzer->GetVal();
|
||||
if ( ! analyzer_val )
|
||||
return nullptr;
|
||||
|
||||
return packet_mgr->GetAnalyzer(analyzer_val->AsEnumVal());
|
||||
}
|
||||
return packet_mgr->GetAnalyzer(analyzer_val->AsEnumVal());
|
||||
}
|
||||
|
||||
const Tag Analyzer::GetAnalyzerTag() const
|
||||
{
|
||||
assert(tag);
|
||||
return tag;
|
||||
}
|
||||
const Tag Analyzer::GetAnalyzerTag() const {
|
||||
assert(tag);
|
||||
return tag;
|
||||
}
|
||||
|
||||
const char* Analyzer::GetAnalyzerName() const
|
||||
{
|
||||
assert(tag);
|
||||
return packet_mgr->GetComponentName(tag).c_str();
|
||||
}
|
||||
const char* Analyzer::GetAnalyzerName() const {
|
||||
assert(tag);
|
||||
return packet_mgr->GetComponentName(tag).c_str();
|
||||
}
|
||||
|
||||
bool Analyzer::IsAnalyzer(const char* name)
|
||||
{
|
||||
assert(tag);
|
||||
return packet_mgr->GetComponentName(tag) == name;
|
||||
}
|
||||
bool Analyzer::IsAnalyzer(const char* name) {
|
||||
assert(tag);
|
||||
return packet_mgr->GetComponentName(tag) == name;
|
||||
}
|
||||
|
||||
AnalyzerPtr Analyzer::Lookup(uint32_t identifier) const
|
||||
{
|
||||
return dispatcher.Lookup(identifier);
|
||||
}
|
||||
AnalyzerPtr Analyzer::Lookup(uint32_t identifier) const { return dispatcher.Lookup(identifier); }
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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 )
|
||||
inner_analyzer = default_analyzer;
|
||||
|
||||
if ( ! inner_analyzer )
|
||||
{
|
||||
DBG_LOG(DBG_PACKET_ANALYSIS,
|
||||
"Analysis in %s failed, could not find analyzer for identifier %#x.",
|
||||
GetAnalyzerName(), identifier);
|
||||
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 )
|
||||
packet_mgr->ReportUnknownProtocol(GetAnalyzerName(), identifier, data, len);
|
||||
if ( report_unknown_protocols )
|
||||
packet_mgr->ReportUnknownProtocol(GetAnalyzerName(), identifier, data, len);
|
||||
|
||||
return false;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
DBG_LOG(DBG_PACKET_ANALYSIS, "Analysis in %s succeeded, next layer identifier is %#x.", GetAnalyzerName(),
|
||||
identifier);
|
||||
return inner_analyzer->AnalyzePacket(len, data, packet);
|
||||
}
|
||||
|
||||
bool Analyzer::ForwardPacket(size_t len, const uint8_t* data, Packet* packet) const
|
||||
{
|
||||
AnalyzerPtr inner_analyzer = nullptr;
|
||||
bool Analyzer::ForwardPacket(size_t len, const uint8_t* data, Packet* packet) const {
|
||||
AnalyzerPtr inner_analyzer = nullptr;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
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 )
|
||||
inner_analyzer = default_analyzer;
|
||||
|
||||
if ( ! inner_analyzer )
|
||||
{
|
||||
DBG_LOG(DBG_PACKET_ANALYSIS, "Analysis in %s stopped, no default analyzer available.",
|
||||
GetAnalyzerName());
|
||||
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);
|
||||
if ( report_unknown_protocols )
|
||||
Weird("no_suitable_analyzer_found", packet);
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return inner_analyzer->AnalyzePacket(len, data, packet);
|
||||
}
|
||||
return inner_analyzer->AnalyzePacket(len, data, packet);
|
||||
}
|
||||
|
||||
void Analyzer::DumpDebug() const
|
||||
{
|
||||
void Analyzer::DumpDebug() const {
|
||||
#ifdef DEBUG
|
||||
DBG_LOG(DBG_PACKET_ANALYSIS, "Dispatcher for %s", this->GetAnalyzerName());
|
||||
dispatcher.DumpDebug();
|
||||
DBG_LOG(DBG_PACKET_ANALYSIS, "Dispatcher for %s", this->GetAnalyzerName());
|
||||
dispatcher.DumpDebug();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void Analyzer::RegisterProtocol(uint32_t identifier, AnalyzerPtr child)
|
||||
{
|
||||
if ( run_state::detail::zeek_init_done )
|
||||
reporter->FatalError("Packet protocols cannot be registered after zeek_init has finished.");
|
||||
void Analyzer::RegisterProtocol(uint32_t identifier, AnalyzerPtr child) {
|
||||
if ( run_state::detail::zeek_init_done )
|
||||
reporter->FatalError("Packet protocols cannot be registered after zeek_init has finished.");
|
||||
|
||||
dispatcher.Register(identifier, std::move(child));
|
||||
}
|
||||
dispatcher.Register(identifier, std::move(child));
|
||||
}
|
||||
|
||||
void Analyzer::Weird(const char* name, Packet* packet, const char* addl) const
|
||||
{
|
||||
session_mgr->Weird(name, packet, addl, GetAnalyzerName());
|
||||
}
|
||||
void Analyzer::Weird(const char* name, Packet* packet, const char* addl) const {
|
||||
session_mgr->Weird(name, packet, addl, GetAnalyzerName());
|
||||
}
|
||||
|
||||
void Analyzer::EnqueueAnalyzerConfirmationInfo(session::Session* session, const zeek::Tag& arg_tag)
|
||||
{
|
||||
static auto info_type = zeek::id::find_type<RecordType>("AnalyzerConfirmationInfo");
|
||||
static auto info_c_idx = info_type->FieldOffset("c");
|
||||
void Analyzer::EnqueueAnalyzerConfirmationInfo(session::Session* session, const zeek::Tag& arg_tag) {
|
||||
static auto info_type = zeek::id::find_type<RecordType>("AnalyzerConfirmationInfo");
|
||||
static auto info_c_idx = info_type->FieldOffset("c");
|
||||
|
||||
auto info = make_intrusive<RecordVal>(info_type);
|
||||
info->Assign(info_c_idx, session->GetVal());
|
||||
auto info = make_intrusive<RecordVal>(info_type);
|
||||
info->Assign(info_c_idx, session->GetVal());
|
||||
|
||||
event_mgr.Enqueue(analyzer_confirmation_info, arg_tag.AsVal(), info);
|
||||
}
|
||||
event_mgr.Enqueue(analyzer_confirmation_info, arg_tag.AsVal(), info);
|
||||
}
|
||||
|
||||
void Analyzer::AnalyzerConfirmation(session::Session* session, zeek::Tag arg_tag)
|
||||
{
|
||||
const auto& effective_tag = arg_tag ? arg_tag : GetAnalyzerTag();
|
||||
void Analyzer::AnalyzerConfirmation(session::Session* session, zeek::Tag arg_tag) {
|
||||
const auto& effective_tag = arg_tag ? arg_tag : GetAnalyzerTag();
|
||||
|
||||
if ( ! session )
|
||||
return;
|
||||
if ( ! session )
|
||||
return;
|
||||
|
||||
if ( session->AnalyzerState(effective_tag) == session::AnalyzerConfirmationState::CONFIRMED )
|
||||
return;
|
||||
if ( session->AnalyzerState(effective_tag) == session::AnalyzerConfirmationState::CONFIRMED )
|
||||
return;
|
||||
|
||||
// If this session violated previously, we don't allow through a confirmation.
|
||||
if ( session->AnalyzerState(effective_tag) == session::AnalyzerConfirmationState::VIOLATED )
|
||||
return;
|
||||
// If this session violated previously, we don't allow through a confirmation.
|
||||
if ( session->AnalyzerState(effective_tag) == session::AnalyzerConfirmationState::VIOLATED )
|
||||
return;
|
||||
|
||||
session->SetAnalyzerState(effective_tag, session::AnalyzerConfirmationState::CONFIRMED);
|
||||
session->SetAnalyzerState(effective_tag, session::AnalyzerConfirmationState::CONFIRMED);
|
||||
|
||||
if ( analyzer_confirmation_info )
|
||||
EnqueueAnalyzerConfirmationInfo(session, effective_tag);
|
||||
}
|
||||
if ( analyzer_confirmation_info )
|
||||
EnqueueAnalyzerConfirmationInfo(session, effective_tag);
|
||||
}
|
||||
|
||||
void Analyzer::EnqueueAnalyzerViolationInfo(session::Session* session, const char* reason,
|
||||
const char* data, int len, const zeek::Tag& arg_tag)
|
||||
{
|
||||
static auto info_type = zeek::id::find_type<RecordType>("AnalyzerViolationInfo");
|
||||
static auto info_reason_idx = info_type->FieldOffset("reason");
|
||||
static auto info_c_idx = info_type->FieldOffset("c");
|
||||
static auto info_data_idx = info_type->FieldOffset("data");
|
||||
void Analyzer::EnqueueAnalyzerViolationInfo(session::Session* session, const char* reason, const char* data, int len,
|
||||
const zeek::Tag& arg_tag) {
|
||||
static auto info_type = zeek::id::find_type<RecordType>("AnalyzerViolationInfo");
|
||||
static auto info_reason_idx = info_type->FieldOffset("reason");
|
||||
static auto info_c_idx = info_type->FieldOffset("c");
|
||||
static auto info_data_idx = info_type->FieldOffset("data");
|
||||
|
||||
auto info = zeek::make_intrusive<RecordVal>(info_type);
|
||||
info->Assign(info_reason_idx, make_intrusive<StringVal>(reason));
|
||||
info->Assign(info_c_idx, session->GetVal());
|
||||
if ( data && len )
|
||||
info->Assign(info_data_idx, make_intrusive<StringVal>(len, data));
|
||||
auto info = zeek::make_intrusive<RecordVal>(info_type);
|
||||
info->Assign(info_reason_idx, make_intrusive<StringVal>(reason));
|
||||
info->Assign(info_c_idx, session->GetVal());
|
||||
if ( data && len )
|
||||
info->Assign(info_data_idx, make_intrusive<StringVal>(len, data));
|
||||
|
||||
event_mgr.Enqueue(analyzer_violation_info, arg_tag.AsVal(), info);
|
||||
}
|
||||
event_mgr.Enqueue(analyzer_violation_info, arg_tag.AsVal(), info);
|
||||
}
|
||||
|
||||
void Analyzer::AnalyzerViolation(const char* reason, session::Session* session, const char* data,
|
||||
int len, zeek::Tag arg_tag)
|
||||
{
|
||||
const auto& effective_tag = arg_tag ? arg_tag : GetAnalyzerTag();
|
||||
void Analyzer::AnalyzerViolation(const char* reason, session::Session* session, const char* data, int len,
|
||||
zeek::Tag arg_tag) {
|
||||
const auto& effective_tag = arg_tag ? arg_tag : GetAnalyzerTag();
|
||||
|
||||
if ( ! session )
|
||||
return;
|
||||
if ( ! session )
|
||||
return;
|
||||
|
||||
if ( session->AnalyzerState(effective_tag) == session::AnalyzerConfirmationState::VIOLATED )
|
||||
return;
|
||||
if ( session->AnalyzerState(effective_tag) == session::AnalyzerConfirmationState::VIOLATED )
|
||||
return;
|
||||
|
||||
session->SetAnalyzerState(effective_tag, session::AnalyzerConfirmationState::VIOLATED);
|
||||
session->SetAnalyzerState(effective_tag, session::AnalyzerConfirmationState::VIOLATED);
|
||||
|
||||
if ( analyzer_violation_info )
|
||||
EnqueueAnalyzerViolationInfo(session, reason, data, len, effective_tag);
|
||||
}
|
||||
if ( analyzer_violation_info )
|
||||
EnqueueAnalyzerViolationInfo(session, reason, data, len, effective_tag);
|
||||
}
|
||||
|
||||
} // namespace zeek::packet_analysis
|
||||
} // namespace zeek::packet_analysis
|
||||
|
|
|
@ -8,279 +8,269 @@
|
|||
#include "zeek/packet_analysis/Manager.h"
|
||||
#include "zeek/session/Session.h"
|
||||
|
||||
namespace zeek::packet_analysis
|
||||
{
|
||||
namespace zeek::packet_analysis {
|
||||
|
||||
/**
|
||||
* Main packet analyzer interface.
|
||||
*/
|
||||
class Analyzer
|
||||
{
|
||||
class Analyzer {
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @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, bool report_unknown_protocols = true);
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @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, bool report_unknown_protocols = true);
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param tag The tag for the type of analyzer. The tag must map to
|
||||
* the name the corresponding Component registers.
|
||||
*/
|
||||
explicit Analyzer(const zeek::Tag& tag);
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param tag The tag for the type of analyzer. The tag must map to
|
||||
* the name the corresponding Component registers.
|
||||
*/
|
||||
explicit Analyzer(const zeek::Tag& tag);
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~Analyzer() = default;
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~Analyzer() = default;
|
||||
|
||||
/**
|
||||
* Initialize the analyzer. This method is called after the configuration
|
||||
* was read. Derived classes can override this method to implement custom
|
||||
* initialization.
|
||||
* When overriding this methods, always make sure to call the base-class
|
||||
* version to ensure proper initialization.
|
||||
*/
|
||||
virtual void Initialize();
|
||||
/**
|
||||
* Initialize the analyzer. This method is called after the configuration
|
||||
* was read. Derived classes can override this method to implement custom
|
||||
* initialization.
|
||||
* When overriding this methods, always make sure to call the base-class
|
||||
* version to ensure proper initialization.
|
||||
*/
|
||||
virtual void Initialize();
|
||||
|
||||
/**
|
||||
* Returns the tag associated with the analyzer's type.
|
||||
*/
|
||||
const zeek::Tag GetAnalyzerTag() const;
|
||||
/**
|
||||
* Returns the tag associated with the analyzer's type.
|
||||
*/
|
||||
const zeek::Tag GetAnalyzerTag() const;
|
||||
|
||||
/**
|
||||
* Returns a textual description of the analyzer's type. This is
|
||||
* what's passed to the constructor and usually corresponds to the
|
||||
* protocol name, e.g., "ARP".
|
||||
*/
|
||||
const char* GetAnalyzerName() const;
|
||||
/**
|
||||
* Returns a textual description of the analyzer's type. This is
|
||||
* what's passed to the constructor and usually corresponds to the
|
||||
* protocol name, e.g., "ARP".
|
||||
*/
|
||||
const char* GetAnalyzerName() const;
|
||||
|
||||
/**
|
||||
* Returns true if this analyzer's type matches the name passes in.
|
||||
* This is shortcut for comparing GetAnalyzerName() with the given
|
||||
* name.
|
||||
*
|
||||
* @param name The name to check.
|
||||
*/
|
||||
bool IsAnalyzer(const char* name);
|
||||
/**
|
||||
* Returns true if this analyzer's type matches the name passes in.
|
||||
* This is shortcut for comparing GetAnalyzerName() with the given
|
||||
* name.
|
||||
*
|
||||
* @param name The name to check.
|
||||
*/
|
||||
bool IsAnalyzer(const char* name);
|
||||
|
||||
/**
|
||||
* Return whether this analyzer is enabled or not.
|
||||
*
|
||||
* @return true if the analyzer is enabled, else false.
|
||||
*/
|
||||
bool IsEnabled() const { return enabled; }
|
||||
/**
|
||||
* 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
|
||||
* in the header. In this case, derived classes may use ForwardPacket() to
|
||||
* forward the payload to the corresponding analyzer.
|
||||
*
|
||||
* @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 false if the analysis failed, else true.
|
||||
*/
|
||||
virtual bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) = 0;
|
||||
/**
|
||||
* Analyzes the given packet. A common case is that the analyzed protocol
|
||||
* encapsulates another protocol, which can be determined by an identifier
|
||||
* in the header. In this case, derived classes may use ForwardPacket() to
|
||||
* forward the payload to the corresponding analyzer.
|
||||
*
|
||||
* @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 false if the analysis failed, else true.
|
||||
*/
|
||||
virtual bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) = 0;
|
||||
|
||||
/**
|
||||
* Dumps out debug information to the \c analyzer debug stream.
|
||||
*/
|
||||
void DumpDebug() const;
|
||||
/**
|
||||
* Dumps out debug information to the \c analyzer debug stream.
|
||||
*/
|
||||
void DumpDebug() const;
|
||||
|
||||
/**
|
||||
* Adds a protocol to this analyzer's dispatcher.
|
||||
*
|
||||
* @param identifier The identifier for the protocol being added.
|
||||
* @param child The analyzer that will be called for the new protocol during
|
||||
* forwarding.
|
||||
*/
|
||||
void RegisterProtocol(uint32_t identifier, AnalyzerPtr child);
|
||||
/**
|
||||
* Adds a protocol to this analyzer's dispatcher.
|
||||
*
|
||||
* @param identifier The identifier for the protocol being added.
|
||||
* @param child The analyzer that will be called for the new protocol during
|
||||
* forwarding.
|
||||
*/
|
||||
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); }
|
||||
/**
|
||||
* 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; }
|
||||
/**
|
||||
* 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; }
|
||||
|
||||
/**
|
||||
* Signals Zeek's protocol detection that the analyzer has recognized
|
||||
* the input to indeed conform to the expected protocol. This should
|
||||
* be called as early as possible during a connection's life-time. It
|
||||
* may turn into \c analyzer_confirmation_info event at the script-layer (but
|
||||
* only once per analyzer for each connection, even if the method is
|
||||
* called multiple times).
|
||||
*
|
||||
* If tag is given, it overrides the analyzer tag passed to the
|
||||
* scripting layer; the default is the one of the analyzer itself.
|
||||
*/
|
||||
virtual void AnalyzerConfirmation(session::Session* session, zeek::Tag tag = zeek::Tag());
|
||||
/**
|
||||
* Signals Zeek's protocol detection that the analyzer has recognized
|
||||
* the input to indeed conform to the expected protocol. This should
|
||||
* be called as early as possible during a connection's life-time. It
|
||||
* may turn into \c analyzer_confirmation_info event at the script-layer (but
|
||||
* only once per analyzer for each connection, even if the method is
|
||||
* called multiple times).
|
||||
*
|
||||
* If tag is given, it overrides the analyzer tag passed to the
|
||||
* scripting layer; the default is the one of the analyzer itself.
|
||||
*/
|
||||
virtual void AnalyzerConfirmation(session::Session* session, zeek::Tag tag = zeek::Tag());
|
||||
|
||||
/**
|
||||
* Signals Zeek's protocol detection that the analyzer has found a
|
||||
* severe protocol violation that could indicate that it's not
|
||||
* parsing the expected protocol. This turns into \c
|
||||
* analyzer_violation_info events at the script-layer (one such event is
|
||||
* raised for each call to this method so that the script-layer can
|
||||
* built up a notion of how prevalent protocol violations are; the
|
||||
* more, the less likely it's the right protocol).
|
||||
*
|
||||
* @param reason A textual description of the error encountered.
|
||||
*
|
||||
* @param data An optional pointer to the malformed data.
|
||||
*
|
||||
* @param len If \a data is given, the length of it.
|
||||
*/
|
||||
virtual void AnalyzerViolation(const char* reason, session::Session* session,
|
||||
const char* data = nullptr, int len = 0,
|
||||
zeek::Tag tag = zeek::Tag());
|
||||
/**
|
||||
* Signals Zeek's protocol detection that the analyzer has found a
|
||||
* severe protocol violation that could indicate that it's not
|
||||
* parsing the expected protocol. This turns into \c
|
||||
* analyzer_violation_info events at the script-layer (one such event is
|
||||
* raised for each call to this method so that the script-layer can
|
||||
* built up a notion of how prevalent protocol violations are; the
|
||||
* more, the less likely it's the right protocol).
|
||||
*
|
||||
* @param reason A textual description of the error encountered.
|
||||
*
|
||||
* @param data An optional pointer to the malformed data.
|
||||
*
|
||||
* @param len If \a data is given, the length of it.
|
||||
*/
|
||||
virtual void AnalyzerViolation(const char* reason, session::Session* session, const char* data = nullptr,
|
||||
int len = 0, zeek::Tag tag = zeek::Tag());
|
||||
|
||||
/**
|
||||
* Returns true if ProtocolConfirmation() has been called at least
|
||||
* once.
|
||||
*/
|
||||
bool AnalyzerConfirmed(session::Session* session) const
|
||||
{
|
||||
return session->AnalyzerState(GetAnalyzerTag()) ==
|
||||
session::AnalyzerConfirmationState::CONFIRMED;
|
||||
}
|
||||
bool AnalyzerViolated(session::Session* session) const
|
||||
{
|
||||
return session->AnalyzerState(GetAnalyzerTag()) ==
|
||||
session::AnalyzerConfirmationState::VIOLATED;
|
||||
}
|
||||
/**
|
||||
* Returns true if ProtocolConfirmation() has been called at least
|
||||
* once.
|
||||
*/
|
||||
bool AnalyzerConfirmed(session::Session* session) const {
|
||||
return session->AnalyzerState(GetAnalyzerTag()) == session::AnalyzerConfirmationState::CONFIRMED;
|
||||
}
|
||||
bool AnalyzerViolated(session::Session* session) const {
|
||||
return session->AnalyzerState(GetAnalyzerTag()) == session::AnalyzerConfirmationState::VIOLATED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports a Weird with the analyzer's name included in the addl field.
|
||||
*
|
||||
* @param name The name of the weird.
|
||||
* @param packet An optional pointer to a packet to be used for additional
|
||||
* information in the weird output.
|
||||
* @param addl An optional string containing additional information about
|
||||
* the weird. If this is passed, the analyzer's name will be prepended to
|
||||
* it before output.
|
||||
*/
|
||||
void Weird(const char* name, Packet* packet = nullptr, const char* addl = "") const;
|
||||
/**
|
||||
* Reports a Weird with the analyzer's name included in the addl field.
|
||||
*
|
||||
* @param name The name of the weird.
|
||||
* @param packet An optional pointer to a packet to be used for additional
|
||||
* information in the weird output.
|
||||
* @param addl An optional string containing additional information about
|
||||
* the weird. If this is passed, the analyzer's name will be prepended to
|
||||
* it before output.
|
||||
*/
|
||||
void Weird(const char* name, Packet* packet = nullptr, const char* addl = "") const;
|
||||
|
||||
protected:
|
||||
friend class Component;
|
||||
friend class Manager;
|
||||
friend class Component;
|
||||
friend class Manager;
|
||||
|
||||
/**
|
||||
* Looks up the analyzer for the encapsulated protocol based on the given
|
||||
* identifier.
|
||||
*
|
||||
* @param identifier Identifier for the encapsulated protocol.
|
||||
* @return The analyzer registered for the given identifier. Returns a
|
||||
* nullptr if no analyzer is registered.
|
||||
*/
|
||||
AnalyzerPtr Lookup(uint32_t identifier) const;
|
||||
/**
|
||||
* Looks up the analyzer for the encapsulated protocol based on the given
|
||||
* identifier.
|
||||
*
|
||||
* @param identifier Identifier for the encapsulated protocol.
|
||||
* @return The analyzer registered for the given identifier. Returns a
|
||||
* nullptr if no analyzer is registered.
|
||||
*/
|
||||
AnalyzerPtr Lookup(uint32_t identifier) const;
|
||||
|
||||
/**
|
||||
* Returns an analyzer based on a script-land definition.
|
||||
*
|
||||
* @param name The script-land identifier for a PacketAnalyzer::Tag value.
|
||||
* @return The defined analyzer if available, else nullptr.
|
||||
*/
|
||||
AnalyzerPtr LoadAnalyzer(const std::string& name);
|
||||
/**
|
||||
* Returns an analyzer based on a script-land definition.
|
||||
*
|
||||
* @param name The script-land identifier for a PacketAnalyzer::Tag value.
|
||||
* @return The defined analyzer if available, else nullptr.
|
||||
*/
|
||||
AnalyzerPtr LoadAnalyzer(const std::string& name);
|
||||
|
||||
/**
|
||||
* Enable or disable this analyzer. This is meant for internal use by
|
||||
* manager and component.
|
||||
*
|
||||
* @param value The new enabled value.
|
||||
*/
|
||||
void SetEnabled(bool value) { enabled = value; }
|
||||
/**
|
||||
* Enable or disable this analyzer. This is meant for internal use by
|
||||
* manager and component.
|
||||
*
|
||||
* @param value The new enabled value.
|
||||
*/
|
||||
void SetEnabled(bool value) { enabled = value; }
|
||||
|
||||
/**
|
||||
* Returns the module name corresponding to the analyzer, i.e. its script-land
|
||||
* namespace. Configuration values for the analyzer are expected in this module.
|
||||
* @return Analyzer's module name.
|
||||
*/
|
||||
std::string GetModuleName() const
|
||||
{
|
||||
return util::fmt("PacketAnalyzer::%s::", GetAnalyzerName());
|
||||
};
|
||||
/**
|
||||
* Returns the module name corresponding to the analyzer, i.e. its script-land
|
||||
* namespace. Configuration values for the analyzer are expected in this module.
|
||||
* @return Analyzer's module name.
|
||||
*/
|
||||
std::string GetModuleName() const { return util::fmt("PacketAnalyzer::%s::", GetAnalyzerName()); };
|
||||
|
||||
/**
|
||||
* Triggers analysis of the encapsulated packet. The encapsulated protocol
|
||||
* is determined using the given identifier.
|
||||
*
|
||||
* @param len The length of the data left to analyze.
|
||||
* @param data Pointer to the payload in the raw packet left to analyze.
|
||||
* @param packet The packet to analyze.
|
||||
* @param identifier The identifier of the encapsulated protocol.
|
||||
*
|
||||
* @return false if the analysis failed, else true.
|
||||
*/
|
||||
bool ForwardPacket(size_t len, const uint8_t* data, Packet* packet, uint32_t identifier) const;
|
||||
/**
|
||||
* Triggers analysis of the encapsulated packet. The encapsulated protocol
|
||||
* is determined using the given identifier.
|
||||
*
|
||||
* @param len The length of the data left to analyze.
|
||||
* @param data Pointer to the payload in the raw packet left to analyze.
|
||||
* @param packet The packet to analyze.
|
||||
* @param identifier The identifier of the encapsulated protocol.
|
||||
*
|
||||
* @return false if the analysis failed, else true.
|
||||
*/
|
||||
bool ForwardPacket(size_t len, const uint8_t* data, Packet* packet, uint32_t identifier) const;
|
||||
|
||||
/**
|
||||
* Triggers default analysis of the encapsulated packet if the default analyzer
|
||||
* is set.
|
||||
*
|
||||
* @param len The length of the data left to analyze.
|
||||
* @param data Pointer to the payload in the raw packet left to analyze.
|
||||
* @param packet The packet to analyze.
|
||||
*
|
||||
* @return false if the analysis failed, else true.
|
||||
*/
|
||||
bool ForwardPacket(size_t len, const uint8_t* data, Packet* packet) const;
|
||||
/**
|
||||
* Triggers default analysis of the encapsulated packet if the default analyzer
|
||||
* is set.
|
||||
*
|
||||
* @param len The length of the data left to analyze.
|
||||
* @param data Pointer to the payload in the raw packet left to analyze.
|
||||
* @param packet The packet to analyze.
|
||||
*
|
||||
* @return false if the analysis failed, else true.
|
||||
*/
|
||||
bool ForwardPacket(size_t len, const uint8_t* data, Packet* packet) const;
|
||||
|
||||
private:
|
||||
// Internal helper to raise analyzer_confirmation events
|
||||
void EnqueueAnalyzerConfirmationInfo(session::Session* session, const zeek::Tag& arg_tag);
|
||||
// Internal helper to raise analyzer_confirmation events
|
||||
void EnqueueAnalyzerConfirmationInfo(session::Session* session, const zeek::Tag& arg_tag);
|
||||
|
||||
// Internal helper to raise analyzer_violation_info
|
||||
void EnqueueAnalyzerViolationInfo(session::Session* session, const char* reason,
|
||||
const char* data, int len, const zeek::Tag& arg_tag);
|
||||
// Internal helper to raise analyzer_violation_info
|
||||
void EnqueueAnalyzerViolationInfo(session::Session* session, const char* reason, const char* data, int len,
|
||||
const zeek::Tag& arg_tag);
|
||||
|
||||
zeek::Tag tag;
|
||||
Dispatcher dispatcher;
|
||||
AnalyzerPtr default_analyzer = nullptr;
|
||||
bool enabled = true;
|
||||
zeek::Tag tag;
|
||||
Dispatcher dispatcher;
|
||||
AnalyzerPtr default_analyzer = nullptr;
|
||||
bool enabled = true;
|
||||
|
||||
/**
|
||||
* Flag for whether to report unknown protocols in ForwardPacket.
|
||||
*/
|
||||
bool report_unknown_protocols = true;
|
||||
/**
|
||||
* Flag for whether to report unknown protocols in ForwardPacket.
|
||||
*/
|
||||
bool report_unknown_protocols = true;
|
||||
|
||||
std::set<AnalyzerPtr> analyzers_to_detect;
|
||||
std::set<AnalyzerPtr> analyzers_to_detect;
|
||||
|
||||
void Init(const zeek::Tag& tag);
|
||||
};
|
||||
void Init(const zeek::Tag& tag);
|
||||
};
|
||||
|
||||
using AnalyzerPtr = std::shared_ptr<Analyzer>;
|
||||
|
||||
}
|
||||
} // namespace zeek::packet_analysis
|
||||
|
|
|
@ -8,37 +8,30 @@
|
|||
|
||||
using namespace zeek::packet_analysis;
|
||||
|
||||
Component::Component(const std::string& name, factory_callback arg_factory,
|
||||
Tag::subtype_t arg_subtype)
|
||||
: plugin::Component(plugin::component::PACKET_ANALYZER, name, arg_subtype,
|
||||
packet_mgr->GetTagType())
|
||||
{
|
||||
factory = arg_factory;
|
||||
}
|
||||
Component::Component(const std::string& name, factory_callback arg_factory, Tag::subtype_t arg_subtype)
|
||||
: plugin::Component(plugin::component::PACKET_ANALYZER, name, arg_subtype, packet_mgr->GetTagType()) {
|
||||
factory = arg_factory;
|
||||
}
|
||||
|
||||
void Component::Initialize()
|
||||
{
|
||||
InitializeTag();
|
||||
packet_mgr->RegisterComponent(this, "ANALYZER_");
|
||||
}
|
||||
void Component::Initialize() {
|
||||
InitializeTag();
|
||||
packet_mgr->RegisterComponent(this, "ANALYZER_");
|
||||
}
|
||||
|
||||
void Component::SetEnabled(bool arg_enabled)
|
||||
{
|
||||
enabled = arg_enabled;
|
||||
void Component::SetEnabled(bool arg_enabled) {
|
||||
enabled = arg_enabled;
|
||||
|
||||
// If we already have instantiated an analyzer, update its state.
|
||||
if ( auto analyzer = packet_mgr->GetAnalyzer(Tag().AsVal().get()) )
|
||||
analyzer->SetEnabled(enabled);
|
||||
}
|
||||
// If we already have instantiated an analyzer, update its state.
|
||||
if ( auto analyzer = packet_mgr->GetAnalyzer(Tag().AsVal().get()) )
|
||||
analyzer->SetEnabled(enabled);
|
||||
}
|
||||
|
||||
void Component::DoDescribe(ODesc* d) const
|
||||
{
|
||||
if ( factory )
|
||||
{
|
||||
d->Add("ANALYZER_");
|
||||
d->Add(CanonicalName());
|
||||
d->Add(", ");
|
||||
}
|
||||
void Component::DoDescribe(ODesc* d) const {
|
||||
if ( factory ) {
|
||||
d->Add("ANALYZER_");
|
||||
d->Add(CanonicalName());
|
||||
d->Add(", ");
|
||||
}
|
||||
|
||||
d->Add(enabled ? "enabled" : "disabled");
|
||||
}
|
||||
d->Add(enabled ? "enabled" : "disabled");
|
||||
}
|
||||
|
|
|
@ -10,55 +10,53 @@
|
|||
#include "zeek/plugin/Component.h"
|
||||
#include "zeek/util.h"
|
||||
|
||||
namespace zeek::packet_analysis
|
||||
{
|
||||
namespace zeek::packet_analysis {
|
||||
|
||||
class Analyzer;
|
||||
using AnalyzerPtr = std::shared_ptr<Analyzer>;
|
||||
|
||||
class Component : public plugin::Component
|
||||
{
|
||||
class Component : public plugin::Component {
|
||||
public:
|
||||
using factory_callback = std::function<AnalyzerPtr()>;
|
||||
using factory_callback = std::function<AnalyzerPtr()>;
|
||||
|
||||
Component(const std::string& name, factory_callback factory, zeek::Tag::subtype_t subtype = 0);
|
||||
~Component() override = default;
|
||||
Component(const std::string& name, factory_callback factory, zeek::Tag::subtype_t subtype = 0);
|
||||
~Component() override = default;
|
||||
|
||||
/**
|
||||
* Initialization function. This function has to be called before any
|
||||
* plugin component functionality is used; it is used to add the
|
||||
* plugin component to the list of components and to initialize tags
|
||||
*/
|
||||
void Initialize() override;
|
||||
/**
|
||||
* Initialization function. This function has to be called before any
|
||||
* plugin component functionality is used; it is used to add the
|
||||
* plugin component to the list of components and to initialize tags
|
||||
*/
|
||||
void Initialize() override;
|
||||
|
||||
/**
|
||||
* Returns the analyzer's factory function.
|
||||
*/
|
||||
factory_callback Factory() const { return factory; }
|
||||
/**
|
||||
* Returns the analyzer's factory function.
|
||||
*/
|
||||
factory_callback Factory() const { return factory; }
|
||||
|
||||
/**
|
||||
* Returns true if the analyzer is currently enabled and hence
|
||||
* available for use.
|
||||
*/
|
||||
bool Enabled() const { return enabled; }
|
||||
/**
|
||||
* Returns true if the analyzer is currently enabled and hence
|
||||
* available for use.
|
||||
*/
|
||||
bool Enabled() const { return enabled; }
|
||||
|
||||
/**
|
||||
* Enables or disables this analyzer.
|
||||
*
|
||||
* @param arg_enabled True to enabled, false to disable.
|
||||
*
|
||||
*/
|
||||
void SetEnabled(bool arg_enabled);
|
||||
/**
|
||||
* Enables or disables this analyzer.
|
||||
*
|
||||
* @param arg_enabled True to enabled, false to disable.
|
||||
*
|
||||
*/
|
||||
void SetEnabled(bool arg_enabled);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Overridden from plugin::Component.
|
||||
*/
|
||||
void DoDescribe(ODesc* d) const override;
|
||||
/**
|
||||
* Overridden from plugin::Component.
|
||||
*/
|
||||
void DoDescribe(ODesc* d) const override;
|
||||
|
||||
private:
|
||||
factory_callback factory; // The analyzer's factory callback.
|
||||
bool enabled = true; // True if the analyzer is enabled.
|
||||
};
|
||||
factory_callback factory; // The analyzer's factory callback.
|
||||
bool enabled = true; // True if the analyzer is enabled.
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace zeek::packet_analysis
|
||||
|
|
|
@ -8,99 +8,76 @@
|
|||
#include "zeek/Reporter.h"
|
||||
#include "zeek/packet_analysis/Analyzer.h"
|
||||
|
||||
namespace zeek::packet_analysis
|
||||
{
|
||||
namespace zeek::packet_analysis {
|
||||
|
||||
Dispatcher::~Dispatcher()
|
||||
{
|
||||
FreeValues();
|
||||
}
|
||||
Dispatcher::~Dispatcher() { FreeValues(); }
|
||||
|
||||
void Dispatcher::Register(uint32_t identifier, AnalyzerPtr analyzer)
|
||||
{
|
||||
// If the table has size 1 and the entry is nullptr, there was nothing added yet. Just add it.
|
||||
if ( table.size() == 1 && table[0] == nullptr )
|
||||
{
|
||||
table[0] = std::move(analyzer);
|
||||
lowest_identifier = identifier;
|
||||
return;
|
||||
}
|
||||
void Dispatcher::Register(uint32_t identifier, AnalyzerPtr analyzer) {
|
||||
// If the table has size 1 and the entry is nullptr, there was nothing added yet. Just add it.
|
||||
if ( table.size() == 1 && table[0] == nullptr ) {
|
||||
table[0] = std::move(analyzer);
|
||||
lowest_identifier = identifier;
|
||||
return;
|
||||
}
|
||||
|
||||
// If highestIdentifier == identifier, overwrite would happen -> no check needed, will return
|
||||
// false
|
||||
if ( GetHighestIdentifier() < identifier )
|
||||
{
|
||||
table.resize(table.size() + (identifier - GetHighestIdentifier()), nullptr);
|
||||
}
|
||||
else if ( identifier < lowest_identifier )
|
||||
{
|
||||
// Lower than the lowest registered identifier. Shift up by lowerBound - identifier
|
||||
uint32_t distance = lowest_identifier - identifier;
|
||||
table.resize(table.size() + distance, nullptr);
|
||||
// If highestIdentifier == identifier, overwrite would happen -> no check needed, will return
|
||||
// false
|
||||
if ( GetHighestIdentifier() < identifier ) {
|
||||
table.resize(table.size() + (identifier - GetHighestIdentifier()), nullptr);
|
||||
}
|
||||
else if ( identifier < lowest_identifier ) {
|
||||
// Lower than the lowest registered identifier. Shift up by lowerBound - identifier
|
||||
uint32_t distance = lowest_identifier - identifier;
|
||||
table.resize(table.size() + distance, nullptr);
|
||||
|
||||
// Shift values
|
||||
for ( ssize_t i = table.size() - 1; i >= 0; i-- )
|
||||
{
|
||||
if ( table[i] != nullptr )
|
||||
{
|
||||
table.at(i + distance) = std::move(table.at(i));
|
||||
table.at(i) = nullptr;
|
||||
}
|
||||
}
|
||||
// Shift values
|
||||
for ( ssize_t i = table.size() - 1; i >= 0; i-- ) {
|
||||
if ( table[i] != nullptr ) {
|
||||
table.at(i + distance) = std::move(table.at(i));
|
||||
table.at(i) = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
lowest_identifier = identifier;
|
||||
}
|
||||
lowest_identifier = identifier;
|
||||
}
|
||||
|
||||
int64_t index = identifier - lowest_identifier;
|
||||
if ( table[index] != nullptr )
|
||||
reporter->Info("Overwriting packet analyzer mapping %#8" PRIx64 " => %s with %s",
|
||||
index + lowest_identifier, table[index]->GetAnalyzerName(),
|
||||
analyzer->GetAnalyzerName());
|
||||
table[index] = std::move(analyzer);
|
||||
}
|
||||
int64_t index = identifier - lowest_identifier;
|
||||
if ( table[index] != nullptr )
|
||||
reporter->Info("Overwriting packet analyzer mapping %#8" PRIx64 " => %s with %s", index + lowest_identifier,
|
||||
table[index]->GetAnalyzerName(), analyzer->GetAnalyzerName());
|
||||
table[index] = std::move(analyzer);
|
||||
}
|
||||
|
||||
AnalyzerPtr Dispatcher::Lookup(uint32_t identifier) const
|
||||
{
|
||||
int64_t index = identifier - lowest_identifier;
|
||||
if ( index >= 0 && index < static_cast<int64_t>(table.size()) && table[index] != nullptr )
|
||||
return table[index];
|
||||
AnalyzerPtr Dispatcher::Lookup(uint32_t identifier) const {
|
||||
int64_t index = identifier - lowest_identifier;
|
||||
if ( index >= 0 && index < static_cast<int64_t>(table.size()) && table[index] != nullptr )
|
||||
return table[index];
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t Dispatcher::Count() const
|
||||
{
|
||||
return std::count_if(table.begin(), table.end(),
|
||||
[](AnalyzerPtr a)
|
||||
{
|
||||
return a != nullptr;
|
||||
});
|
||||
}
|
||||
size_t Dispatcher::Count() const {
|
||||
return std::count_if(table.begin(), table.end(), [](AnalyzerPtr a) { return a != nullptr; });
|
||||
}
|
||||
|
||||
void Dispatcher::Clear()
|
||||
{
|
||||
FreeValues();
|
||||
table.clear();
|
||||
}
|
||||
void Dispatcher::Clear() {
|
||||
FreeValues();
|
||||
table.clear();
|
||||
}
|
||||
|
||||
void Dispatcher::FreeValues()
|
||||
{
|
||||
for ( auto& current : table )
|
||||
current = nullptr;
|
||||
}
|
||||
void Dispatcher::FreeValues() {
|
||||
for ( auto& current : table )
|
||||
current = nullptr;
|
||||
}
|
||||
|
||||
void Dispatcher::DumpDebug() const
|
||||
{
|
||||
void Dispatcher::DumpDebug() const {
|
||||
#ifdef DEBUG
|
||||
DBG_LOG(DBG_PACKET_ANALYSIS, "Dispatcher elements (used/total): %lu/%lu", Count(),
|
||||
table.size());
|
||||
for ( size_t i = 0; i < table.size(); i++ )
|
||||
{
|
||||
if ( table[i] != nullptr )
|
||||
DBG_LOG(DBG_PACKET_ANALYSIS, "%#8lx => %s", i + lowest_identifier,
|
||||
table[i]->GetAnalyzerName());
|
||||
}
|
||||
DBG_LOG(DBG_PACKET_ANALYSIS, "Dispatcher elements (used/total): %lu/%lu", Count(), table.size());
|
||||
for ( size_t i = 0; i < table.size(); i++ ) {
|
||||
if ( table[i] != nullptr )
|
||||
DBG_LOG(DBG_PACKET_ANALYSIS, "%#8lx => %s", i + lowest_identifier, table[i]->GetAnalyzerName());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace zeek::packet_analysis
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace zeek::packet_analysis
|
||||
{
|
||||
namespace zeek::packet_analysis {
|
||||
|
||||
class Analyzer; // Forward declaration for Value
|
||||
using AnalyzerPtr = std::shared_ptr<zeek::packet_analysis::Analyzer>;
|
||||
|
@ -16,52 +15,51 @@ using AnalyzerPtr = std::shared_ptr<zeek::packet_analysis::Analyzer>;
|
|||
/**
|
||||
* The Dispatcher class manages identifier-to-analyzer mappings.
|
||||
*/
|
||||
class Dispatcher
|
||||
{
|
||||
class Dispatcher {
|
||||
public:
|
||||
Dispatcher() : table(std::vector<AnalyzerPtr>(1, nullptr)){};
|
||||
~Dispatcher();
|
||||
Dispatcher() : table(std::vector<AnalyzerPtr>(1, nullptr)){};
|
||||
~Dispatcher();
|
||||
|
||||
/**
|
||||
* Register an analyzer for a given identifier.
|
||||
*
|
||||
* @param identifier The identifier.
|
||||
* @param analyzer The analyzer to register.
|
||||
*/
|
||||
void Register(uint32_t identifier, AnalyzerPtr analyzer);
|
||||
/**
|
||||
* Register an analyzer for a given identifier.
|
||||
*
|
||||
* @param identifier The identifier.
|
||||
* @param analyzer The analyzer to register.
|
||||
*/
|
||||
void Register(uint32_t identifier, AnalyzerPtr analyzer);
|
||||
|
||||
/**
|
||||
* Looks up the analyzer for an identifier.
|
||||
*
|
||||
* @param identifier The identifier to look up.
|
||||
* @return The analyzer registered for the given identifier. Returns a
|
||||
* nullptr if no analyzer is registered.
|
||||
*/
|
||||
AnalyzerPtr Lookup(uint32_t identifier) const;
|
||||
/**
|
||||
* Looks up the analyzer for an identifier.
|
||||
*
|
||||
* @param identifier The identifier to look up.
|
||||
* @return The analyzer registered for the given identifier. Returns a
|
||||
* nullptr if no analyzer is registered.
|
||||
*/
|
||||
AnalyzerPtr Lookup(uint32_t identifier) const;
|
||||
|
||||
/**
|
||||
* Returns the number of registered analyzers.
|
||||
* @return Number of registered analyzers.
|
||||
*/
|
||||
size_t Count() const;
|
||||
/**
|
||||
* Returns the number of registered analyzers.
|
||||
* @return Number of registered analyzers.
|
||||
*/
|
||||
size_t Count() const;
|
||||
|
||||
/**
|
||||
* Removes all mappings from the dispatcher.
|
||||
*/
|
||||
void Clear();
|
||||
/**
|
||||
* Removes all mappings from the dispatcher.
|
||||
*/
|
||||
void Clear();
|
||||
|
||||
/**
|
||||
* Dumps out the data structure to the \c analyzer debug stream.
|
||||
*/
|
||||
void DumpDebug() const;
|
||||
/**
|
||||
* Dumps out the data structure to the \c analyzer debug stream.
|
||||
*/
|
||||
void DumpDebug() const;
|
||||
|
||||
private:
|
||||
uint32_t lowest_identifier = 0;
|
||||
std::vector<AnalyzerPtr> table;
|
||||
uint32_t lowest_identifier = 0;
|
||||
std::vector<AnalyzerPtr> table;
|
||||
|
||||
void FreeValues();
|
||||
void FreeValues();
|
||||
|
||||
inline uint32_t GetHighestIdentifier() const { return lowest_identifier + table.size() - 1; }
|
||||
};
|
||||
inline uint32_t GetHighestIdentifier() const { return lowest_identifier + table.size() - 1; }
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace zeek::packet_analysis
|
||||
|
|
|
@ -13,266 +13,228 @@
|
|||
|
||||
using namespace zeek::packet_analysis;
|
||||
|
||||
Manager::Manager()
|
||||
: plugin::ComponentManager<packet_analysis::Component>("PacketAnalyzer", "Tag", "AllAnalyzers")
|
||||
{
|
||||
}
|
||||
Manager::Manager() : plugin::ComponentManager<packet_analysis::Component>("PacketAnalyzer", "Tag", "AllAnalyzers") {}
|
||||
|
||||
Manager::~Manager()
|
||||
{
|
||||
delete pkt_profiler;
|
||||
delete pkt_filter;
|
||||
}
|
||||
Manager::~Manager() {
|
||||
delete pkt_profiler;
|
||||
delete pkt_filter;
|
||||
}
|
||||
|
||||
void Manager::InitPostScript(const std::string& unprocessed_output_file)
|
||||
{
|
||||
// Instantiate objects for all available analyzers
|
||||
for ( const auto& analyzerComponent : GetComponents() )
|
||||
{
|
||||
if ( AnalyzerPtr newAnalyzer = InstantiateAnalyzer(analyzerComponent->Tag()) )
|
||||
{
|
||||
newAnalyzer->SetEnabled(analyzerComponent->Enabled());
|
||||
analyzers.emplace(analyzerComponent->Name(), newAnalyzer);
|
||||
}
|
||||
}
|
||||
void Manager::InitPostScript(const std::string& unprocessed_output_file) {
|
||||
// Instantiate objects for all available analyzers
|
||||
for ( const auto& analyzerComponent : GetComponents() ) {
|
||||
if ( AnalyzerPtr newAnalyzer = InstantiateAnalyzer(analyzerComponent->Tag()) ) {
|
||||
newAnalyzer->SetEnabled(analyzerComponent->Enabled());
|
||||
analyzers.emplace(analyzerComponent->Name(), newAnalyzer);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize all analyzers
|
||||
for ( auto& [name, analyzer] : analyzers )
|
||||
analyzer->Initialize();
|
||||
// Initialize all analyzers
|
||||
for ( auto& [name, analyzer] : analyzers )
|
||||
analyzer->Initialize();
|
||||
|
||||
root_analyzer = analyzers["Root"];
|
||||
root_analyzer = analyzers["Root"];
|
||||
|
||||
auto pkt_profile_file = id::find_val("pkt_profile_file");
|
||||
auto pkt_profile_file = id::find_val("pkt_profile_file");
|
||||
|
||||
if ( detail::pkt_profile_mode && detail::pkt_profile_freq > 0 && pkt_profile_file )
|
||||
pkt_profiler = new detail::PacketProfiler(
|
||||
detail::pkt_profile_mode, detail::pkt_profile_freq, pkt_profile_file->AsFile());
|
||||
if ( detail::pkt_profile_mode && detail::pkt_profile_freq > 0 && pkt_profile_file )
|
||||
pkt_profiler =
|
||||
new detail::PacketProfiler(detail::pkt_profile_mode, detail::pkt_profile_freq, pkt_profile_file->AsFile());
|
||||
|
||||
unknown_sampling_rate = id::find_val("UnknownProtocol::sampling_rate")->AsCount();
|
||||
unknown_sampling_threshold = id::find_val("UnknownProtocol::sampling_threshold")->AsCount();
|
||||
unknown_sampling_duration = id::find_val("UnknownProtocol::sampling_duration")->AsInterval();
|
||||
unknown_first_bytes_count = id::find_val("UnknownProtocol::first_bytes_count")->AsCount();
|
||||
unknown_sampling_rate = id::find_val("UnknownProtocol::sampling_rate")->AsCount();
|
||||
unknown_sampling_threshold = id::find_val("UnknownProtocol::sampling_threshold")->AsCount();
|
||||
unknown_sampling_duration = id::find_val("UnknownProtocol::sampling_duration")->AsInterval();
|
||||
unknown_first_bytes_count = id::find_val("UnknownProtocol::first_bytes_count")->AsCount();
|
||||
|
||||
if ( ! unprocessed_output_file.empty() )
|
||||
// This gets automatically cleaned up by iosource_mgr. No need to delete it locally.
|
||||
unprocessed_dumper = iosource_mgr->OpenPktDumper(unprocessed_output_file, true);
|
||||
}
|
||||
if ( ! unprocessed_output_file.empty() )
|
||||
// This gets automatically cleaned up by iosource_mgr. No need to delete it locally.
|
||||
unprocessed_dumper = iosource_mgr->OpenPktDumper(unprocessed_output_file, true);
|
||||
}
|
||||
|
||||
void Manager::Done() { }
|
||||
void Manager::Done() {}
|
||||
|
||||
void Manager::DumpDebug()
|
||||
{
|
||||
void Manager::DumpDebug() {
|
||||
#ifdef DEBUG
|
||||
DBG_LOG(DBG_PACKET_ANALYSIS, "Available packet analyzers after zeek_init():");
|
||||
for ( auto& current : GetComponents() )
|
||||
DBG_LOG(DBG_PACKET_ANALYSIS, " %s", current->Name().c_str());
|
||||
DBG_LOG(DBG_PACKET_ANALYSIS, "Available packet analyzers after zeek_init():");
|
||||
for ( auto& current : GetComponents() )
|
||||
DBG_LOG(DBG_PACKET_ANALYSIS, " %s", current->Name().c_str());
|
||||
|
||||
DBG_LOG(DBG_PACKET_ANALYSIS, "Packet analyzer debug information:");
|
||||
for ( auto& [name, analyzer] : analyzers )
|
||||
analyzer->DumpDebug();
|
||||
DBG_LOG(DBG_PACKET_ANALYSIS, "Packet analyzer debug information:");
|
||||
for ( auto& [name, analyzer] : analyzers )
|
||||
analyzer->DumpDebug();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
AnalyzerPtr Manager::GetAnalyzer(EnumVal* val)
|
||||
{
|
||||
auto analyzer_comp = Lookup(val);
|
||||
if ( ! analyzer_comp )
|
||||
return nullptr;
|
||||
AnalyzerPtr Manager::GetAnalyzer(EnumVal* val) {
|
||||
auto analyzer_comp = Lookup(val);
|
||||
if ( ! analyzer_comp )
|
||||
return nullptr;
|
||||
|
||||
return GetAnalyzer(analyzer_comp->Name());
|
||||
}
|
||||
return GetAnalyzer(analyzer_comp->Name());
|
||||
}
|
||||
|
||||
AnalyzerPtr Manager::GetAnalyzer(const std::string& name)
|
||||
{
|
||||
auto analyzer_it = analyzers.find(name);
|
||||
if ( analyzer_it == analyzers.end() )
|
||||
return nullptr;
|
||||
AnalyzerPtr Manager::GetAnalyzer(const std::string& name) {
|
||||
auto analyzer_it = analyzers.find(name);
|
||||
if ( analyzer_it == analyzers.end() )
|
||||
return nullptr;
|
||||
|
||||
return analyzer_it->second;
|
||||
}
|
||||
return analyzer_it->second;
|
||||
}
|
||||
|
||||
bool Manager::EnableAnalyzer(EnumVal* tag)
|
||||
{
|
||||
Component* c = Lookup(tag);
|
||||
c->SetEnabled(true);
|
||||
bool Manager::EnableAnalyzer(EnumVal* tag) {
|
||||
Component* c = Lookup(tag);
|
||||
c->SetEnabled(true);
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Manager::DisableAnalyzer(EnumVal* tag)
|
||||
{
|
||||
Component* c = Lookup(tag);
|
||||
c->SetEnabled(false);
|
||||
bool Manager::DisableAnalyzer(EnumVal* tag) {
|
||||
Component* c = Lookup(tag);
|
||||
c->SetEnabled(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Manager::ProcessPacket(Packet* packet)
|
||||
{
|
||||
void Manager::ProcessPacket(Packet* packet) {
|
||||
#ifdef DEBUG
|
||||
static size_t counter = 0;
|
||||
DBG_LOG(DBG_PACKET_ANALYSIS, "Analyzing packet %ld, ts=%.3f...", ++counter, packet->time);
|
||||
static size_t counter = 0;
|
||||
DBG_LOG(DBG_PACKET_ANALYSIS, "Analyzing packet %ld, ts=%.3f...", ++counter, packet->time);
|
||||
#endif
|
||||
|
||||
zeek::detail::SegmentProfiler prof(detail::segment_logger, "dispatching-packet");
|
||||
if ( pkt_profiler )
|
||||
pkt_profiler->ProfilePkt(zeek::run_state::processing_start_time, packet->cap_len);
|
||||
zeek::detail::SegmentProfiler prof(detail::segment_logger, "dispatching-packet");
|
||||
if ( pkt_profiler )
|
||||
pkt_profiler->ProfilePkt(zeek::run_state::processing_start_time, packet->cap_len);
|
||||
|
||||
++num_packets_processed;
|
||||
++num_packets_processed;
|
||||
|
||||
bool dumped_packet = false;
|
||||
if ( packet->dump_packet || zeek::detail::record_all_packets )
|
||||
{
|
||||
DumpPacket(packet, packet->dump_size);
|
||||
dumped_packet = true;
|
||||
}
|
||||
bool dumped_packet = false;
|
||||
if ( packet->dump_packet || zeek::detail::record_all_packets ) {
|
||||
DumpPacket(packet, packet->dump_size);
|
||||
dumped_packet = true;
|
||||
}
|
||||
|
||||
// Start packet analysis
|
||||
root_analyzer->ForwardPacket(packet->cap_len, packet->data, packet, packet->link_type);
|
||||
// Start packet analysis
|
||||
root_analyzer->ForwardPacket(packet->cap_len, packet->data, packet, packet->link_type);
|
||||
|
||||
if ( ! packet->processed )
|
||||
{
|
||||
if ( packet_not_processed )
|
||||
event_mgr.Enqueue(packet_not_processed, Packet::ToVal(packet));
|
||||
if ( ! packet->processed ) {
|
||||
if ( packet_not_processed )
|
||||
event_mgr.Enqueue(packet_not_processed, Packet::ToVal(packet));
|
||||
|
||||
plugin_mgr->HookUnprocessedPacket(packet);
|
||||
plugin_mgr->HookUnprocessedPacket(packet);
|
||||
|
||||
if ( unprocessed_dumper )
|
||||
unprocessed_dumper->Dump(packet);
|
||||
if ( unprocessed_dumper )
|
||||
unprocessed_dumper->Dump(packet);
|
||||
|
||||
total_not_processed++;
|
||||
}
|
||||
total_not_processed++;
|
||||
}
|
||||
|
||||
if ( raw_packet )
|
||||
event_mgr.Enqueue(raw_packet, packet->ToRawPktHdrVal());
|
||||
if ( raw_packet )
|
||||
event_mgr.Enqueue(raw_packet, packet->ToRawPktHdrVal());
|
||||
|
||||
// Check whether packet should be recorded based on session analysis
|
||||
if ( packet->dump_packet && ! dumped_packet )
|
||||
DumpPacket(packet, packet->dump_size);
|
||||
}
|
||||
// Check whether packet should be recorded based on session analysis
|
||||
if ( packet->dump_packet && ! dumped_packet )
|
||||
DumpPacket(packet, packet->dump_size);
|
||||
}
|
||||
|
||||
bool Manager::ProcessInnerPacket(Packet* packet)
|
||||
{
|
||||
return root_analyzer->ForwardPacket(packet->cap_len, packet->data, packet, packet->link_type);
|
||||
}
|
||||
bool Manager::ProcessInnerPacket(Packet* packet) {
|
||||
return root_analyzer->ForwardPacket(packet->cap_len, packet->data, packet, packet->link_type);
|
||||
}
|
||||
|
||||
AnalyzerPtr Manager::InstantiateAnalyzer(const Tag& tag)
|
||||
{
|
||||
Component* c = Lookup(tag);
|
||||
AnalyzerPtr Manager::InstantiateAnalyzer(const Tag& tag) {
|
||||
Component* c = Lookup(tag);
|
||||
|
||||
if ( ! c )
|
||||
{
|
||||
reporter->InternalWarning("request to instantiate unknown packet_analysis");
|
||||
return nullptr;
|
||||
}
|
||||
if ( ! c ) {
|
||||
reporter->InternalWarning("request to instantiate unknown packet_analysis");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if ( ! c->Factory() )
|
||||
{
|
||||
reporter->InternalWarning("analyzer %s cannot be instantiated dynamically",
|
||||
GetComponentName(tag).c_str());
|
||||
return nullptr;
|
||||
}
|
||||
if ( ! c->Factory() ) {
|
||||
reporter->InternalWarning("analyzer %s cannot be instantiated dynamically", GetComponentName(tag).c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AnalyzerPtr a = c->Factory()();
|
||||
AnalyzerPtr a = c->Factory()();
|
||||
|
||||
if ( ! a )
|
||||
{
|
||||
reporter->InternalWarning("analyzer instantiation failed");
|
||||
return nullptr;
|
||||
}
|
||||
if ( ! a ) {
|
||||
reporter->InternalWarning("analyzer instantiation failed");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if ( tag != a->GetAnalyzerTag() )
|
||||
{
|
||||
reporter->InternalError("Mismatch of requested analyzer %s and instantiated analyzer %s. "
|
||||
"This usually means that the plugin author made a mistake.",
|
||||
GetComponentName(tag).c_str(),
|
||||
GetComponentName(a->GetAnalyzerTag()).c_str());
|
||||
}
|
||||
if ( tag != a->GetAnalyzerTag() ) {
|
||||
reporter->InternalError(
|
||||
"Mismatch of requested analyzer %s and instantiated analyzer %s. "
|
||||
"This usually means that the plugin author made a mistake.",
|
||||
GetComponentName(tag).c_str(), GetComponentName(a->GetAnalyzerTag()).c_str());
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
AnalyzerPtr Manager::InstantiateAnalyzer(const std::string& name)
|
||||
{
|
||||
Tag tag = GetComponentTag(name);
|
||||
return tag ? InstantiateAnalyzer(tag) : nullptr;
|
||||
}
|
||||
AnalyzerPtr Manager::InstantiateAnalyzer(const std::string& name) {
|
||||
Tag tag = GetComponentTag(name);
|
||||
return tag ? InstantiateAnalyzer(tag) : nullptr;
|
||||
}
|
||||
|
||||
void Manager::DumpPacket(const Packet* pkt, int len)
|
||||
{
|
||||
if ( ! run_state::detail::pkt_dumper )
|
||||
return;
|
||||
void Manager::DumpPacket(const Packet* pkt, int len) {
|
||||
if ( ! run_state::detail::pkt_dumper )
|
||||
return;
|
||||
|
||||
if ( len != 0 )
|
||||
{
|
||||
if ( (uint32_t)len > pkt->cap_len )
|
||||
reporter->Warning("bad modified caplen");
|
||||
else
|
||||
const_cast<Packet*>(pkt)->cap_len = len;
|
||||
}
|
||||
if ( len != 0 ) {
|
||||
if ( (uint32_t)len > pkt->cap_len )
|
||||
reporter->Warning("bad modified caplen");
|
||||
else
|
||||
const_cast<Packet*>(pkt)->cap_len = len;
|
||||
}
|
||||
|
||||
run_state::detail::pkt_dumper->Dump(pkt);
|
||||
}
|
||||
run_state::detail::pkt_dumper->Dump(pkt);
|
||||
}
|
||||
|
||||
class UnknownProtocolTimer final : public zeek::detail::Timer
|
||||
{
|
||||
class UnknownProtocolTimer final : public zeek::detail::Timer {
|
||||
public:
|
||||
// Represents a combination of an analyzer name and protocol identifier, where the identifier
|
||||
// was reported as unknown by the analyzer.
|
||||
using UnknownProtocolPair = std::pair<std::string, uint32_t>;
|
||||
// Represents a combination of an analyzer name and protocol identifier, where the identifier
|
||||
// was reported as unknown by the analyzer.
|
||||
using UnknownProtocolPair = std::pair<std::string, uint32_t>;
|
||||
|
||||
UnknownProtocolTimer(double t, UnknownProtocolPair p, double timeout)
|
||||
: zeek::detail::Timer(t + timeout, zeek::detail::TIMER_UNKNOWN_PROTOCOL_EXPIRE),
|
||||
unknown_protocol(std::move(p))
|
||||
{
|
||||
}
|
||||
UnknownProtocolTimer(double t, UnknownProtocolPair p, double timeout)
|
||||
: zeek::detail::Timer(t + timeout, zeek::detail::TIMER_UNKNOWN_PROTOCOL_EXPIRE),
|
||||
unknown_protocol(std::move(p)) {}
|
||||
|
||||
void Dispatch(double t, bool is_expire) override
|
||||
{
|
||||
zeek::packet_mgr->ResetUnknownProtocolTimer(unknown_protocol.first,
|
||||
unknown_protocol.second);
|
||||
}
|
||||
void Dispatch(double t, bool is_expire) override {
|
||||
zeek::packet_mgr->ResetUnknownProtocolTimer(unknown_protocol.first, unknown_protocol.second);
|
||||
}
|
||||
|
||||
UnknownProtocolPair unknown_protocol;
|
||||
};
|
||||
UnknownProtocolPair unknown_protocol;
|
||||
};
|
||||
|
||||
void Manager::ResetUnknownProtocolTimer(const std::string& analyzer, uint32_t protocol)
|
||||
{
|
||||
unknown_protocols.erase(std::make_pair(analyzer, protocol));
|
||||
}
|
||||
void Manager::ResetUnknownProtocolTimer(const std::string& analyzer, uint32_t protocol) {
|
||||
unknown_protocols.erase(std::make_pair(analyzer, protocol));
|
||||
}
|
||||
|
||||
bool Manager::PermitUnknownProtocol(const std::string& analyzer, uint32_t protocol)
|
||||
{
|
||||
auto p = std::make_pair(analyzer, protocol);
|
||||
uint64_t& count = unknown_protocols[p];
|
||||
++count;
|
||||
bool Manager::PermitUnknownProtocol(const std::string& analyzer, uint32_t protocol) {
|
||||
auto p = std::make_pair(analyzer, protocol);
|
||||
uint64_t& count = unknown_protocols[p];
|
||||
++count;
|
||||
|
||||
if ( count == 1 )
|
||||
detail::timer_mgr->Add(
|
||||
new UnknownProtocolTimer(run_state::network_time, p, unknown_sampling_duration));
|
||||
if ( count == 1 )
|
||||
detail::timer_mgr->Add(new UnknownProtocolTimer(run_state::network_time, p, unknown_sampling_duration));
|
||||
|
||||
if ( count < unknown_sampling_threshold )
|
||||
return true;
|
||||
if ( count < unknown_sampling_threshold )
|
||||
return true;
|
||||
|
||||
auto num_above_threshold = count - unknown_sampling_threshold;
|
||||
if ( unknown_sampling_rate )
|
||||
return num_above_threshold % unknown_sampling_rate == 0;
|
||||
auto num_above_threshold = count - unknown_sampling_threshold;
|
||||
if ( unknown_sampling_rate )
|
||||
return num_above_threshold % unknown_sampling_rate == 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Manager::ReportUnknownProtocol(const std::string& analyzer, uint32_t protocol,
|
||||
const uint8_t* data, size_t len)
|
||||
{
|
||||
if ( unknown_protocol )
|
||||
{
|
||||
if ( PermitUnknownProtocol(analyzer, protocol) )
|
||||
{
|
||||
int bytes_len = std::min(unknown_first_bytes_count, static_cast<uint64_t>(len));
|
||||
void Manager::ReportUnknownProtocol(const std::string& analyzer, uint32_t protocol, const uint8_t* data, size_t len) {
|
||||
if ( unknown_protocol ) {
|
||||
if ( PermitUnknownProtocol(analyzer, protocol) ) {
|
||||
int bytes_len = std::min(unknown_first_bytes_count, static_cast<uint64_t>(len));
|
||||
|
||||
event_mgr.Enqueue(unknown_protocol, make_intrusive<StringVal>(analyzer),
|
||||
val_mgr->Count(protocol),
|
||||
make_intrusive<StringVal>(bytes_len, (const char*)data));
|
||||
}
|
||||
}
|
||||
}
|
||||
event_mgr.Enqueue(unknown_protocol, make_intrusive<StringVal>(analyzer), val_mgr->Count(protocol),
|
||||
make_intrusive<StringVal>(bytes_len, (const char*)data));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,222 +10,216 @@
|
|||
#include "zeek/packet_analysis/Dispatcher.h"
|
||||
#include "zeek/plugin/ComponentManager.h"
|
||||
|
||||
namespace zeek
|
||||
{
|
||||
namespace zeek {
|
||||
|
||||
namespace detail
|
||||
{
|
||||
namespace detail {
|
||||
class PacketProfiler;
|
||||
}
|
||||
}
|
||||
|
||||
namespace iosource
|
||||
{
|
||||
namespace iosource {
|
||||
class PktDumper;
|
||||
}
|
||||
}
|
||||
|
||||
namespace packet_analysis
|
||||
{
|
||||
namespace packet_analysis {
|
||||
|
||||
class Analyzer;
|
||||
using AnalyzerPtr = std::shared_ptr<Analyzer>;
|
||||
|
||||
class Manager : public plugin::ComponentManager<Component>
|
||||
{
|
||||
class Manager : public plugin::ComponentManager<Component> {
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
Manager();
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
Manager();
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~Manager();
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~Manager();
|
||||
|
||||
/**
|
||||
* Second-stage initialization of the manager. This is called late
|
||||
* during Zeek's initialization after any scripts are processed.
|
||||
*
|
||||
* @param unprocessed_output_file A path to a file where unprocessed
|
||||
* packets will be written. This can be an empty string to disable
|
||||
* writing packets.
|
||||
*/
|
||||
void InitPostScript(const std::string& unprocessed_output_file);
|
||||
/**
|
||||
* Second-stage initialization of the manager. This is called late
|
||||
* during Zeek's initialization after any scripts are processed.
|
||||
*
|
||||
* @param unprocessed_output_file A path to a file where unprocessed
|
||||
* packets will be written. This can be an empty string to disable
|
||||
* writing packets.
|
||||
*/
|
||||
void InitPostScript(const std::string& unprocessed_output_file);
|
||||
|
||||
/**
|
||||
* Finished the manager's operations.
|
||||
*/
|
||||
void Done();
|
||||
/**
|
||||
* Finished the manager's operations.
|
||||
*/
|
||||
void Done();
|
||||
|
||||
/**
|
||||
* Dumps out the state of all registered analyzers to the \c analyzer
|
||||
* debug stream. Should be called only after any \c zeek_init events
|
||||
* have executed to ensure that any of their changes are applied.
|
||||
*/
|
||||
void DumpDebug(); // Called after zeek_init() events.
|
||||
/**
|
||||
* Dumps out the state of all registered analyzers to the \c analyzer
|
||||
* debug stream. Should be called only after any \c zeek_init events
|
||||
* have executed to ensure that any of their changes are applied.
|
||||
*/
|
||||
void DumpDebug(); // Called after zeek_init() events.
|
||||
|
||||
/**
|
||||
* Looks up an analyzer instance.
|
||||
*
|
||||
* @param val The analyzer's tag value.
|
||||
*
|
||||
* @return The analyzer instance or nullptr if no instance is found.
|
||||
*/
|
||||
AnalyzerPtr GetAnalyzer(EnumVal* val);
|
||||
/**
|
||||
* Looks up an analyzer instance.
|
||||
*
|
||||
* @param val The analyzer's tag value.
|
||||
*
|
||||
* @return The analyzer instance or nullptr if no instance is found.
|
||||
*/
|
||||
AnalyzerPtr GetAnalyzer(EnumVal* val);
|
||||
|
||||
/**
|
||||
* Looks up an analyzer instance.
|
||||
*
|
||||
* @param name The name of the analyzer.
|
||||
*
|
||||
* @return The analyzer instance or nullptr if no instance is found.
|
||||
*/
|
||||
AnalyzerPtr GetAnalyzer(const std::string& name);
|
||||
/**
|
||||
* Looks up an analyzer instance.
|
||||
*
|
||||
* @param name The name of the analyzer.
|
||||
*
|
||||
* @return The analyzer instance or nullptr if no instance is found.
|
||||
*/
|
||||
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(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()); }
|
||||
/**
|
||||
* 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(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()); };
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param packet The packet to process.
|
||||
*/
|
||||
void ProcessPacket(Packet* packet);
|
||||
/**
|
||||
* Processes a packet by applying the configured packet analyzers.
|
||||
*
|
||||
* @param packet The packet to process.
|
||||
*/
|
||||
void ProcessPacket(Packet* packet);
|
||||
|
||||
/**
|
||||
* Process the inner packet of an encapsulation. This can be used by tunnel
|
||||
* analyzers to process a inner packet from the "beginning" directly through
|
||||
* the root analyzer. This short-circuits some of the additional processing
|
||||
* that happens in ProcessPacket().
|
||||
*
|
||||
* @param packet The packet to process.
|
||||
*/
|
||||
bool ProcessInnerPacket(Packet* packet);
|
||||
/**
|
||||
* Process the inner packet of an encapsulation. This can be used by tunnel
|
||||
* analyzers to process a inner packet from the "beginning" directly through
|
||||
* the root analyzer. This short-circuits some of the additional processing
|
||||
* that happens in ProcessPacket().
|
||||
*
|
||||
* @param packet The packet to process.
|
||||
*/
|
||||
bool ProcessInnerPacket(Packet* packet);
|
||||
|
||||
uint64_t PacketsProcessed() const { return num_packets_processed; }
|
||||
uint64_t PacketsProcessed() const { return num_packets_processed; }
|
||||
|
||||
/**
|
||||
* Records the given packet if a dumper is active.
|
||||
*
|
||||
* @param pkt The packet to record.
|
||||
* @param len The number of bytes to record. If set to zero, the whole
|
||||
* packet is recorded.
|
||||
*/
|
||||
void DumpPacket(const Packet* pkt, int len = 0);
|
||||
/**
|
||||
* Records the given packet if a dumper is active.
|
||||
*
|
||||
* @param pkt The packet to record.
|
||||
* @param len The number of bytes to record. If set to zero, the whole
|
||||
* packet is recorded.
|
||||
*/
|
||||
void DumpPacket(const Packet* pkt, int len = 0);
|
||||
|
||||
/**
|
||||
* Attempts to write an entry to unknown_protocols.log, rate-limited to avoid
|
||||
* spamming the log with duplicates.
|
||||
*
|
||||
* @param analyzer The name of the analyzer that was trying to forward the packet.
|
||||
* @param protocol The protocol of the next header that couldn't be forwarded.
|
||||
* @param data A pointer to the data of the next header being processed. If this
|
||||
* is passed as a nullptr, the first_bytes log column will be blank.
|
||||
* @param len The remaining length of the data in the packet being processed.
|
||||
*/
|
||||
void ReportUnknownProtocol(const std::string& analyzer, uint32_t protocol,
|
||||
const uint8_t* data = nullptr, size_t len = 0);
|
||||
/**
|
||||
* Attempts to write an entry to unknown_protocols.log, rate-limited to avoid
|
||||
* spamming the log with duplicates.
|
||||
*
|
||||
* @param analyzer The name of the analyzer that was trying to forward the packet.
|
||||
* @param protocol The protocol of the next header that couldn't be forwarded.
|
||||
* @param data A pointer to the data of the next header being processed. If this
|
||||
* is passed as a nullptr, the first_bytes log column will be blank.
|
||||
* @param len The remaining length of the data in the packet being processed.
|
||||
*/
|
||||
void ReportUnknownProtocol(const std::string& analyzer, uint32_t protocol, const uint8_t* data = nullptr,
|
||||
size_t len = 0);
|
||||
|
||||
/**
|
||||
* Callback method for UnknownProtocolTimer to remove an analyzer/protocol
|
||||
* pair from the map so that it can be logged again.
|
||||
*/
|
||||
void ResetUnknownProtocolTimer(const std::string& analyzer, uint32_t protocol);
|
||||
/**
|
||||
* Callback method for UnknownProtocolTimer to remove an analyzer/protocol
|
||||
* pair from the map so that it can be logged again.
|
||||
*/
|
||||
void ResetUnknownProtocolTimer(const std::string& analyzer, uint32_t protocol);
|
||||
|
||||
detail::PacketFilter* GetPacketFilter(bool init = true)
|
||||
{
|
||||
if ( ! pkt_filter && init )
|
||||
pkt_filter = new detail::PacketFilter(detail::packet_filter_default);
|
||||
return pkt_filter;
|
||||
}
|
||||
detail::PacketFilter* GetPacketFilter(bool init = true) {
|
||||
if ( ! pkt_filter && init )
|
||||
pkt_filter = new detail::PacketFilter(detail::packet_filter_default);
|
||||
return pkt_filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total number of packets received that weren't considered
|
||||
* processed by some analyzer.
|
||||
*/
|
||||
uint64_t GetUnprocessedCount() const { return total_not_processed; }
|
||||
/**
|
||||
* Returns the total number of packets received that weren't considered
|
||||
* processed by some analyzer.
|
||||
*/
|
||||
uint64_t GetUnprocessedCount() const { return total_not_processed; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* Instantiates a new analyzer instance.
|
||||
*
|
||||
* @param tag The analyzer's tag.
|
||||
*
|
||||
* @return The new analyzer instance. Returns null if tag is invalid, the
|
||||
* requested analyzer is disabled, or the analyzer can't be instantiated.
|
||||
*/
|
||||
AnalyzerPtr InstantiateAnalyzer(const zeek::Tag& tag);
|
||||
/**
|
||||
* Instantiates a new analyzer instance.
|
||||
*
|
||||
* @param tag The analyzer's tag.
|
||||
*
|
||||
* @return The new analyzer instance. Returns null if tag is invalid, the
|
||||
* requested analyzer is disabled, or the analyzer can't be instantiated.
|
||||
*/
|
||||
AnalyzerPtr InstantiateAnalyzer(const zeek::Tag& tag);
|
||||
|
||||
/**
|
||||
* Instantiates a new analyzer.
|
||||
*
|
||||
* @param name The name of the analyzer.
|
||||
*
|
||||
* @return The new analyzer instance. Returns null if the name is not known
|
||||
* or if the requested analyzer that is disabled.
|
||||
*/
|
||||
AnalyzerPtr InstantiateAnalyzer(const std::string& name);
|
||||
/**
|
||||
* Instantiates a new analyzer.
|
||||
*
|
||||
* @param name The name of the analyzer.
|
||||
*
|
||||
* @return The new analyzer instance. Returns null if the name is not known
|
||||
* or if the requested analyzer that is disabled.
|
||||
*/
|
||||
AnalyzerPtr InstantiateAnalyzer(const std::string& name);
|
||||
|
||||
bool PermitUnknownProtocol(const std::string& analyzer, uint32_t protocol);
|
||||
bool PermitUnknownProtocol(const std::string& analyzer, uint32_t protocol);
|
||||
|
||||
std::map<std::string, AnalyzerPtr> analyzers;
|
||||
AnalyzerPtr root_analyzer = nullptr;
|
||||
std::map<std::string, AnalyzerPtr> analyzers;
|
||||
AnalyzerPtr root_analyzer = nullptr;
|
||||
|
||||
uint64_t num_packets_processed = 0;
|
||||
detail::PacketProfiler* pkt_profiler = nullptr;
|
||||
detail::PacketFilter* pkt_filter = nullptr;
|
||||
uint64_t num_packets_processed = 0;
|
||||
detail::PacketProfiler* pkt_profiler = nullptr;
|
||||
detail::PacketFilter* pkt_filter = nullptr;
|
||||
|
||||
using UnknownProtocolPair = std::pair<std::string, uint32_t>;
|
||||
std::map<UnknownProtocolPair, uint64_t> unknown_protocols;
|
||||
using UnknownProtocolPair = std::pair<std::string, uint32_t>;
|
||||
std::map<UnknownProtocolPair, uint64_t> unknown_protocols;
|
||||
|
||||
uint64_t unknown_sampling_threshold = 0;
|
||||
uint64_t unknown_sampling_rate = 0;
|
||||
double unknown_sampling_duration = 0;
|
||||
uint64_t unknown_first_bytes_count = 0;
|
||||
uint64_t unknown_sampling_threshold = 0;
|
||||
uint64_t unknown_sampling_rate = 0;
|
||||
double unknown_sampling_duration = 0;
|
||||
uint64_t unknown_first_bytes_count = 0;
|
||||
|
||||
uint64_t total_not_processed = 0;
|
||||
iosource::PktDumper* unprocessed_dumper = nullptr;
|
||||
};
|
||||
uint64_t total_not_processed = 0;
|
||||
iosource::PktDumper* unprocessed_dumper = nullptr;
|
||||
};
|
||||
|
||||
} // namespace packet_analysis
|
||||
} // namespace packet_analysis
|
||||
|
||||
extern zeek::packet_analysis::Manager* packet_mgr;
|
||||
|
||||
} // namespace zeek
|
||||
} // namespace zeek
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
using namespace zeek::packet_analysis::ARP;
|
||||
|
||||
ARPAnalyzer::ARPAnalyzer() : zeek::packet_analysis::Analyzer("ARP") { }
|
||||
ARPAnalyzer::ARPAnalyzer() : zeek::packet_analysis::Analyzer("ARP") {}
|
||||
|
||||
// Argh! FreeBSD and Linux have almost completely different net/if_arp.h .
|
||||
// ... and on Solaris we are missing half of the ARPOP codes, so define
|
||||
|
@ -84,165 +84,140 @@ ARPAnalyzer::ARPAnalyzer() : zeek::packet_analysis::Analyzer("ARP") { }
|
|||
#define ARPHRD_IEEE802 6
|
||||
#endif
|
||||
|
||||
bool ARPAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet)
|
||||
{
|
||||
packet->l3_proto = L3_ARP;
|
||||
bool ARPAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) {
|
||||
packet->l3_proto = L3_ARP;
|
||||
|
||||
// Check whether the header is complete.
|
||||
if ( sizeof(struct arp_pkthdr) > len )
|
||||
{
|
||||
Weird("truncated_ARP", packet);
|
||||
return false;
|
||||
}
|
||||
// Check whether the header is complete.
|
||||
if ( sizeof(struct arp_pkthdr) > len ) {
|
||||
Weird("truncated_ARP", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check whether the packet is OK ("inspired" in tcpdump's print-arp.c).
|
||||
auto ah = (const struct arp_pkthdr*)data;
|
||||
// Check whether the packet is OK ("inspired" in tcpdump's print-arp.c).
|
||||
auto ah = (const struct arp_pkthdr*)data;
|
||||
|
||||
// Check the size.
|
||||
size_t min_length = (ar_tpa(ah) - (caddr_t)data) + ah->ar_pln;
|
||||
if ( min_length > len )
|
||||
{
|
||||
Weird("truncated_ARP", packet);
|
||||
return false;
|
||||
}
|
||||
// Check the size.
|
||||
size_t min_length = (ar_tpa(ah) - (caddr_t)data) + ah->ar_pln;
|
||||
if ( min_length > len ) {
|
||||
Weird("truncated_ARP", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
// ARP packets are considered processed if we get to this point. There may be issues
|
||||
// with the processing of them, but they're actually an ARP packet and anything else
|
||||
// will be reported via events.
|
||||
packet->processed = true;
|
||||
// ARP packets are considered processed if we get to this point. There may be issues
|
||||
// with the processing of them, but they're actually an ARP packet and anything else
|
||||
// will be reported via events.
|
||||
packet->processed = true;
|
||||
|
||||
// Check the address description fields.
|
||||
switch ( ntohs(ah->ar_hrd) )
|
||||
{
|
||||
case ARPHRD_ETHER:
|
||||
case ARPHRD_IEEE802:
|
||||
if ( ah->ar_hln != 6 )
|
||||
{
|
||||
// don't know how to handle the opcode
|
||||
BadARPEvent(ah, "corrupt-arp-header (hrd=%i, hln=%i)", ntohs(ah->ar_hrd),
|
||||
ah->ar_hln);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
// Check the address description fields.
|
||||
switch ( ntohs(ah->ar_hrd) ) {
|
||||
case ARPHRD_ETHER:
|
||||
case ARPHRD_IEEE802:
|
||||
if ( ah->ar_hln != 6 ) {
|
||||
// don't know how to handle the opcode
|
||||
BadARPEvent(ah, "corrupt-arp-header (hrd=%i, hln=%i)", ntohs(ah->ar_hrd), ah->ar_hln);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
// don't know how to proceed
|
||||
BadARPEvent(ah, "unknown-arp-hw-address (hrd=%i)", ntohs(ah->ar_hrd));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
default: {
|
||||
// don't know how to proceed
|
||||
BadARPEvent(ah, "unknown-arp-hw-address (hrd=%i)", ntohs(ah->ar_hrd));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Note: We don't support IPv6 addresses.
|
||||
switch ( ntohs(ah->ar_pro) )
|
||||
{
|
||||
case ETHERTYPE_IP:
|
||||
if ( ah->ar_pln != 4 )
|
||||
{
|
||||
// don't know how to handle the opcode
|
||||
BadARPEvent(ah, "corrupt-arp-header (pro=%i, pln=%i)", ntohs(ah->ar_pro),
|
||||
ah->ar_pln);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
// Note: We don't support IPv6 addresses.
|
||||
switch ( ntohs(ah->ar_pro) ) {
|
||||
case ETHERTYPE_IP:
|
||||
if ( ah->ar_pln != 4 ) {
|
||||
// don't know how to handle the opcode
|
||||
BadARPEvent(ah, "corrupt-arp-header (pro=%i, pln=%i)", ntohs(ah->ar_pro), ah->ar_pln);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
// don't know how to proceed
|
||||
BadARPEvent(ah, "unknown-arp-proto-address (pro=%i)", ntohs(ah->ar_pro));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
default: {
|
||||
// don't know how to proceed
|
||||
BadARPEvent(ah, "unknown-arp-proto-address (pro=%i)", ntohs(ah->ar_pro));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check MAC src address = ARP sender MAC address.
|
||||
if ( memcmp(packet->l2_src, (const char*)ar_sha(ah), ah->ar_hln) != 0 )
|
||||
{
|
||||
BadARPEvent(ah, "weird-arp-sha");
|
||||
return false;
|
||||
}
|
||||
// Check MAC src address = ARP sender MAC address.
|
||||
if ( memcmp(packet->l2_src, (const char*)ar_sha(ah), ah->ar_hln) != 0 ) {
|
||||
BadARPEvent(ah, "weird-arp-sha");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the code is supported.
|
||||
switch ( ntohs(ah->ar_op) )
|
||||
{
|
||||
case ARPOP_REQUEST:
|
||||
RequestReplyEvent(arp_request, packet->l2_src, packet->l2_dst, ah);
|
||||
break;
|
||||
// Check the code is supported.
|
||||
switch ( ntohs(ah->ar_op) ) {
|
||||
case ARPOP_REQUEST: RequestReplyEvent(arp_request, packet->l2_src, packet->l2_dst, ah); break;
|
||||
|
||||
case ARPOP_REPLY:
|
||||
RequestReplyEvent(arp_reply, packet->l2_src, packet->l2_dst, ah);
|
||||
break;
|
||||
case ARPOP_REPLY: RequestReplyEvent(arp_reply, packet->l2_src, packet->l2_dst, ah); break;
|
||||
|
||||
case ARPOP_REVREQUEST:
|
||||
case ARPOP_REVREPLY:
|
||||
case ARPOP_INVREQUEST:
|
||||
case ARPOP_INVREPLY:
|
||||
{
|
||||
// don't know how to handle the opcode
|
||||
BadARPEvent(ah, "unimplemented-arp-opcode (%i)", ntohs(ah->ar_op));
|
||||
return false;
|
||||
}
|
||||
case ARPOP_REVREQUEST:
|
||||
case ARPOP_REVREPLY:
|
||||
case ARPOP_INVREQUEST:
|
||||
case ARPOP_INVREPLY: {
|
||||
// don't know how to handle the opcode
|
||||
BadARPEvent(ah, "unimplemented-arp-opcode (%i)", ntohs(ah->ar_op));
|
||||
return false;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
// invalid opcode
|
||||
BadARPEvent(ah, "invalid-arp-opcode (opcode=%i)", ntohs(ah->ar_op));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
default: {
|
||||
// invalid opcode
|
||||
BadARPEvent(ah, "invalid-arp-opcode (opcode=%i)", ntohs(ah->ar_op));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Leave packet analyzer land
|
||||
return true;
|
||||
}
|
||||
// Leave packet analyzer land
|
||||
return true;
|
||||
}
|
||||
|
||||
zeek::AddrValPtr ARPAnalyzer::ToAddrVal(const void* addr, size_t len)
|
||||
{
|
||||
if ( len < 4 )
|
||||
return zeek::make_intrusive<zeek::AddrVal>(static_cast<uint32_t>(0));
|
||||
zeek::AddrValPtr ARPAnalyzer::ToAddrVal(const void* addr, size_t len) {
|
||||
if ( len < 4 )
|
||||
return zeek::make_intrusive<zeek::AddrVal>(static_cast<uint32_t>(0));
|
||||
|
||||
// Note: We only handle IPv4 addresses.
|
||||
return zeek::make_intrusive<zeek::AddrVal>(*(const uint32_t*)addr);
|
||||
}
|
||||
// Note: We only handle IPv4 addresses.
|
||||
return zeek::make_intrusive<zeek::AddrVal>(*(const uint32_t*)addr);
|
||||
}
|
||||
|
||||
zeek::StringValPtr ARPAnalyzer::ToEthAddrStr(const u_char* addr, size_t len)
|
||||
{
|
||||
if ( len < 6 )
|
||||
return zeek::make_intrusive<zeek::StringVal>("");
|
||||
zeek::StringValPtr ARPAnalyzer::ToEthAddrStr(const u_char* addr, size_t len) {
|
||||
if ( len < 6 )
|
||||
return zeek::make_intrusive<zeek::StringVal>("");
|
||||
|
||||
char buf[1024];
|
||||
snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x", addr[0], addr[1], addr[2], addr[3],
|
||||
addr[4], addr[5]);
|
||||
return zeek::make_intrusive<zeek::StringVal>(buf);
|
||||
}
|
||||
char buf[1024];
|
||||
snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
|
||||
return zeek::make_intrusive<zeek::StringVal>(buf);
|
||||
}
|
||||
|
||||
void ARPAnalyzer::BadARPEvent(const struct arp_pkthdr* hdr, const char* fmt, ...)
|
||||
{
|
||||
if ( ! bad_arp )
|
||||
return;
|
||||
void ARPAnalyzer::BadARPEvent(const struct arp_pkthdr* hdr, const char* fmt, ...) {
|
||||
if ( ! bad_arp )
|
||||
return;
|
||||
|
||||
char msg[1024];
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(msg, sizeof(msg), fmt, args);
|
||||
va_end(args);
|
||||
char msg[1024];
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(msg, sizeof(msg), fmt, args);
|
||||
va_end(args);
|
||||
|
||||
event_mgr.Enqueue(bad_arp, ToAddrVal(reinterpret_cast<const u_char*>(ar_spa(hdr)), hdr->ar_pln),
|
||||
ToEthAddrStr(reinterpret_cast<const u_char*>(ar_sha(hdr)), hdr->ar_hln),
|
||||
ToAddrVal(reinterpret_cast<const u_char*>(ar_tpa(hdr)), hdr->ar_pln),
|
||||
ToEthAddrStr(reinterpret_cast<const u_char*>(ar_tha(hdr)), hdr->ar_hln),
|
||||
zeek::make_intrusive<zeek::StringVal>(msg));
|
||||
}
|
||||
event_mgr.Enqueue(bad_arp, ToAddrVal(reinterpret_cast<const u_char*>(ar_spa(hdr)), hdr->ar_pln),
|
||||
ToEthAddrStr(reinterpret_cast<const u_char*>(ar_sha(hdr)), hdr->ar_hln),
|
||||
ToAddrVal(reinterpret_cast<const u_char*>(ar_tpa(hdr)), hdr->ar_pln),
|
||||
ToEthAddrStr(reinterpret_cast<const u_char*>(ar_tha(hdr)), hdr->ar_hln),
|
||||
zeek::make_intrusive<zeek::StringVal>(msg));
|
||||
}
|
||||
|
||||
void ARPAnalyzer::RequestReplyEvent(EventHandlerPtr e, const u_char* src, const u_char* dst,
|
||||
const struct arp_pkthdr* hdr)
|
||||
{
|
||||
if ( ! e )
|
||||
return;
|
||||
const struct arp_pkthdr* hdr) {
|
||||
if ( ! e )
|
||||
return;
|
||||
|
||||
// The src and dst pointers are the l2_src and l2_dst addresses from the packet. We assume
|
||||
// that the length of those were validated at some point earlier in the processing.
|
||||
event_mgr.Enqueue(e, ToEthAddrStr(src, 6), ToEthAddrStr(dst, 6),
|
||||
ToAddrVal(ar_spa(hdr), hdr->ar_pln),
|
||||
ToEthAddrStr(reinterpret_cast<const u_char*>(ar_sha(hdr)), hdr->ar_hln),
|
||||
ToAddrVal(ar_tpa(hdr), hdr->ar_pln),
|
||||
ToEthAddrStr(reinterpret_cast<const u_char*>(ar_tha(hdr)), hdr->ar_hln));
|
||||
}
|
||||
// The src and dst pointers are the l2_src and l2_dst addresses from the packet. We assume
|
||||
// that the length of those were validated at some point earlier in the processing.
|
||||
event_mgr.Enqueue(e, ToEthAddrStr(src, 6), ToEthAddrStr(dst, 6), ToAddrVal(ar_spa(hdr), hdr->ar_pln),
|
||||
ToEthAddrStr(reinterpret_cast<const u_char*>(ar_sha(hdr)), hdr->ar_hln),
|
||||
ToAddrVal(ar_tpa(hdr), hdr->ar_pln),
|
||||
ToEthAddrStr(reinterpret_cast<const u_char*>(ar_tha(hdr)), hdr->ar_hln));
|
||||
}
|
||||
|
|
|
@ -15,30 +15,23 @@
|
|||
#define arp_pkthdr arphdr
|
||||
#endif
|
||||
|
||||
namespace zeek::packet_analysis::ARP
|
||||
{
|
||||
namespace zeek::packet_analysis::ARP {
|
||||
|
||||
class ARPAnalyzer : public Analyzer
|
||||
{
|
||||
class ARPAnalyzer : public Analyzer {
|
||||
public:
|
||||
ARPAnalyzer();
|
||||
~ARPAnalyzer() override = default;
|
||||
ARPAnalyzer();
|
||||
~ARPAnalyzer() override = default;
|
||||
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate()
|
||||
{
|
||||
return std::make_shared<ARPAnalyzer>();
|
||||
}
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate() { return std::make_shared<ARPAnalyzer>(); }
|
||||
|
||||
private:
|
||||
zeek::AddrValPtr ToAddrVal(const void* addr, size_t len);
|
||||
zeek::StringValPtr ToEthAddrStr(const u_char* addr, size_t len);
|
||||
zeek::AddrValPtr ToAddrVal(const void* addr, size_t len);
|
||||
zeek::StringValPtr ToEthAddrStr(const u_char* addr, size_t len);
|
||||
|
||||
void BadARPEvent(const struct arp_pkthdr* hdr, const char* fmt, ...)
|
||||
__attribute__((format(printf, 3, 4)));
|
||||
void RequestReplyEvent(EventHandlerPtr e, const u_char* src, const u_char* dst,
|
||||
const struct arp_pkthdr* hdr);
|
||||
};
|
||||
void BadARPEvent(const struct arp_pkthdr* hdr, const char* fmt, ...) __attribute__((format(printf, 3, 4)));
|
||||
void RequestReplyEvent(EventHandlerPtr e, const u_char* src, const u_char* dst, const struct arp_pkthdr* hdr);
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace zeek::packet_analysis::ARP
|
||||
|
|
|
@ -5,23 +5,19 @@
|
|||
#include "zeek/packet_analysis/Component.h"
|
||||
#include "zeek/packet_analysis/protocol/arp/ARP.h"
|
||||
|
||||
namespace zeek::plugin::Zeek_ARP
|
||||
{
|
||||
namespace zeek::plugin::Zeek_ARP {
|
||||
|
||||
class Plugin final : public zeek::plugin::Plugin
|
||||
{
|
||||
class Plugin final : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure() override
|
||||
{
|
||||
AddComponent(new zeek::packet_analysis::Component(
|
||||
"ARP", zeek::packet_analysis::ARP::ARPAnalyzer::Instantiate));
|
||||
zeek::plugin::Configuration Configure() override {
|
||||
AddComponent(new zeek::packet_analysis::Component("ARP", zeek::packet_analysis::ARP::ARPAnalyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::ARP";
|
||||
config.description = "ARP packet analyzer";
|
||||
return config;
|
||||
}
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::ARP";
|
||||
config.description = "ARP packet analyzer";
|
||||
return config;
|
||||
}
|
||||
|
||||
} plugin;
|
||||
} plugin;
|
||||
|
||||
}
|
||||
} // namespace zeek::plugin::Zeek_ARP
|
||||
|
|
|
@ -6,80 +6,72 @@
|
|||
|
||||
using namespace zeek::packet_analysis::AYIYA;
|
||||
|
||||
AYIYAAnalyzer::AYIYAAnalyzer() : zeek::packet_analysis::Analyzer("AYIYA") { }
|
||||
AYIYAAnalyzer::AYIYAAnalyzer() : zeek::packet_analysis::Analyzer("AYIYA") {}
|
||||
|
||||
bool AYIYAAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet)
|
||||
{
|
||||
// AYIYA always comes from a TCP or UDP connection, which means that session
|
||||
// should always be valid and always be a connection. Return a weird if we
|
||||
// didn't have a session stored.
|
||||
if ( ! packet->session )
|
||||
{
|
||||
Analyzer::Weird("ayiya_missing_connection");
|
||||
return false;
|
||||
}
|
||||
else if ( AnalyzerViolated(packet->session) )
|
||||
return false;
|
||||
bool AYIYAAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) {
|
||||
// AYIYA always comes from a TCP or UDP connection, which means that session
|
||||
// should always be valid and always be a connection. Return a weird if we
|
||||
// didn't have a session stored.
|
||||
if ( ! packet->session ) {
|
||||
Analyzer::Weird("ayiya_missing_connection");
|
||||
return false;
|
||||
}
|
||||
else if ( AnalyzerViolated(packet->session) )
|
||||
return false;
|
||||
|
||||
if ( packet->encap && packet->encap->Depth() >= BifConst::Tunnel::max_depth )
|
||||
{
|
||||
Weird("exceeded_tunnel_max_depth", packet);
|
||||
return false;
|
||||
}
|
||||
if ( packet->encap && packet->encap->Depth() >= BifConst::Tunnel::max_depth ) {
|
||||
Weird("exceeded_tunnel_max_depth", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
// This will be expanded based on the header data, but it has to be at least
|
||||
// this long.
|
||||
size_t hdr_size = 8;
|
||||
// This will be expanded based on the header data, but it has to be at least
|
||||
// this long.
|
||||
size_t hdr_size = 8;
|
||||
|
||||
if ( hdr_size > len )
|
||||
{
|
||||
AnalyzerViolation("Truncated AYIYA", packet->session);
|
||||
return false;
|
||||
}
|
||||
if ( hdr_size > len ) {
|
||||
AnalyzerViolation("Truncated AYIYA", packet->session);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t identity_len = 1 << (data[0] >> 4);
|
||||
uint8_t signature_len = (data[1] >> 4) * 4;
|
||||
hdr_size += identity_len + signature_len;
|
||||
uint8_t identity_len = 1 << (data[0] >> 4);
|
||||
uint8_t signature_len = (data[1] >> 4) * 4;
|
||||
hdr_size += identity_len + signature_len;
|
||||
|
||||
// Double-check this one now that we know the actual full length of the header.
|
||||
if ( hdr_size > len )
|
||||
{
|
||||
AnalyzerViolation("Truncated AYIYA", packet->session);
|
||||
return false;
|
||||
}
|
||||
// Double-check this one now that we know the actual full length of the header.
|
||||
if ( hdr_size > len ) {
|
||||
AnalyzerViolation("Truncated AYIYA", packet->session);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t op_code = data[2] & 0x0F;
|
||||
uint8_t op_code = data[2] & 0x0F;
|
||||
|
||||
// Check that op_code is the "forward" command. Everything else is ignored.
|
||||
// This isn't an error, it's just the end of our parsing.
|
||||
if ( op_code != 1 )
|
||||
return true;
|
||||
// Check that op_code is the "forward" command. Everything else is ignored.
|
||||
// This isn't an error, it's just the end of our parsing.
|
||||
if ( op_code != 1 )
|
||||
return true;
|
||||
|
||||
uint8_t next_header = data[3];
|
||||
uint8_t next_header = data[3];
|
||||
|
||||
len -= hdr_size;
|
||||
data += hdr_size;
|
||||
len -= hdr_size;
|
||||
data += hdr_size;
|
||||
|
||||
// We've successfully parsed the AYIYA part, so we might as well confirm this.
|
||||
AnalyzerConfirmation(packet->session);
|
||||
// We've successfully parsed the AYIYA part, so we might as well confirm this.
|
||||
AnalyzerConfirmation(packet->session);
|
||||
|
||||
if ( len == 0 )
|
||||
{
|
||||
// A AYIYA header that isn't followed by a tunnelled packet seems weird.
|
||||
Weird("ayiya_empty_packet", packet);
|
||||
return false;
|
||||
}
|
||||
if ( len == 0 ) {
|
||||
// A AYIYA header that isn't followed by a tunnelled packet seems weird.
|
||||
Weird("ayiya_empty_packet", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
int encap_index = 0;
|
||||
auto inner_packet = packet_analysis::IPTunnel::build_inner_packet(
|
||||
packet, &encap_index, nullptr, len, data, DLT_RAW, BifEnum::Tunnel::AYIYA,
|
||||
GetAnalyzerTag());
|
||||
int encap_index = 0;
|
||||
auto inner_packet = packet_analysis::IPTunnel::build_inner_packet(packet, &encap_index, nullptr, len, data, DLT_RAW,
|
||||
BifEnum::Tunnel::AYIYA, GetAnalyzerTag());
|
||||
|
||||
return ForwardPacket(len, data, inner_packet.get(), next_header);
|
||||
}
|
||||
return ForwardPacket(len, data, inner_packet.get(), next_header);
|
||||
}
|
||||
|
||||
bool AYIYAAnalyzer::DetectProtocol(size_t len, const uint8_t* data, Packet* packet)
|
||||
{
|
||||
// These magic numbers are based on the old DPD entry, which was based on... something?
|
||||
return len >= 3 && data[1] == 0x52 && data[2] == 0x11;
|
||||
}
|
||||
bool AYIYAAnalyzer::DetectProtocol(size_t len, const uint8_t* data, Packet* packet) {
|
||||
// These magic numbers are based on the old DPD entry, which was based on... something?
|
||||
return len >= 3 && data[1] == 0x52 && data[2] == 0x11;
|
||||
}
|
||||
|
|
|
@ -5,23 +5,18 @@
|
|||
#include "zeek/packet_analysis/Analyzer.h"
|
||||
#include "zeek/packet_analysis/Component.h"
|
||||
|
||||
namespace zeek::packet_analysis::AYIYA
|
||||
{
|
||||
namespace zeek::packet_analysis::AYIYA {
|
||||
|
||||
class AYIYAAnalyzer : public zeek::packet_analysis::Analyzer
|
||||
{
|
||||
class AYIYAAnalyzer : public zeek::packet_analysis::Analyzer {
|
||||
public:
|
||||
AYIYAAnalyzer();
|
||||
~AYIYAAnalyzer() override = default;
|
||||
AYIYAAnalyzer();
|
||||
~AYIYAAnalyzer() override = default;
|
||||
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate()
|
||||
{
|
||||
return std::make_shared<AYIYAAnalyzer>();
|
||||
}
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate() { return std::make_shared<AYIYAAnalyzer>(); }
|
||||
|
||||
bool DetectProtocol(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
};
|
||||
bool DetectProtocol(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace zeek::packet_analysis::AYIYA
|
||||
|
|
|
@ -5,23 +5,20 @@
|
|||
#include "zeek/packet_analysis/Component.h"
|
||||
#include "zeek/packet_analysis/protocol/ayiya/AYIYA.h"
|
||||
|
||||
namespace zeek::plugin::Zeek_AYIYA
|
||||
{
|
||||
namespace zeek::plugin::Zeek_AYIYA {
|
||||
|
||||
class Plugin final : public zeek::plugin::Plugin
|
||||
{
|
||||
class Plugin final : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure() override
|
||||
{
|
||||
AddComponent(new zeek::packet_analysis::Component(
|
||||
"AYIYA", zeek::packet_analysis::AYIYA::AYIYAAnalyzer::Instantiate));
|
||||
zeek::plugin::Configuration Configure() override {
|
||||
AddComponent(
|
||||
new zeek::packet_analysis::Component("AYIYA", zeek::packet_analysis::AYIYA::AYIYAAnalyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::AYIYA";
|
||||
config.description = "AYIYA packet analyzer";
|
||||
return config;
|
||||
}
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::AYIYA";
|
||||
config.description = "AYIYA packet analyzer";
|
||||
return config;
|
||||
}
|
||||
|
||||
} plugin;
|
||||
} plugin;
|
||||
|
||||
}
|
||||
} // namespace zeek::plugin::Zeek_AYIYA
|
||||
|
|
|
@ -6,75 +6,67 @@
|
|||
|
||||
using namespace zeek::packet_analysis::Ethernet;
|
||||
|
||||
EthernetAnalyzer::EthernetAnalyzer() : zeek::packet_analysis::Analyzer("Ethernet")
|
||||
{
|
||||
snap_forwarding_key = id::find_val("PacketAnalyzer::ETHERNET::SNAP_FORWARDING_KEY")->AsCount();
|
||||
novell_forwarding_key =
|
||||
id::find_val("PacketAnalyzer::ETHERNET::NOVELL_FORWARDING_KEY")->AsCount();
|
||||
llc_forwarding_key = id::find_val("PacketAnalyzer::ETHERNET::LLC_FORWARDING_KEY")->AsCount();
|
||||
}
|
||||
EthernetAnalyzer::EthernetAnalyzer() : zeek::packet_analysis::Analyzer("Ethernet") {
|
||||
snap_forwarding_key = id::find_val("PacketAnalyzer::ETHERNET::SNAP_FORWARDING_KEY")->AsCount();
|
||||
novell_forwarding_key = id::find_val("PacketAnalyzer::ETHERNET::NOVELL_FORWARDING_KEY")->AsCount();
|
||||
llc_forwarding_key = id::find_val("PacketAnalyzer::ETHERNET::LLC_FORWARDING_KEY")->AsCount();
|
||||
}
|
||||
|
||||
bool EthernetAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet)
|
||||
{
|
||||
// Make sure that we actually got an entire ethernet header before trying
|
||||
// to pull bytes out of it.
|
||||
if ( 16 >= len )
|
||||
{
|
||||
Weird("truncated_ethernet_frame", packet);
|
||||
return false;
|
||||
}
|
||||
bool EthernetAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) {
|
||||
// Make sure that we actually got an entire ethernet header before trying
|
||||
// to pull bytes out of it.
|
||||
if ( 16 >= len ) {
|
||||
Weird("truncated_ethernet_frame", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip past Cisco FabricPath to encapsulated ethernet frame.
|
||||
if ( data[12] == 0x89 && data[13] == 0x03 )
|
||||
{
|
||||
auto constexpr cfplen = 16;
|
||||
// Skip past Cisco FabricPath to encapsulated ethernet frame.
|
||||
if ( data[12] == 0x89 && data[13] == 0x03 ) {
|
||||
auto constexpr cfplen = 16;
|
||||
|
||||
if ( cfplen + 14 >= len )
|
||||
{
|
||||
Weird("truncated_link_header_cfp", packet);
|
||||
return false;
|
||||
}
|
||||
if ( cfplen + 14 >= len ) {
|
||||
Weird("truncated_link_header_cfp", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
data += cfplen;
|
||||
len -= cfplen;
|
||||
}
|
||||
data += cfplen;
|
||||
len -= cfplen;
|
||||
}
|
||||
|
||||
// Get protocol being carried from the ethernet frame.
|
||||
uint32_t protocol = (data[12] << 8) + data[13];
|
||||
// Get protocol being carried from the ethernet frame.
|
||||
uint32_t protocol = (data[12] << 8) + data[13];
|
||||
|
||||
packet->eth_type = protocol;
|
||||
packet->l2_dst = data;
|
||||
packet->l2_src = data + 6;
|
||||
packet->eth_type = protocol;
|
||||
packet->l2_dst = data;
|
||||
packet->l2_src = data + 6;
|
||||
|
||||
// Ethernet II frames
|
||||
if ( protocol >= 1536 )
|
||||
return ForwardPacket(len - 14, data + 14, packet, protocol);
|
||||
// Ethernet II frames
|
||||
if ( protocol >= 1536 )
|
||||
return ForwardPacket(len - 14, data + 14, packet, protocol);
|
||||
|
||||
// Other ethernet frame types
|
||||
if ( protocol <= 1500 )
|
||||
{
|
||||
len -= 14;
|
||||
data += 14;
|
||||
// Other ethernet frame types
|
||||
if ( protocol <= 1500 ) {
|
||||
len -= 14;
|
||||
data += 14;
|
||||
|
||||
if ( len < protocol )
|
||||
{
|
||||
Weird("truncated_ethernet_frame", packet);
|
||||
return false;
|
||||
}
|
||||
if ( len < protocol ) {
|
||||
Weird("truncated_ethernet_frame", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Let specialized analyzers take over for non Ethernet II frames.
|
||||
if ( data[0] == 0xAA && data[1] == 0xAA )
|
||||
// IEEE 802.2 SNAP
|
||||
return ForwardPacket(len, data, packet, snap_forwarding_key);
|
||||
else if ( data[0] == 0xFF && data[1] == 0xFF )
|
||||
// Novell raw IEEE 802.3
|
||||
return ForwardPacket(len, data, packet, novell_forwarding_key);
|
||||
else
|
||||
// IEEE 802.2 LLC
|
||||
return ForwardPacket(len, data, packet, llc_forwarding_key);
|
||||
}
|
||||
// Let specialized analyzers take over for non Ethernet II frames.
|
||||
if ( data[0] == 0xAA && data[1] == 0xAA )
|
||||
// IEEE 802.2 SNAP
|
||||
return ForwardPacket(len, data, packet, snap_forwarding_key);
|
||||
else if ( data[0] == 0xFF && data[1] == 0xFF )
|
||||
// Novell raw IEEE 802.3
|
||||
return ForwardPacket(len, data, packet, novell_forwarding_key);
|
||||
else
|
||||
// IEEE 802.2 LLC
|
||||
return ForwardPacket(len, data, packet, llc_forwarding_key);
|
||||
}
|
||||
|
||||
// Undefined (1500 < EtherType < 1536)
|
||||
Weird("undefined_ether_type", packet);
|
||||
return false;
|
||||
}
|
||||
// Undefined (1500 < EtherType < 1536)
|
||||
Weird("undefined_ether_type", packet);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -5,26 +5,21 @@
|
|||
#include "zeek/packet_analysis/Analyzer.h"
|
||||
#include "zeek/packet_analysis/Component.h"
|
||||
|
||||
namespace zeek::packet_analysis::Ethernet
|
||||
{
|
||||
namespace zeek::packet_analysis::Ethernet {
|
||||
|
||||
class EthernetAnalyzer : public Analyzer
|
||||
{
|
||||
class EthernetAnalyzer : public Analyzer {
|
||||
public:
|
||||
EthernetAnalyzer();
|
||||
~EthernetAnalyzer() override = default;
|
||||
EthernetAnalyzer();
|
||||
~EthernetAnalyzer() override = default;
|
||||
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate()
|
||||
{
|
||||
return std::make_shared<EthernetAnalyzer>();
|
||||
}
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate() { return std::make_shared<EthernetAnalyzer>(); }
|
||||
|
||||
private:
|
||||
zeek_uint_t snap_forwarding_key = 0;
|
||||
zeek_uint_t novell_forwarding_key = 0;
|
||||
zeek_uint_t llc_forwarding_key = 0;
|
||||
};
|
||||
zeek_uint_t snap_forwarding_key = 0;
|
||||
zeek_uint_t novell_forwarding_key = 0;
|
||||
zeek_uint_t llc_forwarding_key = 0;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace zeek::packet_analysis::Ethernet
|
||||
|
|
|
@ -5,23 +5,21 @@
|
|||
#include "zeek/packet_analysis/Component.h"
|
||||
#include "zeek/packet_analysis/protocol/ethernet/Ethernet.h"
|
||||
|
||||
namespace zeek::plugin::Zeek_Ethernet
|
||||
{
|
||||
namespace zeek::plugin::Zeek_Ethernet {
|
||||
|
||||
class Plugin final : public zeek::plugin::Plugin
|
||||
{
|
||||
class Plugin final : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure() override
|
||||
{
|
||||
AddComponent(new zeek::packet_analysis::Component(
|
||||
"Ethernet", zeek::packet_analysis::Ethernet::EthernetAnalyzer::Instantiate));
|
||||
zeek::plugin::Configuration Configure() override {
|
||||
AddComponent(
|
||||
new zeek::packet_analysis::Component("Ethernet",
|
||||
zeek::packet_analysis::Ethernet::EthernetAnalyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::Ethernet";
|
||||
config.description = "Ethernet packet analyzer";
|
||||
return config;
|
||||
}
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::Ethernet";
|
||||
config.description = "Ethernet packet analyzer";
|
||||
return config;
|
||||
}
|
||||
|
||||
} plugin;
|
||||
} plugin;
|
||||
|
||||
}
|
||||
} // namespace zeek::plugin::Zeek_Ethernet
|
||||
|
|
|
@ -4,18 +4,16 @@
|
|||
|
||||
using namespace zeek::packet_analysis::FDDI;
|
||||
|
||||
FDDIAnalyzer::FDDIAnalyzer() : zeek::packet_analysis::Analyzer("FDDI") { }
|
||||
FDDIAnalyzer::FDDIAnalyzer() : zeek::packet_analysis::Analyzer("FDDI") {}
|
||||
|
||||
bool FDDIAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet)
|
||||
{
|
||||
size_t hdr_size = 13 + 8; // FDDI header + LLC
|
||||
bool FDDIAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) {
|
||||
size_t hdr_size = 13 + 8; // FDDI header + LLC
|
||||
|
||||
if ( hdr_size >= len )
|
||||
{
|
||||
Weird("FDDI_analyzer_failed");
|
||||
return false;
|
||||
}
|
||||
if ( hdr_size >= len ) {
|
||||
Weird("FDDI_analyzer_failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
// We just skip the header and hope for default analysis
|
||||
return ForwardPacket(len - hdr_size, data + hdr_size, packet);
|
||||
}
|
||||
// We just skip the header and hope for default analysis
|
||||
return ForwardPacket(len - hdr_size, data + hdr_size, packet);
|
||||
}
|
||||
|
|
|
@ -5,21 +5,16 @@
|
|||
#include "zeek/packet_analysis/Analyzer.h"
|
||||
#include "zeek/packet_analysis/Component.h"
|
||||
|
||||
namespace zeek::packet_analysis::FDDI
|
||||
{
|
||||
namespace zeek::packet_analysis::FDDI {
|
||||
|
||||
class FDDIAnalyzer : public zeek::packet_analysis::Analyzer
|
||||
{
|
||||
class FDDIAnalyzer : public zeek::packet_analysis::Analyzer {
|
||||
public:
|
||||
FDDIAnalyzer();
|
||||
~FDDIAnalyzer() override = default;
|
||||
FDDIAnalyzer();
|
||||
~FDDIAnalyzer() override = default;
|
||||
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate()
|
||||
{
|
||||
return std::make_shared<FDDIAnalyzer>();
|
||||
}
|
||||
};
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate() { return std::make_shared<FDDIAnalyzer>(); }
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace zeek::packet_analysis::FDDI
|
||||
|
|
|
@ -5,23 +5,20 @@
|
|||
#include "zeek/packet_analysis/Component.h"
|
||||
#include "zeek/packet_analysis/protocol/fddi/FDDI.h"
|
||||
|
||||
namespace zeek::plugin::Zeek_FDDI
|
||||
{
|
||||
namespace zeek::plugin::Zeek_FDDI {
|
||||
|
||||
class Plugin final : public zeek::plugin::Plugin
|
||||
{
|
||||
class Plugin final : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure() override
|
||||
{
|
||||
AddComponent(new zeek::packet_analysis::Component(
|
||||
"FDDI", zeek::packet_analysis::FDDI::FDDIAnalyzer::Instantiate));
|
||||
zeek::plugin::Configuration Configure() override {
|
||||
AddComponent(
|
||||
new zeek::packet_analysis::Component("FDDI", zeek::packet_analysis::FDDI::FDDIAnalyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::FDDI";
|
||||
config.description = "FDDI packet analyzer";
|
||||
return config;
|
||||
}
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::FDDI";
|
||||
config.description = "FDDI packet analyzer";
|
||||
return config;
|
||||
}
|
||||
|
||||
} plugin;
|
||||
} plugin;
|
||||
|
||||
}
|
||||
} // namespace zeek::plugin::Zeek_FDDI
|
||||
|
|
|
@ -7,93 +7,82 @@
|
|||
|
||||
using namespace zeek::packet_analysis::Geneve;
|
||||
|
||||
GeneveAnalyzer::GeneveAnalyzer() : zeek::packet_analysis::Analyzer("Geneve") { }
|
||||
GeneveAnalyzer::GeneveAnalyzer() : zeek::packet_analysis::Analyzer("Geneve") {}
|
||||
|
||||
bool GeneveAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet)
|
||||
{
|
||||
// Geneve always comes from a UDP connection, which means that session should always
|
||||
// be valid and always be a connection. Return a weird if we didn't have a session
|
||||
// stored.
|
||||
if ( ! packet->session )
|
||||
{
|
||||
Analyzer::Weird("geneve_missing_connection");
|
||||
return false;
|
||||
}
|
||||
else if ( AnalyzerViolated(packet->session) )
|
||||
return false;
|
||||
bool GeneveAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) {
|
||||
// Geneve always comes from a UDP connection, which means that session should always
|
||||
// be valid and always be a connection. Return a weird if we didn't have a session
|
||||
// stored.
|
||||
if ( ! packet->session ) {
|
||||
Analyzer::Weird("geneve_missing_connection");
|
||||
return false;
|
||||
}
|
||||
else if ( AnalyzerViolated(packet->session) )
|
||||
return false;
|
||||
|
||||
if ( packet->encap && packet->encap->Depth() >= BifConst::Tunnel::max_depth )
|
||||
{
|
||||
Weird("exceeded_tunnel_max_depth", packet);
|
||||
return false;
|
||||
}
|
||||
if ( packet->encap && packet->encap->Depth() >= BifConst::Tunnel::max_depth ) {
|
||||
Weird("exceeded_tunnel_max_depth", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
// This will be expanded based on the length of the options in the header,
|
||||
// but it will be at least this long.
|
||||
uint16_t hdr_size = 8;
|
||||
// This will be expanded based on the length of the options in the header,
|
||||
// but it will be at least this long.
|
||||
uint16_t hdr_size = 8;
|
||||
|
||||
if ( hdr_size > len )
|
||||
{
|
||||
AnalyzerViolation("Geneve header truncation", packet->session,
|
||||
reinterpret_cast<const char*>(data), len);
|
||||
return false;
|
||||
}
|
||||
if ( hdr_size > len ) {
|
||||
AnalyzerViolation("Geneve header truncation", packet->session, reinterpret_cast<const char*>(data), len);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate that the version number is correct. According to the RFC, this
|
||||
// should always be zero, and anything else should be treated as an error.
|
||||
auto version = data[0] >> 6;
|
||||
if ( version != 0 )
|
||||
{
|
||||
Weird("geneve_invalid_version", packet, util::fmt("%d", version));
|
||||
return false;
|
||||
}
|
||||
// Validate that the version number is correct. According to the RFC, this
|
||||
// should always be zero, and anything else should be treated as an error.
|
||||
auto version = data[0] >> 6;
|
||||
if ( version != 0 ) {
|
||||
Weird("geneve_invalid_version", packet, util::fmt("%d", version));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Option length is the number of bytes for options, expressed in 4-byte multiples.
|
||||
uint8_t opt_len = (data[0] & 0x3F) * 4;
|
||||
hdr_size += opt_len;
|
||||
// Option length is the number of bytes for options, expressed in 4-byte multiples.
|
||||
uint8_t opt_len = (data[0] & 0x3F) * 4;
|
||||
hdr_size += opt_len;
|
||||
|
||||
// Double-check this one now that we know the actual full length of the header.
|
||||
if ( hdr_size > len )
|
||||
{
|
||||
AnalyzerViolation("Geneve option header truncation", packet->session,
|
||||
reinterpret_cast<const char*>(data), len);
|
||||
return false;
|
||||
}
|
||||
// Double-check this one now that we know the actual full length of the header.
|
||||
if ( hdr_size > len ) {
|
||||
AnalyzerViolation("Geneve option header truncation", packet->session, reinterpret_cast<const char*>(data), len);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the next header. This will probably be Ethernet (0x6558), but get it
|
||||
// anyways so that the forwarding can do its thing.
|
||||
auto next_header = (data[2] << 8) + data[3];
|
||||
// Get the next header. This will probably be Ethernet (0x6558), but get it
|
||||
// anyways so that the forwarding can do its thing.
|
||||
auto next_header = (data[2] << 8) + data[3];
|
||||
|
||||
// Grab the VNI out of the data before advancing the data pointer
|
||||
auto vni = (data[4] << 16) + (data[5] << 8) + data[6];
|
||||
// Grab the VNI out of the data before advancing the data pointer
|
||||
auto vni = (data[4] << 16) + (data[5] << 8) + data[6];
|
||||
|
||||
len -= hdr_size;
|
||||
data += hdr_size;
|
||||
len -= hdr_size;
|
||||
data += hdr_size;
|
||||
|
||||
// We've successfully parsed the Geneve part, so we might as well confirm this.
|
||||
AnalyzerConfirmation(packet->session);
|
||||
// We've successfully parsed the Geneve part, so we might as well confirm this.
|
||||
AnalyzerConfirmation(packet->session);
|
||||
|
||||
if ( len == 0 )
|
||||
{
|
||||
// A Geneve header that isn't followed by a tunnelled packet seems weird.
|
||||
Weird("geneve_empty_packet", packet);
|
||||
return false;
|
||||
}
|
||||
if ( len == 0 ) {
|
||||
// A Geneve header that isn't followed by a tunnelled packet seems weird.
|
||||
Weird("geneve_empty_packet", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
int encap_index = 0;
|
||||
auto inner_packet = packet_analysis::IPTunnel::build_inner_packet(
|
||||
packet, &encap_index, nullptr, len, data, DLT_RAW, BifEnum::Tunnel::GENEVE,
|
||||
GetAnalyzerTag());
|
||||
int encap_index = 0;
|
||||
auto inner_packet = packet_analysis::IPTunnel::build_inner_packet(packet, &encap_index, nullptr, len, data, DLT_RAW,
|
||||
BifEnum::Tunnel::GENEVE, GetAnalyzerTag());
|
||||
|
||||
bool analysis_succeeded = ForwardPacket(len, data, inner_packet.get(), next_header);
|
||||
bool analysis_succeeded = ForwardPacket(len, data, inner_packet.get(), next_header);
|
||||
|
||||
if ( analysis_succeeded && geneve_packet )
|
||||
{
|
||||
EncapsulatingConn* ec = inner_packet->encap->At(encap_index);
|
||||
if ( ec && ec->ip_hdr )
|
||||
inner_packet->session->EnqueueEvent(geneve_packet, nullptr, packet->session->GetVal(),
|
||||
ec->ip_hdr->ToPktHdrVal(), val_mgr->Count(vni));
|
||||
}
|
||||
if ( analysis_succeeded && geneve_packet ) {
|
||||
EncapsulatingConn* ec = inner_packet->encap->At(encap_index);
|
||||
if ( ec && ec->ip_hdr )
|
||||
inner_packet->session->EnqueueEvent(geneve_packet, nullptr, packet->session->GetVal(),
|
||||
ec->ip_hdr->ToPktHdrVal(), val_mgr->Count(vni));
|
||||
}
|
||||
|
||||
return analysis_succeeded;
|
||||
}
|
||||
return analysis_succeeded;
|
||||
}
|
||||
|
|
|
@ -5,21 +5,16 @@
|
|||
#include "zeek/packet_analysis/Analyzer.h"
|
||||
#include "zeek/packet_analysis/Component.h"
|
||||
|
||||
namespace zeek::packet_analysis::Geneve
|
||||
{
|
||||
namespace zeek::packet_analysis::Geneve {
|
||||
|
||||
class GeneveAnalyzer : public zeek::packet_analysis::Analyzer
|
||||
{
|
||||
class GeneveAnalyzer : public zeek::packet_analysis::Analyzer {
|
||||
public:
|
||||
GeneveAnalyzer();
|
||||
~GeneveAnalyzer() override = default;
|
||||
GeneveAnalyzer();
|
||||
~GeneveAnalyzer() override = default;
|
||||
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate()
|
||||
{
|
||||
return std::make_shared<GeneveAnalyzer>();
|
||||
}
|
||||
};
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate() { return std::make_shared<GeneveAnalyzer>(); }
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace zeek::packet_analysis::Geneve
|
||||
|
|
|
@ -5,23 +5,20 @@
|
|||
#include "zeek/packet_analysis/Component.h"
|
||||
#include "zeek/packet_analysis/protocol/geneve/Geneve.h"
|
||||
|
||||
namespace zeek::plugin::Zeek_Geneve
|
||||
{
|
||||
namespace zeek::plugin::Zeek_Geneve {
|
||||
|
||||
class Plugin final : public zeek::plugin::Plugin
|
||||
{
|
||||
class Plugin final : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure() override
|
||||
{
|
||||
AddComponent(new zeek::packet_analysis::Component(
|
||||
"Geneve", zeek::packet_analysis::Geneve::GeneveAnalyzer::Instantiate));
|
||||
zeek::plugin::Configuration Configure() override {
|
||||
AddComponent(
|
||||
new zeek::packet_analysis::Component("Geneve", zeek::packet_analysis::Geneve::GeneveAnalyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::Geneve";
|
||||
config.description = "Geneve packet analyzer";
|
||||
return config;
|
||||
}
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::Geneve";
|
||||
config.description = "Geneve packet analyzer";
|
||||
return config;
|
||||
}
|
||||
|
||||
} plugin;
|
||||
} plugin;
|
||||
|
||||
}
|
||||
} // namespace zeek::plugin::Zeek_Geneve
|
||||
|
|
|
@ -11,221 +11,192 @@
|
|||
|
||||
using namespace zeek::packet_analysis::GRE;
|
||||
|
||||
static unsigned int gre_header_len(uint16_t flags = 0)
|
||||
{
|
||||
unsigned int len = 4; // Always has 2 byte flags and 2 byte protocol type.
|
||||
static unsigned int gre_header_len(uint16_t flags = 0) {
|
||||
unsigned int len = 4; // Always has 2 byte flags and 2 byte protocol type.
|
||||
|
||||
if ( flags & 0x8000 )
|
||||
// Checksum/Reserved1 present.
|
||||
len += 4;
|
||||
if ( flags & 0x8000 )
|
||||
// Checksum/Reserved1 present.
|
||||
len += 4;
|
||||
|
||||
// Not considering routing presence bit since it's deprecated ...
|
||||
// Not considering routing presence bit since it's deprecated ...
|
||||
|
||||
if ( flags & 0x2000 )
|
||||
// Key present.
|
||||
len += 4;
|
||||
if ( flags & 0x2000 )
|
||||
// Key present.
|
||||
len += 4;
|
||||
|
||||
if ( flags & 0x1000 )
|
||||
// Sequence present.
|
||||
len += 4;
|
||||
if ( flags & 0x1000 )
|
||||
// Sequence present.
|
||||
len += 4;
|
||||
|
||||
if ( flags & 0x0080 )
|
||||
// Acknowledgement present.
|
||||
len += 4;
|
||||
if ( flags & 0x0080 )
|
||||
// Acknowledgement present.
|
||||
len += 4;
|
||||
|
||||
return len;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
GREAnalyzer::GREAnalyzer() : zeek::packet_analysis::Analyzer("GRE") { }
|
||||
GREAnalyzer::GREAnalyzer() : zeek::packet_analysis::Analyzer("GRE") {}
|
||||
|
||||
bool GREAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet)
|
||||
{
|
||||
if ( ! packet->ip_hdr )
|
||||
{
|
||||
reporter->InternalError("GREAnalyzer: ip_hdr not provided from earlier analyzer");
|
||||
return false;
|
||||
}
|
||||
bool GREAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) {
|
||||
if ( ! packet->ip_hdr ) {
|
||||
reporter->InternalError("GREAnalyzer: ip_hdr not provided from earlier analyzer");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( len < gre_header_len() )
|
||||
{
|
||||
Weird("truncated_GRE", packet);
|
||||
return false;
|
||||
}
|
||||
if ( len < gre_header_len() ) {
|
||||
Weird("truncated_GRE", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
int proto = packet->proto;
|
||||
int gre_link_type = DLT_RAW;
|
||||
int proto = packet->proto;
|
||||
int gre_link_type = DLT_RAW;
|
||||
|
||||
uint16_t flags_ver = ntohs(*((uint16_t*)(data + 0)));
|
||||
uint16_t proto_typ = ntohs(*((uint16_t*)(data + 2)));
|
||||
int gre_version = flags_ver & 0x0007;
|
||||
uint16_t flags_ver = ntohs(*((uint16_t*)(data + 0)));
|
||||
uint16_t proto_typ = ntohs(*((uint16_t*)(data + 2)));
|
||||
int gre_version = flags_ver & 0x0007;
|
||||
|
||||
unsigned int eth_len = 0;
|
||||
unsigned int gre_len = gre_header_len(flags_ver);
|
||||
unsigned int pptp_len = gre_version == 1 ? 4 : 0;
|
||||
unsigned int erspan_len = 0;
|
||||
unsigned int eth_len = 0;
|
||||
unsigned int gre_len = gre_header_len(flags_ver);
|
||||
unsigned int pptp_len = gre_version == 1 ? 4 : 0;
|
||||
unsigned int erspan_len = 0;
|
||||
|
||||
if ( gre_version != 0 && gre_version != 1 )
|
||||
{
|
||||
Weird("unknown_gre_version", packet, util::fmt("version=%d", gre_version));
|
||||
return false;
|
||||
}
|
||||
if ( gre_version != 0 && gre_version != 1 ) {
|
||||
Weird("unknown_gre_version", packet, util::fmt("version=%d", gre_version));
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( gre_version == 0 )
|
||||
{
|
||||
if ( proto_typ == 0x6558 )
|
||||
{
|
||||
// transparent ethernet bridging
|
||||
if ( len > gre_len + 14 )
|
||||
{
|
||||
eth_len = 14;
|
||||
gre_link_type = DLT_EN10MB;
|
||||
}
|
||||
else
|
||||
{
|
||||
Weird("truncated_GRE", packet);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ( gre_version == 0 ) {
|
||||
if ( proto_typ == 0x6558 ) {
|
||||
// transparent ethernet bridging
|
||||
if ( len > gre_len + 14 ) {
|
||||
eth_len = 14;
|
||||
gre_link_type = DLT_EN10MB;
|
||||
}
|
||||
else {
|
||||
Weird("truncated_GRE", packet);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
else if ( proto_typ == 0x88be )
|
||||
{
|
||||
if ( len > gre_len + 14 )
|
||||
{
|
||||
// ERSPAN type I
|
||||
erspan_len = 0;
|
||||
eth_len = 14;
|
||||
gre_link_type = DLT_EN10MB;
|
||||
bool have_sequence_header = ((flags_ver & 0x1000) == 0x1000);
|
||||
if ( have_sequence_header )
|
||||
{
|
||||
// ERSPAN type II
|
||||
erspan_len += 8;
|
||||
if ( len < gre_len + eth_len + erspan_len )
|
||||
{
|
||||
Weird("truncated_GRE", packet);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Weird("truncated_GRE", packet);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if ( proto_typ == 0x88be ) {
|
||||
if ( len > gre_len + 14 ) {
|
||||
// ERSPAN type I
|
||||
erspan_len = 0;
|
||||
eth_len = 14;
|
||||
gre_link_type = DLT_EN10MB;
|
||||
bool have_sequence_header = ((flags_ver & 0x1000) == 0x1000);
|
||||
if ( have_sequence_header ) {
|
||||
// ERSPAN type II
|
||||
erspan_len += 8;
|
||||
if ( len < gre_len + eth_len + erspan_len ) {
|
||||
Weird("truncated_GRE", packet);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
Weird("truncated_GRE", packet);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
else if ( proto_typ == 0x22eb )
|
||||
{
|
||||
// ERSPAN type III
|
||||
if ( len > gre_len + 14 + 12 )
|
||||
{
|
||||
erspan_len = 12;
|
||||
eth_len = 14;
|
||||
gre_link_type = DLT_EN10MB;
|
||||
else if ( proto_typ == 0x22eb ) {
|
||||
// ERSPAN type III
|
||||
if ( len > gre_len + 14 + 12 ) {
|
||||
erspan_len = 12;
|
||||
eth_len = 14;
|
||||
gre_link_type = DLT_EN10MB;
|
||||
|
||||
auto flags = data + gre_len + erspan_len - 1;
|
||||
bool have_opt_header = ((*flags & 0x01) == 0x01);
|
||||
auto flags = data + gre_len + erspan_len - 1;
|
||||
bool have_opt_header = ((*flags & 0x01) == 0x01);
|
||||
|
||||
if ( have_opt_header )
|
||||
{
|
||||
if ( len > gre_len + erspan_len + 8 + eth_len )
|
||||
erspan_len += 8;
|
||||
else
|
||||
{
|
||||
Weird("truncated_GRE", packet);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Weird("truncated_GRE", packet);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if ( ((proto_typ & 0x8200) == 0x8200 && (proto_typ & 0x0F) == 0) ||
|
||||
((proto_typ & 0x8300) == 0x8300 && (proto_typ & 0x0F) == 0 &&
|
||||
(proto_typ <= 0x8370)) ||
|
||||
(proto_typ == 0x9000) )
|
||||
{
|
||||
// ARUBA: Set gre_link_type to IEEE802.11 so the IPTUNNEL analyzer uses
|
||||
// that to instantiate the fake tunnel packet, otherwise it'd be using
|
||||
// DLT_RAW which is not correct for ARUBA.
|
||||
if ( len <= gre_len )
|
||||
{
|
||||
Weird("truncated_GRE", packet);
|
||||
return false;
|
||||
}
|
||||
if ( have_opt_header ) {
|
||||
if ( len > gre_len + erspan_len + 8 + eth_len )
|
||||
erspan_len += 8;
|
||||
else {
|
||||
Weird("truncated_GRE", packet);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
Weird("truncated_GRE", packet);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if ( ((proto_typ & 0x8200) == 0x8200 && (proto_typ & 0x0F) == 0) ||
|
||||
((proto_typ & 0x8300) == 0x8300 && (proto_typ & 0x0F) == 0 && (proto_typ <= 0x8370)) ||
|
||||
(proto_typ == 0x9000) ) {
|
||||
// ARUBA: Set gre_link_type to IEEE802.11 so the IPTUNNEL analyzer uses
|
||||
// that to instantiate the fake tunnel packet, otherwise it'd be using
|
||||
// DLT_RAW which is not correct for ARUBA.
|
||||
if ( len <= gre_len ) {
|
||||
Weird("truncated_GRE", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
gre_link_type = DLT_IEEE802_11;
|
||||
proto = proto_typ;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise let the packet analysis forwarding handle it.
|
||||
proto = proto_typ;
|
||||
}
|
||||
}
|
||||
gre_link_type = DLT_IEEE802_11;
|
||||
proto = proto_typ;
|
||||
}
|
||||
else {
|
||||
// Otherwise let the packet analysis forwarding handle it.
|
||||
proto = proto_typ;
|
||||
}
|
||||
}
|
||||
|
||||
else // gre_version == 1
|
||||
{
|
||||
if ( proto_typ != 0x880b )
|
||||
{
|
||||
// Enhanced GRE payload must be PPTP.
|
||||
Weird("egre_protocol_type", packet, util::fmt("proto=%d", proto_typ));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else // gre_version == 1
|
||||
{
|
||||
if ( proto_typ != 0x880b ) {
|
||||
// Enhanced GRE payload must be PPTP.
|
||||
Weird("egre_protocol_type", packet, util::fmt("proto=%d", proto_typ));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( flags_ver & 0x4000 )
|
||||
{
|
||||
// RFC 2784 deprecates the variable length routing field specified by RFC 1701. It could be
|
||||
// parsed here, but easiest to just skip for now.
|
||||
Weird("gre_routing", packet);
|
||||
return false;
|
||||
}
|
||||
if ( flags_ver & 0x4000 ) {
|
||||
// RFC 2784 deprecates the variable length routing field specified by RFC 1701. It could be
|
||||
// parsed here, but easiest to just skip for now.
|
||||
Weird("gre_routing", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( flags_ver & 0x0078 )
|
||||
{
|
||||
// Expect last 4 bits of flags are reserved, undefined.
|
||||
Weird("unknown_gre_flags", packet);
|
||||
return false;
|
||||
}
|
||||
if ( flags_ver & 0x0078 ) {
|
||||
// Expect last 4 bits of flags are reserved, undefined.
|
||||
Weird("unknown_gre_flags", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( len < gre_len + pptp_len + eth_len + erspan_len )
|
||||
{
|
||||
Weird("truncated_GRE", packet);
|
||||
return false;
|
||||
}
|
||||
if ( len < gre_len + pptp_len + eth_len + erspan_len ) {
|
||||
Weird("truncated_GRE", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
// For GRE version 1/PPTP, reset the protocol based on a value from the PPTP header.
|
||||
// TODO: where are these two values defined?
|
||||
if ( gre_version == 1 )
|
||||
{
|
||||
uint16_t pptp_proto = ntohs(*((uint16_t*)(data + gre_len + 2)));
|
||||
// For GRE version 1/PPTP, reset the protocol based on a value from the PPTP header.
|
||||
// TODO: where are these two values defined?
|
||||
if ( gre_version == 1 ) {
|
||||
uint16_t pptp_proto = ntohs(*((uint16_t*)(data + gre_len + 2)));
|
||||
|
||||
if ( pptp_proto != 0x0021 && pptp_proto != 0x0057 )
|
||||
{
|
||||
Weird("non_ip_packet_in_encap", packet);
|
||||
return false;
|
||||
}
|
||||
if ( pptp_proto != 0x0021 && pptp_proto != 0x0057 ) {
|
||||
Weird("non_ip_packet_in_encap", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
proto = (pptp_proto == 0x0021) ? IPPROTO_IPV4 : IPPROTO_IPV6;
|
||||
}
|
||||
proto = (pptp_proto == 0x0021) ? IPPROTO_IPV4 : IPPROTO_IPV6;
|
||||
}
|
||||
|
||||
data += gre_len + pptp_len + erspan_len;
|
||||
len -= gre_len + pptp_len + erspan_len;
|
||||
data += gre_len + pptp_len + erspan_len;
|
||||
len -= gre_len + pptp_len + erspan_len;
|
||||
|
||||
// Treat GRE tunnel like IP tunnels, fallthrough to logic below now that GRE header is stripped
|
||||
// and only payload packet remains. The only thing different is the tunnel type enum value to
|
||||
// use.
|
||||
packet->tunnel_type = BifEnum::Tunnel::GRE;
|
||||
packet->gre_version = gre_version;
|
||||
packet->gre_link_type = gre_link_type;
|
||||
packet->proto = proto;
|
||||
// Treat GRE tunnel like IP tunnels, fallthrough to logic below now that GRE header is stripped
|
||||
// and only payload packet remains. The only thing different is the tunnel type enum value to
|
||||
// use.
|
||||
packet->tunnel_type = BifEnum::Tunnel::GRE;
|
||||
packet->gre_version = gre_version;
|
||||
packet->gre_link_type = gre_link_type;
|
||||
packet->proto = proto;
|
||||
|
||||
// This will default to forwarding into IP Tunnel unless something custom is set up.
|
||||
ForwardPacket(len, data, packet, proto);
|
||||
// This will default to forwarding into IP Tunnel unless something custom is set up.
|
||||
ForwardPacket(len, data, packet, proto);
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -5,21 +5,16 @@
|
|||
#include "zeek/packet_analysis/Analyzer.h"
|
||||
#include "zeek/packet_analysis/Component.h"
|
||||
|
||||
namespace zeek::packet_analysis::GRE
|
||||
{
|
||||
namespace zeek::packet_analysis::GRE {
|
||||
|
||||
class GREAnalyzer : public Analyzer
|
||||
{
|
||||
class GREAnalyzer : public Analyzer {
|
||||
public:
|
||||
GREAnalyzer();
|
||||
~GREAnalyzer() override = default;
|
||||
GREAnalyzer();
|
||||
~GREAnalyzer() override = default;
|
||||
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate()
|
||||
{
|
||||
return std::make_shared<GREAnalyzer>();
|
||||
}
|
||||
};
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate() { return std::make_shared<GREAnalyzer>(); }
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace zeek::packet_analysis::GRE
|
||||
|
|
|
@ -5,23 +5,19 @@
|
|||
#include "zeek/packet_analysis/Component.h"
|
||||
#include "zeek/packet_analysis/protocol/gre/GRE.h"
|
||||
|
||||
namespace zeek::plugin::Zeek_GRE
|
||||
{
|
||||
namespace zeek::plugin::Zeek_GRE {
|
||||
|
||||
class Plugin final : public zeek::plugin::Plugin
|
||||
{
|
||||
class Plugin final : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure() override
|
||||
{
|
||||
AddComponent(new zeek::packet_analysis::Component(
|
||||
"GRE", zeek::packet_analysis::GRE::GREAnalyzer::Instantiate));
|
||||
zeek::plugin::Configuration Configure() override {
|
||||
AddComponent(new zeek::packet_analysis::Component("GRE", zeek::packet_analysis::GRE::GREAnalyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::GRE";
|
||||
config.description = "GRE packet analyzer";
|
||||
return config;
|
||||
}
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::GRE";
|
||||
config.description = "GRE packet analyzer";
|
||||
return config;
|
||||
}
|
||||
|
||||
} plugin;
|
||||
} plugin;
|
||||
|
||||
}
|
||||
} // namespace zeek::plugin::Zeek_GRE
|
||||
|
|
|
@ -6,97 +6,83 @@
|
|||
#include "zeek/packet_analysis/protocol/ip/IP.h"
|
||||
#include "zeek/packet_analysis/protocol/iptunnel/IPTunnel.h"
|
||||
|
||||
namespace zeek::packet_analysis::gtpv1
|
||||
{
|
||||
GTPv1_Analyzer::GTPv1_Analyzer() : zeek::packet_analysis::Analyzer("GTPV1") { }
|
||||
namespace zeek::packet_analysis::gtpv1 {
|
||||
GTPv1_Analyzer::GTPv1_Analyzer() : zeek::packet_analysis::Analyzer("GTPV1") {}
|
||||
|
||||
bool GTPv1_Analyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet)
|
||||
{
|
||||
// GTPv1 always comes from a UDP connection, which means that session should always
|
||||
// be valid and always be a connection. Return a weird if we didn't have a session
|
||||
// stored.
|
||||
if ( ! packet->session )
|
||||
{
|
||||
Analyzer::Weird("gtpv1_missing_connection");
|
||||
return false;
|
||||
}
|
||||
bool GTPv1_Analyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) {
|
||||
// GTPv1 always comes from a UDP connection, which means that session should always
|
||||
// be valid and always be a connection. Return a weird if we didn't have a session
|
||||
// stored.
|
||||
if ( ! packet->session ) {
|
||||
Analyzer::Weird("gtpv1_missing_connection");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto conn = static_cast<Connection*>(packet->session);
|
||||
zeek::detail::ConnKey conn_key = conn->Key();
|
||||
auto conn = static_cast<Connection*>(packet->session);
|
||||
zeek::detail::ConnKey conn_key = conn->Key();
|
||||
|
||||
auto cm_it = conn_map.find(conn_key);
|
||||
if ( cm_it == conn_map.end() )
|
||||
cm_it = conn_map.insert(cm_it,
|
||||
{conn_key, std::make_unique<binpac::GTPv1::GTPv1_Conn>(this)});
|
||||
auto cm_it = conn_map.find(conn_key);
|
||||
if ( cm_it == conn_map.end() )
|
||||
cm_it = conn_map.insert(cm_it, {conn_key, std::make_unique<binpac::GTPv1::GTPv1_Conn>(this)});
|
||||
|
||||
try
|
||||
{
|
||||
cm_it->second->set_raw_packet(packet);
|
||||
cm_it->second->NewData(packet->is_orig, data, data + len);
|
||||
}
|
||||
catch ( const binpac::Exception& e )
|
||||
{
|
||||
AnalyzerViolation(util::fmt("Binpac exception: %s", e.c_msg()), packet->session);
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
cm_it->second->set_raw_packet(packet);
|
||||
cm_it->second->NewData(packet->is_orig, data, data + len);
|
||||
} catch ( const binpac::Exception& e ) {
|
||||
AnalyzerViolation(util::fmt("Binpac exception: %s", e.c_msg()), packet->session);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Inner packet offset not being set means we failed to process somewhere, and SetInnerInfo()
|
||||
// was never called by the binpac code. Assume this is a failure and return false.
|
||||
if ( inner_packet_offset <= 0 )
|
||||
return false;
|
||||
// Inner packet offset not being set means we failed to process somewhere, and SetInnerInfo()
|
||||
// was never called by the binpac code. Assume this is a failure and return false.
|
||||
if ( inner_packet_offset <= 0 )
|
||||
return false;
|
||||
|
||||
auto odata = data;
|
||||
auto olen = len;
|
||||
data += inner_packet_offset;
|
||||
len -= inner_packet_offset;
|
||||
inner_packet_offset = -1;
|
||||
auto odata = data;
|
||||
auto olen = len;
|
||||
data += inner_packet_offset;
|
||||
len -= inner_packet_offset;
|
||||
inner_packet_offset = -1;
|
||||
|
||||
// TODO: i'm not sure about this. on the one hand, we do some error checking with the result
|
||||
// but on the other hand we duplicate this work here. maybe this header could just be stored
|
||||
// and reused in the IP analyzer somehow?
|
||||
std::shared_ptr<IP_Hdr> inner = nullptr;
|
||||
auto result = packet_analysis::IP::ParsePacket(len, data, next_header, inner);
|
||||
// TODO: i'm not sure about this. on the one hand, we do some error checking with the result
|
||||
// but on the other hand we duplicate this work here. maybe this header could just be stored
|
||||
// and reused in the IP analyzer somehow?
|
||||
std::shared_ptr<IP_Hdr> inner = nullptr;
|
||||
auto result = packet_analysis::IP::ParsePacket(len, data, next_header, inner);
|
||||
|
||||
if ( result == packet_analysis::IP::ParseResult::Ok )
|
||||
{
|
||||
cm_it->second->set_valid(packet->is_orig, true);
|
||||
if ( result == packet_analysis::IP::ParseResult::Ok ) {
|
||||
cm_it->second->set_valid(packet->is_orig, true);
|
||||
|
||||
if ( (! BifConst::Tunnel::delay_gtp_confirmation) ||
|
||||
(cm_it->second->valid(true) && cm_it->second->valid(false)) )
|
||||
AnalyzerConfirmation(packet->session);
|
||||
if ( (! BifConst::Tunnel::delay_gtp_confirmation) ||
|
||||
(cm_it->second->valid(true) && cm_it->second->valid(false)) )
|
||||
AnalyzerConfirmation(packet->session);
|
||||
|
||||
if ( gtp_hdr_val )
|
||||
{
|
||||
BifEvent::enqueue_gtpv1_g_pdu_packet(nullptr, conn, std::move(gtp_hdr_val),
|
||||
inner->ToPktHdrVal());
|
||||
gtp_hdr_val = nullptr;
|
||||
}
|
||||
}
|
||||
else if ( result == packet_analysis::IP::ParseResult::BadProtocol )
|
||||
{
|
||||
AnalyzerViolation("Invalid IP version in wrapped packet", packet->session);
|
||||
gtp_hdr_val = nullptr;
|
||||
return false;
|
||||
}
|
||||
else if ( result == packet_analysis::IP::ParseResult::CaplenTooSmall )
|
||||
{
|
||||
AnalyzerViolation("Truncated GTPv1", packet->session);
|
||||
gtp_hdr_val = nullptr;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
AnalyzerViolation("GTPv1 payload length", packet->session);
|
||||
gtp_hdr_val = nullptr;
|
||||
return false;
|
||||
}
|
||||
if ( gtp_hdr_val ) {
|
||||
BifEvent::enqueue_gtpv1_g_pdu_packet(nullptr, conn, std::move(gtp_hdr_val), inner->ToPktHdrVal());
|
||||
gtp_hdr_val = nullptr;
|
||||
}
|
||||
}
|
||||
else if ( result == packet_analysis::IP::ParseResult::BadProtocol ) {
|
||||
AnalyzerViolation("Invalid IP version in wrapped packet", packet->session);
|
||||
gtp_hdr_val = nullptr;
|
||||
return false;
|
||||
}
|
||||
else if ( result == packet_analysis::IP::ParseResult::CaplenTooSmall ) {
|
||||
AnalyzerViolation("Truncated GTPv1", packet->session);
|
||||
gtp_hdr_val = nullptr;
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
AnalyzerViolation("GTPv1 payload length", packet->session);
|
||||
gtp_hdr_val = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
int encap_index = 0;
|
||||
auto inner_packet = packet_analysis::IPTunnel::build_inner_packet(
|
||||
packet, &encap_index, nullptr, len, data, DLT_RAW, BifEnum::Tunnel::GTPv1,
|
||||
GetAnalyzerTag());
|
||||
int encap_index = 0;
|
||||
auto inner_packet = packet_analysis::IPTunnel::build_inner_packet(packet, &encap_index, nullptr, len, data, DLT_RAW,
|
||||
BifEnum::Tunnel::GTPv1, GetAnalyzerTag());
|
||||
|
||||
return ForwardPacket(len, data, inner_packet.get());
|
||||
}
|
||||
return ForwardPacket(len, data, inner_packet.get());
|
||||
}
|
||||
|
||||
} // namespace zeek::packet_analysis::gtpv1
|
||||
} // namespace zeek::packet_analysis::gtpv1
|
||||
|
|
|
@ -4,43 +4,36 @@
|
|||
|
||||
#include "packet_analysis/protocol/gtpv1/gtpv1_pac.h"
|
||||
|
||||
namespace binpac::GTPv1
|
||||
{
|
||||
namespace binpac::GTPv1 {
|
||||
class GTPv1_Conn;
|
||||
}
|
||||
}
|
||||
|
||||
namespace zeek::packet_analysis::gtpv1
|
||||
{
|
||||
namespace zeek::packet_analysis::gtpv1 {
|
||||
|
||||
class GTPv1_Analyzer final : public packet_analysis::Analyzer
|
||||
{
|
||||
class GTPv1_Analyzer final : public packet_analysis::Analyzer {
|
||||
public:
|
||||
explicit GTPv1_Analyzer();
|
||||
~GTPv1_Analyzer() override = default;
|
||||
explicit GTPv1_Analyzer();
|
||||
~GTPv1_Analyzer() override = default;
|
||||
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate()
|
||||
{
|
||||
return std::make_shared<GTPv1_Analyzer>();
|
||||
}
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate() { return std::make_shared<GTPv1_Analyzer>(); }
|
||||
|
||||
void SetInnerInfo(int offset, uint8_t next, RecordValPtr val)
|
||||
{
|
||||
inner_packet_offset = offset;
|
||||
next_header = next;
|
||||
gtp_hdr_val = std::move(val);
|
||||
}
|
||||
void SetInnerInfo(int offset, uint8_t next, RecordValPtr val) {
|
||||
inner_packet_offset = offset;
|
||||
next_header = next;
|
||||
gtp_hdr_val = std::move(val);
|
||||
}
|
||||
|
||||
void RemoveConnection(const zeek::detail::ConnKey& conn_key) { conn_map.erase(conn_key); }
|
||||
void RemoveConnection(const zeek::detail::ConnKey& conn_key) { conn_map.erase(conn_key); }
|
||||
|
||||
protected:
|
||||
using ConnMap = std::map<zeek::detail::ConnKey, std::unique_ptr<binpac::GTPv1::GTPv1_Conn>>;
|
||||
ConnMap conn_map;
|
||||
using ConnMap = std::map<zeek::detail::ConnKey, std::unique_ptr<binpac::GTPv1::GTPv1_Conn>>;
|
||||
ConnMap conn_map;
|
||||
|
||||
int inner_packet_offset = -1;
|
||||
uint8_t next_header = 0;
|
||||
RecordValPtr gtp_hdr_val;
|
||||
};
|
||||
int inner_packet_offset = -1;
|
||||
uint8_t next_header = 0;
|
||||
RecordValPtr gtp_hdr_val;
|
||||
};
|
||||
|
||||
} // namespace zeek::packet_analysis::gtpv1
|
||||
} // namespace zeek::packet_analysis::gtpv1
|
||||
|
|
|
@ -5,22 +5,19 @@
|
|||
#include "zeek/packet_analysis/Component.h"
|
||||
#include "zeek/packet_analysis/protocol/gtpv1/GTPv1.h"
|
||||
|
||||
namespace zeek::plugin::detail::Zeek_GTPv1
|
||||
{
|
||||
namespace zeek::plugin::detail::Zeek_GTPv1 {
|
||||
|
||||
class Plugin final : public zeek::plugin::Plugin
|
||||
{
|
||||
class Plugin final : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure() override
|
||||
{
|
||||
AddComponent(new zeek::packet_analysis::Component(
|
||||
"GTPv1", zeek::packet_analysis::gtpv1::GTPv1_Analyzer::Instantiate));
|
||||
zeek::plugin::Configuration Configure() override {
|
||||
AddComponent(
|
||||
new zeek::packet_analysis::Component("GTPv1", zeek::packet_analysis::gtpv1::GTPv1_Analyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::GTPv1";
|
||||
config.description = "GTPv1 analyzer";
|
||||
return config;
|
||||
}
|
||||
} plugin;
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::GTPv1";
|
||||
config.description = "GTPv1 analyzer";
|
||||
return config;
|
||||
}
|
||||
} plugin;
|
||||
|
||||
} // namespace zeek::plugin::detail::Zeek_GTPv1
|
||||
} // namespace zeek::plugin::detail::Zeek_GTPv1
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -8,87 +8,81 @@
|
|||
#include "zeek/packet_analysis/protocol/ip/IPBasedAnalyzer.h"
|
||||
#include "zeek/packet_analysis/protocol/ip/SessionAdapter.h"
|
||||
|
||||
namespace zeek
|
||||
{
|
||||
namespace zeek {
|
||||
|
||||
class VectorVal;
|
||||
using VectorValPtr = IntrusivePtr<VectorVal>;
|
||||
class RecordVal;
|
||||
using RecordValPtr = IntrusivePtr<RecordVal>;
|
||||
|
||||
namespace packet_analysis::ICMP
|
||||
{
|
||||
namespace packet_analysis::ICMP {
|
||||
|
||||
class ICMPSessionAdapter;
|
||||
|
||||
class ICMPAnalyzer final : public IP::IPBasedAnalyzer
|
||||
{
|
||||
class ICMPAnalyzer final : public IP::IPBasedAnalyzer {
|
||||
public:
|
||||
ICMPAnalyzer();
|
||||
~ICMPAnalyzer() override = default;
|
||||
ICMPAnalyzer();
|
||||
~ICMPAnalyzer() override = default;
|
||||
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate()
|
||||
{
|
||||
return std::make_shared<ICMPAnalyzer>();
|
||||
}
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate() { return std::make_shared<ICMPAnalyzer>(); }
|
||||
|
||||
packet_analysis::IP::SessionAdapter* MakeSessionAdapter(Connection* conn) override;
|
||||
packet_analysis::IP::SessionAdapter* MakeSessionAdapter(Connection* conn) override;
|
||||
|
||||
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;
|
||||
/**
|
||||
* 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;
|
||||
void DeliverPacket(Connection* c, double t, bool is_orig, int remaining, Packet* pkt) override;
|
||||
|
||||
private:
|
||||
void NextICMP4(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data,
|
||||
const IP_Hdr* ip_hdr, ICMPSessionAdapter* adapter);
|
||||
void NextICMP4(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr,
|
||||
ICMPSessionAdapter* adapter);
|
||||
|
||||
void NextICMP6(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data,
|
||||
const IP_Hdr* ip_hdr, ICMPSessionAdapter* adapter);
|
||||
void NextICMP6(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr,
|
||||
ICMPSessionAdapter* adapter);
|
||||
|
||||
void ICMP_Sent(const struct icmp* icmpp, int len, int caplen, int icmpv6, const u_char* data,
|
||||
const IP_Hdr* ip_hdr, ICMPSessionAdapter* adapter);
|
||||
void ICMP_Sent(const struct icmp* icmpp, int len, int caplen, int icmpv6, const u_char* data, const IP_Hdr* ip_hdr,
|
||||
ICMPSessionAdapter* adapter);
|
||||
|
||||
void Echo(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data,
|
||||
const IP_Hdr* ip_hdr, ICMPSessionAdapter* adapter);
|
||||
void Redirect(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data,
|
||||
const IP_Hdr* ip_hdr, ICMPSessionAdapter* adapter);
|
||||
void RouterAdvert(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data,
|
||||
const IP_Hdr* ip_hdr, ICMPSessionAdapter* adapter);
|
||||
void NeighborAdvert(double t, const struct icmp* icmpp, int len, int caplen,
|
||||
const u_char*& data, const IP_Hdr* ip_hdr, ICMPSessionAdapter* adapter);
|
||||
void NeighborSolicit(double t, const struct icmp* icmpp, int len, int caplen,
|
||||
const u_char*& data, const IP_Hdr* ip_hdr, ICMPSessionAdapter* adapter);
|
||||
void RouterSolicit(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data,
|
||||
const IP_Hdr* ip_hdr, ICMPSessionAdapter* adapter);
|
||||
void Echo(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr,
|
||||
ICMPSessionAdapter* adapter);
|
||||
void Redirect(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr,
|
||||
ICMPSessionAdapter* adapter);
|
||||
void RouterAdvert(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data,
|
||||
const IP_Hdr* ip_hdr, ICMPSessionAdapter* adapter);
|
||||
void NeighborAdvert(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data,
|
||||
const IP_Hdr* ip_hdr, ICMPSessionAdapter* adapter);
|
||||
void NeighborSolicit(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data,
|
||||
const IP_Hdr* ip_hdr, ICMPSessionAdapter* adapter);
|
||||
void RouterSolicit(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data,
|
||||
const IP_Hdr* ip_hdr, ICMPSessionAdapter* adapter);
|
||||
|
||||
RecordValPtr BuildInfo(const struct icmp* icmpp, int len, bool icmpv6, const IP_Hdr* ip_hdr);
|
||||
RecordValPtr BuildInfo(const struct icmp* icmpp, int len, bool icmpv6, const IP_Hdr* ip_hdr);
|
||||
|
||||
RecordValPtr ExtractICMP4Context(int len, const u_char*& data);
|
||||
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, ICMPSessionAdapter* adapter);
|
||||
void Context4(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr,
|
||||
ICMPSessionAdapter* adapter);
|
||||
|
||||
TransportProto GetContextProtocol(const IP_Hdr* ip_hdr, uint32_t* src_port, uint32_t* dst_port);
|
||||
TransportProto GetContextProtocol(const IP_Hdr* ip_hdr, uint32_t* src_port, uint32_t* dst_port);
|
||||
|
||||
RecordValPtr ExtractICMP6Context(int len, const u_char*& data);
|
||||
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, ICMPSessionAdapter* adapter);
|
||||
void Context6(double t, const struct icmp* icmpp, int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr,
|
||||
ICMPSessionAdapter* adapter);
|
||||
|
||||
// RFC 4861 Neighbor Discover message options
|
||||
VectorValPtr BuildNDOptionsVal(int caplen, const u_char* data, ICMPSessionAdapter* adapter);
|
||||
// RFC 4861 Neighbor Discover message options
|
||||
VectorValPtr BuildNDOptionsVal(int caplen, const u_char* data, ICMPSessionAdapter* adapter);
|
||||
|
||||
void UpdateEndpointVal(const ValPtr& endp, bool is_orig);
|
||||
};
|
||||
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 packet_analysis::ICMP
|
||||
} // namespace zeek
|
||||
} // namespace packet_analysis::ICMP
|
||||
} // namespace zeek
|
||||
|
|
|
@ -8,77 +8,66 @@
|
|||
using namespace zeek::packet_analysis::ICMP;
|
||||
using namespace zeek::packet_analysis::IP;
|
||||
|
||||
enum ICMP_EndpointState
|
||||
{
|
||||
ICMP_INACTIVE, // no packet seen
|
||||
ICMP_ACTIVE, // packets seen
|
||||
};
|
||||
enum ICMP_EndpointState {
|
||||
ICMP_INACTIVE, // no packet seen
|
||||
ICMP_ACTIVE, // packets seen
|
||||
};
|
||||
|
||||
void ICMPSessionAdapter::AddExtraAnalyzers(Connection* conn)
|
||||
{
|
||||
static zeek::Tag analyzer_connsize = analyzer_mgr->GetComponentTag("CONNSIZE");
|
||||
void ICMPSessionAdapter::AddExtraAnalyzers(Connection* conn) {
|
||||
static zeek::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));
|
||||
}
|
||||
if ( analyzer_mgr->IsEnabled(analyzer_connsize) )
|
||||
// Add ConnSize analyzer. Needs to see packets, not stream.
|
||||
AddChildAnalyzer(new analyzer::conn_size::ConnSize_Analyzer(conn));
|
||||
}
|
||||
|
||||
void ICMPSessionAdapter::UpdateConnVal(zeek::RecordVal* conn_val)
|
||||
{
|
||||
const auto& orig_endp = conn_val->GetField("orig");
|
||||
const auto& resp_endp = conn_val->GetField("resp");
|
||||
void ICMPSessionAdapter::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);
|
||||
UpdateEndpointVal(orig_endp, true);
|
||||
UpdateEndpointVal(resp_endp, false);
|
||||
|
||||
analyzer::Analyzer::UpdateConnVal(conn_val);
|
||||
}
|
||||
analyzer::Analyzer::UpdateConnVal(conn_val);
|
||||
}
|
||||
|
||||
void ICMPSessionAdapter::UpdateEndpointVal(const ValPtr& endp_arg, bool is_orig)
|
||||
{
|
||||
Conn()->EnableStatusUpdateTimer();
|
||||
void ICMPSessionAdapter::UpdateEndpointVal(const ValPtr& endp_arg, bool is_orig) {
|
||||
Conn()->EnableStatusUpdateTimer();
|
||||
|
||||
int size = is_orig ? request_len : reply_len;
|
||||
auto endp = endp_arg->AsRecordVal();
|
||||
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)));
|
||||
}
|
||||
}
|
||||
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 ICMPSessionAdapter::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 ICMPSessionAdapter::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 ICMPSessionAdapter::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 ICMPSessionAdapter::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 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 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 ICMPSessionAdapter::Done()
|
||||
{
|
||||
SessionAdapter::Done();
|
||||
matcher_state.FinishEndpointMatcher();
|
||||
}
|
||||
void ICMPSessionAdapter::Done() {
|
||||
SessionAdapter::Done();
|
||||
matcher_state.FinishEndpointMatcher();
|
||||
}
|
||||
|
|
|
@ -5,29 +5,26 @@
|
|||
#include "zeek/RuleMatcher.h"
|
||||
#include "zeek/packet_analysis/protocol/ip/SessionAdapter.h"
|
||||
|
||||
namespace zeek::packet_analysis::ICMP
|
||||
{
|
||||
|
||||
class ICMPSessionAdapter final : public IP::SessionAdapter
|
||||
{
|
||||
namespace zeek::packet_analysis::ICMP {
|
||||
|
||||
class ICMPSessionAdapter final : public IP::SessionAdapter {
|
||||
public:
|
||||
ICMPSessionAdapter(Connection* conn) : IP::SessionAdapter("ICMP", conn) { }
|
||||
ICMPSessionAdapter(Connection* conn) : IP::SessionAdapter("ICMP", conn) {}
|
||||
|
||||
void AddExtraAnalyzers(Connection* conn) override;
|
||||
void UpdateConnVal(RecordVal* conn_val) override;
|
||||
void UpdateEndpointVal(const ValPtr& endp, bool is_orig);
|
||||
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 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);
|
||||
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;
|
||||
};
|
||||
detail::RuleMatcherState matcher_state;
|
||||
int request_len = -1;
|
||||
int reply_len = -1;
|
||||
};
|
||||
|
||||
} // namespace zeek::packet_analysis::ICMP
|
||||
} // namespace zeek::packet_analysis::ICMP
|
||||
|
|
|
@ -7,24 +7,21 @@
|
|||
#include "zeek/packet_analysis/protocol/icmp/ICMP.h"
|
||||
#include "zeek/packet_analysis/protocol/icmp/ICMPSessionAdapter.h"
|
||||
|
||||
namespace zeek::plugin::Zeek_ICMP
|
||||
{
|
||||
namespace zeek::plugin::Zeek_ICMP {
|
||||
|
||||
class Plugin final : public zeek::plugin::Plugin
|
||||
{
|
||||
class Plugin final : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure() override
|
||||
{
|
||||
AddComponent(new zeek::packet_analysis::Component(
|
||||
"ICMP", zeek::packet_analysis::ICMP::ICMPAnalyzer::Instantiate));
|
||||
AddComponent(new zeek::analyzer::Component("ICMP", nullptr, 0, true, false, true));
|
||||
zeek::plugin::Configuration Configure() override {
|
||||
AddComponent(
|
||||
new zeek::packet_analysis::Component("ICMP", zeek::packet_analysis::ICMP::ICMPAnalyzer::Instantiate));
|
||||
AddComponent(new zeek::analyzer::Component("ICMP", nullptr, 0, true, false, true));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::ICMP";
|
||||
config.description = "Packet analyzer for ICMP";
|
||||
return config;
|
||||
}
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::ICMP";
|
||||
config.description = "Packet analyzer for ICMP";
|
||||
return config;
|
||||
}
|
||||
|
||||
} plugin;
|
||||
} plugin;
|
||||
|
||||
}
|
||||
} // namespace zeek::plugin::Zeek_ICMP
|
||||
|
|
|
@ -4,179 +4,160 @@
|
|||
|
||||
using namespace zeek::packet_analysis::IEEE802_11;
|
||||
|
||||
IEEE802_11Analyzer::IEEE802_11Analyzer() : zeek::packet_analysis::Analyzer("IEEE802_11") { }
|
||||
IEEE802_11Analyzer::IEEE802_11Analyzer() : zeek::packet_analysis::Analyzer("IEEE802_11") {}
|
||||
|
||||
bool IEEE802_11Analyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet)
|
||||
{
|
||||
u_char len_80211 = 24; // minimal length of data frames
|
||||
bool IEEE802_11Analyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) {
|
||||
u_char len_80211 = 24; // minimal length of data frames
|
||||
|
||||
if ( len_80211 >= len )
|
||||
{
|
||||
Weird("truncated_802_11_header", packet);
|
||||
return false;
|
||||
}
|
||||
if ( len_80211 >= len ) {
|
||||
Weird("truncated_802_11_header", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
u_char fc_80211 = data[0]; // Frame Control field
|
||||
bool is_amsdu = false;
|
||||
u_char fc_80211 = data[0]; // Frame Control field
|
||||
bool is_amsdu = false;
|
||||
|
||||
// Skip non-data frame types (management & control).
|
||||
if ( ! ((fc_80211 >> 2) & 0x02) )
|
||||
return false;
|
||||
// Skip non-data frame types (management & control).
|
||||
if ( ! ((fc_80211 >> 2) & 0x02) )
|
||||
return false;
|
||||
|
||||
// Skip subtypes without data.
|
||||
if ( (fc_80211 >> 4) & 0x04 )
|
||||
return false;
|
||||
// Skip subtypes without data.
|
||||
if ( (fc_80211 >> 4) & 0x04 )
|
||||
return false;
|
||||
|
||||
// 'To DS' and 'From DS' flags set indicate use of the 4th address field.
|
||||
if ( (data[1] & 0x03) == 0x03 )
|
||||
len_80211 += packet->L2_ADDR_LEN;
|
||||
// 'To DS' and 'From DS' flags set indicate use of the 4th address field.
|
||||
if ( (data[1] & 0x03) == 0x03 )
|
||||
len_80211 += packet->L2_ADDR_LEN;
|
||||
|
||||
if ( len_80211 >= len )
|
||||
{
|
||||
Weird("truncated_802_11_header", packet);
|
||||
return false;
|
||||
}
|
||||
if ( len_80211 >= len ) {
|
||||
Weird("truncated_802_11_header", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Look for the QoS indicator bit.
|
||||
if ( (fc_80211 >> 4) & 0x08 )
|
||||
{
|
||||
// Store off whether this is an A-MSDU header, which indicates that there are
|
||||
// multiple packets following the 802.11 header.
|
||||
is_amsdu = (data[len_80211] & 0x80) == 0x80;
|
||||
// Look for the QoS indicator bit.
|
||||
if ( (fc_80211 >> 4) & 0x08 ) {
|
||||
// Store off whether this is an A-MSDU header, which indicates that there are
|
||||
// multiple packets following the 802.11 header.
|
||||
is_amsdu = (data[len_80211] & 0x80) == 0x80;
|
||||
|
||||
// Check for the protected bit. This means the data is encrypted and we can't
|
||||
// do anything with it.
|
||||
if ( data[1] & 0x40 )
|
||||
return true;
|
||||
// Check for the protected bit. This means the data is encrypted and we can't
|
||||
// do anything with it.
|
||||
if ( data[1] & 0x40 )
|
||||
return true;
|
||||
|
||||
len_80211 += 2;
|
||||
}
|
||||
len_80211 += 2;
|
||||
}
|
||||
|
||||
if ( len_80211 >= len )
|
||||
{
|
||||
Weird("truncated_802_11_header", packet);
|
||||
return false;
|
||||
}
|
||||
if ( len_80211 >= len ) {
|
||||
Weird("truncated_802_11_header", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Determine link-layer addresses based on 'To DS' and 'From DS' flags
|
||||
switch ( data[1] & 0x03 )
|
||||
{
|
||||
case 0x00:
|
||||
packet->l2_src = data + 10;
|
||||
packet->l2_dst = data + 4;
|
||||
break;
|
||||
// Determine link-layer addresses based on 'To DS' and 'From DS' flags
|
||||
switch ( data[1] & 0x03 ) {
|
||||
case 0x00:
|
||||
packet->l2_src = data + 10;
|
||||
packet->l2_dst = data + 4;
|
||||
break;
|
||||
|
||||
case 0x01:
|
||||
packet->l2_src = data + 10;
|
||||
packet->l2_dst = data + 16;
|
||||
break;
|
||||
case 0x01:
|
||||
packet->l2_src = data + 10;
|
||||
packet->l2_dst = data + 16;
|
||||
break;
|
||||
|
||||
case 0x02:
|
||||
packet->l2_src = data + 16;
|
||||
packet->l2_dst = data + 4;
|
||||
break;
|
||||
case 0x02:
|
||||
packet->l2_src = data + 16;
|
||||
packet->l2_dst = data + 4;
|
||||
break;
|
||||
|
||||
case 0x03:
|
||||
packet->l2_src = data + 24;
|
||||
packet->l2_dst = data + 16;
|
||||
break;
|
||||
}
|
||||
case 0x03:
|
||||
packet->l2_src = data + 24;
|
||||
packet->l2_dst = data + 16;
|
||||
break;
|
||||
}
|
||||
|
||||
// skip the 802.11 data header
|
||||
data += len_80211;
|
||||
len -= len_80211;
|
||||
// skip the 802.11 data header
|
||||
data += len_80211;
|
||||
len -= len_80211;
|
||||
|
||||
if ( ! is_amsdu )
|
||||
{
|
||||
return HandleInnerPacket(len, data, packet);
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t amsdu_padding = 0;
|
||||
size_t encap_index = packet->encap ? packet->encap->Depth() : 0;
|
||||
if ( ! is_amsdu ) {
|
||||
return HandleInnerPacket(len, data, packet);
|
||||
}
|
||||
else {
|
||||
size_t amsdu_padding = 0;
|
||||
size_t encap_index = packet->encap ? packet->encap->Depth() : 0;
|
||||
|
||||
while ( len > 0 )
|
||||
{
|
||||
if ( len < 14 )
|
||||
{
|
||||
Weird("truncated_802_11_amsdu_header", packet);
|
||||
return false;
|
||||
}
|
||||
while ( len > 0 ) {
|
||||
if ( len < 14 ) {
|
||||
Weird("truncated_802_11_amsdu_header", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
// This is the length of everything after the A-MSDU subframe header.
|
||||
size_t amsdu_len = (data[12] << 8) + data[13];
|
||||
if ( len < amsdu_len + 14 )
|
||||
{
|
||||
Weird("truncated_802_11_amsdu_packet", packet);
|
||||
return false;
|
||||
}
|
||||
// This is the length of everything after the A-MSDU subframe header.
|
||||
size_t amsdu_len = (data[12] << 8) + data[13];
|
||||
if ( len < amsdu_len + 14 ) {
|
||||
Weird("truncated_802_11_amsdu_packet", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip the A-MSDU subframe header. This should place us at the start of an LLC header.
|
||||
data += 14;
|
||||
len -= 14;
|
||||
// Skip the A-MSDU subframe header. This should place us at the start of an LLC header.
|
||||
data += 14;
|
||||
len -= 14;
|
||||
|
||||
if ( ! HandleInnerPacket(amsdu_len, data, packet) )
|
||||
{
|
||||
Weird("invalid_802_11_amsdu_inner_packet", packet);
|
||||
return false;
|
||||
}
|
||||
if ( ! HandleInnerPacket(amsdu_len, data, packet) ) {
|
||||
Weird("invalid_802_11_amsdu_inner_packet", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
data += amsdu_len;
|
||||
len -= amsdu_len;
|
||||
data += amsdu_len;
|
||||
len -= amsdu_len;
|
||||
|
||||
// Each A-MSDU subframe is padded by up to 3 bytes to make a multiple of 4. This padding
|
||||
// isn't included in the length field value. The padding also doesn't happen with the
|
||||
// last subframe, so check to see that we can even subtract it. Unfortunately, there
|
||||
// isn't a frame counter in the header so we just have trust that it all works out.
|
||||
amsdu_padding = amsdu_len % 4;
|
||||
if ( len >= amsdu_padding )
|
||||
{
|
||||
data += amsdu_padding;
|
||||
len -= amsdu_padding;
|
||||
}
|
||||
// Each A-MSDU subframe is padded by up to 3 bytes to make a multiple of 4. This padding
|
||||
// isn't included in the length field value. The padding also doesn't happen with the
|
||||
// last subframe, so check to see that we can even subtract it. Unfortunately, there
|
||||
// isn't a frame counter in the header so we just have trust that it all works out.
|
||||
amsdu_padding = amsdu_len % 4;
|
||||
if ( len >= amsdu_padding ) {
|
||||
data += amsdu_padding;
|
||||
len -= amsdu_padding;
|
||||
}
|
||||
|
||||
// Pop encapsuations back up to the level where we started processing so that the next
|
||||
// subframe gets the same encapsulation stack.
|
||||
if ( packet->encap )
|
||||
{
|
||||
while ( packet->encap->Depth() > encap_index )
|
||||
packet->encap->Pop();
|
||||
}
|
||||
}
|
||||
// Pop encapsuations back up to the level where we started processing so that the next
|
||||
// subframe gets the same encapsulation stack.
|
||||
if ( packet->encap ) {
|
||||
while ( packet->encap->Depth() > encap_index )
|
||||
packet->encap->Pop();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool IEEE802_11Analyzer::HandleInnerPacket(size_t len, const uint8_t* data, Packet* packet) const
|
||||
{
|
||||
// Make sure there's room for an LLC header.
|
||||
if ( len < 8 )
|
||||
{
|
||||
Weird("truncated_802_11_llc_header", packet);
|
||||
return false;
|
||||
}
|
||||
bool IEEE802_11Analyzer::HandleInnerPacket(size_t len, const uint8_t* data, Packet* packet) const {
|
||||
// Make sure there's room for an LLC header.
|
||||
if ( len < 8 ) {
|
||||
Weird("truncated_802_11_llc_header", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that the DSAP and SSAP are both SNAP and that the control field indicates that this is
|
||||
// an unnumbered frame. The organization code (24bits) needs to also be zero to indicate that
|
||||
// this is encapsulated ethernet.
|
||||
if ( data[0] == 0xAA && data[1] == 0xAA && data[2] == 0x03 && data[3] == 0 && data[4] == 0 &&
|
||||
data[5] == 0 )
|
||||
{
|
||||
data += 6;
|
||||
len -= 6;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If this is a logical link control frame without the possibility of having a protocol we
|
||||
// care about, we'll just skip it for now.
|
||||
return false;
|
||||
}
|
||||
// Check that the DSAP and SSAP are both SNAP and that the control field indicates that this is
|
||||
// an unnumbered frame. The organization code (24bits) needs to also be zero to indicate that
|
||||
// this is encapsulated ethernet.
|
||||
if ( data[0] == 0xAA && data[1] == 0xAA && data[2] == 0x03 && data[3] == 0 && data[4] == 0 && data[5] == 0 ) {
|
||||
data += 6;
|
||||
len -= 6;
|
||||
}
|
||||
else {
|
||||
// If this is a logical link control frame without the possibility of having a protocol we
|
||||
// care about, we'll just skip it for now.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the protocol and skip the rest of the LLC header.
|
||||
uint32_t protocol = (data[0] << 8) + data[1];
|
||||
data += 2;
|
||||
len -= 2;
|
||||
// Get the protocol and skip the rest of the LLC header.
|
||||
uint32_t protocol = (data[0] << 8) + data[1];
|
||||
data += 2;
|
||||
len -= 2;
|
||||
|
||||
return ForwardPacket(len, data, packet, protocol);
|
||||
}
|
||||
return ForwardPacket(len, data, packet, protocol);
|
||||
}
|
||||
|
|
|
@ -5,24 +5,19 @@
|
|||
#include "zeek/packet_analysis/Analyzer.h"
|
||||
#include "zeek/packet_analysis/Component.h"
|
||||
|
||||
namespace zeek::packet_analysis::IEEE802_11
|
||||
{
|
||||
namespace zeek::packet_analysis::IEEE802_11 {
|
||||
|
||||
class IEEE802_11Analyzer : public Analyzer
|
||||
{
|
||||
class IEEE802_11Analyzer : public Analyzer {
|
||||
public:
|
||||
IEEE802_11Analyzer();
|
||||
~IEEE802_11Analyzer() override = default;
|
||||
IEEE802_11Analyzer();
|
||||
~IEEE802_11Analyzer() override = default;
|
||||
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate()
|
||||
{
|
||||
return std::make_shared<IEEE802_11Analyzer>();
|
||||
}
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate() { return std::make_shared<IEEE802_11Analyzer>(); }
|
||||
|
||||
private:
|
||||
bool HandleInnerPacket(size_t len, const uint8_t* data, Packet* packet) const;
|
||||
};
|
||||
bool HandleInnerPacket(size_t len, const uint8_t* data, Packet* packet) const;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace zeek::packet_analysis::IEEE802_11
|
||||
|
|
|
@ -5,23 +5,21 @@
|
|||
#include "zeek/packet_analysis/Component.h"
|
||||
#include "zeek/packet_analysis/protocol/ieee802_11/IEEE802_11.h"
|
||||
|
||||
namespace zeek::plugin::Zeek_IEEE802_11
|
||||
{
|
||||
namespace zeek::plugin::Zeek_IEEE802_11 {
|
||||
|
||||
class Plugin final : public zeek::plugin::Plugin
|
||||
{
|
||||
class Plugin final : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure() override
|
||||
{
|
||||
AddComponent(new zeek::packet_analysis::Component(
|
||||
"IEEE802_11", zeek::packet_analysis::IEEE802_11::IEEE802_11Analyzer::Instantiate));
|
||||
zeek::plugin::Configuration Configure() override {
|
||||
AddComponent(
|
||||
new zeek::packet_analysis::Component("IEEE802_11",
|
||||
zeek::packet_analysis::IEEE802_11::IEEE802_11Analyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::IEEE802_11";
|
||||
config.description = "IEEE 802.11 packet analyzer";
|
||||
return config;
|
||||
}
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::IEEE802_11";
|
||||
config.description = "IEEE 802.11 packet analyzer";
|
||||
return config;
|
||||
}
|
||||
|
||||
} plugin;
|
||||
} plugin;
|
||||
|
||||
}
|
||||
} // namespace zeek::plugin::Zeek_IEEE802_11
|
||||
|
|
|
@ -6,27 +6,21 @@
|
|||
|
||||
using namespace zeek::packet_analysis::IEEE802_11_Radio;
|
||||
|
||||
IEEE802_11_RadioAnalyzer::IEEE802_11_RadioAnalyzer()
|
||||
: zeek::packet_analysis::Analyzer("IEEE802_11_Radio")
|
||||
{
|
||||
}
|
||||
IEEE802_11_RadioAnalyzer::IEEE802_11_RadioAnalyzer() : zeek::packet_analysis::Analyzer("IEEE802_11_Radio") {}
|
||||
|
||||
bool IEEE802_11_RadioAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet)
|
||||
{
|
||||
if ( 3 >= len )
|
||||
{
|
||||
Weird("truncated_radiotap_header", packet);
|
||||
return false;
|
||||
}
|
||||
bool IEEE802_11_RadioAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) {
|
||||
if ( 3 >= len ) {
|
||||
Weird("truncated_radiotap_header", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip over the RadioTap header
|
||||
size_t rtheader_len = (data[3] << 8) + data[2];
|
||||
// Skip over the RadioTap header
|
||||
size_t rtheader_len = (data[3] << 8) + data[2];
|
||||
|
||||
if ( rtheader_len >= len )
|
||||
{
|
||||
Weird("truncated_radiotap_header", packet);
|
||||
return false;
|
||||
}
|
||||
if ( rtheader_len >= len ) {
|
||||
Weird("truncated_radiotap_header", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
return ForwardPacket(len - rtheader_len, data + rtheader_len, packet, DLT_IEEE802_11);
|
||||
}
|
||||
return ForwardPacket(len - rtheader_len, data + rtheader_len, packet, DLT_IEEE802_11);
|
||||
}
|
||||
|
|
|
@ -5,21 +5,16 @@
|
|||
#include "zeek/packet_analysis/Analyzer.h"
|
||||
#include "zeek/packet_analysis/Component.h"
|
||||
|
||||
namespace zeek::packet_analysis::IEEE802_11_Radio
|
||||
{
|
||||
namespace zeek::packet_analysis::IEEE802_11_Radio {
|
||||
|
||||
class IEEE802_11_RadioAnalyzer : public Analyzer
|
||||
{
|
||||
class IEEE802_11_RadioAnalyzer : public Analyzer {
|
||||
public:
|
||||
IEEE802_11_RadioAnalyzer();
|
||||
~IEEE802_11_RadioAnalyzer() override = default;
|
||||
IEEE802_11_RadioAnalyzer();
|
||||
~IEEE802_11_RadioAnalyzer() override = default;
|
||||
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate()
|
||||
{
|
||||
return std::make_shared<IEEE802_11_RadioAnalyzer>();
|
||||
}
|
||||
};
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate() { return std::make_shared<IEEE802_11_RadioAnalyzer>(); }
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace zeek::packet_analysis::IEEE802_11_Radio
|
||||
|
|
|
@ -5,23 +5,19 @@
|
|||
#include "zeek/packet_analysis/Component.h"
|
||||
#include "zeek/packet_analysis/protocol/ieee802_11_radio/IEEE802_11_Radio.h"
|
||||
|
||||
namespace zeek::plugin::Zeek_IEEE802_11_Radio
|
||||
{
|
||||
namespace zeek::plugin::Zeek_IEEE802_11_Radio {
|
||||
|
||||
class Plugin final : public zeek::plugin::Plugin
|
||||
{
|
||||
class Plugin final : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure() override
|
||||
{
|
||||
AddComponent(new zeek::packet_analysis::Component(
|
||||
"IEEE802_11_Radio",
|
||||
zeek::packet_analysis::IEEE802_11_Radio::IEEE802_11_RadioAnalyzer::Instantiate));
|
||||
zeek::plugin::Configuration Configure() override {
|
||||
AddComponent(new zeek::packet_analysis::Component(
|
||||
"IEEE802_11_Radio", zeek::packet_analysis::IEEE802_11_Radio::IEEE802_11_RadioAnalyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::IEEE802_11_Radio";
|
||||
config.description = "IEEE 802.11 Radiotap packet analyzer";
|
||||
return config;
|
||||
}
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::IEEE802_11_Radio";
|
||||
config.description = "IEEE 802.11 Radiotap packet analyzer";
|
||||
return config;
|
||||
}
|
||||
|
||||
} plugin;
|
||||
}
|
||||
} plugin;
|
||||
} // namespace zeek::plugin::Zeek_IEEE802_11_Radio
|
||||
|
|
|
@ -18,326 +18,288 @@
|
|||
|
||||
using namespace zeek::packet_analysis::IP;
|
||||
|
||||
IPAnalyzer::IPAnalyzer() : zeek::packet_analysis::Analyzer("IP")
|
||||
{
|
||||
discarder = new detail::Discarder();
|
||||
if ( ! discarder->IsActive() )
|
||||
{
|
||||
delete discarder;
|
||||
discarder = nullptr;
|
||||
}
|
||||
}
|
||||
IPAnalyzer::IPAnalyzer() : zeek::packet_analysis::Analyzer("IP") {
|
||||
discarder = new detail::Discarder();
|
||||
if ( ! discarder->IsActive() ) {
|
||||
delete discarder;
|
||||
discarder = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
IPAnalyzer::~IPAnalyzer()
|
||||
{
|
||||
delete discarder;
|
||||
}
|
||||
IPAnalyzer::~IPAnalyzer() { delete discarder; }
|
||||
|
||||
bool IPAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet)
|
||||
{
|
||||
// Check to make sure we have enough data left for an IP header to be here. Note we only
|
||||
// check ipv4 here. We'll check ipv6 later once we determine we have an ipv6 header.
|
||||
if ( len < sizeof(struct ip) )
|
||||
{
|
||||
Weird("truncated_IP", packet);
|
||||
return false;
|
||||
}
|
||||
bool IPAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) {
|
||||
// Check to make sure we have enough data left for an IP header to be here. Note we only
|
||||
// check ipv4 here. We'll check ipv6 later once we determine we have an ipv6 header.
|
||||
if ( len < sizeof(struct ip) ) {
|
||||
Weird("truncated_IP", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t hdr_size = static_cast<int32_t>(data - packet->data);
|
||||
int32_t hdr_size = static_cast<int32_t>(data - packet->data);
|
||||
|
||||
// Cast the current data pointer to an IP header pointer so we can use it to get some
|
||||
// data about the header.
|
||||
auto ip = (const struct ip*)data;
|
||||
uint32_t protocol = ip->ip_v;
|
||||
std::shared_ptr<IP_Hdr> ip_hdr;
|
||||
// Cast the current data pointer to an IP header pointer so we can use it to get some
|
||||
// data about the header.
|
||||
auto ip = (const struct ip*)data;
|
||||
uint32_t protocol = ip->ip_v;
|
||||
std::shared_ptr<IP_Hdr> ip_hdr;
|
||||
|
||||
if ( protocol == 4 )
|
||||
{
|
||||
ip_hdr = std::make_shared<IP_Hdr>(ip, false);
|
||||
packet->l3_proto = L3_IPV4;
|
||||
}
|
||||
else if ( protocol == 6 )
|
||||
{
|
||||
if ( len < sizeof(struct ip6_hdr) )
|
||||
{
|
||||
Weird("truncated_IP", packet);
|
||||
return false;
|
||||
}
|
||||
if ( protocol == 4 ) {
|
||||
ip_hdr = std::make_shared<IP_Hdr>(ip, false);
|
||||
packet->l3_proto = L3_IPV4;
|
||||
}
|
||||
else if ( protocol == 6 ) {
|
||||
if ( len < sizeof(struct ip6_hdr) ) {
|
||||
Weird("truncated_IP", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
ip_hdr = std::make_shared<IP_Hdr>((const struct ip6_hdr*)data, false,
|
||||
static_cast<int>(len));
|
||||
packet->l3_proto = L3_IPV6;
|
||||
}
|
||||
else
|
||||
{
|
||||
Weird("unknown_ip_version", packet);
|
||||
return false;
|
||||
}
|
||||
ip_hdr = std::make_shared<IP_Hdr>((const struct ip6_hdr*)data, false, static_cast<int>(len));
|
||||
packet->l3_proto = L3_IPV6;
|
||||
}
|
||||
else {
|
||||
Weird("unknown_ip_version", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
// TotalLen() returns the full length of the IP portion of the packet, including
|
||||
// the IP header and payload.
|
||||
uint32_t total_len = ip_hdr->TotalLen();
|
||||
if ( total_len == 0 )
|
||||
{
|
||||
// TCP segmentation offloading can zero out the ip_len field.
|
||||
Weird("ip_hdr_len_zero", packet);
|
||||
// TotalLen() returns the full length of the IP portion of the packet, including
|
||||
// the IP header and payload.
|
||||
uint32_t total_len = ip_hdr->TotalLen();
|
||||
if ( total_len == 0 ) {
|
||||
// TCP segmentation offloading can zero out the ip_len field.
|
||||
Weird("ip_hdr_len_zero", packet);
|
||||
|
||||
if ( detail::ignore_checksums )
|
||||
// Cope with the zero'd out ip_len field by using the caplen.
|
||||
total_len = packet->cap_len - hdr_size;
|
||||
else
|
||||
// If this is caused by segmentation offloading, the checksum will
|
||||
// also be incorrect. If checksum validation is enabled - just bail here.
|
||||
return false;
|
||||
}
|
||||
if ( detail::ignore_checksums )
|
||||
// Cope with the zero'd out ip_len field by using the caplen.
|
||||
total_len = packet->cap_len - hdr_size;
|
||||
else
|
||||
// If this is caused by segmentation offloading, the checksum will
|
||||
// also be incorrect. If checksum validation is enabled - just bail here.
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( packet->len < total_len + hdr_size )
|
||||
{
|
||||
Weird("truncated_IP_len", packet);
|
||||
return false;
|
||||
}
|
||||
if ( packet->len < total_len + hdr_size ) {
|
||||
Weird("truncated_IP_len", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
// For both of these it is safe to pass ip_hdr because the presence
|
||||
// is guaranteed for the functions that pass data to us.
|
||||
uint16_t ip_hdr_len = ip_hdr->HdrLen();
|
||||
if ( ip_hdr_len > total_len )
|
||||
{
|
||||
Weird("invalid_IP_header_size", packet);
|
||||
return false;
|
||||
}
|
||||
// For both of these it is safe to pass ip_hdr because the presence
|
||||
// is guaranteed for the functions that pass data to us.
|
||||
uint16_t ip_hdr_len = ip_hdr->HdrLen();
|
||||
if ( ip_hdr_len > total_len ) {
|
||||
Weird("invalid_IP_header_size", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ip_hdr_len > len )
|
||||
{
|
||||
Weird("internally_truncated_header", packet);
|
||||
return false;
|
||||
}
|
||||
if ( ip_hdr_len > len ) {
|
||||
Weird("internally_truncated_header", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
const struct ip* ip4 = ip_hdr->IP4_Hdr();
|
||||
const struct ip* ip4 = ip_hdr->IP4_Hdr();
|
||||
|
||||
if ( ip4 )
|
||||
{
|
||||
if ( ip_hdr_len < sizeof(struct ip) )
|
||||
{
|
||||
Weird("IPv4_min_header_size", packet);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ip_hdr_len < sizeof(struct ip6_hdr) )
|
||||
{
|
||||
Weird("IPv6_min_header_size", packet);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ( ip4 ) {
|
||||
if ( ip_hdr_len < sizeof(struct ip) ) {
|
||||
Weird("IPv4_min_header_size", packet);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( ip_hdr_len < sizeof(struct ip6_hdr) ) {
|
||||
Weird("IPv6_min_header_size", packet);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If we got here, the IP_Hdr is most likely valid and safe to use.
|
||||
packet->ip_hdr = ip_hdr;
|
||||
// If we got here, the IP_Hdr is most likely valid and safe to use.
|
||||
packet->ip_hdr = ip_hdr;
|
||||
|
||||
// If there's an encapsulation stack in this packet, meaning this packet is part of a chain
|
||||
// of tunnels, make sure to store the IP header in the last flow in the stack so it can be
|
||||
// used by previous analyzers as we return up the chain.
|
||||
if ( packet->encap )
|
||||
{
|
||||
if ( auto* ec = packet->encap->Last() )
|
||||
ec->ip_hdr = packet->ip_hdr;
|
||||
}
|
||||
// If there's an encapsulation stack in this packet, meaning this packet is part of a chain
|
||||
// of tunnels, make sure to store the IP header in the last flow in the stack so it can be
|
||||
// used by previous analyzers as we return up the chain.
|
||||
if ( packet->encap ) {
|
||||
if ( auto* ec = packet->encap->Last() )
|
||||
ec->ip_hdr = packet->ip_hdr;
|
||||
}
|
||||
|
||||
// Ignore if packet matches packet filter.
|
||||
detail::PacketFilter* packet_filter = packet_mgr->GetPacketFilter(false);
|
||||
if ( packet_filter && packet_filter->Match(packet->ip_hdr, total_len, len) )
|
||||
return false;
|
||||
// Ignore if packet matches packet filter.
|
||||
detail::PacketFilter* packet_filter = packet_mgr->GetPacketFilter(false);
|
||||
if ( packet_filter && packet_filter->Match(packet->ip_hdr, total_len, len) )
|
||||
return false;
|
||||
|
||||
if ( ! packet->l3_checksummed && ! detail::ignore_checksums && ip4 &&
|
||||
! IPBasedAnalyzer::GetIgnoreChecksumsNets()->Contains(packet->ip_hdr->IPHeaderSrcAddr()) &&
|
||||
detail::in_cksum(reinterpret_cast<const uint8_t*>(ip4), ip_hdr_len) != 0xffff )
|
||||
{
|
||||
Weird("bad_IP_checksum", packet);
|
||||
return false;
|
||||
}
|
||||
if ( ! packet->l3_checksummed && ! detail::ignore_checksums && ip4 &&
|
||||
! IPBasedAnalyzer::GetIgnoreChecksumsNets()->Contains(packet->ip_hdr->IPHeaderSrcAddr()) &&
|
||||
detail::in_cksum(reinterpret_cast<const uint8_t*>(ip4), ip_hdr_len) != 0xffff ) {
|
||||
Weird("bad_IP_checksum", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( discarder && discarder->NextPacket(packet->ip_hdr, total_len, len) )
|
||||
return false;
|
||||
if ( discarder && discarder->NextPacket(packet->ip_hdr, total_len, len) )
|
||||
return false;
|
||||
|
||||
detail::FragReassembler* f = nullptr;
|
||||
detail::FragReassembler* f = nullptr;
|
||||
|
||||
// Store this off so that it can be reset back to the original value before returning from
|
||||
// this method.
|
||||
size_t orig_cap_len = packet->cap_len;
|
||||
// Store this off so that it can be reset back to the original value before returning from
|
||||
// this method.
|
||||
size_t orig_cap_len = packet->cap_len;
|
||||
|
||||
if ( packet->ip_hdr->IsFragment() )
|
||||
{
|
||||
packet->dump_packet = true; // always record fragments
|
||||
if ( packet->ip_hdr->IsFragment() ) {
|
||||
packet->dump_packet = true; // always record fragments
|
||||
|
||||
if ( len < total_len )
|
||||
{
|
||||
Weird("incompletely_captured_fragment", packet);
|
||||
if ( len < total_len ) {
|
||||
Weird("incompletely_captured_fragment", packet);
|
||||
|
||||
// Don't try to reassemble, that's doomed.
|
||||
// Discard all except the first fragment (which
|
||||
// is useful in analyzing header-only traces)
|
||||
if ( packet->ip_hdr->FragOffset() != 0 )
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
f = detail::fragment_mgr->NextFragment(run_state::processing_start_time, packet->ip_hdr,
|
||||
packet->data + hdr_size);
|
||||
std::shared_ptr<IP_Hdr> ih = f->ReassembledPkt();
|
||||
// Don't try to reassemble, that's doomed.
|
||||
// Discard all except the first fragment (which
|
||||
// is useful in analyzing header-only traces)
|
||||
if ( packet->ip_hdr->FragOffset() != 0 )
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
f = detail::fragment_mgr->NextFragment(run_state::processing_start_time, packet->ip_hdr,
|
||||
packet->data + hdr_size);
|
||||
std::shared_ptr<IP_Hdr> ih = f->ReassembledPkt();
|
||||
|
||||
if ( ! ih )
|
||||
// It didn't reassemble into anything yet.
|
||||
return true;
|
||||
if ( ! ih )
|
||||
// It didn't reassemble into anything yet.
|
||||
return true;
|
||||
|
||||
ip4 = ih->IP4_Hdr();
|
||||
ip4 = ih->IP4_Hdr();
|
||||
|
||||
// Switch the stored ip header over to the one from the
|
||||
// fragmented packet.
|
||||
packet->ip_hdr = std::move(ih);
|
||||
// Switch the stored ip header over to the one from the
|
||||
// fragmented packet.
|
||||
packet->ip_hdr = std::move(ih);
|
||||
|
||||
len = total_len = packet->ip_hdr->TotalLen();
|
||||
ip_hdr_len = packet->ip_hdr->HdrLen();
|
||||
len = total_len = packet->ip_hdr->TotalLen();
|
||||
ip_hdr_len = packet->ip_hdr->HdrLen();
|
||||
|
||||
if ( ip_hdr_len > total_len )
|
||||
{
|
||||
Weird("invalid_IP_header_size", packet);
|
||||
return false;
|
||||
}
|
||||
if ( ip_hdr_len > total_len ) {
|
||||
Weird("invalid_IP_header_size", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
packet->cap_len = total_len + hdr_size;
|
||||
// Assumes reassembled packet has wire length == capture length.
|
||||
packet->len = packet->cap_len;
|
||||
}
|
||||
}
|
||||
packet->cap_len = total_len + hdr_size;
|
||||
// Assumes reassembled packet has wire length == capture length.
|
||||
packet->len = packet->cap_len;
|
||||
}
|
||||
}
|
||||
|
||||
detail::FragReassemblerTracker frt(f);
|
||||
detail::FragReassemblerTracker frt(f);
|
||||
|
||||
// We stop building the chain when seeing IPPROTO_ESP so if it's
|
||||
// there, it's always the last.
|
||||
if ( packet->ip_hdr->LastHeader() == IPPROTO_ESP )
|
||||
{
|
||||
packet->dump_packet = true;
|
||||
if ( esp_packet )
|
||||
event_mgr.Enqueue(esp_packet, packet->ip_hdr->ToPktHdrVal());
|
||||
// We stop building the chain when seeing IPPROTO_ESP so if it's
|
||||
// there, it's always the last.
|
||||
if ( packet->ip_hdr->LastHeader() == IPPROTO_ESP ) {
|
||||
packet->dump_packet = true;
|
||||
if ( esp_packet )
|
||||
event_mgr.Enqueue(esp_packet, packet->ip_hdr->ToPktHdrVal());
|
||||
|
||||
// Can't do more since upper-layer payloads are going to be encrypted.
|
||||
packet->cap_len = orig_cap_len;
|
||||
return true;
|
||||
}
|
||||
// Can't do more since upper-layer payloads are going to be encrypted.
|
||||
packet->cap_len = orig_cap_len;
|
||||
return true;
|
||||
}
|
||||
|
||||
// We stop building the chain when seeing IPPROTO_MOBILITY so it's always
|
||||
// last if present.
|
||||
if ( packet->ip_hdr->LastHeader() == IPPROTO_MOBILITY )
|
||||
{
|
||||
packet->dump_packet = true;
|
||||
// We stop building the chain when seeing IPPROTO_MOBILITY so it's always
|
||||
// last if present.
|
||||
if ( packet->ip_hdr->LastHeader() == IPPROTO_MOBILITY ) {
|
||||
packet->dump_packet = true;
|
||||
|
||||
if ( ! detail::ignore_checksums &&
|
||||
mobility_header_checksum(packet->ip_hdr.get()) != 0xffff )
|
||||
{
|
||||
Weird("bad_MH_checksum", packet);
|
||||
packet->cap_len = orig_cap_len;
|
||||
return false;
|
||||
}
|
||||
if ( ! detail::ignore_checksums && mobility_header_checksum(packet->ip_hdr.get()) != 0xffff ) {
|
||||
Weird("bad_MH_checksum", packet);
|
||||
packet->cap_len = orig_cap_len;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( mobile_ipv6_message )
|
||||
event_mgr.Enqueue(mobile_ipv6_message, packet->ip_hdr->ToPktHdrVal());
|
||||
if ( mobile_ipv6_message )
|
||||
event_mgr.Enqueue(mobile_ipv6_message, packet->ip_hdr->ToPktHdrVal());
|
||||
|
||||
if ( packet->ip_hdr->NextProto() != IPPROTO_NONE )
|
||||
Weird("mobility_piggyback", packet);
|
||||
if ( packet->ip_hdr->NextProto() != IPPROTO_NONE )
|
||||
Weird("mobility_piggyback", packet);
|
||||
|
||||
packet->cap_len = orig_cap_len;
|
||||
return true;
|
||||
}
|
||||
packet->cap_len = orig_cap_len;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Set the data pointer to match the payload from the IP header. This makes sure that it's also
|
||||
// pointing at the reassembled data for a fragmented packet.
|
||||
data = packet->ip_hdr->Payload();
|
||||
len -= ip_hdr_len;
|
||||
// Set the data pointer to match the payload from the IP header. This makes sure that it's also
|
||||
// pointing at the reassembled data for a fragmented packet.
|
||||
data = packet->ip_hdr->Payload();
|
||||
len -= ip_hdr_len;
|
||||
|
||||
// Session analysis assumes that the header size stored in the packet does not include the IP
|
||||
// header size. There are two reasons for this: 1) Packet::ToRawPktHdrVal() wants to look at the
|
||||
// IP header for reporting, and 2) The VXLAN analyzer uses the header position to create the
|
||||
// next packet in the tunnel chain. Once the TCP/UDP work is done and the VXLAN analyzer can
|
||||
// move into packet analysis, this can change, but for now we leave it as it is.
|
||||
// Session analysis assumes that the header size stored in the packet does not include the IP
|
||||
// header size. There are two reasons for this: 1) Packet::ToRawPktHdrVal() wants to look at the
|
||||
// IP header for reporting, and 2) The VXLAN analyzer uses the header position to create the
|
||||
// next packet in the tunnel chain. Once the TCP/UDP work is done and the VXLAN analyzer can
|
||||
// move into packet analysis, this can change, but for now we leave it as it is.
|
||||
|
||||
bool return_val = true;
|
||||
int proto = packet->ip_hdr->NextProto();
|
||||
bool return_val = true;
|
||||
int proto = packet->ip_hdr->NextProto();
|
||||
|
||||
packet->proto = proto;
|
||||
packet->proto = proto;
|
||||
|
||||
// Double check the lengths one more time before forwarding this on.
|
||||
if ( total_len < packet->ip_hdr->HdrLen() )
|
||||
{
|
||||
Weird("bogus_IP_header_lengths", packet);
|
||||
packet->cap_len = orig_cap_len;
|
||||
return false;
|
||||
}
|
||||
// Double check the lengths one more time before forwarding this on.
|
||||
if ( total_len < packet->ip_hdr->HdrLen() ) {
|
||||
Weird("bogus_IP_header_lengths", packet);
|
||||
packet->cap_len = orig_cap_len;
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the next protocol is a tunneled type, set the tunnel_type field in the packet to IP
|
||||
// so that it gets handled correctly.
|
||||
if ( proto == IPPROTO_IPV4 || proto == IPPROTO_IPV6 )
|
||||
packet->tunnel_type = BifEnum::Tunnel::IP;
|
||||
// If the next protocol is a tunneled type, set the tunnel_type field in the packet to IP
|
||||
// so that it gets handled correctly.
|
||||
if ( proto == IPPROTO_IPV4 || proto == IPPROTO_IPV6 )
|
||||
packet->tunnel_type = BifEnum::Tunnel::IP;
|
||||
|
||||
switch ( proto )
|
||||
{
|
||||
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
|
||||
// not sure the reason for the No Next header in the packet.
|
||||
if ( ! (packet->encap && packet->encap->LastType() == BifEnum::Tunnel::TEREDO) )
|
||||
{
|
||||
Weird("ipv6_no_next", packet);
|
||||
return_val = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
packet->proto = proto;
|
||||
switch ( proto ) {
|
||||
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
|
||||
// not sure the reason for the No Next header in the packet.
|
||||
if ( ! (packet->encap && packet->encap->LastType() == BifEnum::Tunnel::TEREDO) ) {
|
||||
Weird("ipv6_no_next", packet);
|
||||
return_val = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
packet->proto = proto;
|
||||
|
||||
// For everything else, pass it on to another analyzer. If there's no one to handle
|
||||
// that, it'll report a Weird.
|
||||
return_val = ForwardPacket(len, data, packet, proto);
|
||||
break;
|
||||
}
|
||||
// For everything else, pass it on to another analyzer. If there's no one to handle
|
||||
// that, it'll report a Weird.
|
||||
return_val = ForwardPacket(len, data, packet, proto);
|
||||
break;
|
||||
}
|
||||
|
||||
if ( f )
|
||||
f->DeleteTimer();
|
||||
if ( f )
|
||||
f->DeleteTimer();
|
||||
|
||||
packet->cap_len = orig_cap_len;
|
||||
return return_val;
|
||||
}
|
||||
packet->cap_len = orig_cap_len;
|
||||
return return_val;
|
||||
}
|
||||
|
||||
ParseResult zeek::packet_analysis::IP::ParsePacket(int caplen, const u_char* const pkt, int proto,
|
||||
std::shared_ptr<zeek::IP_Hdr>& inner)
|
||||
{
|
||||
if ( proto == IPPROTO_IPV6 )
|
||||
{
|
||||
if ( caplen < (int)sizeof(struct ip6_hdr) )
|
||||
return ParseResult::CaplenTooSmall;
|
||||
std::shared_ptr<zeek::IP_Hdr>& inner) {
|
||||
if ( proto == IPPROTO_IPV6 ) {
|
||||
if ( caplen < (int)sizeof(struct ip6_hdr) )
|
||||
return ParseResult::CaplenTooSmall;
|
||||
|
||||
const struct ip6_hdr* ip6 = (const struct ip6_hdr*)pkt;
|
||||
inner = std::make_shared<zeek::IP_Hdr>(ip6, false, caplen);
|
||||
if ( (ip6->ip6_ctlun.ip6_un2_vfc & 0xF0) != 0x60 )
|
||||
return ParseResult::BadProtocol;
|
||||
}
|
||||
const struct ip6_hdr* ip6 = (const struct ip6_hdr*)pkt;
|
||||
inner = std::make_shared<zeek::IP_Hdr>(ip6, false, caplen);
|
||||
if ( (ip6->ip6_ctlun.ip6_un2_vfc & 0xF0) != 0x60 )
|
||||
return ParseResult::BadProtocol;
|
||||
}
|
||||
|
||||
else if ( proto == IPPROTO_IPV4 )
|
||||
{
|
||||
if ( caplen < (int)sizeof(struct ip) )
|
||||
return ParseResult::BadProtocol;
|
||||
else if ( proto == IPPROTO_IPV4 ) {
|
||||
if ( caplen < (int)sizeof(struct ip) )
|
||||
return ParseResult::BadProtocol;
|
||||
|
||||
const struct ip* ip4 = (const struct ip*)pkt;
|
||||
inner = std::make_shared<zeek::IP_Hdr>(ip4, false);
|
||||
if ( ip4->ip_v != 4 )
|
||||
return ParseResult::BadProtocol;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ParseResult::BadProtocol;
|
||||
}
|
||||
const struct ip* ip4 = (const struct ip*)pkt;
|
||||
inner = std::make_shared<zeek::IP_Hdr>(ip4, false);
|
||||
if ( ip4->ip_v != 4 )
|
||||
return ParseResult::BadProtocol;
|
||||
}
|
||||
else {
|
||||
return ParseResult::BadProtocol;
|
||||
}
|
||||
|
||||
if ( (uint32_t)caplen != inner->TotalLen() )
|
||||
return (uint32_t)caplen < inner->TotalLen() ? ParseResult::CaplenTooSmall
|
||||
: ParseResult::CaplenTooLarge;
|
||||
if ( (uint32_t)caplen != inner->TotalLen() )
|
||||
return (uint32_t)caplen < inner->TotalLen() ? ParseResult::CaplenTooSmall : ParseResult::CaplenTooLarge;
|
||||
|
||||
return ParseResult::Ok;
|
||||
}
|
||||
return ParseResult::Ok;
|
||||
}
|
||||
|
|
|
@ -6,42 +6,30 @@
|
|||
#include "zeek/packet_analysis/Analyzer.h"
|
||||
#include "zeek/packet_analysis/Component.h"
|
||||
|
||||
namespace zeek::detail
|
||||
{
|
||||
namespace zeek::detail {
|
||||
class Discarder;
|
||||
}
|
||||
}
|
||||
|
||||
namespace zeek::packet_analysis::IP
|
||||
{
|
||||
namespace zeek::packet_analysis::IP {
|
||||
|
||||
class IPAnalyzer : public Analyzer
|
||||
{
|
||||
class IPAnalyzer : public Analyzer {
|
||||
public:
|
||||
IPAnalyzer();
|
||||
~IPAnalyzer() override;
|
||||
IPAnalyzer();
|
||||
~IPAnalyzer() override;
|
||||
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate()
|
||||
{
|
||||
return std::make_shared<IPAnalyzer>();
|
||||
}
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate() { return std::make_shared<IPAnalyzer>(); }
|
||||
|
||||
private:
|
||||
// Returns a reassembled packet, or nil if there are still
|
||||
// some missing fragments.
|
||||
zeek::detail::FragReassembler* NextFragment(double t, const IP_Hdr* ip, const u_char* pkt);
|
||||
// Returns a reassembled packet, or nil if there are still
|
||||
// some missing fragments.
|
||||
zeek::detail::FragReassembler* NextFragment(double t, const IP_Hdr* ip, const u_char* pkt);
|
||||
|
||||
zeek::detail::Discarder* discarder = nullptr;
|
||||
};
|
||||
zeek::detail::Discarder* discarder = nullptr;
|
||||
};
|
||||
|
||||
enum class ParseResult
|
||||
{
|
||||
Ok = 0,
|
||||
CaplenTooSmall = -1,
|
||||
BadProtocol = -2,
|
||||
CaplenTooLarge = 1
|
||||
};
|
||||
enum class ParseResult { Ok = 0, CaplenTooSmall = -1, BadProtocol = -2, CaplenTooLarge = 1 };
|
||||
|
||||
/**
|
||||
* Returns a wrapper IP_Hdr object if \a pkt appears to be a valid IPv4
|
||||
|
@ -67,7 +55,6 @@ enum class ParseResult
|
|||
* or IPPROTO_IPV6 or if \a proto does not match the protocol
|
||||
* in the header's version field.
|
||||
*/
|
||||
ParseResult ParsePacket(int caplen, const u_char* const pkt, int proto,
|
||||
std::shared_ptr<IP_Hdr>& inner);
|
||||
ParseResult ParsePacket(int caplen, const u_char* const pkt, int proto, std::shared_ptr<IP_Hdr>& inner);
|
||||
|
||||
}
|
||||
} // namespace zeek::packet_analysis::IP
|
||||
|
|
|
@ -13,297 +13,260 @@
|
|||
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(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()
|
||||
{
|
||||
for ( const auto& mapping : analyzers_by_port )
|
||||
delete mapping.second;
|
||||
}
|
||||
IPBasedAnalyzer::~IPBasedAnalyzer() {
|
||||
for ( const auto& mapping : analyzers_by_port )
|
||||
delete mapping.second;
|
||||
}
|
||||
|
||||
bool IPBasedAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* pkt)
|
||||
{
|
||||
ConnTuple tuple;
|
||||
if ( ! BuildConnTuple(len, data, pkt, tuple) )
|
||||
return false;
|
||||
bool IPBasedAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* pkt) {
|
||||
ConnTuple tuple;
|
||||
if ( ! BuildConnTuple(len, data, pkt, tuple) )
|
||||
return false;
|
||||
|
||||
const std::shared_ptr<IP_Hdr>& ip_hdr = pkt->ip_hdr;
|
||||
detail::ConnKey key(tuple);
|
||||
const std::shared_ptr<IP_Hdr>& ip_hdr = pkt->ip_hdr;
|
||||
detail::ConnKey key(tuple);
|
||||
|
||||
Connection* conn = session_mgr->FindConnection(key);
|
||||
Connection* conn = session_mgr->FindConnection(key);
|
||||
|
||||
if ( ! conn )
|
||||
{
|
||||
conn = NewConn(&tuple, 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);
|
||||
if ( ! conn ) {
|
||||
conn = NewConn(&tuple, 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(&tuple, key, pkt);
|
||||
if ( conn )
|
||||
session_mgr->Insert(conn, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
conn->CheckEncapsulation(pkt->encap);
|
||||
}
|
||||
}
|
||||
session_mgr->Remove(conn);
|
||||
conn = NewConn(&tuple, key, pkt);
|
||||
if ( conn )
|
||||
session_mgr->Insert(conn, false);
|
||||
}
|
||||
else {
|
||||
conn->CheckEncapsulation(pkt->encap);
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! conn )
|
||||
return false;
|
||||
if ( ! conn )
|
||||
return false;
|
||||
|
||||
// If we successfully made a connection for this packet that means it'll eventually
|
||||
// get logged, which means we can mark this packet as having been processed.
|
||||
pkt->processed = true;
|
||||
// If we successfully made a connection for this packet that means it'll eventually
|
||||
// get logged, which means we can mark this packet as having been processed.
|
||||
pkt->processed = true;
|
||||
|
||||
bool is_orig = (tuple.src_addr == conn->OrigAddr()) && (tuple.src_port == conn->OrigPort());
|
||||
pkt->is_orig = is_orig;
|
||||
bool is_orig = (tuple.src_addr == conn->OrigAddr()) && (tuple.src_port == conn->OrigPort());
|
||||
pkt->is_orig = is_orig;
|
||||
|
||||
conn->CheckFlowLabel(is_orig, ip_hdr->FlowLabel());
|
||||
conn->CheckFlowLabel(is_orig, ip_hdr->FlowLabel());
|
||||
|
||||
zeek::ValPtr pkt_hdr_val;
|
||||
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 ( 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_packet )
|
||||
conn->EnqueueEvent(new_packet, nullptr, conn->GetVal(),
|
||||
pkt_hdr_val ? std::move(pkt_hdr_val) : ip_hdr->ToPktHdrVal());
|
||||
|
||||
conn->SetRecordPackets(true);
|
||||
conn->SetRecordContents(true);
|
||||
conn->SetRecordPackets(true);
|
||||
conn->SetRecordContents(true);
|
||||
|
||||
const u_char* payload = pkt->ip_hdr->Payload();
|
||||
const u_char* payload = pkt->ip_hdr->Payload();
|
||||
|
||||
run_state::current_timestamp = run_state::processing_start_time;
|
||||
run_state::current_pkt = pkt;
|
||||
run_state::current_timestamp = run_state::processing_start_time;
|
||||
run_state::current_pkt = pkt;
|
||||
|
||||
// TODO: Does this actually mean anything?
|
||||
if ( conn->GetSessionAdapter()->Skipping() )
|
||||
return true;
|
||||
// TODO: Does this actually mean anything?
|
||||
if ( conn->GetSessionAdapter()->Skipping() )
|
||||
return true;
|
||||
|
||||
DeliverPacket(conn, run_state::processing_start_time, is_orig, len, pkt);
|
||||
DeliverPacket(conn, run_state::processing_start_time, is_orig, len, pkt);
|
||||
|
||||
run_state::current_timestamp = 0;
|
||||
run_state::current_pkt = nullptr;
|
||||
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 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 = payload - pkt->data;
|
||||
}
|
||||
// If we don't want the content, set the dump size to include just
|
||||
// the header.
|
||||
if ( ! conn->RecordContents() )
|
||||
pkt->dump_size = payload - pkt->data;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IPBasedAnalyzer::CheckHeaderTrunc(size_t min_hdr_len, size_t remaining, Packet* packet)
|
||||
{
|
||||
// If segment offloading or similar is enabled, the payload len will return 0.
|
||||
// Thus, let's ignore that case.
|
||||
if ( packet->ip_hdr->PayloadLen() && 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;
|
||||
}
|
||||
bool IPBasedAnalyzer::CheckHeaderTrunc(size_t min_hdr_len, size_t remaining, Packet* packet) {
|
||||
// If segment offloading or similar is enabled, the payload len will return 0.
|
||||
// Thus, let's ignore that case.
|
||||
if ( packet->ip_hdr->PayloadLen() && 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;
|
||||
}
|
||||
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<zeek_uint_t> port_cache;
|
||||
static bool have_cache = false;
|
||||
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<zeek_uint_t> port_cache;
|
||||
static bool have_cache = false;
|
||||
|
||||
if ( ! have_cache )
|
||||
{
|
||||
auto likely_server_ports = id::find_val<TableVal>("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;
|
||||
}
|
||||
if ( ! have_cache ) {
|
||||
auto likely_server_ports = id::find_val<TableVal>("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;
|
||||
// We exploit our knowledge of PortVal's internal storage mechanism here.
|
||||
port |= server_port_mask;
|
||||
|
||||
return port_cache.find(port) != port_cache.end();
|
||||
}
|
||||
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;
|
||||
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;
|
||||
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);
|
||||
Connection* conn = new Connection(key, run_state::processing_start_time, id, pkt->ip_hdr->FlowLabel(), pkt);
|
||||
conn->SetTransport(transport);
|
||||
|
||||
if ( flip && ! id->dst_addr.IsBroadcast() )
|
||||
conn->FlipRoles();
|
||||
if ( flip && ! id->dst_addr.IsBroadcast() )
|
||||
conn->FlipRoles();
|
||||
|
||||
BuildSessionAnalyzerTree(conn);
|
||||
BuildSessionAnalyzerTree(conn);
|
||||
|
||||
if ( new_connection )
|
||||
conn->Event(new_connection, nullptr);
|
||||
if ( new_connection )
|
||||
conn->Event(new_connection, nullptr);
|
||||
|
||||
return conn;
|
||||
}
|
||||
return conn;
|
||||
}
|
||||
|
||||
void IPBasedAnalyzer::BuildSessionAnalyzerTree(Connection* conn)
|
||||
{
|
||||
SessionAdapter* root = MakeSessionAdapter(conn);
|
||||
analyzer::pia::PIA* pia = MakePIA(conn);
|
||||
void IPBasedAnalyzer::BuildSessionAnalyzerTree(Connection* conn) {
|
||||
SessionAdapter* root = MakeSessionAdapter(conn);
|
||||
analyzer::pia::PIA* pia = MakePIA(conn);
|
||||
|
||||
bool scheduled = analyzer_mgr->ApplyScheduledAnalyzers(conn, false, root);
|
||||
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 ( ! analyzers_by_port.empty() && ! zeek::detail::dpd_ignore_ports )
|
||||
{
|
||||
int resp_port = ntohs(conn->RespPort());
|
||||
std::set<zeek::Tag>* ports = LookupPort(resp_port, false);
|
||||
// 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 ( ! analyzers_by_port.empty() && ! zeek::detail::dpd_ignore_ports ) {
|
||||
int resp_port = ntohs(conn->RespPort());
|
||||
std::set<zeek::Tag>* ports = LookupPort(resp_port, false);
|
||||
|
||||
if ( ports )
|
||||
{
|
||||
for ( const auto& port : *ports )
|
||||
{
|
||||
analyzer::Analyzer* analyzer = analyzer_mgr->InstantiateAnalyzer(port, conn);
|
||||
if ( ports ) {
|
||||
for ( const auto& port : *ports ) {
|
||||
analyzer::Analyzer* analyzer = analyzer_mgr->InstantiateAnalyzer(port, conn);
|
||||
|
||||
if ( ! analyzer )
|
||||
continue;
|
||||
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->AddChildAnalyzer(analyzer, false);
|
||||
DBG_ANALYZER_ARGS(conn, "activated %s analyzer due to port %d",
|
||||
analyzer_mgr->GetComponentName(port).c_str(), resp_port);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make analyzers added above through known ports visible via GetChildren()
|
||||
root->AppendNewChildren();
|
||||
// Make analyzers added above through known ports visible via GetChildren()
|
||||
root->AppendNewChildren();
|
||||
|
||||
root->AddExtraAnalyzers(conn);
|
||||
root->AddExtraAnalyzers(conn);
|
||||
|
||||
if ( pia )
|
||||
root->AddChildAnalyzer(pia->AsAnalyzer());
|
||||
if ( pia )
|
||||
root->AddChildAnalyzer(pia->AsAnalyzer());
|
||||
|
||||
conn->SetSessionAdapter(root, pia);
|
||||
root->Init();
|
||||
root->InitChildren();
|
||||
conn->SetSessionAdapter(root, pia);
|
||||
root->Init();
|
||||
root->InitChildren();
|
||||
|
||||
PLUGIN_HOOK_VOID(HOOK_SETUP_ANALYZER_TREE, HookSetupAnalyzerTree(conn));
|
||||
}
|
||||
PLUGIN_HOOK_VOID(HOOK_SETUP_ANALYZER_TREE, HookSetupAnalyzerTree(conn));
|
||||
}
|
||||
|
||||
bool IPBasedAnalyzer::RegisterAnalyzerForPort(const zeek::Tag& tag, uint32_t port)
|
||||
{
|
||||
tag_set* l = LookupPort(port, true);
|
||||
bool IPBasedAnalyzer::RegisterAnalyzerForPort(const zeek::Tag& tag, uint32_t port) {
|
||||
tag_set* l = LookupPort(port, true);
|
||||
|
||||
if ( ! l )
|
||||
return false;
|
||||
if ( ! l )
|
||||
return false;
|
||||
|
||||
#ifdef DEBUG
|
||||
const char* name = analyzer_mgr->GetComponentName(tag).c_str();
|
||||
DBG_LOG(DBG_ANALYZER, "Registering analyzer %s for port %" PRIu32 "/%d", name, port, transport);
|
||||
const char* name = analyzer_mgr->GetComponentName(tag).c_str();
|
||||
DBG_LOG(DBG_ANALYZER, "Registering analyzer %s for port %" PRIu32 "/%d", name, port, transport);
|
||||
#endif
|
||||
|
||||
l->insert(tag);
|
||||
return true;
|
||||
}
|
||||
l->insert(tag);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IPBasedAnalyzer::UnregisterAnalyzerForPort(const zeek::Tag& tag, uint32_t port)
|
||||
{
|
||||
tag_set* l = LookupPort(port, true);
|
||||
bool IPBasedAnalyzer::UnregisterAnalyzerForPort(const zeek::Tag& tag, uint32_t port) {
|
||||
tag_set* l = LookupPort(port, true);
|
||||
|
||||
if ( ! l )
|
||||
return true; // still a "successful" unregistration
|
||||
if ( ! l )
|
||||
return true; // still a "successful" unregistration
|
||||
|
||||
#ifdef DEBUG
|
||||
const char* name = analyzer_mgr->GetComponentName(tag).c_str();
|
||||
DBG_LOG(DBG_ANALYZER, "Unregistering analyzer %s for port %" PRIu32 "/%d", name, port,
|
||||
transport);
|
||||
const char* name = analyzer_mgr->GetComponentName(tag).c_str();
|
||||
DBG_LOG(DBG_ANALYZER, "Unregistering analyzer %s for port %" PRIu32 "/%d", name, port, transport);
|
||||
#endif
|
||||
|
||||
l->erase(tag);
|
||||
return true;
|
||||
}
|
||||
l->erase(tag);
|
||||
return true;
|
||||
}
|
||||
|
||||
IPBasedAnalyzer::tag_set* IPBasedAnalyzer::LookupPort(uint32_t port, bool add_if_not_found)
|
||||
{
|
||||
analyzer_map_by_port::const_iterator i = analyzers_by_port.find(port);
|
||||
IPBasedAnalyzer::tag_set* IPBasedAnalyzer::LookupPort(uint32_t port, bool add_if_not_found) {
|
||||
analyzer_map_by_port::const_iterator i = analyzers_by_port.find(port);
|
||||
|
||||
if ( i != analyzers_by_port.end() )
|
||||
return i->second;
|
||||
if ( i != analyzers_by_port.end() )
|
||||
return i->second;
|
||||
|
||||
if ( ! add_if_not_found )
|
||||
return nullptr;
|
||||
if ( ! add_if_not_found )
|
||||
return nullptr;
|
||||
|
||||
tag_set* l = new tag_set{};
|
||||
analyzers_by_port.insert(std::make_pair(port, l));
|
||||
return l;
|
||||
}
|
||||
tag_set* l = new tag_set{};
|
||||
analyzers_by_port.insert(std::make_pair(port, l));
|
||||
return l;
|
||||
}
|
||||
|
||||
void IPBasedAnalyzer::DumpPortDebug()
|
||||
{
|
||||
for ( const auto& mapping : analyzers_by_port )
|
||||
{
|
||||
std::string s;
|
||||
void IPBasedAnalyzer::DumpPortDebug() {
|
||||
for ( const auto& mapping : analyzers_by_port ) {
|
||||
std::string s;
|
||||
|
||||
for ( const auto& tag : *(mapping.second) )
|
||||
s += std::string(analyzer_mgr->GetComponentName(tag)) + " ";
|
||||
for ( const auto& tag : *(mapping.second) )
|
||||
s += std::string(analyzer_mgr->GetComponentName(tag)) + " ";
|
||||
|
||||
DBG_LOG(DBG_ANALYZER, " %d/%s: %s", mapping.first, transport_proto_string(transport),
|
||||
s.c_str());
|
||||
}
|
||||
}
|
||||
DBG_LOG(DBG_ANALYZER, " %d/%s: %s", mapping.first, transport_proto_string(transport), s.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
TableValPtr IPBasedAnalyzer::ignore_checksums_nets_table = nullptr;
|
||||
|
||||
void IPBasedAnalyzer::SetIgnoreChecksumsNets(TableValPtr t)
|
||||
{
|
||||
IPBasedAnalyzer::ignore_checksums_nets_table = t;
|
||||
}
|
||||
void IPBasedAnalyzer::SetIgnoreChecksumsNets(TableValPtr t) { IPBasedAnalyzer::ignore_checksums_nets_table = t; }
|
||||
|
||||
TableValPtr IPBasedAnalyzer::GetIgnoreChecksumsNets()
|
||||
{
|
||||
if ( ! IPBasedAnalyzer::ignore_checksums_nets_table )
|
||||
IPBasedAnalyzer::ignore_checksums_nets_table = zeek::id::find_val<TableVal>(
|
||||
"ignore_checksums_nets");
|
||||
return IPBasedAnalyzer::ignore_checksums_nets_table;
|
||||
}
|
||||
TableValPtr IPBasedAnalyzer::GetIgnoreChecksumsNets() {
|
||||
if ( ! IPBasedAnalyzer::ignore_checksums_nets_table )
|
||||
IPBasedAnalyzer::ignore_checksums_nets_table = zeek::id::find_val<TableVal>("ignore_checksums_nets");
|
||||
return IPBasedAnalyzer::ignore_checksums_nets_table;
|
||||
}
|
||||
|
|
|
@ -9,13 +9,11 @@
|
|||
#include "zeek/Tag.h"
|
||||
#include "zeek/packet_analysis/Analyzer.h"
|
||||
|
||||
namespace zeek::analyzer::pia
|
||||
{
|
||||
namespace zeek::analyzer::pia {
|
||||
class PIA;
|
||||
}
|
||||
}
|
||||
|
||||
namespace zeek::packet_analysis::IP
|
||||
{
|
||||
namespace zeek::packet_analysis::IP {
|
||||
|
||||
class SessionAdapter;
|
||||
|
||||
|
@ -24,183 +22,176 @@ class SessionAdapter;
|
|||
* 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
|
||||
{
|
||||
class IPBasedAnalyzer : public Analyzer {
|
||||
public:
|
||||
~IPBasedAnalyzer() override;
|
||||
~IPBasedAnalyzer() override;
|
||||
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) 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
|
||||
* 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; }
|
||||
/**
|
||||
* 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; }
|
||||
|
||||
/**
|
||||
* Registers a well-known port for an analyzer. Once registered,
|
||||
* connection on that port will start with a corresponding analyzer
|
||||
* assigned.
|
||||
*
|
||||
* @param tag The analyzer's tag.
|
||||
* @param port The port's number.
|
||||
* @return True if successful.
|
||||
*/
|
||||
bool RegisterAnalyzerForPort(const zeek::Tag& tag, uint32_t port);
|
||||
/**
|
||||
* Registers a well-known port for an analyzer. Once registered,
|
||||
* connection on that port will start with a corresponding analyzer
|
||||
* assigned.
|
||||
*
|
||||
* @param tag The analyzer's tag.
|
||||
* @param port The port's number.
|
||||
* @return True if successful.
|
||||
*/
|
||||
bool RegisterAnalyzerForPort(const zeek::Tag& tag, uint32_t port);
|
||||
|
||||
/**
|
||||
* Unregisters a well-known port for an analyzer.
|
||||
*
|
||||
* @param tag The analyzer's tag.
|
||||
* @param port The port's number.
|
||||
* @param tag The analyzer's tag as an enum of script type \c
|
||||
* Tag.
|
||||
*/
|
||||
bool UnregisterAnalyzerForPort(const zeek::Tag& tag, uint32_t port);
|
||||
/**
|
||||
* Unregisters a well-known port for an analyzer.
|
||||
*
|
||||
* @param tag The analyzer's tag.
|
||||
* @param port The port's number.
|
||||
* @param tag The analyzer's tag as an enum of script type \c
|
||||
* Tag.
|
||||
*/
|
||||
bool UnregisterAnalyzerForPort(const zeek::Tag& tag, uint32_t port);
|
||||
|
||||
/**
|
||||
* Dumps information about the registered session analyzers per port.
|
||||
* Used by analyzer::Manager.
|
||||
*/
|
||||
void DumpPortDebug();
|
||||
/**
|
||||
* Dumps information about the registered session analyzers per port.
|
||||
* Used by analyzer::Manager.
|
||||
*/
|
||||
void DumpPortDebug();
|
||||
|
||||
/**
|
||||
* Updates the internal pointer to the script-level variable `ignore_checksums_nets`.
|
||||
* This is used to prevent repeated (costly) lookup of the script-level variable
|
||||
* by IP-based analyzers.
|
||||
*
|
||||
* @param t New value of ignore_checksums_nets
|
||||
*/
|
||||
static void SetIgnoreChecksumsNets(TableValPtr t);
|
||||
/**
|
||||
* Updates the internal pointer to the script-level variable `ignore_checksums_nets`.
|
||||
* This is used to prevent repeated (costly) lookup of the script-level variable
|
||||
* by IP-based analyzers.
|
||||
*
|
||||
* @param t New value of ignore_checksums_nets
|
||||
*/
|
||||
static void SetIgnoreChecksumsNets(TableValPtr t);
|
||||
|
||||
/**
|
||||
* Gets the internal pointer to the script-level variable `ignore_checksums_nets`.
|
||||
* This is used to prevent repeated (costly) lookup of the script-level variable
|
||||
* by IP-based analyzers.
|
||||
*
|
||||
* @return Current value of `ignore_checksums_nets`.
|
||||
*/
|
||||
static TableValPtr GetIgnoreChecksumsNets();
|
||||
/**
|
||||
* Gets the internal pointer to the script-level variable `ignore_checksums_nets`.
|
||||
* This is used to prevent repeated (costly) lookup of the script-level variable
|
||||
* by IP-based analyzers.
|
||||
*
|
||||
* @return Current value of `ignore_checksums_nets`.
|
||||
*/
|
||||
static TableValPtr GetIgnoreChecksumsNets();
|
||||
|
||||
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);
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Parse the header from the packet into a ConnTuple object.
|
||||
*/
|
||||
virtual bool BuildConnTuple(size_t len, const uint8_t* data, Packet* packet,
|
||||
ConnTuple& tuple) = 0;
|
||||
/**
|
||||
* Parse the header from the packet into a ConnTuple object.
|
||||
*/
|
||||
virtual bool BuildConnTuple(size_t len, const uint8_t* data, Packet* packet, ConnTuple& tuple) = 0;
|
||||
|
||||
/**
|
||||
* 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 DeliverPacket(Connection* conn, double t, bool is_orig, int remaining, Packet* pkt)
|
||||
{
|
||||
}
|
||||
/**
|
||||
* 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 DeliverPacket(Connection* conn, double t, bool is_orig, int remaining, Packet* pkt) {}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
/**
|
||||
* 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 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 SessionAdapter* MakeSessionAdapter(Connection* conn) = 0;
|
||||
/**
|
||||
* 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 SessionAdapter* MakeSessionAdapter(Connection* conn) = 0;
|
||||
|
||||
/**
|
||||
* 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; }
|
||||
/**
|
||||
* 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; }
|
||||
|
||||
/**
|
||||
* 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);
|
||||
/**
|
||||
* 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
|
||||
* 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;
|
||||
/**
|
||||
* 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;
|
||||
|
||||
private:
|
||||
// While this is storing session analyzer tags, we store it here since packet analyzers
|
||||
// are persistent objects. We can't do this in the adapters because those get created
|
||||
// and destroyed for each connection.
|
||||
using tag_set = std::set<zeek::Tag>;
|
||||
using analyzer_map_by_port = std::map<uint32_t, tag_set*>;
|
||||
analyzer_map_by_port analyzers_by_port;
|
||||
// While this is storing session analyzer tags, we store it here since packet analyzers
|
||||
// are persistent objects. We can't do this in the adapters because those get created
|
||||
// and destroyed for each connection.
|
||||
using tag_set = std::set<zeek::Tag>;
|
||||
using analyzer_map_by_port = std::map<uint32_t, tag_set*>;
|
||||
analyzer_map_by_port analyzers_by_port;
|
||||
|
||||
tag_set* LookupPort(uint32_t port, bool add_if_not_found);
|
||||
tag_set* LookupPort(uint32_t port, bool add_if_not_found);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
/**
|
||||
* 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);
|
||||
|
||||
void BuildSessionAnalyzerTree(Connection* conn);
|
||||
void BuildSessionAnalyzerTree(Connection* conn);
|
||||
|
||||
TransportProto transport;
|
||||
uint32_t server_port_mask;
|
||||
static TableValPtr ignore_checksums_nets_table;
|
||||
};
|
||||
TransportProto transport;
|
||||
uint32_t server_port_mask;
|
||||
static TableValPtr ignore_checksums_nets_table;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace zeek::packet_analysis::IP
|
||||
|
|
|
@ -5,23 +5,19 @@
|
|||
#include "zeek/packet_analysis/Component.h"
|
||||
#include "zeek/packet_analysis/protocol/ip/IP.h"
|
||||
|
||||
namespace zeek::plugin::Zeek_IP
|
||||
{
|
||||
namespace zeek::plugin::Zeek_IP {
|
||||
|
||||
class Plugin final : public zeek::plugin::Plugin
|
||||
{
|
||||
class Plugin final : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure() override
|
||||
{
|
||||
AddComponent(new zeek::packet_analysis::Component(
|
||||
"IP", zeek::packet_analysis::IP::IPAnalyzer::Instantiate));
|
||||
zeek::plugin::Configuration Configure() override {
|
||||
AddComponent(new zeek::packet_analysis::Component("IP", zeek::packet_analysis::IP::IPAnalyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::IP";
|
||||
config.description = "Packet analyzer for IP fallback (v4 or v6)";
|
||||
return config;
|
||||
}
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::IP";
|
||||
config.description = "Packet analyzer for IP fallback (v4 or v6)";
|
||||
return config;
|
||||
}
|
||||
|
||||
} plugin;
|
||||
} plugin;
|
||||
|
||||
}
|
||||
} // namespace zeek::plugin::Zeek_IP
|
||||
|
|
|
@ -6,33 +6,23 @@
|
|||
|
||||
using namespace zeek::packet_analysis::IP;
|
||||
|
||||
void SessionAdapter::Done()
|
||||
{
|
||||
Analyzer::Done();
|
||||
}
|
||||
void SessionAdapter::Done() { Analyzer::Done(); }
|
||||
|
||||
bool SessionAdapter::IsReuse(double t, const u_char* pkt)
|
||||
{
|
||||
return parent->IsReuse(t, pkt);
|
||||
}
|
||||
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");
|
||||
}
|
||||
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;
|
||||
}
|
||||
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<StringVal>(cbs);
|
||||
EnqueueConnEvent(packet_contents, ConnVal(), std::move(contents));
|
||||
}
|
||||
}
|
||||
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<StringVal>(cbs);
|
||||
EnqueueConnEvent(packet_contents, ConnVal(), std::move(contents));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,13 +2,11 @@
|
|||
|
||||
#include "zeek/analyzer/Analyzer.h"
|
||||
|
||||
namespace zeek::analyzer::pia
|
||||
{
|
||||
namespace zeek::analyzer::pia {
|
||||
class PIA;
|
||||
}
|
||||
}
|
||||
|
||||
namespace zeek::packet_analysis::IP
|
||||
{
|
||||
namespace zeek::packet_analysis::IP {
|
||||
|
||||
class IPBasedAnalyzer;
|
||||
|
||||
|
@ -17,88 +15,86 @@ class IPBasedAnalyzer;
|
|||
* 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
|
||||
{
|
||||
|
||||
class SessionAdapter : public analyzer::Analyzer {
|
||||
public:
|
||||
SessionAdapter(const char* name, Connection* conn) : analyzer::Analyzer(name, conn) { }
|
||||
SessionAdapter(const char* name, Connection* conn) : analyzer::Analyzer(name, conn) {}
|
||||
|
||||
/**
|
||||
* Overridden from parent class.
|
||||
*/
|
||||
virtual void Done() override;
|
||||
/**
|
||||
* 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; }
|
||||
/**
|
||||
* 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);
|
||||
/**
|
||||
* 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 analyzers 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;
|
||||
/**
|
||||
* Pure virtual method to allow extra session analyzers 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
|
||||
* override 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);
|
||||
/**
|
||||
* Associates a file with the analyzer in which to record all
|
||||
* analyzed input. This must only be called with derived classes that
|
||||
* override 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 override 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;
|
||||
/**
|
||||
* Returns an associated contents file, if any. This must only be
|
||||
* called with derived classes that override 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; }
|
||||
/**
|
||||
* 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; }
|
||||
/**
|
||||
* 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 data to pass to the event.
|
||||
*
|
||||
* @param len The length of \a data.
|
||||
*/
|
||||
void PacketContents(const u_char* data, int len);
|
||||
/**
|
||||
* Helper to raise a \c packet_contents event.
|
||||
*
|
||||
* @param data The data to pass to the event.
|
||||
*
|
||||
* @param len The length of \a data.
|
||||
*/
|
||||
void PacketContents(const u_char* data, int len);
|
||||
|
||||
protected:
|
||||
IPBasedAnalyzer* parent = nullptr;
|
||||
analyzer::pia::PIA* pia = nullptr;
|
||||
};
|
||||
IPBasedAnalyzer* parent = nullptr;
|
||||
analyzer::pia::PIA* pia = nullptr;
|
||||
};
|
||||
|
||||
} // namespace zeek::packet_analysis::IP
|
||||
} // namespace zeek::packet_analysis::IP
|
||||
|
|
|
@ -10,231 +10,207 @@
|
|||
#include "zeek/TunnelEncapsulation.h"
|
||||
#include "zeek/packet_analysis/protocol/ip/IP.h"
|
||||
|
||||
namespace zeek::packet_analysis::IPTunnel
|
||||
{
|
||||
namespace zeek::packet_analysis::IPTunnel {
|
||||
|
||||
IPTunnelAnalyzer* ip_tunnel_analyzer;
|
||||
|
||||
IPTunnelAnalyzer::IPTunnelAnalyzer() : zeek::packet_analysis::Analyzer("IPTunnel")
|
||||
{
|
||||
ip_tunnel_analyzer = this;
|
||||
}
|
||||
IPTunnelAnalyzer::IPTunnelAnalyzer() : zeek::packet_analysis::Analyzer("IPTunnel") { ip_tunnel_analyzer = this; }
|
||||
|
||||
bool IPTunnelAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet)
|
||||
{
|
||||
if ( ! packet->ip_hdr )
|
||||
{
|
||||
reporter->InternalError("IPTunnelAnalyzer: null ip_hdr in packet");
|
||||
return false;
|
||||
}
|
||||
bool IPTunnelAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) {
|
||||
if ( ! packet->ip_hdr ) {
|
||||
reporter->InternalError("IPTunnelAnalyzer: null ip_hdr in packet");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( packet->encap && packet->encap->Depth() >= BifConst::Tunnel::max_depth )
|
||||
{
|
||||
Weird("exceeded_tunnel_max_depth", packet);
|
||||
return false;
|
||||
}
|
||||
if ( packet->encap && packet->encap->Depth() >= BifConst::Tunnel::max_depth ) {
|
||||
Weird("exceeded_tunnel_max_depth", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
int proto = packet->proto;
|
||||
int gre_version = packet->gre_version;
|
||||
BifEnum::Tunnel::Type tunnel_type = packet->tunnel_type;
|
||||
int gre_link_type = packet->gre_link_type;
|
||||
int proto = packet->proto;
|
||||
int gre_version = packet->gre_version;
|
||||
BifEnum::Tunnel::Type tunnel_type = packet->tunnel_type;
|
||||
int gre_link_type = packet->gre_link_type;
|
||||
|
||||
std::shared_ptr<IP_Hdr> inner = nullptr;
|
||||
std::shared_ptr<IP_Hdr> inner = nullptr;
|
||||
|
||||
if ( gre_version != 0 )
|
||||
{
|
||||
// Check for a valid inner packet first.
|
||||
auto result = packet_analysis::IP::ParsePacket(len, data, proto, inner);
|
||||
if ( result == packet_analysis::IP::ParseResult::BadProtocol )
|
||||
Weird("invalid_inner_IP_version", packet);
|
||||
else if ( result < packet_analysis::IP::ParseResult::CaplenTooSmall )
|
||||
Weird("truncated_inner_IP", packet);
|
||||
else if ( result > packet_analysis::IP::ParseResult::CaplenTooLarge )
|
||||
Weird("inner_IP_payload_length_mismatch", packet);
|
||||
if ( gre_version != 0 ) {
|
||||
// Check for a valid inner packet first.
|
||||
auto result = packet_analysis::IP::ParsePacket(len, data, proto, inner);
|
||||
if ( result == packet_analysis::IP::ParseResult::BadProtocol )
|
||||
Weird("invalid_inner_IP_version", packet);
|
||||
else if ( result < packet_analysis::IP::ParseResult::CaplenTooSmall )
|
||||
Weird("truncated_inner_IP", packet);
|
||||
else if ( result > packet_analysis::IP::ParseResult::CaplenTooLarge )
|
||||
Weird("inner_IP_payload_length_mismatch", packet);
|
||||
|
||||
if ( result != packet_analysis::IP::ParseResult::Ok )
|
||||
return false;
|
||||
}
|
||||
if ( result != packet_analysis::IP::ParseResult::Ok )
|
||||
return false;
|
||||
}
|
||||
|
||||
// Look up to see if we've already seen this IP tunnel, identified
|
||||
// by the pair of IP addresses, so that we can always associate the
|
||||
// same UID with it.
|
||||
IPPair tunnel_idx;
|
||||
if ( packet->ip_hdr->SrcAddr() < packet->ip_hdr->DstAddr() )
|
||||
tunnel_idx = IPPair(packet->ip_hdr->SrcAddr(), packet->ip_hdr->DstAddr());
|
||||
else
|
||||
tunnel_idx = IPPair(packet->ip_hdr->DstAddr(), packet->ip_hdr->SrcAddr());
|
||||
// Look up to see if we've already seen this IP tunnel, identified
|
||||
// by the pair of IP addresses, so that we can always associate the
|
||||
// same UID with it.
|
||||
IPPair tunnel_idx;
|
||||
if ( packet->ip_hdr->SrcAddr() < packet->ip_hdr->DstAddr() )
|
||||
tunnel_idx = IPPair(packet->ip_hdr->SrcAddr(), packet->ip_hdr->DstAddr());
|
||||
else
|
||||
tunnel_idx = IPPair(packet->ip_hdr->DstAddr(), packet->ip_hdr->SrcAddr());
|
||||
|
||||
IPTunnelMap::iterator tunnel_it = ip_tunnels.find(tunnel_idx);
|
||||
IPTunnelMap::iterator tunnel_it = ip_tunnels.find(tunnel_idx);
|
||||
|
||||
if ( tunnel_it == ip_tunnels.end() )
|
||||
{
|
||||
EncapsulatingConn ec(packet->ip_hdr->SrcAddr(), packet->ip_hdr->DstAddr(), tunnel_type);
|
||||
ip_tunnels[tunnel_idx] = TunnelActivity(ec, run_state::network_time);
|
||||
zeek::detail::timer_mgr->Add(
|
||||
new detail::IPTunnelTimer(run_state::network_time, tunnel_idx, this));
|
||||
}
|
||||
else
|
||||
tunnel_it->second.second = zeek::run_state::network_time;
|
||||
if ( tunnel_it == ip_tunnels.end() ) {
|
||||
EncapsulatingConn ec(packet->ip_hdr->SrcAddr(), packet->ip_hdr->DstAddr(), tunnel_type);
|
||||
ip_tunnels[tunnel_idx] = TunnelActivity(ec, run_state::network_time);
|
||||
zeek::detail::timer_mgr->Add(new detail::IPTunnelTimer(run_state::network_time, tunnel_idx, this));
|
||||
}
|
||||
else
|
||||
tunnel_it->second.second = zeek::run_state::network_time;
|
||||
|
||||
if ( gre_version == 0 )
|
||||
return ProcessEncapsulatedPacket(run_state::processing_start_time, packet, len, len, data,
|
||||
gre_link_type, packet->encap,
|
||||
ip_tunnels[tunnel_idx].first);
|
||||
else
|
||||
return ProcessEncapsulatedPacket(run_state::processing_start_time, packet, inner,
|
||||
packet->encap, ip_tunnels[tunnel_idx].first);
|
||||
}
|
||||
if ( gre_version == 0 )
|
||||
return ProcessEncapsulatedPacket(run_state::processing_start_time, packet, len, len, data, gre_link_type,
|
||||
packet->encap, ip_tunnels[tunnel_idx].first);
|
||||
else
|
||||
return ProcessEncapsulatedPacket(run_state::processing_start_time, packet, inner, packet->encap,
|
||||
ip_tunnels[tunnel_idx].first);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a packet that contains an IP header directly after the tunnel header.
|
||||
*/
|
||||
bool IPTunnelAnalyzer::ProcessEncapsulatedPacket(double t, const Packet* pkt,
|
||||
const std::shared_ptr<IP_Hdr>& inner,
|
||||
bool IPTunnelAnalyzer::ProcessEncapsulatedPacket(double t, const Packet* pkt, const std::shared_ptr<IP_Hdr>& inner,
|
||||
std::shared_ptr<EncapsulationStack> prev,
|
||||
const EncapsulatingConn& ec)
|
||||
{
|
||||
uint32_t caplen, len;
|
||||
caplen = len = inner->TotalLen();
|
||||
const EncapsulatingConn& ec) {
|
||||
uint32_t caplen, len;
|
||||
caplen = len = inner->TotalLen();
|
||||
|
||||
pkt_timeval ts;
|
||||
int link_type;
|
||||
pkt_timeval ts;
|
||||
int link_type;
|
||||
|
||||
if ( pkt )
|
||||
ts = pkt->ts;
|
||||
else
|
||||
{
|
||||
ts.tv_sec = (time_t)run_state::network_time;
|
||||
ts.tv_usec = (suseconds_t)((run_state::network_time - (double)ts.tv_sec) * 1000000);
|
||||
}
|
||||
if ( pkt )
|
||||
ts = pkt->ts;
|
||||
else {
|
||||
ts.tv_sec = (time_t)run_state::network_time;
|
||||
ts.tv_usec = (suseconds_t)((run_state::network_time - (double)ts.tv_sec) * 1000000);
|
||||
}
|
||||
|
||||
const u_char* data = nullptr;
|
||||
const u_char* data = nullptr;
|
||||
|
||||
if ( inner->IP4_Hdr() )
|
||||
data = (const u_char*)inner->IP4_Hdr();
|
||||
else
|
||||
data = (const u_char*)inner->IP6_Hdr();
|
||||
if ( inner->IP4_Hdr() )
|
||||
data = (const u_char*)inner->IP4_Hdr();
|
||||
else
|
||||
data = (const u_char*)inner->IP6_Hdr();
|
||||
|
||||
auto outer = prev ? prev : std::make_shared<EncapsulationStack>();
|
||||
outer->Add(ec);
|
||||
auto outer = prev ? prev : std::make_shared<EncapsulationStack>();
|
||||
outer->Add(ec);
|
||||
|
||||
// Construct fake packet containing the inner packet so it can be processed
|
||||
// like a normal one.
|
||||
Packet p;
|
||||
p.Init(DLT_RAW, &ts, caplen, len, data, false, "");
|
||||
p.encap = outer;
|
||||
// Construct fake packet containing the inner packet so it can be processed
|
||||
// like a normal one.
|
||||
Packet p;
|
||||
p.Init(DLT_RAW, &ts, caplen, len, data, false, "");
|
||||
p.encap = outer;
|
||||
|
||||
// Forward the packet back to the IP analyzer.
|
||||
bool return_val = ForwardPacket(len, data, &p);
|
||||
// Forward the packet back to the IP analyzer.
|
||||
bool return_val = ForwardPacket(len, data, &p);
|
||||
|
||||
return return_val;
|
||||
}
|
||||
return return_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a packet that contains a physical-layer header after the tunnel header.
|
||||
*/
|
||||
bool IPTunnelAnalyzer::ProcessEncapsulatedPacket(double t, const Packet* pkt, uint32_t caplen,
|
||||
uint32_t len, const u_char* data, int link_type,
|
||||
bool IPTunnelAnalyzer::ProcessEncapsulatedPacket(double t, const Packet* pkt, uint32_t caplen, uint32_t len,
|
||||
const u_char* data, int link_type,
|
||||
std::shared_ptr<EncapsulationStack> prev,
|
||||
const EncapsulatingConn& ec)
|
||||
{
|
||||
pkt_timeval ts;
|
||||
const EncapsulatingConn& ec) {
|
||||
pkt_timeval ts;
|
||||
|
||||
if ( pkt )
|
||||
ts = pkt->ts;
|
||||
else
|
||||
{
|
||||
ts.tv_sec = (time_t)run_state::network_time;
|
||||
ts.tv_usec = (suseconds_t)((run_state::network_time - (double)ts.tv_sec) * 1000000);
|
||||
}
|
||||
if ( pkt )
|
||||
ts = pkt->ts;
|
||||
else {
|
||||
ts.tv_sec = (time_t)run_state::network_time;
|
||||
ts.tv_usec = (suseconds_t)((run_state::network_time - (double)ts.tv_sec) * 1000000);
|
||||
}
|
||||
|
||||
auto outer = prev ? prev : std::make_shared<EncapsulationStack>();
|
||||
outer->Add(ec);
|
||||
auto outer = prev ? prev : std::make_shared<EncapsulationStack>();
|
||||
outer->Add(ec);
|
||||
|
||||
// Construct fake packet containing the inner packet so it can be processed
|
||||
// like a normal one.
|
||||
Packet p;
|
||||
p.Init(link_type, &ts, caplen, len, data, false, "");
|
||||
p.encap = outer;
|
||||
// Construct fake packet containing the inner packet so it can be processed
|
||||
// like a normal one.
|
||||
Packet p;
|
||||
p.Init(link_type, &ts, caplen, len, data, false, "");
|
||||
p.encap = outer;
|
||||
|
||||
// Process the packet as if it was a brand new packet by passing it back
|
||||
// to the packet manager.
|
||||
bool return_val = packet_mgr->ProcessInnerPacket(&p);
|
||||
// Process the packet as if it was a brand new packet by passing it back
|
||||
// to the packet manager.
|
||||
bool return_val = packet_mgr->ProcessInnerPacket(&p);
|
||||
|
||||
return return_val;
|
||||
}
|
||||
return return_val;
|
||||
}
|
||||
|
||||
std::unique_ptr<Packet> build_inner_packet(Packet* outer_pkt, int* encap_index,
|
||||
std::shared_ptr<EncapsulationStack> encap_stack,
|
||||
uint32_t inner_cap_len, const u_char* data,
|
||||
int link_type, BifEnum::Tunnel::Type tunnel_type,
|
||||
const Tag& analyzer_tag)
|
||||
{
|
||||
auto inner_pkt = std::make_unique<Packet>();
|
||||
std::shared_ptr<EncapsulationStack> encap_stack, uint32_t inner_cap_len,
|
||||
const u_char* data, int link_type, BifEnum::Tunnel::Type tunnel_type,
|
||||
const Tag& analyzer_tag) {
|
||||
auto inner_pkt = std::make_unique<Packet>();
|
||||
|
||||
assert(outer_pkt->cap_len >= inner_cap_len);
|
||||
assert(outer_pkt->len >= outer_pkt->cap_len - inner_cap_len);
|
||||
assert(outer_pkt->cap_len >= inner_cap_len);
|
||||
assert(outer_pkt->len >= outer_pkt->cap_len - inner_cap_len);
|
||||
|
||||
// Compute the wire length of the inner packet based on the wire length of
|
||||
// the outer and the difference in capture lengths. This ensures that for
|
||||
// truncated packets the wire length of the inner packet stays intact. Wire
|
||||
// length may be greater than data available for truncated packets. However,
|
||||
// analyzers do validate lengths found in headers with the wire length
|
||||
// of the packet and keeping it consistent avoids violations.
|
||||
uint32_t consumed_len = outer_pkt->cap_len - inner_cap_len;
|
||||
uint32_t inner_wire_len = outer_pkt->len - consumed_len;
|
||||
// Compute the wire length of the inner packet based on the wire length of
|
||||
// the outer and the difference in capture lengths. This ensures that for
|
||||
// truncated packets the wire length of the inner packet stays intact. Wire
|
||||
// length may be greater than data available for truncated packets. However,
|
||||
// analyzers do validate lengths found in headers with the wire length
|
||||
// of the packet and keeping it consistent avoids violations.
|
||||
uint32_t consumed_len = outer_pkt->cap_len - inner_cap_len;
|
||||
uint32_t inner_wire_len = outer_pkt->len - consumed_len;
|
||||
|
||||
pkt_timeval ts;
|
||||
ts.tv_sec = static_cast<time_t>(run_state::current_timestamp);
|
||||
ts.tv_usec = static_cast<suseconds_t>(
|
||||
(run_state::current_timestamp - static_cast<double>(ts.tv_sec)) * 1000000);
|
||||
inner_pkt->Init(link_type, &ts, inner_cap_len, inner_wire_len, data);
|
||||
pkt_timeval ts;
|
||||
ts.tv_sec = static_cast<time_t>(run_state::current_timestamp);
|
||||
ts.tv_usec = static_cast<suseconds_t>((run_state::current_timestamp - static_cast<double>(ts.tv_sec)) * 1000000);
|
||||
inner_pkt->Init(link_type, &ts, inner_cap_len, inner_wire_len, data);
|
||||
|
||||
*encap_index = 0;
|
||||
if ( outer_pkt->session )
|
||||
{
|
||||
EncapsulatingConn inner(static_cast<Connection*>(outer_pkt->session), tunnel_type);
|
||||
*encap_index = 0;
|
||||
if ( outer_pkt->session ) {
|
||||
EncapsulatingConn inner(static_cast<Connection*>(outer_pkt->session), tunnel_type);
|
||||
|
||||
if ( ! outer_pkt->encap )
|
||||
outer_pkt->encap = encap_stack != nullptr ? encap_stack
|
||||
: std::make_shared<EncapsulationStack>();
|
||||
if ( ! outer_pkt->encap )
|
||||
outer_pkt->encap = encap_stack != nullptr ? encap_stack : std::make_shared<EncapsulationStack>();
|
||||
|
||||
outer_pkt->encap->Add(inner);
|
||||
inner_pkt->encap = outer_pkt->encap;
|
||||
*encap_index = outer_pkt->encap->Depth();
|
||||
}
|
||||
outer_pkt->encap->Add(inner);
|
||||
inner_pkt->encap = outer_pkt->encap;
|
||||
*encap_index = outer_pkt->encap->Depth();
|
||||
}
|
||||
|
||||
return inner_pkt;
|
||||
}
|
||||
return inner_pkt;
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
namespace detail {
|
||||
|
||||
IPTunnelTimer::IPTunnelTimer(double t, IPTunnelAnalyzer::IPPair p, IPTunnelAnalyzer* analyzer)
|
||||
: Timer(t + BifConst::Tunnel::ip_tunnel_timeout, zeek::detail::TIMER_IP_TUNNEL_INACTIVITY),
|
||||
tunnel_idx(p), analyzer(analyzer)
|
||||
{
|
||||
}
|
||||
: Timer(t + BifConst::Tunnel::ip_tunnel_timeout, zeek::detail::TIMER_IP_TUNNEL_INACTIVITY),
|
||||
tunnel_idx(p),
|
||||
analyzer(analyzer) {}
|
||||
|
||||
void IPTunnelTimer::Dispatch(double t, bool is_expire)
|
||||
{
|
||||
IPTunnelAnalyzer::IPTunnelMap::const_iterator it = analyzer->ip_tunnels.find(tunnel_idx);
|
||||
void IPTunnelTimer::Dispatch(double t, bool is_expire) {
|
||||
IPTunnelAnalyzer::IPTunnelMap::const_iterator it = analyzer->ip_tunnels.find(tunnel_idx);
|
||||
|
||||
if ( it == analyzer->ip_tunnels.end() )
|
||||
return;
|
||||
if ( it == analyzer->ip_tunnels.end() )
|
||||
return;
|
||||
|
||||
double last_active = it->second.second;
|
||||
double inactive_time = t > last_active ? t - last_active : 0;
|
||||
double last_active = it->second.second;
|
||||
double inactive_time = t > last_active ? t - last_active : 0;
|
||||
|
||||
if ( inactive_time >= BifConst::Tunnel::ip_tunnel_timeout )
|
||||
// tunnel activity timed out, delete it from map
|
||||
analyzer->ip_tunnels.erase(tunnel_idx);
|
||||
if ( inactive_time >= BifConst::Tunnel::ip_tunnel_timeout )
|
||||
// tunnel activity timed out, delete it from map
|
||||
analyzer->ip_tunnels.erase(tunnel_idx);
|
||||
|
||||
else if ( ! is_expire )
|
||||
// tunnel activity didn't timeout, schedule another timer
|
||||
zeek::detail::timer_mgr->Add(new IPTunnelTimer(t, tunnel_idx, analyzer));
|
||||
}
|
||||
else if ( ! is_expire )
|
||||
// tunnel activity didn't timeout, schedule another timer
|
||||
zeek::detail::timer_mgr->Add(new IPTunnelTimer(t, tunnel_idx, analyzer));
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace detail
|
||||
|
||||
} // namespace zeek::packet_analysis::IPTunnel
|
||||
} // namespace zeek::packet_analysis::IPTunnel
|
||||
|
|
|
@ -7,76 +7,67 @@
|
|||
#include "zeek/packet_analysis/Analyzer.h"
|
||||
#include "zeek/packet_analysis/Component.h"
|
||||
|
||||
namespace zeek::packet_analysis::IPTunnel
|
||||
{
|
||||
namespace zeek::packet_analysis::IPTunnel {
|
||||
|
||||
namespace detail
|
||||
{
|
||||
namespace detail {
|
||||
class IPTunnelTimer;
|
||||
}
|
||||
}
|
||||
|
||||
class IPTunnelAnalyzer : public Analyzer
|
||||
{
|
||||
class IPTunnelAnalyzer : public Analyzer {
|
||||
public:
|
||||
IPTunnelAnalyzer();
|
||||
~IPTunnelAnalyzer() override = default;
|
||||
IPTunnelAnalyzer();
|
||||
~IPTunnelAnalyzer() override = default;
|
||||
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate()
|
||||
{
|
||||
return std::make_shared<IPTunnelAnalyzer>();
|
||||
}
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate() { return std::make_shared<IPTunnelAnalyzer>(); }
|
||||
|
||||
/**
|
||||
* Wrapper that handles encapsulated IP packets and passes them back into
|
||||
* packet analysis.
|
||||
*
|
||||
* @param t Network time.
|
||||
* @param pkt If the outer pcap header is available, this pointer can be set
|
||||
* so the fake pcap header passed to the next analyzer will use the
|
||||
* same timeval. The caplen and len fields of the fake pcap header
|
||||
* are always set to the TotalLength() of \a inner.
|
||||
* @param inner Pointer to IP header wrapper of the inner packet, ownership
|
||||
* of the pointer's memory is assumed by this function.
|
||||
* @param prev Any previous encapsulation stack of the caller, not including
|
||||
* the most-recently found depth of encapsulation.
|
||||
* @param ec The most-recently found depth of encapsulation.
|
||||
*/
|
||||
bool ProcessEncapsulatedPacket(double t, const Packet* pkt,
|
||||
const std::shared_ptr<IP_Hdr>& inner,
|
||||
std::shared_ptr<EncapsulationStack> prev,
|
||||
const EncapsulatingConn& ec);
|
||||
/**
|
||||
* Wrapper that handles encapsulated IP packets and passes them back into
|
||||
* packet analysis.
|
||||
*
|
||||
* @param t Network time.
|
||||
* @param pkt If the outer pcap header is available, this pointer can be set
|
||||
* so the fake pcap header passed to the next analyzer will use the
|
||||
* same timeval. The caplen and len fields of the fake pcap header
|
||||
* are always set to the TotalLength() of \a inner.
|
||||
* @param inner Pointer to IP header wrapper of the inner packet, ownership
|
||||
* of the pointer's memory is assumed by this function.
|
||||
* @param prev Any previous encapsulation stack of the caller, not including
|
||||
* the most-recently found depth of encapsulation.
|
||||
* @param ec The most-recently found depth of encapsulation.
|
||||
*/
|
||||
bool ProcessEncapsulatedPacket(double t, const Packet* pkt, const std::shared_ptr<IP_Hdr>& inner,
|
||||
std::shared_ptr<EncapsulationStack> prev, const EncapsulatingConn& ec);
|
||||
|
||||
/**
|
||||
* Wrapper that handles encapsulated Ethernet/IP packets and passes them back into
|
||||
* packet analysis.
|
||||
*
|
||||
* @param t Network time.
|
||||
* @param pkt If the outer pcap header is available, this pointer can be set
|
||||
* so the fake pcap header passed to the next analyzer will use the
|
||||
* same timeval.
|
||||
* @param caplen Number of captured bytes remaining
|
||||
* @param len Number of bytes remaining as claimed by outer framing
|
||||
* @param data The remaining packet data
|
||||
* @param link_type Layer 2 link type used for initializing inner packet
|
||||
* @param prev Any previous encapsulation stack of the caller, not
|
||||
* including the most-recently found depth of encapsulation.
|
||||
* @param ec The most-recently found depth of encapsulation.
|
||||
*/
|
||||
bool ProcessEncapsulatedPacket(double t, const Packet* pkt, uint32_t caplen, uint32_t len,
|
||||
const u_char* data, int link_type,
|
||||
std::shared_ptr<EncapsulationStack> prev,
|
||||
const EncapsulatingConn& ec);
|
||||
/**
|
||||
* Wrapper that handles encapsulated Ethernet/IP packets and passes them back into
|
||||
* packet analysis.
|
||||
*
|
||||
* @param t Network time.
|
||||
* @param pkt If the outer pcap header is available, this pointer can be set
|
||||
* so the fake pcap header passed to the next analyzer will use the
|
||||
* same timeval.
|
||||
* @param caplen Number of captured bytes remaining
|
||||
* @param len Number of bytes remaining as claimed by outer framing
|
||||
* @param data The remaining packet data
|
||||
* @param link_type Layer 2 link type used for initializing inner packet
|
||||
* @param prev Any previous encapsulation stack of the caller, not
|
||||
* including the most-recently found depth of encapsulation.
|
||||
* @param ec The most-recently found depth of encapsulation.
|
||||
*/
|
||||
bool ProcessEncapsulatedPacket(double t, const Packet* pkt, uint32_t caplen, uint32_t len, const u_char* data,
|
||||
int link_type, std::shared_ptr<EncapsulationStack> prev,
|
||||
const EncapsulatingConn& ec);
|
||||
|
||||
protected:
|
||||
friend class detail::IPTunnelTimer;
|
||||
friend class detail::IPTunnelTimer;
|
||||
|
||||
using IPPair = std::pair<IPAddr, IPAddr>;
|
||||
using TunnelActivity = std::pair<EncapsulatingConn, double>;
|
||||
using IPTunnelMap = std::map<IPPair, TunnelActivity>;
|
||||
IPTunnelMap ip_tunnels;
|
||||
};
|
||||
using IPPair = std::pair<IPAddr, IPAddr>;
|
||||
using TunnelActivity = std::pair<EncapsulatingConn, double>;
|
||||
using IPTunnelMap = std::map<IPPair, TunnelActivity>;
|
||||
IPTunnelMap ip_tunnels;
|
||||
};
|
||||
|
||||
/**
|
||||
* Utility function for packet analyzers for encapsulation/tunnel protocols. This
|
||||
|
@ -103,29 +94,26 @@ protected:
|
|||
*/
|
||||
extern std::unique_ptr<Packet> build_inner_packet(Packet* outer_pkt, int* encap_index,
|
||||
std::shared_ptr<EncapsulationStack> encap_stack,
|
||||
uint32_t inner_cap_len, const u_char* data,
|
||||
int link_type, BifEnum::Tunnel::Type tunnel_type,
|
||||
const Tag& analyzer_tag);
|
||||
uint32_t inner_cap_len, const u_char* data, int link_type,
|
||||
BifEnum::Tunnel::Type tunnel_type, const Tag& analyzer_tag);
|
||||
|
||||
namespace detail
|
||||
{
|
||||
namespace detail {
|
||||
|
||||
class IPTunnelTimer final : public zeek::detail::Timer
|
||||
{
|
||||
class IPTunnelTimer final : public zeek::detail::Timer {
|
||||
public:
|
||||
IPTunnelTimer(double t, IPTunnelAnalyzer::IPPair p, IPTunnelAnalyzer* analyzer);
|
||||
~IPTunnelTimer() override = default;
|
||||
IPTunnelTimer(double t, IPTunnelAnalyzer::IPPair p, IPTunnelAnalyzer* analyzer);
|
||||
~IPTunnelTimer() override = default;
|
||||
|
||||
void Dispatch(double t, bool is_expire) override;
|
||||
void Dispatch(double t, bool is_expire) override;
|
||||
|
||||
protected:
|
||||
IPTunnelAnalyzer::IPPair tunnel_idx;
|
||||
IPTunnelAnalyzer* analyzer;
|
||||
};
|
||||
IPTunnelAnalyzer::IPPair tunnel_idx;
|
||||
IPTunnelAnalyzer* analyzer;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace detail
|
||||
|
||||
// This is temporary until the TCP and UDP analyzers are moved to be packet analyzers.
|
||||
extern IPTunnelAnalyzer* ip_tunnel_analyzer;
|
||||
|
||||
}
|
||||
} // namespace zeek::packet_analysis::IPTunnel
|
||||
|
|
|
@ -5,23 +5,21 @@
|
|||
#include "zeek/packet_analysis/Component.h"
|
||||
#include "zeek/packet_analysis/protocol/iptunnel/IPTunnel.h"
|
||||
|
||||
namespace zeek::plugin::Zeek_IPTunnel
|
||||
{
|
||||
namespace zeek::plugin::Zeek_IPTunnel {
|
||||
|
||||
class Plugin final : public zeek::plugin::Plugin
|
||||
{
|
||||
class Plugin final : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure() override
|
||||
{
|
||||
AddComponent(new zeek::packet_analysis::Component(
|
||||
"IPTunnel", zeek::packet_analysis::IPTunnel::IPTunnelAnalyzer::Instantiate));
|
||||
zeek::plugin::Configuration Configure() override {
|
||||
AddComponent(
|
||||
new zeek::packet_analysis::Component("IPTunnel",
|
||||
zeek::packet_analysis::IPTunnel::IPTunnelAnalyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::IPTunnel";
|
||||
config.description = "IPTunnel packet analyzer";
|
||||
return config;
|
||||
}
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::IPTunnel";
|
||||
config.description = "IPTunnel packet analyzer";
|
||||
return config;
|
||||
}
|
||||
|
||||
} plugin;
|
||||
} plugin;
|
||||
|
||||
}
|
||||
} // namespace zeek::plugin::Zeek_IPTunnel
|
||||
|
|
|
@ -4,27 +4,25 @@
|
|||
|
||||
using namespace zeek::packet_analysis::LinuxSLL;
|
||||
|
||||
LinuxSLLAnalyzer::LinuxSLLAnalyzer() : zeek::packet_analysis::Analyzer("LinuxSLL") { }
|
||||
LinuxSLLAnalyzer::LinuxSLLAnalyzer() : zeek::packet_analysis::Analyzer("LinuxSLL") {}
|
||||
|
||||
bool LinuxSLLAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet)
|
||||
{
|
||||
auto len_sll_hdr = sizeof(SLLHeader);
|
||||
if ( len_sll_hdr >= len )
|
||||
{
|
||||
Weird("truncated_Linux_SLL_header", packet);
|
||||
return false;
|
||||
}
|
||||
bool LinuxSLLAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) {
|
||||
auto len_sll_hdr = sizeof(SLLHeader);
|
||||
if ( len_sll_hdr >= len ) {
|
||||
Weird("truncated_Linux_SLL_header", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Note: We assume to see an Ethertype and don't consider different ARPHRD_types
|
||||
// (see https://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL.html)
|
||||
auto hdr = (const SLLHeader*)data;
|
||||
// Note: We assume to see an Ethertype and don't consider different ARPHRD_types
|
||||
// (see https://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL.html)
|
||||
auto hdr = (const SLLHeader*)data;
|
||||
|
||||
uint32_t protocol = ntohs(hdr->protocol_type);
|
||||
packet->l2_src = (u_char*)&(hdr->addr);
|
||||
uint32_t protocol = ntohs(hdr->protocol_type);
|
||||
packet->l2_src = (u_char*)&(hdr->addr);
|
||||
|
||||
// SLL doesn't include a destination address in the header, but not setting l2_dst to something
|
||||
// here will cause crashes elsewhere.
|
||||
packet->l2_dst = Packet::L2_EMPTY_ADDR;
|
||||
// SLL doesn't include a destination address in the header, but not setting l2_dst to something
|
||||
// here will cause crashes elsewhere.
|
||||
packet->l2_dst = Packet::L2_EMPTY_ADDR;
|
||||
|
||||
return ForwardPacket(len - len_sll_hdr, data + len_sll_hdr, packet, protocol);
|
||||
}
|
||||
return ForwardPacket(len - len_sll_hdr, data + len_sll_hdr, packet, protocol);
|
||||
}
|
||||
|
|
|
@ -5,32 +5,26 @@
|
|||
#include "zeek/packet_analysis/Analyzer.h"
|
||||
#include "zeek/packet_analysis/Component.h"
|
||||
|
||||
namespace zeek::packet_analysis::LinuxSLL
|
||||
{
|
||||
namespace zeek::packet_analysis::LinuxSLL {
|
||||
|
||||
class LinuxSLLAnalyzer : public Analyzer
|
||||
{
|
||||
class LinuxSLLAnalyzer : public Analyzer {
|
||||
public:
|
||||
LinuxSLLAnalyzer();
|
||||
~LinuxSLLAnalyzer() override = default;
|
||||
LinuxSLLAnalyzer();
|
||||
~LinuxSLLAnalyzer() override = default;
|
||||
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate()
|
||||
{
|
||||
return std::make_shared<LinuxSLLAnalyzer>();
|
||||
}
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate() { return std::make_shared<LinuxSLLAnalyzer>(); }
|
||||
|
||||
private:
|
||||
// Structure layout is based on https://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL.html
|
||||
struct SLLHeader
|
||||
{
|
||||
uint16_t packet_type;
|
||||
uint16_t arphrd_type;
|
||||
uint16_t addr_len;
|
||||
uint64_t addr;
|
||||
uint16_t protocol_type;
|
||||
} __attribute__((__packed__));
|
||||
};
|
||||
// Structure layout is based on https://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL.html
|
||||
struct SLLHeader {
|
||||
uint16_t packet_type;
|
||||
uint16_t arphrd_type;
|
||||
uint16_t addr_len;
|
||||
uint64_t addr;
|
||||
uint16_t protocol_type;
|
||||
} __attribute__((__packed__));
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace zeek::packet_analysis::LinuxSLL
|
||||
|
|
|
@ -5,23 +5,21 @@
|
|||
#include "zeek/packet_analysis/Component.h"
|
||||
#include "zeek/packet_analysis/protocol/linux_sll/LinuxSLL.h"
|
||||
|
||||
namespace zeek::plugin::Zeek_LinuxSLL
|
||||
{
|
||||
namespace zeek::plugin::Zeek_LinuxSLL {
|
||||
|
||||
class Plugin final : public zeek::plugin::Plugin
|
||||
{
|
||||
class Plugin final : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure() override
|
||||
{
|
||||
AddComponent(new zeek::packet_analysis::Component(
|
||||
"LinuxSLL", zeek::packet_analysis::LinuxSLL::LinuxSLLAnalyzer::Instantiate));
|
||||
zeek::plugin::Configuration Configure() override {
|
||||
AddComponent(
|
||||
new zeek::packet_analysis::Component("LinuxSLL",
|
||||
zeek::packet_analysis::LinuxSLL::LinuxSLLAnalyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::LinuxSLL";
|
||||
config.description = "Linux cooked capture (SLL) packet analyzer";
|
||||
return config;
|
||||
}
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::LinuxSLL";
|
||||
config.description = "Linux cooked capture (SLL) packet analyzer";
|
||||
return config;
|
||||
}
|
||||
|
||||
} plugin;
|
||||
} plugin;
|
||||
|
||||
}
|
||||
} // namespace zeek::plugin::Zeek_LinuxSLL
|
||||
|
|
|
@ -4,27 +4,25 @@
|
|||
|
||||
using namespace zeek::packet_analysis::LinuxSLL2;
|
||||
|
||||
LinuxSLL2Analyzer::LinuxSLL2Analyzer() : zeek::packet_analysis::Analyzer("LinuxSLL2") { }
|
||||
LinuxSLL2Analyzer::LinuxSLL2Analyzer() : zeek::packet_analysis::Analyzer("LinuxSLL2") {}
|
||||
|
||||
bool LinuxSLL2Analyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet)
|
||||
{
|
||||
auto len_sll2_hdr = sizeof(SLL2Header);
|
||||
if ( len_sll2_hdr >= len )
|
||||
{
|
||||
Weird("truncated_Linux_SLL2_header", packet);
|
||||
return false;
|
||||
}
|
||||
bool LinuxSLL2Analyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) {
|
||||
auto len_sll2_hdr = sizeof(SLL2Header);
|
||||
if ( len_sll2_hdr >= len ) {
|
||||
Weird("truncated_Linux_SLL2_header", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Note: We assume to see an Ethertype and don't consider different ARPHRD_types
|
||||
// (see https://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL2.html)
|
||||
auto hdr = (const SLL2Header*)data;
|
||||
// Note: We assume to see an Ethertype and don't consider different ARPHRD_types
|
||||
// (see https://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL2.html)
|
||||
auto hdr = (const SLL2Header*)data;
|
||||
|
||||
uint32_t protocol = ntohs(hdr->protocol_type);
|
||||
packet->l2_src = (u_char*)&(hdr->addr);
|
||||
uint32_t protocol = ntohs(hdr->protocol_type);
|
||||
packet->l2_src = (u_char*)&(hdr->addr);
|
||||
|
||||
// SLL doesn't include a destination address in the header, but not setting l2_dst to something
|
||||
// here will cause crashes elsewhere.
|
||||
packet->l2_dst = Packet::L2_EMPTY_ADDR;
|
||||
// SLL doesn't include a destination address in the header, but not setting l2_dst to something
|
||||
// here will cause crashes elsewhere.
|
||||
packet->l2_dst = Packet::L2_EMPTY_ADDR;
|
||||
|
||||
return ForwardPacket(len - len_sll2_hdr, data + len_sll2_hdr, packet, protocol);
|
||||
}
|
||||
return ForwardPacket(len - len_sll2_hdr, data + len_sll2_hdr, packet, protocol);
|
||||
}
|
||||
|
|
|
@ -5,34 +5,28 @@
|
|||
#include "zeek/packet_analysis/Analyzer.h"
|
||||
#include "zeek/packet_analysis/Component.h"
|
||||
|
||||
namespace zeek::packet_analysis::LinuxSLL2
|
||||
{
|
||||
namespace zeek::packet_analysis::LinuxSLL2 {
|
||||
|
||||
class LinuxSLL2Analyzer : public Analyzer
|
||||
{
|
||||
class LinuxSLL2Analyzer : public Analyzer {
|
||||
public:
|
||||
LinuxSLL2Analyzer();
|
||||
~LinuxSLL2Analyzer() override = default;
|
||||
LinuxSLL2Analyzer();
|
||||
~LinuxSLL2Analyzer() override = default;
|
||||
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate()
|
||||
{
|
||||
return std::make_shared<LinuxSLL2Analyzer>();
|
||||
}
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate() { return std::make_shared<LinuxSLL2Analyzer>(); }
|
||||
|
||||
private:
|
||||
// Structure layout is based on https://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL2.html
|
||||
struct SLL2Header
|
||||
{
|
||||
uint16_t protocol_type;
|
||||
uint16_t reserved;
|
||||
uint32_t interface_index;
|
||||
uint16_t arphrd_type;
|
||||
uint8_t packet_type;
|
||||
uint8_t addr_len;
|
||||
uint64_t addr;
|
||||
} __attribute__((__packed__));
|
||||
};
|
||||
// Structure layout is based on https://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL2.html
|
||||
struct SLL2Header {
|
||||
uint16_t protocol_type;
|
||||
uint16_t reserved;
|
||||
uint32_t interface_index;
|
||||
uint16_t arphrd_type;
|
||||
uint8_t packet_type;
|
||||
uint8_t addr_len;
|
||||
uint64_t addr;
|
||||
} __attribute__((__packed__));
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace zeek::packet_analysis::LinuxSLL2
|
||||
|
|
|
@ -5,23 +5,21 @@
|
|||
#include "zeek/packet_analysis/Component.h"
|
||||
#include "zeek/packet_analysis/protocol/linux_sll2/LinuxSLL2.h"
|
||||
|
||||
namespace zeek::plugin::Zeek_LinuxSLL2
|
||||
{
|
||||
namespace zeek::plugin::Zeek_LinuxSLL2 {
|
||||
|
||||
class Plugin final : public zeek::plugin::Plugin
|
||||
{
|
||||
class Plugin final : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure() override
|
||||
{
|
||||
AddComponent(new zeek::packet_analysis::Component(
|
||||
"LinuxSLL2", zeek::packet_analysis::LinuxSLL2::LinuxSLL2Analyzer::Instantiate));
|
||||
zeek::plugin::Configuration Configure() override {
|
||||
AddComponent(
|
||||
new zeek::packet_analysis::Component("LinuxSLL2",
|
||||
zeek::packet_analysis::LinuxSLL2::LinuxSLL2Analyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::LinuxSLL2";
|
||||
config.description = "Linux cooked capture version 2 (SLL2) packet analyzer";
|
||||
return config;
|
||||
}
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::LinuxSLL2";
|
||||
config.description = "Linux cooked capture version 2 (SLL2) packet analyzer";
|
||||
return config;
|
||||
}
|
||||
|
||||
} plugin;
|
||||
} plugin;
|
||||
|
||||
}
|
||||
} // namespace zeek::plugin::Zeek_LinuxSLL2
|
||||
|
|
|
@ -4,31 +4,28 @@
|
|||
|
||||
using namespace zeek::packet_analysis::LLC;
|
||||
|
||||
LLCAnalyzer::LLCAnalyzer() : zeek::packet_analysis::Analyzer("LLC") { }
|
||||
LLCAnalyzer::LLCAnalyzer() : zeek::packet_analysis::Analyzer("LLC") {}
|
||||
|
||||
bool LLCAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet)
|
||||
{
|
||||
// An LLC header is at least 3 bytes, check for that first.
|
||||
if ( len < 3 )
|
||||
{
|
||||
Weird("truncated_llc_header", packet);
|
||||
return false;
|
||||
}
|
||||
bool LLCAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) {
|
||||
// An LLC header is at least 3 bytes, check for that first.
|
||||
if ( len < 3 ) {
|
||||
Weird("truncated_llc_header", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the control field doesn't have an unnumbered PDU, the header is actually 4
|
||||
// bytes long. Whether this is unnumbered is denoted by the last two bits being
|
||||
// set.
|
||||
size_t llc_header_len = 3;
|
||||
if ( (data[2] & 0x03) != 0x03 )
|
||||
llc_header_len++;
|
||||
// If the control field doesn't have an unnumbered PDU, the header is actually 4
|
||||
// bytes long. Whether this is unnumbered is denoted by the last two bits being
|
||||
// set.
|
||||
size_t llc_header_len = 3;
|
||||
if ( (data[2] & 0x03) != 0x03 )
|
||||
llc_header_len++;
|
||||
|
||||
if ( len < llc_header_len )
|
||||
{
|
||||
Weird("truncated_llc_header", packet);
|
||||
return false;
|
||||
}
|
||||
if ( len < llc_header_len ) {
|
||||
Weird("truncated_llc_header", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
// The destination SAP should be the next protocol in the chain, so forward
|
||||
// based on that value. The DSAP is the first byte in header.
|
||||
return ForwardPacket(len, data, packet, data[0]);
|
||||
}
|
||||
// The destination SAP should be the next protocol in the chain, so forward
|
||||
// based on that value. The DSAP is the first byte in header.
|
||||
return ForwardPacket(len, data, packet, data[0]);
|
||||
}
|
||||
|
|
|
@ -5,21 +5,16 @@
|
|||
#include "zeek/packet_analysis/Analyzer.h"
|
||||
#include "zeek/packet_analysis/Component.h"
|
||||
|
||||
namespace zeek::packet_analysis::LLC
|
||||
{
|
||||
namespace zeek::packet_analysis::LLC {
|
||||
|
||||
class LLCAnalyzer : public Analyzer
|
||||
{
|
||||
class LLCAnalyzer : public Analyzer {
|
||||
public:
|
||||
LLCAnalyzer();
|
||||
~LLCAnalyzer() override = default;
|
||||
LLCAnalyzer();
|
||||
~LLCAnalyzer() override = default;
|
||||
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate()
|
||||
{
|
||||
return std::make_shared<LLCAnalyzer>();
|
||||
}
|
||||
};
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate() { return std::make_shared<LLCAnalyzer>(); }
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace zeek::packet_analysis::LLC
|
||||
|
|
|
@ -5,23 +5,19 @@
|
|||
#include "zeek/packet_analysis/Component.h"
|
||||
#include "zeek/packet_analysis/protocol/llc/LLC.h"
|
||||
|
||||
namespace zeek::plugin::Zeek_LLC
|
||||
{
|
||||
namespace zeek::plugin::Zeek_LLC {
|
||||
|
||||
class Plugin final : public zeek::plugin::Plugin
|
||||
{
|
||||
class Plugin final : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure() override
|
||||
{
|
||||
AddComponent(new zeek::packet_analysis::Component(
|
||||
"LLC", zeek::packet_analysis::LLC::LLCAnalyzer::Instantiate));
|
||||
zeek::plugin::Configuration Configure() override {
|
||||
AddComponent(new zeek::packet_analysis::Component("LLC", zeek::packet_analysis::LLC::LLCAnalyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::LLC";
|
||||
config.description = "LLC packet analyzer";
|
||||
return config;
|
||||
}
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::LLC";
|
||||
config.description = "LLC packet analyzer";
|
||||
return config;
|
||||
}
|
||||
|
||||
} plugin;
|
||||
} plugin;
|
||||
|
||||
}
|
||||
} // namespace zeek::plugin::Zeek_LLC
|
||||
|
|
|
@ -4,27 +4,24 @@
|
|||
|
||||
using namespace zeek::packet_analysis::MPLS;
|
||||
|
||||
MPLSAnalyzer::MPLSAnalyzer() : zeek::packet_analysis::Analyzer("MPLS") { }
|
||||
MPLSAnalyzer::MPLSAnalyzer() : zeek::packet_analysis::Analyzer("MPLS") {}
|
||||
|
||||
bool MPLSAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet)
|
||||
{
|
||||
// Skip the MPLS label stack.
|
||||
bool end_of_stack = false;
|
||||
bool MPLSAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) {
|
||||
// Skip the MPLS label stack.
|
||||
bool end_of_stack = false;
|
||||
|
||||
while ( ! end_of_stack )
|
||||
{
|
||||
if ( 4 >= len )
|
||||
{
|
||||
Weird("truncated_link_header", packet);
|
||||
return false;
|
||||
}
|
||||
while ( ! end_of_stack ) {
|
||||
if ( 4 >= len ) {
|
||||
Weird("truncated_link_header", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
end_of_stack = *(data + 2u) & 0x01;
|
||||
data += 4;
|
||||
len -= 4;
|
||||
}
|
||||
end_of_stack = *(data + 2u) & 0x01;
|
||||
data += 4;
|
||||
len -= 4;
|
||||
}
|
||||
|
||||
// According to RFC3032 the encapsulated protocol is not encoded.
|
||||
// We use the configured default analyzer.
|
||||
return ForwardPacket(len, data, packet);
|
||||
}
|
||||
// According to RFC3032 the encapsulated protocol is not encoded.
|
||||
// We use the configured default analyzer.
|
||||
return ForwardPacket(len, data, packet);
|
||||
}
|
||||
|
|
|
@ -5,21 +5,16 @@
|
|||
#include "zeek/packet_analysis/Analyzer.h"
|
||||
#include "zeek/packet_analysis/Component.h"
|
||||
|
||||
namespace zeek::packet_analysis::MPLS
|
||||
{
|
||||
namespace zeek::packet_analysis::MPLS {
|
||||
|
||||
class MPLSAnalyzer : public zeek::packet_analysis::Analyzer
|
||||
{
|
||||
class MPLSAnalyzer : public zeek::packet_analysis::Analyzer {
|
||||
public:
|
||||
MPLSAnalyzer();
|
||||
~MPLSAnalyzer() override = default;
|
||||
MPLSAnalyzer();
|
||||
~MPLSAnalyzer() override = default;
|
||||
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate()
|
||||
{
|
||||
return std::make_shared<MPLSAnalyzer>();
|
||||
}
|
||||
};
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate() { return std::make_shared<MPLSAnalyzer>(); }
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace zeek::packet_analysis::MPLS
|
||||
|
|
|
@ -5,23 +5,20 @@
|
|||
#include "zeek/packet_analysis/Component.h"
|
||||
#include "zeek/packet_analysis/protocol/mpls/MPLS.h"
|
||||
|
||||
namespace zeek::plugin::Zeek_MPLS
|
||||
{
|
||||
namespace zeek::plugin::Zeek_MPLS {
|
||||
|
||||
class Plugin final : public zeek::plugin::Plugin
|
||||
{
|
||||
class Plugin final : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure() override
|
||||
{
|
||||
AddComponent(new zeek::packet_analysis::Component(
|
||||
"MPLS", zeek::packet_analysis::MPLS::MPLSAnalyzer::Instantiate));
|
||||
zeek::plugin::Configuration Configure() override {
|
||||
AddComponent(
|
||||
new zeek::packet_analysis::Component("MPLS", zeek::packet_analysis::MPLS::MPLSAnalyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::MPLS";
|
||||
config.description = "MPLS packet analyzer";
|
||||
return config;
|
||||
}
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::MPLS";
|
||||
config.description = "MPLS packet analyzer";
|
||||
return config;
|
||||
}
|
||||
|
||||
} plugin;
|
||||
} plugin;
|
||||
|
||||
}
|
||||
} // namespace zeek::plugin::Zeek_MPLS
|
||||
|
|
|
@ -4,80 +4,71 @@
|
|||
|
||||
using namespace zeek::packet_analysis::NFLog;
|
||||
|
||||
NFLogAnalyzer::NFLogAnalyzer() : zeek::packet_analysis::Analyzer("NFLog") { }
|
||||
NFLogAnalyzer::NFLogAnalyzer() : zeek::packet_analysis::Analyzer("NFLog") {}
|
||||
|
||||
bool NFLogAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet)
|
||||
{
|
||||
if ( 4 >= len )
|
||||
{
|
||||
Weird("truncated_nflog_header", packet);
|
||||
return false;
|
||||
}
|
||||
bool NFLogAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) {
|
||||
if ( 4 >= len ) {
|
||||
Weird("truncated_nflog_header", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
// See https://www.tcpdump.org/linktypes/LINKTYPE_NFLOG.html
|
||||
uint32_t protocol = data[0];
|
||||
uint8_t version = data[1];
|
||||
// See https://www.tcpdump.org/linktypes/LINKTYPE_NFLOG.html
|
||||
uint32_t protocol = data[0];
|
||||
uint8_t version = data[1];
|
||||
|
||||
if ( version != 0 )
|
||||
{
|
||||
Weird("unknown_nflog_version", packet);
|
||||
return false;
|
||||
}
|
||||
if ( version != 0 ) {
|
||||
Weird("unknown_nflog_version", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip to TLVs.
|
||||
data += 4;
|
||||
len -= 4;
|
||||
// Skip to TLVs.
|
||||
data += 4;
|
||||
len -= 4;
|
||||
|
||||
uint16_t tlv_len;
|
||||
uint16_t tlv_type;
|
||||
uint16_t tlv_len;
|
||||
uint16_t tlv_type;
|
||||
|
||||
while ( true )
|
||||
{
|
||||
if ( 4 >= len )
|
||||
{
|
||||
Weird("nflog_no_pcap_payload", packet);
|
||||
return false;
|
||||
}
|
||||
while ( true ) {
|
||||
if ( 4 >= len ) {
|
||||
Weird("nflog_no_pcap_payload", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
// TLV Type and Length values are specified in host byte order
|
||||
// (libpcap should have done any needed byteswapping already).
|
||||
// TLV Type and Length values are specified in host byte order
|
||||
// (libpcap should have done any needed byteswapping already).
|
||||
|
||||
tlv_len = *(reinterpret_cast<const uint16_t*>(data));
|
||||
tlv_type = *(reinterpret_cast<const uint16_t*>(data + 2));
|
||||
tlv_len = *(reinterpret_cast<const uint16_t*>(data));
|
||||
tlv_type = *(reinterpret_cast<const uint16_t*>(data + 2));
|
||||
|
||||
auto constexpr nflog_type_payload = 9;
|
||||
auto constexpr nflog_type_payload = 9;
|
||||
|
||||
if ( tlv_type == nflog_type_payload )
|
||||
{
|
||||
// The raw packet payload follows this TLV.
|
||||
data += 4;
|
||||
len -= 4;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The Length value includes the 4 octets for the Type and
|
||||
// Length values, but TLVs are also implicitly padded to
|
||||
// 32-bit alignments (that padding may not be included in
|
||||
// the Length value).
|
||||
if ( tlv_type == nflog_type_payload ) {
|
||||
// The raw packet payload follows this TLV.
|
||||
data += 4;
|
||||
len -= 4;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
// The Length value includes the 4 octets for the Type and
|
||||
// Length values, but TLVs are also implicitly padded to
|
||||
// 32-bit alignments (that padding may not be included in
|
||||
// the Length value).
|
||||
|
||||
if ( tlv_len < 4 )
|
||||
{
|
||||
Weird("nflog_bad_tlv_len", packet);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto rem = tlv_len % 4;
|
||||
if ( tlv_len < 4 ) {
|
||||
Weird("nflog_bad_tlv_len", packet);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
auto rem = tlv_len % 4;
|
||||
|
||||
if ( rem != 0 )
|
||||
tlv_len += 4 - rem;
|
||||
}
|
||||
if ( rem != 0 )
|
||||
tlv_len += 4 - rem;
|
||||
}
|
||||
|
||||
data += tlv_len;
|
||||
len -= tlv_len;
|
||||
}
|
||||
}
|
||||
data += tlv_len;
|
||||
len -= tlv_len;
|
||||
}
|
||||
}
|
||||
|
||||
return ForwardPacket(len, data, packet, protocol);
|
||||
}
|
||||
return ForwardPacket(len, data, packet, protocol);
|
||||
}
|
||||
|
|
|
@ -5,18 +5,16 @@
|
|||
#include "zeek/packet_analysis/Analyzer.h"
|
||||
#include "zeek/packet_analysis/Component.h"
|
||||
|
||||
namespace zeek::packet_analysis::NFLog
|
||||
{
|
||||
namespace zeek::packet_analysis::NFLog {
|
||||
|
||||
class NFLogAnalyzer : public Analyzer
|
||||
{
|
||||
class NFLogAnalyzer : public Analyzer {
|
||||
public:
|
||||
NFLogAnalyzer();
|
||||
~NFLogAnalyzer() override = default;
|
||||
NFLogAnalyzer();
|
||||
~NFLogAnalyzer() override = default;
|
||||
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
|
||||
static AnalyzerPtr Instantiate() { return std::make_shared<NFLogAnalyzer>(); }
|
||||
};
|
||||
static AnalyzerPtr Instantiate() { return std::make_shared<NFLogAnalyzer>(); }
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace zeek::packet_analysis::NFLog
|
||||
|
|
|
@ -5,22 +5,19 @@
|
|||
#include "zeek/packet_analysis/Component.h"
|
||||
#include "zeek/packet_analysis/protocol/nflog/NFLog.h"
|
||||
|
||||
namespace zeek::plugin::Zeek_NFLog
|
||||
{
|
||||
namespace zeek::plugin::Zeek_NFLog {
|
||||
|
||||
class Plugin final : public zeek::plugin::Plugin
|
||||
{
|
||||
class Plugin final : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure() override
|
||||
{
|
||||
AddComponent(new zeek::packet_analysis::Component(
|
||||
"NFLog", zeek::packet_analysis::NFLog::NFLogAnalyzer::Instantiate));
|
||||
zeek::plugin::Configuration Configure() override {
|
||||
AddComponent(
|
||||
new zeek::packet_analysis::Component("NFLog", zeek::packet_analysis::NFLog::NFLogAnalyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::NFLog";
|
||||
config.description = "NFLog packet analyzer";
|
||||
return config;
|
||||
}
|
||||
} plugin;
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::NFLog";
|
||||
config.description = "NFLog packet analyzer";
|
||||
return config;
|
||||
}
|
||||
} plugin;
|
||||
|
||||
}
|
||||
} // namespace zeek::plugin::Zeek_NFLog
|
||||
|
|
|
@ -4,11 +4,10 @@
|
|||
|
||||
using namespace zeek::packet_analysis::Novell_802_3;
|
||||
|
||||
Novell_802_3Analyzer::Novell_802_3Analyzer() : zeek::packet_analysis::Analyzer("Novell_802_3") { }
|
||||
Novell_802_3Analyzer::Novell_802_3Analyzer() : zeek::packet_analysis::Analyzer("Novell_802_3") {}
|
||||
|
||||
bool Novell_802_3Analyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet)
|
||||
{
|
||||
// Attempt to forward into the default analyzer, if one exists. This should be an IPX analyzer,
|
||||
// but one doesn't exist yet.
|
||||
return ForwardPacket(len, data, packet);
|
||||
}
|
||||
bool Novell_802_3Analyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) {
|
||||
// Attempt to forward into the default analyzer, if one exists. This should be an IPX analyzer,
|
||||
// but one doesn't exist yet.
|
||||
return ForwardPacket(len, data, packet);
|
||||
}
|
||||
|
|
|
@ -5,21 +5,16 @@
|
|||
#include "zeek/packet_analysis/Analyzer.h"
|
||||
#include "zeek/packet_analysis/Component.h"
|
||||
|
||||
namespace zeek::packet_analysis::Novell_802_3
|
||||
{
|
||||
namespace zeek::packet_analysis::Novell_802_3 {
|
||||
|
||||
class Novell_802_3Analyzer : public Analyzer
|
||||
{
|
||||
class Novell_802_3Analyzer : public Analyzer {
|
||||
public:
|
||||
Novell_802_3Analyzer();
|
||||
~Novell_802_3Analyzer() override = default;
|
||||
Novell_802_3Analyzer();
|
||||
~Novell_802_3Analyzer() override = default;
|
||||
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate()
|
||||
{
|
||||
return std::make_shared<Novell_802_3Analyzer>();
|
||||
}
|
||||
};
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate() { return std::make_shared<Novell_802_3Analyzer>(); }
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace zeek::packet_analysis::Novell_802_3
|
||||
|
|
|
@ -5,24 +5,20 @@
|
|||
#include "zeek/packet_analysis/Component.h"
|
||||
#include "zeek/packet_analysis/protocol/novell_802_3/Novell_802_3.h"
|
||||
|
||||
namespace zeek::plugin::Zeek_Novell_802_3
|
||||
{
|
||||
namespace zeek::plugin::Zeek_Novell_802_3 {
|
||||
|
||||
class Plugin final : public zeek::plugin::Plugin
|
||||
{
|
||||
class Plugin final : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure() override
|
||||
{
|
||||
AddComponent(new zeek::packet_analysis::Component(
|
||||
"NOVELL_802_3",
|
||||
zeek::packet_analysis::Novell_802_3::Novell_802_3Analyzer::Instantiate));
|
||||
zeek::plugin::Configuration Configure() override {
|
||||
AddComponent(new zeek::packet_analysis::Component("NOVELL_802_3", zeek::packet_analysis::Novell_802_3::
|
||||
Novell_802_3Analyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::NOVELL_802_3";
|
||||
config.description = "Novell 802.3 variantx packet analyzer";
|
||||
return config;
|
||||
}
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::NOVELL_802_3";
|
||||
config.description = "Novell 802.3 variantx packet analyzer";
|
||||
return config;
|
||||
}
|
||||
|
||||
} plugin;
|
||||
} plugin;
|
||||
|
||||
}
|
||||
} // namespace zeek::plugin::Zeek_Novell_802_3
|
||||
|
|
|
@ -4,17 +4,15 @@
|
|||
|
||||
using namespace zeek::packet_analysis::Null;
|
||||
|
||||
NullAnalyzer::NullAnalyzer() : zeek::packet_analysis::Analyzer("Null") { }
|
||||
NullAnalyzer::NullAnalyzer() : zeek::packet_analysis::Analyzer("Null") {}
|
||||
|
||||
bool NullAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet)
|
||||
{
|
||||
if ( 4 >= len )
|
||||
{
|
||||
Weird("null_analyzer_failed", packet);
|
||||
return false;
|
||||
}
|
||||
bool NullAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) {
|
||||
if ( 4 >= len ) {
|
||||
Weird("null_analyzer_failed", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t protocol = (data[3] << 24) + (data[2] << 16) + (data[1] << 8) + data[0];
|
||||
// skip link header
|
||||
return ForwardPacket(len - 4, data + 4, packet, protocol);
|
||||
}
|
||||
uint32_t protocol = (data[3] << 24) + (data[2] << 16) + (data[1] << 8) + data[0];
|
||||
// skip link header
|
||||
return ForwardPacket(len - 4, data + 4, packet, protocol);
|
||||
}
|
||||
|
|
|
@ -5,21 +5,16 @@
|
|||
#include "zeek/packet_analysis/Analyzer.h"
|
||||
#include "zeek/packet_analysis/Component.h"
|
||||
|
||||
namespace zeek::packet_analysis::Null
|
||||
{
|
||||
namespace zeek::packet_analysis::Null {
|
||||
|
||||
class NullAnalyzer : public Analyzer
|
||||
{
|
||||
class NullAnalyzer : public Analyzer {
|
||||
public:
|
||||
NullAnalyzer();
|
||||
~NullAnalyzer() override = default;
|
||||
NullAnalyzer();
|
||||
~NullAnalyzer() override = default;
|
||||
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate()
|
||||
{
|
||||
return std::make_shared<NullAnalyzer>();
|
||||
}
|
||||
};
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate() { return std::make_shared<NullAnalyzer>(); }
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace zeek::packet_analysis::Null
|
||||
|
|
|
@ -5,23 +5,20 @@
|
|||
#include "zeek/packet_analysis/Component.h"
|
||||
#include "zeek/packet_analysis/protocol/null/Null.h"
|
||||
|
||||
namespace zeek::plugin::Zeek_Null
|
||||
{
|
||||
namespace zeek::plugin::Zeek_Null {
|
||||
|
||||
class Plugin final : public zeek::plugin::Plugin
|
||||
{
|
||||
class Plugin final : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure() override
|
||||
{
|
||||
AddComponent(new zeek::packet_analysis::Component(
|
||||
"Null", zeek::packet_analysis::Null::NullAnalyzer::Instantiate));
|
||||
zeek::plugin::Configuration Configure() override {
|
||||
AddComponent(
|
||||
new zeek::packet_analysis::Component("Null", zeek::packet_analysis::Null::NullAnalyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::Null";
|
||||
config.description = "Null packet analyzer";
|
||||
return config;
|
||||
}
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::Null";
|
||||
config.description = "Null packet analyzer";
|
||||
return config;
|
||||
}
|
||||
|
||||
} plugin;
|
||||
} plugin;
|
||||
|
||||
}
|
||||
} // namespace zeek::plugin::Zeek_Null
|
||||
|
|
|
@ -7,16 +7,14 @@ using namespace zeek::packet_analysis::PBB;
|
|||
constexpr int PBB_LEN = 18;
|
||||
constexpr int PBB_C_DST_OFF = 4;
|
||||
|
||||
PBBAnalyzer::PBBAnalyzer() : zeek::packet_analysis::Analyzer("PBB") { }
|
||||
PBBAnalyzer::PBBAnalyzer() : zeek::packet_analysis::Analyzer("PBB") {}
|
||||
|
||||
bool PBBAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet)
|
||||
{
|
||||
if ( PBB_LEN >= len )
|
||||
{
|
||||
Weird("truncated_PBB_header", packet);
|
||||
return false;
|
||||
}
|
||||
bool PBBAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) {
|
||||
if ( PBB_LEN >= len ) {
|
||||
Weird("truncated_PBB_header", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
// pass this on to the ethernet analyzer
|
||||
return ForwardPacket(len - PBB_C_DST_OFF, data + PBB_C_DST_OFF, packet);
|
||||
}
|
||||
// pass this on to the ethernet analyzer
|
||||
return ForwardPacket(len - PBB_C_DST_OFF, data + PBB_C_DST_OFF, packet);
|
||||
}
|
||||
|
|
|
@ -5,21 +5,16 @@
|
|||
#include "zeek/packet_analysis/Analyzer.h"
|
||||
#include "zeek/packet_analysis/Component.h"
|
||||
|
||||
namespace zeek::packet_analysis::PBB
|
||||
{
|
||||
namespace zeek::packet_analysis::PBB {
|
||||
|
||||
class PBBAnalyzer : public Analyzer
|
||||
{
|
||||
class PBBAnalyzer : public Analyzer {
|
||||
public:
|
||||
PBBAnalyzer();
|
||||
~PBBAnalyzer() override = default;
|
||||
PBBAnalyzer();
|
||||
~PBBAnalyzer() override = default;
|
||||
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate()
|
||||
{
|
||||
return std::make_shared<PBBAnalyzer>();
|
||||
}
|
||||
};
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate() { return std::make_shared<PBBAnalyzer>(); }
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace zeek::packet_analysis::PBB
|
||||
|
|
|
@ -5,23 +5,19 @@
|
|||
#include "zeek/packet_analysis/Component.h"
|
||||
#include "zeek/packet_analysis/protocol/pbb/PBB.h"
|
||||
|
||||
namespace zeek::plugin::Zeek_PBB
|
||||
{
|
||||
namespace zeek::plugin::Zeek_PBB {
|
||||
|
||||
class Plugin final : public zeek::plugin::Plugin
|
||||
{
|
||||
class Plugin final : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure() override
|
||||
{
|
||||
AddComponent(new zeek::packet_analysis::Component(
|
||||
"PBB", zeek::packet_analysis::PBB::PBBAnalyzer::Instantiate));
|
||||
zeek::plugin::Configuration Configure() override {
|
||||
AddComponent(new zeek::packet_analysis::Component("PBB", zeek::packet_analysis::PBB::PBBAnalyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::PBB";
|
||||
config.description = "PBB packet analyzer";
|
||||
return config;
|
||||
}
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::PBB";
|
||||
config.description = "PBB packet analyzer";
|
||||
return config;
|
||||
}
|
||||
|
||||
} plugin;
|
||||
} plugin;
|
||||
|
||||
}
|
||||
} // namespace zeek::plugin::Zeek_PBB
|
||||
|
|
|
@ -4,37 +4,33 @@
|
|||
|
||||
using namespace zeek::packet_analysis::PPP;
|
||||
|
||||
PPPAnalyzer::PPPAnalyzer() : zeek::packet_analysis::Analyzer("PPP") { }
|
||||
PPPAnalyzer::PPPAnalyzer() : zeek::packet_analysis::Analyzer("PPP") {}
|
||||
|
||||
bool PPPAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet)
|
||||
{
|
||||
// Analyzer is meant to handle DLT_PPP.
|
||||
//
|
||||
// From https://www.tcpdump.org/linktypes.html for LINKTYPE_PPP (0x9):
|
||||
//
|
||||
// PPP, as per RFC 1661 and RFC 1662; if the first 2 bytes are 0xff and 0x03,
|
||||
// it's PPP in HDLC-like framing, with the PPP header following those two bytes,
|
||||
// otherwise it's PPP without framing, and the packet begins with the PPP header.
|
||||
// The data in the frame is not octet-stuffed or bit-stuffed.
|
||||
if ( 2 >= len )
|
||||
{
|
||||
Weird("truncated_ppp_header", packet);
|
||||
return false;
|
||||
}
|
||||
bool PPPAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) {
|
||||
// Analyzer is meant to handle DLT_PPP.
|
||||
//
|
||||
// From https://www.tcpdump.org/linktypes.html for LINKTYPE_PPP (0x9):
|
||||
//
|
||||
// PPP, as per RFC 1661 and RFC 1662; if the first 2 bytes are 0xff and 0x03,
|
||||
// it's PPP in HDLC-like framing, with the PPP header following those two bytes,
|
||||
// otherwise it's PPP without framing, and the packet begins with the PPP header.
|
||||
// The data in the frame is not octet-stuffed or bit-stuffed.
|
||||
if ( 2 >= len ) {
|
||||
Weird("truncated_ppp_header", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( data[0] == 0xff && data[1] == 0x03 )
|
||||
{
|
||||
// HDLC-Framing
|
||||
if ( 4 >= len )
|
||||
{
|
||||
Weird("truncated_ppp_hdlc_header", packet);
|
||||
return false;
|
||||
}
|
||||
if ( data[0] == 0xff && data[1] == 0x03 ) {
|
||||
// HDLC-Framing
|
||||
if ( 4 >= len ) {
|
||||
Weird("truncated_ppp_hdlc_header", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t protocol = (data[2] << 8) + data[3];
|
||||
return ForwardPacket(len - 4, data + 4, packet, protocol);
|
||||
}
|
||||
uint32_t protocol = (data[2] << 8) + data[3];
|
||||
return ForwardPacket(len - 4, data + 4, packet, protocol);
|
||||
}
|
||||
|
||||
uint32_t protocol = (data[0] << 8) + data[1];
|
||||
return ForwardPacket(len - 2, data + 2, packet, protocol);
|
||||
}
|
||||
uint32_t protocol = (data[0] << 8) + data[1];
|
||||
return ForwardPacket(len - 2, data + 2, packet, protocol);
|
||||
}
|
||||
|
|
|
@ -5,21 +5,16 @@
|
|||
#include "zeek/packet_analysis/Analyzer.h"
|
||||
#include "zeek/packet_analysis/Component.h"
|
||||
|
||||
namespace zeek::packet_analysis::PPP
|
||||
{
|
||||
namespace zeek::packet_analysis::PPP {
|
||||
|
||||
class PPPAnalyzer : public Analyzer
|
||||
{
|
||||
class PPPAnalyzer : public Analyzer {
|
||||
public:
|
||||
PPPAnalyzer();
|
||||
~PPPAnalyzer() override = default;
|
||||
PPPAnalyzer();
|
||||
~PPPAnalyzer() override = default;
|
||||
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate()
|
||||
{
|
||||
return std::make_shared<PPPAnalyzer>();
|
||||
}
|
||||
};
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate() { return std::make_shared<PPPAnalyzer>(); }
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace zeek::packet_analysis::PPP
|
||||
|
|
|
@ -5,23 +5,19 @@
|
|||
#include "zeek/packet_analysis/Component.h"
|
||||
#include "zeek/packet_analysis/protocol/ppp/PPP.h"
|
||||
|
||||
namespace zeek::plugin::Zeek_PPP
|
||||
{
|
||||
namespace zeek::plugin::Zeek_PPP {
|
||||
|
||||
class Plugin final : public zeek::plugin::Plugin
|
||||
{
|
||||
class Plugin final : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure() override
|
||||
{
|
||||
AddComponent(new zeek::packet_analysis::Component(
|
||||
"PPP", zeek::packet_analysis::PPP::PPPAnalyzer::Instantiate));
|
||||
zeek::plugin::Configuration Configure() override {
|
||||
AddComponent(new zeek::packet_analysis::Component("PPP", zeek::packet_analysis::PPP::PPPAnalyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::PPP";
|
||||
config.description = "PPP packet analyzer";
|
||||
return config;
|
||||
}
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::PPP";
|
||||
config.description = "PPP packet analyzer";
|
||||
return config;
|
||||
}
|
||||
|
||||
} plugin;
|
||||
} plugin;
|
||||
|
||||
}
|
||||
} // namespace zeek::plugin::Zeek_PPP
|
||||
|
|
|
@ -4,18 +4,16 @@
|
|||
|
||||
using namespace zeek::packet_analysis::PPPSerial;
|
||||
|
||||
PPPSerialAnalyzer::PPPSerialAnalyzer() : zeek::packet_analysis::Analyzer("PPPSerial") { }
|
||||
PPPSerialAnalyzer::PPPSerialAnalyzer() : zeek::packet_analysis::Analyzer("PPPSerial") {}
|
||||
|
||||
bool PPPSerialAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet)
|
||||
{
|
||||
if ( 4 >= len )
|
||||
{
|
||||
Weird("truncated_ppp_serial_header", packet);
|
||||
return false;
|
||||
}
|
||||
bool PPPSerialAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) {
|
||||
if ( 4 >= len ) {
|
||||
Weird("truncated_ppp_serial_header", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Extract protocol identifier
|
||||
uint32_t protocol = (data[2] << 8) + data[3];
|
||||
// skip link header
|
||||
return ForwardPacket(len - 4, data + 4, packet, protocol);
|
||||
}
|
||||
// Extract protocol identifier
|
||||
uint32_t protocol = (data[2] << 8) + data[3];
|
||||
// skip link header
|
||||
return ForwardPacket(len - 4, data + 4, packet, protocol);
|
||||
}
|
||||
|
|
|
@ -5,21 +5,16 @@
|
|||
#include "zeek/packet_analysis/Analyzer.h"
|
||||
#include "zeek/packet_analysis/Component.h"
|
||||
|
||||
namespace zeek::packet_analysis::PPPSerial
|
||||
{
|
||||
namespace zeek::packet_analysis::PPPSerial {
|
||||
|
||||
class PPPSerialAnalyzer : public Analyzer
|
||||
{
|
||||
class PPPSerialAnalyzer : public Analyzer {
|
||||
public:
|
||||
PPPSerialAnalyzer();
|
||||
~PPPSerialAnalyzer() override = default;
|
||||
PPPSerialAnalyzer();
|
||||
~PPPSerialAnalyzer() override = default;
|
||||
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate()
|
||||
{
|
||||
return std::make_shared<PPPSerialAnalyzer>();
|
||||
}
|
||||
};
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate() { return std::make_shared<PPPSerialAnalyzer>(); }
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace zeek::packet_analysis::PPPSerial
|
||||
|
|
|
@ -5,23 +5,21 @@
|
|||
#include "zeek/packet_analysis/Component.h"
|
||||
#include "zeek/packet_analysis/protocol/ppp_serial/PPPSerial.h"
|
||||
|
||||
namespace zeek::plugin::Zeek_PPPSerial
|
||||
{
|
||||
namespace zeek::plugin::Zeek_PPPSerial {
|
||||
|
||||
class Plugin final : public zeek::plugin::Plugin
|
||||
{
|
||||
class Plugin final : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure() override
|
||||
{
|
||||
AddComponent(new zeek::packet_analysis::Component(
|
||||
"PPPSerial", zeek::packet_analysis::PPPSerial::PPPSerialAnalyzer::Instantiate));
|
||||
zeek::plugin::Configuration Configure() override {
|
||||
AddComponent(
|
||||
new zeek::packet_analysis::Component("PPPSerial",
|
||||
zeek::packet_analysis::PPPSerial::PPPSerialAnalyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::PPPSerial";
|
||||
config.description = "PPPSerial packet analyzer";
|
||||
return config;
|
||||
}
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::PPPSerial";
|
||||
config.description = "PPPSerial packet analyzer";
|
||||
return config;
|
||||
}
|
||||
|
||||
} plugin;
|
||||
} plugin;
|
||||
|
||||
}
|
||||
} // namespace zeek::plugin::Zeek_PPPSerial
|
||||
|
|
|
@ -4,18 +4,16 @@
|
|||
|
||||
using namespace zeek::packet_analysis::PPPoE;
|
||||
|
||||
PPPoEAnalyzer::PPPoEAnalyzer() : zeek::packet_analysis::Analyzer("PPPoE") { }
|
||||
PPPoEAnalyzer::PPPoEAnalyzer() : zeek::packet_analysis::Analyzer("PPPoE") {}
|
||||
|
||||
bool PPPoEAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet)
|
||||
{
|
||||
if ( 8 >= len )
|
||||
{
|
||||
Weird("truncated_pppoe_header", packet);
|
||||
return false;
|
||||
}
|
||||
bool PPPoEAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) {
|
||||
if ( 8 >= len ) {
|
||||
Weird("truncated_pppoe_header", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Extract protocol identifier
|
||||
uint32_t protocol = (data[6] << 8u) + data[7];
|
||||
// Skip the PPPoE session and PPP header
|
||||
return ForwardPacket(len - 8, data + 8, packet, protocol);
|
||||
}
|
||||
// Extract protocol identifier
|
||||
uint32_t protocol = (data[6] << 8u) + data[7];
|
||||
// Skip the PPPoE session and PPP header
|
||||
return ForwardPacket(len - 8, data + 8, packet, protocol);
|
||||
}
|
||||
|
|
|
@ -5,21 +5,16 @@
|
|||
#include "zeek/packet_analysis/Analyzer.h"
|
||||
#include "zeek/packet_analysis/Component.h"
|
||||
|
||||
namespace zeek::packet_analysis::PPPoE
|
||||
{
|
||||
namespace zeek::packet_analysis::PPPoE {
|
||||
|
||||
class PPPoEAnalyzer : public Analyzer
|
||||
{
|
||||
class PPPoEAnalyzer : public Analyzer {
|
||||
public:
|
||||
PPPoEAnalyzer();
|
||||
~PPPoEAnalyzer() override = default;
|
||||
PPPoEAnalyzer();
|
||||
~PPPoEAnalyzer() override = default;
|
||||
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate()
|
||||
{
|
||||
return std::make_shared<PPPoEAnalyzer>();
|
||||
}
|
||||
};
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate() { return std::make_shared<PPPoEAnalyzer>(); }
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace zeek::packet_analysis::PPPoE
|
||||
|
|
|
@ -5,23 +5,20 @@
|
|||
#include "zeek/packet_analysis/Component.h"
|
||||
#include "zeek/packet_analysis/protocol/pppoe/PPPoE.h"
|
||||
|
||||
namespace zeek::plugin::Zeek_PPPoE
|
||||
{
|
||||
namespace zeek::plugin::Zeek_PPPoE {
|
||||
|
||||
class Plugin final : public zeek::plugin::Plugin
|
||||
{
|
||||
class Plugin final : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure() override
|
||||
{
|
||||
AddComponent(new zeek::packet_analysis::Component(
|
||||
"PPPoE", zeek::packet_analysis::PPPoE::PPPoEAnalyzer::Instantiate));
|
||||
zeek::plugin::Configuration Configure() override {
|
||||
AddComponent(
|
||||
new zeek::packet_analysis::Component("PPPoE", zeek::packet_analysis::PPPoE::PPPoEAnalyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::PPPoE";
|
||||
config.description = "PPPoE packet analyzer";
|
||||
return config;
|
||||
}
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::PPPoE";
|
||||
config.description = "PPPoE packet analyzer";
|
||||
return config;
|
||||
}
|
||||
|
||||
} plugin;
|
||||
} plugin;
|
||||
|
||||
}
|
||||
} // namespace zeek::plugin::Zeek_PPPoE
|
||||
|
|
|
@ -5,23 +5,20 @@
|
|||
#include "zeek/packet_analysis/Component.h"
|
||||
#include "zeek/packet_analysis/protocol/root/Root.h"
|
||||
|
||||
namespace zeek::plugin::Zeek_Root
|
||||
{
|
||||
namespace zeek::plugin::Zeek_Root {
|
||||
|
||||
class Plugin final : public zeek::plugin::Plugin
|
||||
{
|
||||
class Plugin final : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure() override
|
||||
{
|
||||
AddComponent(new zeek::packet_analysis::Component(
|
||||
"Root", zeek::packet_analysis::Root::RootAnalyzer::Instantiate));
|
||||
zeek::plugin::Configuration Configure() override {
|
||||
AddComponent(
|
||||
new zeek::packet_analysis::Component("Root", zeek::packet_analysis::Root::RootAnalyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::Root";
|
||||
config.description = "Root packet analyzer";
|
||||
return config;
|
||||
}
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::Root";
|
||||
config.description = "Root packet analyzer";
|
||||
return config;
|
||||
}
|
||||
|
||||
} plugin;
|
||||
} plugin;
|
||||
|
||||
}
|
||||
} // namespace zeek::plugin::Zeek_Root
|
||||
|
|
|
@ -4,9 +4,8 @@
|
|||
|
||||
using namespace zeek::packet_analysis::Root;
|
||||
|
||||
RootAnalyzer::RootAnalyzer() : zeek::packet_analysis::Analyzer("Root") { }
|
||||
RootAnalyzer::RootAnalyzer() : zeek::packet_analysis::Analyzer("Root") {}
|
||||
|
||||
bool RootAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet)
|
||||
{
|
||||
reporter->InternalError("AnalyzePacket() was called for the root analyzer.");
|
||||
}
|
||||
bool RootAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) {
|
||||
reporter->InternalError("AnalyzePacket() was called for the root analyzer.");
|
||||
}
|
||||
|
|
|
@ -5,21 +5,16 @@
|
|||
#include "zeek/packet_analysis/Analyzer.h"
|
||||
#include "zeek/packet_analysis/Component.h"
|
||||
|
||||
namespace zeek::packet_analysis::Root
|
||||
{
|
||||
namespace zeek::packet_analysis::Root {
|
||||
|
||||
class RootAnalyzer : public Analyzer
|
||||
{
|
||||
class RootAnalyzer : public Analyzer {
|
||||
public:
|
||||
RootAnalyzer();
|
||||
~RootAnalyzer() override = default;
|
||||
RootAnalyzer();
|
||||
~RootAnalyzer() override = default;
|
||||
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate()
|
||||
{
|
||||
return std::make_shared<RootAnalyzer>();
|
||||
}
|
||||
};
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate() { return std::make_shared<RootAnalyzer>(); }
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace zeek::packet_analysis::Root
|
||||
|
|
|
@ -5,23 +5,20 @@
|
|||
#include "zeek/packet_analysis/Component.h"
|
||||
#include "zeek/packet_analysis/protocol/skip/Skip.h"
|
||||
|
||||
namespace zeek::plugin::Zeek_Skip
|
||||
{
|
||||
namespace zeek::plugin::Zeek_Skip {
|
||||
|
||||
class Plugin final : public zeek::plugin::Plugin
|
||||
{
|
||||
class Plugin final : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure() override
|
||||
{
|
||||
AddComponent(new zeek::packet_analysis::Component(
|
||||
"Skip", zeek::packet_analysis::Skip::SkipAnalyzer::Instantiate));
|
||||
zeek::plugin::Configuration Configure() override {
|
||||
AddComponent(
|
||||
new zeek::packet_analysis::Component("Skip", zeek::packet_analysis::Skip::SkipAnalyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::Skip";
|
||||
config.description = "Skip packet analyzer";
|
||||
return config;
|
||||
}
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::Skip";
|
||||
config.description = "Skip packet analyzer";
|
||||
return config;
|
||||
}
|
||||
|
||||
} plugin;
|
||||
} plugin;
|
||||
|
||||
}
|
||||
} // namespace zeek::plugin::Zeek_Skip
|
||||
|
|
|
@ -4,20 +4,18 @@
|
|||
|
||||
using namespace zeek::packet_analysis::Skip;
|
||||
|
||||
SkipAnalyzer::SkipAnalyzer() : zeek::packet_analysis::Analyzer("Skip") { }
|
||||
SkipAnalyzer::SkipAnalyzer() : zeek::packet_analysis::Analyzer("Skip") {}
|
||||
|
||||
void SkipAnalyzer::Initialize()
|
||||
{
|
||||
Analyzer::Initialize();
|
||||
void SkipAnalyzer::Initialize() {
|
||||
Analyzer::Initialize();
|
||||
|
||||
auto& skip_val = zeek::id::find_val("PacketAnalyzer::SKIP::skip_bytes");
|
||||
if ( ! skip_val )
|
||||
return;
|
||||
auto& skip_val = zeek::id::find_val("PacketAnalyzer::SKIP::skip_bytes");
|
||||
if ( ! skip_val )
|
||||
return;
|
||||
|
||||
skip_bytes = skip_val->AsCount();
|
||||
}
|
||||
skip_bytes = skip_val->AsCount();
|
||||
}
|
||||
|
||||
bool SkipAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet)
|
||||
{
|
||||
return ForwardPacket(len - skip_bytes, data + skip_bytes, packet);
|
||||
}
|
||||
bool SkipAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) {
|
||||
return ForwardPacket(len - skip_bytes, data + skip_bytes, packet);
|
||||
}
|
||||
|
|
|
@ -5,25 +5,20 @@
|
|||
#include "zeek/packet_analysis/Analyzer.h"
|
||||
#include "zeek/packet_analysis/Component.h"
|
||||
|
||||
namespace zeek::packet_analysis::Skip
|
||||
{
|
||||
namespace zeek::packet_analysis::Skip {
|
||||
|
||||
class SkipAnalyzer : public Analyzer
|
||||
{
|
||||
class SkipAnalyzer : public Analyzer {
|
||||
public:
|
||||
SkipAnalyzer();
|
||||
~SkipAnalyzer() override = default;
|
||||
SkipAnalyzer();
|
||||
~SkipAnalyzer() override = default;
|
||||
|
||||
void Initialize() override;
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
void Initialize() override;
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate()
|
||||
{
|
||||
return std::make_shared<SkipAnalyzer>();
|
||||
}
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate() { return std::make_shared<SkipAnalyzer>(); }
|
||||
|
||||
private:
|
||||
zeek_uint_t skip_bytes = 0;
|
||||
};
|
||||
zeek_uint_t skip_bytes = 0;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace zeek::packet_analysis::Skip
|
||||
|
|
|
@ -5,23 +5,20 @@
|
|||
#include "zeek/packet_analysis/Component.h"
|
||||
#include "zeek/packet_analysis/protocol/snap/SNAP.h"
|
||||
|
||||
namespace zeek::plugin::Zeek_SNAP
|
||||
{
|
||||
namespace zeek::plugin::Zeek_SNAP {
|
||||
|
||||
class Plugin final : public zeek::plugin::Plugin
|
||||
{
|
||||
class Plugin final : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure() override
|
||||
{
|
||||
AddComponent(new zeek::packet_analysis::Component(
|
||||
"SNAP", zeek::packet_analysis::SNAP::SNAPAnalyzer::Instantiate));
|
||||
zeek::plugin::Configuration Configure() override {
|
||||
AddComponent(
|
||||
new zeek::packet_analysis::Component("SNAP", zeek::packet_analysis::SNAP::SNAPAnalyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::SNAP";
|
||||
config.description = "SNAP packet analyzer";
|
||||
return config;
|
||||
}
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::SNAP";
|
||||
config.description = "SNAP packet analyzer";
|
||||
return config;
|
||||
}
|
||||
|
||||
} plugin;
|
||||
} plugin;
|
||||
|
||||
}
|
||||
} // namespace zeek::plugin::Zeek_SNAP
|
||||
|
|
|
@ -4,47 +4,43 @@
|
|||
|
||||
using namespace zeek::packet_analysis::SNAP;
|
||||
|
||||
SNAPAnalyzer::SNAPAnalyzer() : zeek::packet_analysis::Analyzer("SNAP") { }
|
||||
SNAPAnalyzer::SNAPAnalyzer() : zeek::packet_analysis::Analyzer("SNAP") {}
|
||||
|
||||
bool SNAPAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet)
|
||||
{
|
||||
// The first part of the header is an LLC header, which we need to determine the
|
||||
// length of the full header. Check to see if the shorter 3-byte version will fit.
|
||||
if ( len < 3 )
|
||||
{
|
||||
Weird("truncated_snap_llc_header", packet);
|
||||
return false;
|
||||
}
|
||||
bool SNAPAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) {
|
||||
// The first part of the header is an LLC header, which we need to determine the
|
||||
// length of the full header. Check to see if the shorter 3-byte version will fit.
|
||||
if ( len < 3 ) {
|
||||
Weird("truncated_snap_llc_header", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the control field doesn't have an unnumbered PDU, the header is actually 4
|
||||
// bytes long. Whether this is unnumbered is denoted by the last two bits being
|
||||
// set.
|
||||
size_t llc_header_len = 3;
|
||||
if ( (data[2] & 0x03) != 0x03 )
|
||||
llc_header_len++;
|
||||
// If the control field doesn't have an unnumbered PDU, the header is actually 4
|
||||
// bytes long. Whether this is unnumbered is denoted by the last two bits being
|
||||
// set.
|
||||
size_t llc_header_len = 3;
|
||||
if ( (data[2] & 0x03) != 0x03 )
|
||||
llc_header_len++;
|
||||
|
||||
// Check the full length of the SNAP header, which is the LLC header plus 5 bytes.
|
||||
if ( len < llc_header_len + 5 )
|
||||
{
|
||||
Weird("truncated_snap_header", packet);
|
||||
return false;
|
||||
}
|
||||
// Check the full length of the SNAP header, which is the LLC header plus 5 bytes.
|
||||
if ( len < llc_header_len + 5 ) {
|
||||
Weird("truncated_snap_header", packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
data += llc_header_len;
|
||||
len -= llc_header_len;
|
||||
data += llc_header_len;
|
||||
len -= llc_header_len;
|
||||
|
||||
int oui = (data[0] << 16) | (data[1] << 8) | data[2];
|
||||
int protocol = (data[3] << 8) | data[4];
|
||||
int oui = (data[0] << 16) | (data[1] << 8) | data[2];
|
||||
int protocol = (data[3] << 8) | data[4];
|
||||
|
||||
data += 5;
|
||||
len -= 5;
|
||||
data += 5;
|
||||
len -= 5;
|
||||
|
||||
if ( oui == 0 )
|
||||
{
|
||||
// If the OUI is zero, the protocol is a standard ethertype and can be
|
||||
// forwarded as such.
|
||||
return ForwardPacket(len, data, packet, protocol);
|
||||
}
|
||||
if ( oui == 0 ) {
|
||||
// If the OUI is zero, the protocol is a standard ethertype and can be
|
||||
// forwarded as such.
|
||||
return ForwardPacket(len, data, packet, protocol);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -5,21 +5,16 @@
|
|||
#include "zeek/packet_analysis/Analyzer.h"
|
||||
#include "zeek/packet_analysis/Component.h"
|
||||
|
||||
namespace zeek::packet_analysis::SNAP
|
||||
{
|
||||
namespace zeek::packet_analysis::SNAP {
|
||||
|
||||
class SNAPAnalyzer : public Analyzer
|
||||
{
|
||||
class SNAPAnalyzer : public Analyzer {
|
||||
public:
|
||||
SNAPAnalyzer();
|
||||
~SNAPAnalyzer() override = default;
|
||||
SNAPAnalyzer();
|
||||
~SNAPAnalyzer() override = default;
|
||||
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate()
|
||||
{
|
||||
return std::make_shared<SNAPAnalyzer>();
|
||||
}
|
||||
};
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate() { return std::make_shared<SNAPAnalyzer>(); }
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace zeek::packet_analysis::SNAP
|
||||
|
|
|
@ -7,24 +7,20 @@
|
|||
#include "zeek/packet_analysis/protocol/tcp/TCP.h"
|
||||
#include "zeek/packet_analysis/protocol/tcp/TCPSessionAdapter.h"
|
||||
|
||||
namespace zeek::plugin::Zeek_TCP
|
||||
{
|
||||
namespace zeek::plugin::Zeek_TCP {
|
||||
|
||||
class Plugin final : public zeek::plugin::Plugin
|
||||
{
|
||||
class Plugin final : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure() override
|
||||
{
|
||||
AddComponent(new zeek::packet_analysis::Component(
|
||||
"TCP", zeek::packet_analysis::TCP::TCPAnalyzer::Instantiate));
|
||||
AddComponent(new zeek::analyzer::Component("TCP", nullptr, 0, true, false, true));
|
||||
zeek::plugin::Configuration Configure() override {
|
||||
AddComponent(new zeek::packet_analysis::Component("TCP", zeek::packet_analysis::TCP::TCPAnalyzer::Instantiate));
|
||||
AddComponent(new zeek::analyzer::Component("TCP", nullptr, 0, true, false, true));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::TCP_PKT";
|
||||
config.description = "Packet analyzer for TCP";
|
||||
return config;
|
||||
}
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::TCP_PKT";
|
||||
config.description = "Packet analyzer for TCP";
|
||||
return config;
|
||||
}
|
||||
|
||||
} plugin;
|
||||
} plugin;
|
||||
|
||||
}
|
||||
} // namespace zeek::plugin::Zeek_TCP
|
||||
|
|
|
@ -5,85 +5,70 @@
|
|||
#include "zeek/File.h"
|
||||
#include "zeek/analyzer/protocol/tcp/events.bif.h"
|
||||
|
||||
namespace zeek::packet_analysis::TCP
|
||||
{
|
||||
namespace zeek::packet_analysis::TCP {
|
||||
|
||||
TCPStateStats::TCPStateStats()
|
||||
{
|
||||
for ( int i = 0; i < analyzer::tcp::TCP_ENDPOINT_RESET + 1; ++i )
|
||||
for ( int j = 0; j < analyzer::tcp::TCP_ENDPOINT_RESET + 1; ++j )
|
||||
state_cnt[i][j] = 0;
|
||||
}
|
||||
TCPStateStats::TCPStateStats() {
|
||||
for ( int i = 0; i < analyzer::tcp::TCP_ENDPOINT_RESET + 1; ++i )
|
||||
for ( int j = 0; j < analyzer::tcp::TCP_ENDPOINT_RESET + 1; ++j )
|
||||
state_cnt[i][j] = 0;
|
||||
}
|
||||
|
||||
void TCPStateStats::ChangeState(analyzer::tcp::EndpointState o_prev,
|
||||
analyzer::tcp::EndpointState o_now,
|
||||
analyzer::tcp::EndpointState r_prev,
|
||||
analyzer::tcp::EndpointState r_now)
|
||||
{
|
||||
--state_cnt[o_prev][r_prev];
|
||||
++state_cnt[o_now][r_now];
|
||||
}
|
||||
void TCPStateStats::ChangeState(analyzer::tcp::EndpointState o_prev, analyzer::tcp::EndpointState o_now,
|
||||
analyzer::tcp::EndpointState r_prev, analyzer::tcp::EndpointState r_now) {
|
||||
--state_cnt[o_prev][r_prev];
|
||||
++state_cnt[o_now][r_now];
|
||||
}
|
||||
|
||||
void TCPStateStats::FlipState(analyzer::tcp::EndpointState orig, analyzer::tcp::EndpointState resp)
|
||||
{
|
||||
--state_cnt[orig][resp];
|
||||
++state_cnt[resp][orig];
|
||||
}
|
||||
void TCPStateStats::FlipState(analyzer::tcp::EndpointState orig, analyzer::tcp::EndpointState resp) {
|
||||
--state_cnt[orig][resp];
|
||||
++state_cnt[resp][orig];
|
||||
}
|
||||
|
||||
unsigned int TCPStateStats::NumStatePartial() const
|
||||
{
|
||||
unsigned int sum = 0;
|
||||
for ( int i = 0; i < analyzer::tcp::TCP_ENDPOINT_RESET + 1; ++i )
|
||||
{
|
||||
sum += state_cnt[analyzer::tcp::TCP_ENDPOINT_PARTIAL][i];
|
||||
sum += state_cnt[i][analyzer::tcp::TCP_ENDPOINT_PARTIAL];
|
||||
}
|
||||
unsigned int TCPStateStats::NumStatePartial() const {
|
||||
unsigned int sum = 0;
|
||||
for ( int i = 0; i < analyzer::tcp::TCP_ENDPOINT_RESET + 1; ++i ) {
|
||||
sum += state_cnt[analyzer::tcp::TCP_ENDPOINT_PARTIAL][i];
|
||||
sum += state_cnt[i][analyzer::tcp::TCP_ENDPOINT_PARTIAL];
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
void TCPStateStats::PrintStats(File* file, const char* prefix)
|
||||
{
|
||||
file->Write(prefix);
|
||||
file->Write(" Inact. Syn. SA Part. Est. Fin. Rst.\n");
|
||||
void TCPStateStats::PrintStats(File* file, const char* prefix) {
|
||||
file->Write(prefix);
|
||||
file->Write(" Inact. Syn. SA Part. Est. Fin. Rst.\n");
|
||||
|
||||
for ( int i = 0; i < analyzer::tcp::TCP_ENDPOINT_RESET + 1; ++i )
|
||||
{
|
||||
file->Write(prefix);
|
||||
for ( int i = 0; i < analyzer::tcp::TCP_ENDPOINT_RESET + 1; ++i ) {
|
||||
file->Write(prefix);
|
||||
|
||||
switch ( i )
|
||||
{
|
||||
#define STATE_STRING(state, str) \
|
||||
case state: \
|
||||
file->Write(str); \
|
||||
break;
|
||||
switch ( i ) {
|
||||
#define STATE_STRING(state, str) \
|
||||
case state: file->Write(str); break;
|
||||
|
||||
STATE_STRING(analyzer::tcp::TCP_ENDPOINT_INACTIVE, "Inact.");
|
||||
STATE_STRING(analyzer::tcp::TCP_ENDPOINT_SYN_SENT, "Syn. ");
|
||||
STATE_STRING(analyzer::tcp::TCP_ENDPOINT_SYN_ACK_SENT, "SA ");
|
||||
STATE_STRING(analyzer::tcp::TCP_ENDPOINT_PARTIAL, "Part. ");
|
||||
STATE_STRING(analyzer::tcp::TCP_ENDPOINT_ESTABLISHED, "Est. ");
|
||||
STATE_STRING(analyzer::tcp::TCP_ENDPOINT_CLOSED, "Fin. ");
|
||||
STATE_STRING(analyzer::tcp::TCP_ENDPOINT_RESET, "Rst. ");
|
||||
}
|
||||
STATE_STRING(analyzer::tcp::TCP_ENDPOINT_INACTIVE, "Inact.");
|
||||
STATE_STRING(analyzer::tcp::TCP_ENDPOINT_SYN_SENT, "Syn. ");
|
||||
STATE_STRING(analyzer::tcp::TCP_ENDPOINT_SYN_ACK_SENT, "SA ");
|
||||
STATE_STRING(analyzer::tcp::TCP_ENDPOINT_PARTIAL, "Part. ");
|
||||
STATE_STRING(analyzer::tcp::TCP_ENDPOINT_ESTABLISHED, "Est. ");
|
||||
STATE_STRING(analyzer::tcp::TCP_ENDPOINT_CLOSED, "Fin. ");
|
||||
STATE_STRING(analyzer::tcp::TCP_ENDPOINT_RESET, "Rst. ");
|
||||
}
|
||||
|
||||
file->Write(" ");
|
||||
file->Write(" ");
|
||||
|
||||
for ( int j = 0; j < analyzer::tcp::TCP_ENDPOINT_RESET + 1; ++j )
|
||||
{
|
||||
unsigned int n = state_cnt[i][j];
|
||||
if ( n > 0 )
|
||||
{
|
||||
char buf[32];
|
||||
snprintf(buf, sizeof(buf), "%-8d", state_cnt[i][j]);
|
||||
file->Write(buf);
|
||||
}
|
||||
else
|
||||
file->Write(" ");
|
||||
}
|
||||
for ( int j = 0; j < analyzer::tcp::TCP_ENDPOINT_RESET + 1; ++j ) {
|
||||
unsigned int n = state_cnt[i][j];
|
||||
if ( n > 0 ) {
|
||||
char buf[32];
|
||||
snprintf(buf, sizeof(buf), "%-8d", state_cnt[i][j]);
|
||||
file->Write(buf);
|
||||
}
|
||||
else
|
||||
file->Write(" ");
|
||||
}
|
||||
|
||||
file->Write("\n");
|
||||
}
|
||||
}
|
||||
file->Write("\n");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace zeek::packet_analysis::TCP
|
||||
} // namespace zeek::packet_analysis::TCP
|
||||
|
|
|
@ -4,77 +4,62 @@
|
|||
|
||||
#include "zeek/analyzer/protocol/tcp/TCP_Endpoint.h"
|
||||
|
||||
namespace zeek::packet_analysis::TCP
|
||||
{
|
||||
namespace zeek::packet_analysis::TCP {
|
||||
|
||||
/**
|
||||
* A TCPStateStats object tracks the distribution of TCP states for
|
||||
* the currently active connections.
|
||||
*/
|
||||
class TCPStateStats
|
||||
{
|
||||
class TCPStateStats {
|
||||
public:
|
||||
TCPStateStats();
|
||||
~TCPStateStats() = default;
|
||||
TCPStateStats();
|
||||
~TCPStateStats() = default;
|
||||
|
||||
void ChangeState(analyzer::tcp::EndpointState o_prev, analyzer::tcp::EndpointState o_now,
|
||||
analyzer::tcp::EndpointState r_prev, analyzer::tcp::EndpointState r_now);
|
||||
void FlipState(analyzer::tcp::EndpointState orig, analyzer::tcp::EndpointState resp);
|
||||
void ChangeState(analyzer::tcp::EndpointState o_prev, analyzer::tcp::EndpointState o_now,
|
||||
analyzer::tcp::EndpointState r_prev, analyzer::tcp::EndpointState r_now);
|
||||
void FlipState(analyzer::tcp::EndpointState orig, analyzer::tcp::EndpointState resp);
|
||||
|
||||
void StateEntered(analyzer::tcp::EndpointState o_state, analyzer::tcp::EndpointState r_state)
|
||||
{
|
||||
++state_cnt[o_state][r_state];
|
||||
}
|
||||
void StateLeft(analyzer::tcp::EndpointState o_state, analyzer::tcp::EndpointState r_state)
|
||||
{
|
||||
--state_cnt[o_state][r_state];
|
||||
}
|
||||
void StateEntered(analyzer::tcp::EndpointState o_state, analyzer::tcp::EndpointState r_state) {
|
||||
++state_cnt[o_state][r_state];
|
||||
}
|
||||
void StateLeft(analyzer::tcp::EndpointState o_state, analyzer::tcp::EndpointState r_state) {
|
||||
--state_cnt[o_state][r_state];
|
||||
}
|
||||
|
||||
unsigned int Cnt(analyzer::tcp::EndpointState state) const { return Cnt(state, state); }
|
||||
unsigned int Cnt(analyzer::tcp::EndpointState state1, analyzer::tcp::EndpointState state2) const
|
||||
{
|
||||
return state_cnt[state1][state2];
|
||||
}
|
||||
unsigned int Cnt(analyzer::tcp::EndpointState state) const { return Cnt(state, state); }
|
||||
unsigned int Cnt(analyzer::tcp::EndpointState state1, analyzer::tcp::EndpointState state2) const {
|
||||
return state_cnt[state1][state2];
|
||||
}
|
||||
|
||||
unsigned int NumStateEstablished() const
|
||||
{
|
||||
return Cnt(analyzer::tcp::TCP_ENDPOINT_ESTABLISHED);
|
||||
}
|
||||
unsigned int NumStateHalfClose() const
|
||||
{ // corresponds to S2,S3
|
||||
return Cnt(analyzer::tcp::TCP_ENDPOINT_ESTABLISHED, analyzer::tcp::TCP_ENDPOINT_CLOSED) +
|
||||
Cnt(analyzer::tcp::TCP_ENDPOINT_CLOSED, analyzer::tcp::TCP_ENDPOINT_ESTABLISHED);
|
||||
}
|
||||
unsigned int NumStateHalfRst() const
|
||||
{
|
||||
return Cnt(analyzer::tcp::TCP_ENDPOINT_ESTABLISHED, analyzer::tcp::TCP_ENDPOINT_RESET) +
|
||||
Cnt(analyzer::tcp::TCP_ENDPOINT_RESET, analyzer::tcp::TCP_ENDPOINT_ESTABLISHED);
|
||||
}
|
||||
unsigned int NumStateClosed() const { return Cnt(analyzer::tcp::TCP_ENDPOINT_CLOSED); }
|
||||
unsigned int NumStateRequest() const
|
||||
{
|
||||
assert(Cnt(analyzer::tcp::TCP_ENDPOINT_INACTIVE, analyzer::tcp::TCP_ENDPOINT_SYN_SENT) ==
|
||||
0);
|
||||
return Cnt(analyzer::tcp::TCP_ENDPOINT_SYN_SENT, analyzer::tcp::TCP_ENDPOINT_INACTIVE);
|
||||
}
|
||||
unsigned int NumStateSuccRequest() const
|
||||
{
|
||||
return Cnt(analyzer::tcp::TCP_ENDPOINT_SYN_SENT, analyzer::tcp::TCP_ENDPOINT_SYN_ACK_SENT) +
|
||||
Cnt(analyzer::tcp::TCP_ENDPOINT_SYN_ACK_SENT, analyzer::tcp::TCP_ENDPOINT_SYN_SENT);
|
||||
}
|
||||
unsigned int NumStateRstRequest() const
|
||||
{
|
||||
return Cnt(analyzer::tcp::TCP_ENDPOINT_SYN_SENT, analyzer::tcp::TCP_ENDPOINT_RESET) +
|
||||
Cnt(analyzer::tcp::TCP_ENDPOINT_RESET, analyzer::tcp::TCP_ENDPOINT_SYN_SENT);
|
||||
}
|
||||
unsigned int NumStateInactive() const { return Cnt(analyzer::tcp::TCP_ENDPOINT_INACTIVE); }
|
||||
unsigned int NumStatePartial() const;
|
||||
unsigned int NumStateEstablished() const { return Cnt(analyzer::tcp::TCP_ENDPOINT_ESTABLISHED); }
|
||||
unsigned int NumStateHalfClose() const { // corresponds to S2,S3
|
||||
return Cnt(analyzer::tcp::TCP_ENDPOINT_ESTABLISHED, analyzer::tcp::TCP_ENDPOINT_CLOSED) +
|
||||
Cnt(analyzer::tcp::TCP_ENDPOINT_CLOSED, analyzer::tcp::TCP_ENDPOINT_ESTABLISHED);
|
||||
}
|
||||
unsigned int NumStateHalfRst() const {
|
||||
return Cnt(analyzer::tcp::TCP_ENDPOINT_ESTABLISHED, analyzer::tcp::TCP_ENDPOINT_RESET) +
|
||||
Cnt(analyzer::tcp::TCP_ENDPOINT_RESET, analyzer::tcp::TCP_ENDPOINT_ESTABLISHED);
|
||||
}
|
||||
unsigned int NumStateClosed() const { return Cnt(analyzer::tcp::TCP_ENDPOINT_CLOSED); }
|
||||
unsigned int NumStateRequest() const {
|
||||
assert(Cnt(analyzer::tcp::TCP_ENDPOINT_INACTIVE, analyzer::tcp::TCP_ENDPOINT_SYN_SENT) == 0);
|
||||
return Cnt(analyzer::tcp::TCP_ENDPOINT_SYN_SENT, analyzer::tcp::TCP_ENDPOINT_INACTIVE);
|
||||
}
|
||||
unsigned int NumStateSuccRequest() const {
|
||||
return Cnt(analyzer::tcp::TCP_ENDPOINT_SYN_SENT, analyzer::tcp::TCP_ENDPOINT_SYN_ACK_SENT) +
|
||||
Cnt(analyzer::tcp::TCP_ENDPOINT_SYN_ACK_SENT, analyzer::tcp::TCP_ENDPOINT_SYN_SENT);
|
||||
}
|
||||
unsigned int NumStateRstRequest() const {
|
||||
return Cnt(analyzer::tcp::TCP_ENDPOINT_SYN_SENT, analyzer::tcp::TCP_ENDPOINT_RESET) +
|
||||
Cnt(analyzer::tcp::TCP_ENDPOINT_RESET, analyzer::tcp::TCP_ENDPOINT_SYN_SENT);
|
||||
}
|
||||
unsigned int NumStateInactive() const { return Cnt(analyzer::tcp::TCP_ENDPOINT_INACTIVE); }
|
||||
unsigned int NumStatePartial() const;
|
||||
|
||||
void PrintStats(File* file, const char* prefix);
|
||||
void PrintStats(File* file, const char* prefix);
|
||||
|
||||
private:
|
||||
unsigned int state_cnt[analyzer::tcp::TCP_ENDPOINT_RESET + 1]
|
||||
[analyzer::tcp::TCP_ENDPOINT_RESET + 1];
|
||||
};
|
||||
unsigned int state_cnt[analyzer::tcp::TCP_ENDPOINT_RESET + 1][analyzer::tcp::TCP_ENDPOINT_RESET + 1];
|
||||
};
|
||||
|
||||
} // namespace zeek::packet_analysis::TCP
|
||||
} // namespace zeek::packet_analysis::TCP
|
||||
|
|
|
@ -12,166 +12,149 @@ using namespace zeek;
|
|||
using namespace zeek::packet_analysis::TCP;
|
||||
using namespace zeek::packet_analysis::IP;
|
||||
|
||||
TCPAnalyzer::TCPAnalyzer() : IPBasedAnalyzer("TCP", TRANSPORT_TCP, TCP_PORT_MASK, false) { }
|
||||
TCPAnalyzer::TCPAnalyzer() : IPBasedAnalyzer("TCP", TRANSPORT_TCP, TCP_PORT_MASK, false) {}
|
||||
|
||||
void TCPAnalyzer::Initialize() { }
|
||||
void TCPAnalyzer::Initialize() {}
|
||||
|
||||
SessionAdapter* TCPAnalyzer::MakeSessionAdapter(Connection* conn)
|
||||
{
|
||||
auto* root = new TCPSessionAdapter(conn);
|
||||
root->SetParent(this);
|
||||
SessionAdapter* TCPAnalyzer::MakeSessionAdapter(Connection* conn) {
|
||||
auto* root = new TCPSessionAdapter(conn);
|
||||
root->SetParent(this);
|
||||
|
||||
conn->EnableStatusUpdateTimer();
|
||||
conn->SetInactivityTimeout(zeek::detail::udp_inactivity_timeout);
|
||||
conn->EnableStatusUpdateTimer();
|
||||
conn->SetInactivityTimeout(zeek::detail::udp_inactivity_timeout);
|
||||
|
||||
return root;
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
zeek::analyzer::pia::PIA* TCPAnalyzer::MakePIA(Connection* conn)
|
||||
{
|
||||
return new analyzer::pia::PIA_TCP(conn);
|
||||
}
|
||||
zeek::analyzer::pia::PIA* TCPAnalyzer::MakePIA(Connection* conn) { return new analyzer::pia::PIA_TCP(conn); }
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
tuple.src_addr = packet->ip_hdr->SrcAddr();
|
||||
tuple.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();
|
||||
data = packet->ip_hdr->Payload();
|
||||
|
||||
const struct tcphdr* tp = (const struct tcphdr*)data;
|
||||
tuple.src_port = tp->th_sport;
|
||||
tuple.dst_port = tp->th_dport;
|
||||
tuple.is_one_way = false;
|
||||
tuple.proto = TRANSPORT_TCP;
|
||||
const struct tcphdr* tp = (const struct tcphdr*)data;
|
||||
tuple.src_port = tp->th_sport;
|
||||
tuple.dst_port = tp->th_dport;
|
||||
tuple.is_one_way = false;
|
||||
tuple.proto = TRANSPORT_TCP;
|
||||
|
||||
return true;
|
||||
}
|
||||
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;
|
||||
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) || (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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void TCPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int remaining, Packet* pkt)
|
||||
{
|
||||
const u_char* data = pkt->ip_hdr->Payload();
|
||||
int len = pkt->ip_hdr->PayloadLen();
|
||||
// If the header length is zero, tcp checksum offloading is probably enabled
|
||||
// In this case, let's fix up the length.
|
||||
if ( pkt->ip_hdr->TotalLen() == 0 )
|
||||
len = remaining;
|
||||
auto* adapter = static_cast<TCPSessionAdapter*>(c->GetSessionAdapter());
|
||||
void TCPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int remaining, Packet* pkt) {
|
||||
const u_char* data = pkt->ip_hdr->Payload();
|
||||
int len = pkt->ip_hdr->PayloadLen();
|
||||
// If the header length is zero, tcp checksum offloading is probably enabled
|
||||
// In this case, let's fix up the length.
|
||||
if ( pkt->ip_hdr->TotalLen() == 0 )
|
||||
len = remaining;
|
||||
auto* adapter = static_cast<TCPSessionAdapter*>(c->GetSessionAdapter());
|
||||
|
||||
const struct tcphdr* tp = ExtractTCP_Header(data, len, remaining, adapter);
|
||||
if ( ! tp )
|
||||
return;
|
||||
const struct tcphdr* tp = ExtractTCP_Header(data, len, remaining, adapter);
|
||||
if ( ! tp )
|
||||
return;
|
||||
|
||||
// We need the min() here because Ethernet frame padding can lead to
|
||||
// remaining > len.
|
||||
if ( packet_contents )
|
||||
adapter->PacketContents(data, std::min(len, remaining));
|
||||
// We need the min() here because Ethernet frame padding can lead to
|
||||
// remaining > len.
|
||||
if ( packet_contents )
|
||||
adapter->PacketContents(data, std::min(len, remaining));
|
||||
|
||||
analyzer::tcp::TCP_Endpoint* endpoint = is_orig ? adapter->orig : adapter->resp;
|
||||
analyzer::tcp::TCP_Endpoint* peer = endpoint->peer;
|
||||
const std::shared_ptr<IP_Hdr>& ip = pkt->ip_hdr;
|
||||
analyzer::tcp::TCP_Endpoint* endpoint = is_orig ? adapter->orig : adapter->resp;
|
||||
analyzer::tcp::TCP_Endpoint* peer = endpoint->peer;
|
||||
const std::shared_ptr<IP_Hdr>& ip = pkt->ip_hdr;
|
||||
|
||||
if ( ! ValidateChecksum(ip.get(), tp, endpoint, len, remaining, adapter) )
|
||||
return;
|
||||
if ( ! ValidateChecksum(ip.get(), tp, endpoint, len, remaining, adapter) )
|
||||
return;
|
||||
|
||||
adapter->Process(is_orig, tp, len, ip, data, remaining);
|
||||
adapter->Process(is_orig, tp, len, ip, data, remaining);
|
||||
|
||||
// Store the session in the packet in case we get an encapsulation here. We need it for
|
||||
// handling those properly.
|
||||
pkt->session = c;
|
||||
// Store the session in the packet in case we get an encapsulation here. We need it for
|
||||
// handling those properly.
|
||||
pkt->session = c;
|
||||
|
||||
// Send the packet back into the packet analysis framework.
|
||||
ForwardPacket(std::min(len, remaining), data, pkt);
|
||||
// Send the packet back into the packet analysis framework.
|
||||
ForwardPacket(std::min(len, remaining), data, pkt);
|
||||
|
||||
// Call DeliverPacket on the adapter directly here. Normally we'd call ForwardPacket
|
||||
// but this adapter does some other things in its DeliverPacket with the packet children
|
||||
// analyzers.
|
||||
adapter->DeliverPacket(std::min(len, remaining), data, is_orig, adapter->LastRelDataSeq(),
|
||||
ip.get(), pkt->cap_len);
|
||||
}
|
||||
// Call DeliverPacket on the adapter directly here. Normally we'd call ForwardPacket
|
||||
// but this adapter does some other things in its DeliverPacket with the packet children
|
||||
// analyzers.
|
||||
adapter->DeliverPacket(std::min(len, remaining), data, is_orig, adapter->LastRelDataSeq(), ip.get(), pkt->cap_len);
|
||||
}
|
||||
|
||||
const struct tcphdr* TCPAnalyzer::ExtractTCP_Header(const u_char*& data, int& len, int& remaining,
|
||||
TCPSessionAdapter* adapter)
|
||||
{
|
||||
const struct tcphdr* tp = (const struct tcphdr*)data;
|
||||
uint32_t tcp_hdr_len = tp->th_off * 4;
|
||||
TCPSessionAdapter* adapter) {
|
||||
const struct tcphdr* tp = (const struct tcphdr*)data;
|
||||
uint32_t tcp_hdr_len = tp->th_off * 4;
|
||||
|
||||
if ( tcp_hdr_len < sizeof(struct tcphdr) )
|
||||
{
|
||||
adapter->Weird("bad_TCP_header_len");
|
||||
return nullptr;
|
||||
}
|
||||
if ( tcp_hdr_len < sizeof(struct tcphdr) ) {
|
||||
adapter->Weird("bad_TCP_header_len");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if ( tcp_hdr_len > uint32_t(len) || tcp_hdr_len > uint32_t(remaining) )
|
||||
{
|
||||
// This can happen even with the above test, due to TCP options.
|
||||
adapter->Weird("truncated_header");
|
||||
return nullptr;
|
||||
}
|
||||
if ( tcp_hdr_len > uint32_t(len) || tcp_hdr_len > uint32_t(remaining) ) {
|
||||
// This can happen even with the above test, due to TCP options.
|
||||
adapter->Weird("truncated_header");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
len -= tcp_hdr_len; // remove TCP header
|
||||
remaining -= tcp_hdr_len;
|
||||
data += tcp_hdr_len;
|
||||
len -= tcp_hdr_len; // remove TCP header
|
||||
remaining -= tcp_hdr_len;
|
||||
data += tcp_hdr_len;
|
||||
|
||||
return tp;
|
||||
}
|
||||
return tp;
|
||||
}
|
||||
|
||||
bool TCPAnalyzer::ValidateChecksum(const IP_Hdr* ip, const struct tcphdr* tp,
|
||||
analyzer::tcp::TCP_Endpoint* endpoint, int len, int caplen,
|
||||
TCPSessionAdapter* adapter)
|
||||
{
|
||||
if ( ! run_state::current_pkt->l4_checksummed && ! detail::ignore_checksums &&
|
||||
! GetIgnoreChecksumsNets()->Contains(ip->IPHeaderSrcAddr()) && caplen >= len &&
|
||||
! endpoint->ValidChecksum(tp, len, ip->IP4_Hdr()) )
|
||||
{
|
||||
adapter->Weird("bad_TCP_checksum");
|
||||
endpoint->ChecksumError();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
bool TCPAnalyzer::ValidateChecksum(const IP_Hdr* ip, const struct tcphdr* tp, analyzer::tcp::TCP_Endpoint* endpoint,
|
||||
int len, int caplen, TCPSessionAdapter* adapter) {
|
||||
if ( ! run_state::current_pkt->l4_checksummed && ! detail::ignore_checksums &&
|
||||
! GetIgnoreChecksumsNets()->Contains(ip->IPHeaderSrcAddr()) && caplen >= len &&
|
||||
! endpoint->ValidChecksum(tp, len, ip->IP4_Hdr()) ) {
|
||||
adapter->Weird("bad_TCP_checksum");
|
||||
endpoint->ChecksumError();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -8,85 +8,75 @@
|
|||
#include "zeek/packet_analysis/protocol/ip/IPBasedAnalyzer.h"
|
||||
#include "zeek/packet_analysis/protocol/tcp/Stats.h"
|
||||
|
||||
namespace zeek::analyzer::tcp
|
||||
{
|
||||
namespace zeek::analyzer::tcp {
|
||||
class TCP_Endpoint;
|
||||
}
|
||||
}
|
||||
|
||||
namespace zeek::packet_analysis::TCP
|
||||
{
|
||||
namespace zeek::packet_analysis::TCP {
|
||||
|
||||
class TCPSessionAdapter;
|
||||
|
||||
class TCPAnalyzer final : public IP::IPBasedAnalyzer
|
||||
{
|
||||
class TCPAnalyzer final : public IP::IPBasedAnalyzer {
|
||||
public:
|
||||
TCPAnalyzer();
|
||||
~TCPAnalyzer() override = default;
|
||||
TCPAnalyzer();
|
||||
~TCPAnalyzer() override = default;
|
||||
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate()
|
||||
{
|
||||
return std::make_shared<TCPAnalyzer>();
|
||||
}
|
||||
static zeek::packet_analysis::AnalyzerPtr Instantiate() { return std::make_shared<TCPAnalyzer>(); }
|
||||
|
||||
/*
|
||||
* 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;
|
||||
/*
|
||||
* 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;
|
||||
|
||||
static TCPStateStats& GetStats()
|
||||
{
|
||||
static TCPStateStats stats;
|
||||
return stats;
|
||||
}
|
||||
static TCPStateStats& GetStats() {
|
||||
static TCPStateStats stats;
|
||||
return stats;
|
||||
}
|
||||
|
||||
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;
|
||||
/**
|
||||
* 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;
|
||||
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)
|
||||
* 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;
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
packet_analysis::IP::SessionAdapter* MakeSessionAdapter(Connection* conn) override;
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
packet_analysis::IP::SessionAdapter* MakeSessionAdapter(Connection* conn) override;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
analyzer::pia::PIA* MakePIA(Connection* conn) override;
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
analyzer::pia::PIA* MakePIA(Connection* conn) override;
|
||||
|
||||
private:
|
||||
const struct tcphdr* ExtractTCP_Header(const u_char*& data, int& len, int& remaining,
|
||||
TCPSessionAdapter* adapter);
|
||||
const struct tcphdr* ExtractTCP_Header(const u_char*& data, int& len, int& remaining, TCPSessionAdapter* adapter);
|
||||
|
||||
// Returns true if the checksum is valid, false if not (and in which
|
||||
// case also updates the status history of the endpoint).
|
||||
bool ValidateChecksum(const IP_Hdr* ip, const struct tcphdr* tp,
|
||||
analyzer::tcp::TCP_Endpoint* endpoint, int len, int caplen,
|
||||
TCPSessionAdapter* adapter);
|
||||
};
|
||||
// Returns true if the checksum is valid, false if not (and in which
|
||||
// case also updates the status history of the endpoint).
|
||||
bool ValidateChecksum(const IP_Hdr* ip, const struct tcphdr* tp, analyzer::tcp::TCP_Endpoint* endpoint, int len,
|
||||
int caplen, TCPSessionAdapter* adapter);
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace zeek::packet_analysis::TCP
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -10,185 +10,173 @@
|
|||
#include "zeek/packet_analysis/protocol/ip/SessionAdapter.h"
|
||||
#include "zeek/session/Manager.h"
|
||||
|
||||
namespace zeek::analyzer::pia
|
||||
{
|
||||
namespace zeek::analyzer::pia {
|
||||
class PIA_TCP;
|
||||
}
|
||||
namespace zeek::analyzer::tcp
|
||||
{
|
||||
}
|
||||
namespace zeek::analyzer::tcp {
|
||||
class TCP_Reassembler;
|
||||
}
|
||||
}
|
||||
|
||||
namespace zeek::packet_analysis::TCP
|
||||
{
|
||||
namespace zeek::packet_analysis::TCP {
|
||||
|
||||
constexpr bool DEBUG_tcp_data_sent = false;
|
||||
constexpr bool DEBUG_tcp_connection_close = false;
|
||||
|
||||
class TCPAnalyzer;
|
||||
|
||||
class TCPSessionAdapter final : public packet_analysis::IP::SessionAdapter
|
||||
{
|
||||
class TCPSessionAdapter final : public packet_analysis::IP::SessionAdapter {
|
||||
public:
|
||||
explicit TCPSessionAdapter(Connection* conn);
|
||||
~TCPSessionAdapter() override;
|
||||
explicit TCPSessionAdapter(Connection* conn);
|
||||
~TCPSessionAdapter() override;
|
||||
|
||||
void Process(bool is_orig, const struct tcphdr* tp, int len, const std::shared_ptr<IP_Hdr>& ip,
|
||||
const u_char* data, int remaining);
|
||||
void Process(bool is_orig, const struct tcphdr* tp, int len, const std::shared_ptr<IP_Hdr>& ip, const u_char* data,
|
||||
int remaining);
|
||||
|
||||
void EnableReassembly();
|
||||
void EnableReassembly();
|
||||
|
||||
// Add a child analyzer that will always get the packets,
|
||||
// independently of whether we do any reassembly.
|
||||
void AddChildPacketAnalyzer(analyzer::Analyzer* a);
|
||||
// Add a child analyzer that will always get the packets,
|
||||
// independently of whether we do any reassembly.
|
||||
void AddChildPacketAnalyzer(analyzer::Analyzer* a);
|
||||
|
||||
Analyzer* FindChild(analyzer::ID id) override;
|
||||
Analyzer* FindChild(zeek::Tag tag) override;
|
||||
bool RemoveChildAnalyzer(analyzer::ID id) override;
|
||||
Analyzer* FindChild(analyzer::ID id) override;
|
||||
Analyzer* FindChild(zeek::Tag tag) override;
|
||||
bool RemoveChildAnalyzer(analyzer::ID id) override;
|
||||
|
||||
// True if the connection has closed in some sense, false otherwise.
|
||||
bool IsClosed() const { return orig->did_close || resp->did_close; }
|
||||
bool BothClosed() const { return orig->did_close && resp->did_close; }
|
||||
// True if the connection has closed in some sense, false otherwise.
|
||||
bool IsClosed() const { return orig->did_close || resp->did_close; }
|
||||
bool BothClosed() const { return orig->did_close && resp->did_close; }
|
||||
|
||||
bool IsPartial() const { return is_partial; }
|
||||
bool IsPartial() const { return is_partial; }
|
||||
|
||||
bool HadGap(bool orig) const;
|
||||
bool HadGap(bool orig) const;
|
||||
|
||||
analyzer::tcp::TCP_Endpoint* Orig() const { return orig; }
|
||||
analyzer::tcp::TCP_Endpoint* Resp() const { return resp; }
|
||||
int OrigState() const { return orig->state; }
|
||||
int RespState() const { return resp->state; }
|
||||
int OrigPrevState() const { return orig->prev_state; }
|
||||
int RespPrevState() const { return resp->prev_state; }
|
||||
uint32_t OrigSeq() const { return orig->LastSeq(); }
|
||||
uint32_t RespSeq() const { return resp->LastSeq(); }
|
||||
analyzer::tcp::TCP_Endpoint* Orig() const { return orig; }
|
||||
analyzer::tcp::TCP_Endpoint* Resp() const { return resp; }
|
||||
int OrigState() const { return orig->state; }
|
||||
int RespState() const { return resp->state; }
|
||||
int OrigPrevState() const { return orig->prev_state; }
|
||||
int RespPrevState() const { return resp->prev_state; }
|
||||
uint32_t OrigSeq() const { return orig->LastSeq(); }
|
||||
uint32_t RespSeq() const { return resp->LastSeq(); }
|
||||
|
||||
// True if either endpoint still has pending data. closing_endp
|
||||
// is an endpoint that has indicated it is closing (i.e., for
|
||||
// which we have seen a FIN) - for it, data is pending unless
|
||||
// everything's been delivered up to the FIN. For its peer,
|
||||
// the test is whether it has any outstanding, un-acked data.
|
||||
bool DataPending(analyzer::tcp::TCP_Endpoint* closing_endp);
|
||||
// True if either endpoint still has pending data. closing_endp
|
||||
// is an endpoint that has indicated it is closing (i.e., for
|
||||
// which we have seen a FIN) - for it, data is pending unless
|
||||
// everything's been delivered up to the FIN. For its peer,
|
||||
// the test is whether it has any outstanding, un-acked data.
|
||||
bool DataPending(analyzer::tcp::TCP_Endpoint* closing_endp);
|
||||
|
||||
void SetContentsFile(unsigned int direction, FilePtr f) override;
|
||||
FilePtr GetContentsFile(unsigned int direction) const override;
|
||||
void SetContentsFile(unsigned int direction, FilePtr f) override;
|
||||
FilePtr GetContentsFile(unsigned int direction) const override;
|
||||
|
||||
// From Analyzer.h
|
||||
void UpdateConnVal(RecordVal* conn_val) override;
|
||||
// From Analyzer.h
|
||||
void UpdateConnVal(RecordVal* conn_val) override;
|
||||
|
||||
void AddExtraAnalyzers(Connection* conn) override;
|
||||
void AddExtraAnalyzers(Connection* conn) override;
|
||||
|
||||
static int get_segment_len(int payload_len, analyzer::tcp::TCP_Flags flags);
|
||||
static uint64_t get_relative_seq(const analyzer::tcp::TCP_Endpoint* endpoint, uint32_t cur_base,
|
||||
uint32_t last, uint32_t wraps, bool* underflow);
|
||||
static int get_segment_len(int payload_len, analyzer::tcp::TCP_Flags flags);
|
||||
static uint64_t get_relative_seq(const analyzer::tcp::TCP_Endpoint* endpoint, uint32_t cur_base, uint32_t last,
|
||||
uint32_t wraps, bool* underflow);
|
||||
|
||||
protected:
|
||||
friend class analyzer::tcp::TCP_ApplicationAnalyzer;
|
||||
friend class analyzer::tcp::TCP_Endpoint;
|
||||
friend class analyzer::tcp::TCP_Reassembler;
|
||||
friend class analyzer::pia::PIA_TCP;
|
||||
friend class packet_analysis::TCP::TCPAnalyzer;
|
||||
friend class analyzer::tcp::TCP_ApplicationAnalyzer;
|
||||
friend class analyzer::tcp::TCP_Endpoint;
|
||||
friend class analyzer::tcp::TCP_Reassembler;
|
||||
friend class analyzer::pia::PIA_TCP;
|
||||
friend class packet_analysis::TCP::TCPAnalyzer;
|
||||
|
||||
// Analyzer interface.
|
||||
void Init() override;
|
||||
void Done() override;
|
||||
void DeliverPacket(int len, const u_char* data, bool orig, uint64_t seq, const IP_Hdr* ip,
|
||||
int caplen) override;
|
||||
void DeliverStream(int len, const u_char* data, bool orig) override;
|
||||
void Undelivered(uint64_t seq, int len, bool orig) override;
|
||||
void FlipRoles() override;
|
||||
bool IsReuse(double t, const u_char* pkt) override;
|
||||
// Analyzer interface.
|
||||
void Init() override;
|
||||
void Done() override;
|
||||
void DeliverPacket(int len, const u_char* data, bool orig, uint64_t seq, const IP_Hdr* ip, int caplen) override;
|
||||
void DeliverStream(int len, const u_char* data, bool orig) override;
|
||||
void Undelivered(uint64_t seq, int len, bool orig) override;
|
||||
void FlipRoles() override;
|
||||
bool IsReuse(double t, const u_char* pkt) override;
|
||||
|
||||
void SetPartialStatus(analyzer::tcp::TCP_Flags flags, bool is_orig);
|
||||
void SetFirstPacketSeen(bool is_orig);
|
||||
void SetPartialStatus(analyzer::tcp::TCP_Flags flags, bool is_orig);
|
||||
void SetFirstPacketSeen(bool is_orig);
|
||||
|
||||
// Update the state machine of the TCPs based on the activity. This
|
||||
// includes our pseudo-states such as TCP_ENDPOINT_PARTIAL.
|
||||
//
|
||||
// On return, do_close is true if we should consider the connection
|
||||
// as closed, and gen_event if we should generate an event about
|
||||
// this fact.
|
||||
void UpdateStateMachine(double t, analyzer::tcp::TCP_Endpoint* endpoint,
|
||||
analyzer::tcp::TCP_Endpoint* peer, uint32_t base_seq, uint32_t ack_seq,
|
||||
int len, int32_t delta_last, bool is_orig,
|
||||
analyzer::tcp::TCP_Flags flags, bool& do_close, bool& gen_event);
|
||||
// Update the state machine of the TCPs based on the activity. This
|
||||
// includes our pseudo-states such as TCP_ENDPOINT_PARTIAL.
|
||||
//
|
||||
// On return, do_close is true if we should consider the connection
|
||||
// as closed, and gen_event if we should generate an event about
|
||||
// this fact.
|
||||
void UpdateStateMachine(double t, analyzer::tcp::TCP_Endpoint* endpoint, analyzer::tcp::TCP_Endpoint* peer,
|
||||
uint32_t base_seq, uint32_t ack_seq, int len, int32_t delta_last, bool is_orig,
|
||||
analyzer::tcp::TCP_Flags flags, bool& do_close, bool& gen_event);
|
||||
|
||||
void UpdateInactiveState(double t, analyzer::tcp::TCP_Endpoint* endpoint,
|
||||
analyzer::tcp::TCP_Endpoint* peer, uint32_t base_seq, uint32_t ack_seq,
|
||||
int len, bool is_orig, analyzer::tcp::TCP_Flags flags, bool& do_close,
|
||||
bool& gen_event);
|
||||
void UpdateInactiveState(double t, analyzer::tcp::TCP_Endpoint* endpoint, analyzer::tcp::TCP_Endpoint* peer,
|
||||
uint32_t base_seq, uint32_t ack_seq, int len, bool is_orig, analyzer::tcp::TCP_Flags flags,
|
||||
bool& do_close, bool& gen_event);
|
||||
|
||||
void UpdateSYN_SentState(analyzer::tcp::TCP_Endpoint* endpoint,
|
||||
analyzer::tcp::TCP_Endpoint* peer, int len, bool is_orig,
|
||||
analyzer::tcp::TCP_Flags flags, bool& do_close, bool& gen_event);
|
||||
void UpdateSYN_SentState(analyzer::tcp::TCP_Endpoint* endpoint, analyzer::tcp::TCP_Endpoint* peer, int len,
|
||||
bool is_orig, analyzer::tcp::TCP_Flags flags, bool& do_close, bool& gen_event);
|
||||
|
||||
void UpdateEstablishedState(analyzer::tcp::TCP_Endpoint* endpoint,
|
||||
analyzer::tcp::TCP_Endpoint* peer, analyzer::tcp::TCP_Flags flags,
|
||||
bool& do_close, bool& gen_event);
|
||||
void UpdateEstablishedState(analyzer::tcp::TCP_Endpoint* endpoint, analyzer::tcp::TCP_Endpoint* peer,
|
||||
analyzer::tcp::TCP_Flags flags, bool& do_close, bool& gen_event);
|
||||
|
||||
void UpdateClosedState(double t, analyzer::tcp::TCP_Endpoint* endpoint, int32_t delta_last,
|
||||
analyzer::tcp::TCP_Flags flags, bool& do_close);
|
||||
void UpdateClosedState(double t, analyzer::tcp::TCP_Endpoint* endpoint, int32_t delta_last,
|
||||
analyzer::tcp::TCP_Flags flags, bool& do_close);
|
||||
|
||||
void UpdateResetState(int len, analyzer::tcp::TCP_Flags flags);
|
||||
void UpdateResetState(int len, analyzer::tcp::TCP_Flags flags);
|
||||
|
||||
void GeneratePacketEvent(uint64_t rel_seq, uint64_t rel_ack, const u_char* data, int len,
|
||||
int caplen, bool is_orig, analyzer::tcp::TCP_Flags flags);
|
||||
void GeneratePacketEvent(uint64_t rel_seq, uint64_t rel_ack, const u_char* data, int len, int caplen, bool is_orig,
|
||||
analyzer::tcp::TCP_Flags flags);
|
||||
|
||||
bool DeliverData(double t, const u_char* data, int len, int caplen, const IP_Hdr* ip,
|
||||
const struct tcphdr* tp, analyzer::tcp::TCP_Endpoint* endpoint,
|
||||
uint64_t rel_data_seq, bool is_orig, analyzer::tcp::TCP_Flags flags);
|
||||
bool DeliverData(double t, const u_char* data, int len, int caplen, const IP_Hdr* ip, const struct tcphdr* tp,
|
||||
analyzer::tcp::TCP_Endpoint* endpoint, uint64_t rel_data_seq, bool is_orig,
|
||||
analyzer::tcp::TCP_Flags flags);
|
||||
|
||||
void CheckPIA_FirstPacket(bool is_orig, const IP_Hdr* ip);
|
||||
void CheckPIA_FirstPacket(bool is_orig, const IP_Hdr* ip);
|
||||
|
||||
friend class session::detail::Timer;
|
||||
void AttemptTimer(double t);
|
||||
void PartialCloseTimer(double t);
|
||||
void ExpireTimer(double t);
|
||||
void ResetTimer(double t);
|
||||
void DeleteTimer(double t);
|
||||
void ConnDeleteTimer(double t);
|
||||
friend class session::detail::Timer;
|
||||
void AttemptTimer(double t);
|
||||
void PartialCloseTimer(double t);
|
||||
void ExpireTimer(double t);
|
||||
void ResetTimer(double t);
|
||||
void DeleteTimer(double t);
|
||||
void ConnDeleteTimer(double t);
|
||||
|
||||
void EndpointEOF(analyzer::tcp::TCP_Reassembler* endp);
|
||||
void ConnectionClosed(analyzer::tcp::TCP_Endpoint* endpoint, analyzer::tcp::TCP_Endpoint* peer,
|
||||
bool gen_event);
|
||||
void ConnectionFinished(bool half_finished);
|
||||
void ConnectionReset();
|
||||
void PacketWithRST();
|
||||
void EndpointEOF(analyzer::tcp::TCP_Reassembler* endp);
|
||||
void ConnectionClosed(analyzer::tcp::TCP_Endpoint* endpoint, analyzer::tcp::TCP_Endpoint* peer, bool gen_event);
|
||||
void ConnectionFinished(bool half_finished);
|
||||
void ConnectionReset();
|
||||
void PacketWithRST();
|
||||
|
||||
void SetReassembler(analyzer::tcp::TCP_Reassembler* rorig,
|
||||
analyzer::tcp::TCP_Reassembler* rresp);
|
||||
void SetReassembler(analyzer::tcp::TCP_Reassembler* rorig, analyzer::tcp::TCP_Reassembler* rresp);
|
||||
|
||||
uint64_t LastRelDataSeq() const { return rel_data_seq; }
|
||||
uint64_t LastRelDataSeq() const { return rel_data_seq; }
|
||||
|
||||
private:
|
||||
void SynWeirds(analyzer::tcp::TCP_Flags flags, analyzer::tcp::TCP_Endpoint* endpoint,
|
||||
int data_len) const;
|
||||
void SynWeirds(analyzer::tcp::TCP_Flags flags, analyzer::tcp::TCP_Endpoint* endpoint, int data_len) const;
|
||||
|
||||
int ParseTCPOptions(const struct tcphdr* tcp, bool is_orig);
|
||||
int ParseTCPOptions(const struct tcphdr* tcp, bool is_orig);
|
||||
|
||||
void CheckRecording(bool need_contents, analyzer::tcp::TCP_Flags flags);
|
||||
void CheckRecording(bool need_contents, analyzer::tcp::TCP_Flags flags);
|
||||
|
||||
analyzer::tcp::TCP_Endpoint* orig;
|
||||
analyzer::tcp::TCP_Endpoint* resp;
|
||||
analyzer::tcp::TCP_Endpoint* orig;
|
||||
analyzer::tcp::TCP_Endpoint* resp;
|
||||
|
||||
analyzer::analyzer_list packet_children;
|
||||
uint64_t rel_data_seq = 0;
|
||||
analyzer::analyzer_list packet_children;
|
||||
uint64_t rel_data_seq = 0;
|
||||
|
||||
unsigned int first_packet_seen : 2;
|
||||
unsigned int reassembling : 1;
|
||||
unsigned int is_partial : 1;
|
||||
unsigned int is_active : 1;
|
||||
unsigned int finished : 1;
|
||||
unsigned int first_packet_seen : 2;
|
||||
unsigned int reassembling : 1;
|
||||
unsigned int is_partial : 1;
|
||||
unsigned int is_active : 1;
|
||||
unsigned int finished : 1;
|
||||
|
||||
// Whether we're waiting on final data delivery before closing
|
||||
// this connection.
|
||||
unsigned int close_deferred : 1;
|
||||
// Whether we're waiting on final data delivery before closing
|
||||
// this connection.
|
||||
unsigned int close_deferred : 1;
|
||||
|
||||
// Whether to generate an event when we finally do close it.
|
||||
unsigned int deferred_gen_event : 1;
|
||||
// Whether to generate an event when we finally do close it.
|
||||
unsigned int deferred_gen_event : 1;
|
||||
|
||||
// Whether we have seen the first ACK from the originator.
|
||||
unsigned int seen_first_ACK : 1;
|
||||
};
|
||||
// Whether we have seen the first ACK from the originator.
|
||||
unsigned int seen_first_ACK : 1;
|
||||
};
|
||||
|
||||
} // namespace zeek::packet_analysis::tcp
|
||||
} // namespace zeek::packet_analysis::TCP
|
||||
|
|
|
@ -5,22 +5,19 @@
|
|||
#include "zeek/packet_analysis/Component.h"
|
||||
#include "zeek/packet_analysis/protocol/teredo/Teredo.h"
|
||||
|
||||
namespace zeek::plugin::detail::Zeek_Teredo
|
||||
{
|
||||
namespace zeek::plugin::detail::Zeek_Teredo {
|
||||
|
||||
class Plugin final : public zeek::plugin::Plugin
|
||||
{
|
||||
class Plugin final : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure() override
|
||||
{
|
||||
AddComponent(new zeek::packet_analysis::Component(
|
||||
"Teredo", zeek::packet_analysis::teredo::TeredoAnalyzer::Instantiate));
|
||||
zeek::plugin::Configuration Configure() override {
|
||||
AddComponent(
|
||||
new zeek::packet_analysis::Component("Teredo", zeek::packet_analysis::teredo::TeredoAnalyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::Teredo";
|
||||
config.description = "Teredo packet analyzer";
|
||||
return config;
|
||||
}
|
||||
} plugin;
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::Teredo";
|
||||
config.description = "Teredo packet analyzer";
|
||||
return config;
|
||||
}
|
||||
} plugin;
|
||||
|
||||
} // namespace zeek::plugin::detail::Zeek_Teredo
|
||||
} // namespace zeek::plugin::detail::Zeek_Teredo
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue