Add base class for IP-based packet analyzers

This commit is contained in:
Tim Wojtulewicz 2021-04-13 15:36:31 -07:00
parent 3e1692676d
commit c1f0d312b5
23 changed files with 781 additions and 421 deletions

View file

@ -10,7 +10,8 @@
namespace zeek::packet_analysis {
Analyzer::Analyzer(std::string name)
Analyzer::Analyzer(std::string name, bool report_unknown_protocols) :
report_unknown_protocols(report_unknown_protocols)
{
Tag t = packet_mgr->GetComponentTag(name);
@ -80,10 +81,15 @@ bool Analyzer::ForwardPacket(size_t len, const uint8_t* data, Packet* packet,
if ( inner_analyzer == nullptr )
{
DBG_LOG(DBG_PACKET_ANALYSIS, "Analysis in %s failed, could not find analyzer for identifier %#x.",
GetAnalyzerName(), identifier);
packet_mgr->ReportUnknownProtocol(GetAnalyzerName(), identifier, data, len);
return false;
if ( report_unknown_protocols )
{
DBG_LOG(DBG_PACKET_ANALYSIS, "Analysis in %s failed, could not find analyzer for identifier %#x.",
GetAnalyzerName(), identifier);
packet_mgr->ReportUnknownProtocol(GetAnalyzerName(), identifier, data, len);
return false;
}
else
return true;
}
DBG_LOG(DBG_PACKET_ANALYSIS, "Analysis in %s succeeded, next layer identifier is %#x.",
@ -99,7 +105,9 @@ bool Analyzer::ForwardPacket(size_t len, const uint8_t* data, Packet* packet) co
DBG_LOG(DBG_PACKET_ANALYSIS, "Analysis in %s stopped, no default analyzer available.",
GetAnalyzerName());
Weird("no_suitable_analyzer_found", packet);
if ( report_unknown_protocols )
Weird("no_suitable_analyzer_found", packet);
return true;
}

View file

@ -17,8 +17,11 @@ public:
*
* @param name The name for the type of analyzer. The name must match
* the one the corresponding Component registers.
* @param report_unknown_protocols Flag for whether to report unknown
* protocols during packet forwarding. This should generally always be
* set to true.
*/
explicit Analyzer(std::string name);
explicit Analyzer(std::string name, bool report_unknown_protocols=true);
/**
* Constructor.
@ -165,6 +168,11 @@ private:
Dispatcher dispatcher;
AnalyzerPtr default_analyzer = nullptr;
/**
* Flag for whether to report unknown protocols in ForwardPacket.
*/
bool report_unknown_protocols = true;
void Init(const Tag& tag);
};

View file

@ -101,7 +101,7 @@ void Manager::ProcessPacket(Packet* packet)
bool dumped_packet = false;
if ( packet->dump_packet || zeek::detail::record_all_packets )
{
DumpPacket(packet);
DumpPacket(packet, packet->dump_size);
dumped_packet = true;
}
@ -114,7 +114,7 @@ void Manager::ProcessPacket(Packet* packet)
// Check whether packet should be recorded based on session analysis
if ( packet->dump_packet && ! dumped_packet )
DumpPacket(packet);
DumpPacket(packet, packet->dump_size);
}
bool Manager::ProcessInnerPacket(Packet* packet)

View file

@ -1,13 +1,16 @@
// See the file "COPYING" in the main distribution directory for copyright.
#include "zeek/packet_analysis/protocol/icmp/ICMP.h"
#include <netinet/icmp6.h>
#include "zeek/RunState.h"
#include "zeek/session/Manager.h"
using namespace zeek::packet_analysis::ICMP;
using namespace zeek::packet_analysis::IP;
ICMPAnalyzer::ICMPAnalyzer()
: zeek::packet_analysis::Analyzer("ICMP_PKT")
ICMPAnalyzer::ICMPAnalyzer() : IPBasedAnalyzer("ICMP", TRANSPORT_ICMP, ICMP_PORT_MASK, false)
{
}
@ -17,6 +20,96 @@ ICMPAnalyzer::~ICMPAnalyzer()
bool ICMPAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet)
{
session_mgr->ProcessTransportLayer(run_state::processing_start_time, packet, len);
if ( ! CheckHeaderTrunc(ICMP_MINLEN, len, packet) )
return false;
ConnTuple id;
id.src_addr = packet->ip_hdr->SrcAddr();
id.dst_addr = packet->ip_hdr->DstAddr();
id.proto = TRANSPORT_ICMP;
const struct icmp* icmpp = (const struct icmp *) data;
id.src_port = htons(icmpp->icmp_type);
if ( packet->proto == IPPROTO_ICMP )
id.dst_port = htons(ICMP4_counterpart(icmpp->icmp_type, icmpp->icmp_code, id.is_one_way));
else if ( packet->proto == IPPROTO_ICMPV6 )
id.dst_port = htons(ICMP6_counterpart(icmpp->icmp_type, icmpp->icmp_code, id.is_one_way));
else
reporter->InternalError("Reached ICMP packet analyzer with unknown packet protocol %x",
packet->proto);
ProcessConnection(id, packet, len);
return true;
}
void ICMPAnalyzer::ContinueProcessing(Connection* c, double t, bool is_orig, int remaining, Packet* pkt)
{
}
void ICMPAnalyzer::CreateTransportAnalyzer(Connection* conn, IPBasedTransportAnalyzer*& root,
analyzer::pia::PIA*& pia, bool& check_port)
{
}
int ICMPAnalyzer::ICMP4_counterpart(int icmp_type, int icmp_code, bool& is_one_way)
{
is_one_way = false;
// Return the counterpart type if one exists. This allows us
// to track corresponding ICMP requests/replies.
// Note that for the two-way ICMP messages, icmp_code is
// always 0 (RFC 792).
switch ( icmp_type ) {
case ICMP_ECHO: return ICMP_ECHOREPLY;
case ICMP_ECHOREPLY: return ICMP_ECHO;
case ICMP_TSTAMP: return ICMP_TSTAMPREPLY;
case ICMP_TSTAMPREPLY: return ICMP_TSTAMP;
case ICMP_IREQ: return ICMP_IREQREPLY;
case ICMP_IREQREPLY: return ICMP_IREQ;
case ICMP_ROUTERSOLICIT: return ICMP_ROUTERADVERT;
case ICMP_ROUTERADVERT: return ICMP_ROUTERSOLICIT;
case ICMP_MASKREQ: return ICMP_MASKREPLY;
case ICMP_MASKREPLY: return ICMP_MASKREQ;
default: is_one_way = true; return icmp_code;
}
}
int ICMPAnalyzer::ICMP6_counterpart(int icmp_type, int icmp_code, bool& is_one_way)
{
is_one_way = false;
switch ( icmp_type ) {
case ICMP6_ECHO_REQUEST: return ICMP6_ECHO_REPLY;
case ICMP6_ECHO_REPLY: return ICMP6_ECHO_REQUEST;
case ND_ROUTER_SOLICIT: return ND_ROUTER_ADVERT;
case ND_ROUTER_ADVERT: return ND_ROUTER_SOLICIT;
case ND_NEIGHBOR_SOLICIT: return ND_NEIGHBOR_ADVERT;
case ND_NEIGHBOR_ADVERT: return ND_NEIGHBOR_SOLICIT;
case MLD_LISTENER_QUERY: return MLD_LISTENER_REPORT;
case MLD_LISTENER_REPORT: return MLD_LISTENER_QUERY;
// ICMP node information query and response respectively (not defined in
// icmp6.h)
case 139: return 140;
case 140: return 139;
// Home Agent Address Discovery Request Message and reply
case 144: return 145;
case 145: return 144;
// TODO: Add further counterparts.
default: is_one_way = true; return icmp_code;
}
}

