diff --git a/CHANGES b/CHANGES index 9fb37caa22..656d970950 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,32 @@ +4.1.0-dev.660 | 2021-05-24 12:38:44 -0700 + + * Add type field to session::Key to help avoid collisions in map (Tim Wojtulewicz, Corelight) + + * Move bad UDP checksum handling into adapter object (Tim Wojtulewicz, Corelight) + + * Rename IPBasedTransportAnalyzer to SessionAdapter (Tim Wojtulewicz, Corelight) + + This also also combines the old TransportLayerAnalyzer class into + SessionAdapter, and removes the old class. This requires naming changes + in a few places but no functionality changes. + + * Move building session analyzer tree out of analyzer::Manager (Tim Wojtulewicz, Corelight) + + * Rework the packet flow through the IP-based analyzers (Tim Wojtulewicz, Corelight) + + * Add new UDP packet analyzer, remove old one (Tim Wojtulewicz, Corelight) + + * Add new ICMP packet analyzer, remove old one (Tim Wojtulewicz, Corelight) + + * Add base class for IP-based packet analyzers (Tim Wojtulewicz, Corelight) + + * Move SessionManager::ParseIPPacket to IP analyzer's namespace (Tim Wojtulewicz, Corelight) + + * Added skeletons for TCP/UDP/ICMP packet analysis plugins. (Tim Wojtulewicz, Corelight) + + This includes integration into the IP plugin and calling of the sessions code from each plugin. + 4.1.0-dev.646 | 2021-05-18 11:47:25 -0700 * Omit unneeded decimal points in modp_dtoa2() scientific notation output (Jon Siwek, Corelight) diff --git a/VERSION b/VERSION index c76b75482e..a33230ef04 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.1.0-dev.646 +4.1.0-dev.660 diff --git a/scripts/base/packet-protocols/__load__.zeek b/scripts/base/packet-protocols/__load__.zeek index 6432eb5bd0..3a4d9209cb 100644 --- a/scripts/base/packet-protocols/__load__.zeek +++ b/scripts/base/packet-protocols/__load__.zeek @@ -15,3 +15,6 @@ @load base/packet-protocols/gre @load base/packet-protocols/iptunnel @load base/packet-protocols/vntag +@load base/packet-protocols/udp +@load base/packet-protocols/tcp +@load base/packet-protocols/icmp diff --git a/scripts/base/packet-protocols/icmp/__load__.zeek b/scripts/base/packet-protocols/icmp/__load__.zeek new file mode 100644 index 0000000000..d551be57d3 --- /dev/null +++ b/scripts/base/packet-protocols/icmp/__load__.zeek @@ -0,0 +1 @@ +@load ./main \ No newline at end of file diff --git a/scripts/base/packet-protocols/icmp/main.zeek b/scripts/base/packet-protocols/icmp/main.zeek new file mode 100644 index 0000000000..6746463e61 --- /dev/null +++ b/scripts/base/packet-protocols/icmp/main.zeek @@ -0,0 +1,5 @@ +module PacketAnalyzer::ICMP; + +#event zeek_init() &priority=20 +# { +# } diff --git a/scripts/base/packet-protocols/ip/main.zeek b/scripts/base/packet-protocols/ip/main.zeek index 1f33b6bc50..0e1c506bcb 100644 --- a/scripts/base/packet-protocols/ip/main.zeek +++ b/scripts/base/packet-protocols/ip/main.zeek @@ -1,8 +1,22 @@ module PacketAnalyzer::IP; +const IPPROTO_TCP : count = 6; +const IPPROTO_UDP : count = 17; +const IPPROTO_ICMP : count = 1; +const IPPROTO_ICMP6 : count = 58; + +const IPPROTO_IPIP : count = 4; +const IPPROTO_IPV6 : count = 41; +const IPPROTO_GRE : count = 47; + event zeek_init() &priority=20 { - PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, 4, PacketAnalyzer::ANALYZER_IPTUNNEL); - PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, 41, PacketAnalyzer::ANALYZER_IPTUNNEL); - PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, 47, PacketAnalyzer::ANALYZER_GRE); + PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, IPPROTO_IPIP, PacketAnalyzer::ANALYZER_IPTUNNEL); + PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, IPPROTO_IPV6, PacketAnalyzer::ANALYZER_IPTUNNEL); + PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, IPPROTO_GRE, PacketAnalyzer::ANALYZER_GRE); + + PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, IPPROTO_TCP, PacketAnalyzer::ANALYZER_TCP); + PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, IPPROTO_UDP, PacketAnalyzer::ANALYZER_UDP); + PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, IPPROTO_ICMP, PacketAnalyzer::ANALYZER_ICMP); + PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, IPPROTO_ICMP6, PacketAnalyzer::ANALYZER_ICMP); } diff --git a/scripts/base/packet-protocols/tcp/__load__.zeek b/scripts/base/packet-protocols/tcp/__load__.zeek new file mode 100644 index 0000000000..d551be57d3 --- /dev/null +++ b/scripts/base/packet-protocols/tcp/__load__.zeek @@ -0,0 +1 @@ +@load ./main \ No newline at end of file diff --git a/scripts/base/packet-protocols/tcp/main.zeek b/scripts/base/packet-protocols/tcp/main.zeek new file mode 100644 index 0000000000..ae11833950 --- /dev/null +++ b/scripts/base/packet-protocols/tcp/main.zeek @@ -0,0 +1,5 @@ +module PacketAnalyzer::TCP; + +#event zeek_init() &priority=20 +# { +# } diff --git a/scripts/base/packet-protocols/udp/__load__.zeek b/scripts/base/packet-protocols/udp/__load__.zeek new file mode 100644 index 0000000000..d551be57d3 --- /dev/null +++ b/scripts/base/packet-protocols/udp/__load__.zeek @@ -0,0 +1 @@ +@load ./main \ No newline at end of file diff --git a/scripts/base/packet-protocols/udp/main.zeek b/scripts/base/packet-protocols/udp/main.zeek new file mode 100644 index 0000000000..fe117ebf07 --- /dev/null +++ b/scripts/base/packet-protocols/udp/main.zeek @@ -0,0 +1,5 @@ +module PacketAnalyzer::UDP; + +#event zeek_init() &priority=20 +# { +# } diff --git a/src/Conn.cc b/src/Conn.cc index da76dc509c..d2d8d0f3da 100644 --- a/src/Conn.cc +++ b/src/Conn.cc @@ -19,6 +19,7 @@ #include "zeek/analyzer/Analyzer.h" #include "zeek/analyzer/Manager.h" #include "zeek/iosource/IOSource.h" +#include "zeek/packet_analysis/protocol/ip/SessionAdapter.h" namespace zeek { @@ -64,7 +65,7 @@ Connection::Connection(const detail::ConnKey& k, double t, hist_seen = 0; history = ""; - root_analyzer = nullptr; + adapter = nullptr; primary_PIA = nullptr; ++current_connections; @@ -83,7 +84,7 @@ Connection::~Connection() if ( conn_val ) conn_val->SetOrigin(nullptr); - delete root_analyzer; + delete adapter; --current_connections; } @@ -129,7 +130,7 @@ void Connection::Done() // somewhere, but it's session-related, so maybe not? if ( ConnTransport() == TRANSPORT_TCP ) { - auto ta = static_cast(GetRootAnalyzer()); + auto ta = static_cast(adapter); assert(ta->IsAnalyzer("TCP")); analyzer::tcp::TCP_Endpoint* to = ta->Orig(); analyzer::tcp::TCP_Endpoint* tr = ta->Resp(); @@ -139,8 +140,8 @@ void Connection::Done() finished = 1; - if ( root_analyzer && ! root_analyzer->IsFinished() ) - root_analyzer->Done(); + if ( adapter && ! adapter->IsFinished() ) + adapter->Done(); } void Connection::NextPacket(double t, bool is_orig, @@ -156,11 +157,11 @@ void Connection::NextPacket(double t, bool is_orig, if ( Skipping() ) return; - if ( root_analyzer ) + if ( adapter ) { record_current_packet = record_packet; record_current_content = record_content; - root_analyzer->NextPacket(len, data, is_orig, -1, ip, caplen); + adapter->NextPacket(len, data, is_orig, -1, ip, caplen); record_packet = record_current_packet; record_content = record_current_content; } @@ -173,7 +174,7 @@ void Connection::NextPacket(double t, bool is_orig, bool Connection::IsReuse(double t, const u_char* pkt) { - return root_analyzer && root_analyzer->IsReuse(t, pkt); + return adapter && adapter->IsReuse(t, pkt); } bool Connection::ScaledHistoryEntry(char code, uint32_t& counter, @@ -275,8 +276,8 @@ const RecordValPtr& Connection::GetVal() } - if ( root_analyzer ) - root_analyzer->UpdateConnVal(conn_val.get()); + if ( adapter ) + adapter->UpdateConnVal(conn_val.get()); conn_val->AssignTime(3, start_time); // ### conn_val->AssignInterval(4, last_time - start_time); @@ -289,17 +290,17 @@ const RecordValPtr& Connection::GetVal() analyzer::Analyzer* Connection::FindAnalyzer(analyzer::ID id) { - return root_analyzer ? root_analyzer->FindChild(id) : nullptr; + return adapter ? adapter->FindChild(id) : nullptr; } analyzer::Analyzer* Connection::FindAnalyzer(const analyzer::Tag& tag) { - return root_analyzer ? root_analyzer->FindChild(tag) : nullptr; + return adapter ? adapter->FindChild(tag) : nullptr; } analyzer::Analyzer* Connection::FindAnalyzer(const char* name) { - return root_analyzer->FindChild(name); + return adapter->FindChild(name); } void Connection::AppendAddl(const char* str) @@ -370,8 +371,8 @@ void Connection::FlipRoles() conn_val = nullptr; - if ( root_analyzer ) - root_analyzer->FlipRoles(); + if ( adapter ) + adapter->FlipRoles(); analyzer_mgr->ApplyScheduledAnalyzers(this); @@ -383,7 +384,7 @@ unsigned int Connection::MemoryAllocation() const return session::Session::MemoryAllocation() + padded_sizeof(*this) + (timers.MemoryAllocation() - padded_sizeof(timers)) + (conn_val ? conn_val->MemoryAllocation() : 0) - + (root_analyzer ? root_analyzer->MemoryAllocation(): 0) + + (adapter ? adapter->MemoryAllocation(): 0) // primary_PIA is already contained in the analyzer tree. ; } @@ -448,10 +449,10 @@ void Connection::IDString(ODesc* d) const d->Add(ntohs(resp_port)); } -void Connection::SetRootAnalyzer(analyzer::TransportLayerAnalyzer* analyzer, - analyzer::pia::PIA* pia) +void Connection::SetSessionAdapter(packet_analysis::IP::SessionAdapter* aa, + analyzer::pia::PIA* pia) { - root_analyzer = analyzer; + adapter = aa; primary_PIA = pia; } diff --git a/src/Conn.h b/src/Conn.h index d6ca89a27b..19d5d943d3 100644 --- a/src/Conn.h +++ b/src/Conn.h @@ -41,12 +41,8 @@ class RuleHdrTest; } // namespace detail -namespace analyzer { - -class TransportLayerAnalyzer; -class Analyzer; - -} // namespace analyzer +namespace analyzer { class Analyzer; } +namespace packet_analysis::IP { class SessionAdapter; } enum ConnEventToFlag { NUL_IN_LINE, @@ -117,7 +113,10 @@ public: // should be marked invalid. const detail::ConnKey& Key() const { return key; } session::detail::Key SessionKey(bool copy) const override - { return session::detail::Key{&key, sizeof(key), copy}; } + { + return session::detail::Key{ + &key, sizeof(key), session::detail::Key::CONNECTION_KEY_TYPE, copy}; + } const IPAddr& OrigAddr() const { return orig_addr; } const IPAddr& RespAddr() const { return resp_addr; } @@ -231,8 +230,8 @@ public: void AddHistory(char code) { history += code; } // Sets the root of the analyzer tree as well as the primary PIA. - void SetRootAnalyzer(analyzer::TransportLayerAnalyzer* analyzer, analyzer::pia::PIA* pia); - analyzer::TransportLayerAnalyzer* GetRootAnalyzer() { return root_analyzer; } + void SetSessionAdapter(packet_analysis::IP::SessionAdapter* aa, analyzer::pia::PIA* pia); + packet_analysis::IP::SessionAdapter* GetSessionAdapter() { return adapter; } analyzer::pia::PIA* GetPrimaryPIA() { return primary_PIA; } // Sets the transport protocol in use. @@ -279,7 +278,7 @@ private: uint32_t hist_seen; std::string history; - analyzer::TransportLayerAnalyzer* root_analyzer; + packet_analysis::IP::SessionAdapter* adapter; analyzer::pia::PIA* primary_PIA; UID uid; // Globally unique connection ID. diff --git a/src/Dict.h b/src/Dict.h index c1a2b0cfa1..6204a0bcc8 100644 --- a/src/Dict.h +++ b/src/Dict.h @@ -177,6 +177,7 @@ public: bool operator!=( const DictIterator& that ) const { return !(*this == that); } private: + friend class Dictionary; DictIterator(const Dictionary* d, detail::DictEntry* begin, detail::DictEntry* end); diff --git a/src/RuleCondition.cc b/src/RuleCondition.cc index 33de7f86fc..b765cbaded 100644 --- a/src/RuleCondition.cc +++ b/src/RuleCondition.cc @@ -25,12 +25,12 @@ namespace zeek::detail { bool RuleConditionTCPState::DoMatch(Rule* rule, RuleEndpointState* state, const u_char* data, int len) { - analyzer::Analyzer* root = state->GetAnalyzer()->Conn()->GetRootAnalyzer(); + auto* adapter = state->GetAnalyzer()->Conn()->GetSessionAdapter(); - if ( ! root || ! root->IsAnalyzer("TCP") ) + if ( ! adapter || ! adapter->IsAnalyzer("TCP") ) return false; - auto* ta = static_cast(root); + auto* ta = static_cast(adapter); if ( tcpstates & RULE_STATE_STATELESS ) return true; @@ -57,9 +57,9 @@ void RuleConditionTCPState::PrintDebug() bool RuleConditionUDPState::DoMatch(Rule* rule, RuleEndpointState* state, const u_char* data, int len) { - analyzer::Analyzer* root = state->GetAnalyzer()->Conn()->GetRootAnalyzer(); + auto* adapter = state->GetAnalyzer()->Conn()->GetSessionAdapter(); - if ( ! root || ! root->IsAnalyzer("UDP") ) + if ( ! adapter || ! adapter->IsAnalyzer("UDP") ) return false; if ( states & RULE_STATE_STATELESS ) diff --git a/src/analyzer/Analyzer.cc b/src/analyzer/Analyzer.cc index 2f3bb22fcc..074e7407ab 100644 --- a/src/analyzer/Analyzer.cc +++ b/src/analyzer/Analyzer.cc @@ -880,31 +880,4 @@ void SupportAnalyzer::ForwardUndelivered(uint64_t seq, int len, bool is_orig) } -void TransportLayerAnalyzer::Done() - { - Analyzer::Done(); - } - -void TransportLayerAnalyzer::SetContentsFile(unsigned int /* direction */, - FilePtr /* f */) - { - reporter->Error("analyzer type does not support writing to a contents file"); - } - -FilePtr TransportLayerAnalyzer::GetContentsFile(unsigned int /* direction */) const - { - reporter->Error("analyzer type does not support writing to a contents file"); - return nullptr; - } - -void TransportLayerAnalyzer::PacketContents(const u_char* data, int len) - { - if ( packet_contents && len > 0 ) - { - String* cbs = new String(data, len, true); - auto contents = make_intrusive(cbs); - EnqueueConnEvent(packet_contents, ConnVal(), std::move(contents)); - } - } - } // namespace zeek::analyzer diff --git a/src/analyzer/Analyzer.h b/src/analyzer/Analyzer.h index 5999063fe6..c4505051a1 100644 --- a/src/analyzer/Analyzer.h +++ b/src/analyzer/Analyzer.h @@ -25,6 +25,7 @@ using FilePtr = zeek::IntrusivePtr; using RecordValPtr = zeek::IntrusivePtr; namespace detail { class Rule; } +namespace packet_analysis::IP { class IPBasedAnalyzer; } } // namespace zeek @@ -601,6 +602,7 @@ protected: friend class Manager; friend class zeek::Connection; friend class zeek::analyzer::tcp::TCP_ApplicationAnalyzer; + friend class zeek::packet_analysis::IP::IPBasedAnalyzer; /** * Return a string represantation of an analyzer, containing its name @@ -844,83 +846,4 @@ private: #define CONTENTS_RESP 2 #define CONTENTS_BOTH 3 -/** - * Base class for analyzers parsing transport-layer protocols. - */ -class TransportLayerAnalyzer : public Analyzer { -public: - /** - * Constructor. - * - * @param name A name for the protocol the analyzer is parsing. The - * name must match the one the corresponding Component registers. - * - * @param conn The connection the analyzer is associated with. - */ - TransportLayerAnalyzer(const char* name, Connection* conn) - : Analyzer(name, conn) { pia = nullptr; } - - /** - * Overridden from parent class. - */ - void Done() 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) = 0; - - /** - * Associates a file with the analyzer in which to record all - * analyzed input. This must only be called with derived classes that - * overide 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 overide 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; } - - /** - * 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 dass to pass to the event. - * - * @param len The length of \a data. - */ - void PacketContents(const u_char* data, int len); - -private: - analyzer::pia::PIA* pia; -}; - } // namespace zeek::analyzer diff --git a/src/analyzer/Manager.cc b/src/analyzer/Manager.cc index 7efb0ac3fe..27b0621b31 100644 --- a/src/analyzer/Manager.cc +++ b/src/analyzer/Manager.cc @@ -8,11 +8,11 @@ #include "zeek/RunState.h" #include "zeek/analyzer/protocol/conn-size/ConnSize.h" -#include "zeek/analyzer/protocol/icmp/ICMP.h" #include "zeek/analyzer/protocol/pia/PIA.h" #include "zeek/analyzer/protocol/stepping-stone/SteppingStone.h" #include "zeek/analyzer/protocol/tcp/TCP.h" -#include "zeek/analyzer/protocol/udp/UDP.h" +#include "zeek/packet_analysis/protocol/ip/IPBasedAnalyzer.h" +#include "zeek/packet_analysis/protocol/ip/SessionAdapter.h" #include "zeek/plugin/Manager.h" @@ -354,15 +354,10 @@ Manager::tag_set* Manager::LookupPort(TransportProto proto, uint32_t port, bool return l; } -Manager::tag_set* Manager::LookupPort(PortVal* val, bool add_if_not_found) - { - return LookupPort(val->PortType(), val->Port(), add_if_not_found); - } - bool Manager::BuildInitialAnalyzerTree(Connection* conn) { analyzer::tcp::TCP_Analyzer* tcp = nullptr; - TransportLayerAnalyzer* root = nullptr; + packet_analysis::IP::SessionAdapter* root = nullptr; analyzer::pia::PIA* pia = nullptr; bool check_port = false; @@ -375,19 +370,6 @@ bool Manager::BuildInitialAnalyzerTree(Connection* conn) DBG_ANALYZER(conn, "activated TCP analyzer"); break; - case TRANSPORT_UDP: - root = new analyzer::udp::UDP_Analyzer(conn); - pia = new analyzer::pia::PIA_UDP(conn); - check_port = true; - DBG_ANALYZER(conn, "activated UDP analyzer"); - break; - - case TRANSPORT_ICMP: { - root = new analyzer::icmp::ICMP_Analyzer(conn); - DBG_ANALYZER(conn, "activated ICMP analyzer"); - break; - } - default: reporter->InternalWarning("unknown protocol can't build analyzer tree"); return false; @@ -489,7 +471,7 @@ bool Manager::BuildInitialAnalyzerTree(Connection* conn) if ( pia ) root->AddChildAnalyzer(pia->AsAnalyzer()); - conn->SetRootAnalyzer(root, pia); + conn->SetSessionAdapter(root, pia); root->Init(); root->InitChildren(); @@ -607,10 +589,11 @@ Manager::tag_set Manager::GetScheduled(const Connection* conn) return result; } -bool Manager::ApplyScheduledAnalyzers(Connection* conn, bool init, TransportLayerAnalyzer* parent) +bool Manager::ApplyScheduledAnalyzers(Connection* conn, bool init, + packet_analysis::IP::SessionAdapter* parent) { if ( ! parent ) - parent = conn->GetRootAnalyzer(); + parent = conn->GetSessionAdapter(); if ( ! parent ) return false; diff --git a/src/analyzer/Manager.h b/src/analyzer/Manager.h index 7137a57390..65c38a6fbf 100644 --- a/src/analyzer/Manager.h +++ b/src/analyzer/Manager.h @@ -35,6 +35,14 @@ #include "zeek/analyzer/analyzer.bif.h" namespace zeek { + +namespace packet_analysis::IP { + +class IPBasedAnalyzer; +class SessionAdapter; + +} // namespace packet_analysis::IP + namespace analyzer { /** @@ -244,8 +252,8 @@ public: * * @param conn The connection to add the initial set of analyzers to. * - * @return False if the tree cannot be build; that's usually an - * internally error. + * @return False if the tree cannot be built; that's usually an + * internal error. */ bool BuildInitialAnalyzerTree(Connection* conn); @@ -313,7 +321,7 @@ public: * @return True if at least one scheduled analyzer was found. */ bool ApplyScheduledAnalyzers(Connection* conn, bool init_and_event = true, - TransportLayerAnalyzer* parent = nullptr); + packet_analysis::IP::SessionAdapter* parent = nullptr); /** * Schedules a particular analyzer for an upcoming connection. Once @@ -345,10 +353,11 @@ public: private: + friend class packet_analysis::IP::IPBasedAnalyzer; + using tag_set = std::set; using analyzer_map_by_port = std::map; - tag_set* LookupPort(PortVal* val, bool add_if_not_found); tag_set* LookupPort(TransportProto proto, uint32_t port, bool add_if_not_found); tag_set GetScheduled(const Connection* conn); diff --git a/src/analyzer/protocol/CMakeLists.txt b/src/analyzer/protocol/CMakeLists.txt index 49dde00190..0d628ded1d 100644 --- a/src/analyzer/protocol/CMakeLists.txt +++ b/src/analyzer/protocol/CMakeLists.txt @@ -14,7 +14,6 @@ add_subdirectory(gnutella) add_subdirectory(gssapi) add_subdirectory(gtpv1) add_subdirectory(http) -add_subdirectory(icmp) add_subdirectory(ident) add_subdirectory(imap) add_subdirectory(irc) @@ -45,7 +44,6 @@ add_subdirectory(stepping-stone) add_subdirectory(syslog) add_subdirectory(tcp) add_subdirectory(teredo) -add_subdirectory(udp) add_subdirectory(vxlan) add_subdirectory(xmpp) add_subdirectory(zip) diff --git a/src/analyzer/protocol/ayiya/AYIYA.cc b/src/analyzer/protocol/ayiya/AYIYA.cc index b97a78570a..5c3812ddc6 100644 --- a/src/analyzer/protocol/ayiya/AYIYA.cc +++ b/src/analyzer/protocol/ayiya/AYIYA.cc @@ -2,9 +2,9 @@ #include "zeek/analyzer/protocol/ayiya/AYIYA.h" -#include "zeek/session/Manager.h" #include "zeek/Func.h" #include "zeek/packet_analysis/protocol/iptunnel/IPTunnel.h" +#include "zeek/packet_analysis/protocol/ip/IP.h" namespace zeek::analyzer::ayiya { @@ -46,8 +46,8 @@ void AYIYA_Analyzer::DeliverPacket(int len, const u_char* data, bool orig, uint6 caplen -= inner_packet_offset; inner_packet_offset = -1; - IP_Hdr* inner = nullptr; - int result = session_mgr->ParseIPPacket(len, data, next_header, inner); + std::unique_ptr inner; + int result = packet_analysis::IP::ParsePacket(len, data, next_header, inner); if ( result == 0 ) { @@ -66,9 +66,6 @@ void AYIYA_Analyzer::DeliverPacket(int len, const u_char* data, bool orig, uint6 else ProtocolViolation("AYIYA payload length", reinterpret_cast(data), len); - - if ( result != 0 ) - delete inner; } } // namespace zeek::analyzer::ayiya diff --git a/src/analyzer/protocol/dhcp/DHCP.h b/src/analyzer/protocol/dhcp/DHCP.h index dbe13d4df7..8ae911ae44 100644 --- a/src/analyzer/protocol/dhcp/DHCP.h +++ b/src/analyzer/protocol/dhcp/DHCP.h @@ -1,7 +1,5 @@ #pragma once -#include "zeek/analyzer/protocol/udp/UDP.h" - #include "analyzer/protocol/dhcp/dhcp_pac.h" namespace zeek::analyzer::dhcp { diff --git a/src/analyzer/protocol/dnp3/DNP3.h b/src/analyzer/protocol/dnp3/DNP3.h index 3fe5d1e9f0..6540be39d6 100644 --- a/src/analyzer/protocol/dnp3/DNP3.h +++ b/src/analyzer/protocol/dnp3/DNP3.h @@ -1,7 +1,6 @@ #pragma once #include "zeek/analyzer/protocol/tcp/TCP.h" -#include "zeek/analyzer/protocol/udp/UDP.h" #include "analyzer/protocol/dnp3/dnp3_pac.h" diff --git a/src/analyzer/protocol/gnutella/Gnutella.cc b/src/analyzer/protocol/gnutella/Gnutella.cc index 661863c33d..610e8b0a5b 100644 --- a/src/analyzer/protocol/gnutella/Gnutella.cc +++ b/src/analyzer/protocol/gnutella/Gnutella.cc @@ -129,7 +129,7 @@ bool Gnutella_Analyzer::IsHTTP(std::string header) if ( Parent()->IsAnalyzer("TCP") ) { // Replay buffered data. - analyzer::pia::PIA* pia = static_cast(Parent())->GetPIA(); + analyzer::pia::PIA* pia = static_cast(Parent())->GetPIA(); if ( pia ) static_cast(pia)->ReplayStreamBuffer(a); } diff --git a/src/analyzer/protocol/gtpv1/GTPv1.cc b/src/analyzer/protocol/gtpv1/GTPv1.cc index 08d44171ee..f1c432d08d 100644 --- a/src/analyzer/protocol/gtpv1/GTPv1.cc +++ b/src/analyzer/protocol/gtpv1/GTPv1.cc @@ -2,8 +2,8 @@ #include "zeek/analyzer/protocol/gtpv1/GTPv1.h" #include "zeek/packet_analysis/protocol/iptunnel/IPTunnel.h" +#include "zeek/packet_analysis/protocol/ip/IP.h" -#include "zeek/session/Manager.h" #include "zeek/analyzer/protocol/gtpv1/events.bif.h" namespace zeek::analyzer::gtpv1 { @@ -47,8 +47,8 @@ void GTPv1_Analyzer::DeliverPacket(int len, const u_char* data, bool orig, uint6 caplen -= inner_packet_offset; inner_packet_offset = -1; - IP_Hdr* inner = nullptr; - int result = session_mgr->ParseIPPacket(len, data, next_header, inner); + std::unique_ptr inner = nullptr; + int result = packet_analysis::IP::ParsePacket(len, data, next_header, inner); if ( result == 0 ) { @@ -77,9 +77,6 @@ void GTPv1_Analyzer::DeliverPacket(int len, const u_char* data, bool orig, uint6 else ProtocolViolation("GTPv1 payload length", reinterpret_cast(odata), olen); - - if ( result != 0 ) - delete inner; } } // namespace zeek::analyzer::gtpv1 diff --git a/src/analyzer/protocol/icmp/ICMP.h b/src/analyzer/protocol/icmp/ICMP.h deleted file mode 100644 index ef9aeddf92..0000000000 --- a/src/analyzer/protocol/icmp/ICMP.h +++ /dev/null @@ -1,99 +0,0 @@ -// See the file "COPYING" in the main distribution directory for copyright. - -#pragma once - -#include "zeek/RuleMatcher.h" -#include "zeek/analyzer/Analyzer.h" -#include "zeek/net_util.h" - -namespace zeek { - -class VectorVal; -using VectorValPtr = IntrusivePtr; - -namespace analyzer::icmp { - -enum ICMP_EndpointState { - ICMP_INACTIVE, // no packet seen - ICMP_ACTIVE, // packets seen -}; - -// We do not have an PIA for ICMP (yet) and therefore derive from -// RuleMatcherState to perform our own matching. -class ICMP_Analyzer final : public analyzer::TransportLayerAnalyzer { -public: - explicit ICMP_Analyzer(Connection* conn); - - void UpdateConnVal(RecordVal *conn_val) override; - - static analyzer::Analyzer* Instantiate(Connection* conn) - { return new ICMP_Analyzer(conn); } - -protected: - void Done() override; - void DeliverPacket(int len, const u_char* data, bool orig, - uint64_t seq, const IP_Hdr* ip, int caplen) override; - bool IsReuse(double t, const u_char* pkt) override; - unsigned int MemoryAllocation() const override; - - void ICMP_Sent(const struct icmp* icmpp, int len, int caplen, int icmpv6, - const u_char* data, const IP_Hdr* ip_hdr); - - void Echo(double t, const struct icmp* icmpp, int len, - int caplen, const u_char*& data, const IP_Hdr* ip_hdr); - void Redirect(double t, const struct icmp* icmpp, int len, - int caplen, const u_char*& data, const IP_Hdr* ip_hdr); - void RouterAdvert(double t, const struct icmp* icmpp, int len, - int caplen, const u_char*& data, const IP_Hdr* ip_hdr); - void NeighborAdvert(double t, const struct icmp* icmpp, int len, - int caplen, const u_char*& data, const IP_Hdr* ip_hdr); - void NeighborSolicit(double t, const struct icmp* icmpp, int len, - int caplen, const u_char*& data, const IP_Hdr* ip_hdr); - void RouterSolicit(double t, const struct icmp* icmpp, int len, - int caplen, const u_char*& data, const IP_Hdr* ip_hdr); - - void Describe(ODesc* d) const; - - RecordValPtr BuildInfo(const struct icmp* icmpp, int len, - bool icmpv6, const IP_Hdr* ip_hdr); - - void NextICMP4(double t, const struct icmp* icmpp, int len, int caplen, - const u_char*& data, const IP_Hdr* ip_hdr ); - - 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); - - TransportProto GetContextProtocol(const IP_Hdr* ip_hdr, uint32_t* src_port, - uint32_t* dst_port); - - void NextICMP6(double t, const struct icmp* icmpp, int len, int caplen, - const u_char*& data, const IP_Hdr* ip_hdr ); - - 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); - - // RFC 4861 Neighbor Discover message options - VectorValPtr BuildNDOptionsVal(int caplen, const u_char* data); - - RecordValPtr icmp_conn_val; - int type; - int code; - int request_len, reply_len; - - detail::RuleMatcherState matcher_state; - -private: - 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 analyzer::icmp -} // namespace zeek diff --git a/src/analyzer/protocol/icmp/Plugin.cc b/src/analyzer/protocol/icmp/Plugin.cc deleted file mode 100644 index 7326604034..0000000000 --- a/src/analyzer/protocol/icmp/Plugin.cc +++ /dev/null @@ -1,22 +0,0 @@ -// See the file in the main distribution directory for copyright. - -#include "zeek/plugin/Plugin.h" -#include "zeek/analyzer/Component.h" -#include "zeek/analyzer/protocol/icmp/ICMP.h" - -namespace zeek::plugin::detail::Zeek_ICMP { - -class Plugin : public zeek::plugin::Plugin { -public: - zeek::plugin::Configuration Configure() override - { - AddComponent(new zeek::analyzer::Component("ICMP", zeek::analyzer::icmp::ICMP_Analyzer::Instantiate)); - - zeek::plugin::Configuration config; - config.name = "Zeek::ICMP"; - config.description = "ICMP analyzer"; - return config; - } -} plugin; - -} // namespace zeek::plugin::detail::Zeek_ICMP diff --git a/src/analyzer/protocol/netbios/NetbiosSSN.h b/src/analyzer/protocol/netbios/NetbiosSSN.h index f73631f435..a3a97728e2 100644 --- a/src/analyzer/protocol/netbios/NetbiosSSN.h +++ b/src/analyzer/protocol/netbios/NetbiosSSN.h @@ -2,7 +2,6 @@ #pragma once -#include "zeek/analyzer/protocol/udp/UDP.h" #include "zeek/analyzer/protocol/tcp/TCP.h" namespace zeek::analyzer::netbios_ssn { diff --git a/src/analyzer/protocol/ntp/NTP.h b/src/analyzer/protocol/ntp/NTP.h index 0e829f9288..9d2fcb07b1 100644 --- a/src/analyzer/protocol/ntp/NTP.h +++ b/src/analyzer/protocol/ntp/NTP.h @@ -1,7 +1,5 @@ #pragma once -#include "zeek/analyzer/protocol/udp/UDP.h" - #include "zeek/analyzer/protocol/ntp/events.bif.h" #include "zeek/analyzer/protocol/ntp/types.bif.h" #include "zeek/analyzer/protocol/ntp/ntp_pac.h" diff --git a/src/analyzer/protocol/radius/RADIUS.h b/src/analyzer/protocol/radius/RADIUS.h index 1e1648c84f..7ab093e073 100644 --- a/src/analyzer/protocol/radius/RADIUS.h +++ b/src/analyzer/protocol/radius/RADIUS.h @@ -1,7 +1,5 @@ #pragma once -#include "zeek/analyzer/protocol/udp/UDP.h" - #include "zeek/analyzer/protocol/radius/events.bif.h" #include "zeek/analyzer/protocol/radius/radius_pac.h" diff --git a/src/analyzer/protocol/rdp/RDPEUDP.h b/src/analyzer/protocol/rdp/RDPEUDP.h index 13c5651633..01f2326adb 100644 --- a/src/analyzer/protocol/rdp/RDPEUDP.h +++ b/src/analyzer/protocol/rdp/RDPEUDP.h @@ -1,7 +1,5 @@ #pragma once -#include "zeek/analyzer/protocol/udp/UDP.h" - #include "zeek/analyzer/protocol/rdp/events.bif.h" #include "zeek/analyzer/protocol/rdp/rdpeudp_pac.h" diff --git a/src/analyzer/protocol/sip/SIP.h b/src/analyzer/protocol/sip/SIP.h index 18ec010a8b..15fe1371f3 100644 --- a/src/analyzer/protocol/sip/SIP.h +++ b/src/analyzer/protocol/sip/SIP.h @@ -1,7 +1,5 @@ #pragma once -#include "zeek/analyzer/protocol/udp/UDP.h" - #include "zeek/analyzer/protocol/sip/events.bif.h" #include "zeek/analyzer/protocol/sip/sip_pac.h" diff --git a/src/analyzer/protocol/ssl/DTLS.h b/src/analyzer/protocol/ssl/DTLS.h index 1554c1bb6e..121af08cde 100644 --- a/src/analyzer/protocol/ssl/DTLS.h +++ b/src/analyzer/protocol/ssl/DTLS.h @@ -1,7 +1,5 @@ #pragma once -#include "zeek/analyzer/protocol/udp/UDP.h" - #include "zeek/analyzer/protocol/ssl/events.bif.h" namespace binpac { namespace DTLS { class SSL_Conn; } } diff --git a/src/analyzer/protocol/syslog/Syslog.h b/src/analyzer/protocol/syslog/Syslog.h index d1aea12d05..941492a96c 100644 --- a/src/analyzer/protocol/syslog/Syslog.h +++ b/src/analyzer/protocol/syslog/Syslog.h @@ -1,6 +1,5 @@ #pragma once -#include "zeek/analyzer/protocol/udp/UDP.h" #include "zeek/analyzer/protocol/tcp/TCP.h" #include "analyzer/protocol/syslog/syslog_pac.h" diff --git a/src/analyzer/protocol/tcp/TCP.cc b/src/analyzer/protocol/tcp/TCP.cc index f4a5d3b4bd..8dd7479df1 100644 --- a/src/analyzer/protocol/tcp/TCP.cc +++ b/src/analyzer/protocol/tcp/TCP.cc @@ -123,7 +123,7 @@ static RecordVal* build_syn_packet_val(bool is_orig, const IP_Hdr* ip, TCP_Analyzer::TCP_Analyzer(Connection* conn) -: TransportLayerAnalyzer("TCP", conn) + : packet_analysis::IP::SessionAdapter("TCP", conn) { // Set a timer to eventually time out this connection. ADD_ANALYZER_TIMER(&TCP_Analyzer::ExpireTimer, @@ -180,7 +180,7 @@ void TCP_Analyzer::Done() analyzer::Analyzer* TCP_Analyzer::FindChild(analyzer::ID arg_id) { - analyzer::Analyzer* child = analyzer::TransportLayerAnalyzer::FindChild(arg_id); + analyzer::Analyzer* child = packet_analysis::IP::SessionAdapter::FindChild(arg_id); if ( child ) return child; @@ -197,7 +197,7 @@ analyzer::Analyzer* TCP_Analyzer::FindChild(analyzer::ID arg_id) analyzer::Analyzer* TCP_Analyzer::FindChild(analyzer::Tag arg_tag) { - analyzer::Analyzer* child = analyzer::TransportLayerAnalyzer::FindChild(arg_tag); + analyzer::Analyzer* child = packet_analysis::IP::SessionAdapter::FindChild(arg_tag); if ( child ) return child; @@ -214,7 +214,7 @@ analyzer::Analyzer* TCP_Analyzer::FindChild(analyzer::Tag arg_tag) bool TCP_Analyzer::RemoveChildAnalyzer(analyzer::ID id) { - auto rval = analyzer::TransportLayerAnalyzer::RemoveChildAnalyzer(id); + auto rval = packet_analysis::IP::SessionAdapter::RemoveChildAnalyzer(id); if ( rval ) return rval; @@ -1048,7 +1048,7 @@ static int32_t update_last_seq(TCP_Endpoint* endpoint, uint32_t last_seq, void TCP_Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig, uint64_t seq, const IP_Hdr* ip, int caplen) { - TransportLayerAnalyzer::DeliverPacket(len, data, orig, seq, ip, caplen); + packet_analysis::IP::SessionAdapter::DeliverPacket(len, data, orig, seq, ip, caplen); const struct tcphdr* tp = ExtractTCP_Header(data, len, caplen); if ( ! tp ) diff --git a/src/analyzer/protocol/tcp/TCP.h b/src/analyzer/protocol/tcp/TCP.h index 27e42e7e91..d03920d031 100644 --- a/src/analyzer/protocol/tcp/TCP.h +++ b/src/analyzer/protocol/tcp/TCP.h @@ -6,6 +6,7 @@ #include "zeek/IPAddr.h" #include "zeek/analyzer/protocol/tcp/TCP_Endpoint.h" #include "zeek/analyzer/protocol/tcp/TCP_Flags.h" +#include "zeek/packet_analysis/protocol/ip/SessionAdapter.h" #include "zeek/Conn.h" // We define two classes here: @@ -22,7 +23,7 @@ class TCP_Endpoint; class TCP_Reassembler; class TCP_ApplicationAnalyzer; -class TCP_Analyzer final : public analyzer::TransportLayerAnalyzer { +class TCP_Analyzer final : public packet_analysis::IP::SessionAdapter { public: explicit TCP_Analyzer(Connection* conn); ~TCP_Analyzer() override; @@ -72,6 +73,8 @@ public: static analyzer::Analyzer* Instantiate(Connection* conn) { return new TCP_Analyzer(conn); } + void AddExtraAnalyzers(Connection* conn) override {} + protected: friend class TCP_ApplicationAnalyzer; friend class TCP_Reassembler; diff --git a/src/analyzer/protocol/tcp/functions.bif b/src/analyzer/protocol/tcp/functions.bif index ffdc542893..65669e524a 100644 --- a/src/analyzer/protocol/tcp/functions.bif +++ b/src/analyzer/protocol/tcp/functions.bif @@ -101,7 +101,7 @@ function set_contents_file%(cid: conn_id, direction: count, f: file%): bool if ( ! c ) return zeek::val_mgr->False(); - c->GetRootAnalyzer()->SetContentsFile(direction, {zeek::NewRef{}, f}); + c->GetSessionAdapter()->SetContentsFile(direction, {zeek::NewRef{}, f}); return zeek::val_mgr->True(); %} @@ -124,7 +124,7 @@ function get_contents_file%(cid: conn_id, direction: count%): file if ( c ) { - auto cf = c->GetRootAnalyzer()->GetContentsFile(direction); + auto cf = c->GetSessionAdapter()->GetContentsFile(direction); if ( cf ) return zeek::make_intrusive(std::move(cf)); diff --git a/src/analyzer/protocol/teredo/Teredo.cc b/src/analyzer/protocol/teredo/Teredo.cc index f697802187..f7a8982b2f 100644 --- a/src/analyzer/protocol/teredo/Teredo.cc +++ b/src/analyzer/protocol/teredo/Teredo.cc @@ -4,10 +4,10 @@ #include "zeek/Conn.h" #include "zeek/IP.h" #include "zeek/Reporter.h" -#include "zeek/session/Manager.h" #include "zeek/ZeekString.h" #include "zeek/RunState.h" #include "zeek/packet_analysis/protocol/iptunnel/IPTunnel.h" +#include "zeek/packet_analysis/protocol/ip/IP.h" #include "zeek/analyzer/protocol/teredo/events.bif.h" @@ -94,7 +94,7 @@ bool TeredoEncapsulation::DoParse(const u_char* data, int& len, return false; } -RecordValPtr TeredoEncapsulation::BuildVal(const IP_Hdr* inner) const +RecordValPtr TeredoEncapsulation::BuildVal(const std::unique_ptr& inner) const { static auto teredo_hdr_type = id::find_type("teredo_hdr"); static auto teredo_auth_type = id::find_type("teredo_auth"); @@ -164,8 +164,8 @@ void Teredo_Analyzer::DeliverPacket(int len, const u_char* data, bool orig, return; } - IP_Hdr* inner = nullptr; - int rslt = session_mgr->ParseIPPacket(len, te.InnerIP(), IPPROTO_IPV6, inner); + std::unique_ptr inner = nullptr; + int rslt = packet_analysis::IP::ParsePacket(len, te.InnerIP(), IPPROTO_IPV6, inner); if ( rslt > 0 ) { @@ -175,7 +175,6 @@ void Teredo_Analyzer::DeliverPacket(int len, const u_char* data, bool orig, Weird("Teredo_bubble_with_payload", true); else { - delete inner; ProtocolViolation("Teredo payload length", (const char*) data, len); return; } @@ -193,7 +192,6 @@ void Teredo_Analyzer::DeliverPacket(int len, const u_char* data, bool orig, else { - delete inner; ProtocolViolation("Truncated Teredo or invalid inner IP version", (const char*) data, len); return; } diff --git a/src/analyzer/protocol/teredo/Teredo.h b/src/analyzer/protocol/teredo/Teredo.h index d2d87f7319..f6f377d056 100644 --- a/src/analyzer/protocol/teredo/Teredo.h +++ b/src/analyzer/protocol/teredo/Teredo.h @@ -74,7 +74,7 @@ public: const u_char* Authentication() const { return auth; } - RecordValPtr BuildVal(const IP_Hdr* inner) const; + RecordValPtr BuildVal(const std::unique_ptr& inner) const; protected: bool DoParse(const u_char* data, int& len, bool found_orig, bool found_au); diff --git a/src/analyzer/protocol/udp/Plugin.cc b/src/analyzer/protocol/udp/Plugin.cc deleted file mode 100644 index fc08de2eb3..0000000000 --- a/src/analyzer/protocol/udp/Plugin.cc +++ /dev/null @@ -1,22 +0,0 @@ -// See the file in the main distribution directory for copyright. - -#include "zeek/plugin/Plugin.h" -#include "zeek/analyzer/Component.h" -#include "zeek/analyzer/protocol/udp/UDP.h" - -namespace zeek::plugin::detail::Zeek_UDP { - -class Plugin : public zeek::plugin::Plugin { -public: - zeek::plugin::Configuration Configure() override - { - AddComponent(new zeek::analyzer::Component("UDP", zeek::analyzer::udp::UDP_Analyzer::Instantiate)); - - zeek::plugin::Configuration config; - config.name = "Zeek::UDP"; - config.description = "UDP Analyzer"; - return config; - } -} plugin; - -} // namespace zeek::plugin::detail::Zeek_UDP diff --git a/src/analyzer/protocol/udp/UDP.cc b/src/analyzer/protocol/udp/UDP.cc deleted file mode 100644 index e29f14d251..0000000000 --- a/src/analyzer/protocol/udp/UDP.cc +++ /dev/null @@ -1,275 +0,0 @@ -// See the file "COPYING" in the main distribution directory for copyright. - -#include "zeek/zeek-config.h" -#include "zeek/analyzer/protocol/udp/UDP.h" - -#include - -#include "zeek/RunState.h" -#include "zeek/NetVar.h" -#include "zeek/analyzer/Manager.h" -#include "zeek/Reporter.h" -#include "zeek/Conn.h" - -#include "zeek/analyzer/protocol/udp/events.bif.h" - -namespace zeek::analyzer::udp { - -UDP_Analyzer::UDP_Analyzer(Connection* conn) - : analyzer::TransportLayerAnalyzer("UDP", conn) - { - conn->EnableStatusUpdateTimer(); - conn->SetInactivityTimeout(zeek::detail::udp_inactivity_timeout); - request_len = reply_len = -1; // -1 means "haven't seen any activity" - - req_chk_cnt = rep_chk_cnt = 0; - req_chk_thresh = rep_chk_thresh = 1; - } - -UDP_Analyzer::~UDP_Analyzer() - { - // XXX: need to implement this! - // delete src_pkt_writer; - } - -void UDP_Analyzer::Init() - { - } - -void UDP_Analyzer::Done() - { - Analyzer::Done(); - } - -void UDP_Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig, - uint64_t seq, const IP_Hdr* ip, int caplen) - { - assert(ip); - - Analyzer::DeliverPacket(len, data, is_orig, seq, ip, caplen); - - const struct udphdr* up = (const struct udphdr*) data; - - // Increment data before checksum check so that data will - // point to UDP payload even if checksum fails. Particularly, - // it allows event packet_contents to get to the data. - data += sizeof(struct udphdr); - - // We need the min() here because Ethernet frame padding can lead to - // caplen > len. - if ( packet_contents ) - PacketContents(data, std::min(len, caplen) - sizeof(struct udphdr)); - - int chksum = up->uh_sum; - - auto validate_checksum = - ! run_state::current_pkt->l3_checksummed && - ! zeek::detail::ignore_checksums && - ! zeek::id::find_val("ignore_checksums_nets")->Contains(ip->IPHeaderSrcAddr()) && - caplen >=len; - - constexpr auto vxlan_len = 8; - constexpr auto eth_len = 14; - - if ( validate_checksum && - len > ((int)sizeof(struct udphdr) + vxlan_len + eth_len) && - (data[0] & 0x08) == 0x08 ) - { - auto& vxlan_ports = analyzer_mgr->GetVxlanPorts(); - - if ( std::find(vxlan_ports.begin(), vxlan_ports.end(), - ntohs(up->uh_dport)) != vxlan_ports.end() ) - { - // Looks like VXLAN on a well-known port, so the checksum should be - // transmitted as zero, and we should accept that. If not - // transmitted as zero, then validating the checksum is optional. - if ( chksum == 0 ) - validate_checksum = false; - else - validate_checksum = BifConst::Tunnel::validate_vxlan_checksums; - } - } - - if ( validate_checksum ) - { - bool bad = false; - - if ( ip->IP4_Hdr() ) - { - if ( chksum && ! ValidateChecksum(ip, up, len) ) - bad = true; - } - - /* checksum is not optional for IPv6 */ - else if ( ! ValidateChecksum(ip, up, len) ) - bad = true; - - if ( bad ) - { - Weird("bad_UDP_checksum"); - - if ( is_orig ) - { - uint32_t t = req_chk_thresh; - if ( Conn()->ScaledHistoryEntry('C', req_chk_cnt, - req_chk_thresh) ) - ChecksumEvent(is_orig, t); - } - else - { - uint32_t t = rep_chk_thresh; - if ( Conn()->ScaledHistoryEntry('c', rep_chk_cnt, - rep_chk_thresh) ) - ChecksumEvent(is_orig, t); - } - - return; - } - } - - int ulen = ntohs(up->uh_ulen); - if ( ulen != len ) - Weird("UDP_datagram_length_mismatch", util::fmt("%d != %d", ulen, len)); - - len -= sizeof(struct udphdr); - ulen -= sizeof(struct udphdr); - caplen -= sizeof(struct udphdr); - - Conn()->SetLastTime(run_state::current_timestamp); - - if ( udp_contents ) - { - static auto udp_content_ports = id::find_val("udp_content_ports"); - static auto udp_content_delivery_ports_orig = id::find_val("udp_content_delivery_ports_orig"); - static auto udp_content_delivery_ports_resp = id::find_val("udp_content_delivery_ports_resp"); - bool do_udp_contents = false; - const auto& sport_val = val_mgr->Port(ntohs(up->uh_sport), TRANSPORT_UDP); - const auto& dport_val = val_mgr->Port(ntohs(up->uh_dport), TRANSPORT_UDP); - - if ( udp_content_ports->FindOrDefault(dport_val) || - udp_content_ports->FindOrDefault(sport_val) ) - do_udp_contents = true; - else - { - uint16_t p = zeek::detail::udp_content_delivery_ports_use_resp ? Conn()->RespPort() - : up->uh_dport; - const auto& port_val = zeek::val_mgr->Port(ntohs(p), TRANSPORT_UDP); - - if ( is_orig ) - { - auto result = udp_content_delivery_ports_orig->FindOrDefault(port_val); - - if ( zeek::detail::udp_content_deliver_all_orig || (result && result->AsBool()) ) - do_udp_contents = true; - } - else - { - auto result = udp_content_delivery_ports_resp->FindOrDefault(port_val); - - if ( zeek::detail::udp_content_deliver_all_resp || (result && result->AsBool()) ) - do_udp_contents = true; - } - } - - if ( do_udp_contents ) - EnqueueConnEvent(udp_contents, - ConnVal(), - val_mgr->Bool(is_orig), - make_intrusive(len, (const char*) data)); - } - - if ( is_orig ) - { - Conn()->CheckHistory(HIST_ORIG_DATA_PKT, 'D'); - - if ( request_len < 0 ) - request_len = ulen; - else - { - request_len += ulen; -#ifdef DEBUG - if ( request_len < 0 ) - reporter->Warning("wrapping around for UDP request length"); -#endif - } - - Event(udp_request); - } - - else - { - Conn()->CheckHistory(HIST_RESP_DATA_PKT, 'd'); - - if ( reply_len < 0 ) - reply_len = ulen; - else - { - reply_len += ulen; -#ifdef DEBUG - if ( reply_len < 0 ) - reporter->Warning("wrapping around for UDP reply length"); -#endif - } - - Event(udp_reply); - } - - if ( caplen >= len ) - ForwardPacket(len, data, is_orig, seq, ip, caplen); - } - -void UDP_Analyzer::UpdateConnVal(RecordVal* conn_val) - { - auto orig_endp = conn_val->GetFieldAs("orig"); - auto resp_endp = conn_val->GetFieldAs("resp"); - - UpdateEndpointVal(orig_endp, true); - UpdateEndpointVal(resp_endp, false); - - // Call children's UpdateConnVal - Analyzer::UpdateConnVal(conn_val); - } - -void UDP_Analyzer::UpdateEndpointVal(RecordVal* endp, bool is_orig) - { - bro_int_t size = is_orig ? request_len : reply_len; - if ( size < 0 ) - { - endp->Assign(0, 0); - endp->Assign(1, UDP_INACTIVE); - } - - else - { - endp->Assign(0, static_cast(size)); - endp->Assign(1, UDP_ACTIVE); - } - } - -bool UDP_Analyzer::IsReuse(double /* t */, const u_char* /* pkt */) - { - return false; - } - -unsigned int UDP_Analyzer::MemoryAllocation() const - { - // A rather low lower bound.... - return Analyzer::MemoryAllocation() + padded_sizeof(*this) - 24; - } - -void UDP_Analyzer::ChecksumEvent(bool is_orig, uint32_t threshold) - { - Conn()->HistoryThresholdEvent(udp_multiple_checksum_errors, - is_orig, threshold); - } - -bool UDP_Analyzer::ValidateChecksum(const IP_Hdr* ip, const udphdr* up, int len) - { - auto sum = detail::ip_in_cksum(ip->IP4_Hdr(), ip->SrcAddr(), ip->DstAddr(), - IPPROTO_UDP, - reinterpret_cast(up), len); - - return sum == 0xffff; - } - -} // namespace zeek::analyzer::udp diff --git a/src/analyzer/protocol/udp/UDP.h b/src/analyzer/protocol/udp/UDP.h deleted file mode 100644 index 1a1ef94e62..0000000000 --- a/src/analyzer/protocol/udp/UDP.h +++ /dev/null @@ -1,57 +0,0 @@ -// See the file "COPYING" in the main distribution directory for copyright. - -#pragma once - -// This will include netinet/udp.h for us, plus set up some defines that make it work on all -// of the CI platforms. -#include "zeek/net_util.h" - -#include "zeek/analyzer/Analyzer.h" - -namespace zeek::analyzer::udp { - -enum UDP_EndpointState { - UDP_INACTIVE, // no packet seen - UDP_ACTIVE, // packets seen -}; - -class UDP_Analyzer final : public analyzer::TransportLayerAnalyzer { -public: - explicit UDP_Analyzer(Connection* conn); - ~UDP_Analyzer() override; - - void Init() override; - void UpdateConnVal(RecordVal *conn_val) override; - - static analyzer::Analyzer* Instantiate(Connection* conn) - { return new UDP_Analyzer(conn); } - -protected: - void Done() override; - void DeliverPacket(int len, const u_char* data, bool orig, - uint64_t seq, const IP_Hdr* ip, int caplen) override; - bool IsReuse(double t, const u_char* pkt) override; - unsigned int MemoryAllocation() const override; - - void ChecksumEvent(bool is_orig, uint32_t threshold); - - // Returns true if the checksum is valid, false if not - static bool ValidateChecksum(const IP_Hdr* ip, const struct udphdr* up, - int len); - - bro_int_t request_len, reply_len; - -private: - void UpdateEndpointVal(RecordVal* endp, bool is_orig); - -#define HIST_ORIG_DATA_PKT 0x1 -#define HIST_RESP_DATA_PKT 0x2 -#define HIST_ORIG_CORRUPT_PKT 0x4 -#define HIST_RESP_CORRUPT_PKT 0x8 - - // For tracking checksum history. - uint32_t req_chk_cnt, req_chk_thresh; - uint32_t rep_chk_cnt, rep_chk_thresh; -}; - -} // namespace zeek::analyzer::udp diff --git a/src/fuzzers/pop3-fuzzer.cc b/src/fuzzers/pop3-fuzzer.cc index c5d2b8e2c0..7bd036af89 100644 --- a/src/fuzzers/pop3-fuzzer.cc +++ b/src/fuzzers/pop3-fuzzer.cc @@ -41,7 +41,7 @@ static zeek::analyzer::Analyzer* add_analyzer(zeek::Connection* conn) auto a = zeek::analyzer_mgr->InstantiateAnalyzer(ZEEK_FUZZ_ANALYZER, conn); tcp->AddChildAnalyzer(a); tcp->AddChildAnalyzer(pia->AsAnalyzer()); - conn->SetRootAnalyzer(tcp, pia); + conn->SetSessionAdapter(tcp, pia); return a; } diff --git a/src/iosource/Packet.h b/src/iosource/Packet.h index 20469b3105..dfd0ec356c 100644 --- a/src/iosource/Packet.h +++ b/src/iosource/Packet.h @@ -189,6 +189,13 @@ public: */ mutable bool dump_packet; + /** + * Indicates the amount of data to be dumped. If only a header is needed, + * set this to the size of the header. Setting it to zero will dump the + * entire packet. + */ + mutable int dump_size = 0; + // These are fields passed between various packet analyzers. They're best // stored with the packet so they stay available as the packet is passed // around. diff --git a/src/packet_analysis/Analyzer.cc b/src/packet_analysis/Analyzer.cc index 45b90a52fc..79b8f94602 100644 --- a/src/packet_analysis/Analyzer.cc +++ b/src/packet_analysis/Analyzer.cc @@ -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; } diff --git a/src/packet_analysis/Analyzer.h b/src/packet_analysis/Analyzer.h index 90a3508aca..eeaf36edf7 100644 --- a/src/packet_analysis/Analyzer.h +++ b/src/packet_analysis/Analyzer.h @@ -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); }; diff --git a/src/packet_analysis/Manager.cc b/src/packet_analysis/Manager.cc index 0bf4252ec8..c307823c76 100644 --- a/src/packet_analysis/Manager.cc +++ b/src/packet_analysis/Manager.cc @@ -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) diff --git a/src/packet_analysis/protocol/CMakeLists.txt b/src/packet_analysis/protocol/CMakeLists.txt index 62d1e1549b..9468bf2625 100644 --- a/src/packet_analysis/protocol/CMakeLists.txt +++ b/src/packet_analysis/protocol/CMakeLists.txt @@ -15,6 +15,9 @@ add_subdirectory(linux_sll) add_subdirectory(arp) add_subdirectory(ip) +add_subdirectory(udp) +add_subdirectory(tcp) +add_subdirectory(icmp) add_subdirectory(gre) add_subdirectory(iptunnel) add_subdirectory(vntag) diff --git a/src/analyzer/protocol/icmp/CMakeLists.txt b/src/packet_analysis/protocol/icmp/CMakeLists.txt similarity index 100% rename from src/analyzer/protocol/icmp/CMakeLists.txt rename to src/packet_analysis/protocol/icmp/CMakeLists.txt diff --git a/src/analyzer/protocol/icmp/ICMP.cc b/src/packet_analysis/protocol/icmp/ICMP.cc similarity index 57% rename from src/analyzer/protocol/icmp/ICMP.cc rename to src/packet_analysis/protocol/icmp/ICMP.cc index 4abcca8f62..8ceba9cf3a 100644 --- a/src/analyzer/protocol/icmp/ICMP.cc +++ b/src/packet_analysis/protocol/icmp/ICMP.cc @@ -1,55 +1,89 @@ // See the file "COPYING" in the main distribution directory for copyright. -#include "zeek/zeek-config.h" -#include "zeek/analyzer/protocol/icmp/ICMP.h" +#include "zeek/packet_analysis/protocol/icmp/ICMP.h" #include -#include -#include "zeek/IP.h" #include "zeek/RunState.h" -#include "zeek/NetVar.h" -#include "zeek/Event.h" #include "zeek/Conn.h" -#include "zeek/Desc.h" #include "zeek/Reporter.h" +#include "zeek/Desc.h" +#include "zeek/Val.h" +#include "zeek/analyzer/Manager.h" +#include "zeek/session/Manager.h" +#include "zeek/analyzer/protocol/conn-size/ConnSize.h" -#include "zeek/analyzer/protocol/icmp/events.bif.h" +#include "zeek/ZeekString.h" -namespace zeek::analyzer::icmp { +#include "zeek/packet_analysis/protocol/icmp/events.bif.h" -ICMP_Analyzer::ICMP_Analyzer(Connection* c) - : TransportLayerAnalyzer("ICMP", c), - icmp_conn_val(), type(), code(), request_len(-1), reply_len(-1) +enum ICMP_EndpointState { + ICMP_INACTIVE, // no packet seen + ICMP_ACTIVE, // packets seen +}; + +using namespace zeek::packet_analysis::ICMP; +using namespace zeek::packet_analysis::IP; + +ICMPAnalyzer::ICMPAnalyzer() : IPBasedAnalyzer("ICMP", TRANSPORT_ICMP, ICMP_PORT_MASK, false) { - c->SetInactivityTimeout(zeek::detail::icmp_inactivity_timeout); + // TODO: remove once the other plugins are done + new_plugin = true; } -void ICMP_Analyzer::Done() +ICMPAnalyzer::~ICMPAnalyzer() { - TransportLayerAnalyzer::Done(); - icmp_conn_val = nullptr; - matcher_state.FinishEndpointMatcher(); } -void ICMP_Analyzer::DeliverPacket(int len, const u_char* data, - bool is_orig, uint64_t seq, const IP_Hdr* ip, int caplen) +SessionAdapter* ICMPAnalyzer::MakeSessionAdapter(Connection* conn) { - assert(ip); + auto* root = new ICMPSessionAdapter(conn); + root->SetParent(this); + conn->SetInactivityTimeout(zeek::detail::icmp_inactivity_timeout); - TransportLayerAnalyzer::DeliverPacket(len, data, is_orig, seq, ip, caplen); + return root; + } - // We need the min() here because Ethernet frame padding can lead to - // caplen > len. - if ( packet_contents ) - // Subtract off the common part of ICMP header. - PacketContents(data + 8, std::min(len, caplen) - 8); +bool ICMPAnalyzer::BuildConnTuple(size_t len, const uint8_t* data, Packet* packet, + ConnTuple& tuple) + { + if ( ! CheckHeaderTrunc(ICMP_MINLEN, len, packet) ) + return false; + + tuple.src_addr = packet->ip_hdr->SrcAddr(); + tuple.dst_addr = packet->ip_hdr->DstAddr(); + tuple.proto = TRANSPORT_ICMP; + + const struct icmp* icmpp = (const struct icmp *) data; + tuple.src_port = htons(icmpp->icmp_type); + + if ( packet->proto == IPPROTO_ICMP ) + tuple.dst_port = htons(ICMP4_counterpart(icmpp->icmp_type, icmpp->icmp_code, tuple.is_one_way)); + else if ( packet->proto == IPPROTO_ICMPV6 ) + tuple.dst_port = htons(ICMP6_counterpart(icmpp->icmp_type, icmpp->icmp_code, tuple.is_one_way)); + else + reporter->InternalError("Reached ICMP packet analyzer with unknown packet protocol %x", + packet->proto); + + return true; + } + +void ICMPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int remaining, Packet* pkt) + { + auto* adapter = static_cast(c->GetSessionAdapter()); + + const u_char* data = pkt->ip_hdr->Payload(); + int len = pkt->ip_hdr->PayloadLen(); + + if ( packet_contents && len > 0 ) + adapter->PacketContents(data + 8, std::min(len, remaining) - 8); const struct icmp* icmpp = (const struct icmp*) data; + const std::unique_ptr& ip = pkt->ip_hdr; if ( ! zeek::detail::ignore_checksums && ! zeek::id::find_val("ignore_checksums_nets")->Contains(ip->IPHeaderSrcAddr()) && - caplen >= len ) + remaining >= len ) { int chksum = 0; @@ -60,94 +94,81 @@ void ICMP_Analyzer::DeliverPacket(int len, const u_char* data, break; case IPPROTO_ICMPV6: - chksum = icmp6_checksum(icmpp, ip, len); + chksum = icmp6_checksum(icmpp, ip.get(), len); break; default: - reporter->AnalyzerError( - this, "unexpected IP proto in ICMP analyzer: %d", ip->NextProto()); + reporter->Error("unexpected IP proto in ICMP analyzer: %d", ip->NextProto()); return; } if ( chksum != 0xffff ) { - Weird("bad_ICMP_checksum"); + adapter->Weird("bad_ICMP_checksum"); return; } } - Conn()->SetLastTime(run_state::current_timestamp); - - if ( zeek::detail::rule_matcher ) - { - if ( ! matcher_state.MatcherInitialized(is_orig) ) - matcher_state.InitEndpointMatcher(this, ip, len, is_orig, nullptr); - } - - type = icmpp->icmp_type; - code = icmpp->icmp_code; + c->SetLastTime(run_state::current_timestamp); + adapter->InitEndpointMatcher(ip.get(), len, is_orig); // Move past common portion of ICMP header. data += 8; - caplen -= 8; + remaining -= 8; len -= 8; - int& len_stat = is_orig ? request_len : reply_len; - if ( len_stat < 0 ) - len_stat = len; - else - len_stat += len; + adapter->UpdateLength(is_orig, len); if ( ip->NextProto() == IPPROTO_ICMP ) - NextICMP4(run_state::current_timestamp, icmpp, len, caplen, data, ip); + NextICMP4(run_state::current_timestamp, icmpp, len, remaining, data, ip.get(), adapter); else if ( ip->NextProto() == IPPROTO_ICMPV6 ) - NextICMP6(run_state::current_timestamp, icmpp, len, caplen, data, ip); + NextICMP6(run_state::current_timestamp, icmpp, len, remaining, data, ip.get(), adapter); else { - reporter->AnalyzerError( - this, "expected ICMP as IP packet's protocol, got %d", ip->NextProto()); + reporter->Error("expected ICMP as IP packet's protocol, got %d", ip->NextProto()); return; } + ForwardPacket(len, data, pkt); - if ( caplen >= len ) - ForwardPacket(len, data, is_orig, seq, ip, caplen); + if ( remaining >= len ) + adapter->ForwardPacket(len, data, is_orig, -1, ip.get(), remaining); - if ( zeek::detail::rule_matcher ) - matcher_state.Match(zeek::detail::Rule::PAYLOAD, data, len, is_orig, - false, false, true); + adapter->MatchEndpoint(data, len, is_orig); } -void ICMP_Analyzer::NextICMP4(double t, const struct icmp* icmpp, int len, int caplen, - const u_char*& data, const IP_Hdr* ip_hdr ) +void ICMPAnalyzer::NextICMP4(double t, const struct icmp* icmpp, int len, int caplen, + const u_char*& data, const IP_Hdr* ip_hdr, + ICMPSessionAdapter* adapter) { switch ( icmpp->icmp_type ) { case ICMP_ECHO: case ICMP_ECHOREPLY: - Echo(t, icmpp, len, caplen, data, ip_hdr); + Echo(t, icmpp, len, caplen, data, ip_hdr, adapter); break; case ICMP_UNREACH: case ICMP_TIMXCEED: - Context4(t, icmpp, len, caplen, data, ip_hdr); + Context4(t, icmpp, len, caplen, data, ip_hdr, adapter); break; default: - ICMP_Sent(icmpp, len, caplen, 0, data, ip_hdr); + ICMP_Sent(icmpp, len, caplen, 0, data, ip_hdr, adapter); break; } } -void ICMP_Analyzer::NextICMP6(double t, const struct icmp* icmpp, int len, int caplen, - const u_char*& data, const IP_Hdr* ip_hdr ) +void ICMPAnalyzer::NextICMP6(double t, const struct icmp* icmpp, int len, int caplen, + const u_char*& data, const IP_Hdr* ip_hdr, + ICMPSessionAdapter* adapter) { switch ( icmpp->icmp_type ) { // Echo types. case ICMP6_ECHO_REQUEST: case ICMP6_ECHO_REPLY: - Echo(t, icmpp, len, caplen, data, ip_hdr); + Echo(t, icmpp, len, caplen, data, ip_hdr, adapter); break; // Error messages all have the same structure for their context, @@ -156,27 +177,27 @@ void ICMP_Analyzer::NextICMP6(double t, const struct icmp* icmpp, int len, int c case ICMP6_TIME_EXCEEDED: case ICMP6_PACKET_TOO_BIG: case ICMP6_DST_UNREACH: - Context6(t, icmpp, len, caplen, data, ip_hdr); + Context6(t, icmpp, len, caplen, data, ip_hdr, adapter); break; // Router related messages. case ND_REDIRECT: - Redirect(t, icmpp, len, caplen, data, ip_hdr); + Redirect(t, icmpp, len, caplen, data, ip_hdr, adapter); break; case ND_ROUTER_ADVERT: - RouterAdvert(t, icmpp, len, caplen, data, ip_hdr); + RouterAdvert(t, icmpp, len, caplen, data, ip_hdr, adapter); break; case ND_NEIGHBOR_ADVERT: - NeighborAdvert(t, icmpp, len, caplen, data, ip_hdr); + NeighborAdvert(t, icmpp, len, caplen, data, ip_hdr, adapter); break; case ND_NEIGHBOR_SOLICIT: - NeighborSolicit(t, icmpp, len, caplen, data, ip_hdr); + NeighborSolicit(t, icmpp, len, caplen, data, ip_hdr, adapter); break; case ND_ROUTER_SOLICIT: - RouterSolicit(t, icmpp, len, caplen, data, ip_hdr); + RouterSolicit(t, icmpp, len, caplen, data, ip_hdr, adapter); break; case ICMP6_ROUTER_RENUMBERING: - ICMP_Sent(icmpp, len, caplen, 1, data, ip_hdr); + ICMP_Sent(icmpp, len, caplen, 1, data, ip_hdr, adapter); break; #if 0 @@ -190,49 +211,45 @@ void ICMP_Analyzer::NextICMP6(double t, const struct icmp* icmpp, int len, int c // the same structure for their context, and are // handled by the same function. if ( icmpp->icmp_type < 128 ) - Context6(t, icmpp, len, caplen, data, ip_hdr); + Context6(t, icmpp, len, caplen, data, ip_hdr, adapter); else - ICMP_Sent(icmpp, len, caplen, 1, data, ip_hdr); + ICMP_Sent(icmpp, len, caplen, 1, data, ip_hdr, adapter); break; } } -void ICMP_Analyzer::ICMP_Sent(const struct icmp* icmpp, int len, int caplen, - int icmpv6, const u_char* data, - const IP_Hdr* ip_hdr) +void ICMPAnalyzer::ICMP_Sent(const struct icmp* icmpp, int len, int caplen, + int icmpv6, const u_char* data, const IP_Hdr* ip_hdr, + ICMPSessionAdapter* adapter) { if ( icmp_sent ) - EnqueueConnEvent(icmp_sent, - ConnVal(), - BuildInfo(icmpp, len, icmpv6, ip_hdr) - ); + adapter->EnqueueConnEvent(icmp_sent, adapter->ConnVal(), + BuildInfo(icmpp, len, icmpv6, ip_hdr)); if ( icmp_sent_payload ) { String* payload = new String(data, std::min(len, caplen), false); - EnqueueConnEvent(icmp_sent_payload, - ConnVal(), - BuildInfo(icmpp, len, icmpv6, ip_hdr), - make_intrusive(payload) - ); + adapter->EnqueueConnEvent(icmp_sent_payload, adapter->ConnVal(), + BuildInfo(icmpp, len, icmpv6, ip_hdr), + make_intrusive(payload)); } } -RecordValPtr ICMP_Analyzer::BuildInfo(const struct icmp* icmpp, int len, +zeek::RecordValPtr ICMPAnalyzer::BuildInfo(const struct icmp* icmpp, int len, bool icmpv6, const IP_Hdr* ip_hdr) { static auto icmp_info = id::find_type("icmp_info"); - auto rval = make_intrusive(icmp_info); - rval->Assign(0, static_cast(icmpv6)); - rval->Assign(1, icmpp->icmp_type); - rval->Assign(2, icmpp->icmp_code); - rval->Assign(3, len); - rval->Assign(4, ip_hdr->TTL()); + auto rval = make_intrusive(icmp_info); + rval->Assign(0, val_mgr->Bool(icmpv6)); + rval->Assign(1, val_mgr->Count(icmpp->icmp_type)); + rval->Assign(2, val_mgr->Count(icmpp->icmp_code)); + rval->Assign(3, val_mgr->Count(len)); + rval->Assign(4, val_mgr->Count(ip_hdr->TTL())); return rval; } -TransportProto ICMP_Analyzer::GetContextProtocol(const IP_Hdr* ip_hdr, uint32_t* src_port, uint32_t* dst_port) +TransportProto ICMPAnalyzer::GetContextProtocol(const IP_Hdr* ip_hdr, uint32_t* src_port, uint32_t* dst_port) { const u_char* transport_hdr; uint32_t ip_hdr_len = ip_hdr->HdrLen(); @@ -297,7 +314,7 @@ TransportProto ICMP_Analyzer::GetContextProtocol(const IP_Hdr* ip_hdr, uint32_t* return proto; } -RecordValPtr ICMP_Analyzer::ExtractICMP4Context(int len, const u_char*& data) +zeek::RecordValPtr ICMPAnalyzer::ExtractICMP4Context(int len, const u_char*& data) { const IP_Hdr ip_hdr_data((const struct ip*) data, false); const IP_Hdr* ip_hdr = &ip_hdr_data; @@ -346,8 +363,8 @@ RecordValPtr ICMP_Analyzer::ExtractICMP4Context(int len, const u_char*& data) } static auto icmp_context = id::find_type("icmp_context"); - auto iprec = make_intrusive(icmp_context); - auto id_val = make_intrusive(id::conn_id); + auto iprec = make_intrusive(icmp_context); + auto id_val = make_intrusive(id::conn_id); id_val->Assign(0, make_intrusive(src_addr)); id_val->Assign(1, val_mgr->Port(src_port, proto)); @@ -355,18 +372,18 @@ RecordValPtr ICMP_Analyzer::ExtractICMP4Context(int len, const u_char*& data) id_val->Assign(3, val_mgr->Port(dst_port, proto)); iprec->Assign(0, std::move(id_val)); - iprec->Assign(1, ip_len); - iprec->Assign(2, proto); - iprec->Assign(3, frag_offset); - iprec->Assign(4, static_cast(bad_hdr_len)); - iprec->Assign(5, static_cast(bad_checksum)); - iprec->Assign(6, static_cast(MF)); - iprec->Assign(7, static_cast(DF)); + iprec->Assign(1, val_mgr->Count(ip_len)); + iprec->Assign(2, val_mgr->Count(proto)); + iprec->Assign(3, val_mgr->Count(frag_offset)); + iprec->Assign(4, val_mgr->Bool(bad_hdr_len)); + iprec->Assign(5, val_mgr->Bool(bad_checksum)); + iprec->Assign(6, val_mgr->Bool(MF)); + iprec->Assign(7, val_mgr->Bool(DF)); return iprec; } -RecordValPtr ICMP_Analyzer::ExtractICMP6Context(int len, const u_char*& data) +zeek::RecordValPtr ICMPAnalyzer::ExtractICMP6Context(int len, const u_char*& data) { int DF = 0, MF = 0, bad_hdr_len = 0; TransportProto proto = TRANSPORT_UNKNOWN; @@ -406,8 +423,8 @@ RecordValPtr ICMP_Analyzer::ExtractICMP6Context(int len, const u_char*& data) } static auto icmp_context = id::find_type("icmp_context"); - auto iprec = make_intrusive(icmp_context); - auto id_val = make_intrusive(id::conn_id); + auto iprec = make_intrusive(icmp_context); + auto id_val = make_intrusive(id::conn_id); id_val->Assign(0, make_intrusive(src_addr)); id_val->Assign(1, val_mgr->Port(src_port, proto)); @@ -415,84 +432,21 @@ RecordValPtr ICMP_Analyzer::ExtractICMP6Context(int len, const u_char*& data) id_val->Assign(3, val_mgr->Port(dst_port, proto)); iprec->Assign(0, std::move(id_val)); - iprec->Assign(1, ip_len); - iprec->Assign(2, proto); - iprec->Assign(3, frag_offset); - iprec->Assign(4, static_cast(bad_hdr_len)); + iprec->Assign(1, val_mgr->Count(ip_len)); + iprec->Assign(2, val_mgr->Count(proto)); + iprec->Assign(3, val_mgr->Count(frag_offset)); + iprec->Assign(4, val_mgr->Bool(bad_hdr_len)); // bad_checksum is always false since IPv6 layer doesn't have a checksum. - iprec->Assign(5, false); - iprec->Assign(6, static_cast(MF)); - iprec->Assign(7, static_cast(DF)); + iprec->Assign(5, val_mgr->False()); + iprec->Assign(6, val_mgr->Bool(MF)); + iprec->Assign(7, val_mgr->Bool(DF)); return iprec; } -bool ICMP_Analyzer::IsReuse(double /* t */, const u_char* /* pkt */) - { - return false; - } - -void ICMP_Analyzer::Describe(ODesc* d) const - { - d->Add(Conn()->StartTime()); - d->Add("("); - d->Add(Conn()->LastTime()); - d->AddSP(")"); - - d->Add(Conn()->OrigAddr()); - d->Add("."); - d->Add(type); - d->Add("."); - d->Add(code); - - d->SP(); - d->AddSP("->"); - - d->Add(Conn()->RespAddr()); - } - -void ICMP_Analyzer::UpdateConnVal(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); - - // Call children's UpdateConnVal - Analyzer::UpdateConnVal(conn_val); - } - -void ICMP_Analyzer::UpdateEndpointVal(const ValPtr& endp_arg, bool is_orig) - { - Conn()->EnableStatusUpdateTimer(); - - int size = is_orig ? request_len : reply_len; - auto endp = endp_arg->AsRecordVal(); - - if ( size < 0 ) - { - endp->Assign(0, 0); - endp->Assign(1, ICMP_INACTIVE); - } - - else - { - endp->Assign(0, size); - endp->Assign(1, ICMP_ACTIVE); - } - } - -unsigned int ICMP_Analyzer::MemoryAllocation() const - { - return Analyzer::MemoryAllocation() - + padded_sizeof(*this) - padded_sizeof(Connection) - + (icmp_conn_val ? icmp_conn_val->MemoryAllocation() : 0); - } - - -void ICMP_Analyzer::Echo(double t, const struct icmp* icmpp, int len, - int caplen, const u_char*& data, const IP_Hdr* ip_hdr) +void ICMPAnalyzer::Echo(double t, const struct icmp* icmpp, int len, + int caplen, const u_char*& data, const IP_Hdr* ip_hdr, + ICMPSessionAdapter* adapter) { // For handling all Echo related ICMP messages EventHandlerPtr f = nullptr; @@ -512,8 +466,8 @@ void ICMP_Analyzer::Echo(double t, const struct icmp* icmpp, int len, String* payload = new String(data, caplen, false); - EnqueueConnEvent(f, - ConnVal(), + adapter->EnqueueConnEvent(f, + adapter->ConnVal(), BuildInfo(icmpp, len, ip_hdr->NextProto() != IPPROTO_ICMP, ip_hdr), val_mgr->Count(iid), val_mgr->Count(iseq), @@ -522,8 +476,9 @@ void ICMP_Analyzer::Echo(double t, const struct icmp* icmpp, int len, } -void ICMP_Analyzer::RouterAdvert(double t, const struct icmp* icmpp, int len, - int caplen, const u_char*& data, const IP_Hdr* ip_hdr) +void ICMPAnalyzer::RouterAdvert(double t, const struct icmp* icmpp, int len, + int caplen, const u_char*& data, const IP_Hdr* ip_hdr, + ICMPSessionAdapter* adapter) { EventHandlerPtr f = icmp_router_advertisement; @@ -540,8 +495,8 @@ void ICMP_Analyzer::RouterAdvert(double t, const struct icmp* icmpp, int len, int opt_offset = sizeof(reachable) + sizeof(retrans); - EnqueueConnEvent(f, - ConnVal(), + adapter->EnqueueConnEvent(f, + adapter->ConnVal(), BuildInfo(icmpp, len, 1, ip_hdr), val_mgr->Count(icmpp->icmp_num_addrs), // Cur Hop Limit val_mgr->Bool(icmpp->icmp_wpa & 0x80), // Managed @@ -553,13 +508,14 @@ void ICMP_Analyzer::RouterAdvert(double t, const struct icmp* icmpp, int len, make_intrusive((double)ntohs(icmpp->icmp_lifetime), Seconds), make_intrusive((double)ntohl(reachable), Milliseconds), make_intrusive((double)ntohl(retrans), Milliseconds), - BuildNDOptionsVal(caplen - opt_offset, data + opt_offset) + BuildNDOptionsVal(caplen - opt_offset, data + opt_offset, adapter) ); } -void ICMP_Analyzer::NeighborAdvert(double t, const struct icmp* icmpp, int len, - int caplen, const u_char*& data, const IP_Hdr* ip_hdr) +void ICMPAnalyzer::NeighborAdvert(double t, const struct icmp* icmpp, int len, + int caplen, const u_char*& data, const IP_Hdr* ip_hdr, + ICMPSessionAdapter* adapter) { EventHandlerPtr f = icmp_neighbor_advertisement; @@ -573,20 +529,21 @@ void ICMP_Analyzer::NeighborAdvert(double t, const struct icmp* icmpp, int len, int opt_offset = sizeof(in6_addr); - EnqueueConnEvent(f, - ConnVal(), + adapter->EnqueueConnEvent(f, + adapter->ConnVal(), BuildInfo(icmpp, len, 1, ip_hdr), val_mgr->Bool(icmpp->icmp_num_addrs & 0x80), // Router val_mgr->Bool(icmpp->icmp_num_addrs & 0x40), // Solicited val_mgr->Bool(icmpp->icmp_num_addrs & 0x20), // Override make_intrusive(tgtaddr), - BuildNDOptionsVal(caplen - opt_offset, data + opt_offset) + BuildNDOptionsVal(caplen - opt_offset, data + opt_offset, adapter) ); } -void ICMP_Analyzer::NeighborSolicit(double t, const struct icmp* icmpp, int len, - int caplen, const u_char*& data, const IP_Hdr* ip_hdr) +void ICMPAnalyzer::NeighborSolicit(double t, const struct icmp* icmpp, int len, + int caplen, const u_char*& data, const IP_Hdr* ip_hdr, + ICMPSessionAdapter* adapter) { EventHandlerPtr f = icmp_neighbor_solicitation; @@ -600,17 +557,18 @@ void ICMP_Analyzer::NeighborSolicit(double t, const struct icmp* icmpp, int len, int opt_offset = sizeof(in6_addr); - EnqueueConnEvent(f, - ConnVal(), + adapter->EnqueueConnEvent(f, + adapter->ConnVal(), BuildInfo(icmpp, len, 1, ip_hdr), make_intrusive(tgtaddr), - BuildNDOptionsVal(caplen - opt_offset, data + opt_offset) + BuildNDOptionsVal(caplen - opt_offset, data + opt_offset, adapter) ); } -void ICMP_Analyzer::Redirect(double t, const struct icmp* icmpp, int len, - int caplen, const u_char*& data, const IP_Hdr* ip_hdr) +void ICMPAnalyzer::Redirect(double t, const struct icmp* icmpp, int len, + int caplen, const u_char*& data, const IP_Hdr* ip_hdr, + ICMPSessionAdapter* adapter) { EventHandlerPtr f = icmp_redirect; @@ -627,34 +585,36 @@ void ICMP_Analyzer::Redirect(double t, const struct icmp* icmpp, int len, int opt_offset = 2 * sizeof(in6_addr); - EnqueueConnEvent(f, - ConnVal(), + adapter->EnqueueConnEvent(f, + adapter->ConnVal(), BuildInfo(icmpp, len, 1, ip_hdr), make_intrusive(tgtaddr), make_intrusive(dstaddr), - BuildNDOptionsVal(caplen - opt_offset, data + opt_offset) + BuildNDOptionsVal(caplen - opt_offset, data + opt_offset, adapter) ); } -void ICMP_Analyzer::RouterSolicit(double t, const struct icmp* icmpp, int len, - int caplen, const u_char*& data, const IP_Hdr* ip_hdr) +void ICMPAnalyzer::RouterSolicit(double t, const struct icmp* icmpp, int len, + int caplen, const u_char*& data, const IP_Hdr* ip_hdr, + ICMPSessionAdapter* adapter) { EventHandlerPtr f = icmp_router_solicitation; if ( ! f ) return; - EnqueueConnEvent(f, - ConnVal(), + adapter->EnqueueConnEvent(f, + adapter->ConnVal(), BuildInfo(icmpp, len, 1, ip_hdr), - BuildNDOptionsVal(caplen, data) + BuildNDOptionsVal(caplen, data, adapter) ); } -void ICMP_Analyzer::Context4(double t, const struct icmp* icmpp, - int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr) +void ICMPAnalyzer::Context4(double t, const struct icmp* icmpp, int len, + int caplen, const u_char*& data, const IP_Hdr* ip_hdr, + ICMPSessionAdapter* adapter) { EventHandlerPtr f = nullptr; @@ -670,8 +630,8 @@ void ICMP_Analyzer::Context4(double t, const struct icmp* icmpp, } if ( f ) - EnqueueConnEvent(f, - ConnVal(), + adapter->EnqueueConnEvent(f, + adapter->ConnVal(), BuildInfo(icmpp, len, 0, ip_hdr), val_mgr->Count(icmpp->icmp_code), ExtractICMP4Context(caplen, data) @@ -679,8 +639,9 @@ void ICMP_Analyzer::Context4(double t, const struct icmp* icmpp, } -void ICMP_Analyzer::Context6(double t, const struct icmp* icmpp, - int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr) +void ICMPAnalyzer::Context6(double t, const struct icmp* icmpp, int len, + int caplen, const u_char*& data, const IP_Hdr* ip_hdr, + ICMPSessionAdapter* adapter) { EventHandlerPtr f = nullptr; @@ -708,20 +669,21 @@ void ICMP_Analyzer::Context6(double t, const struct icmp* icmpp, } if ( f ) - EnqueueConnEvent(f, - ConnVal(), + adapter->EnqueueConnEvent(f, + adapter->ConnVal(), BuildInfo(icmpp, len, 1, ip_hdr), val_mgr->Count(icmpp->icmp_code), ExtractICMP6Context(caplen, data) ); } -VectorValPtr ICMP_Analyzer::BuildNDOptionsVal(int caplen, const u_char* data) +zeek::VectorValPtr ICMPAnalyzer::BuildNDOptionsVal(int caplen, const u_char* data, + ICMPSessionAdapter* adapter) { static auto icmp6_nd_option_type = id::find_type("icmp6_nd_option"); static auto icmp6_nd_prefix_info_type = id::find_type("icmp6_nd_prefix_info"); - auto vv = make_intrusive( + auto vv = make_intrusive( id::find_type("icmp6_nd_options")); while ( caplen > 0 ) @@ -729,7 +691,7 @@ VectorValPtr ICMP_Analyzer::BuildNDOptionsVal(int caplen, const u_char* data) // Must have at least type & length to continue parsing options. if ( caplen < 2 ) { - Weird("truncated_ICMPv6_ND_options"); + adapter->Weird("truncated_ICMPv6_ND_options"); break; } @@ -738,13 +700,13 @@ VectorValPtr ICMP_Analyzer::BuildNDOptionsVal(int caplen, const u_char* data) if ( length == 0 ) { - Weird("zero_length_ICMPv6_ND_option"); + adapter->Weird("zero_length_ICMPv6_ND_option"); break; } - auto rv = make_intrusive(icmp6_nd_option_type); - rv->Assign(0, type); - rv->Assign(1, length); + auto rv = make_intrusive(icmp6_nd_option_type); + rv->Assign(0, val_mgr->Count(type)); + rv->Assign(1, val_mgr->Count(length)); // Adjust length to be in units of bytes, exclude type/length fields. length = length * 8 - 2; @@ -763,7 +725,7 @@ VectorValPtr ICMP_Analyzer::BuildNDOptionsVal(int caplen, const u_char* data) if ( caplen >= length ) { String* link_addr = new String(data, length, false); - rv->Assign(2, link_addr); + rv->Assign(2, make_intrusive(link_addr)); } else set_payload_field = true; @@ -776,18 +738,18 @@ VectorValPtr ICMP_Analyzer::BuildNDOptionsVal(int caplen, const u_char* data) { if ( caplen >= 30 ) { - auto info = make_intrusive(icmp6_nd_prefix_info_type); + auto info = make_intrusive(icmp6_nd_prefix_info_type); uint8_t prefix_len = *((const uint8_t*)(data)); bool L_flag = (*((const uint8_t*)(data + 1)) & 0x80) != 0; bool A_flag = (*((const uint8_t*)(data + 1)) & 0x40) != 0; uint32_t valid_life = *((const uint32_t*)(data + 2)); uint32_t prefer_life = *((const uint32_t*)(data + 6)); in6_addr prefix = *((const in6_addr*)(data + 14)); - info->Assign(0, prefix_len); - info->Assign(1, L_flag); - info->Assign(2, A_flag); - info->AssignInterval(3, double(ntohl(valid_life))); - info->AssignInterval(4, double(ntohl(prefer_life))); + info->Assign(0, val_mgr->Count(prefix_len)); + info->Assign(1, val_mgr->Bool(L_flag)); + info->Assign(2, val_mgr->Bool(A_flag)); + info->Assign(3, make_intrusive((double)ntohl(valid_life), Seconds)); + info->Assign(4, make_intrusive((double)ntohl(prefer_life), Seconds)); info->Assign(5, make_intrusive(IPAddr(prefix))); rv->Assign(3, std::move(info)); } @@ -816,7 +778,7 @@ VectorValPtr ICMP_Analyzer::BuildNDOptionsVal(int caplen, const u_char* data) // MTU option { if ( caplen >= 6 ) - rv->Assign(5, ntohl(*((const uint32_t*)(data + 2)))); + rv->Assign(5, val_mgr->Count(ntohl(*((const uint32_t*)(data + 2))))); else set_payload_field = true; @@ -833,7 +795,7 @@ VectorValPtr ICMP_Analyzer::BuildNDOptionsVal(int caplen, const u_char* data) if ( set_payload_field ) { String* payload = new String(data, std::min((int)length, caplen), false); - rv->Assign(6, payload); + rv->Assign(6, make_intrusive(payload)); } data += length; @@ -845,7 +807,7 @@ VectorValPtr ICMP_Analyzer::BuildNDOptionsVal(int caplen, const u_char* data) return vv; } -int ICMP4_counterpart(int icmp_type, int icmp_code, bool& is_one_way) +int ICMPAnalyzer::ICMP4_counterpart(int icmp_type, int icmp_code, bool& is_one_way) { is_one_way = false; @@ -873,7 +835,7 @@ 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) +int ICMPAnalyzer::ICMP6_counterpart(int icmp_type, int icmp_code, bool& is_one_way) { is_one_way = false; @@ -905,4 +867,72 @@ int ICMP6_counterpart(int icmp_type, int icmp_code, bool& is_one_way) } } -} // namespace zeek::analyzer::icmp +void ICMPSessionAdapter::AddExtraAnalyzers(Connection* conn) + { + static analyzer::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)); + } + +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); + + analyzer::Analyzer::UpdateConnVal(conn_val); + } + +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(); + + 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::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::Done() + { + SessionAdapter::Done(); + matcher_state.FinishEndpointMatcher(); + } diff --git a/src/packet_analysis/protocol/icmp/ICMP.h b/src/packet_analysis/protocol/icmp/ICMP.h new file mode 100644 index 0000000000..6d930a98e9 --- /dev/null +++ b/src/packet_analysis/protocol/icmp/ICMP.h @@ -0,0 +1,138 @@ +// 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/packet_analysis/protocol/ip/IPBasedAnalyzer.h" +#include "zeek/analyzer/Analyzer.h" +#include "zeek/RuleMatcher.h" + +namespace zeek { + +class VectorVal; +using VectorValPtr = IntrusivePtr; +class RecordVal; +using RecordValPtr = IntrusivePtr; + +namespace packet_analysis::ICMP { + +class ICMPSessionAdapter; + +class ICMPAnalyzer final : public IP::IPBasedAnalyzer { +public: + ICMPAnalyzer(); + ~ICMPAnalyzer() override; + + static zeek::packet_analysis::AnalyzerPtr Instantiate() + { + return std::make_shared(); + } + + 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; + + 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 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 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 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); + + TransportProto GetContextProtocol(const IP_Hdr* ip_hdr, uint32_t* src_port, + uint32_t* dst_port); + + 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); + + // RFC 4861 Neighbor Discover message options + VectorValPtr BuildNDOptionsVal(int caplen, const u_char* data, + ICMPSessionAdapter* adapter); + + 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). + 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); + }; + +class ICMPSessionAdapter final : public IP::SessionAdapter { + +public: + + ICMPSessionAdapter(Connection* conn) : + IP::SessionAdapter("ICMP", conn) { } + + static zeek::analyzer::Analyzer* Instantiate(Connection* conn) + { + return new ICMPSessionAdapter(conn); + } + + 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 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; +}; + +} // namespace packet_analysis::ICMP +} // namespace zeek diff --git a/src/packet_analysis/protocol/icmp/Plugin.cc b/src/packet_analysis/protocol/icmp/Plugin.cc new file mode 100644 index 0000000000..d4aa34a7c3 --- /dev/null +++ b/src/packet_analysis/protocol/icmp/Plugin.cc @@ -0,0 +1,26 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#include "zeek/plugin/Plugin.h" +#include "zeek/packet_analysis/Component.h" +#include "zeek/packet_analysis/protocol/icmp/ICMP.h" + +namespace zeek::plugin::Zeek_ICMP { + +class Plugin : public zeek::plugin::Plugin { +public: + zeek::plugin::Configuration Configure() + { + AddComponent(new zeek::packet_analysis::Component("ICMP", + zeek::packet_analysis::ICMP::ICMPAnalyzer::Instantiate)); + AddComponent(new zeek::analyzer::Component("ICMP", + zeek::packet_analysis::ICMP::ICMPSessionAdapter::Instantiate)); + + zeek::plugin::Configuration config; + config.name = "Zeek::ICMP"; + config.description = "Packet analyzer for ICMP"; + return config; + } + +} plugin; + +} diff --git a/src/analyzer/protocol/icmp/events.bif b/src/packet_analysis/protocol/icmp/events.bif similarity index 100% rename from src/analyzer/protocol/icmp/events.bif rename to src/packet_analysis/protocol/icmp/events.bif diff --git a/src/packet_analysis/protocol/ip/CMakeLists.txt b/src/packet_analysis/protocol/ip/CMakeLists.txt index 3be79005d9..fb851f552e 100644 --- a/src/packet_analysis/protocol/ip/CMakeLists.txt +++ b/src/packet_analysis/protocol/ip/CMakeLists.txt @@ -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 SessionAdapter.cc Plugin.cc) zeek_plugin_end() diff --git a/src/packet_analysis/protocol/ip/IP.cc b/src/packet_analysis/protocol/ip/IP.cc index f38952bdc4..4d05600e6a 100644 --- a/src/packet_analysis/protocol/ip/IP.cc +++ b/src/packet_analysis/protocol/ip/IP.cc @@ -10,6 +10,7 @@ #include "zeek/Frag.h" #include "zeek/Event.h" #include "zeek/TunnelEncapsulation.h" +#include "zeek/IPAddr.h" using namespace zeek::packet_analysis::IP; @@ -235,14 +236,6 @@ bool IPAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) packet->proto = proto; switch ( proto ) { - case IPPROTO_TCP: - case IPPROTO_UDP: - case IPPROTO_ICMP: - case IPPROTO_ICMPV6: - DBG_LOG(DBG_PACKET_ANALYSIS, "Analysis in %s succeeded, next layer identifier is %#x.", - GetAnalyzerName(), proto); - session_mgr->ProcessTransportLayer(run_state::processing_start_time, packet, len); - break; 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 @@ -268,3 +261,40 @@ bool IPAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) return return_val; } + +int zeek::packet_analysis::IP::ParsePacket(int caplen, const u_char* const pkt, int proto, + std::unique_ptr& inner) + { + if ( proto == IPPROTO_IPV6 ) + { + if ( caplen < (int)sizeof(struct ip6_hdr) ) + return -1; + + const struct ip6_hdr* ip6 = (const struct ip6_hdr*) pkt; + inner = std::make_unique(ip6, false, caplen); + if ( ( ip6->ip6_ctlun.ip6_un2_vfc & 0xF0 ) != 0x60 ) + return -2; + } + + else if ( proto == IPPROTO_IPV4 ) + { + if ( caplen < (int)sizeof(struct ip) ) + return -1; + + const struct ip* ip4 = (const struct ip*) pkt; + inner = std::make_unique(ip4, false); + if ( ip4->ip_v != 4 ) + return -2; + } + + else + { + zeek::reporter->InternalWarning("Bad IP protocol version in IP::ParsePacket"); + return -1; + } + + if ( (uint32_t)caplen != inner->TotalLen() ) + return (uint32_t)caplen < inner->TotalLen() ? -1 : 1; + + return 0; + } diff --git a/src/packet_analysis/protocol/ip/IP.h b/src/packet_analysis/protocol/ip/IP.h index e24f842283..5baec822c1 100644 --- a/src/packet_analysis/protocol/ip/IP.h +++ b/src/packet_analysis/protocol/ip/IP.h @@ -32,4 +32,28 @@ private: zeek::detail::Discarder* discarder = nullptr; }; +/** + * Returns a wrapper IP_Hdr object if \a pkt appears to be a valid IPv4 + * or IPv6 header based on whether it's long enough to contain such a header, + * if version given in the header matches the proto argument, and also checks + * that the payload length field of that header matches the actual + * length of \a pkt given by \a caplen. + * + * @param caplen The length of \a pkt in bytes. + * @param pkt The inner IP packet data. + * @param proto Either IPPROTO_IPV6 or IPPROTO_IPV4 to indicate which IP + * protocol \a pkt corresponds to. + * @param inner The inner IP packet wrapper pointer to be allocated/assigned + * if \a pkt looks like a valid IP packet or at least long enough + * to hold an IP header. + * @return 0 If the inner IP packet appeared valid, else -1 if \a caplen + * is greater than the supposed IP packet's payload length field, -2 + * if the version of the inner header does not match proto or + * 1 if \a caplen is less than the supposed packet's payload length. + * In the -1 case, \a inner may still be non-null if \a caplen was + * long enough to be an IP header, and \a inner is always non-null + * for other return values. + */ +int ParsePacket(int caplen, const u_char* const pkt, int proto, + std::unique_ptr& inner); } diff --git a/src/packet_analysis/protocol/ip/IPBasedAnalyzer.cc b/src/packet_analysis/protocol/ip/IPBasedAnalyzer.cc new file mode 100644 index 0000000000..660d238366 --- /dev/null +++ b/src/packet_analysis/protocol/ip/IPBasedAnalyzer.cc @@ -0,0 +1,273 @@ +// 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" +#include "zeek/analyzer/protocol/pia/PIA.h" +#include "zeek/plugin/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() + { + } + +bool IPBasedAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* pkt) + { + ConnTuple tuple; + if ( ! BuildConnTuple(len, data, pkt, tuple) ) + return false; + + const std::unique_ptr& ip_hdr = pkt->ip_hdr; + detail::ConnKey key(tuple); + + 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); + + 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; + + bool is_orig = (tuple.src_addr == conn->OrigAddr()) && + (tuple.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 true; + + DeliverPacket(conn, run_state::processing_start_time, is_orig, len, 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(), + len, 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; + } + } + + return true; + } + +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 port_cache; + static bool have_cache = false; + + if ( ! have_cache ) + { + auto likely_server_ports = id::find_val("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 ( ! BuildSessionAnalyzerTree(conn) ) + { + conn->Done(); + Unref(conn); + return nullptr; + } + + if ( new_connection ) + conn->Event(new_connection, nullptr); + + return conn; + } + +bool IPBasedAnalyzer::BuildSessionAnalyzerTree(Connection* conn) + { + SessionAdapter* root = MakeSessionAdapter(conn); + analyzer::pia::PIA* pia = MakePIA(conn); + + // TODO: temporary, can be replaced when the port lookup stuff is moved from analyzer_mgr + bool check_port = conn->ConnTransport() != TRANSPORT_ICMP; + + 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 ( check_port && ! zeek::detail::dpd_ignore_ports ) + { + // TODO: ideally this lookup would be local to the packet analyzer instead of + // calling out to the analyzer manager. This code can move once the TCP work + // is in progress so that it doesn't have to be done piecemeal. + // + int resp_port = ntohs(conn->RespPort()); + std::set* ports = analyzer_mgr->LookupPort(conn->ConnTransport(), resp_port, false); + + if ( ports ) + { + for ( const auto& port : *ports ) + { + analyzer::Analyzer* analyzer = analyzer_mgr->InstantiateAnalyzer(port, conn); + + 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->AddExtraAnalyzers(conn); + + if ( pia ) + root->AddChildAnalyzer(pia->AsAnalyzer()); + + conn->SetSessionAdapter(root, pia); + root->Init(); + root->InitChildren(); + + PLUGIN_HOOK_VOID(HOOK_SETUP_ANALYZER_TREE, HookSetupAnalyzerTree(conn)); + + // TODO: temporary + return true; + } diff --git a/src/packet_analysis/protocol/ip/IPBasedAnalyzer.h b/src/packet_analysis/protocol/ip/IPBasedAnalyzer.h new file mode 100644 index 0000000000..425b541377 --- /dev/null +++ b/src/packet_analysis/protocol/ip/IPBasedAnalyzer.h @@ -0,0 +1,149 @@ +// 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/packet_analysis/protocol/ip/SessionAdapter.h" +#include "zeek/analyzer/Analyzer.h" +#include "zeek/analyzer/Manager.h" + +namespace zeek::analyzer::pia { class PIA; } + +namespace zeek::packet_analysis::IP { + +/** + * A base class for reuse by packet analyzers 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; + + 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; } + +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); + + /** + * 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) {} + + /** + * 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 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); + + /** + * 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; + + + // 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); + + bool BuildSessionAnalyzerTree(Connection* conn); + + TransportProto transport; + uint32_t server_port_mask; +}; + +} diff --git a/src/packet_analysis/protocol/ip/SessionAdapter.cc b/src/packet_analysis/protocol/ip/SessionAdapter.cc new file mode 100644 index 0000000000..15210328eb --- /dev/null +++ b/src/packet_analysis/protocol/ip/SessionAdapter.cc @@ -0,0 +1,39 @@ +#include "zeek/packet_analysis/protocol/ip/SessionAdapter.h" + +#include "zeek/File.h" +#include "zeek/ZeekString.h" +#include "zeek/packet_analysis/protocol/ip/IPBasedAnalyzer.h" + +using namespace zeek::packet_analysis::IP; + +void SessionAdapter::Done() + { + Analyzer::Done(); + } + +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"); + } + +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(cbs); + EnqueueConnEvent(packet_contents, ConnVal(), std::move(contents)); + } + } diff --git a/src/packet_analysis/protocol/ip/SessionAdapter.h b/src/packet_analysis/protocol/ip/SessionAdapter.h new file mode 100644 index 0000000000..71c9a58016 --- /dev/null +++ b/src/packet_analysis/protocol/ip/SessionAdapter.h @@ -0,0 +1,102 @@ +#pragma once + +#include "zeek/analyzer/Analyzer.h" + +namespace zeek::analyzer::pia { class PIA; } + +namespace zeek::packet_analysis::IP { + +class IPBasedAnalyzer; + +/** + * 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 SessionAdapter : public analyzer::Analyzer { + +public: + + SessionAdapter(const char* name, Connection* conn) + : analyzer::Analyzer(name, conn) { } + + /** + * 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; } + + /** + * 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 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; + + /** + * Associates a file with the analyzer in which to record all + * analyzed input. This must only be called with derived classes that + * overide 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 overide 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; } + + /** + * 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 dass to pass to the event. + * + * @param len The length of \a data. + */ + void PacketContents(const u_char* data, int len); + +protected: + + IPBasedAnalyzer* parent; + analyzer::pia::PIA* pia; +}; + +} // namespace zeek::packet_analysis::IP diff --git a/src/packet_analysis/protocol/iptunnel/IPTunnel.cc b/src/packet_analysis/protocol/iptunnel/IPTunnel.cc index 1131b2bce7..f6b9f07b12 100644 --- a/src/packet_analysis/protocol/iptunnel/IPTunnel.cc +++ b/src/packet_analysis/protocol/iptunnel/IPTunnel.cc @@ -4,10 +4,10 @@ #include // For DLT_ constants -#include "zeek/session/Manager.h" #include "zeek/RunState.h" #include "zeek/IP.h" #include "zeek/TunnelEncapsulation.h" +#include "zeek/packet_analysis/protocol/ip/IP.h" namespace zeek::packet_analysis::IPTunnel { @@ -45,12 +45,12 @@ bool IPTunnelAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* pa BifEnum::Tunnel::Type tunnel_type = packet->tunnel_type; int gre_link_type = packet->gre_link_type; - IP_Hdr* inner = nullptr; + std::unique_ptr inner = nullptr; if ( gre_version != 0 ) { // Check for a valid inner packet first. - int result = session_mgr->ParseIPPacket(len, data, proto, inner); + int result = packet_analysis::IP::ParsePacket(len, data, proto, inner); if ( result == -2 ) Weird("invalid_inner_IP_version", packet); else if ( result < 0 ) @@ -59,10 +59,7 @@ bool IPTunnelAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* pa Weird("inner_IP_payload_length_mismatch", packet); if ( result != 0 ) - { - delete inner; return false; - } } // Look up to see if we've already seen this IP tunnel, identified @@ -100,7 +97,7 @@ bool IPTunnelAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* pa * Handles a packet that contains an IP header directly after the tunnel header. */ bool IPTunnelAnalyzer::ProcessEncapsulatedPacket(double t, const Packet* pkt, - const IP_Hdr* inner, + const std::unique_ptr& inner, std::shared_ptr prev, const EncapsulatingConn& ec) { @@ -138,8 +135,6 @@ bool IPTunnelAnalyzer::ProcessEncapsulatedPacket(double t, const Packet* pkt, // Forward the packet back to the IP analyzer. bool return_val = ForwardPacket(len, data, &p); - delete inner; - return return_val; } diff --git a/src/packet_analysis/protocol/iptunnel/IPTunnel.h b/src/packet_analysis/protocol/iptunnel/IPTunnel.h index ddc8e04466..4e8242b17d 100644 --- a/src/packet_analysis/protocol/iptunnel/IPTunnel.h +++ b/src/packet_analysis/protocol/iptunnel/IPTunnel.h @@ -40,7 +40,7 @@ public: * @param ec The most-recently found depth of encapsulation. */ bool ProcessEncapsulatedPacket(double t, const Packet *pkt, - const IP_Hdr* inner, + const std::unique_ptr& inner, std::shared_ptr prev, const EncapsulatingConn& ec); diff --git a/src/packet_analysis/protocol/tcp/CMakeLists.txt b/src/packet_analysis/protocol/tcp/CMakeLists.txt new file mode 100644 index 0000000000..c42cca2b25 --- /dev/null +++ b/src/packet_analysis/protocol/tcp/CMakeLists.txt @@ -0,0 +1,8 @@ + +include(ZeekPlugin) + +include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) + +zeek_plugin_begin(PacketAnalyzer TCP_PKT) +zeek_plugin_cc(TCP.cc Plugin.cc) +zeek_plugin_end() diff --git a/src/packet_analysis/protocol/tcp/Plugin.cc b/src/packet_analysis/protocol/tcp/Plugin.cc new file mode 100644 index 0000000000..45b41c3884 --- /dev/null +++ b/src/packet_analysis/protocol/tcp/Plugin.cc @@ -0,0 +1,24 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#include "zeek/plugin/Plugin.h" +#include "zeek/packet_analysis/Component.h" +#include "zeek/packet_analysis/protocol/tcp/TCP.h" + +namespace zeek::plugin::Zeek_TCP { + +class Plugin : public zeek::plugin::Plugin { +public: + zeek::plugin::Configuration Configure() + { + AddComponent(new zeek::packet_analysis::Component("TCP", + zeek::packet_analysis::TCP::TCPAnalyzer::Instantiate)); + + zeek::plugin::Configuration config; + config.name = "Zeek::TCP_PKT"; + config.description = "Packet analyzer for TCP"; + return config; + } + +} plugin; + +} diff --git a/src/packet_analysis/protocol/tcp/TCP.cc b/src/packet_analysis/protocol/tcp/TCP.cc new file mode 100644 index 0000000000..e373d7b48c --- /dev/null +++ b/src/packet_analysis/protocol/tcp/TCP.cc @@ -0,0 +1,76 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#include "zeek/packet_analysis/protocol/tcp/TCP.h" +#include "zeek/RunState.h" + +using namespace zeek::packet_analysis::TCP; +using namespace zeek::packet_analysis::IP; + +TCPAnalyzer::TCPAnalyzer() : IPBasedAnalyzer("TCP", TRANSPORT_TCP, TCP_PORT_MASK, false) + { + } + +TCPAnalyzer::~TCPAnalyzer() + { + } + +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(); + + 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; + + 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; + } diff --git a/src/packet_analysis/protocol/tcp/TCP.h b/src/packet_analysis/protocol/tcp/TCP.h new file mode 100644 index 0000000000..cb5ec8e214 --- /dev/null +++ b/src/packet_analysis/protocol/tcp/TCP.h @@ -0,0 +1,54 @@ +// 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/packet_analysis/protocol/ip/IPBasedAnalyzer.h" + +namespace zeek::packet_analysis::TCP { + +class TCPAnalyzer final : public IP::IPBasedAnalyzer { +public: + TCPAnalyzer(); + ~TCPAnalyzer() override; + + static zeek::packet_analysis::AnalyzerPtr Instantiate() + { + return std::make_shared(); + } + + /** + * Returns an 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. + * + * TODO: this is a stub until the TCP analyzer moves to the packet analysis framework. + */ + IP::SessionAdapter* MakeSessionAdapter(Connection* conn) override { return nullptr; } + +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; + + /** + * 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; +}; + +} diff --git a/src/analyzer/protocol/udp/CMakeLists.txt b/src/packet_analysis/protocol/udp/CMakeLists.txt similarity index 100% rename from src/analyzer/protocol/udp/CMakeLists.txt rename to src/packet_analysis/protocol/udp/CMakeLists.txt diff --git a/src/packet_analysis/protocol/udp/Plugin.cc b/src/packet_analysis/protocol/udp/Plugin.cc new file mode 100644 index 0000000000..3ccab7b7d4 --- /dev/null +++ b/src/packet_analysis/protocol/udp/Plugin.cc @@ -0,0 +1,26 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#include "zeek/plugin/Plugin.h" +#include "zeek/packet_analysis/Component.h" +#include "zeek/packet_analysis/protocol/udp/UDP.h" + +namespace zeek::plugin::Zeek_UDP { + +class Plugin : public zeek::plugin::Plugin { +public: + zeek::plugin::Configuration Configure() + { + AddComponent(new zeek::packet_analysis::Component("UDP", + zeek::packet_analysis::UDP::UDPAnalyzer::Instantiate)); + AddComponent(new zeek::analyzer::Component("UDP", + zeek::packet_analysis::UDP::UDPSessionAdapter::Instantiate)); + + zeek::plugin::Configuration config; + config.name = "Zeek::UDP"; + config.description = "Packet analyzer for UDP"; + return config; + } + +} plugin; + +} diff --git a/src/packet_analysis/protocol/udp/UDP.cc b/src/packet_analysis/protocol/udp/UDP.cc new file mode 100644 index 0000000000..ffb2693e9d --- /dev/null +++ b/src/packet_analysis/protocol/udp/UDP.cc @@ -0,0 +1,338 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#include "zeek/packet_analysis/protocol/udp/UDP.h" +#include "zeek/RunState.h" +#include "zeek/Conn.h" +#include "zeek/session/Manager.h" +#include "zeek/analyzer/Manager.h" +#include "zeek/analyzer/protocol/pia/PIA.h" +#include "zeek/analyzer/protocol/conn-size/ConnSize.h" + +#include "zeek/packet_analysis/protocol/udp/events.bif.h" + +using namespace zeek::packet_analysis::UDP; +using namespace zeek::packet_analysis::IP; + +constexpr uint32_t HIST_ORIG_DATA_PKT = 0x1; +constexpr uint32_t HIST_RESP_DATA_PKT = 0x2; +constexpr uint32_t HIST_ORIG_CORRUPT_PKT = 0x4; +constexpr uint32_t HIST_RESP_CORRUPT_PKT = 0x8; + +enum UDP_EndpointState { + UDP_INACTIVE, // no packet seen + UDP_ACTIVE, // packets seen +}; + +UDPAnalyzer::UDPAnalyzer() : IPBasedAnalyzer("UDP", TRANSPORT_UDP, UDP_PORT_MASK, false) + { + // TODO: remove once the other plugins are done + new_plugin = true; + } + +UDPAnalyzer::~UDPAnalyzer() + { + } + +SessionAdapter* UDPAnalyzer::MakeSessionAdapter(Connection* conn) + { + auto* root = new UDPSessionAdapter(conn); + root->SetParent(this); + + conn->EnableStatusUpdateTimer(); + conn->SetInactivityTimeout(zeek::detail::udp_inactivity_timeout); + + return root; + } + +zeek::analyzer::pia::PIA* UDPAnalyzer::MakePIA(Connection* conn) + { + return new analyzer::pia::PIA_UDP(conn); + } + +void UDPAnalyzer::Initialize() + { + IPBasedAnalyzer::Initialize(); + + const auto& id = detail::global_scope()->Find("Tunnel::vxlan_ports"); + + if ( ! (id && id->GetVal()) ) + reporter->FatalError("Tunnel::vxlan_ports not defined"); + + auto table_val = id->GetVal()->AsTableVal(); + auto port_list = table_val->ToPureListVal(); + + for ( auto i = 0; i < port_list->Length(); ++i ) + vxlan_ports.emplace_back(port_list->Idx(i)->AsPortVal()->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; + } + +bool UDPAnalyzer::BuildConnTuple(size_t len, const uint8_t* data, Packet* packet, + ConnTuple& tuple) + { + uint32_t min_hdr_len = sizeof(struct udphdr); + if ( ! CheckHeaderTrunc(min_hdr_len, len, packet) ) + return false; + + tuple.src_addr = packet->ip_hdr->SrcAddr(); + tuple.dst_addr = packet->ip_hdr->DstAddr(); + + const struct udphdr* up = (const struct udphdr *) packet->ip_hdr->Payload(); + tuple.src_port = up->uh_sport; + tuple.dst_port = up->uh_dport; + tuple.is_one_way = false; + tuple.proto = TRANSPORT_UDP; + + return true; + } + +void UDPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int remaining, Packet* pkt) + { + auto* adapter = static_cast(c->GetSessionAdapter()); + + const u_char* data = pkt->ip_hdr->Payload(); + int len = pkt->ip_hdr->PayloadLen(); + + const struct udphdr* up = (const struct udphdr*) data; + const std::unique_ptr& ip = pkt->ip_hdr; + + adapter->DeliverPacket(len, data, is_orig, -1, ip.get(), remaining); + + // Increment data before checksum check so that data will + // point to UDP payload even if checksum fails. Particularly, + // it allows event packet_contents to get to the data. + data += sizeof(struct udphdr); + + // We need the min() here because Ethernet frame padding can lead to + // remaining > len. + if ( packet_contents ) + adapter->PacketContents(data, std::min(len, remaining) - sizeof(struct udphdr)); + + int chksum = up->uh_sum; + + auto validate_checksum = + ! run_state::current_pkt->l3_checksummed && + ! zeek::detail::ignore_checksums && + ! zeek::id::find_val("ignore_checksums_nets")->Contains(ip->IPHeaderSrcAddr()) && + remaining >=len; + + constexpr auto vxlan_len = 8; + constexpr auto eth_len = 14; + + if ( validate_checksum && + len > ((int)sizeof(struct udphdr) + vxlan_len + eth_len) && + (data[0] & 0x08) == 0x08 ) + { + if ( std::find(vxlan_ports.begin(), vxlan_ports.end(), + ntohs(up->uh_dport)) != vxlan_ports.end() ) + { + // Looks like VXLAN on a well-known port, so the checksum should be + // transmitted as zero, and we should accept that. If not + // transmitted as zero, then validating the checksum is optional. + if ( chksum == 0 ) + validate_checksum = false; + else + validate_checksum = BifConst::Tunnel::validate_vxlan_checksums; + } + } + + if ( validate_checksum ) + { + bool bad = false; + + if ( ip->IP4_Hdr() ) + { + if ( chksum && ! ValidateChecksum(ip.get(), up, len) ) + bad = true; + } + + /* checksum is not optional for IPv6 */ + else if ( ! ValidateChecksum(ip.get(), up, len) ) + bad = true; + + if ( bad ) + { + adapter->HandleBadChecksum(is_orig); + return; + } + } + + int ulen = ntohs(up->uh_ulen); + if ( ulen != len ) + adapter->Weird("UDP_datagram_length_mismatch", util::fmt("%d != %d", ulen, len)); + + len -= sizeof(struct udphdr); + ulen -= sizeof(struct udphdr); + remaining -= sizeof(struct udphdr); + + c->SetLastTime(run_state::current_timestamp); + + if ( udp_contents ) + { + static auto udp_content_ports = id::find_val("udp_content_ports"); + static auto udp_content_delivery_ports_orig = id::find_val("udp_content_delivery_ports_orig"); + static auto udp_content_delivery_ports_resp = id::find_val("udp_content_delivery_ports_resp"); + bool do_udp_contents = false; + const auto& sport_val = val_mgr->Port(ntohs(up->uh_sport), TRANSPORT_UDP); + const auto& dport_val = val_mgr->Port(ntohs(up->uh_dport), TRANSPORT_UDP); + + if ( udp_content_ports->FindOrDefault(dport_val) || + udp_content_ports->FindOrDefault(sport_val) ) + do_udp_contents = true; + else + { + uint16_t p = zeek::detail::udp_content_delivery_ports_use_resp ? c->RespPort() + : up->uh_dport; + const auto& port_val = zeek::val_mgr->Port(ntohs(p), TRANSPORT_UDP); + + if ( is_orig ) + { + auto result = udp_content_delivery_ports_orig->FindOrDefault(port_val); + + if ( zeek::detail::udp_content_deliver_all_orig || (result && result->AsBool()) ) + do_udp_contents = true; + } + else + { + auto result = udp_content_delivery_ports_resp->FindOrDefault(port_val); + + if ( zeek::detail::udp_content_deliver_all_resp || (result && result->AsBool()) ) + do_udp_contents = true; + } + } + + if ( do_udp_contents ) + adapter->EnqueueConnEvent(udp_contents, + adapter->ConnVal(), + val_mgr->Bool(is_orig), + make_intrusive(len, (const char*) data)); + } + + if ( is_orig ) + { + c->CheckHistory(HIST_ORIG_DATA_PKT, 'D'); + adapter->UpdateLength(is_orig, ulen); + adapter->Event(udp_request); + } + else + { + c->CheckHistory(HIST_RESP_DATA_PKT, 'd'); + adapter->UpdateLength(is_orig, ulen); + adapter->Event(udp_reply); + } + + // Send the packet back into the packet analysis framework. + ForwardPacket(len, data, pkt); + + // Also try sending it into session analysis. + if ( remaining >= len ) + adapter->ForwardPacket(len, data, is_orig, -1, ip.get(), remaining); + } + +bool UDPAnalyzer::ValidateChecksum(const IP_Hdr* ip, const udphdr* up, int len) + { + auto sum = detail::ip_in_cksum(ip->IP4_Hdr(), ip->SrcAddr(), ip->DstAddr(), + IPPROTO_UDP, + reinterpret_cast(up), len); + + return sum == 0xffff; + } + +void UDPSessionAdapter::AddExtraAnalyzers(Connection* conn) + { + static analyzer::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)); + } + +void UDPSessionAdapter::UpdateConnVal(RecordVal* conn_val) + { + auto orig_endp = conn_val->GetField("orig"); + auto resp_endp = conn_val->GetField("resp"); + + UpdateEndpointVal(orig_endp, true); + UpdateEndpointVal(resp_endp, false); + + // Call children's UpdateConnVal + Analyzer::UpdateConnVal(conn_val); + } + +void UDPSessionAdapter::UpdateEndpointVal(const ValPtr& endp_arg, bool is_orig) + { + bro_int_t 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, UDP_INACTIVE); + } + + else + { + endp->Assign(0, static_cast(size)); + endp->Assign(1, UDP_ACTIVE); + } + } + +void UDPSessionAdapter::UpdateLength(bool is_orig, int len) + { + if ( is_orig ) + { + if ( request_len < 0 ) + request_len = len; + else + { + request_len += len; +#ifdef DEBUG + if ( request_len < 0 ) + reporter->Warning("wrapping around for UDP request length"); +#endif + } + } + else + { + if ( reply_len < 0 ) + reply_len = len; + else + { + reply_len += len; +#ifdef DEBUG + if ( reply_len < 0 ) + reporter->Warning("wrapping around for UDP reply length"); +#endif + } + } + } + +void UDPSessionAdapter::HandleBadChecksum(bool is_orig) + { + Weird("bad_UDP_checksum"); + + if ( is_orig ) + { + uint32_t t = req_chk_thresh; + + if ( Conn()->ScaledHistoryEntry('C', req_chk_cnt, req_chk_thresh) ) + ChecksumEvent(is_orig, t); + } + else + { + uint32_t t = rep_chk_thresh; + + if ( Conn()->ScaledHistoryEntry('c', rep_chk_cnt, rep_chk_thresh) ) + ChecksumEvent(is_orig, t); + } + } + +void UDPSessionAdapter::ChecksumEvent(bool is_orig, uint32_t threshold) + { + Conn()->HistoryThresholdEvent(udp_multiple_checksum_errors, is_orig, threshold); + } diff --git a/src/packet_analysis/protocol/udp/UDP.h b/src/packet_analysis/protocol/udp/UDP.h new file mode 100644 index 0000000000..78fd0ce481 --- /dev/null +++ b/src/packet_analysis/protocol/udp/UDP.h @@ -0,0 +1,100 @@ +// 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/packet_analysis/protocol/ip/IPBasedAnalyzer.h" + +namespace zeek::packet_analysis::UDP { + +class UDPAnalyzer final : public IP::IPBasedAnalyzer { +public: + UDPAnalyzer(); + ~UDPAnalyzer() override; + + static zeek::packet_analysis::AnalyzerPtr Instantiate() + { + return std::make_shared(); + } + + /** + * 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; + +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; + + 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; + + packet_analysis::IP::SessionAdapter* MakeSessionAdapter(Connection* conn) override; + analyzer::pia::PIA* MakePIA(Connection* conn) override; + +private: + + // Returns true if the checksum is valid, false if not + static bool ValidateChecksum(const IP_Hdr* ip, const struct udphdr* up, + int len); + + std::vector vxlan_ports; +}; + +class UDPSessionAdapter final : public IP::SessionAdapter { + +public: + + UDPSessionAdapter(Connection* conn) : + IP::SessionAdapter("UDP", conn) { } + + static zeek::analyzer::Analyzer* Instantiate(Connection* conn) + { + return new UDPSessionAdapter(conn); + } + + void AddExtraAnalyzers(Connection* conn) override; + void UpdateConnVal(RecordVal* conn_val) override; + + void UpdateLength(bool is_orig, int len); + void HandleBadChecksum(bool is_orig); + + // For tracking checksum history. These are connection-specific so they + // need to be stored in the session adapter created for each connection. + uint32_t req_chk_cnt = 0; + uint32_t req_chk_thresh = 1; + uint32_t rep_chk_cnt = 0; + uint32_t rep_chk_thresh = 1; + +private: + + void UpdateEndpointVal(const ValPtr& endp_arg, bool is_orig); + void ChecksumEvent(bool is_orig, uint32_t threshold); + + bro_int_t request_len = -1; + bro_int_t reply_len = -1; +}; + +} diff --git a/src/analyzer/protocol/udp/events.bif b/src/packet_analysis/protocol/udp/events.bif similarity index 100% rename from src/analyzer/protocol/udp/events.bif rename to src/packet_analysis/protocol/udp/events.bif diff --git a/src/session/Key.cc b/src/session/Key.cc index 6044f493f8..5c7317505c 100644 --- a/src/session/Key.cc +++ b/src/session/Key.cc @@ -4,7 +4,8 @@ namespace zeek::session::detail { -Key::Key(const void* session, size_t size, bool copy) : size(size) +Key::Key(const void* session, size_t size, size_t type, bool copy) : + size(size), type(type) { data = reinterpret_cast(session); @@ -63,6 +64,8 @@ bool Key::operator<(const Key& rhs) const { if ( size != rhs.size ) return size < rhs.size; + else if ( type != rhs.type ) + return type < rhs.type; return memcmp(data, rhs.data, size) < 0; } diff --git a/src/session/Key.h b/src/session/Key.h index f07ec8996b..7201fbcaa5 100644 --- a/src/session/Key.h +++ b/src/session/Key.h @@ -20,16 +20,22 @@ namespace zeek::session::detail { class Key final { public: + const static size_t CONNECTION_KEY_TYPE=0; + /** * Create a new session key from a data pointer. * * @param session A pointer to the data for the key. * @param size The size of the key data, in bytes. + * @param type An identifier for the type of this key. The value used should be + * unique across all types of session keys. CONNECTION_KEY_TYPE (0) is used by + * Connection sessions and is reserved. This value is used to avoid collisions + * when doing comparisons of the memory stored by keys. * @param copy Flag for whether the data should be copied into the Key * during construction. This defaults to false because normally the only time * data is copied into the key is when it's inserted into the session map. */ - Key(const void* key_data, size_t size, bool copy=false); + Key(const void* key_data, size_t size, size_t type, bool copy=false); ~Key(); @@ -55,6 +61,7 @@ public: private: const uint8_t* data = nullptr; size_t size = 0; + size_t type = CONNECTION_KEY_TYPE; bool copied = false; }; diff --git a/src/session/Manager.cc b/src/session/Manager.cc index 0076cf1305..82ee11b217 100644 --- a/src/session/Manager.cc +++ b/src/session/Manager.cc @@ -21,9 +21,6 @@ #include "zeek/session/Session.h" #include "zeek/TunnelEncapsulation.h" #include "zeek/telemetry/Manager.h" - -#include "zeek/analyzer/protocol/icmp/ICMP.h" -#include "zeek/analyzer/protocol/udp/UDP.h" #include "zeek/analyzer/Manager.h" #include "zeek/iosource/IOSource.h" @@ -107,234 +104,6 @@ void Manager::Done() { } -void Manager::ProcessTransportLayer(double t, const Packet* pkt, size_t remaining) - { - const std::unique_ptr& ip_hdr = pkt->ip_hdr; - - uint32_t len = ip_hdr->TotalLen(); - uint16_t ip_hdr_len = ip_hdr->HdrLen(); - - if ( len < ip_hdr_len ) - { - session_mgr->Weird("bogus_IP_header_lengths", pkt); - return; - } - - len -= ip_hdr_len; // remove IP header - - int proto = ip_hdr->NextProto(); - - if ( CheckHeaderTrunc(proto, len, remaining, pkt) ) - return; - - const u_char* data = ip_hdr->Payload(); - - ConnTuple id; - id.src_addr = ip_hdr->SrcAddr(); - id.dst_addr = ip_hdr->DstAddr(); - BifEnum::Tunnel::Type tunnel_type = BifEnum::Tunnel::IP; - - switch ( proto ) { - case IPPROTO_TCP: - { - 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; - break; - } - - case IPPROTO_UDP: - { - const struct udphdr* up = (const struct udphdr *) data; - id.src_port = up->uh_sport; - id.dst_port = up->uh_dport; - id.is_one_way = false; - id.proto = TRANSPORT_UDP; - break; - } - - case IPPROTO_ICMP: - { - const struct icmp* icmpp = (const struct icmp *) data; - - id.src_port = icmpp->icmp_type; - id.dst_port = analyzer::icmp::ICMP4_counterpart(icmpp->icmp_type, - icmpp->icmp_code, - id.is_one_way); - id.src_port = htons(id.src_port); - id.dst_port = htons(id.dst_port); - id.proto = TRANSPORT_ICMP; - break; - } - - case IPPROTO_ICMPV6: - { - const struct icmp* icmpp = (const struct icmp *) data; - - id.src_port = icmpp->icmp_type; - id.dst_port = analyzer::icmp::ICMP6_counterpart(icmpp->icmp_type, - icmpp->icmp_code, - id.is_one_way); - id.src_port = htons(id.src_port); - id.dst_port = htons(id.dst_port); - id.proto = TRANSPORT_ICMP; - break; - } - - default: - Weird("unknown_protocol", pkt, util::fmt("%d", proto)); - return; - } - - zeek::detail::ConnKey conn_key(id); - detail::Key key(&conn_key, sizeof(conn_key), false); - Connection* conn = nullptr; - - // FIXME: The following is getting pretty complex. Need to split up - // into separate functions. - auto it = session_map.find(key); - if (it != session_map.end() ) - conn = static_cast(it->second); - - if ( ! conn ) - { - conn = NewConn(conn_key, t, &id, data, proto, ip_hdr->FlowLabel(), pkt); - if ( conn ) - InsertSession(std::move(key), conn); - } - else - { - // We already know that connection. - if ( conn->IsReuse(t, data) ) - { - conn->Event(connection_reused, nullptr); - - Remove(conn); - conn = NewConn(conn_key, t, &id, data, proto, ip_hdr->FlowLabel(), pkt); - if ( conn ) - InsertSession(std::move(key), conn); - } - else - { - conn->CheckEncapsulation(pkt->encap); - } - } - - if ( ! conn ) - return; - - int record_packet = 1; // whether to record the packet at all - int record_content = 1; // whether to record its data - - bool is_orig = (id.src_addr == conn->OrigAddr()) && - (id.src_port == conn->OrigPort()); - - conn->CheckFlowLabel(is_orig, ip_hdr->FlowLabel()); - - 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()); - - conn->NextPacket(t, is_orig, ip_hdr.get(), len, remaining, data, - record_packet, record_content, pkt); - - // We skip this block for reassembled packets because the pointer - // math wouldn't work. - if ( ! ip_hdr->reassembled && record_packet ) - { - if ( record_content ) - pkt->dump_packet = true; // save the whole thing - - else - { - int hdr_len = data - pkt->data; - packet_mgr->DumpPacket(pkt, hdr_len); // just save the header - } - } - } - -int Manager::ParseIPPacket(int caplen, const u_char* const pkt, int proto, - IP_Hdr*& inner) - { - if ( proto == IPPROTO_IPV6 ) - { - if ( caplen < (int)sizeof(struct ip6_hdr) ) - return -1; - - const struct ip6_hdr* ip6 = (const struct ip6_hdr*) pkt; - inner = new IP_Hdr(ip6, false, caplen); - if ( ( ip6->ip6_ctlun.ip6_un2_vfc & 0xF0 ) != 0x60 ) - return -2; - } - - else if ( proto == IPPROTO_IPV4 ) - { - if ( caplen < (int)sizeof(struct ip) ) - return -1; - - const struct ip* ip4 = (const struct ip*) pkt; - inner = new IP_Hdr(ip4, false); - if ( ip4->ip_v != 4 ) - return -2; - } - - else - { - reporter->InternalWarning("Bad IP protocol version in ParseIPPacket"); - return -1; - } - - if ( (uint32_t)caplen != inner->TotalLen() ) - return (uint32_t)caplen < inner->TotalLen() ? -1 : 1; - - return 0; - } - -bool Manager::CheckHeaderTrunc(int proto, uint32_t len, uint32_t caplen, - const Packet* p) - { - uint32_t min_hdr_len = 0; - switch ( proto ) { - case IPPROTO_TCP: - min_hdr_len = sizeof(struct tcphdr); - break; - case IPPROTO_UDP: - min_hdr_len = sizeof(struct udphdr); - break; - case IPPROTO_ICMP: - case IPPROTO_ICMPV6: - default: - // Use for all other packets. - min_hdr_len = ICMP_MINLEN; - break; - } - - if ( len < min_hdr_len ) - { - Weird("truncated_header", p); - return true; - } - - if ( caplen < min_hdr_len ) - { - Weird("internally_truncated_header", p); - return true; - } - - return false; - } - Connection* Manager::FindConnection(Val* v) { const auto& vt = v->GetType(); @@ -380,14 +149,19 @@ Connection* Manager::FindConnection(Val* v) htons((unsigned short) resp_portv->Port()), orig_portv->PortType(), false); - detail::Key key(&conn_key, sizeof(conn_key), false); + return FindConnection(conn_key); + } + +Connection* Manager::FindConnection(const zeek::detail::ConnKey& conn_key) + { + detail::Key key(&conn_key, sizeof(conn_key), + detail::Key::CONNECTION_KEY_TYPE, false); - Connection* conn = nullptr; auto it = session_map.find(key); if ( it != session_map.end() ) - conn = static_cast(it->second); + return static_cast(it->second); - return conn; + return nullptr; } void Manager::Remove(Session* s) @@ -418,16 +192,20 @@ void Manager::Remove(Session* s) } } -void Manager::Insert(Session* s) +void Manager::Insert(Session* s, bool remove_existing) { Session* old = nullptr; detail::Key key = s->SessionKey(true); - auto it = session_map.find(key); - if ( it != session_map.end() ) - old = it->second; + if ( remove_existing ) + { + auto it = session_map.find(key); + if ( it != session_map.end() ) + old = it->second; + + session_map.erase(key); + } - session_map.erase(key); InsertSession(std::move(key), s); if ( old && old != s ) @@ -482,140 +260,6 @@ void Manager::GetStats(Stats& s) s.num_packets = packet_mgr->PacketsProcessed(); } -Connection* Manager::NewConn(const zeek::detail::ConnKey& k, double t, const ConnTuple* id, - const u_char* data, int proto, uint32_t flow_label, - const Packet* pkt) - { - // FIXME: This should be cleaned up a bit, it's too protocol-specific. - // But I'm not yet sure what the right abstraction for these things is. - int src_h = ntohs(id->src_port); - int dst_h = ntohs(id->dst_port); - int flags = 0; - - // Hmm... This is not great. - TransportProto tproto = TRANSPORT_UNKNOWN; - switch ( proto ) { - case IPPROTO_ICMP: - tproto = TRANSPORT_ICMP; - break; - case IPPROTO_TCP: - tproto = TRANSPORT_TCP; - break; - case IPPROTO_UDP: - tproto = TRANSPORT_UDP; - break; - case IPPROTO_ICMPV6: - tproto = TRANSPORT_ICMP; - break; - default: - reporter->InternalWarning("unknown transport protocol"); - return nullptr; - }; - - if ( tproto == TRANSPORT_TCP ) - { - const struct tcphdr* tp = (const struct tcphdr*) data; - flags = tp->th_flags; - } - - bool flip = false; - - if ( ! WantConnection(src_h, dst_h, tproto, flags, flip) ) - return nullptr; - - Connection* conn = new Connection(k, t, id, flow_label, pkt); - conn->SetTransport(tproto); - - if ( flip ) - conn->FlipRoles(); - - if ( ! analyzer_mgr->BuildInitialAnalyzerTree(conn) ) - { - conn->Done(); - Unref(conn); - return nullptr; - } - - if ( new_connection ) - conn->Event(new_connection, nullptr); - - return conn; - } - -bool Manager::IsLikelyServerPort(uint32_t port, TransportProto proto) const - { - // We keep a cached in-core version of the table to speed up the lookup. - static std::set port_cache; - static bool have_cache = false; - - if ( ! have_cache ) - { - auto likely_server_ports = id::find_val("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. - if ( proto == TRANSPORT_TCP ) - port |= TCP_PORT_MASK; - else if ( proto == TRANSPORT_UDP ) - port |= UDP_PORT_MASK; - else if ( proto == TRANSPORT_ICMP ) - port |= ICMP_PORT_MASK; - - return port_cache.find(port) != port_cache.end(); - } - -bool Manager::WantConnection(uint16_t src_port, uint16_t dst_port, - TransportProto transport_proto, - uint8_t tcp_flags, bool& flip_roles) - { - flip_roles = false; - - if ( transport_proto == TRANSPORT_TCP ) - { - 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, TRANSPORT_TCP) ) - { // connection is a candidate for flipping - if ( IsLikelyServerPort(dst_port, TRANSPORT_TCP) ) - // 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; - } - } - } - - else if ( transport_proto == TRANSPORT_UDP ) - flip_roles = - IsLikelyServerPort(src_port, TRANSPORT_UDP) && - ! IsLikelyServerPort(dst_port, TRANSPORT_UDP); - - return true; - } - void Manager::Weird(const char* name, const Packet* pkt, const char* addl, const char* source) { const char* weird_name = name; diff --git a/src/session/Manager.h b/src/session/Manager.h index b65b245203..0b108adfaa 100644 --- a/src/session/Manager.h +++ b/src/session/Manager.h @@ -60,14 +60,13 @@ public: /** * Looks up the connection referred to by a given key. * - * @param key The key for the connection to search for. - * @param proto The transport protocol for the connection. + * @param conn_key The key for the connection to search for. * @return The connection, or nullptr if one doesn't exist. */ - Connection* FindConnection(const zeek::detail::ConnKey& key, TransportProto proto); + Connection* FindConnection(const zeek::detail::ConnKey& conn_key); void Remove(Session* s); - void Insert(Session* c); + void Insert(Session* c, bool remove_existing=true); // Generating connection_pending events for all connections // that are still active. @@ -94,43 +93,6 @@ public: [[deprecated("Remove in v5.1. Use CurrentSessions().")]] unsigned int CurrentConnections() { return CurrentSessions(); } - /** - * Main entry point for processing packets destined for session analyzers. This - * method is called by the packet analysis manager when after it has processed - * an IP-based packet, and shouldn't be called directly from other places. - * - * @param t The timestamp for this packet. - * @param pkt The packet being processed. - * @param len The number of bytes that haven't been processed yet by packet - * analysis. - */ - void ProcessTransportLayer(double t, const Packet *pkt, size_t len); - - /** - * Returns a wrapper IP_Hdr object if \a pkt appears to be a valid IPv4 - * or IPv6 header based on whether it's long enough to contain such a header, - * if version given in the header matches the proto argument, and also checks - * that the payload length field of that header matches the actual - * length of \a pkt given by \a caplen. - * - * @param caplen The length of \a pkt in bytes. - * @param pkt The inner IP packet data. - * @param proto Either IPPROTO_IPV6 or IPPROTO_IPV4 to indicate which IP - * protocol \a pkt corresponds to. - * @param inner The inner IP packet wrapper pointer to be allocated/assigned - * if \a pkt looks like a valid IP packet or at least long enough - * to hold an IP header. - * @return 0 If the inner IP packet appeared valid, else -1 if \a caplen - * is greater than the supposed IP packet's payload length field, -2 - * if the version of the inner header does not match proto or - * 1 if \a caplen is less than the supposed packet's payload length. - * In the -1 case, \a inner may still be non-null if \a caplen was - * long enough to be an IP header, and \a inner is always non-null - * for other return values. - */ - int ParseIPPacket(int caplen, const u_char* const pkt, int proto, - IP_Hdr*& inner); - unsigned int SessionMemoryUsage(); unsigned int SessionMemoryUsageVals(); @@ -148,32 +110,6 @@ private: using SessionMap = std::map; - Connection* NewConn(const zeek::detail::ConnKey& k, double t, const ConnTuple* id, - const u_char* data, int proto, uint32_t flow_label, - const Packet* pkt); - - // Returns true if the port corresonds to an application - // for which there's a Bro analyzer (even if it might not - // be used by the present policy script), or it's more - // generally a likely server port, false otherwise. - // - // Note, port is in host order. - bool IsLikelyServerPort(uint32_t port, TransportProto transport_proto) const; - - // 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 or such). - // Use tcp_flags=0 for non-TCP. - bool WantConnection(uint16_t src_port, uint16_t dest_port, - TransportProto transport_proto, - uint8_t tcp_flags, bool& flip_roles); - - // For a given protocol, checks whether the header's length as derived - // from lower-level headers or the length actually captured is less - // than that protocol's minimum header size. - bool CheckHeaderTrunc(int proto, uint32_t len, uint32_t caplen, const Packet *pkt); - // Inserts a new connection into the sessions map. If a connection with // the same key already exists in the map, it will be overwritten by // the new one. Connection count stats get updated either way (so most diff --git a/testing/btest/Baseline/core.truncation/output b/testing/btest/Baseline/core.truncation/output index 882692db5e..d9a595ca2e 100644 --- a/testing/btest/Baseline/core.truncation/output +++ b/testing/btest/Baseline/core.truncation/output @@ -37,8 +37,8 @@ XXXXXXXXXX.XXXXXX - 2001:4f8:4:7:2e0:81ff:fe52:ffff 0 2001:4f8:4:7:2e0:81ff:fe52 #open XXXX-XX-XX-XX-XX-XX #fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p name addl notice peer source #types time string addr port addr port string string bool string string -XXXXXXXXXX.XXXXXX - 10.0.0.1 0 192.0.43.10 0 internally_truncated_header - F zeek - -XXXXXXXXXX.XXXXXX - 192.0.43.10 0 10.0.0.1 0 internally_truncated_header - F zeek - +XXXXXXXXXX.XXXXXX - 10.0.0.1 0 192.0.43.10 0 internally_truncated_header - F zeek ICMP +XXXXXXXXXX.XXXXXX - 192.0.43.10 0 10.0.0.1 0 internally_truncated_header - F zeek ICMP #close XXXX-XX-XX-XX-XX-XX #separator \x09 #set_separator , diff --git a/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log b/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log index af52d127d0..95228fc7ea 100644 --- a/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log +++ b/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log @@ -57,6 +57,12 @@ scripts/base/init-bare.zeek scripts/base/packet-protocols/iptunnel/main.zeek scripts/base/packet-protocols/vntag/__load__.zeek scripts/base/packet-protocols/vntag/main.zeek + scripts/base/packet-protocols/udp/__load__.zeek + scripts/base/packet-protocols/udp/main.zeek + scripts/base/packet-protocols/tcp/__load__.zeek + scripts/base/packet-protocols/tcp/main.zeek + scripts/base/packet-protocols/icmp/__load__.zeek + scripts/base/packet-protocols/icmp/main.zeek scripts/base/init-frameworks-and-bifs.zeek scripts/base/frameworks/logging/__load__.zeek scripts/base/frameworks/logging/main.zeek @@ -125,7 +131,6 @@ scripts/base/init-frameworks-and-bifs.zeek build/scripts/base/bif/plugins/Zeek_GTPv1.events.bif.zeek build/scripts/base/bif/plugins/Zeek_HTTP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_HTTP.functions.bif.zeek - build/scripts/base/bif/plugins/Zeek_ICMP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_Ident.events.bif.zeek build/scripts/base/bif/plugins/Zeek_IMAP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_IRC.events.bif.zeek @@ -201,10 +206,11 @@ scripts/base/init-frameworks-and-bifs.zeek build/scripts/base/bif/plugins/Zeek_TCP.types.bif.zeek build/scripts/base/bif/plugins/Zeek_TCP.functions.bif.zeek build/scripts/base/bif/plugins/Zeek_Teredo.events.bif.zeek - build/scripts/base/bif/plugins/Zeek_UDP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_VXLAN.events.bif.zeek build/scripts/base/bif/plugins/Zeek_XMPP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_ARP.events.bif.zeek + build/scripts/base/bif/plugins/Zeek_UDP.events.bif.zeek + build/scripts/base/bif/plugins/Zeek_ICMP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_FileEntropy.events.bif.zeek build/scripts/base/bif/plugins/Zeek_FileExtract.events.bif.zeek build/scripts/base/bif/plugins/Zeek_FileExtract.functions.bif.zeek diff --git a/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log b/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log index 84aa4662ee..4ebc37ef20 100644 --- a/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log +++ b/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log @@ -57,6 +57,12 @@ scripts/base/init-bare.zeek scripts/base/packet-protocols/iptunnel/main.zeek scripts/base/packet-protocols/vntag/__load__.zeek scripts/base/packet-protocols/vntag/main.zeek + scripts/base/packet-protocols/udp/__load__.zeek + scripts/base/packet-protocols/udp/main.zeek + scripts/base/packet-protocols/tcp/__load__.zeek + scripts/base/packet-protocols/tcp/main.zeek + scripts/base/packet-protocols/icmp/__load__.zeek + scripts/base/packet-protocols/icmp/main.zeek scripts/base/init-frameworks-and-bifs.zeek scripts/base/frameworks/logging/__load__.zeek scripts/base/frameworks/logging/main.zeek @@ -125,7 +131,6 @@ scripts/base/init-frameworks-and-bifs.zeek build/scripts/base/bif/plugins/Zeek_GTPv1.events.bif.zeek build/scripts/base/bif/plugins/Zeek_HTTP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_HTTP.functions.bif.zeek - build/scripts/base/bif/plugins/Zeek_ICMP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_Ident.events.bif.zeek build/scripts/base/bif/plugins/Zeek_IMAP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_IRC.events.bif.zeek @@ -201,10 +206,11 @@ scripts/base/init-frameworks-and-bifs.zeek build/scripts/base/bif/plugins/Zeek_TCP.types.bif.zeek build/scripts/base/bif/plugins/Zeek_TCP.functions.bif.zeek build/scripts/base/bif/plugins/Zeek_Teredo.events.bif.zeek - build/scripts/base/bif/plugins/Zeek_UDP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_VXLAN.events.bif.zeek build/scripts/base/bif/plugins/Zeek_XMPP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_ARP.events.bif.zeek + build/scripts/base/bif/plugins/Zeek_UDP.events.bif.zeek + build/scripts/base/bif/plugins/Zeek_ICMP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_FileEntropy.events.bif.zeek build/scripts/base/bif/plugins/Zeek_FileExtract.events.bif.zeek build/scripts/base/bif/plugins/Zeek_FileExtract.functions.bif.zeek diff --git a/testing/btest/Baseline/plugins.hooks/output b/testing/btest/Baseline/plugins.hooks/output index 35ef76d80b..2074af1a3a 100644 --- a/testing/btest/Baseline/plugins.hooks/output +++ b/testing/btest/Baseline/plugins.hooks/output @@ -572,9 +572,13 @@ 0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IEEE802_11, 32821, PacketAnalyzer::ANALYZER_ARP)) -> 0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IEEE802_11, 34525, PacketAnalyzer::ANALYZER_IP)) -> 0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IEEE802_11_RADIO, 105, PacketAnalyzer::ANALYZER_IEEE802_11)) -> +0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 1, PacketAnalyzer::ANALYZER_ICMP)) -> +0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 17, PacketAnalyzer::ANALYZER_UDP)) -> 0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 4, PacketAnalyzer::ANALYZER_IPTUNNEL)) -> 0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 41, PacketAnalyzer::ANALYZER_IPTUNNEL)) -> 0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 47, PacketAnalyzer::ANALYZER_GRE)) -> +0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 58, PacketAnalyzer::ANALYZER_ICMP)) -> +0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 6, PacketAnalyzer::ANALYZER_TCP)) -> 0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_LINUXSLL, 2048, PacketAnalyzer::ANALYZER_IP)) -> 0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_LINUXSLL, 2054, PacketAnalyzer::ANALYZER_ARP)) -> 0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_LINUXSLL, 32821, PacketAnalyzer::ANALYZER_ARP)) -> @@ -915,6 +919,7 @@ 0.000000 MetaHookPost LoadFile(0, base<...>/hash, <...>/hash) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/hash_hrw, <...>/hash_hrw.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/http, <...>/http) -> -1 +0.000000 MetaHookPost LoadFile(0, base<...>/icmp, <...>/icmp) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/ieee802_11, <...>/ieee802_11) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/ieee802_11_radio, <...>/ieee802_11_radio) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/imap, <...>/imap) -> -1 @@ -979,10 +984,12 @@ 0.000000 MetaHookPost LoadFile(0, base<...>/supervisor, <...>/supervisor) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/supervisor.bif, <...>/supervisor.bif.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/syslog, <...>/syslog) -> -1 +0.000000 MetaHookPost LoadFile(0, base<...>/tcp, <...>/tcp) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/thresholds, <...>/thresholds.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/time, <...>/time.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/tunnels, <...>/tunnels) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/types.bif, <...>/types.bif.zeek) -> -1 +0.000000 MetaHookPost LoadFile(0, base<...>/udp, <...>/udp) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/urls, <...>/urls.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/utils, <...>/utils.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/version, <...>/version.zeek) -> -1 @@ -1582,9 +1589,13 @@ 0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IEEE802_11, 32821, PacketAnalyzer::ANALYZER_ARP)) 0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IEEE802_11, 34525, PacketAnalyzer::ANALYZER_IP)) 0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IEEE802_11_RADIO, 105, PacketAnalyzer::ANALYZER_IEEE802_11)) +0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 1, PacketAnalyzer::ANALYZER_ICMP)) +0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 17, PacketAnalyzer::ANALYZER_UDP)) 0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 4, PacketAnalyzer::ANALYZER_IPTUNNEL)) 0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 41, PacketAnalyzer::ANALYZER_IPTUNNEL)) 0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 47, PacketAnalyzer::ANALYZER_GRE)) +0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 58, PacketAnalyzer::ANALYZER_ICMP)) +0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 6, PacketAnalyzer::ANALYZER_TCP)) 0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_LINUXSLL, 2048, PacketAnalyzer::ANALYZER_IP)) 0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_LINUXSLL, 2054, PacketAnalyzer::ANALYZER_ARP)) 0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_LINUXSLL, 32821, PacketAnalyzer::ANALYZER_ARP)) @@ -1925,6 +1936,7 @@ 0.000000 MetaHookPre LoadFile(0, base<...>/hash, <...>/hash) 0.000000 MetaHookPre LoadFile(0, base<...>/hash_hrw, <...>/hash_hrw.zeek) 0.000000 MetaHookPre LoadFile(0, base<...>/http, <...>/http) +0.000000 MetaHookPre LoadFile(0, base<...>/icmp, <...>/icmp) 0.000000 MetaHookPre LoadFile(0, base<...>/ieee802_11, <...>/ieee802_11) 0.000000 MetaHookPre LoadFile(0, base<...>/ieee802_11_radio, <...>/ieee802_11_radio) 0.000000 MetaHookPre LoadFile(0, base<...>/imap, <...>/imap) @@ -1989,10 +2001,12 @@ 0.000000 MetaHookPre LoadFile(0, base<...>/supervisor, <...>/supervisor) 0.000000 MetaHookPre LoadFile(0, base<...>/supervisor.bif, <...>/supervisor.bif.zeek) 0.000000 MetaHookPre LoadFile(0, base<...>/syslog, <...>/syslog) +0.000000 MetaHookPre LoadFile(0, base<...>/tcp, <...>/tcp) 0.000000 MetaHookPre LoadFile(0, base<...>/thresholds, <...>/thresholds.zeek) 0.000000 MetaHookPre LoadFile(0, base<...>/time, <...>/time.zeek) 0.000000 MetaHookPre LoadFile(0, base<...>/tunnels, <...>/tunnels) 0.000000 MetaHookPre LoadFile(0, base<...>/types.bif, <...>/types.bif.zeek) +0.000000 MetaHookPre LoadFile(0, base<...>/udp, <...>/udp) 0.000000 MetaHookPre LoadFile(0, base<...>/urls, <...>/urls.zeek) 0.000000 MetaHookPre LoadFile(0, base<...>/utils, <...>/utils.zeek) 0.000000 MetaHookPre LoadFile(0, base<...>/version, <...>/version.zeek) @@ -2591,9 +2605,13 @@ 0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IEEE802_11, 32821, PacketAnalyzer::ANALYZER_ARP) 0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IEEE802_11, 34525, PacketAnalyzer::ANALYZER_IP) 0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IEEE802_11_RADIO, 105, PacketAnalyzer::ANALYZER_IEEE802_11) +0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, 1, PacketAnalyzer::ANALYZER_ICMP) +0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, 17, PacketAnalyzer::ANALYZER_UDP) 0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, 4, PacketAnalyzer::ANALYZER_IPTUNNEL) 0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, 41, PacketAnalyzer::ANALYZER_IPTUNNEL) 0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, 47, PacketAnalyzer::ANALYZER_GRE) +0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, 58, PacketAnalyzer::ANALYZER_ICMP) +0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, 6, PacketAnalyzer::ANALYZER_TCP) 0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_LINUXSLL, 2048, PacketAnalyzer::ANALYZER_IP) 0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_LINUXSLL, 2054, PacketAnalyzer::ANALYZER_ARP) 0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_LINUXSLL, 32821, PacketAnalyzer::ANALYZER_ARP) @@ -2946,6 +2964,7 @@ 0.000000 | HookLoadFile base<...>/hash <...>/hash 0.000000 | HookLoadFile base<...>/hash_hrw <...>/hash_hrw.zeek 0.000000 | HookLoadFile base<...>/http <...>/http +0.000000 | HookLoadFile base<...>/icmp <...>/icmp 0.000000 | HookLoadFile base<...>/ieee802_11 <...>/ieee802_11 0.000000 | HookLoadFile base<...>/ieee802_11_radio <...>/ieee802_11_radio 0.000000 | HookLoadFile base<...>/imap <...>/imap @@ -3010,10 +3029,12 @@ 0.000000 | HookLoadFile base<...>/supervisor <...>/supervisor 0.000000 | HookLoadFile base<...>/supervisor.bif <...>/supervisor.bif.zeek 0.000000 | HookLoadFile base<...>/syslog <...>/syslog +0.000000 | HookLoadFile base<...>/tcp <...>/tcp 0.000000 | HookLoadFile base<...>/thresholds <...>/thresholds.zeek 0.000000 | HookLoadFile base<...>/time <...>/time.zeek 0.000000 | HookLoadFile base<...>/tunnels <...>/tunnels 0.000000 | HookLoadFile base<...>/types.bif <...>/types.bif.zeek +0.000000 | HookLoadFile base<...>/udp <...>/udp 0.000000 | HookLoadFile base<...>/urls <...>/urls.zeek 0.000000 | HookLoadFile base<...>/utils <...>/utils.zeek 0.000000 | HookLoadFile base<...>/version <...>/version.zeek