diff --git a/src/analyzer/protocol/http/HTTP.cc b/src/analyzer/protocol/http/HTTP.cc index 5cef7d79c7..684abce01b 100644 --- a/src/analyzer/protocol/http/HTTP.cc +++ b/src/analyzer/protocol/http/HTTP.cc @@ -946,8 +946,8 @@ void HTTP_Analyzer::DeliverStream(int len, const u_char* data, bool is_orig) { pia = new analyzer::pia::PIA_TCP(Conn()); if ( AddChildAnalyzer(pia) ) { - pia->FirstPacket(true, nullptr); - pia->FirstPacket(false, nullptr); + pia->FirstPacket(true, TransportProto::TRANSPORT_TCP); + pia->FirstPacket(false, TransportProto::TRANSPORT_TCP); int remaining_in_content_line = content_line_resp->GetDeliverStreamRemainingLength(); if ( remaining_in_content_line > 0 ) { @@ -1396,8 +1396,8 @@ void HTTP_Analyzer::HTTP_Upgrade() { upgrade_protocol.c_str()); pia = new analyzer::pia::PIA_TCP(Conn()); if ( AddChildAnalyzer(pia) ) { - pia->FirstPacket(true, nullptr); - pia->FirstPacket(false, nullptr); + pia->FirstPacket(true, TransportProto::TRANSPORT_TCP); + pia->FirstPacket(false, TransportProto::TRANSPORT_TCP); } } diff --git a/src/analyzer/protocol/pia/PIA.cc b/src/analyzer/protocol/pia/PIA.cc index 5b1aa80413..07cf4a49e1 100644 --- a/src/analyzer/protocol/pia/PIA.cc +++ b/src/analyzer/protocol/pia/PIA.cc @@ -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& proto, const IP_Hdr* ip) { 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 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 ) { + if ( ! ip && proto ) { // proto needed here to avoid GCC warning that it may be used uninitialized // Create a dummy packet. Not very elegant, but everything // else would be *really* ugly ... - if ( ! ip4_hdr ) { - ip4 = (struct ip*)dummy_packet; - tcp4 = (struct tcphdr*)(dummy_packet + sizeof(struct ip)); - ip4->ip_len = sizeof(struct ip) + sizeof(struct tcphdr); - ip4->ip_hl = sizeof(struct ip) >> 2; - ip4->ip_p = IPPROTO_TCP; + switch ( *proto ) { + case TransportProto::TRANSPORT_TCP: { + DBG_LOG(DBG_ANALYZER, "PIA/TCP FirstPacket(%s)", (is_orig ? "T" : "F")); - // Cast to const so that it doesn't delete it. - ip4_hdr = new IP_Hdr(ip4, false); + if ( ! ip4_tcp_hdr ) { + 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) ) DoMatch((const u_char*)"", 0, is_orig, true, false, false, ip); } diff --git a/src/analyzer/protocol/pia/PIA.h b/src/analyzer/protocol/pia/PIA.h index f7d70d13d6..09ab8dd0ca 100644 --- a/src/analyzer/protocol/pia/PIA.h +++ b/src/analyzer/protocol/pia/PIA.h @@ -36,6 +36,32 @@ public: 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 // as pointer to an 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, const IP_Hdr* ip = nullptr); + auto Conn() const { return conn; } void SetConn(Connection* c) { conn = c; } Buffer pkt_buffer; private: + // Joint backend for the two public FirstPacket() methods. + void FirstPacket(bool is_orig, const std::optional& proto, const IP_Hdr* ip); + analyzer::Analyzer* as_analyzer; Connection* conn; DataBlock current_packet; @@ -123,16 +153,6 @@ public: 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); static analyzer::Analyzer* Instantiate(Connection* conn) { return new PIA_TCP(conn); } diff --git a/src/analyzer/protocol/socks/SOCKS.cc b/src/analyzer/protocol/socks/SOCKS.cc index bb816975ed..fe9a87ff7a 100644 --- a/src/analyzer/protocol/socks/SOCKS.cc +++ b/src/analyzer/protocol/socks/SOCKS.cc @@ -48,8 +48,8 @@ void SOCKS_Analyzer::DeliverStream(int len, const u_char* data, bool orig) { if ( ! pia ) { pia = new analyzer::pia::PIA_TCP(Conn()); if ( AddChildAnalyzer(pia) ) { - pia->FirstPacket(true, nullptr); - pia->FirstPacket(false, nullptr); + pia->FirstPacket(true, TransportProto::TRANSPORT_TCP); + pia->FirstPacket(false, TransportProto::TRANSPORT_TCP); } else pia = nullptr; diff --git a/src/analyzer/protocol/ssl/SSL.cc b/src/analyzer/protocol/ssl/SSL.cc index 87c1f6c0b2..55f3469870 100644 --- a/src/analyzer/protocol/ssl/SSL.cc +++ b/src/analyzer/protocol/ssl/SSL.cc @@ -357,8 +357,8 @@ void SSL_Analyzer::ForwardDecryptedData(const std::vector& data, bool is if ( ! pia ) { pia = new analyzer::pia::PIA_TCP(Conn()); if ( AddChildAnalyzer(pia) ) { - pia->FirstPacket(true, nullptr); - pia->FirstPacket(false, nullptr); + pia->FirstPacket(true, TransportProto::TRANSPORT_TCP); + pia->FirstPacket(false, TransportProto::TRANSPORT_TCP); } else reporter->Error("Could not initialize PIA"); diff --git a/src/analyzer/protocol/websocket/WebSocket.cc b/src/analyzer/protocol/websocket/WebSocket.cc index 81318f6963..8cd47aeefc 100644 --- a/src/analyzer/protocol/websocket/WebSocket.cc +++ b/src/analyzer/protocol/websocket/WebSocket.cc @@ -79,8 +79,8 @@ bool WebSocket_Analyzer::Configure(zeek::RecordValPtr config) { auto* pia = new analyzer::pia::PIA_TCP(Conn()); if ( effective_analyzer->AddChildAnalyzer(pia) ) { - pia->FirstPacket(true, nullptr); - pia->FirstPacket(false, nullptr); + pia->FirstPacket(true, TransportProto::TRANSPORT_TCP); + pia->FirstPacket(false, TransportProto::TRANSPORT_TCP); return true; }