diff --git a/scripts/base/packet-protocols/ip/main.zeek b/scripts/base/packet-protocols/ip/main.zeek index 556b460a1c..0e1c506bcb 100644 --- a/scripts/base/packet-protocols/ip/main.zeek +++ b/scripts/base/packet-protocols/ip/main.zeek @@ -15,8 +15,8 @@ event zeek_init() &priority=20 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_PKT); - PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, IPPROTO_UDP, PacketAnalyzer::ANALYZER_UDP_PKT); - PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, IPPROTO_ICMP, PacketAnalyzer::ANALYZER_ICMP_PKT); - PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, IPPROTO_ICMP6, PacketAnalyzer::ANALYZER_ICMP_PKT); + 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/src/analyzer/Manager.cc b/src/analyzer/Manager.cc index 7efb0ac3fe..3d44017d97 100644 --- a/src/analyzer/Manager.cc +++ b/src/analyzer/Manager.cc @@ -13,6 +13,7 @@ #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/plugin/Manager.h" @@ -498,6 +499,57 @@ bool Manager::BuildInitialAnalyzerTree(Connection* conn) return true; } +bool Manager::BuildSessionAnalyzerTree(Connection* conn, packet_analysis::IP::IPBasedAnalyzer* analyzer) + { + packet_analysis::IP::IPBasedTransportAnalyzer* root = nullptr; + analyzer::pia::PIA* pia = nullptr; + bool check_port = false; + + analyzer->CreateTransportAnalyzer(conn, root, pia, check_port); + + bool scheduled = 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 ) + { + int resp_port = ntohs(conn->RespPort()); + tag_set* ports = LookupPort(conn->ConnTransport(), resp_port, false); + + if ( ports ) + { + for ( tag_set::const_iterator j = ports->begin(); j != ports->end(); ++j ) + { + Analyzer* analyzer = analyzer_mgr->InstantiateAnalyzer(*j, conn); + + if ( ! analyzer ) + continue; + + root->AddChildAnalyzer(analyzer, false); + DBG_ANALYZER_ARGS(conn, "activated %s analyzer due to port %d", + analyzer_mgr->GetComponentName(*j).c_str(), resp_port); + } + } + } + } + + root->AddExtraAnalyzers(conn); + + if ( pia ) + root->AddChildAnalyzer(pia->AsAnalyzer()); + + conn->SetRootAnalyzer(root, pia); + root->Init(); + root->InitChildren(); + + PLUGIN_HOOK_VOID(HOOK_SETUP_ANALYZER_TREE, HookSetupAnalyzerTree(conn)); + + return true; + } + void Manager::ExpireScheduledAnalyzers() { if ( ! run_state::network_time ) diff --git a/src/analyzer/Manager.h b/src/analyzer/Manager.h index 7137a57390..0899110663 100644 --- a/src/analyzer/Manager.h +++ b/src/analyzer/Manager.h @@ -35,6 +35,9 @@ #include "zeek/analyzer/analyzer.bif.h" namespace zeek { + +namespace packet_analysis::IP { class IPBasedAnalyzer; } + namespace analyzer { /** @@ -244,11 +247,23 @@ 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); + /** + * Builds the analyzer tree used by transport-layer analyzers in the + * packet analysis framework. + * + * @param conn The connection to add the initial set of analyzers to. + * @param analyzer The packet analyzer requesting the tree. + * @return False if the tree cannot be built; that's usually an + * internal error. + */ + bool BuildSessionAnalyzerTree(Connection* conn, + packet_analysis::IP::IPBasedAnalyzer* analyzer); + /** * Schedules a particular analyzer for an upcoming connection. Once * the connection is seen, BuildInitAnalyzerTree() will add the 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/icmp/ICMP.cc b/src/packet_analysis/protocol/icmp/ICMP.cc index 928c31db5c..2eaf18b621 100644 --- a/src/packet_analysis/protocol/icmp/ICMP.cc +++ b/src/packet_analysis/protocol/icmp/ICMP.cc @@ -1,13 +1,16 @@ // See the file "COPYING" in the main distribution directory for copyright. #include "zeek/packet_analysis/protocol/icmp/ICMP.h" + +#include + #include "zeek/RunState.h" #include "zeek/session/Manager.h" using namespace zeek::packet_analysis::ICMP; +using namespace zeek::packet_analysis::IP; -ICMPAnalyzer::ICMPAnalyzer() - : zeek::packet_analysis::Analyzer("ICMP_PKT") +ICMPAnalyzer::ICMPAnalyzer() : IPBasedAnalyzer("ICMP", TRANSPORT_ICMP, ICMP_PORT_MASK, false) { } @@ -17,6 +20,96 @@ ICMPAnalyzer::~ICMPAnalyzer() bool ICMPAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) { - session_mgr->ProcessTransportLayer(run_state::processing_start_time, packet, len); + if ( ! CheckHeaderTrunc(ICMP_MINLEN, len, packet) ) + return false; + + ConnTuple id; + id.src_addr = packet->ip_hdr->SrcAddr(); + id.dst_addr = packet->ip_hdr->DstAddr(); + id.proto = TRANSPORT_ICMP; + + const struct icmp* icmpp = (const struct icmp *) data; + id.src_port = htons(icmpp->icmp_type); + + if ( packet->proto == IPPROTO_ICMP ) + id.dst_port = htons(ICMP4_counterpart(icmpp->icmp_type, icmpp->icmp_code, id.is_one_way)); + else if ( packet->proto == IPPROTO_ICMPV6 ) + id.dst_port = htons(ICMP6_counterpart(icmpp->icmp_type, icmpp->icmp_code, id.is_one_way)); + else + reporter->InternalError("Reached ICMP packet analyzer with unknown packet protocol %x", + packet->proto); + + ProcessConnection(id, packet, len); + return true; } + +void ICMPAnalyzer::ContinueProcessing(Connection* c, double t, bool is_orig, int remaining, Packet* pkt) + { + } + +void ICMPAnalyzer::CreateTransportAnalyzer(Connection* conn, IPBasedTransportAnalyzer*& root, + analyzer::pia::PIA*& pia, bool& check_port) + { + } + + +int ICMPAnalyzer::ICMP4_counterpart(int icmp_type, int icmp_code, bool& is_one_way) + { + is_one_way = false; + + // Return the counterpart type if one exists. This allows us + // to track corresponding ICMP requests/replies. + // Note that for the two-way ICMP messages, icmp_code is + // always 0 (RFC 792). + switch ( icmp_type ) { + case ICMP_ECHO: return ICMP_ECHOREPLY; + case ICMP_ECHOREPLY: return ICMP_ECHO; + + case ICMP_TSTAMP: return ICMP_TSTAMPREPLY; + case ICMP_TSTAMPREPLY: return ICMP_TSTAMP; + + case ICMP_IREQ: return ICMP_IREQREPLY; + case ICMP_IREQREPLY: return ICMP_IREQ; + + case ICMP_ROUTERSOLICIT: return ICMP_ROUTERADVERT; + case ICMP_ROUTERADVERT: return ICMP_ROUTERSOLICIT; + + case ICMP_MASKREQ: return ICMP_MASKREPLY; + case ICMP_MASKREPLY: return ICMP_MASKREQ; + + default: is_one_way = true; return icmp_code; + } + } + +int ICMPAnalyzer::ICMP6_counterpart(int icmp_type, int icmp_code, bool& is_one_way) + { + is_one_way = false; + + switch ( icmp_type ) { + case ICMP6_ECHO_REQUEST: return ICMP6_ECHO_REPLY; + case ICMP6_ECHO_REPLY: return ICMP6_ECHO_REQUEST; + + case ND_ROUTER_SOLICIT: return ND_ROUTER_ADVERT; + case ND_ROUTER_ADVERT: return ND_ROUTER_SOLICIT; + + case ND_NEIGHBOR_SOLICIT: return ND_NEIGHBOR_ADVERT; + case ND_NEIGHBOR_ADVERT: return ND_NEIGHBOR_SOLICIT; + + case MLD_LISTENER_QUERY: return MLD_LISTENER_REPORT; + case MLD_LISTENER_REPORT: return MLD_LISTENER_QUERY; + + // ICMP node information query and response respectively (not defined in + // icmp6.h) + case 139: return 140; + case 140: return 139; + + // Home Agent Address Discovery Request Message and reply + case 144: return 145; + case 145: return 144; + + // TODO: Add further counterparts. + + default: is_one_way = true; return icmp_code; + } + } diff --git a/src/packet_analysis/protocol/icmp/ICMP.h b/src/packet_analysis/protocol/icmp/ICMP.h index 439a2740fe..c0acc8d6f0 100644 --- a/src/packet_analysis/protocol/icmp/ICMP.h +++ b/src/packet_analysis/protocol/icmp/ICMP.h @@ -4,10 +4,11 @@ #include "zeek/packet_analysis/Analyzer.h" #include "zeek/packet_analysis/Component.h" +#include "zeek/packet_analysis/protocol/ip/IPBasedAnalyzer.h" namespace zeek::packet_analysis::ICMP { -class ICMPAnalyzer : public Analyzer { +class ICMPAnalyzer final : public IP::IPBasedAnalyzer { public: ICMPAnalyzer(); ~ICMPAnalyzer() override; @@ -19,8 +20,21 @@ public: return std::make_shared(); } + void CreateTransportAnalyzer(Connection* conn, IP::IPBasedTransportAnalyzer*& root, + analyzer::pia::PIA*& pia, bool& check_port) override; + +protected: + + void ContinueProcessing(Connection* c, double t, bool is_orig, int remaining, + Packet* pkt) override; + private: + // Returns the counterpart type to the given type (e.g., the counterpart + // to ICMP_ECHOREPLY is ICMP_ECHO). + int ICMP4_counterpart(int icmp_type, int icmp_code, bool& is_one_way); + int ICMP6_counterpart(int icmp_type, int icmp_code, bool& is_one_way); + }; } diff --git a/src/packet_analysis/protocol/icmp/Plugin.cc b/src/packet_analysis/protocol/icmp/Plugin.cc index 0e339ebba1..b16205e78a 100644 --- a/src/packet_analysis/protocol/icmp/Plugin.cc +++ b/src/packet_analysis/protocol/icmp/Plugin.cc @@ -10,7 +10,7 @@ class Plugin : public zeek::plugin::Plugin { public: zeek::plugin::Configuration Configure() { - AddComponent(new zeek::packet_analysis::Component("ICMP_PKT", + AddComponent(new zeek::packet_analysis::Component("ICMP", zeek::packet_analysis::ICMP::ICMPAnalyzer::Instantiate)); zeek::plugin::Configuration config; diff --git a/src/packet_analysis/protocol/ip/CMakeLists.txt b/src/packet_analysis/protocol/ip/CMakeLists.txt index 3be79005d9..89971b9334 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 Plugin.cc) zeek_plugin_end() diff --git a/src/packet_analysis/protocol/ip/IPBasedAnalyzer.cc b/src/packet_analysis/protocol/ip/IPBasedAnalyzer.cc new file mode 100644 index 0000000000..877c9b17e0 --- /dev/null +++ b/src/packet_analysis/protocol/ip/IPBasedAnalyzer.cc @@ -0,0 +1,209 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#include "zeek/packet_analysis/protocol/ip/IPBasedAnalyzer.h" + +#include "zeek/RunState.h" +#include "zeek/Conn.h" +#include "zeek/Val.h" +#include "zeek/session/Manager.h" +#include "zeek/analyzer/Manager.h" + +using namespace zeek; +using namespace zeek::packet_analysis::IP; + +IPBasedAnalyzer::IPBasedAnalyzer(const char* name, TransportProto proto, uint32_t mask, + bool report_unknown_protocols) + : zeek::packet_analysis::Analyzer(name, report_unknown_protocols), + transport(proto), server_port_mask(mask) + { + } + +IPBasedAnalyzer::~IPBasedAnalyzer() + { + } + +void IPBasedAnalyzer::ProcessConnection(const ConnTuple& conn_id, Packet* pkt, size_t remaining) + { + const std::unique_ptr& ip_hdr = pkt->ip_hdr; + detail::ConnKey key(conn_id); + + Connection* conn = session_mgr->FindConnection(key); + + if ( ! conn ) + { + conn = NewConn(&conn_id, key, pkt); + if ( conn ) + session_mgr->Insert(conn, false); + } + else + { + if ( conn->IsReuse(run_state::processing_start_time, ip_hdr->Payload()) ) + { + conn->Event(connection_reused, nullptr); + + session_mgr->Remove(conn); + conn = NewConn(&conn_id, key, pkt); + if ( conn ) + session_mgr->Insert(conn, false); + } + else + { + conn->CheckEncapsulation(pkt->encap); + } + } + + if ( ! conn ) + return; + + bool is_orig = (conn_id.src_addr == conn->OrigAddr()) && + (conn_id.src_port == conn->OrigPort()); + + conn->CheckFlowLabel(is_orig, ip_hdr->FlowLabel()); + + zeek::ValPtr pkt_hdr_val; + + if ( ipv6_ext_headers && ip_hdr->NumHeaders() > 1 ) + { + pkt_hdr_val = ip_hdr->ToPktHdrVal(); + conn->EnqueueEvent(ipv6_ext_headers, nullptr, conn->GetVal(), + pkt_hdr_val); + } + + if ( new_packet ) + conn->EnqueueEvent(new_packet, nullptr, conn->GetVal(), + pkt_hdr_val ? std::move(pkt_hdr_val) : ip_hdr->ToPktHdrVal()); + + if ( new_plugin ) + { + conn->SetRecordPackets(true); + conn->SetRecordContents(true); + + const u_char* data = pkt->ip_hdr->Payload(); + + run_state::current_timestamp = run_state::processing_start_time; + run_state::current_pkt = pkt; + + // TODO: Does this actually mean anything? + if ( conn->Skipping() ) + return; + + ContinueProcessing(conn, run_state::processing_start_time, is_orig, remaining, pkt); + + run_state::current_timestamp = 0; + run_state::current_pkt = nullptr; + + // If the packet is reassembled, disable packet dumping because the + // pointer math to dump the data wouldn't work. + if ( pkt->ip_hdr->reassembled ) + pkt->dump_packet = false; + else if ( conn->RecordPackets() ) + { + pkt->dump_packet = true; + + // If we don't want the content, set the dump size to include just + // the header. + if ( ! conn->RecordContents() ) + pkt->dump_size = data - pkt->data; + } + } + else + { + int record_packet = 1; // whether to record the packet at all + int record_content = 1; // whether to record its data + + const u_char* data = pkt->ip_hdr->Payload(); + + conn->NextPacket(run_state::processing_start_time, is_orig, ip_hdr.get(), ip_hdr->PayloadLen(), + remaining, data, record_packet, record_content, pkt); + + // If the packet is reassembled, disable packet dumping because the + // pointer math to dump the data wouldn't work. + if ( ip_hdr->reassembled ) + pkt->dump_packet = false; + else if ( record_packet ) + { + pkt->dump_packet = true; + + // If we don't want the content, set the dump size to include just + // the header. + if ( ! record_content ) + pkt->dump_size = data - pkt->data; + } + } + } + +bool IPBasedAnalyzer::CheckHeaderTrunc(size_t min_hdr_len, size_t remaining, Packet* packet) + { + if ( packet->ip_hdr->PayloadLen() < min_hdr_len ) + { + Weird("truncated_header", packet); + return false; + } + else if ( remaining < min_hdr_len ) + { + Weird("internally_truncated_header", packet); + return false; + } + + return true; + } + +bool IPBasedAnalyzer::IsLikelyServerPort(uint32_t port) const + { + // We keep a cached in-core version of the table to speed up the lookup. + static std::set 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 ( ! analyzer_mgr->BuildSessionAnalyzerTree(conn, this) ) + { + conn->Done(); + Unref(conn); + return nullptr; + } + + if ( new_connection ) + conn->Event(new_connection, nullptr); + + return conn; + } diff --git a/src/packet_analysis/protocol/ip/IPBasedAnalyzer.h b/src/packet_analysis/protocol/ip/IPBasedAnalyzer.h new file mode 100644 index 0000000000..129a098720 --- /dev/null +++ b/src/packet_analysis/protocol/ip/IPBasedAnalyzer.h @@ -0,0 +1,182 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#pragma once + +#include "zeek/packet_analysis/Analyzer.h" +#include "zeek/packet_analysis/Component.h" +#include "zeek/analyzer/Analyzer.h" +#include "zeek/analyzer/Manager.h" + +namespace zeek::analyzer::pia { class PIA; } + +namespace zeek::packet_analysis::IP { + +class IPBasedTransportAnalyzer; + +/** + * A base class for any packet analyzer based on IP. This is used by default by + * the TCP, UDP, and ICMP analyzers to reduce a large amount of duplicated code + * that those plugins have in common. + */ +class IPBasedAnalyzer : public Analyzer { +public: + ~IPBasedAnalyzer() override; + + /** + * Returns true if the analyzer determines that in fact a new + * connection has started without the connection statement having + * terminated the previous one, i.e., the new data is arriving at + * what's the analyzer for the previous instance. This is used only + * for TCP. + */ + virtual bool IsReuse(double t, const u_char* pkt) { return false; } + + /** + * TODO: comment + */ + virtual void CreateTransportAnalyzer(Connection* conn, IPBasedTransportAnalyzer*& root, + analyzer::pia::PIA*& pia, bool& check_port) = 0; + +protected: + + /** + * Construct a new IP-based analyzer. + * + * @param name The name for the type of analyzer. The name must match + * the one the corresponding Component registers. + * @param proto The transport protocol implemented by this analyzer. + * @param mask The mask used to determine if a port is a server port + * for this protocol. This is used by IsLikelyServerPort(). + * @param report_unknown_protocols Flag for whether to report unknown + * protocols during packet forwarding. This is typically false for IP + * protocols since packets may go into the session analysis framework + * as well. + */ + IPBasedAnalyzer(const char* name, TransportProto proto, uint32_t mask, + bool report_unknown_protocols); + + /** + * Entry point for child classes to call to do the actual heavy lifting for + * processing a packet and extracting a connection out of it. + * + * @param conn_id The connection ID generated by the child class. + * @param pkt The packet being processed. + * @param remaining The number of bytes remaining to be processed in the packet. + */ + void ProcessConnection(const ConnTuple& conn_id, Packet* pkt, size_t remaining); + + /** + * Verifies that there is enough data in the packet to process the header + * length requested. + * + * @param min_hdr_len The minimum data in bytes that needs to exist. + * @param remaining The remaining number of bytes in the packet reported by + * previous analyzer. + * @param packet The packet being processed. This will be used to pull out the + * number of bytes the IP header says we have remaining. + */ + bool CheckHeaderTrunc(size_t min_hdr_len, size_t remaining, Packet* packet); + + /** + * Upon seeing the first packet of a connection, checks whether we want + * to analyze it (e.g. we may not want to look at partial connections) + * and, if yes, whether we should flip the roles of originator and + * responder based on known ports and such. + * + * @param src_port The source port of the connection. + * @param dst_port The destination port of the connection. + * @param data The payload data for the packet being processed. + * @param flip_roles Return value if the roles should be flipped. + * @return True if the connection is wanted. False otherwise. + */ + virtual bool WantConnection(uint16_t src_port, uint16_t dst_port, + const u_char* data, bool& flip_roles) const + { + flip_roles = false; + return true; + } + + /** + * Returns true if the port corresponds to an application for which there + * is a Zeek analyzer (even if it might not be used by the present policy + * script) or if it's generally a likely server port. + * + * @param port The port number to check, in host order. + */ + bool IsLikelyServerPort(uint32_t port) const; + + /** + * Continues process of packet after the connection has been inserted into the + * session manager. This should be implemented by all child classes. + * + * @param conn The connection currently being processed. + * @param t The timestamp for the current packet. + * @param is_orig Flag denoting whether this packet is from the originator of + * the connection. + * @param remaining The remaining about of data in the packet. + * @param pkt The packet being processed. + */ + virtual void ContinueProcessing(Connection* conn, double t, bool is_orig, int remaining, + Packet* pkt) {} + + // TODO: temporary, until all of the plugins are implemented + bool new_plugin = false; + +private: + + /** + * Creates a new Connection object from data gleaned from the current packet. + * + * @param id A connection ID generated from the packet data. This should have been + * passed in from a child analyzer. + * @param key A connection ID key generated from the ID. + * @param pkt The packet associated with the new connection. + */ + zeek::Connection* NewConn(const ConnTuple* id, const detail::ConnKey& key, + const Packet* pkt); + + TransportProto transport; + uint32_t server_port_mask; +}; + +/** + * This class represents the interface between the packet analysis framework and + * the session analysis framework. One of these should be implemented for each + * packet analyzer that intends to forward into the session analysis. + */ +class IPBasedTransportAnalyzer : public zeek::analyzer::TransportLayerAnalyzer { + +public: + + IPBasedTransportAnalyzer(const char* name, Connection* conn) + : TransportLayerAnalyzer(name, conn) { } + + /** + * Sets the parent packet analyzer for this transport analyzer. This can't be passed to + * the constructor due to the way that TransportLayerAnalyzer gets instantiated. + * + * @param p The parent packet analyzer to store + */ + void SetParent(IPBasedAnalyzer* p) { parent = p; } + + /** + * Returns true if the analyzer determines that in fact a new connection has started + * without the connection statement having terminated the previous one, i.e., the new + * data is arriving at what's the analyzer for the previous instance. This is used only + * for TCP. + */ + bool IsReuse(double t, const u_char* pkt) override { return parent->IsReuse(t, pkt); } + + /** + * Pure virtual method to allow extra session analzyers to be added to this analyzer's + * tree of children. This is used by analyzer::Manager when creating the session analyzer + * tree. + */ + virtual void AddExtraAnalyzers(Connection* conn) = 0; + +protected: + + IPBasedAnalyzer* parent; +}; + +} diff --git a/src/packet_analysis/protocol/tcp/Plugin.cc b/src/packet_analysis/protocol/tcp/Plugin.cc index cc791eedfa..45b41c3884 100644 --- a/src/packet_analysis/protocol/tcp/Plugin.cc +++ b/src/packet_analysis/protocol/tcp/Plugin.cc @@ -10,7 +10,7 @@ class Plugin : public zeek::plugin::Plugin { public: zeek::plugin::Configuration Configure() { - AddComponent(new zeek::packet_analysis::Component("TCP_PKT", + AddComponent(new zeek::packet_analysis::Component("TCP", zeek::packet_analysis::TCP::TCPAnalyzer::Instantiate)); zeek::plugin::Configuration config; diff --git a/src/packet_analysis/protocol/tcp/TCP.cc b/src/packet_analysis/protocol/tcp/TCP.cc index 7fed612e07..0abf645357 100644 --- a/src/packet_analysis/protocol/tcp/TCP.cc +++ b/src/packet_analysis/protocol/tcp/TCP.cc @@ -2,12 +2,11 @@ #include "zeek/packet_analysis/protocol/tcp/TCP.h" #include "zeek/RunState.h" -#include "zeek/session/Manager.h" using namespace zeek::packet_analysis::TCP; +using namespace zeek::packet_analysis::IP; -TCPAnalyzer::TCPAnalyzer() - : zeek::packet_analysis::Analyzer("TCP_PKT") +TCPAnalyzer::TCPAnalyzer() : IPBasedAnalyzer("TCP", TRANSPORT_TCP, TCP_PORT_MASK, false) { } @@ -17,6 +16,68 @@ TCPAnalyzer::~TCPAnalyzer() bool TCPAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) { - session_mgr->ProcessTransportLayer(run_state::processing_start_time, packet, len); + uint32_t min_hdr_len = sizeof(struct tcphdr); + if ( ! CheckHeaderTrunc(min_hdr_len, len, packet) ) + return false; + + ConnTuple id; + id.src_addr = packet->ip_hdr->SrcAddr(); + id.dst_addr = packet->ip_hdr->DstAddr(); + + data = packet->ip_hdr->Payload(); + + const struct tcphdr* tp = (const struct tcphdr *) data; + id.src_port = tp->th_sport; + id.dst_port = tp->th_dport; + id.is_one_way = false; + id.proto = TRANSPORT_TCP; + + ProcessConnection(id, packet, len); + return true; } + +bool TCPAnalyzer::WantConnection(uint16_t src_port, uint16_t dst_port, + const u_char* data, bool& flip_roles) const + { + flip_roles = false; + const struct tcphdr* tp = (const struct tcphdr*) data; + uint8_t tcp_flags = tp->th_flags; + + if ( ! (tcp_flags & TH_SYN) || (tcp_flags & TH_ACK) ) + { + // The new connection is starting either without a SYN, + // or with a SYN ack. This means it's a partial connection. + if ( ! zeek::detail::partial_connection_ok ) + return false; + + if ( tcp_flags & TH_SYN && ! zeek::detail::tcp_SYN_ack_ok ) + return false; + + // Try to guess true responder by the port numbers. + // (We might also think that for SYN acks we could + // safely flip the roles, but that doesn't work + // for stealth scans.) + if ( IsLikelyServerPort(src_port) ) + { // connection is a candidate for flipping + if ( IsLikelyServerPort(dst_port) ) + // Hmmm, both source and destination + // are plausible. Heuristic: flip only + // if (1) this isn't a SYN ACK (to avoid + // confusing stealth scans) and + // (2) dest port > src port (to favor + // more plausible servers). + flip_roles = ! (tcp_flags & TH_SYN) && src_port < dst_port; + else + // Source is plausible, destination isn't. + flip_roles = true; + } + } + + return true; + } + +void TCPAnalyzer::CreateTransportAnalyzer(Connection* conn, IPBasedTransportAnalyzer*& root, + analyzer::pia::PIA*& pia, bool& check_port) + { + } diff --git a/src/packet_analysis/protocol/tcp/TCP.h b/src/packet_analysis/protocol/tcp/TCP.h index 51f9208805..d836451945 100644 --- a/src/packet_analysis/protocol/tcp/TCP.h +++ b/src/packet_analysis/protocol/tcp/TCP.h @@ -4,10 +4,11 @@ #include "zeek/packet_analysis/Analyzer.h" #include "zeek/packet_analysis/Component.h" +#include "zeek/packet_analysis/protocol/ip/IPBasedAnalyzer.h" namespace zeek::packet_analysis::TCP { -class TCPAnalyzer : public Analyzer { +class TCPAnalyzer final : public IP::IPBasedAnalyzer { public: TCPAnalyzer(); ~TCPAnalyzer() override; @@ -19,8 +20,25 @@ public: return std::make_shared(); } -private: + void CreateTransportAnalyzer(Connection* conn, IP::IPBasedTransportAnalyzer*& root, + analyzer::pia::PIA*& pia, bool& check_port) override; +protected: + + /** + * Upon seeing the first packet of a connection, checks whether we want + * to analyze it (e.g. we may not want to look at partial connections) + * and, if yes, whether we should flip the roles of originator and + * responder based on known ports and such. + * + * @param src_port The source port of the connection. + * @param dst_port The destination port of the connection. + * @param data The payload data for the packet being processed. + * @param flip_roles Return value if the roles should be flipped. + * @return True if the connection is wanted. False otherwise. + */ + bool WantConnection(uint16_t src_port, uint16_t dst_port, + const u_char* data, bool& flip_roles) const override; }; } diff --git a/src/packet_analysis/protocol/udp/Plugin.cc b/src/packet_analysis/protocol/udp/Plugin.cc index f22ca797f1..4bbe7d737d 100644 --- a/src/packet_analysis/protocol/udp/Plugin.cc +++ b/src/packet_analysis/protocol/udp/Plugin.cc @@ -10,7 +10,7 @@ class Plugin : public zeek::plugin::Plugin { public: zeek::plugin::Configuration Configure() { - AddComponent(new zeek::packet_analysis::Component("UDP_PKT", + AddComponent(new zeek::packet_analysis::Component("UDP", zeek::packet_analysis::UDP::UDPAnalyzer::Instantiate)); zeek::plugin::Configuration config; diff --git a/src/packet_analysis/protocol/udp/UDP.cc b/src/packet_analysis/protocol/udp/UDP.cc index 620e7eb768..f17e1280dd 100644 --- a/src/packet_analysis/protocol/udp/UDP.cc +++ b/src/packet_analysis/protocol/udp/UDP.cc @@ -2,12 +2,11 @@ #include "zeek/packet_analysis/protocol/udp/UDP.h" #include "zeek/RunState.h" -#include "zeek/session/Manager.h" using namespace zeek::packet_analysis::UDP; +using namespace zeek::packet_analysis::IP; -UDPAnalyzer::UDPAnalyzer() - : zeek::packet_analysis::Analyzer("UDP_PKT") +UDPAnalyzer::UDPAnalyzer() : IPBasedAnalyzer("UDP", TRANSPORT_UDP, UDP_PORT_MASK, false) { } @@ -17,6 +16,31 @@ UDPAnalyzer::~UDPAnalyzer() bool UDPAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) { - session_mgr->ProcessTransportLayer(run_state::processing_start_time, packet, len); + uint32_t min_hdr_len = sizeof(struct udphdr); + if ( ! CheckHeaderTrunc(min_hdr_len, len, packet) ) + return false; + + ConnTuple id; + id.src_addr = packet->ip_hdr->SrcAddr(); + id.dst_addr = packet->ip_hdr->DstAddr(); + const struct udphdr* up = (const struct udphdr *) packet->ip_hdr->Payload(); + id.src_port = up->uh_sport; + id.dst_port = up->uh_dport; + id.is_one_way = false; + id.proto = TRANSPORT_UDP; + + ProcessConnection(id, packet, len); + + return true; + } +void UDPAnalyzer::CreateTransportAnalyzer(Connection* conn, IPBasedTransportAnalyzer*& root, + analyzer::pia::PIA*& pia, bool& check_port) + { + } + +bool UDPAnalyzer::WantConnection(uint16_t src_port, uint16_t dst_port, + const u_char* data, bool& flip_roles) const + { + flip_roles = IsLikelyServerPort(src_port) && ! IsLikelyServerPort(dst_port); return true; } diff --git a/src/packet_analysis/protocol/udp/UDP.h b/src/packet_analysis/protocol/udp/UDP.h index 0a941456a2..2730ece1dd 100644 --- a/src/packet_analysis/protocol/udp/UDP.h +++ b/src/packet_analysis/protocol/udp/UDP.h @@ -4,10 +4,11 @@ #include "zeek/packet_analysis/Analyzer.h" #include "zeek/packet_analysis/Component.h" +#include "zeek/packet_analysis/protocol/ip/IPBasedAnalyzer.h" namespace zeek::packet_analysis::UDP { -class UDPAnalyzer : public Analyzer { +class UDPAnalyzer : public IP::IPBasedAnalyzer { public: UDPAnalyzer(); ~UDPAnalyzer() override; @@ -19,8 +20,25 @@ public: return std::make_shared(); } -private: + void CreateTransportAnalyzer(Connection* conn, IP::IPBasedTransportAnalyzer*& root, + analyzer::pia::PIA*& pia, bool& check_port) override; +protected: + + /** + * Upon seeing the first packet of a connection, checks whether we want + * to analyze it (e.g. we may not want to look at partial connections) + * and, if yes, whether we should flip the roles of originator and + * responder based on known ports and such. + * + * @param src_port The source port of the connection. + * @param dst_port The destination port of the connection. + * @param data The payload data for the packet being processed. + * @param flip_roles Return value if the roles should be flipped. + * @return True if the connection is wanted. False otherwise. + */ + bool WantConnection(uint16_t src_port, uint16_t dst_port, + const u_char* data, bool& flip_roles) const override; }; } diff --git a/src/session/Manager.cc b/src/session/Manager.cc index 746fd14ac0..b7e0cddf71 100644 --- a/src/session/Manager.cc +++ b/src/session/Manager.cc @@ -107,197 +107,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 - } - } - } - -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(); @@ -353,6 +162,17 @@ Connection* Manager::FindConnection(Val* v) return conn; } +Connection* Manager::FindConnection(const zeek::detail::ConnKey& conn_key) + { + detail::Key key(&conn_key, sizeof(conn_key), false); + + auto it = session_map.find(key); + if ( it != session_map.end() ) + return dynamic_cast(it->second); + + return nullptr; + } + void Manager::Remove(Session* s) { if ( s->IsInSessionTable() ) @@ -381,16 +201,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 ) @@ -445,140 +269,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 b798c7f9d4..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,18 +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); - unsigned int SessionMemoryUsage(); unsigned int SessionMemoryUsageVals(); @@ -123,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/plugins.hooks/output b/testing/btest/Baseline/plugins.hooks/output index 61bdd358ac..2074af1a3a 100644 --- a/testing/btest/Baseline/plugins.hooks/output +++ b/testing/btest/Baseline/plugins.hooks/output @@ -572,13 +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_PKT)) -> -0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 17, PacketAnalyzer::ANALYZER_UDP_PKT)) -> +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_PKT)) -> -0.000000 MetaHookPost CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 6, PacketAnalyzer::ANALYZER_TCP_PKT)) -> +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)) -> @@ -1589,13 +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_PKT)) -0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 17, PacketAnalyzer::ANALYZER_UDP_PKT)) +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_PKT)) -0.000000 MetaHookPre CallFunction(PacketAnalyzer::register_packet_analyzer, , (PacketAnalyzer::ANALYZER_IP, 6, PacketAnalyzer::ANALYZER_TCP_PKT)) +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)) @@ -2605,13 +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_PKT) -0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, 17, PacketAnalyzer::ANALYZER_UDP_PKT) +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_PKT) -0.000000 | HookCallFunction PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, 6, PacketAnalyzer::ANALYZER_TCP_PKT) +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)