diff --git a/aux/binpac b/aux/binpac index a8617fdca7..4fc13f7c69 160000 --- a/aux/binpac +++ b/aux/binpac @@ -1 +1 @@ -Subproject commit a8617fdca799bd7af272b712373869698a55b4b7 +Subproject commit 4fc13f7c6987b4163609e3df7a31f38501411cb7 diff --git a/policy/bro.init b/policy/bro.init index 7fbbe216bb..a9ed8fac82 100644 --- a/policy/bro.init +++ b/policy/bro.init @@ -66,8 +66,12 @@ type ftp_port: record { }; type endpoint: record { - size: count; + size: count; # logical size (for TCP: from seq numbers) state: count; + + # The following are set if use_conn_size_analyzer is T. + num_pkts: count &optional; # number of packets on the wire + num_bytes_ip: count &optional; # actual number of IP-level bytes on the wire }; type endpoint_stats: record { @@ -497,6 +501,12 @@ const encap_hdr_size = 0 &redef; # ... or just for the following UDP port. const tunnel_port = 0/udp &redef; +# Whether to use the ConnSize analyzer to count the number of +# packets and IP-level bytes transfered by each endpoint. If +# true, these values are returned in the connection's endpoint +# record val. +const use_conn_size_analyzer = F &redef; + const UDP_INACTIVE = 0; const UDP_ACTIVE = 1; # means we've seen something from this endpoint diff --git a/policy/conn.bro b/policy/conn.bro index a5d620d4c8..52993b0aec 100644 --- a/policy/conn.bro +++ b/policy/conn.bro @@ -18,9 +18,14 @@ global have_SMTP = F; # if true, we've loaded smtp.bro # TODO: Do we have a nicer way of defining this prototype? export { global FTP::is_ftp_data_conn: function(c: connection): bool; } -# Whether to include connection state history in the logs generated -# by record_connection. -const record_state_history = F &redef; +# Whether to add 4 more columns to conn.log with +# orig_packet orig_ip_bytes resp_packets resp_ip_bytes +# Requires use_conn_size_analyzer=T +# Columns are added after history but before addl +const report_conn_size_analyzer = F &redef; + +# Activate conn-size analyzer if necessary. +redef use_conn_size_analyzer = (! report_conn_size_analyzer); # Whether to translate the local address in SensitiveConnection notices # to a hostname. Meant as a demonstration of the "when" construct. @@ -96,6 +101,12 @@ function conn_size(e: endpoint, trans: transport_proto): string return "?"; } +function conn_size_from_analyzer(e: endpoint): string + { + return fmt("%d %d", (e?$num_pkts) ? e$num_pkts : 0, + (e?$num_bytes_ip) ? e$num_bytes_ip : 0); + } + function service_name(c: connection): string { local p = c$id$resp_p; @@ -300,9 +311,9 @@ function record_connection(f: file, c: connection) conn_size(c$orig, trans), conn_size(c$resp, trans), conn_state(c, trans), flags); - if ( record_state_history ) - log_msg = fmt("%s %s", log_msg, - c$history == "" ? "X" : c$history); + if ( use_conn_size_analyzer && report_conn_size_analyzer ) + log_msg = fmt("%s %s %s", log_msg, + conn_size_from_analyzer(c$orig), conn_size_from_analyzer(c$resp)); if ( addl != "" ) log_msg = fmt("%s %s", log_msg, addl); diff --git a/src/Analyzer.cc b/src/Analyzer.cc index c6d33ab2c6..ff159f5b11 100644 --- a/src/Analyzer.cc +++ b/src/Analyzer.cc @@ -36,6 +36,7 @@ #include "SSH.h" #include "SSLProxy.h" #include "SSL-binpac.h" +#include "ConnSizeAnalyzer.h" // Keep same order here as in AnalyzerTag definition! const Analyzer::Config Analyzer::analyzer_configs[] = { @@ -151,6 +152,9 @@ const Analyzer::Config Analyzer::analyzer_configs[] = { { AnalyzerTag::TCPStats, "TCPSTATS", TCPStats_Analyzer::InstantiateAnalyzer, TCPStats_Analyzer::Available, 0, false }, + { AnalyzerTag::ConnSize, "CONNSIZE", + ConnSize_Analyzer::InstantiateAnalyzer, + ConnSize_Analyzer::Available, 0, false }, { AnalyzerTag::Contents, "CONTENTS", 0, 0, 0, false }, { AnalyzerTag::ContentLine, "CONTENTLINE", 0, 0, 0, false }, @@ -852,6 +856,12 @@ unsigned int Analyzer::MemoryAllocation() const return mem; } +void Analyzer::UpdateConnVal(RecordVal *conn_val) + { + LOOP_OVER_CHILDREN(i) + (*i)->UpdateConnVal(conn_val); + } + void SupportAnalyzer::ForwardPacket(int len, const u_char* data, bool is_orig, int seq, const IP_Hdr* ip, int caplen) { diff --git a/src/Analyzer.h b/src/Analyzer.h index d76b8a5050..c889dc6b2f 100644 --- a/src/Analyzer.h +++ b/src/Analyzer.h @@ -227,6 +227,13 @@ public: virtual unsigned int MemoryAllocation() const; + // Called whenever the connection value needs to be updated. Per + // default, this method will be called for each analyzer in the tree. + // Analyzers can use this method to attach additional data to the + // connections. A call to BuildConnVal will in turn trigger a call to + // UpdateConnVal. + virtual void UpdateConnVal(RecordVal *conn_val); + // The following methods are proxies: calls are directly forwarded // to the connection instance. These are for convenience only, // allowing us to reuse more of the old analyzer code unchanged. @@ -366,7 +373,6 @@ public: : Analyzer(tag, conn) { pia = 0; } virtual void Done(); - virtual void UpdateEndpointVal(RecordVal* endp, int is_orig) = 0; virtual bool IsReuse(double t, const u_char* pkt) = 0; virtual void SetContentsFile(unsigned int direction, BroFile* f); diff --git a/src/AnalyzerTags.h b/src/AnalyzerTags.h index 9bf3efbd3c..e5760c41f8 100644 --- a/src/AnalyzerTags.h +++ b/src/AnalyzerTags.h @@ -38,6 +38,8 @@ namespace AnalyzerTag { // Other File, Backdoor, InterConn, SteppingStone, TCPStats, + ConnSize, + // Support-analyzers Contents, ContentLine, NVT, Zip, Contents_DNS, Contents_NCP, diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ac87ae4dd4..2975d1cf04 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -295,6 +295,7 @@ set(bro_SRCS CompHash.cc Conn.cc ConnCompressor.cc + ConnSizeAnalyzer.cc ContentLine.cc DCE_RPC.cc DFA.cc diff --git a/src/Conn.cc b/src/Conn.cc index 8ebef29468..8ef756b134 100644 --- a/src/Conn.cc +++ b/src/Conn.cc @@ -152,7 +152,6 @@ Connection::Connection(NetSessions* s, HashKey* k, double t, const ConnID* id) proto = TRANSPORT_UNKNOWN; conn_val = 0; - orig_endp = resp_endp = 0; login_conn = 0; is_active = 1; @@ -401,12 +400,12 @@ RecordVal* Connection::BuildConnVal() conn_val->Assign(0, id_val); - orig_endp = new RecordVal(endpoint); + RecordVal *orig_endp = new RecordVal(endpoint); orig_endp->Assign(0, new Val(0, TYPE_COUNT)); orig_endp->Assign(1, new Val(0, TYPE_COUNT)); conn_val->Assign(1, orig_endp); - resp_endp = new RecordVal(endpoint); + RecordVal *resp_endp = new RecordVal(endpoint); resp_endp->Assign(0, new Val(0, TYPE_COUNT)); resp_endp->Assign(1, new Val(0, TYPE_COUNT)); conn_val->Assign(2, resp_endp); @@ -425,10 +424,7 @@ RecordVal* Connection::BuildConnVal() } if ( root_analyzer ) - { - root_analyzer->UpdateEndpointVal(orig_endp, 1); - root_analyzer->UpdateEndpointVal(resp_endp, 0); - } + root_analyzer->UpdateConnVal(conn_val); conn_val->Assign(3, new Val(start_time, TYPE_TIME)); // ### conn_val->Assign(4, new Val(last_time - start_time, TYPE_INTERVAL)); @@ -803,10 +799,6 @@ void Connection::FlipRoles() resp_port = orig_port; orig_port = tmp_port; - RecordVal* tmp_rc = resp_endp; - resp_endp = orig_endp; - orig_endp = tmp_rc; - Unref(conn_val); conn_val = 0; @@ -902,8 +894,6 @@ bool Connection::DoSerialize(SerialInfo* info) const return false; SERIALIZE_OPTIONAL(conn_val); - SERIALIZE_OPTIONAL(orig_endp); - SERIALIZE_OPTIONAL(resp_endp); // FIXME: RuleEndpointState not yet serializable. // FIXME: Analyzers not yet serializable. @@ -967,10 +957,6 @@ bool Connection::DoUnserialize(UnserialInfo* info) UNSERIALIZE_OPTIONAL(conn_val, (RecordVal*) Val::Unserialize(info, connection_type)); - UNSERIALIZE_OPTIONAL(orig_endp, - (RecordVal*) Val::Unserialize(info, endpoint)); - UNSERIALIZE_OPTIONAL(resp_endp, - (RecordVal*) Val::Unserialize(info, endpoint)); int iproto; diff --git a/src/Conn.h b/src/Conn.h index eafc6e9fd0..8a178d783a 100644 --- a/src/Conn.h +++ b/src/Conn.h @@ -338,8 +338,6 @@ protected: double start_time, last_time; double inactivity_timeout; RecordVal* conn_val; - RecordVal* orig_endp; - RecordVal* resp_endp; LoginConn* login_conn; // either nil, or this int suppress_event; // suppress certain events to once per conn. diff --git a/src/ConnCompressor.cc b/src/ConnCompressor.cc index 1d384f4ca4..e6428aeebe 100644 --- a/src/ConnCompressor.cc +++ b/src/ConnCompressor.cc @@ -4,6 +4,7 @@ #include "ConnCompressor.h" #include "Event.h" +#include "ConnSizeAnalyzer.h" #include "net_util.h" // The basic model of the compressor is to wait for an answer before @@ -45,6 +46,11 @@ // - We don't match signatures on connections which are completely handled // by the compressor. Matching would require significant additional state // w/o being very helpful. +// +// - If use_conn_size_analyzer is True, the reported counts for bytes and +// packets may not account for some packets/data that is part of those +// packets which the connection compressor handles. The error, if any, will +// however be small. #ifdef DEBUG @@ -234,7 +240,7 @@ Connection* ConnCompressor::NextPacket(double t, HashKey* key, const IP_Hdr* ip, else if ( addr_eq(ip->SrcAddr(), SrcAddr(pending)) && tp->th_sport == SrcPort(pending) ) // Another packet from originator. - tc = NextFromOrig(pending, t, key, tp); + tc = NextFromOrig(pending, t, key, ip, tp); else // A reply. @@ -329,11 +335,15 @@ Connection* ConnCompressor::FirstFromOrig(double t, HashKey* key, } Connection* ConnCompressor::NextFromOrig(PendingConn* pending, double t, - HashKey* key, const tcphdr* tp) + HashKey* key, const IP_Hdr* ip, + const tcphdr* tp) { // Another packet from the same host without seeing an answer so far. DBG_LOG(DBG_COMPRESSOR, "%s same again", fmt_conn_id(pending)); + ++pending->num_pkts; + ++pending->num_bytes_ip += ip->PayloadLen(); + // New window scale overrides old - not great, this is a (subtle) // evasion opportunity. if ( TCP_Analyzer::ParseTCPOptions(tp, parse_tcp_options, 0, 0, @@ -611,6 +621,8 @@ void ConnCompressor::PktHdrToPendingConn(double time, const HashKey* key, c->RST = (tp->th_flags & TH_RST) != 0; c->ACK = (tp->th_flags & TH_ACK) != 0; c->uid = Connection::CalculateNextUID(); + c->num_bytes_ip = ip->TotalLen(); + c->num_pkts = 1; c->invalid = 0; if ( TCP_Analyzer::ParseTCPOptions(tp, parse_tcp_options, 0, 0, c) < 0 ) @@ -851,8 +863,23 @@ void ConnCompressor::Event(const PendingConn* pending, double t, TRANSPORT_TCP)); orig_endp->Assign(0, new Val(orig_size, TYPE_COUNT)); orig_endp->Assign(1, new Val(orig_state, TYPE_COUNT)); + + if ( ConnSize_Analyzer::Available() ) + { + orig_endp->Assign(2, new Val(pending->num_pkts, TYPE_COUNT)); + orig_endp->Assign(3, new Val(pending->num_bytes_ip, TYPE_COUNT)); + } + else + { + orig_endp->Assign(2, new Val(0, TYPE_COUNT)); + orig_endp->Assign(3, new Val(0, TYPE_COUNT)); + } + + resp_endp->Assign(0, new Val(0, TYPE_COUNT)); resp_endp->Assign(1, new Val(resp_state, TYPE_COUNT)); + resp_endp->Assign(2, new Val(0, TYPE_COUNT)); + resp_endp->Assign(3, new Val(0, TYPE_COUNT)); } else { @@ -862,10 +889,26 @@ void ConnCompressor::Event(const PendingConn* pending, double t, id_val->Assign(2, new AddrVal(SrcAddr(pending))); id_val->Assign(3, new PortVal(ntohs(SrcPort(pending)), TRANSPORT_TCP)); + orig_endp->Assign(0, new Val(0, TYPE_COUNT)); orig_endp->Assign(1, new Val(resp_state, TYPE_COUNT)); + orig_endp->Assign(2, new Val(0, TYPE_COUNT)); + orig_endp->Assign(3, new Val(0, TYPE_COUNT)); + resp_endp->Assign(0, new Val(orig_size, TYPE_COUNT)); resp_endp->Assign(1, new Val(orig_state, TYPE_COUNT)); + + if ( ConnSize_Analyzer::Available() ) + { + resp_endp->Assign(2, new Val(pending->num_pkts, TYPE_COUNT)); + resp_endp->Assign(3, new Val(pending->num_bytes_ip, TYPE_COUNT)); + } + else + { + resp_endp->Assign(2, new Val(0, TYPE_COUNT)); + resp_endp->Assign(3, new Val(0, TYPE_COUNT)); + } + DBG_LOG(DBG_COMPRESSOR, "%s swapped direction", fmt_conn_id(pending)); } diff --git a/src/ConnCompressor.h b/src/ConnCompressor.h index 84a1c1266f..040a120ba9 100644 --- a/src/ConnCompressor.h +++ b/src/ConnCompressor.h @@ -98,6 +98,10 @@ public: hash_t hash; uint16 window; uint64 uid; + + // The following are set if use_conn_size_analyzer is T. + uint16 num_pkts; + uint16 num_bytes_ip; }; private: @@ -119,8 +123,8 @@ private: const IP_Hdr* ip, const tcphdr* tp); // Called for more packets from the orginator w/o seeing a response. - Connection* NextFromOrig(PendingConn* pending, - double t, HashKey* key, const tcphdr* tp); + Connection* NextFromOrig(PendingConn* pending, double t, HashKey* key, + const IP_Hdr* ip, const tcphdr* tp); // Called for the first response packet. Instantiates a Connection. Connection* Response(PendingConn* pending, double t, HashKey* key, diff --git a/src/ConnSizeAnalyzer.cc b/src/ConnSizeAnalyzer.cc new file mode 100644 index 0000000000..c98a9f6827 --- /dev/null +++ b/src/ConnSizeAnalyzer.cc @@ -0,0 +1,90 @@ +// $Id$ +// +// See the file "COPYING" in the main distribution directory for copyright. +// +// See ConnSize.h for more extensive comments. + + +#include "ConnSizeAnalyzer.h" +#include "TCP.h" + + + +ConnSize_Analyzer::ConnSize_Analyzer(Connection* c) +: Analyzer(AnalyzerTag::ConnSize, c) + { + } + + +ConnSize_Analyzer::~ConnSize_Analyzer() + { + } + +void ConnSize_Analyzer::Init() + { + Analyzer::Init(); + + orig_bytes = 0; + orig_pkts = 0; + resp_bytes = 0; + resp_pkts = 0; + } + +void ConnSize_Analyzer::Done() + { + Analyzer::Done(); + } + +void ConnSize_Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig, int seq, const IP_Hdr* ip, int caplen) + { + Analyzer::DeliverPacket(len, data, is_orig, seq, ip, caplen); + + if ( is_orig ) + { + orig_bytes += ip->TotalLen(); + orig_pkts ++; + } + else + { + resp_bytes += ip->TotalLen(); + resp_pkts ++; + } + } + +void ConnSize_Analyzer::UpdateConnVal(RecordVal *conn_val) + { + // RecordType *connection_type is decleared in NetVar.h + int orig_endp_idx = connection_type->FieldOffset("orig"); + int resp_endp_idx = connection_type->FieldOffset("resp"); + RecordVal *orig_endp = conn_val->Lookup(orig_endp_idx)->AsRecordVal(); + RecordVal *resp_endp = conn_val->Lookup(resp_endp_idx)->AsRecordVal(); + + // endpoint is the RecordType from NetVar.h + // TODO: or orig_endp->Type()->AsRecordVal()->FieldOffset() + int pktidx = endpoint->FieldOffset("num_pkts"); + int bytesidx = endpoint->FieldOffset("num_bytes_ip"); + + // TODO: error handling? + orig_endp->Assign(pktidx, new Val(orig_pkts, TYPE_COUNT)); + orig_endp->Assign(bytesidx, new Val(orig_bytes, TYPE_COUNT)); + resp_endp->Assign(pktidx, new Val(resp_pkts, TYPE_COUNT)); + resp_endp->Assign(bytesidx, new Val(resp_bytes, TYPE_COUNT)); + + Analyzer::UpdateConnVal(conn_val); + } + + +void ConnSize_Analyzer::FlipRoles() + { + Analyzer::FlipRoles(); + uint64_t tmp; + + tmp = orig_bytes; + orig_bytes = resp_bytes; + resp_bytes = tmp; + + tmp = orig_pkts; + orig_pkts = resp_pkts; + resp_pkts = tmp; + } + diff --git a/src/ConnSizeAnalyzer.h b/src/ConnSizeAnalyzer.h new file mode 100644 index 0000000000..38446b0763 --- /dev/null +++ b/src/ConnSizeAnalyzer.h @@ -0,0 +1,41 @@ +// $Id$ +// +// See the file "COPYING" in the main distribution directory for copyright. +// + +#ifndef CONNSTATS_H +#define CONNSTATS_H + +#include "Analyzer.h" +#include "NetVar.h" + + +class ConnSize_Analyzer : public Analyzer { +public: + ConnSize_Analyzer(Connection* c); + virtual ~ConnSize_Analyzer(); + + virtual void Init(); + virtual void Done(); + + // from Analyzer.h + virtual void UpdateConnVal(RecordVal *conn_val); + virtual void FlipRoles(); + + static Analyzer* InstantiateAnalyzer(Connection* conn) + { return new ConnSize_Analyzer(conn); } + + static bool Available() { return BifConst::use_conn_size_analyzer ; } + +protected: + virtual void DeliverPacket(int len, const u_char* data, bool is_orig, + int seq, const IP_Hdr* ip, int caplen); + + + uint64_t orig_bytes; + uint64_t resp_bytes; + uint64_t orig_pkts; + uint64_t resp_pkts; +}; + +#endif diff --git a/src/DPM.cc b/src/DPM.cc index 35111a38fa..3e27a0501d 100644 --- a/src/DPM.cc +++ b/src/DPM.cc @@ -10,6 +10,7 @@ #include "BackDoor.h" #include "InterConn.h" #include "SteppingStone.h" +#include "ConnSizeAnalyzer.h" ExpectedConn::ExpectedConn(const uint32* _orig, const uint32* _resp, @@ -189,6 +190,8 @@ bool DPM::BuildInitialAnalyzerTree(TransportProto proto, Connection* conn, const u_char* data) { TCP_Analyzer* tcp = 0; + UDP_Analyzer* udp = 0; + ICMP_Analyzer* icmp = 0; TransportLayerAnalyzer* root = 0; AnalyzerTag::Tag expected = AnalyzerTag::Error; analyzer_map* ports = 0; @@ -206,7 +209,7 @@ bool DPM::BuildInitialAnalyzerTree(TransportProto proto, Connection* conn, break; case TRANSPORT_UDP: - root = new UDP_Analyzer(conn); + root = udp = new UDP_Analyzer(conn); pia = new PIA_UDP(conn); expected = GetExpected(proto, conn); ports = &udp_ports; @@ -221,7 +224,7 @@ bool DPM::BuildInitialAnalyzerTree(TransportProto proto, Connection* conn, case ICMP_ECHOREPLY: if ( ICMP_Echo_Analyzer::Available() ) { - root = new ICMP_Echo_Analyzer(conn); + root = icmp = new ICMP_Echo_Analyzer(conn); DBG_DPD(conn, "activated ICMP Echo analyzer"); } break; @@ -229,7 +232,7 @@ bool DPM::BuildInitialAnalyzerTree(TransportProto proto, Connection* conn, case ICMP_UNREACH: if ( ICMP_Unreachable_Analyzer::Available() ) { - root = new ICMP_Unreachable_Analyzer(conn); + root = icmp = new ICMP_Unreachable_Analyzer(conn); DBG_DPD(conn, "activated ICMP Unreachable analyzer"); } break; @@ -237,14 +240,14 @@ bool DPM::BuildInitialAnalyzerTree(TransportProto proto, Connection* conn, case ICMP_TIMXCEED: if ( ICMP_TimeExceeded_Analyzer::Available() ) { - root = new ICMP_TimeExceeded_Analyzer(conn); + root = icmp = new ICMP_TimeExceeded_Analyzer(conn); DBG_DPD(conn, "activated ICMP Time Exceeded analyzer"); } break; } if ( ! root ) - root = new ICMP_Analyzer(conn); + root = icmp = new ICMP_Analyzer(conn); analyzed = true; break; @@ -363,6 +366,16 @@ bool DPM::BuildInitialAnalyzerTree(TransportProto proto, Connection* conn, // we cannot add it as a normal child. if ( TCPStats_Analyzer::Available() ) tcp->AddChildPacketAnalyzer(new TCPStats_Analyzer(conn)); + + // Add ConnSize analyzer. Needs to see packets, not stream. + if ( ConnSize_Analyzer::Available() ) + tcp->AddChildPacketAnalyzer(new ConnSize_Analyzer(conn)); + } + + else + { + if ( ConnSize_Analyzer::Available() ) + root->AddChildAnalyzer(new ConnSize_Analyzer(conn), false); } if ( pia ) @@ -381,7 +394,7 @@ bool DPM::BuildInitialAnalyzerTree(TransportProto proto, Connection* conn, if ( expected != AnalyzerTag::Error ) conn->Event(expected_connection_seen, 0, new Val(expected, TYPE_COUNT)); - + return true; } diff --git a/src/ICMP.cc b/src/ICMP.cc index d73a9a781e..a72e249d81 100644 --- a/src/ICMP.cc +++ b/src/ICMP.cc @@ -79,6 +79,9 @@ void ICMP_Analyzer::DeliverPacket(int arg_len, const u_char* data, NextICMP(current_timestamp, icmpp, len, caplen, data); + if ( caplen >= len ) + ForwardPacket(len, data, is_orig, seq, ip, caplen); + if ( rule_matcher ) matcher_state.Match(Rule::PAYLOAD, data, len, is_orig, false, false, true); @@ -252,6 +255,20 @@ void ICMP_Analyzer::Describe(ODesc* d) const d->Add(dotted_addr(Conn()->RespAddr())); } +void ICMP_Analyzer::UpdateConnVal(RecordVal *conn_val) + { + int orig_endp_idx = connection_type->FieldOffset("orig"); + int resp_endp_idx = connection_type->FieldOffset("resp"); + RecordVal *orig_endp = conn_val->Lookup(orig_endp_idx)->AsRecordVal(); + RecordVal *resp_endp = conn_val->Lookup(resp_endp_idx)->AsRecordVal(); + + UpdateEndpointVal(orig_endp, 1); + UpdateEndpointVal(resp_endp, 0); + + // Call children's UpdateConnVal + Analyzer::UpdateConnVal(conn_val); + } + void ICMP_Analyzer::UpdateEndpointVal(RecordVal* endp, int is_orig) { Conn()->EnableStatusUpdateTimer(); diff --git a/src/ICMP.h b/src/ICMP.h index 43921f1aac..db1984e860 100644 --- a/src/ICMP.h +++ b/src/ICMP.h @@ -18,6 +18,8 @@ class ICMP_Analyzer : public TransportLayerAnalyzer { public: ICMP_Analyzer(Connection* conn); + virtual void UpdateConnVal(RecordVal *conn_val); + static Analyzer* InstantiateAnalyzer(Connection* conn) { return new ICMP_Analyzer(conn); } @@ -30,7 +32,6 @@ protected: virtual void Done(); virtual void DeliverPacket(int len, const u_char* data, bool orig, int seq, const IP_Hdr* ip, int caplen); - virtual void UpdateEndpointVal(RecordVal* endp, int is_orig); virtual bool IsReuse(double t, const u_char* pkt); virtual unsigned int MemoryAllocation() const; @@ -52,6 +53,9 @@ protected: int request_len, reply_len; RuleMatcherState matcher_state; + +private: + void UpdateEndpointVal(RecordVal* endp, int is_orig); }; class ICMP_Echo_Analyzer : public ICMP_Analyzer { diff --git a/src/TCP.cc b/src/TCP.cc index 67d516df7d..ea9d31e7a0 100644 --- a/src/TCP.cc +++ b/src/TCP.cc @@ -2,7 +2,7 @@ // // See the file "COPYING" in the main distribution directory for copyright. - +#include "NetVar.h" #include "PIA.h" #include "File.h" #include "TCP.h" @@ -922,9 +922,6 @@ int TCP_Analyzer::DeliverData(double t, const u_char* data, int len, int caplen, int need_contents = endpoint->DataSent(t, data_seq, len, caplen, data, ip, tp); - LOOP_OVER_GIVEN_CHILDREN(i, packet_children) - (*i)->NextPacket(len, data, is_orig, data_seq, ip, caplen); - return need_contents; } @@ -1053,6 +1050,12 @@ void TCP_Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig, CheckRecording(need_contents, flags); + // Handle child_packet analyzers. Note: This happens *after* the + // packet has been processed and the TCP state updated. + LOOP_OVER_GIVEN_CHILDREN(i, packet_children) + (*i)->NextPacket(len, data, is_orig, + base_seq - endpoint->StartSeq(), ip, caplen); + if ( ! reassembling ) ForwardPacket(len, data, is_orig, base_seq - endpoint->StartSeq(), ip, caplen); @@ -1082,11 +1085,25 @@ void TCP_Analyzer::FlipRoles() resp->is_orig = !resp->is_orig; } -void TCP_Analyzer::UpdateEndpointVal(RecordVal* endp, int is_orig) +void TCP_Analyzer::UpdateConnVal(RecordVal *conn_val) { - TCP_Endpoint* s = is_orig ? orig : resp; - endp->Assign(0, new Val(s->Size(), TYPE_COUNT)); - endp->Assign(1, new Val(int(s->state), TYPE_COUNT)); + int orig_endp_idx = connection_type->FieldOffset("orig"); + int resp_endp_idx = connection_type->FieldOffset("resp"); + + RecordVal *orig_endp_val = conn_val->Lookup(orig_endp_idx)->AsRecordVal(); + RecordVal *resp_endp_val = conn_val->Lookup(resp_endp_idx)->AsRecordVal(); + + orig_endp_val->Assign(0, new Val(orig->Size(), TYPE_COUNT)); + orig_endp_val->Assign(1, new Val(int(orig->state), TYPE_COUNT)); + resp_endp_val->Assign(0, new Val(resp->Size(), TYPE_COUNT)); + resp_endp_val->Assign(1, new Val(int(resp->state), TYPE_COUNT)); + + // Call children's UpdateConnVal + Analyzer::UpdateConnVal(conn_val); + + // Have to do packet_children ourselves. + LOOP_OVER_GIVEN_CHILDREN(i, packet_children) + (*i)->UpdateConnVal(conn_val); } Val* TCP_Analyzer::BuildSYNPacketVal(int is_orig, const IP_Hdr* ip, diff --git a/src/TCP.h b/src/TCP.h index 1acc605dfc..1db8c1ed68 100644 --- a/src/TCP.h +++ b/src/TCP.h @@ -77,6 +77,9 @@ public: const u_char* option, TCP_Analyzer* analyzer, bool is_orig, void* cookie); + // From Analyzer.h + virtual void UpdateConnVal(RecordVal *conn_val); + // Needs to be static because it's passed as a pointer-to-function // rather than pointer-to-member-function. static int ParseTCPOptions(const struct tcphdr* tcp, @@ -100,7 +103,6 @@ protected: virtual void DeliverStream(int len, const u_char* data, bool orig); virtual void Undelivered(int seq, int len, bool orig); virtual void FlipRoles(); - virtual void UpdateEndpointVal(RecordVal* endp, int is_orig); virtual bool IsReuse(double t, const u_char* pkt); // Returns the TCP header pointed to by data (which we assume is diff --git a/src/UDP.cc b/src/UDP.cc index 78020bbbc8..21d5b96945 100644 --- a/src/UDP.cc +++ b/src/UDP.cc @@ -162,6 +162,22 @@ void UDP_Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig, ForwardPacket(len, data, is_orig, seq, ip, caplen); } +void UDP_Analyzer::UpdateConnVal(RecordVal *conn_val) + { + int orig_endp_idx = connection_type->FieldOffset("orig"); + int resp_endp_idx = connection_type->FieldOffset("resp"); + RecordVal *orig_endp = conn_val->Lookup(orig_endp_idx)->AsRecordVal(); + RecordVal *resp_endp = conn_val->Lookup(resp_endp_idx)->AsRecordVal(); + + orig_endp = conn_val->Lookup(orig_endp_idx)->AsRecordVal(); + resp_endp = conn_val->Lookup(resp_endp_idx)->AsRecordVal(); + UpdateEndpointVal(orig_endp, 1); + UpdateEndpointVal(resp_endp, 0); + + // Call children's UpdateConnVal + Analyzer::UpdateConnVal(conn_val); + } + void UDP_Analyzer::UpdateEndpointVal(RecordVal* endp, int is_orig) { bro_int_t size = is_orig ? request_len : reply_len; diff --git a/src/UDP.h b/src/UDP.h index 7fe50492b4..b04c5e3ef0 100644 --- a/src/UDP.h +++ b/src/UDP.h @@ -19,6 +19,8 @@ public: virtual void Init(); + virtual void UpdateConnVal(RecordVal *conn_val); + static Analyzer* InstantiateAnalyzer(Connection* conn) { return new UDP_Analyzer(conn); } @@ -28,12 +30,14 @@ protected: virtual void Done(); virtual void DeliverPacket(int len, const u_char* data, bool orig, int seq, const IP_Hdr* ip, int caplen); - virtual void UpdateEndpointVal(RecordVal* endp, int is_orig); virtual bool IsReuse(double t, const u_char* pkt); virtual unsigned int MemoryAllocation() const; bro_int_t request_len, reply_len; +private: + void UpdateEndpointVal(RecordVal* endp, int is_orig); + #define HIST_ORIG_DATA_PKT 0x1 #define HIST_RESP_DATA_PKT 0x2 #define HIST_ORIG_CORRUPT_PKT 0x4 diff --git a/src/const.bif b/src/const.bif index 4c11d7d47c..e51028c742 100644 --- a/src/const.bif +++ b/src/const.bif @@ -5,3 +5,5 @@ const ignore_keep_alive_rexmit: bool; const skip_http_data: bool; const parse_udp_tunnels: bool; +const use_conn_size_analyzer: bool; + diff --git a/testing/btest/Baseline/analyzers.conn-size-cc/conn.log b/testing/btest/Baseline/analyzers.conn-size-cc/conn.log new file mode 100644 index 0000000000..2f703cbcd6 --- /dev/null +++ b/testing/btest/Baseline/analyzers.conn-size-cc/conn.log @@ -0,0 +1,5 @@ +1128727430.350788 ? 141.42.64.125 125.190.109.199 other 56729 12345 tcp ? ? S0 X 1 60 0 0 cc=1 +1144876538.705610 5.921003 169.229.147.203 239.255.255.253 other 49370 427 udp 147 ? S0 X 3 231 0 0 +1144876599.397603 0.815763 192.150.186.169 194.64.249.244 http 53063 80 tcp 377 445 SF X 6 677 5 713 +1144876709.032670 9.000191 169.229.147.43 239.255.255.253 other 49370 427 udp 196 ? S0 X 4 308 0 0 +1144876697.068273 0.000650 192.150.186.169 192.150.186.15 icmp-unreach 3 3 icmp 56 ? OTH X 2 112 0 0 diff --git a/testing/btest/Baseline/analyzers.conn-size/conn.log b/testing/btest/Baseline/analyzers.conn-size/conn.log new file mode 100644 index 0000000000..8129bc37f8 --- /dev/null +++ b/testing/btest/Baseline/analyzers.conn-size/conn.log @@ -0,0 +1,5 @@ +1128727430.350788 ? 141.42.64.125 125.190.109.199 other 56729 12345 tcp ? ? S0 X 1 60 0 0 +1144876538.705610 5.921003 169.229.147.203 239.255.255.253 other 49370 427 udp 147 ? S0 X 3 231 0 0 +1144876599.397603 0.815763 192.150.186.169 194.64.249.244 http 53063 80 tcp 377 445 SF X 6 697 5 713 +1144876709.032670 9.000191 169.229.147.43 239.255.255.253 other 49370 427 udp 196 ? S0 X 4 308 0 0 +1144876697.068273 0.000650 192.150.186.169 192.150.186.15 icmp-unreach 3 3 icmp 56 ? OTH X 2 112 0 0 diff --git a/testing/btest/Traces/conn-size.trace b/testing/btest/Traces/conn-size.trace new file mode 100644 index 0000000000..8b03d7a67f Binary files /dev/null and b/testing/btest/Traces/conn-size.trace differ diff --git a/testing/btest/analyzers/conn-size-cc.bro b/testing/btest/analyzers/conn-size-cc.bro new file mode 100644 index 0000000000..0ba7977cf5 --- /dev/null +++ b/testing/btest/analyzers/conn-size-cc.bro @@ -0,0 +1,2 @@ +# @TEST-EXEC: bro -C -r ${TRACES}/conn-size.trace tcp udp icmp report_conn_size_analyzer=T +# @TEST-EXEC: btest-diff conn.log diff --git a/testing/btest/analyzers/conn-size.bro b/testing/btest/analyzers/conn-size.bro new file mode 100644 index 0000000000..0e413cc554 --- /dev/null +++ b/testing/btest/analyzers/conn-size.bro @@ -0,0 +1,2 @@ +# @TEST-EXEC: bro -C -r ${TRACES}/conn-size.trace tcp udp icmp report_conn_size_analyzer=T use_connection_compressor=F +# @TEST-EXEC: btest-diff conn.log