diff --git a/scripts/base/protocols/sip/dpd.sig b/scripts/base/protocols/sip/dpd.sig index 143e2d843d..6d8b16a7d3 100644 --- a/scripts/base/protocols/sip/dpd.sig +++ b/scripts/base/protocols/sip/dpd.sig @@ -1,5 +1,17 @@ -signature dpd_sip { +signature dpd_sip_udp_req { + ip-proto == udp + payload /.* SIP\/[0-9]\.[0-9]\x0d\x0a/ + enable "sip" +} + +signature dpd_sip_udp_resp { ip-proto == udp payload /^( SIP\/[0-9]\.[0-9]\x0d\x0a|SIP\/[0-9]\.[0-9] [0-9][0-9][0-9] )/ enable "sip" } + +signature dpd_sip_tcp { + ip-proto == tcp + payload /^( SIP\/[0-9]\.[0-9]\x0d\x0a|SIP\/[0-9]\.[0-9] [0-9][0-9][0-9] )/ + enable "sip_tcp" +} diff --git a/scripts/base/protocols/sip/main.bro b/scripts/base/protocols/sip/main.bro index 13aeb78e16..53b7263180 100644 --- a/scripts/base/protocols/sip/main.bro +++ b/scripts/base/protocols/sip/main.bro @@ -85,13 +85,9 @@ redef record connection += { sip_state: State &optional; }; -const ports = { 5060/udp }; -redef likely_server_ports += { ports }; - event bro_init() &priority=5 { Log::create_stream(SIP::LOG, [$columns=Info, $ev=log_sip]); - Analyzer::register_for_ports(Analyzer::ANALYZER_SIP, ports); } function new_sip_session(c: connection): Info @@ -105,7 +101,7 @@ function new_sip_session(c: connection): Info tmp$trans_depth = c$sip_state$current_request; tmp$path = vector(); - + return tmp; } @@ -209,8 +205,6 @@ event connection_state_remove(c: connection) &priority=-5 { for ( r in c$sip_state$pending ) { - # We don't use pending elements at index 0. - if ( r == 0 ) next; Log::write(SIP::LOG, c$sip_state$pending[r]); } } diff --git a/src/analyzer/protocol/sip/CMakeLists.txt b/src/analyzer/protocol/sip/CMakeLists.txt index d571218b31..58605b1cb8 100644 --- a/src/analyzer/protocol/sip/CMakeLists.txt +++ b/src/analyzer/protocol/sip/CMakeLists.txt @@ -8,3 +8,8 @@ bro_plugin_cc(SIP.cc Plugin.cc) bro_plugin_bif(events.bif) bro_plugin_pac(sip.pac sip-analyzer.pac sip-protocol.pac) bro_plugin_end() + +bro_plugin_begin(Bro SIP_TCP) +bro_plugin_cc(SIP_TCP.cc Plugin_TCP.cc) +bro_plugin_pac(sip_TCP.pac sip-protocol.pac sip-analyzer.pac) +bro_plugin_end() \ No newline at end of file diff --git a/src/analyzer/protocol/sip/Plugin_TCP.cc b/src/analyzer/protocol/sip/Plugin_TCP.cc new file mode 100644 index 0000000000..9ebb473674 --- /dev/null +++ b/src/analyzer/protocol/sip/Plugin_TCP.cc @@ -0,0 +1,20 @@ +//See the file in the main distribution directory for copyright. + +#include "plugin/Plugin.h" +#include "SIP_TCP.h" + +namespace plugin { + namespace Bro_SIP_TCP { + class Plugin : public plugin::Plugin { + public: + plugin::Configuration Configure() + { + AddComponent(new ::analyzer::Component("SIP_TCP", ::analyzer::sip_tcp::SIP_Analyzer::Instantiate)); + plugin::Configuration config; + config.name = "Bro::SIP_TCP"; + config.description = "SIP analyzer (TCP)"; + return config; + } + } plugin; + } +} diff --git a/src/analyzer/protocol/sip/SIP.cc b/src/analyzer/protocol/sip/SIP.cc index 33bb357574..dabddc44ac 100644 --- a/src/analyzer/protocol/sip/SIP.cc +++ b/src/analyzer/protocol/sip/SIP.cc @@ -25,7 +25,11 @@ void SIP_Analyzer::DeliverPacket(int len, const u_char* data, bool orig, { bool real_orig = true; if ( len > 6 && data[0] == 'S' && data[1] == 'I' && data[2] == 'P' && data[3] == '/' ) - real_orig = false; + real_orig = false; + + // Sometimes we see some packets with just '\r\n' - ignore those + if ( len == 2 && data[0] == '\r') + return; Analyzer::DeliverPacket(len, data, real_orig, seq, ip, caplen); diff --git a/src/analyzer/protocol/sip/SIP_TCP.cc b/src/analyzer/protocol/sip/SIP_TCP.cc new file mode 100644 index 0000000000..fa7b2a7a0b --- /dev/null +++ b/src/analyzer/protocol/sip/SIP_TCP.cc @@ -0,0 +1,65 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#include "SIP_TCP.h" +#include "analyzer/protocol/tcp/TCP_Reassembler.h" +#include "events.bif.h" + +using namespace analyzer::sip_tcp; + +SIP_Analyzer::SIP_Analyzer(Connection* conn) + : tcp::TCP_ApplicationAnalyzer("SIP_TCP", conn) +{ + interp = new binpac::SIP_TCP::SIP_Conn(this); + had_gap = false; +} + +SIP_Analyzer::~SIP_Analyzer() +{ + delete interp; +} + +void SIP_Analyzer::Done() +{ + tcp::TCP_ApplicationAnalyzer::Done(); + + interp->FlowEOF(true); + interp->FlowEOF(false); +} + +void SIP_Analyzer::EndpointEOF(bool is_orig) +{ + tcp::TCP_ApplicationAnalyzer::EndpointEOF(is_orig); + interp->FlowEOF(is_orig); +} + +void SIP_Analyzer::DeliverStream(int len, const u_char* data, bool orig) +{ + tcp::TCP_ApplicationAnalyzer::DeliverStream(len, data, orig); + + assert(TCP()); + if ( TCP()->IsPartial() ) + return; + + if ( had_gap ) + // If only one side had a content gap, we could still try to + // deliver data to the other side if the script layer can + // handle this. + return; + + try + { + interp->NewData(orig, data, data + len); + } + catch ( const binpac::Exception& e ) + { + printf("BinPAC Exception: %s\n", e.c_msg()); + ProtocolViolation(e.c_msg()); + } +} + +void SIP_Analyzer::Undelivered(uint64 seq, int len, bool orig) +{ + tcp::TCP_ApplicationAnalyzer::Undelivered(seq, len, orig); + had_gap = true; + interp->NewGap(orig, len); +} diff --git a/src/analyzer/protocol/sip/SIP_TCP.h b/src/analyzer/protocol/sip/SIP_TCP.h new file mode 100644 index 0000000000..0dbae376d9 --- /dev/null +++ b/src/analyzer/protocol/sip/SIP_TCP.h @@ -0,0 +1,37 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#ifndef ANALYZER_PROTOCOL_SIP_SIP_TCP_H +#define ANALYZER_PROTOCOL_SIP_SIP_TCP_H + +#include "analyzer/protocol/tcp/TCP.h" + +#include "sip_TCP_pac.h" + +namespace analyzer { namespace sip_tcp { + + class SIP_Analyzer : public tcp::TCP_ApplicationAnalyzer { + + public: + + SIP_Analyzer(Connection* conn); + virtual ~SIP_Analyzer(); + + virtual void Done(); + virtual void DeliverStream(int len, const u_char* data, bool orig); + virtual void Undelivered(uint64 seq, int len, bool orig); + + // Overriden from tcp::TCP_ApplicationAnalyzer. + virtual void EndpointEOF(bool is_orig); + + static analyzer::Analyzer* Instantiate(Connection* conn) + { return new SIP_Analyzer(conn); } + + protected: + + binpac::SIP_TCP::SIP_Conn* interp; + bool had_gap; + }; + + } } // namespace analyzer::* + +#endif diff --git a/src/analyzer/protocol/sip/sip-analyzer.pac b/src/analyzer/protocol/sip/sip-analyzer.pac index 0a54c87115..6cc5793b73 100644 --- a/src/analyzer/protocol/sip/sip-analyzer.pac +++ b/src/analyzer/protocol/sip/sip-analyzer.pac @@ -18,6 +18,7 @@ refine flow SIP_Flow += { function proc_sip_request(method: bytestring, uri: bytestring, vers: SIP_Version): bool %{ + connection()->bro_analyzer()->ProtocolConfirmation(); if ( sip_request ) { BifEvent::generate_sip_request(connection()->bro_analyzer(), connection()->bro_analyzer()->Conn(), @@ -32,6 +33,7 @@ refine flow SIP_Flow += { function proc_sip_reply(vers: SIP_Version, code: int, reason: bytestring): bool %{ + connection()->bro_analyzer()->ProtocolConfirmation(); if ( sip_reply ) { BifEvent::generate_sip_reply(connection()->bro_analyzer(), connection()->bro_analyzer()->Conn(), diff --git a/src/analyzer/protocol/sip/sip_TCP.pac b/src/analyzer/protocol/sip/sip_TCP.pac new file mode 100644 index 0000000000..b8a0556862 --- /dev/null +++ b/src/analyzer/protocol/sip/sip_TCP.pac @@ -0,0 +1,27 @@ +# BinPAC file for SIP over TCP +# Based heavily on the HTTP BinPAC analyzer + +%include binpac.pac +%include bro.pac + +%extern{ +#include "events.bif.h" +%} + +analyzer SIP_TCP withcontext { + connection: SIP_Conn; + flow: SIP_Flow; +}; + +connection SIP_Conn(bro_analyzer: BroAnalyzer) { + upflow = SIP_Flow(true); + downflow = SIP_Flow(false); +}; + +%include sip-protocol.pac + +flow SIP_Flow(is_orig: bool) { + datagram = SIP_PDU(is_orig) withcontext(connection, this); +}; + +%include sip-analyzer.pac