diff --git a/scripts/base/packet-protocols/teredo/main.zeek b/scripts/base/packet-protocols/teredo/main.zeek index 5bba5c9243..8972a3f803 100644 --- a/scripts/base/packet-protocols/teredo/main.zeek +++ b/scripts/base/packet-protocols/teredo/main.zeek @@ -3,11 +3,15 @@ module PacketAnalyzer::TEREDO; # This needs to be loaded here so the functions are available. Function BIFs normally aren't # loaded until after the packet analysis init scripts are run, and then zeek complains it # can't find the function. +@load base/bif/plugins/Zeek_Teredo.events.bif.zeek @load base/bif/plugins/Zeek_Teredo.functions.bif # Needed for port registration for BPF @load base/frameworks/analyzer/main +# Needed to register Conn::RemovalHook +@load base/protocols/conn/removal-hooks + export { ## Default analyzer const default_analyzer: PacketAnalyzer::Tag = PacketAnalyzer::ANALYZER_IP &redef; @@ -22,7 +26,14 @@ event zeek_init() &priority=20 PacketAnalyzer::register_for_ports(PacketAnalyzer::ANALYZER_UDP, PacketAnalyzer::ANALYZER_TEREDO, teredo_ports); } -event connection_state_remove(c: connection) +# The analyzer keeps state about each Teredo connection in the +# orig_resp_map. Register cleanup. +hook finalize_teredo(c: connection) { remove_teredo_connection(c$id); } + +event new_teredo_state(c: connection) + { + Conn::register_removal_hook(c, finalize_teredo); + } diff --git a/src/packet_analysis/protocol/teredo/Teredo.cc b/src/packet_analysis/protocol/teredo/Teredo.cc index 0dc34f47ef..ea4b551ab2 100644 --- a/src/packet_analysis/protocol/teredo/Teredo.cc +++ b/src/packet_analysis/protocol/teredo/Teredo.cc @@ -154,11 +154,6 @@ bool TeredoAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* pack } auto* conn = static_cast(packet->session); - zeek::detail::ConnKey conn_key = conn->Key(); - - OrigRespMap::iterator or_it = orig_resp_map.find(conn_key); - if ( or_it == orig_resp_map.end() ) - or_it = orig_resp_map.insert(or_it, {conn_key, {}}); detail::TeredoEncapsulation te(this, conn); if ( ! te.Parse(data, len) ) { @@ -188,6 +183,19 @@ bool TeredoAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* pack return false; } + zeek::detail::ConnKey conn_key = conn->Key(); + OrigRespMap::iterator or_it = orig_resp_map.find(conn_key); + + // The first time a teredo packet is parsed successfully, insert + // state into orig_resp_map so we can confirm when both sides + // see valid Teredo packets. Further, raise an event so that script + // layer can install a connection removal hooks to cleanup later. + if ( or_it == orig_resp_map.end() ) { + or_it = orig_resp_map.insert(or_it, {conn_key, {}}); + + packet->session->EnqueueEvent(new_teredo_state, nullptr, packet->session->GetVal()); + } + if ( packet->is_orig ) or_it->second.valid_orig = true; else diff --git a/src/packet_analysis/protocol/teredo/events.bif b/src/packet_analysis/protocol/teredo/events.bif index 080eb1bf6e..5927606a87 100644 --- a/src/packet_analysis/protocol/teredo/events.bif +++ b/src/packet_analysis/protocol/teredo/events.bif @@ -1,3 +1,5 @@ +module GLOBAL; + ## Generated for any IPv6 packet encapsulated in a Teredo tunnel. ## See :rfc:`4380` for more information about the Teredo protocol. ## @@ -11,6 +13,14 @@ ## it may become particularly expensive for real-time analysis. event teredo_packet%(outer: connection, inner: teredo_hdr%); +## Generated when per connection Teredo state is created. +## +## This is primarily useful to install a connection removal hook to clear +## internal per-connection Teredo state. +## +## c: The Teredo tunnel connection. +event new_teredo_state%(c: connection%); + ## Generated for IPv6 packets encapsulated in a Teredo tunnel that ## use the Teredo authentication encapsulation method. ## See :rfc:`4380` for more information about the Teredo protocol.