View file

@ -4,10 +4,11 @@
#include "zeek/packet_analysis/Analyzer.h"
#include "zeek/packet_analysis/Component.h"
#include "zeek/packet_analysis/protocol/ip/IPBasedAnalyzer.h"
namespace zeek::packet_analysis::ICMP {
class ICMPAnalyzer : public Analyzer {
class ICMPAnalyzer final : public IP::IPBasedAnalyzer {
public:
ICMPAnalyzer();
~ICMPAnalyzer() override;
@ -19,8 +20,21 @@ public:
return std::make_shared<ICMPAnalyzer>();
}
void CreateTransportAnalyzer(Connection* conn, IP::IPBasedTransportAnalyzer*& root,
analyzer::pia::PIA*& pia, bool& check_port) override;
protected:
void ContinueProcessing(Connection* c, double t, bool is_orig, int remaining,
Packet* pkt) override;
private:
// Returns the counterpart type to the given type (e.g., the counterpart
// to ICMP_ECHOREPLY is ICMP_ECHO).
int ICMP4_counterpart(int icmp_type, int icmp_code, bool& is_one_way);
int ICMP6_counterpart(int icmp_type, int icmp_code, bool& is_one_way);
};
}

View file

@ -10,7 +10,7 @@ class Plugin : public zeek::plugin::Plugin {
public:
zeek::plugin::Configuration Configure()
{
AddComponent(new zeek::packet_analysis::Component("ICMP_PKT",
AddComponent(new zeek::packet_analysis::Component("ICMP",
zeek::packet_analysis::ICMP::ICMPAnalyzer::Instantiate));
zeek::plugin::Configuration config;

View file

@ -4,5 +4,5 @@ include(ZeekPlugin)
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
zeek_plugin_begin(PacketAnalyzer IP)
zeek_plugin_cc(IP.cc Plugin.cc)
zeek_plugin_cc(IP.cc IPBasedAnalyzer.cc Plugin.cc)
zeek_plugin_end()

View file

@ -0,0 +1,209 @@
// See the file "COPYING" in the main distribution directory for copyright.
#include "zeek/packet_analysis/protocol/ip/IPBasedAnalyzer.h"
#include "zeek/RunState.h"
#include "zeek/Conn.h"
#include "zeek/Val.h"
#include "zeek/session/Manager.h"
#include "zeek/analyzer/Manager.h"
using namespace zeek;
using namespace zeek::packet_analysis::IP;
IPBasedAnalyzer::IPBasedAnalyzer(const char* name, TransportProto proto, uint32_t mask,
bool report_unknown_protocols)
: zeek::packet_analysis::Analyzer(name, report_unknown_protocols),
transport(proto), server_port_mask(mask)
{
}
IPBasedAnalyzer::~IPBasedAnalyzer()
{
}
void IPBasedAnalyzer::ProcessConnection(const ConnTuple& conn_id, Packet* pkt, size_t remaining)
{
const std::unique_ptr<IP_Hdr>& ip_hdr = pkt->ip_hdr;
detail::ConnKey key(conn_id);
Connection* conn = session_mgr->FindConnection(key);
if ( ! conn )
{
conn = NewConn(&conn_id, key, pkt);
if ( conn )
session_mgr->Insert(conn, false);
}
else
{
if ( conn->IsReuse(run_state::processing_start_time, ip_hdr->Payload()) )
{
conn->Event(connection_reused, nullptr);
session_mgr->Remove(conn);
conn = NewConn(&conn_id, key, pkt);
if ( conn )
session_mgr->Insert(conn, false);
}
else
{
conn->CheckEncapsulation(pkt->encap);
}
}
if ( ! conn )
return;
bool is_orig = (conn_id.src_addr == conn->OrigAddr()) &&
(conn_id.src_port == conn->OrigPort());
conn->CheckFlowLabel(is_orig, ip_hdr->FlowLabel());
zeek::ValPtr pkt_hdr_val;
if ( ipv6_ext_headers && ip_hdr->NumHeaders() > 1 )
{
pkt_hdr_val = ip_hdr->ToPktHdrVal();
conn->EnqueueEvent(ipv6_ext_headers, nullptr, conn->GetVal(),
pkt_hdr_val);
}
if ( new_packet )
conn->EnqueueEvent(new_packet, nullptr, conn->GetVal(),
pkt_hdr_val ? std::move(pkt_hdr_val) : ip_hdr->ToPktHdrVal());
if ( new_plugin )
{
conn->SetRecordPackets(true);
conn->SetRecordContents(true);
const u_char* data = pkt->ip_hdr->Payload();
run_state::current_timestamp = run_state::processing_start_time;
run_state::current_pkt = pkt;
// TODO: Does this actually mean anything?
if ( conn->Skipping() )
return;
ContinueProcessing(conn, run_state::processing_start_time, is_orig, remaining, pkt);
run_state::current_timestamp = 0;
run_state::current_pkt = nullptr;
// If the packet is reassembled, disable packet dumping because the
// pointer math to dump the data wouldn't work.
if ( pkt->ip_hdr->reassembled )
pkt->dump_packet = false;
else if ( conn->RecordPackets() )
{
pkt->dump_packet = true;
// If we don't want the content, set the dump size to include just
// the header.
if ( ! conn->RecordContents() )
pkt->dump_size = data - pkt->data;
}
}
else
{
int record_packet = 1; // whether to record the packet at all
int record_content = 1; // whether to record its data
const u_char* data = pkt->ip_hdr->Payload();
conn->NextPacket(run_state::processing_start_time, is_orig, ip_hdr.get(), ip_hdr->PayloadLen(),
remaining, data, record_packet, record_content, pkt);
// If the packet is reassembled, disable packet dumping because the
// pointer math to dump the data wouldn't work.
if ( ip_hdr->reassembled )
pkt->dump_packet = false;
else if ( record_packet )
{
pkt->dump_packet = true;
// If we don't want the content, set the dump size to include just
// the header.
if ( ! record_content )
pkt->dump_size = data - pkt->data;
}
}
}
bool IPBasedAnalyzer::CheckHeaderTrunc(size_t min_hdr_len, size_t remaining, Packet* packet)
{
if ( packet->ip_hdr->PayloadLen() < min_hdr_len )
{
Weird("truncated_header", packet);
return false;
}
else if ( remaining < min_hdr_len )
{
Weird("internally_truncated_header", packet);
return false;
}
return true;
}
bool IPBasedAnalyzer::IsLikelyServerPort(uint32_t port) const
{
// We keep a cached in-core version of the table to speed up the lookup.
static std::set<bro_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;
}
// We exploit our knowledge of PortVal's internal storage mechanism here.
port |= server_port_mask;
return port_cache.find(port) != port_cache.end();
}
zeek::Connection* IPBasedAnalyzer::NewConn(const ConnTuple* id, const detail::ConnKey& key,
const Packet* pkt)
{
int src_h = ntohs(id->src_port);
int dst_h = ntohs(id->dst_port);
bool flip = false;
if ( ! WantConnection(src_h, dst_h, pkt->ip_hdr->Payload(), flip) )
return nullptr;
Connection* conn = new Connection(key, run_state::processing_start_time,
id, pkt->ip_hdr->FlowLabel(), pkt);
conn->SetTransport(transport);
if ( flip )
conn->FlipRoles();
if ( ! new_plugin )
{
if ( ! analyzer_mgr->BuildInitialAnalyzerTree(conn) )
{
conn->Done();
Unref(conn);
return nullptr;
}
}
else if ( ! analyzer_mgr->BuildSessionAnalyzerTree(conn, this) )
{
conn->Done();
Unref(conn);
return nullptr;
}
if ( new_connection )
conn->Event(new_connection, nullptr);
return conn;
}

View file

@ -0,0 +1,182 @@
// See the file "COPYING" in the main distribution directory for copyright.
#pragma once
#include "zeek/packet_analysis/Analyzer.h"
#include "zeek/packet_analysis/Component.h"
#include "zeek/analyzer/Analyzer.h"
#include "zeek/analyzer/Manager.h"
namespace zeek::analyzer::pia { class PIA; }
namespace zeek::packet_analysis::IP {
class IPBasedTransportAnalyzer;
/**
* A base class for any packet analyzer based on IP. This is used by default by
* the TCP, UDP, and ICMP analyzers to reduce a large amount of duplicated code
* that those plugins have in common.
*/
class IPBasedAnalyzer : public Analyzer {
public:
~IPBasedAnalyzer() override;
/**
* Returns true if the analyzer determines that in fact a new
* connection has started without the connection statement having
* terminated the previous one, i.e., the new data is arriving at
* what's the analyzer for the previous instance. This is used only
* for TCP.
*/
virtual bool IsReuse(double t, const u_char* pkt) { return false; }
/**
* TODO: comment
*/
virtual void CreateTransportAnalyzer(Connection* conn, IPBasedTransportAnalyzer*& root,
analyzer::pia::PIA*& pia, bool& check_port) = 0;
protected:
/**
* Construct a new IP-based analyzer.
*
* @param name The name for the type of analyzer. The name must match
* the one the corresponding Component registers.
* @param proto The transport protocol implemented by this analyzer.
* @param mask The mask used to determine if a port is a server port
* for this protocol. This is used by IsLikelyServerPort().
* @param report_unknown_protocols Flag for whether to report unknown
* protocols during packet forwarding. This is typically false for IP
* protocols since packets may go into the session analysis framework
* as well.
*/
IPBasedAnalyzer(const char* name, TransportProto proto, uint32_t mask,
bool report_unknown_protocols);
/**
* Entry point for child classes to call to do the actual heavy lifting for
* processing a packet and extracting a connection out of it.
*
* @param conn_id The connection ID generated by the child class.
* @param pkt The packet being processed.
* @param remaining The number of bytes remaining to be processed in the packet.
*/
void ProcessConnection(const ConnTuple& conn_id, Packet* pkt, size_t remaining);
/**
* Verifies that there is enough data in the packet to process the header
* length requested.
*
* @param min_hdr_len The minimum data in bytes that needs to exist.
* @param remaining The remaining number of bytes in the packet reported by
* previous analyzer.
* @param packet The packet being processed. This will be used to pull out the
* number of bytes the IP header says we have remaining.
*/
bool CheckHeaderTrunc(size_t min_hdr_len, size_t remaining, Packet* packet);
/**
* Upon seeing the first packet of a connection, checks whether we want
* to analyze it (e.g. we may not want to look at partial connections)
* and, if yes, whether we should flip the roles of originator and
* responder based on known ports and such.
*
* @param src_port The source port of the connection.
* @param dst_port The destination port of the connection.
* @param data The payload data for the packet being processed.
* @param flip_roles Return value if the roles should be flipped.
* @return True if the connection is wanted. False otherwise.
*/
virtual bool WantConnection(uint16_t src_port, uint16_t dst_port,
const u_char* data, bool& flip_roles) const
{
flip_roles = false;
return true;
}
/**
* Returns true if the port corresponds to an application for which there
* is a Zeek analyzer (even if it might not be used by the present policy
* script) or if it's generally a likely server port.
*
* @param port The port number to check, in host order.
*/
bool IsLikelyServerPort(uint32_t port) const;
/**
* Continues process of packet after the connection has been inserted into the
* session manager. This should be implemented by all child classes.
*
* @param conn The connection currently being processed.
* @param t The timestamp for the current packet.
* @param is_orig Flag denoting whether this packet is from the originator of
* the connection.
* @param remaining The remaining about of data in the packet.
* @param pkt The packet being processed.
*/
virtual void ContinueProcessing(Connection* conn, double t, bool is_orig, int remaining,
Packet* pkt) {}
// TODO: temporary, until all of the plugins are implemented
bool new_plugin = false;
private:
/**
* Creates a new Connection object from data gleaned from the current packet.
*
* @param id A connection ID generated from the packet data. This should have been
* passed in from a child analyzer.
* @param key A connection ID key generated from the ID.
* @param pkt The packet associated with the new connection.
*/
zeek::Connection* NewConn(const ConnTuple* id, const detail::ConnKey& key,
const Packet* pkt);
TransportProto transport;
uint32_t server_port_mask;
};
/**
* This class represents the interface between the packet analysis framework and
* the session analysis framework. One of these should be implemented for each
* packet analyzer that intends to forward into the session analysis.
*/
class IPBasedTransportAnalyzer : public zeek::analyzer::TransportLayerAnalyzer {
public:
IPBasedTransportAnalyzer(const char* name, Connection* conn)
: TransportLayerAnalyzer(name, conn) { }
/**
* Sets the parent packet analyzer for this transport analyzer. This can't be passed to
* the constructor due to the way that TransportLayerAnalyzer gets instantiated.
*
* @param p The parent packet analyzer to store
*/
void SetParent(IPBasedAnalyzer* p) { parent = p; }
/**
* Returns true if the analyzer determines that in fact a new connection has started
* without the connection statement having terminated the previous one, i.e., the new
* data is arriving at what's the analyzer for the previous instance. This is used only
* for TCP.
*/
bool IsReuse(double t, const u_char* pkt) override { return parent->IsReuse(t, pkt); }
/**
* Pure virtual method to allow extra session analzyers to be added to this analyzer's
* tree of children. This is used by analyzer::Manager when creating the session analyzer
* tree.
*/
virtual void AddExtraAnalyzers(Connection* conn) = 0;
protected:
IPBasedAnalyzer* parent;
};
}

View file

@ -10,7 +10,7 @@ class Plugin : public zeek::plugin::Plugin {
public:
zeek::plugin::Configuration Configure()
{
AddComponent(new zeek::packet_analysis::Component("TCP_PKT",
AddComponent(new zeek::packet_analysis::Component("TCP",
zeek::packet_analysis::TCP::TCPAnalyzer::Instantiate));
zeek::plugin::Configuration config;

View file

@ -2,12 +2,11 @@
#include "zeek/packet_analysis/protocol/tcp/TCP.h"
#include "zeek/RunState.h"
#include "zeek/session/Manager.h"
using namespace zeek::packet_analysis::TCP;
using namespace zeek::packet_analysis::IP;
TCPAnalyzer::TCPAnalyzer()
: zeek::packet_analysis::Analyzer("TCP_PKT")
TCPAnalyzer::TCPAnalyzer() : IPBasedAnalyzer("TCP", TRANSPORT_TCP, TCP_PORT_MASK, false)
{
}
@ -17,6 +16,68 @@ TCPAnalyzer::~TCPAnalyzer()
bool TCPAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet)
{
session_mgr->ProcessTransportLayer(run_state::processing_start_time, packet, len);
uint32_t min_hdr_len = sizeof(struct tcphdr);
if ( ! CheckHeaderTrunc(min_hdr_len, len, packet) )
return false;
ConnTuple id;
id.src_addr = packet->ip_hdr->SrcAddr();
id.dst_addr = packet->ip_hdr->DstAddr();
data = packet->ip_hdr->Payload();
const struct tcphdr* tp = (const struct tcphdr *) data;
id.src_port = tp->th_sport;
id.dst_port = tp->th_dport;
id.is_one_way = false;
id.proto = TRANSPORT_TCP;
ProcessConnection(id, packet, len);
return true;
}
bool TCPAnalyzer::WantConnection(uint16_t src_port, uint16_t dst_port,
const u_char* data, bool& flip_roles) const
{
flip_roles = false;
const struct tcphdr* tp = (const struct tcphdr*) data;
uint8_t tcp_flags = tp->th_flags;
if ( ! (tcp_flags & TH_SYN) || (tcp_flags & TH_ACK) )
{
// The new connection is starting either without a SYN,
// or with a SYN ack. This means it's a partial connection.
if ( ! zeek::detail::partial_connection_ok )
return false;
if ( tcp_flags & TH_SYN && ! zeek::detail::tcp_SYN_ack_ok )
return false;
// Try to guess true responder by the port numbers.
// (We might also think that for SYN acks we could
// safely flip the roles, but that doesn't work
// for stealth scans.)
if ( IsLikelyServerPort(src_port) )
{ // connection is a candidate for flipping
if ( IsLikelyServerPort(dst_port) )
// Hmmm, both source and destination
// are plausible. Heuristic: flip only
// if (1) this isn't a SYN ACK (to avoid
// confusing stealth scans) and
// (2) dest port > src port (to favor
// more plausible servers).
flip_roles = ! (tcp_flags & TH_SYN) && src_port < dst_port;
else
// Source is plausible, destination isn't.
flip_roles = true;
}
}
return true;
}
void TCPAnalyzer::CreateTransportAnalyzer(Connection* conn, IPBasedTransportAnalyzer*& root,
analyzer::pia::PIA*& pia, bool& check_port)
{
}

View file

@ -4,10 +4,11 @@
#include "zeek/packet_analysis/Analyzer.h"
#include "zeek/packet_analysis/Component.h"
#include "zeek/packet_analysis/protocol/ip/IPBasedAnalyzer.h"
namespace zeek::packet_analysis::TCP {
class TCPAnalyzer : public Analyzer {
class TCPAnalyzer final : public IP::IPBasedAnalyzer {
public:
TCPAnalyzer();
~TCPAnalyzer() override;
@ -19,8 +20,25 @@ public:
return std::make_shared<TCPAnalyzer>();
}
private:
void CreateTransportAnalyzer(Connection* conn, IP::IPBasedTransportAnalyzer*& root,
analyzer::pia::PIA*& pia, bool& check_port) override;
protected:
/**
* Upon seeing the first packet of a connection, checks whether we want
* to analyze it (e.g. we may not want to look at partial connections)
* and, if yes, whether we should flip the roles of originator and
* responder based on known ports and such.
*
* @param src_port The source port of the connection.
* @param dst_port The destination port of the connection.
* @param data The payload data for the packet being processed.
* @param flip_roles Return value if the roles should be flipped.
* @return True if the connection is wanted. False otherwise.
*/
bool WantConnection(uint16_t src_port, uint16_t dst_port,
const u_char* data, bool& flip_roles) const override;
};
}

View file

@ -10,7 +10,7 @@ class Plugin : public zeek::plugin::Plugin {
public:
zeek::plugin::Configuration Configure()
{
AddComponent(new zeek::packet_analysis::Component("UDP_PKT",
AddComponent(new zeek::packet_analysis::Component("UDP",
zeek::packet_analysis::UDP::UDPAnalyzer::Instantiate));
zeek::plugin::Configuration config;

View file

@ -2,12 +2,11 @@
#include "zeek/packet_analysis/protocol/udp/UDP.h"
#include "zeek/RunState.h"
#include "zeek/session/Manager.h"
using namespace zeek::packet_analysis::UDP;
using namespace zeek::packet_analysis::IP;
UDPAnalyzer::UDPAnalyzer()
: zeek::packet_analysis::Analyzer("UDP_PKT")
UDPAnalyzer::UDPAnalyzer() : IPBasedAnalyzer("UDP", TRANSPORT_UDP, UDP_PORT_MASK, false)
{
}
@ -17,6 +16,31 @@ UDPAnalyzer::~UDPAnalyzer()
bool UDPAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet)
{
session_mgr->ProcessTransportLayer(run_state::processing_start_time, packet, len);
uint32_t min_hdr_len = sizeof(struct udphdr);
if ( ! CheckHeaderTrunc(min_hdr_len, len, packet) )
return false;
ConnTuple id;
id.src_addr = packet->ip_hdr->SrcAddr();
id.dst_addr = packet->ip_hdr->DstAddr();
const struct udphdr* up = (const struct udphdr *) packet->ip_hdr->Payload();
id.src_port = up->uh_sport;
id.dst_port = up->uh_dport;
id.is_one_way = false;
id.proto = TRANSPORT_UDP;
ProcessConnection(id, packet, len);
return true;
}
void UDPAnalyzer::CreateTransportAnalyzer(Connection* conn, IPBasedTransportAnalyzer*& root,
analyzer::pia::PIA*& pia, bool& check_port)
{
}
bool UDPAnalyzer::WantConnection(uint16_t src_port, uint16_t dst_port,
const u_char* data, bool& flip_roles) const
{
flip_roles = IsLikelyServerPort(src_port) && ! IsLikelyServerPort(dst_port);
return true;
}

View file

@ -4,10 +4,11 @@
#include "zeek/packet_analysis/Analyzer.h"
#include "zeek/packet_analysis/Component.h"
#include "zeek/packet_analysis/protocol/ip/IPBasedAnalyzer.h"
namespace zeek::packet_analysis::UDP {
class UDPAnalyzer : public Analyzer {
class UDPAnalyzer : public IP::IPBasedAnalyzer {
public:
UDPAnalyzer();
~UDPAnalyzer() override;
@ -19,8 +20,25 @@ public:
return std::make_shared<UDPAnalyzer>();
}
private:
void CreateTransportAnalyzer(Connection* conn, IP::IPBasedTransportAnalyzer*& root,
analyzer::pia::PIA*& pia, bool& check_port) override;
protected:
/**
* Upon seeing the first packet of a connection, checks whether we want
* to analyze it (e.g. we may not want to look at partial connections)
* and, if yes, whether we should flip the roles of originator and
* responder based on known ports and such.
*
* @param src_port The source port of the connection.
* @param dst_port The destination port of the connection.
* @param data The payload data for the packet being processed.
* @param flip_roles Return value if the roles should be flipped.
* @return True if the connection is wanted. False otherwise.
*/
bool WantConnection(uint16_t src_port, uint16_t dst_port,
const u_char* data, bool& flip_roles) const override;
};
}