Add Teredo analysis option to reduce false positive decapsulation.

The Tunnel::yielding_teredo_decapsulation (on by default) makes it so
the Teredo analyzer doesn't attempt to decapsulate payloads when
there's already a sibling analyzer that thinks it's parsing the right
protocol.  Sometimes, UDP payloads just happen to look like they are
validly Teredo-encapsulated and doing further analysis on the
decapsulated packet can quickly turn into a weird; this change helps
reduce such weirds.
This commit is contained in:
Jon Siwek 2012-06-07 12:12:57 -05:00
parent 9ddb70b109
commit 6f346c8406
7 changed files with 92 additions and 2 deletions

View file

@ -2705,6 +2705,14 @@ export {
## Toggle whether to do IPv6-in-Teredo decapsulation. ## Toggle whether to do IPv6-in-Teredo decapsulation.
const enable_teredo = T &redef; const enable_teredo = T &redef;
## With this option set, the Teredo analysis will first check to see if
## other protocol analyzers have confirmed that they think they're
## parsing the right protocol and only continue with Teredo tunnel
## decapsulation if nothing else has yet confirmed. This can help
## reduce false positives of UDP traffic (e.g. DNS) that also happens
## to have a valid Teredo encapsulation.
const yielding_teredo_decapsulation = T &redef;
} # end export } # end export
module GLOBAL; module GLOBAL;

View file

@ -343,6 +343,10 @@ private:
for ( analyzer_list::iterator var = the_kids.begin(); \ for ( analyzer_list::iterator var = the_kids.begin(); \
var != the_kids.end(); var++ ) var != the_kids.end(); var++ )
#define LOOP_OVER_GIVEN_CONST_CHILDREN(var, the_kids) \
for ( analyzer_list::const_iterator var = the_kids.begin(); \
var != the_kids.end(); var++ )
class SupportAnalyzer : public Analyzer { class SupportAnalyzer : public Analyzer {
public: public:
SupportAnalyzer(AnalyzerTag::Tag tag, Connection* conn, bool arg_orig) SupportAnalyzer(AnalyzerTag::Tag tag, Connection* conn, bool arg_orig)

View file

@ -158,13 +158,37 @@ void Teredo_Analyzer::DeliverPacket(int len, const u_char* data, bool orig,
int rslt = sessions->ParseIPPacket(len, te.InnerIP(), IPPROTO_IPV6, inner); int rslt = sessions->ParseIPPacket(len, te.InnerIP(), IPPROTO_IPV6, inner);
if ( rslt == 0 ) if ( rslt == 0 )
ProtocolConfirmation(); {
if ( BifConst::Tunnel::yielding_teredo_decapsulation &&
! ProtocolConfirmed() )
{
// Only confirm the Teredo tunnel and start decapsulating packets
// when no other sibling analyzer thinks it's already parsing the
// right protocol.
bool sibling_has_confirmed = false;
if ( Parent() )
{
LOOP_OVER_GIVEN_CONST_CHILDREN(i, Parent()->GetChildren())
{
if ( (*i)->ProtocolConfirmed() )
sibling_has_confirmed = true;
}
}
if ( ! sibling_has_confirmed )
ProtocolConfirmation();
}
else
{
// Aggressively decapsulate anything with valid Teredo encapsulation
ProtocolConfirmation();
}
}
else if ( rslt < 0 ) else if ( rslt < 0 )
ProtocolViolation("Truncated Teredo", (const char*) data, len); ProtocolViolation("Truncated Teredo", (const char*) data, len);
else else
ProtocolViolation("Teredo payload length", (const char*) data, len); ProtocolViolation("Teredo payload length", (const char*) data, len);
if ( rslt != 0 ) return; if ( rslt != 0 || ! ProtocolConfirmed() ) return;
Val* teredo_hdr = 0; Val* teredo_hdr = 0;

View file

@ -15,5 +15,6 @@ const Tunnel::max_depth: count;
const Tunnel::enable_ip: bool; const Tunnel::enable_ip: bool;
const Tunnel::enable_ayiya: bool; const Tunnel::enable_ayiya: bool;
const Tunnel::enable_teredo: bool; const Tunnel::enable_teredo: bool;
const Tunnel::yielding_teredo_decapsulation: bool;
const Threading::heartbeat_interval: interval; const Threading::heartbeat_interval: interval;

View file

@ -0,0 +1,19 @@
#separator \x09
#set_separator ,
#empty_field (empty)
#unset_field -
#path weird
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p name addl notice peer
#types time string addr port addr port string string bool string
1258567191.405770 - - - - - truncated_header - F bro
1258567191.486869 UWkUyAuUGXf 192.168.1.105 57696 192.168.1.1 53 Teredo_payload_len_mismatch - F bro
1258578181.260420 - - - - - truncated_header - F bro
1258578181.516140 nQcgTWjvg4c 192.168.1.104 64838 192.168.1.1 53 Teredo_payload_len_mismatch - F bro
1258579063.557927 - - - - - truncated_header - F bro
1258579063.784919 j4u32Pc5bif 192.168.1.104 55778 192.168.1.1 53 Teredo_payload_len_mismatch - F bro
1258581768.568451 - - - - - truncated_header - F bro
1258581768.898165 TEfuqmmG4bh 192.168.1.104 50798 192.168.1.1 53 Teredo_payload_len_mismatch - F bro
1258584478.859853 - - - - - truncated_header - F bro
1258584478.989528 FrJExwHcSal 192.168.1.104 64963 192.168.1.1 53 Teredo_payload_len_mismatch - F bro
1258600683.934458 - - - - - truncated_header - F bro
1258600683.934672 5OKnoww6xl4 192.168.1.103 59838 192.168.1.1 53 Teredo_payload_len_mismatch - F bro

Binary file not shown.

View file

@ -0,0 +1,34 @@
# @TEST-EXEC: bro -r $TRACES/tunnels/false-teredo.pcap %INPUT >output
# @TEST-EXEC: test ! -e weird.log
# @TEST-EXEC: bro -r $TRACES/tunnels/false-teredo.pcap %INPUT Tunnel::yielding_teredo_decapsulation=F >output
# @TEST-EXEC: btest-diff weird.log
function print_teredo(name: string, outer: connection, inner: teredo_hdr)
{
print fmt("%s: %s", name, outer$id);
print fmt(" ip6: %s", inner$hdr$ip6);
if ( inner?$auth )
print fmt(" auth: %s", inner$auth);
if ( inner?$origin )
print fmt(" origin: %s", inner$origin);
}
event teredo_packet(outer: connection, inner: teredo_hdr)
{
print_teredo("packet", outer, inner);
}
event teredo_authentication(outer: connection, inner: teredo_hdr)
{
print_teredo("auth", outer, inner);
}
event teredo_origin_indication(outer: connection, inner: teredo_hdr)
{
print_teredo("origin", outer, inner);
}
event teredo_bubble(outer: connection, inner: teredo_hdr)
{
print_teredo("bubble", outer, inner);
}