Fixing removal of support analyzers, plus some tweaking and cleanup of

CONNECT code.

Removal of support analyzers was broken. The code now actually doesn't
delete them immediately anymore but instead just flags them as
disabled. They'll be destroyed with the parent analyzer later.

Also includes a new leak tests exercising the CONNECT code.

Lines starting # with '#' will be ignored, and an empty message aborts
the commit. # On branch topic/robin/http-connect # Changes to be
committed: # modified: scripts/base/protocols/http/main.bro #
modified: scripts/base/protocols/ssl/consts.bro # modified:
src/analyzer/Analyzer.cc # modified: src/analyzer/Analyzer.h #
modified: src/analyzer/protocol/http/HTTP.cc # new file:
testing/btest/core/leaks/http-connect.bro # modified:
testing/btest/scripts/base/protocols/http/http-connect.bro # #
Untracked files: # .tags # changes.txt # conn.log # debug.log # diff #
mpls-in-vlan.patch # newfile.pcap # packet_filter.log # reporter.log #
src/PktSrc.cc.orig # weird.log #
This commit is contained in:
Robin Sommer 2014-03-02 13:52:32 -08:00
parent dd0856a57f
commit 338d521003
7 changed files with 128 additions and 65 deletions

View file

@ -86,6 +86,7 @@ export {
[13172] = "next_protocol_negotiation", [13172] = "next_protocol_negotiation",
[13175] = "origin_bound_certificates", [13175] = "origin_bound_certificates",
[13180] = "encrypted_client_certificates", [13180] = "encrypted_client_certificates",
[30031] = "channel_id",
[65281] = "renegotiation_info" [65281] = "renegotiation_info"
} &default=function(i: count):string { return fmt("unknown-%d", i); }; } &default=function(i: count):string { return fmt("unknown-%d", i); };

View file

