diff --git a/src/analyzer/Analyzer.cc b/src/analyzer/Analyzer.cc index 006d2d34fb..2c262bc990 100644 --- a/src/analyzer/Analyzer.cc +++ b/src/analyzer/Analyzer.cc @@ -191,6 +191,19 @@ void Analyzer::NextPacket(int len, const u_char* data, bool is_orig, uint64_t se } } +void Analyzer::NextSkippedPacket(int len, const u_char* data, bool is_orig, uint64_t seq, const IP_Hdr* ip, + int caplen) { + if ( skip ) + return; + + SupportAnalyzer* next_sibling = FirstSupportAnalyzer(is_orig); + + if ( next_sibling ) + next_sibling->NextSkippedPacket(len, data, is_orig, seq, ip, caplen); + else + DeliverSkippedPacket(len, data, is_orig, seq, ip, caplen); +} + void Analyzer::NextStream(int len, const u_char* data, bool is_orig) { if ( skip ) return; @@ -260,6 +273,27 @@ void Analyzer::ForwardPacket(int len, const u_char* data, bool is_orig, uint64_t AppendNewChildren(); } +void Analyzer::ForwardSkippedPacket(int len, const u_char* data, bool is_orig, uint64_t seq, const IP_Hdr* ip, + int caplen) { + if ( output_handler ) + output_handler->DeliverSkippedPacket(len, data, is_orig, seq, ip, caplen); + + AppendNewChildren(); + + for ( auto i = children.begin(); i != children.end(); ) { + Analyzer* current = *i; + + if ( ! (current->finished || current->removing) ) { + current->NextSkippedPacket(len, data, is_orig, seq, ip, caplen); + ++i; + } + else + i = DeleteChild(i); + } + + AppendNewChildren(); +} + void Analyzer::ForwardStream(int len, const u_char* data, bool is_orig) { if ( output_handler ) output_handler->DeliverStream(len, data, is_orig); @@ -587,6 +621,13 @@ void Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig, uint64_t len > 40 ? "..." : ""); } +void Analyzer::DeliverSkippedPacket(int len, const u_char* data, bool is_orig, uint64_t seq, const IP_Hdr* ip, + int caplen) { + DBG_LOG(DBG_ANALYZER, "%s DeliverSkippedPacket(%d, %s, %" PRIu64 ", %p, %d) [%s%s]", fmt_analyzer(this).c_str(), + len, is_orig ? "T" : "F", seq, ip, caplen, util::fmt_bytes((const char*)data, min(40, len)), + len > 40 ? "..." : ""); +} + void Analyzer::DeliverStream(int len, const u_char* data, bool is_orig) { DBG_LOG(DBG_ANALYZER, "%s DeliverStream(%d, %s) [%s%s]", fmt_analyzer(this).c_str(), len, is_orig ? "T" : "F", util::fmt_bytes((const char*)data, min(40, len)), len > 40 ? "..." : ""); diff --git a/src/analyzer/Analyzer.h b/src/analyzer/Analyzer.h index 9a60ec5545..8bb1f3b7ae 100644 --- a/src/analyzer/Analyzer.h +++ b/src/analyzer/Analyzer.h @@ -69,6 +69,13 @@ public: */ virtual void DeliverPacket(int len, const u_char* data, bool orig, uint64_t seq, const IP_Hdr* ip, int caplen) {} + /** + * Hook for receiving skipped packet data. Parameters are the same as for + * Analyzer::DeliverSkippedPacket(). + */ + virtual void DeliverSkippedPacket(int len, const u_char* data, bool orig, uint64_t seq, const IP_Hdr* ip, + int caplen) {} + /** * Hook for receiving stream data. Parameters are the same as for * Analyzer::DeliverStream(). @@ -165,6 +172,29 @@ public: void NextPacket(int len, const u_char* data, bool is_orig, uint64_t seq = -1, const IP_Hdr* ip = nullptr, int caplen = 0); + /** + * Passes a skipped packet input to the analyzer for processing. The + * analyzer will process the input with any support analyzers first + * and then forward the data to DeliverSkippedPacket(), which derived + * classes can override. + * + * @param len The number of bytes passed in. + * + * @param data Pointer the input to process. + * + * @param is_orig True if this is originator-side input. + * + * @param seq Current sequence number, if available (only supported + * if the data is coming from the TCP analyzer. + * + * @param ip An IP packet header associated with the data, if + * available. + * + * @param caplen The packet's capture length, if available. + */ + void NextSkippedPacket(int len, const u_char* data, bool is_orig, uint64_t seq = -1, const IP_Hdr* ip = nullptr, + int caplen = 0); + /** * Passes stream input to the analyzer for processing. The analyzer * will process the input with any support analyzers first and then @@ -216,6 +246,17 @@ public: */ virtual void ForwardPacket(int len, const u_char* data, bool orig, uint64_t seq, const IP_Hdr* ip, int caplen); + /** + * Forwards skipped packet input on to all child analyzers. If the + * analyzer has an associated OutputHandlers, that one receives the + * input as well. + * + * Parameters are the same as for NextSkippedPacket(). + */ + virtual void ForwardSkippedPacket(int len, const u_char* data, bool orig, uint64_t seq, const IP_Hdr* ip, + int caplen); + + /** * Forwards stream input on to all child analyzers. If the analyzer * has an associated OutputHandlers, that one receives the input as @@ -246,6 +287,14 @@ public: */ virtual void DeliverPacket(int len, const u_char* data, bool orig, uint64_t seq, const IP_Hdr* ip, int caplen); + /** + * Hook for accessing skipped packet during parsing. This is called by + * NextSkippedPacket and can be overridden by derived classes. + * Parameters are the same. + */ + virtual void DeliverSkippedPacket(int len, const u_char* data, bool orig, uint64_t seq, const IP_Hdr* ip, + int caplen); + /** * Hook for accessing stream input for parsing. This is called by * NextStream() and can be overridden by derived classes. diff --git a/src/packet_analysis/protocol/icmp/ICMP.cc b/src/packet_analysis/protocol/icmp/ICMP.cc index 15735f1a7e..de6cebf47c 100644 --- a/src/packet_analysis/protocol/icmp/ICMP.cc +++ b/src/packet_analysis/protocol/icmp/ICMP.cc @@ -80,6 +80,7 @@ void ICMPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int rema if ( chksum != 0xffff ) { adapter->Weird("bad_ICMP_checksum"); + adapter->ForwardSkippedPacket(len, data, is_orig, -1, ip.get(), pkt->cap_len); return; } } @@ -103,6 +104,7 @@ void ICMPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int rema NextICMP6(run_state::current_timestamp, icmpp, len, remaining, data, ip.get(), adapter); else { reporter->Error("expected ICMP as IP packet's protocol, got %d", ip->NextProto()); + adapter->ForwardSkippedPacket(len, data, is_orig, -1, ip.get(), pkt->cap_len); return; } diff --git a/src/packet_analysis/protocol/tcp/TCP.cc b/src/packet_analysis/protocol/tcp/TCP.cc index 8780f58e86..7f620d6889 100644 --- a/src/packet_analysis/protocol/tcp/TCP.cc +++ b/src/packet_analysis/protocol/tcp/TCP.cc @@ -83,8 +83,10 @@ void TCPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int remai auto* adapter = static_cast(c->GetSessionAdapter()); const struct tcphdr* tp = ExtractTCP_Header(data, len, remaining, adapter); - if ( ! tp ) + if ( ! tp ) { + adapter->DeliverSkippedPacket(len, data, is_orig, adapter->LastRelDataSeq(), pkt->ip_hdr.get(), pkt->cap_len); return; + } // We need the min() here because Ethernet frame padding can lead to // remaining > len. @@ -95,8 +97,10 @@ void TCPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int remai analyzer::tcp::TCP_Endpoint* peer = endpoint->peer; const std::shared_ptr& ip = pkt->ip_hdr; - if ( ! ValidateChecksum(ip.get(), tp, endpoint, len, remaining, adapter) ) + if ( ! ValidateChecksum(ip.get(), tp, endpoint, len, remaining, adapter) ) { + adapter->DeliverSkippedPacket(len, data, is_orig, adapter->LastRelDataSeq(), ip.get(), pkt->cap_len); return; + } adapter->Process(is_orig, tp, len, ip, data, remaining); diff --git a/src/packet_analysis/protocol/tcp/TCPSessionAdapter.cc b/src/packet_analysis/protocol/tcp/TCPSessionAdapter.cc index b7a73d5da1..1c911d72cf 100644 --- a/src/packet_analysis/protocol/tcp/TCPSessionAdapter.cc +++ b/src/packet_analysis/protocol/tcp/TCPSessionAdapter.cc @@ -1012,6 +1012,30 @@ void TCPSessionAdapter::DeliverPacket(int len, const u_char* data, bool is_orig, ForwardPacket(len, data, is_orig, seq, ip, caplen); } +void TCPSessionAdapter::DeliverSkippedPacket(int len, const u_char* data, bool is_orig, uint64_t seq, const IP_Hdr* ip, + int caplen) { + analyzer::analyzer_list::iterator next; + + for ( auto i = packet_children.begin(); i != packet_children.end(); /* nop */ ) { + auto child = *i; + + if ( child->IsFinished() || child->Removing() ) { + if ( child->Removing() ) + child->Done(); + + DBG_LOG(DBG_ANALYZER, "%s deleted child %s", fmt_analyzer(this).c_str(), fmt_analyzer(child).c_str()); + i = packet_children.erase(i); + delete child; + } + else { + child->NextSkippedPacket(len, data, is_orig, seq, ip, caplen); + ++i; + } + } + + ForwardSkippedPacket(len, data, is_orig, seq, ip, caplen); +} + void TCPSessionAdapter::DeliverStream(int len, const u_char* data, bool orig) { Analyzer::DeliverStream(len, data, orig); } diff --git a/src/packet_analysis/protocol/tcp/TCPSessionAdapter.h b/src/packet_analysis/protocol/tcp/TCPSessionAdapter.h index e6d3e47144..88f615dfaa 100644 --- a/src/packet_analysis/protocol/tcp/TCPSessionAdapter.h +++ b/src/packet_analysis/protocol/tcp/TCPSessionAdapter.h @@ -87,6 +87,8 @@ protected: void Init() override; void Done() override; void DeliverPacket(int len, const u_char* data, bool orig, uint64_t seq, const IP_Hdr* ip, int caplen) override; + void DeliverSkippedPacket(int len, const u_char* data, bool orig, uint64_t seq, const IP_Hdr* ip, + int caplen) override; void DeliverStream(int len, const u_char* data, bool orig) override; void Undelivered(uint64_t seq, int len, bool orig) override; void FlipRoles() override; diff --git a/src/packet_analysis/protocol/udp/UDP.cc b/src/packet_analysis/protocol/udp/UDP.cc index bf114f5518..bb954a5a2e 100644 --- a/src/packet_analysis/protocol/udp/UDP.cc +++ b/src/packet_analysis/protocol/udp/UDP.cc @@ -126,6 +126,7 @@ void UDPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int remai if ( bad ) { adapter->HandleBadChecksum(is_orig); + adapter->ForwardSkippedPacket(len, data, is_orig, -1, ip.get(), pkt->cap_len); return; } }