mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
Extend PIA's FirstPacket
API.
`FirstPacket()` so far supported only TCP. To extend this to UDP, we move the method into the PIA base class; give it a protocol parameter for the case that there's no actual packet is available; and add the ability to create fake UDP packets as well, not just TCP. This whole thing is pretty ugly to begin with, and this doesn't make it nicer, but we need this extension that so we can feed UDP data into the signature engine that's tunneled over other protocols. Without the fake packets, DPD signatures in particular wouldn't have anything to match on.
This commit is contained in:
parent
8dd3debeae
commit
2ec44f098f
6 changed files with 137 additions and 57 deletions
|
@ -946,8 +946,8 @@ void HTTP_Analyzer::DeliverStream(int len, const u_char* data, bool is_orig) {
|
||||||
pia = new analyzer::pia::PIA_TCP(Conn());
|
pia = new analyzer::pia::PIA_TCP(Conn());
|
||||||
|
|
||||||
if ( AddChildAnalyzer(pia) ) {
|
if ( AddChildAnalyzer(pia) ) {
|
||||||
pia->FirstPacket(true, nullptr);
|
pia->FirstPacket(true, TransportProto::TRANSPORT_TCP);
|
||||||
pia->FirstPacket(false, nullptr);
|
pia->FirstPacket(false, TransportProto::TRANSPORT_TCP);
|
||||||
|
|
||||||
int remaining_in_content_line = content_line_resp->GetDeliverStreamRemainingLength();
|
int remaining_in_content_line = content_line_resp->GetDeliverStreamRemainingLength();
|
||||||
if ( remaining_in_content_line > 0 ) {
|
if ( remaining_in_content_line > 0 ) {
|
||||||
|
@ -1396,8 +1396,8 @@ void HTTP_Analyzer::HTTP_Upgrade() {
|
||||||
upgrade_protocol.c_str());
|
upgrade_protocol.c_str());
|
||||||
pia = new analyzer::pia::PIA_TCP(Conn());
|
pia = new analyzer::pia::PIA_TCP(Conn());
|
||||||
if ( AddChildAnalyzer(pia) ) {
|
if ( AddChildAnalyzer(pia) ) {
|
||||||
pia->FirstPacket(true, nullptr);
|
pia->FirstPacket(true, TransportProto::TRANSPORT_TCP);
|
||||||
pia->FirstPacket(false, nullptr);
|
pia->FirstPacket(false, TransportProto::TRANSPORT_TCP);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -169,52 +169,112 @@ void PIA_TCP::Init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PIA_TCP::FirstPacket(bool is_orig, const IP_Hdr* ip) {
|
void PIA::FirstPacket(bool is_orig, TransportProto proto) { FirstPacket(is_orig, proto, nullptr); }
|
||||||
|
|
||||||
|
void PIA::FirstPacket(bool is_orig, const IP_Hdr* ip) {
|
||||||
|
assert(ip);
|
||||||
|
FirstPacket(is_orig, {}, ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PIA::FirstPacket(bool is_orig, const std::optional<TransportProto>& proto, const IP_Hdr* ip) {
|
||||||
static char dummy_packet[sizeof(struct ip) + sizeof(struct tcphdr)];
|
static char dummy_packet[sizeof(struct ip) + sizeof(struct tcphdr)];
|
||||||
static struct ip* ip4 = nullptr;
|
static struct ip* ip4_tcp = nullptr;
|
||||||
|
static struct ip* ip4_udp = nullptr;
|
||||||
static struct tcphdr* tcp4 = nullptr;
|
static struct tcphdr* tcp4 = nullptr;
|
||||||
static IP_Hdr* ip4_hdr = nullptr;
|
static struct udphdr* udp4 = nullptr;
|
||||||
|
static IP_Hdr* ip4_tcp_hdr = nullptr;
|
||||||
|
static IP_Hdr* ip4_udp_hdr = nullptr;
|
||||||
|
|
||||||
DBG_LOG(DBG_ANALYZER, "PIA_TCP[%d] FirstPacket(%s)", GetID(), (is_orig ? "T" : "F"));
|
if ( ! ip && proto ) { // proto needed here to avoid GCC warning that it may be used uninitialized
|
||||||
|
|
||||||
if ( ! ip ) {
|
|
||||||
// Create a dummy packet. Not very elegant, but everything
|
// Create a dummy packet. Not very elegant, but everything
|
||||||
// else would be *really* ugly ...
|
// else would be *really* ugly ...
|
||||||
if ( ! ip4_hdr ) {
|
switch ( *proto ) {
|
||||||
ip4 = (struct ip*)dummy_packet;
|
case TransportProto::TRANSPORT_TCP: {
|
||||||
tcp4 = (struct tcphdr*)(dummy_packet + sizeof(struct ip));
|
DBG_LOG(DBG_ANALYZER, "PIA/TCP FirstPacket(%s)", (is_orig ? "T" : "F"));
|
||||||
ip4->ip_len = sizeof(struct ip) + sizeof(struct tcphdr);
|
|
||||||
ip4->ip_hl = sizeof(struct ip) >> 2;
|
|
||||||
ip4->ip_p = IPPROTO_TCP;
|
|
||||||
|
|
||||||
// Cast to const so that it doesn't delete it.
|
if ( ! ip4_tcp_hdr ) {
|
||||||
ip4_hdr = new IP_Hdr(ip4, false);
|
ip4_tcp = (struct ip*)dummy_packet;
|
||||||
|
tcp4 = (struct tcphdr*)(dummy_packet + sizeof(struct ip));
|
||||||
|
ip4_tcp->ip_len = sizeof(struct ip) + sizeof(struct tcphdr);
|
||||||
|
ip4_tcp->ip_hl = sizeof(struct ip) >> 2;
|
||||||
|
|
||||||
|
// Cast to const so that it doesn't delete it.
|
||||||
|
ip4_tcp_hdr = new IP_Hdr(ip4_tcp, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Locals used to avoid potential alignment problems
|
||||||
|
// with some archs/compilers when grabbing the address
|
||||||
|
// of the struct member directly in the following.
|
||||||
|
in_addr tmp_src;
|
||||||
|
in_addr tmp_dst;
|
||||||
|
|
||||||
|
if ( is_orig ) {
|
||||||
|
Conn()->OrigAddr().CopyIPv4(&tmp_src);
|
||||||
|
Conn()->RespAddr().CopyIPv4(&tmp_dst);
|
||||||
|
tcp4->th_sport = htons(Conn()->OrigPort());
|
||||||
|
tcp4->th_dport = htons(Conn()->RespPort());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Conn()->RespAddr().CopyIPv4(&tmp_src);
|
||||||
|
Conn()->OrigAddr().CopyIPv4(&tmp_dst);
|
||||||
|
tcp4->th_sport = htons(Conn()->RespPort());
|
||||||
|
tcp4->th_dport = htons(Conn()->OrigPort());
|
||||||
|
}
|
||||||
|
|
||||||
|
ip4_tcp->ip_src = tmp_src;
|
||||||
|
ip4_tcp->ip_dst = tmp_dst;
|
||||||
|
ip4_tcp->ip_p = IPPROTO_TCP;
|
||||||
|
ip = ip4_tcp_hdr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TransportProto::TRANSPORT_UDP: {
|
||||||
|
DBG_LOG(DBG_ANALYZER, "PIA/UDP FirstPacket(%s)", (is_orig ? "T" : "F"));
|
||||||
|
|
||||||
|
if ( ! ip4_udp_hdr ) {
|
||||||
|
ip4_udp = (struct ip*)dummy_packet;
|
||||||
|
udp4 = (struct udphdr*)(dummy_packet + sizeof(struct ip));
|
||||||
|
ip4_udp->ip_len = sizeof(struct ip) + sizeof(struct udphdr);
|
||||||
|
ip4_udp->ip_hl = sizeof(struct ip) >> 2;
|
||||||
|
|
||||||
|
// Cast to const so that it doesn't delete it.
|
||||||
|
ip4_udp_hdr = new IP_Hdr(ip4_udp, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Locals used to avoid potential alignment problems
|
||||||
|
// with some archs/compilers when grabbing the address
|
||||||
|
// of the struct member directly in the following.
|
||||||
|
in_addr tmp_src;
|
||||||
|
in_addr tmp_dst;
|
||||||
|
|
||||||
|
if ( is_orig ) {
|
||||||
|
Conn()->OrigAddr().CopyIPv4(&tmp_src);
|
||||||
|
Conn()->RespAddr().CopyIPv4(&tmp_dst);
|
||||||
|
udp4->uh_sport = htons(Conn()->OrigPort());
|
||||||
|
udp4->uh_dport = htons(Conn()->RespPort());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Conn()->RespAddr().CopyIPv4(&tmp_src);
|
||||||
|
Conn()->OrigAddr().CopyIPv4(&tmp_dst);
|
||||||
|
udp4->uh_sport = htons(Conn()->RespPort());
|
||||||
|
udp4->uh_dport = htons(Conn()->OrigPort());
|
||||||
|
}
|
||||||
|
|
||||||
|
ip4_udp->ip_src = tmp_src;
|
||||||
|
ip4_udp->ip_dst = tmp_dst;
|
||||||
|
ip4_udp->ip_p = IPPROTO_UDP;
|
||||||
|
ip = ip4_udp_hdr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TransportProto::TRANSPORT_ICMP: reporter->InternalError("ICMP not supported in PIA::FirstPacket");
|
||||||
|
|
||||||
|
default: reporter->InternalError("unknown transport proto in PIA::FirstPacket");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Locals used to avoid potential alignment problems
|
|
||||||
// with some archs/compilers when grabbing the address
|
|
||||||
// of the struct member directly in the following.
|
|
||||||
in_addr tmp_src;
|
|
||||||
in_addr tmp_dst;
|
|
||||||
|
|
||||||
if ( is_orig ) {
|
|
||||||
Conn()->OrigAddr().CopyIPv4(&tmp_src);
|
|
||||||
Conn()->RespAddr().CopyIPv4(&tmp_dst);
|
|
||||||
tcp4->th_sport = htons(Conn()->OrigPort());
|
|
||||||
tcp4->th_dport = htons(Conn()->RespPort());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Conn()->RespAddr().CopyIPv4(&tmp_src);
|
|
||||||
Conn()->OrigAddr().CopyIPv4(&tmp_dst);
|
|
||||||
tcp4->th_sport = htons(Conn()->RespPort());
|
|
||||||
tcp4->th_dport = htons(Conn()->OrigPort());
|
|
||||||
}
|
|
||||||
|
|
||||||
ip4->ip_src = tmp_src;
|
|
||||||
ip4->ip_dst = tmp_dst;
|
|
||||||
ip = ip4_hdr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(ip);
|
||||||
|
|
||||||
if ( ! MatcherInitialized(is_orig) )
|
if ( ! MatcherInitialized(is_orig) )
|
||||||
DoMatch((const u_char*)"", 0, is_orig, true, false, false, ip);
|
DoMatch((const u_char*)"", 0, is_orig, true, false, false, ip);
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,32 @@ public:
|
||||||
|
|
||||||
void ReplayPacketBuffer(analyzer::Analyzer* analyzer);
|
void ReplayPacketBuffer(analyzer::Analyzer* analyzer);
|
||||||
|
|
||||||
|
// The first packet for each direction of a connection is passed
|
||||||
|
// in here. This initializes the signature engine state for DPD.
|
||||||
|
//
|
||||||
|
// This version of the method should be used preferably, assuming an IP
|
||||||
|
// header is available.
|
||||||
|
//
|
||||||
|
// (This API is a bit crude as it doesn't really fit nicely into the
|
||||||
|
// analyzer interface. Yet we need it for initializing the packet matcher
|
||||||
|
// in the case that we already get reassembled input; and making it part of
|
||||||
|
// the general analyzer interface seems to be unnecessary overhead.)
|
||||||
|
void FirstPacket(bool is_orig, const IP_Hdr* ip);
|
||||||
|
|
||||||
|
// The first packet for each direction of a connection is passed
|
||||||
|
// in here. This initializes the signature engine state for DPD.
|
||||||
|
//
|
||||||
|
// This version of the method should be used if no actual IP header is
|
||||||
|
// available. In that case a fake one will be created internally just for
|
||||||
|
// initializing the signature engine. The fake header's transport-layer
|
||||||
|
// protocol will be `proto`. Only TCP or UDP are supported.
|
||||||
|
//
|
||||||
|
// (Similar to the other variant of this method, this API is a bit crude as
|
||||||
|
// it doesn't really fit nicely into the analyzer interface. This version
|
||||||
|
// we need for feeding data into the matcher that's not directly top-level
|
||||||
|
// IP payload, but decapsulated out of other layers.)
|
||||||
|
void FirstPacket(bool is_orig, TransportProto proto);
|
||||||
|
|
||||||
// Children are also derived from Analyzer. Return this object
|
// Children are also derived from Analyzer. Return this object
|
||||||
// as pointer to an Analyzer.
|
// as pointer to an Analyzer.
|
||||||
analyzer::Analyzer* AsAnalyzer() { return as_analyzer; }
|
analyzer::Analyzer* AsAnalyzer() { return as_analyzer; }
|
||||||
|
@ -77,11 +103,15 @@ protected:
|
||||||
void DoMatch(const u_char* data, int len, bool is_orig, bool bol, bool eol, bool clear_state,
|
void DoMatch(const u_char* data, int len, bool is_orig, bool bol, bool eol, bool clear_state,
|
||||||
const IP_Hdr* ip = nullptr);
|
const IP_Hdr* ip = nullptr);
|
||||||
|
|
||||||
|
auto Conn() const { return conn; }
|
||||||
void SetConn(Connection* c) { conn = c; }
|
void SetConn(Connection* c) { conn = c; }
|
||||||
|
|
||||||
Buffer pkt_buffer;
|
Buffer pkt_buffer;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Joint backend for the two public FirstPacket() methods.
|
||||||
|
void FirstPacket(bool is_orig, const std::optional<TransportProto>& proto, const IP_Hdr* ip);
|
||||||
|
|
||||||
analyzer::Analyzer* as_analyzer;
|
analyzer::Analyzer* as_analyzer;
|
||||||
Connection* conn;
|
Connection* conn;
|
||||||
DataBlock current_packet;
|
DataBlock current_packet;
|
||||||
|
@ -123,16 +153,6 @@ public:
|
||||||
|
|
||||||
void Init() override;
|
void Init() override;
|
||||||
|
|
||||||
// The first packet for each direction of a connection is passed
|
|
||||||
// in here.
|
|
||||||
//
|
|
||||||
// (This is a bit crude as it doesn't really fit nicely into the
|
|
||||||
// analyzer interface. Yet we need it for initializing the packet
|
|
||||||
// matcher in the case that we already get reassembled input,
|
|
||||||
// and making it part of the general analyzer interface seems
|
|
||||||
// to be unnecessary overhead.)
|
|
||||||
void FirstPacket(bool is_orig, const IP_Hdr* ip);
|
|
||||||
|
|
||||||
void ReplayStreamBuffer(analyzer::Analyzer* analyzer);
|
void ReplayStreamBuffer(analyzer::Analyzer* analyzer);
|
||||||
|
|
||||||
static analyzer::Analyzer* Instantiate(Connection* conn) { return new PIA_TCP(conn); }
|
static analyzer::Analyzer* Instantiate(Connection* conn) { return new PIA_TCP(conn); }
|
||||||
|
|
|
@ -48,8 +48,8 @@ void SOCKS_Analyzer::DeliverStream(int len, const u_char* data, bool orig) {
|
||||||
if ( ! pia ) {
|
if ( ! pia ) {
|
||||||
pia = new analyzer::pia::PIA_TCP(Conn());
|
pia = new analyzer::pia::PIA_TCP(Conn());
|
||||||
if ( AddChildAnalyzer(pia) ) {
|
if ( AddChildAnalyzer(pia) ) {
|
||||||
pia->FirstPacket(true, nullptr);
|
pia->FirstPacket(true, TransportProto::TRANSPORT_TCP);
|
||||||
pia->FirstPacket(false, nullptr);
|
pia->FirstPacket(false, TransportProto::TRANSPORT_TCP);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
pia = nullptr;
|
pia = nullptr;
|
||||||
|
|
|
@ -357,8 +357,8 @@ void SSL_Analyzer::ForwardDecryptedData(const std::vector<u_char>& data, bool is
|
||||||
if ( ! pia ) {
|
if ( ! pia ) {
|
||||||
pia = new analyzer::pia::PIA_TCP(Conn());
|
pia = new analyzer::pia::PIA_TCP(Conn());
|
||||||
if ( AddChildAnalyzer(pia) ) {
|
if ( AddChildAnalyzer(pia) ) {
|
||||||
pia->FirstPacket(true, nullptr);
|
pia->FirstPacket(true, TransportProto::TRANSPORT_TCP);
|
||||||
pia->FirstPacket(false, nullptr);
|
pia->FirstPacket(false, TransportProto::TRANSPORT_TCP);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
reporter->Error("Could not initialize PIA");
|
reporter->Error("Could not initialize PIA");
|
||||||
|
|
|
@ -79,8 +79,8 @@ bool WebSocket_Analyzer::Configure(zeek::RecordValPtr config) {
|
||||||
|
|
||||||
auto* pia = new analyzer::pia::PIA_TCP(Conn());
|
auto* pia = new analyzer::pia::PIA_TCP(Conn());
|
||||||
if ( effective_analyzer->AddChildAnalyzer(pia) ) {
|
if ( effective_analyzer->AddChildAnalyzer(pia) ) {
|
||||||
pia->FirstPacket(true, nullptr);
|
pia->FirstPacket(true, TransportProto::TRANSPORT_TCP);
|
||||||
pia->FirstPacket(false, nullptr);
|
pia->FirstPacket(false, TransportProto::TRANSPORT_TCP);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue