diff --git a/src/analyzer/Analyzer.h b/src/analyzer/Analyzer.h index 1eda4c3cf1..83157aadde 100644 --- a/src/analyzer/Analyzer.h +++ b/src/analyzer/Analyzer.h @@ -400,7 +400,7 @@ public: * * @return The analyzer, or null if not found. */ - Analyzer* FindChild(ID id); + virtual Analyzer* FindChild(ID id); /** * Recursively searches all (direct or indirect) childs of the @@ -411,7 +411,7 @@ public: * @return The first analyzer of the given type found, or null if * none. */ - Analyzer* FindChild(Tag tag); + virtual Analyzer* FindChild(Tag tag); /** * Recursively searches all (direct or indirect) childs of the diff --git a/src/analyzer/protocol/conn-size/CMakeLists.txt b/src/analyzer/protocol/conn-size/CMakeLists.txt index efaadef401..f89a6e5b88 100644 --- a/src/analyzer/protocol/conn-size/CMakeLists.txt +++ b/src/analyzer/protocol/conn-size/CMakeLists.txt @@ -6,4 +6,5 @@ include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DI bro_plugin_begin(Bro ConnSize) bro_plugin_cc(ConnSize.cc Plugin.cc) bro_plugin_bif(events.bif) +bro_plugin_bif(functions.bif) bro_plugin_end() diff --git a/src/analyzer/protocol/conn-size/ConnSize.cc b/src/analyzer/protocol/conn-size/ConnSize.cc index 5bfeb2bf90..fbe6b87487 100644 --- a/src/analyzer/protocol/conn-size/ConnSize.cc +++ b/src/analyzer/protocol/conn-size/ConnSize.cc @@ -29,6 +29,11 @@ void ConnSize_Analyzer::Init() orig_pkts = 0; resp_bytes = 0; resp_pkts = 0; + + orig_bytes_thresh = 0; + orig_pkts = 0; + resp_bytes_thresh = 0; + resp_pkts = 0; } void ConnSize_Analyzer::Done() @@ -36,6 +41,18 @@ void ConnSize_Analyzer::Done() Analyzer::Done(); } +void ConnSize_Analyzer::ThresholdEvent(EventHandlerPtr f, uint64 threshold, bool is_orig) + { + if ( ! f ) + return; + + val_list* vl = new val_list; + vl->append(BuildConnVal()); + vl->append(new Val(threshold, TYPE_COUNT)); + vl->append(new Val(is_orig, TYPE_BOOL)); + ConnectionEvent(f, vl); + } + void ConnSize_Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig, uint64 seq, const IP_Hdr* ip, int caplen) { Analyzer::DeliverPacket(len, data, is_orig, seq, ip, caplen); @@ -44,11 +61,71 @@ void ConnSize_Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig, { orig_bytes += ip->TotalLen(); orig_pkts ++; + + if ( orig_bytes_thresh && orig_bytes >= orig_bytes_thresh ) + { + ThresholdEvent(conn_bytes_threshold_crossed, orig_bytes_thresh, is_orig); + orig_bytes_thresh = 0; + } + + if ( orig_pkts_thresh && orig_pkts >= orig_pkts_thresh ) + { + ThresholdEvent(conn_packets_threshold_crossed, orig_pkts_thresh, is_orig); + orig_pkts_thresh = 0; + } } else { resp_bytes += ip->TotalLen(); resp_pkts ++; + + if ( resp_bytes_thresh && resp_bytes >= resp_bytes_thresh ) + { + ThresholdEvent(conn_bytes_threshold_crossed, resp_bytes_thresh, is_orig); + resp_bytes_thresh = 0; + } + + if ( resp_pkts_thresh && resp_pkts >= resp_pkts_thresh ) + { + ThresholdEvent(conn_packets_threshold_crossed, resp_pkts_thresh, is_orig); + resp_pkts_thresh = 0; + } + } + } + +void ConnSize_Analyzer::SetThreshold(uint64 threshold, bool bytes, bool orig) + { + if ( bytes ) + { + if ( orig ) + orig_bytes_thresh = threshold; + else + resp_bytes_thresh = threshold; + } + else + { + if ( orig ) + orig_pkts_thresh = threshold; + else + resp_pkts_thresh = threshold; + } + } + +uint64_t ConnSize_Analyzer::GetThreshold(bool bytes, bool orig) + { + if ( bytes ) + { + if ( orig ) + return orig_bytes_thresh; + else + return resp_bytes_thresh; + } + else + { + if ( orig ) + return orig_pkts_thresh; + else + return resp_pkts_thresh; } } diff --git a/src/analyzer/protocol/conn-size/ConnSize.h b/src/analyzer/protocol/conn-size/ConnSize.h index d48c448822..41388ceb3c 100644 --- a/src/analyzer/protocol/conn-size/ConnSize.h +++ b/src/analyzer/protocol/conn-size/ConnSize.h @@ -21,6 +21,9 @@ public: virtual void UpdateConnVal(RecordVal *conn_val); virtual void FlipRoles(); + void SetThreshold(uint64_t threshold, bool bytes, bool orig); + uint64 GetThreshold(bool bytes, bool orig); + static analyzer::Analyzer* Instantiate(Connection* conn) { return new ConnSize_Analyzer(conn); } @@ -28,11 +31,17 @@ protected: virtual void DeliverPacket(int len, const u_char* data, bool is_orig, uint64 seq, const IP_Hdr* ip, int caplen); + void ThresholdEvent(EventHandlerPtr f, uint64 threshold, bool is_orig); uint64_t orig_bytes; uint64_t resp_bytes; uint64_t orig_pkts; uint64_t resp_pkts; + + uint64_t orig_bytes_thresh; + uint64_t resp_bytes_thresh; + uint64_t orig_pkts_thresh; + uint64_t resp_pkts_thresh; }; } } // namespace analyzer::* diff --git a/src/analyzer/protocol/conn-size/events.bif b/src/analyzer/protocol/conn-size/events.bif index e69de29bb2..ab1034ebb8 100644 --- a/src/analyzer/protocol/conn-size/events.bif +++ b/src/analyzer/protocol/conn-size/events.bif @@ -0,0 +1,23 @@ +## Generated for a connection that crossed a set byte threshold +## +## c: the connection +## +## threshold: the threshold that was set +## +## is_orig: True if the threshold was crossed by the originator of the connection +## +## .. bro:see:: set_conn_packets_threshold set_conn_bytes_threshold conn_packets_threshold_crossed +## get_conn_bytes_threshold get_conn_packets_threshold +event conn_bytes_threshold_crossed%(c: connection, threshold: count, is_orig: bool%); + +## Generated for a connection that crossed a set packet threshold +## +## c: the connection +## +## threshold: the threshold that was set +## +## is_orig: True if the threshold was crossed by the originator of the connection +## +## .. bro:see:: set_conn_packets_threshold set_conn_bytes_threshold conn_bytes_threshold_crossed +## get_conn_bytes_threshold get_conn_packets_threshold +event conn_packets_threshold_crossed%(c: connection, threshold: count, is_orig: bool%); diff --git a/src/analyzer/protocol/conn-size/functions.bif b/src/analyzer/protocol/conn-size/functions.bif new file mode 100644 index 0000000000..838c5976c4 --- /dev/null +++ b/src/analyzer/protocol/conn-size/functions.bif @@ -0,0 +1,106 @@ + +%%{ +#include "analyzer/protocol/conn-size/ConnSize.h" + +analyzer::Analyzer* GetConnsizeAnalyzer(Val* cid) + { + Connection* c = sessions->FindConnection(cid); + if ( ! c ) + { + reporter->Error("cannot find connection"); + return 0; + } + + analyzer::Analyzer* a = c->FindAnalyzer("CONNSIZE"); + if ( ! a ) + reporter->Error("connection does not have ConnSize analyzer"); + + return a; + } + +%%} + +## Sets a threshold for connection sizes. +## +## cid: The connection id. +## +## threshold: Threshold in bytes. +## +## is_orig: If true, threshold is set for bytes from originator, otherwhise for bytes from responder. +## +## .. bro:see:: set_conn_packets_threshold conn_bytes_threshold_crossed conn_packets_threshold_crossed +## get_conn_bytes_threshold get_conn_packets_threshold +function set_conn_bytes_threshold%(cid: conn_id, threshold: count, is_orig: bool%): bool + %{ + analyzer::Analyzer* a = GetConnsizeAnalyzer(cid); + if ( ! a ) + return new Val(0, TYPE_BOOL); + + static_cast(a)->SetThreshold(threshold, 1, is_orig); + + return new Val(0, TYPE_BOOL); + %} + +## Sets a threshold for connection packets. +## +## cid: The connection id. +## +## threshold: Threshold in packets. +## +## is_orig: If true, threshold is set for packets from originator, otherwhise for packets from responder. +## +## .. bro:see:: set_conn_bytes_threshold conn_bytes_threshold_crossed conn_packets_threshold_crossed +## get_conn_bytes_threshold get_conn_packets_threshold +function set_conn_packets_threshold%(cid: conn_id, threshold: count, is_orig: bool%): bool + %{ + analyzer::Analyzer* a = GetConnsizeAnalyzer(cid); + if ( ! a ) + return new Val(0, TYPE_BOOL); + + static_cast(a)->SetThreshold(threshold, 0, is_orig); + + return new Val(0, TYPE_BOOL); + %} + +## Gets the current byte threshold size for a connection. +## +## cid: The connection id. +## +## is_orig: If true, threshold of originator, otherwhise threshold of responder. +## +## Returns: 0 if no threshold is set or the threshold in bytes +## +## .. bro:see:: set_conn_packets_threshold conn_bytes_threshold_crossed conn_packets_threshold_crossed +## get_conn_packets_threshold +function get_conn_bytes_threshold%(cid: conn_id, is_orig: bool%): count + %{ + analyzer::Analyzer* a = GetConnsizeAnalyzer(cid); + if ( ! a ) + return new Val(0, TYPE_COUNT); + + return new Val( + static_cast(a)->GetThreshold(1, is_orig), + TYPE_COUNT); + %} + +## Gets the current packet threshold size for a connection. +## +## cid: The connection id. +## +## is_orig: If true, threshold of originator, otherwhise threshold of responder. +## +## Returns: 0 if no threshold is set or the threshold in packets +## +## .. bro:see:: set_conn_packets_threshold conn_bytes_threshold_crossed conn_packets_threshold_crossed +## get_conn_bytes_threshold +function get_conn_packets_threshold%(cid: conn_id, is_orig: bool%): count + %{ + analyzer::Analyzer* a = GetConnsizeAnalyzer(cid); + if ( ! a ) + return new Val(0, TYPE_COUNT); + + return new Val( + static_cast(a)->GetThreshold(0, is_orig), + TYPE_COUNT); + %} + diff --git a/src/analyzer/protocol/tcp/TCP.cc b/src/analyzer/protocol/tcp/TCP.cc index 88def89689..72cad8a05c 100644 --- a/src/analyzer/protocol/tcp/TCP.cc +++ b/src/analyzer/protocol/tcp/TCP.cc @@ -367,6 +367,41 @@ void TCP_Analyzer::Done() finished = 1; } +analyzer::Analyzer* TCP_Analyzer::FindChild(ID arg_id) + { + analyzer::Analyzer* child = analyzer::TransportLayerAnalyzer::FindChild(arg_id); + + if ( child ) + return child; + + LOOP_OVER_GIVEN_CHILDREN(i, packet_children) + { + analyzer::Analyzer* child = (*i)->FindChild(arg_id); + if ( child ) + return child; + } + + return 0; + } + +analyzer::Analyzer* TCP_Analyzer::FindChild(Tag arg_tag) + { + analyzer::Analyzer* child = analyzer::TransportLayerAnalyzer::FindChild(arg_tag); + + if ( child ) + return child; + + LOOP_OVER_GIVEN_CHILDREN(i, packet_children) + { + analyzer::Analyzer* child = (*i)->FindChild(arg_tag); + if ( child ) + return child; + } + + return 0; + } + + void TCP_Analyzer::EnableReassembly() { SetReassembler(new TCP_Reassembler(this, this, @@ -1764,6 +1799,15 @@ bool TCP_Analyzer::HadGap(bool is_orig) const return endp && endp->HadGap(); } +void TCP_Analyzer::AddChildPacketAnalyzer(analyzer::Analyzer* a) + { + DBG_LOG(DBG_ANALYZER, "%s added packet child %s", + this->GetAnalyzerName(), a->GetAnalyzerName()); + + packet_children.push_back(a); + a->SetParent(this); + } + int TCP_Analyzer::DataPending(TCP_Endpoint* closing_endp) { if ( Skipping() ) diff --git a/src/analyzer/protocol/tcp/TCP.h b/src/analyzer/protocol/tcp/TCP.h index 3073d75fb2..608c06a5aa 100644 --- a/src/analyzer/protocol/tcp/TCP.h +++ b/src/analyzer/protocol/tcp/TCP.h @@ -47,8 +47,10 @@ public: // Add a child analyzer that will always get the packets, // independently of whether we do any reassembly. - void AddChildPacketAnalyzer(analyzer::Analyzer* a) - { packet_children.push_back(a); a->SetParent(this); } + void AddChildPacketAnalyzer(analyzer::Analyzer* a); + + virtual Analyzer* FindChild(ID id); + virtual Analyzer* FindChild(Tag tag); // True if the connection has closed in some sense, false otherwise. int IsClosed() const { return orig->did_close || resp->did_close; } diff --git a/testing/btest/Baseline/core.conn-size-threshold/.stdout b/testing/btest/Baseline/core.conn-size-threshold/.stdout new file mode 100644 index 0000000000..76ad7c0696 --- /dev/null +++ b/testing/btest/Baseline/core.conn-size-threshold/.stdout @@ -0,0 +1,23 @@ +0 +0 +0 +0 +Threshold set for [orig_h=192.168.1.77, orig_p=57640/tcp, resp_h=66.198.80.67, resp_p=6667/tcp] +3000 +2000 +63 +50 +triggered bytes, [orig_h=192.168.1.77, orig_p=57640/tcp, resp_h=66.198.80.67, resp_p=6667/tcp], 2000, F +triggered bytes, [orig_h=192.168.1.77, orig_p=57640/tcp, resp_h=66.198.80.67, resp_p=6667/tcp], 3000, T +triggered packets, [orig_h=192.168.1.77, orig_p=57640/tcp, resp_h=66.198.80.67, resp_p=6667/tcp], 50, F +0 +0 +0 +0 +Threshold set for [orig_h=192.168.1.77, orig_p=57655/tcp, resp_h=209.197.168.151, resp_p=1024/tcp] +3000 +2000 +63 +50 +triggered bytes, [orig_h=192.168.1.77, orig_p=57655/tcp, resp_h=209.197.168.151, resp_p=1024/tcp], 2000, F +triggered packets, [orig_h=192.168.1.77, orig_p=57640/tcp, resp_h=66.198.80.67, resp_p=6667/tcp], 63, T diff --git a/testing/btest/core/conn-size-threshold.bro b/testing/btest/core/conn-size-threshold.bro new file mode 100644 index 0000000000..304683e7e3 --- /dev/null +++ b/testing/btest/core/conn-size-threshold.bro @@ -0,0 +1,32 @@ +# @TEST-EXEC: bro -r $TRACES/irc-dcc-send.trace %INPUT +# @TEST-EXEC: btest-diff .stdout + +event connection_established(c: connection) + { + print get_conn_bytes_threshold(c$id, T); + print get_conn_bytes_threshold(c$id, F); + print get_conn_packets_threshold(c$id, T); + print get_conn_packets_threshold(c$id, F); + + print fmt("Threshold set for %s", cat(c$id)); + set_conn_bytes_threshold(c$id, 3000, T); + set_conn_bytes_threshold(c$id, 2000, F); + + set_conn_packets_threshold(c$id, 50, F); + set_conn_packets_threshold(c$id, 63, T); + + print get_conn_bytes_threshold(c$id, T); + print get_conn_bytes_threshold(c$id, F); + print get_conn_packets_threshold(c$id, T); + print get_conn_packets_threshold(c$id, F); + } + +event conn_bytes_threshold_crossed(c: connection, threshold: count, is_orig: bool) + { + print "triggered bytes", c$id, threshold, is_orig; + } + +event conn_packets_threshold_crossed(c: connection, threshold: count, is_orig: bool) + { + print "triggered packets", c$id, threshold, is_orig; + }