Allow setting packet and byte thresholds for connections.

This extends the ConnSize analyzer to be able to raise events when each
direction of a connection crosses a certain amount of bytes or packets.

Thresholds are set using
set_conn_bytes_threshold(c$id, [num-bytes], [direction]);
and
set_conn_packets_threshold(c$id, [num-packets], [direction]);
respectively.

They raise the event
event conn_bytes_threshold_crossed(c: connection, threshold: count, is_orig: bool)
and
event conn_packets_threshold_crossed(c: connection, threshold: count, is_orig: bool)
respectively.

Current thresholds can be examined using
get_conn_bytes_threshold and get_conn_packets_threshold

Currently only one threshold can be set per connection.

This also fixes a bug where child packet analyzers of the TCP analyzer
where not found using FindChild.
This commit is contained in:
Johanna Amann 2015-04-16 12:44:45 -07:00
parent a129911272
commit f7edf70882
10 changed files with 321 additions and 4 deletions

View file

@ -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

View file

@ -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()

View file

@ -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;
}
}

View file

@ -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::*

View file

@ -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%);

View file

@ -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<analyzer::conn_size::ConnSize_Analyzer*>(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<analyzer::conn_size::ConnSize_Analyzer*>(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<analyzer::conn_size::ConnSize_Analyzer*>(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<analyzer::conn_size::ConnSize_Analyzer*>(a)->GetThreshold(0, is_orig),
TYPE_COUNT);
%}

View file

@ -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() )

View file

@ -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; }

View file

@ -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

View file

@ -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;
}