@ -209,11 +209,11 @@ void Analyzer::NextPacket(int len, const u_char* data, bool is_orig, int seq,
if ( skip ) if ( skip )
return; return;
// If we have support analyzers, we pass it to them. SupportAnalyzer* next_sibling = FirstSupportAnalyzer(is_orig);
if ( is_orig && orig_supporters )
orig_supporters->NextPacket(len, data, is_orig, seq, ip, caplen); if ( next_sibling )
else if ( ! is_orig && resp_supporters ) next_sibling->NextPacket(len, data, is_orig, seq, ip, caplen);
resp_supporters->NextPacket(len, data, is_orig, seq, ip, caplen);
else else
{ {
try try
@ -232,11 +232,11 @@ void Analyzer::NextStream(int len, const u_char* data, bool is_orig)
if ( skip ) if ( skip )
return; return;
// If we have support analyzers, we pass it to them. SupportAnalyzer* next_sibling = FirstSupportAnalyzer(is_orig);
if ( is_orig && orig_supporters )
orig_supporters->NextStream(len, data, is_orig); if ( next_sibling )
else if ( ! is_orig && resp_supporters ) next_sibling->NextStream(len, data, is_orig);
resp_supporters->NextStream(len, data, is_orig);
else else
{ {
try try
@ -255,11 +255,11 @@ void Analyzer::NextUndelivered(int seq, int len, bool is_orig)
if ( skip ) if ( skip )
return; return;
// If we have support analyzers, we pass it to them. SupportAnalyzer* next_sibling = FirstSupportAnalyzer(is_orig);
if ( is_orig && orig_supporters )
orig_supporters->NextUndelivered(seq, len, is_orig); if ( next_sibling )
else if ( ! is_orig && resp_supporters ) next_sibling->NextUndelivered(seq, len, is_orig);
resp_supporters->NextUndelivered(seq, len, is_orig);
else else
{ {
try try
@ -278,11 +278,10 @@ void Analyzer::NextEndOfData(bool is_orig)
if ( skip ) if ( skip )
return; return;
// If we have support analyzers, we pass it to them. SupportAnalyzer* next_sibling = FirstSupportAnalyzer(is_orig);
if ( is_orig && orig_supporters )
orig_supporters->NextEndOfData(is_orig); if ( next_sibling )
else if ( ! is_orig && resp_supporters ) next_sibling->NextEndOfData(is_orig);
resp_supporters->NextEndOfData(is_orig);
else else
EndOfData(is_orig); EndOfData(is_orig);
} }
@ -558,31 +557,17 @@ void Analyzer::AddSupportAnalyzer(SupportAnalyzer* analyzer)
void Analyzer::RemoveSupportAnalyzer(SupportAnalyzer* analyzer) void Analyzer::RemoveSupportAnalyzer(SupportAnalyzer* analyzer)
{ {
SupportAnalyzer** head = DBG_LOG(DBG_ANALYZER, "%s disabled %s support analyzer %s",
analyzer->IsOrig() ? &orig_supporters : &resp_supporters;
SupportAnalyzer* prev = 0;
SupportAnalyzer* s;
for ( s = *head; s && s != analyzer; prev = s, s = s->sibling )
;
if ( ! s )
return;
if ( prev )
prev->sibling = s->sibling;
else
*head = s->sibling;
DBG_LOG(DBG_ANALYZER, "%s removed support %s",
fmt_analyzer(this).c_str(), fmt_analyzer(this).c_str(),
analyzer->IsOrig() ? "originator" : "responder", analyzer->IsOrig() ? "originator" : "responder",
fmt_analyzer(analyzer).c_str()); fmt_analyzer(analyzer).c_str());
if ( ! analyzer->finished ) // We mark the analyzer as being removed here, which will prevent it
analyzer->Done(); // from being used further. However, we don't actually delete it
// before the parent gets destroyed. While we woulc do that, it's a
delete analyzer; // bit tricky to do at the right time and it doesn't seem worth the
// trouble.
analyzer->removing = true;
return; return;
} }
@ -596,6 +581,19 @@ bool Analyzer::HasSupportAnalyzer(Tag tag, bool orig)
return false; return false;
} }
SupportAnalyzer* Analyzer::FirstSupportAnalyzer(bool orig)
{
SupportAnalyzer* sa = orig ? orig_supporters : resp_supporters;
if ( ! sa )
return 0;
if ( ! sa->Removing() )
return sa;
return sa->Sibling(true);
}
void Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig, void Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig,
int seq, const IP_Hdr* ip, int caplen) int seq, const IP_Hdr* ip, int caplen)
{ {
@ -782,16 +780,32 @@ void Analyzer::Weird(const char* name, const char* addl)
conn->Weird(name, addl); conn->Weird(name, addl);
} }
SupportAnalyzer* SupportAnalyzer::Sibling(bool only_active) const
{
if ( ! only_active )
return sibling;
SupportAnalyzer* next = sibling;
while ( next && next->Removing() )
next = next->sibling;
return next;
}
void SupportAnalyzer::ForwardPacket(int len, const u_char* data, bool is_orig, void SupportAnalyzer::ForwardPacket(int len, const u_char* data, bool is_orig,
int seq, const IP_Hdr* ip, int caplen) int seq, const IP_Hdr* ip, int caplen)
{ {
// We do not call parent's method, as we're replacing the functionality. // We do not call parent's method, as we're replacing the functionality.
if ( GetOutputHandler() ) if ( GetOutputHandler() )
GetOutputHandler()->DeliverPacket(len, data, is_orig, seq, GetOutputHandler()->DeliverPacket(len, data, is_orig, seq,
ip, caplen); ip, caplen);
else if ( sibling )
SupportAnalyzer* next_sibling = Sibling(true);
if ( next_sibling )
// Pass to next in chain. // Pass to next in chain.
sibling->NextPacket(len, data, is_orig, seq, ip, caplen); next_sibling->NextPacket(len, data, is_orig, seq, ip, caplen);
else else
// Finished with preprocessing - now it's the parent's turn. // Finished with preprocessing - now it's the parent's turn.
Parent()->DeliverPacket(len, data, is_orig, seq, ip, caplen); Parent()->DeliverPacket(len, data, is_orig, seq, ip, caplen);
@ -800,12 +814,15 @@ void SupportAnalyzer::ForwardPacket(int len, const u_char* data, bool is_orig,
void SupportAnalyzer::ForwardStream(int len, const u_char* data, bool is_orig) void SupportAnalyzer::ForwardStream(int len, const u_char* data, bool is_orig)
{ {
// We do not call parent's method, as we're replacing the functionality. // We do not call parent's method, as we're replacing the functionality.
if ( GetOutputHandler() ) if ( GetOutputHandler() )
GetOutputHandler()->DeliverStream(len, data, is_orig); GetOutputHandler()->DeliverStream(len, data, is_orig);
else if ( sibling ) SupportAnalyzer* next_sibling = Sibling(true);
if ( next_sibling )
// Pass to next in chain. // Pass to next in chain.
sibling->NextStream(len, data, is_orig); next_sibling->NextStream(len, data, is_orig);
else else
// Finished with preprocessing - now it's the parent's turn. // Finished with preprocessing - now it's the parent's turn.
Parent()->DeliverStream(len, data, is_orig); Parent()->DeliverStream(len, data, is_orig);
@ -814,12 +831,15 @@ void SupportAnalyzer::ForwardStream(int len, const u_char* data, bool is_orig)
void SupportAnalyzer::ForwardUndelivered(int seq, int len, bool is_orig) void SupportAnalyzer::ForwardUndelivered(int seq, int len, bool is_orig)
{ {
// We do not call parent's method, as we're replacing the functionality. // We do not call parent's method, as we're replacing the functionality.
if ( GetOutputHandler() ) if ( GetOutputHandler() )
GetOutputHandler()->Undelivered(seq, len, is_orig); GetOutputHandler()->Undelivered(seq, len, is_orig);
else if ( sibling ) SupportAnalyzer* next_sibling = Sibling(true);
if ( next_sibling )
// Pass to next in chain. // Pass to next in chain.
sibling->NextUndelivered(seq, len, is_orig); next_sibling->NextUndelivered(seq, len, is_orig);
else else
// Finished with preprocessing - now it's the parent's turn. // Finished with preprocessing - now it's the parent's turn.
Parent()->Undelivered(seq, len, is_orig); Parent()->Undelivered(seq, len, is_orig);

View file

@ -587,7 +587,7 @@ protected:
void RemoveTimer(Timer* t); void RemoveTimer(Timer* t);
/** /**
* Returnsn true if the analyzer has associated an SupportAnalyzer of a given type. * Returns true if the analyzer has associated an SupportAnalyzer of a given type.
* *
* @param tag The type to check for. * @param tag The type to check for.
* *
@ -595,6 +595,14 @@ protected:
*/ */
bool HasSupportAnalyzer(Tag tag, bool orig); bool HasSupportAnalyzer(Tag tag, bool orig);
/**
* Returns the first still active support analyzer for the given
* direction, or null if none.
*
* @param orig True if asking about the originator side.
*/
SupportAnalyzer* FirstSupportAnalyzer(bool orig);
/** /**
* Adds a a new child analyzer with the option whether to intialize * Adds a a new child analyzer with the option whether to intialize
* it. This is an internal method. * it. This is an internal method.
@ -616,6 +624,12 @@ protected:
*/ */
void AppendNewChildren(); void AppendNewChildren();
/**
* Returns true if the analyzer has been flagged for removal and
* shouldn't be used otherwise anymore.
*/
bool Removing() const { return removing; }
private: private:
// Internal method to eventually delete a child analyzer that's // Internal method to eventually delete a child analyzer that's
// already Done(). // already Done().
@ -718,6 +732,14 @@ public:
*/ */
bool IsOrig() const { return orig; } bool IsOrig() const { return orig; }
/**
* Returns the analyzer's next sibling, or null if none.
*
* only_active: If true, this will skip siblings that are still link
* but flagged for removal.
*/
SupportAnalyzer* Sibling(bool only_active = false) const;
/** /**
* Passes packet input to the next sibling SupportAnalyzer if any, or * Passes packet input to the next sibling SupportAnalyzer if any, or
* on to the associated main analyzer if none. If however there's an * on to the associated main analyzer if none. If however there's an
@ -749,11 +771,6 @@ public:
*/ */
virtual void ForwardUndelivered(int seq, int len, bool orig); virtual void ForwardUndelivered(int seq, int len, bool orig);
/**
* Returns the analyzer next sibling, or null if none.
*/
SupportAnalyzer* Sibling() const { return sibling; }
protected: protected:
friend class Analyzer; friend class Analyzer;

View file

@ -1066,14 +1066,10 @@ void HTTP_Analyzer::DeliverStream(int len, const u_char* data, bool is_orig)
HTTP_Reply(); HTTP_Reply();
InitHTTPMessage(content_line,
reply_message, is_orig,
ExpectReplyMessageBody(),
len);
if ( connect_request && reply_code == 200 ) if ( connect_request && reply_code == 200 )
{ {
pia = new pia::PIA_TCP(Conn()); pia = new pia::PIA_TCP(Conn());
if ( AddChildAnalyzer(pia) ) if ( AddChildAnalyzer(pia) )
{ {
pia->FirstPacket(true, 0); pia->FirstPacket(true, 0);
@ -1084,13 +1080,22 @@ void HTTP_Analyzer::DeliverStream(int len, const u_char* data, bool is_orig)
// need to be removed. // need to be removed.
RemoveSupportAnalyzer(content_line_orig); RemoveSupportAnalyzer(content_line_orig);
RemoveSupportAnalyzer(content_line_resp); RemoveSupportAnalyzer(content_line_resp);
return;
} }
else else
{ {
// Shouldn't really happen.
delete pia;
pia = 0; pia = 0;
} }
} }
InitHTTPMessage(content_line,
reply_message, is_orig,
ExpectReplyMessageBody(),
len);
} }
else else
{ {
@ -1422,6 +1427,12 @@ void HTTP_Analyzer::HTTP_Request()
{ {
ProtocolConfirmation(); ProtocolConfirmation();
const char* method = (const char*) request_method->AsString()->Bytes();
int method_len = request_method->AsString()->Len();
if ( strcasecmp_n(method_len, method, "CONNECT") == 0 )
connect_request = true;
if ( http_request ) if ( http_request )
{ {
val_list* vl = new val_list; val_list* vl = new val_list;
@ -1436,9 +1447,6 @@ void HTTP_Analyzer::HTTP_Request()
// DEBUG_MSG("%.6f http_request\n", network_time); // DEBUG_MSG("%.6f http_request\n", network_time);
ConnectionEvent(http_request, vl); ConnectionEvent(http_request, vl);
} }
if ( strcasecmp_n(request_method->AsString()->Len(), (const char*) (request_method->AsString()->Bytes()), "CONNECT") == 0 )
connect_request = true;
} }
void HTTP_Analyzer::HTTP_Reply() void HTTP_Analyzer::HTTP_Reply()

View file

@ -0,0 +1,14 @@
# Needs perftools support.
#
# @TEST-GROUP: leaks
#
# @TEST-REQUIRES: bro --help 2>&1 | grep -q mem-leaks
#
# @TEST-EXEC: HEAP_CHECK_DUMP_DIRECTORY=. HEAPCHECK=local btest-bg-run bro bro -b -m -r $TRACES/http/connect-with-smtp.trace %INPUT
# @TEST-EXEC: btest-bg-wait 15
@load base/protocols/conn
@load base/protocols/http
@load base/protocols/smtp
@load base/protocols/tunnels
@load base/frameworks/dpd

View file

@ -6,6 +6,9 @@
# @TEST-EXEC: btest-diff smtp.log # @TEST-EXEC: btest-diff smtp.log
# @TEST-EXEC: btest-diff tunnel.log # @TEST-EXEC: btest-diff tunnel.log
# The base analysis scripts are loaded by default. @load base/protocols/conn
#@load base/protocols/http @load base/protocols/http
@load base/protocols/smtp
@load base/protocols/tunnels
@load base/frameworks/dpd