mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
Remove the old session-based tunnel analyzers
This commit is contained in:
parent
2044fbe53b
commit
9135345fa8
31 changed files with 0 additions and 2502 deletions
|
@ -1,4 +1,3 @@
|
||||||
#add_subdirectory(ayiya)
|
|
||||||
add_subdirectory(bittorrent)
|
add_subdirectory(bittorrent)
|
||||||
add_subdirectory(conn-size)
|
add_subdirectory(conn-size)
|
||||||
add_subdirectory(dce-rpc)
|
add_subdirectory(dce-rpc)
|
||||||
|
@ -8,10 +7,8 @@ add_subdirectory(dns)
|
||||||
add_subdirectory(file)
|
add_subdirectory(file)
|
||||||
add_subdirectory(finger)
|
add_subdirectory(finger)
|
||||||
add_subdirectory(ftp)
|
add_subdirectory(ftp)
|
||||||
#add_subdirectory(geneve)
|
|
||||||
add_subdirectory(gnutella)
|
add_subdirectory(gnutella)
|
||||||
add_subdirectory(gssapi)
|
add_subdirectory(gssapi)
|
||||||
#add_subdirectory(gtpv1)
|
|
||||||
add_subdirectory(http)
|
add_subdirectory(http)
|
||||||
add_subdirectory(ident)
|
add_subdirectory(ident)
|
||||||
add_subdirectory(imap)
|
add_subdirectory(imap)
|
||||||
|
@ -41,7 +38,5 @@ add_subdirectory(ssh)
|
||||||
add_subdirectory(ssl)
|
add_subdirectory(ssl)
|
||||||
add_subdirectory(syslog)
|
add_subdirectory(syslog)
|
||||||
add_subdirectory(tcp)
|
add_subdirectory(tcp)
|
||||||
#add_subdirectory(teredo)
|
|
||||||
#add_subdirectory(vxlan)
|
|
||||||
add_subdirectory(xmpp)
|
add_subdirectory(xmpp)
|
||||||
add_subdirectory(zip)
|
add_subdirectory(zip)
|
||||||
|
|
|
@ -1,71 +0,0 @@
|
||||||
// See the file "COPYING" in the main distribution directory for copyright.
|
|
||||||
|
|
||||||
#include "zeek/analyzer/protocol/ayiya/AYIYA.h"
|
|
||||||
|
|
||||||
#include "zeek/Func.h"
|
|
||||||
#include "zeek/packet_analysis/protocol/ip/IP.h"
|
|
||||||
#include "zeek/packet_analysis/protocol/iptunnel/IPTunnel.h"
|
|
||||||
|
|
||||||
namespace zeek::analyzer::ayiya
|
|
||||||
{
|
|
||||||
|
|
||||||
AYIYA_Analyzer::AYIYA_Analyzer(Connection* conn) : Analyzer("AYIYA", conn)
|
|
||||||
{
|
|
||||||
interp = new binpac::AYIYA::AYIYA_Conn(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
AYIYA_Analyzer::~AYIYA_Analyzer()
|
|
||||||
{
|
|
||||||
delete interp;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AYIYA_Analyzer::Done()
|
|
||||||
{
|
|
||||||
Analyzer::Done();
|
|
||||||
Event(udp_session_done);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AYIYA_Analyzer::DeliverPacket(int len, const u_char* data, bool orig, uint64_t seq,
|
|
||||||
const IP_Hdr* ip, int caplen)
|
|
||||||
{
|
|
||||||
Analyzer::DeliverPacket(len, data, orig, seq, ip, caplen);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
interp->NewData(orig, data, data + len);
|
|
||||||
}
|
|
||||||
catch ( const binpac::Exception& e )
|
|
||||||
{
|
|
||||||
AnalyzerViolation(util::fmt("Binpac exception: %s", e.c_msg()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( inner_packet_offset <= 0 )
|
|
||||||
return;
|
|
||||||
|
|
||||||
data += inner_packet_offset;
|
|
||||||
len -= inner_packet_offset;
|
|
||||||
caplen -= inner_packet_offset;
|
|
||||||
inner_packet_offset = -1;
|
|
||||||
|
|
||||||
std::shared_ptr<IP_Hdr> inner;
|
|
||||||
int result = packet_analysis::IP::ParsePacket(len, data, next_header, inner);
|
|
||||||
|
|
||||||
if ( result == 0 )
|
|
||||||
{
|
|
||||||
AnalyzerConfirmation();
|
|
||||||
std:
|
|
||||||
shared_ptr<EncapsulationStack> e = Conn()->GetEncapsulation();
|
|
||||||
EncapsulatingConn ec(Conn(), BifEnum::Tunnel::AYIYA);
|
|
||||||
packet_analysis::IPTunnel::ip_tunnel_analyzer->ProcessEncapsulatedPacket(
|
|
||||||
run_state::network_time, nullptr, inner, e, ec);
|
|
||||||
}
|
|
||||||
else if ( result == -2 )
|
|
||||||
AnalyzerViolation("AYIYA next header internal mismatch",
|
|
||||||
reinterpret_cast<const char*>(data), len);
|
|
||||||
else if ( result < 0 )
|
|
||||||
AnalyzerViolation("Truncated AYIYA", reinterpret_cast<const char*>(data), len);
|
|
||||||
else
|
|
||||||
AnalyzerViolation("AYIYA payload length", reinterpret_cast<const char*>(data), len);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace zeek::analyzer::ayiya
|
|
|
@ -1,37 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "analyzer/protocol/ayiya/ayiya_pac.h"
|
|
||||||
|
|
||||||
namespace binpac::AYIYA
|
|
||||||
{
|
|
||||||
class AYIYA_Conn;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace zeek::analyzer::ayiya
|
|
||||||
{
|
|
||||||
|
|
||||||
class AYIYA_Analyzer final : public analyzer::Analyzer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit AYIYA_Analyzer(Connection* conn);
|
|
||||||
virtual ~AYIYA_Analyzer();
|
|
||||||
|
|
||||||
virtual void Done();
|
|
||||||
virtual void DeliverPacket(int len, const u_char* data, bool orig, uint64_t seq,
|
|
||||||
const IP_Hdr* ip, int caplen);
|
|
||||||
|
|
||||||
static analyzer::Analyzer* Instantiate(Connection* conn) { return new AYIYA_Analyzer(conn); }
|
|
||||||
|
|
||||||
void SetInnerInfo(int offset, uint8_t next)
|
|
||||||
{
|
|
||||||
inner_packet_offset = offset;
|
|
||||||
next_header = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
binpac::AYIYA::AYIYA_Conn* interp;
|
|
||||||
int inner_packet_offset = -1;
|
|
||||||
uint8_t next_header = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace zeek::analyzer::ayiya
|
|
|
@ -1,9 +0,0 @@
|
||||||
|
|
||||||
include(ZeekPlugin)
|
|
||||||
|
|
||||||
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
|
||||||
|
|
||||||
zeek_plugin_begin(Zeek AYIYA)
|
|
||||||
zeek_plugin_cc(AYIYA.cc Plugin.cc)
|
|
||||||
zeek_plugin_pac(ayiya.pac ayiya-protocol.pac ayiya-analyzer.pac)
|
|
||||||
zeek_plugin_end()
|
|
|
@ -1,26 +0,0 @@
|
||||||
// See the file in the main distribution directory for copyright.
|
|
||||||
|
|
||||||
#include "zeek/plugin/Plugin.h"
|
|
||||||
|
|
||||||
#include "zeek/analyzer/Component.h"
|
|
||||||
#include "zeek/analyzer/protocol/ayiya/AYIYA.h"
|
|
||||||
|
|
||||||
namespace zeek::plugin::detail::Zeek_AYIYA
|
|
||||||
{
|
|
||||||
|
|
||||||
class Plugin : public zeek::plugin::Plugin
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
zeek::plugin::Configuration Configure() override
|
|
||||||
{
|
|
||||||
AddComponent(new zeek::analyzer::Component(
|
|
||||||
"AYIYA", zeek::analyzer::ayiya::AYIYA_Analyzer::Instantiate));
|
|
||||||
|
|
||||||
zeek::plugin::Configuration config;
|
|
||||||
config.name = "Zeek::AYIYA";
|
|
||||||
config.description = "AYIYA Analyzer";
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
} plugin;
|
|
||||||
|
|
||||||
} // namespace zeek::plugin::detail::Zeek_AYIYA
|
|
|
@ -1,68 +0,0 @@
|
||||||
%extern{
|
|
||||||
#include "zeek/Conn.h"
|
|
||||||
#include "zeek/analyzer/protocol/ayiya/AYIYA.h"
|
|
||||||
%}
|
|
||||||
|
|
||||||
connection AYIYA_Conn(zeek_analyzer: ZeekAnalyzer)
|
|
||||||
{
|
|
||||||
upflow = AYIYA_Flow;
|
|
||||||
downflow = AYIYA_Flow;
|
|
||||||
};
|
|
||||||
|
|
||||||
flow AYIYA_Flow
|
|
||||||
{
|
|
||||||
datagram = PDU withcontext(connection, this);
|
|
||||||
|
|
||||||
function process_ayiya(pdu: PDU): bool
|
|
||||||
%{
|
|
||||||
zeek::Connection* c = connection()->zeek_analyzer()->Conn();
|
|
||||||
std:shared_ptr<zeek::EncapsulationStack> e = c->GetEncapsulation();
|
|
||||||
|
|
||||||
if ( e && e->Depth() >= zeek::BifConst::Tunnel::max_depth )
|
|
||||||
{
|
|
||||||
connection()->zeek_analyzer()->Weird("tunnel_depth");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ${pdu.op} != 1 )
|
|
||||||
{
|
|
||||||
// 1 is the "forward" command.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ${pdu.next_header} != IPPROTO_IPV6 &&
|
|
||||||
${pdu.next_header} != IPPROTO_IPV4 )
|
|
||||||
{
|
|
||||||
connection()->zeek_analyzer()->Weird("ayiya_tunnel_non_ip");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ${pdu.packet}.length() < (int)sizeof(struct ip) )
|
|
||||||
{
|
|
||||||
connection()->zeek_analyzer()->AnalyzerViolation(
|
|
||||||
"Truncated AYIYA", (const char*) ${pdu.packet}.data(),
|
|
||||||
${pdu.packet}.length());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const struct ip* ip = (const struct ip*) ${pdu.packet}.data();
|
|
||||||
|
|
||||||
if ( ( ${pdu.next_header} == IPPROTO_IPV6 && ip->ip_v != 6 ) ||
|
|
||||||
( ${pdu.next_header} == IPPROTO_IPV4 && ip->ip_v != 4) )
|
|
||||||
{
|
|
||||||
connection()->zeek_analyzer()->AnalyzerViolation(
|
|
||||||
"AYIYA next header mismatch", (const char*)${pdu.packet}.data(),
|
|
||||||
${pdu.packet}.length());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static_cast<zeek::analyzer::ayiya::AYIYA_Analyzer*>(connection()->zeek_analyzer())->SetInnerInfo(${pdu.hdr_len}, ${pdu.next_header});
|
|
||||||
|
|
||||||
return true;
|
|
||||||
%}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
refine typeattr PDU += &let {
|
|
||||||
proc_ayiya = $context.flow.process_ayiya(this);
|
|
||||||
};
|
|
|
@ -1,17 +0,0 @@
|
||||||
|
|
||||||
type PDU = record {
|
|
||||||
identity_byte: uint8;
|
|
||||||
signature_byte: uint8;
|
|
||||||
auth_and_op: uint8;
|
|
||||||
next_header: uint8;
|
|
||||||
epoch: uint32;
|
|
||||||
identity: bytestring &length=identity_len;
|
|
||||||
signature: bytestring &length=signature_len;
|
|
||||||
packet: bytestring &restofdata;
|
|
||||||
} &let {
|
|
||||||
identity_len = (1 << (identity_byte >> 4));
|
|
||||||
signature_len = (signature_byte >> 4) * 4;
|
|
||||||
hdr_len = 8 + identity_len + signature_len;
|
|
||||||
auth = auth_and_op >> 4;
|
|
||||||
op = auth_and_op & 0xF;
|
|
||||||
} &byteorder = littleendian;
|
|
|
@ -1,17 +0,0 @@
|
||||||
|
|
||||||
%include binpac.pac
|
|
||||||
%include zeek.pac
|
|
||||||
|
|
||||||
%extern{
|
|
||||||
#include "zeek/IP.h"
|
|
||||||
#include "zeek/Reporter.h"
|
|
||||||
#include "zeek/TunnelEncapsulation.h"
|
|
||||||
%}
|
|
||||||
|
|
||||||
analyzer AYIYA withcontext {
|
|
||||||
connection: AYIYA_Conn;
|
|
||||||
flow: AYIYA_Flow;
|
|
||||||
};
|
|
||||||
|
|
||||||
%include ayiya-protocol.pac
|
|
||||||
%include ayiya-analyzer.pac
|
|
|
@ -1,8 +0,0 @@
|
||||||
include(ZeekPlugin)
|
|
||||||
|
|
||||||
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
|
||||||
|
|
||||||
zeek_plugin_begin(Zeek Geneve)
|
|
||||||
zeek_plugin_cc(Geneve.cc Plugin.cc)
|
|
||||||
zeek_plugin_bif(events.bif)
|
|
||||||
zeek_plugin_end()
|
|
|
@ -1,95 +0,0 @@
|
||||||
// See the file in the main distribution directory for copyright.
|
|
||||||
|
|
||||||
#include "zeek/analyzer/protocol/geneve/Geneve.h"
|
|
||||||
|
|
||||||
#include "zeek/Conn.h"
|
|
||||||
#include "zeek/IP.h"
|
|
||||||
#include "zeek/RunState.h"
|
|
||||||
#include "zeek/analyzer/protocol/geneve/events.bif.h"
|
|
||||||
#include "zeek/packet_analysis/protocol/iptunnel/IPTunnel.h"
|
|
||||||
|
|
||||||
namespace zeek::analyzer::geneve
|
|
||||||
{
|
|
||||||
|
|
||||||
void Geneve_Analyzer::Done()
|
|
||||||
{
|
|
||||||
Analyzer::Done();
|
|
||||||
Event(udp_session_done);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Geneve_Analyzer::DeliverPacket(int len, const u_char* data, bool orig, uint64_t seq,
|
|
||||||
const IP_Hdr* ip, int caplen)
|
|
||||||
{
|
|
||||||
Analyzer::DeliverPacket(len, data, orig, seq, ip, caplen);
|
|
||||||
|
|
||||||
// Outer Ethernet, IP, and UDP layers already skipped.
|
|
||||||
// Also, generic UDP analyzer already checked/guarantees caplen >= len.
|
|
||||||
|
|
||||||
constexpr auto tunnel_header_len = 8;
|
|
||||||
|
|
||||||
if ( len < tunnel_header_len )
|
|
||||||
{
|
|
||||||
AnalyzerViolation("Geneve header truncation", reinterpret_cast<const char*>(data), len);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto outer = Conn()->GetEncapsulation();
|
|
||||||
|
|
||||||
if ( outer && outer->Depth() >= BifConst::Tunnel::max_depth )
|
|
||||||
{
|
|
||||||
Weird("tunnel_depth");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! outer )
|
|
||||||
outer = std::make_shared<EncapsulationStack>();
|
|
||||||
|
|
||||||
EncapsulatingConn inner(Conn(), BifEnum::Tunnel::GENEVE);
|
|
||||||
outer->Add(inner);
|
|
||||||
int encap_index = outer->Depth();
|
|
||||||
|
|
||||||
uint8_t tunnel_opt_len = (data[0] & 0x3F) * 4;
|
|
||||||
auto vni = (data[4] << 16) + (data[5] << 8) + (data[6] << 0);
|
|
||||||
|
|
||||||
if ( len < tunnel_header_len + tunnel_opt_len )
|
|
||||||
{
|
|
||||||
AnalyzerViolation("Geneve option header truncation", reinterpret_cast<const char*>(data),
|
|
||||||
len);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip over the Geneve headers and create a new packet.
|
|
||||||
data += tunnel_header_len + tunnel_opt_len;
|
|
||||||
caplen -= tunnel_header_len + tunnel_opt_len;
|
|
||||||
len -= tunnel_header_len + tunnel_opt_len;
|
|
||||||
|
|
||||||
pkt_timeval ts;
|
|
||||||
ts.tv_sec = static_cast<time_t>(run_state::current_timestamp);
|
|
||||||
ts.tv_usec = static_cast<suseconds_t>(
|
|
||||||
(run_state::current_timestamp - static_cast<double>(ts.tv_sec)) * 1000000);
|
|
||||||
Packet pkt(DLT_EN10MB, &ts, caplen, len, data);
|
|
||||||
pkt.encap = outer;
|
|
||||||
|
|
||||||
if ( ! packet_mgr->ProcessInnerPacket(&pkt) )
|
|
||||||
{
|
|
||||||
AnalyzerViolation("Geneve invalid inner packet");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This isn't really an error. It's just that the inner packet wasn't an IP packet (like ARP).
|
|
||||||
// Just return without reporting a violation.
|
|
||||||
if ( ! pkt.ip_hdr )
|
|
||||||
return;
|
|
||||||
|
|
||||||
AnalyzerConfirmation();
|
|
||||||
|
|
||||||
if ( geneve_packet )
|
|
||||||
{
|
|
||||||
EncapsulatingConn* ec = pkt.encap->At(encap_index);
|
|
||||||
if ( ec && ec->ip_hdr )
|
|
||||||
Conn()->EnqueueEvent(geneve_packet, nullptr, ConnVal(), pkt.ip_hdr->ToPktHdrVal(),
|
|
||||||
val_mgr->Count(vni));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace zeek::analyzer::geneve
|
|
|
@ -1,23 +0,0 @@
|
||||||
// See the file in the main distribution directory for copyright.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "zeek/analyzer/Analyzer.h"
|
|
||||||
|
|
||||||
namespace zeek::analyzer::geneve
|
|
||||||
{
|
|
||||||
|
|
||||||
class Geneve_Analyzer final : public analyzer::Analyzer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit Geneve_Analyzer(Connection* conn) : Analyzer("Geneve", conn) { }
|
|
||||||
|
|
||||||
void Done() override;
|
|
||||||
|
|
||||||
void DeliverPacket(int len, const u_char* data, bool orig, uint64_t seq, const IP_Hdr* ip,
|
|
||||||
int caplen) override;
|
|
||||||
|
|
||||||
static analyzer::Analyzer* Instantiate(Connection* conn) { return new Geneve_Analyzer(conn); }
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace zeek::analyzer::vxlan
|
|
|
@ -1,26 +0,0 @@
|
||||||
// See the file in the main distribution directory for copyright.
|
|
||||||
|
|
||||||
#include "zeek/plugin/Plugin.h"
|
|
||||||
|
|
||||||
#include "zeek/analyzer/Component.h"
|
|
||||||
#include "zeek/analyzer/protocol/geneve/Geneve.h"
|
|
||||||
|
|
||||||
namespace zeek::plugin::detail::Zeek_Geneve
|
|
||||||
{
|
|
||||||
|
|
||||||
class Plugin : public zeek::plugin::Plugin
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
zeek::plugin::Configuration Configure() override
|
|
||||||
{
|
|
||||||
AddComponent(new zeek::analyzer::Component(
|
|
||||||
"Geneve", zeek::analyzer::geneve::Geneve_Analyzer::Instantiate));
|
|
||||||
|
|
||||||
zeek::plugin::Configuration config;
|
|
||||||
config.name = "Zeek::Geneve";
|
|
||||||
config.description = "Geneve analyzer";
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
} plugin;
|
|
||||||
|
|
||||||
} // namespace zeek::plugin::detail::Zeek_Geneve
|
|
|
@ -1,12 +0,0 @@
|
||||||
## Generated for any packet encapsulated in a Geneve tunnel.
|
|
||||||
## See :rfc:`8926` for more information about the VXLAN protocol.
|
|
||||||
##
|
|
||||||
## outer: The Geneve tunnel connection.
|
|
||||||
##
|
|
||||||
## inner: The Geneve-encapsulated Ethernet packet header and transport header.
|
|
||||||
##
|
|
||||||
## vni: Geneve Network Identifier.
|
|
||||||
##
|
|
||||||
## .. note:: Since this event may be raised on a per-packet basis, handling
|
|
||||||
## it may become particularly expensive for real-time analysis.
|
|
||||||
event geneve_packet%(outer: connection, inner: pkt_hdr, vni: count%);
|
|
|
@ -1,10 +0,0 @@
|
||||||
|
|
||||||
include(ZeekPlugin)
|
|
||||||
|
|
||||||
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
|
||||||
|
|
||||||
zeek_plugin_begin(Zeek GTPv1)
|
|
||||||
zeek_plugin_cc(GTPv1.cc Plugin.cc)
|
|
||||||
zeek_plugin_bif(events.bif)
|
|
||||||
zeek_plugin_pac(gtpv1.pac gtpv1-protocol.pac gtpv1-analyzer.pac)
|
|
||||||
zeek_plugin_end()
|
|
|
@ -1,80 +0,0 @@
|
||||||
// See the file "COPYING" in the main distribution directory for copyright.
|
|
||||||
|
|
||||||
#include "zeek/analyzer/protocol/gtpv1/GTPv1.h"
|
|
||||||
|
|
||||||
#include "zeek/analyzer/protocol/gtpv1/events.bif.h"
|
|
||||||
#include "zeek/packet_analysis/protocol/ip/IP.h"
|
|
||||||
#include "zeek/packet_analysis/protocol/iptunnel/IPTunnel.h"
|
|
||||||
|
|
||||||
namespace zeek::analyzer::gtpv1
|
|
||||||
{
|
|
||||||
|
|
||||||
GTPv1_Analyzer::GTPv1_Analyzer(Connection* conn) : Analyzer("GTPV1", conn)
|
|
||||||
{
|
|
||||||
interp = new binpac::GTPv1::GTPv1_Conn(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
GTPv1_Analyzer::~GTPv1_Analyzer()
|
|
||||||
{
|
|
||||||
delete interp;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GTPv1_Analyzer::Done()
|
|
||||||
{
|
|
||||||
Analyzer::Done();
|
|
||||||
Event(udp_session_done);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GTPv1_Analyzer::DeliverPacket(int len, const u_char* data, bool orig, uint64_t seq,
|
|
||||||
const IP_Hdr* ip, int caplen)
|
|
||||||
{
|
|
||||||
Analyzer::DeliverPacket(len, data, orig, seq, ip, caplen);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
interp->NewData(orig, data, data + len);
|
|
||||||
}
|
|
||||||
catch ( const binpac::Exception& e )
|
|
||||||
{
|
|
||||||
AnalyzerViolation(util::fmt("Binpac exception: %s", e.c_msg()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( inner_packet_offset <= 0 )
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto odata = data;
|
|
||||||
auto olen = len;
|
|
||||||
data += inner_packet_offset;
|
|
||||||
len -= inner_packet_offset;
|
|
||||||
caplen -= inner_packet_offset;
|
|
||||||
inner_packet_offset = -1;
|
|
||||||
|
|
||||||
std::shared_ptr<IP_Hdr> inner = nullptr;
|
|
||||||
int result = packet_analysis::IP::ParsePacket(len, data, next_header, inner);
|
|
||||||
|
|
||||||
if ( result == 0 )
|
|
||||||
{
|
|
||||||
interp->set_valid(orig, true);
|
|
||||||
|
|
||||||
if ( (! BifConst::Tunnel::delay_gtp_confirmation) ||
|
|
||||||
(interp->valid(true) && interp->valid(false)) )
|
|
||||||
AnalyzerConfirmation();
|
|
||||||
|
|
||||||
if ( gtp_hdr_val )
|
|
||||||
BifEvent::enqueue_gtpv1_g_pdu_packet(this, Conn(), std::move(gtp_hdr_val),
|
|
||||||
inner->ToPktHdrVal());
|
|
||||||
|
|
||||||
std::shared_ptr<zeek::EncapsulationStack> e = Conn()->GetEncapsulation();
|
|
||||||
EncapsulatingConn ec(Conn(), BifEnum::Tunnel::GTPv1);
|
|
||||||
zeek::packet_analysis::IPTunnel::ip_tunnel_analyzer->ProcessEncapsulatedPacket(
|
|
||||||
run_state::network_time, nullptr, inner, e, ec);
|
|
||||||
}
|
|
||||||
else if ( result == -2 )
|
|
||||||
AnalyzerViolation("Invalid IP version in wrapped packet",
|
|
||||||
reinterpret_cast<const char*>(odata), olen);
|
|
||||||
else if ( result < 0 )
|
|
||||||
AnalyzerViolation("Truncated GTPv1", reinterpret_cast<const char*>(odata), olen);
|
|
||||||
else
|
|
||||||
AnalyzerViolation("GTPv1 payload length", reinterpret_cast<const char*>(odata), olen);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace zeek::analyzer::gtpv1
|
|
|
@ -1,39 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "analyzer/protocol/gtpv1/gtpv1_pac.h"
|
|
||||||
|
|
||||||
namespace binpac::GTPv1
|
|
||||||
{
|
|
||||||
class GTPv1_Conn;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace zeek::analyzer::gtpv1
|
|
||||||
{
|
|
||||||
|
|
||||||
class GTPv1_Analyzer final : public analyzer::Analyzer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit GTPv1_Analyzer(Connection* conn);
|
|
||||||
virtual ~GTPv1_Analyzer();
|
|
||||||
|
|
||||||
virtual void Done();
|
|
||||||
virtual void DeliverPacket(int len, const u_char* data, bool orig, uint64_t seq,
|
|
||||||
const IP_Hdr* ip, int caplen);
|
|
||||||
|
|
||||||
static analyzer::Analyzer* Instantiate(Connection* conn) { return new GTPv1_Analyzer(conn); }
|
|
||||||
|
|
||||||
void SetInnerInfo(int offset, uint8_t next, RecordValPtr val)
|
|
||||||
{
|
|
||||||
inner_packet_offset = offset;
|
|
||||||
next_header = next;
|
|
||||||
gtp_hdr_val = std::move(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
binpac::GTPv1::GTPv1_Conn* interp;
|
|
||||||
int inner_packet_offset = -1;
|
|
||||||
uint8_t next_header = 0;
|
|
||||||
RecordValPtr gtp_hdr_val;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace zeek::analyzer::gtpv1
|
|
|
@ -1,26 +0,0 @@
|
||||||
// See the file in the main distribution directory for copyright.
|
|
||||||
|
|
||||||
#include "zeek/plugin/Plugin.h"
|
|
||||||
|
|
||||||
#include "zeek/analyzer/Component.h"
|
|
||||||
#include "zeek/analyzer/protocol/gtpv1/GTPv1.h"
|
|
||||||
|
|
||||||
namespace zeek::plugin::detail::Zeek_GTPv1
|
|
||||||
{
|
|
||||||
|
|
||||||
class Plugin : public zeek::plugin::Plugin
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
zeek::plugin::Configuration Configure() override
|
|
||||||
{
|
|
||||||
AddComponent(new zeek::analyzer::Component(
|
|
||||||
"GTPv1", zeek::analyzer::gtpv1::GTPv1_Analyzer::Instantiate));
|
|
||||||
|
|
||||||
zeek::plugin::Configuration config;
|
|
||||||
config.name = "Zeek::GTPv1";
|
|
||||||
config.description = "GTPv1 analyzer";
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
} plugin;
|
|
||||||
|
|
||||||
} // namespace zeek::plugin::detail::Zeek_GTPv1
|
|
|
@ -1,74 +0,0 @@
|
||||||
## Generated for any GTP message with a GTPv1 header.
|
|
||||||
##
|
|
||||||
## c: The connection over which the message is sent.
|
|
||||||
##
|
|
||||||
## hdr: The GTPv1 header.
|
|
||||||
event gtpv1_message%(c: connection, hdr: gtpv1_hdr%);
|
|
||||||
|
|
||||||
## Generated for GTPv1 G-PDU packets. That is, packets with a UDP payload
|
|
||||||
## that includes a GTP header followed by an IPv4 or IPv6 packet.
|
|
||||||
##
|
|
||||||
## outer: The GTP outer tunnel connection.
|
|
||||||
##
|
|
||||||
## inner_gtp: The GTP header.
|
|
||||||
##
|
|
||||||
## inner_ip: The inner IP and transport layer packet headers.
|
|
||||||
##
|
|
||||||
## .. note:: Since this event may be raised on a per-packet basis, handling
|
|
||||||
## it may become particularly expensive for real-time analysis.
|
|
||||||
event gtpv1_g_pdu_packet%(outer: connection, inner_gtp: gtpv1_hdr, inner_ip: pkt_hdr%);
|
|
||||||
|
|
||||||
## Generated for GTPv1-C Create PDP Context Request messages.
|
|
||||||
##
|
|
||||||
## c: The connection over which the message is sent.
|
|
||||||
##
|
|
||||||
## hdr: The GTPv1 header.
|
|
||||||
##
|
|
||||||
## elements: The set of Information Elements comprising the message.
|
|
||||||
event gtpv1_create_pdp_ctx_request%(c: connection, hdr: gtpv1_hdr, elements: gtp_create_pdp_ctx_request_elements%);
|
|
||||||
|
|
||||||
## Generated for GTPv1-C Create PDP Context Response messages.
|
|
||||||
##
|
|
||||||
## c: The connection over which the message is sent.
|
|
||||||
##
|
|
||||||
## hdr: The GTPv1 header.
|
|
||||||
##
|
|
||||||
## elements: The set of Information Elements comprising the message.
|
|
||||||
event gtpv1_create_pdp_ctx_response%(c: connection, hdr: gtpv1_hdr, elements: gtp_create_pdp_ctx_response_elements%);
|
|
||||||
|
|
||||||
## Generated for GTPv1-C Update PDP Context Request messages.
|
|
||||||
##
|
|
||||||
## c: The connection over which the message is sent.
|
|
||||||
##
|
|
||||||
## hdr: The GTPv1 header.
|
|
||||||
##
|
|
||||||
## elements: The set of Information Elements comprising the message.
|
|
||||||
event gtpv1_update_pdp_ctx_request%(c: connection, hdr: gtpv1_hdr, elements: gtp_update_pdp_ctx_request_elements%);
|
|
||||||
|
|
||||||
## Generated for GTPv1-C Update PDP Context Response messages.
|
|
||||||
##
|
|
||||||
## c: The connection over which the message is sent.
|
|
||||||
##
|
|
||||||
## hdr: The GTPv1 header.
|
|
||||||
##
|
|
||||||
## elements: The set of Information Elements comprising the message.
|
|
||||||
event gtpv1_update_pdp_ctx_response%(c: connection, hdr: gtpv1_hdr, elements: gtp_update_pdp_ctx_response_elements%);
|
|
||||||
|
|
||||||
## Generated for GTPv1-C Delete PDP Context Request messages.
|
|
||||||
##
|
|
||||||
## c: The connection over which the message is sent.
|
|
||||||
##
|
|
||||||
## hdr: The GTPv1 header.
|
|
||||||
##
|
|
||||||
## elements: The set of Information Elements comprising the message.
|
|
||||||
event gtpv1_delete_pdp_ctx_request%(c: connection, hdr: gtpv1_hdr, elements: gtp_delete_pdp_ctx_request_elements%);
|
|
||||||
|
|
||||||
## Generated for GTPv1-C Delete PDP Context Response messages.
|
|
||||||
##
|
|
||||||
## c: The connection over which the message is sent.
|
|
||||||
##
|
|
||||||
## hdr: The GTPv1 header.
|
|
||||||
##
|
|
||||||
## elements: The set of Information Elements comprising the message.
|
|
||||||
event gtpv1_delete_pdp_ctx_response%(c: connection, hdr: gtpv1_hdr, elements: gtp_delete_pdp_ctx_response_elements%);
|
|
||||||
|
|
|
@ -1,753 +0,0 @@
|
||||||
%extern{
|
|
||||||
#include "zeek/ZeekString.h"
|
|
||||||
#include "zeek/analyzer/protocol/gtpv1/GTPv1.h"
|
|
||||||
%}
|
|
||||||
|
|
||||||
%code{
|
|
||||||
zeek::RecordValPtr BuildGTPv1Hdr(const GTPv1_Header* pdu)
|
|
||||||
{
|
|
||||||
auto rv = zeek::make_intrusive<zeek::RecordVal>(zeek::BifType::Record::gtpv1_hdr);
|
|
||||||
|
|
||||||
rv->Assign(0, pdu->version());
|
|
||||||
rv->Assign(1, pdu->pt_flag());
|
|
||||||
rv->Assign(2, pdu->rsv());
|
|
||||||
rv->Assign(3, pdu->e_flag());
|
|
||||||
rv->Assign(4, pdu->s_flag());
|
|
||||||
rv->Assign(5, pdu->pn_flag());
|
|
||||||
rv->Assign(6, pdu->msg_type());
|
|
||||||
rv->Assign(7, pdu->length());
|
|
||||||
rv->Assign(8, pdu->teid());
|
|
||||||
|
|
||||||
if ( pdu->has_opt() )
|
|
||||||
{
|
|
||||||
rv->Assign(9, pdu->opt_hdr()->seq());
|
|
||||||
rv->Assign(10, pdu->opt_hdr()->n_pdu());
|
|
||||||
rv->Assign(11, pdu->opt_hdr()->next_type());
|
|
||||||
}
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
static zeek::ValPtr BuildIMSI(const InformationElement* ie)
|
|
||||||
{
|
|
||||||
return zeek::val_mgr->Count(ie->imsi()->value());
|
|
||||||
}
|
|
||||||
|
|
||||||
static zeek::ValPtr BuildRAI(const InformationElement* ie)
|
|
||||||
{
|
|
||||||
auto ev = zeek::make_intrusive<zeek::RecordVal>(zeek::BifType::Record::gtp_rai);
|
|
||||||
ev->Assign(0, ie->rai()->mcc());
|
|
||||||
ev->Assign(1, ie->rai()->mnc());
|
|
||||||
ev->Assign(2, ie->rai()->lac());
|
|
||||||
ev->Assign(3, ie->rai()->rac());
|
|
||||||
return ev;
|
|
||||||
}
|
|
||||||
|
|
||||||
static zeek::ValPtr BuildRecovery(const InformationElement* ie)
|
|
||||||
{
|
|
||||||
return zeek::val_mgr->Count(ie->recovery()->restart_counter());
|
|
||||||
}
|
|
||||||
|
|
||||||
static zeek::ValPtr BuildSelectionMode(const InformationElement* ie)
|
|
||||||
{
|
|
||||||
return zeek::val_mgr->Count(ie->selection_mode()->mode());
|
|
||||||
}
|
|
||||||
|
|
||||||
static zeek::ValPtr BuildTEID1(const InformationElement* ie)
|
|
||||||
{
|
|
||||||
return zeek::val_mgr->Count(ie->teid1()->value());
|
|
||||||
}
|
|
||||||
|
|
||||||
static zeek::ValPtr BuildTEID_ControlPlane(const InformationElement* ie)
|
|
||||||
{
|
|
||||||
return zeek::val_mgr->Count(ie->teidcp()->value());
|
|
||||||
}
|
|
||||||
|
|
||||||
static zeek::ValPtr BuildNSAPI(const InformationElement* ie)
|
|
||||||
{
|
|
||||||
return zeek::val_mgr->Count(ie->nsapi()->nsapi());
|
|
||||||
}
|
|
||||||
|
|
||||||
static zeek::ValPtr BuildChargingCharacteristics(const InformationElement* ie)
|
|
||||||
{
|
|
||||||
return zeek::val_mgr->Count(ie->charging_characteristics()->value());
|
|
||||||
}
|
|
||||||
|
|
||||||
static zeek::ValPtr BuildTraceReference(const InformationElement* ie)
|
|
||||||
{
|
|
||||||
return zeek::val_mgr->Count(ie->trace_reference()->value());
|
|
||||||
}
|
|
||||||
|
|
||||||
static zeek::ValPtr BuildTraceType(const InformationElement* ie)
|
|
||||||
{
|
|
||||||
return zeek::val_mgr->Count(ie->trace_type()->value());
|
|
||||||
}
|
|
||||||
|
|
||||||
zeek::ValPtr BuildEndUserAddr(const InformationElement* ie)
|
|
||||||
{
|
|
||||||
auto ev = zeek::make_intrusive<zeek::RecordVal>(zeek::BifType::Record::gtp_end_user_addr);
|
|
||||||
ev->Assign(0, ie->end_user_addr()->pdp_type_org());
|
|
||||||
ev->Assign(1, ie->end_user_addr()->pdp_type_num());
|
|
||||||
|
|
||||||
int len = ie->end_user_addr()->pdp_addr().length();
|
|
||||||
|
|
||||||
if ( len > 0 )
|
|
||||||
{
|
|
||||||
const uint8* d = ie->end_user_addr()->pdp_addr().data();
|
|
||||||
|
|
||||||
switch ( ie->end_user_addr()->pdp_type_num() ) {
|
|
||||||
case 0x21:
|
|
||||||
ev->Assign(2, zeek::make_intrusive<zeek::AddrVal>(
|
|
||||||
zeek::IPAddr(IPv4, (const uint32*) d, zeek::IPAddr::Network)));
|
|
||||||
break;
|
|
||||||
case 0x57:
|
|
||||||
ev->Assign(2, zeek::make_intrusive<zeek::AddrVal>(
|
|
||||||
zeek::IPAddr(IPv6, (const uint32*) d, zeek::IPAddr::Network)));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ev->Assign(3, new zeek::String((const u_char*) d, len, false));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ev;
|
|
||||||
}
|
|
||||||
|
|
||||||
zeek::ValPtr BuildAccessPointName(const InformationElement* ie)
|
|
||||||
{
|
|
||||||
zeek::String* bs = new zeek::String((const u_char*) ie->ap_name()->value().data(),
|
|
||||||
ie->ap_name()->value().length(), false);
|
|
||||||
return zeek::make_intrusive<zeek::StringVal>(bs);
|
|
||||||
}
|
|
||||||
|
|
||||||
zeek::ValPtr BuildProtoConfigOptions(const InformationElement* ie)
|
|
||||||
{
|
|
||||||
const u_char* d = (const u_char*) ie->proto_config_opts()->value().data();
|
|
||||||
int len = ie->proto_config_opts()->value().length();
|
|
||||||
return zeek::make_intrusive<zeek::StringVal>(new zeek::String(d, len, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
zeek::ValPtr BuildGSN_Addr(const InformationElement* ie)
|
|
||||||
{
|
|
||||||
auto ev = zeek::make_intrusive<zeek::RecordVal>(zeek::BifType::Record::gtp_gsn_addr);
|
|
||||||
|
|
||||||
int len = ie->gsn_addr()->value().length();
|
|
||||||
const uint8* d = ie->gsn_addr()->value().data();
|
|
||||||
|
|
||||||
if ( len == 4 )
|
|
||||||
ev->Assign(0, zeek::make_intrusive<zeek::AddrVal>(
|
|
||||||
zeek::IPAddr(IPv4, (const uint32*) d, zeek::IPAddr::Network)));
|
|
||||||
else if ( len == 16 )
|
|
||||||
ev->Assign(0, zeek::make_intrusive<zeek::AddrVal>(
|
|
||||||
zeek::IPAddr(IPv6, (const uint32*) d, zeek::IPAddr::Network)));
|
|
||||||
else
|
|
||||||
ev->Assign(1, new zeek::String((const u_char*) d, len, false));
|
|
||||||
|
|
||||||
return ev;
|
|
||||||
}
|
|
||||||
|
|
||||||
zeek::ValPtr BuildMSISDN(const InformationElement* ie)
|
|
||||||
{
|
|
||||||
const u_char* d = (const u_char*) ie->msisdn()->value().data();
|
|
||||||
int len = ie->msisdn()->value().length();
|
|
||||||
return zeek::make_intrusive<zeek::StringVal>(new zeek::String(d, len, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
zeek::ValPtr BuildQoS_Profile(const InformationElement* ie)
|
|
||||||
{
|
|
||||||
auto ev = zeek::make_intrusive<zeek::RecordVal>(zeek::BifType::Record::gtp_qos_profile);
|
|
||||||
|
|
||||||
const u_char* d = (const u_char*) ie->qos_profile()->data().data();
|
|
||||||
int len = ie->qos_profile()->data().length();
|
|
||||||
|
|
||||||
ev->Assign(0, ie->qos_profile()->alloc_retention_priority());
|
|
||||||
ev->Assign(1, new zeek::String(d, len, false));
|
|
||||||
|
|
||||||
return ev;
|
|
||||||
}
|
|
||||||
|
|
||||||
zeek::ValPtr BuildTrafficFlowTemplate(const InformationElement* ie)
|
|
||||||
{
|
|
||||||
const uint8* d = ie->traffic_flow_template()->value().data();
|
|
||||||
int len = ie->traffic_flow_template()->value().length();
|
|
||||||
return zeek::make_intrusive<zeek::StringVal>(new zeek::String((const u_char*) d, len, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
zeek::ValPtr BuildTriggerID(const InformationElement* ie)
|
|
||||||
{
|
|
||||||
const uint8* d = ie->trigger_id()->value().data();
|
|
||||||
int len = ie->trigger_id()->value().length();
|
|
||||||
return zeek::make_intrusive<zeek::StringVal>(new zeek::String((const u_char*) d, len, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
zeek::ValPtr BuildOMC_ID(const InformationElement* ie)
|
|
||||||
{
|
|
||||||
const uint8* d = ie->omc_id()->value().data();
|
|
||||||
int len = ie->omc_id()->value().length();
|
|
||||||
return zeek::make_intrusive<zeek::StringVal>(new zeek::String((const u_char*) d, len, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
zeek::ValPtr BuildPrivateExt(const InformationElement* ie)
|
|
||||||
{
|
|
||||||
auto ev = zeek::make_intrusive<zeek::RecordVal>(zeek::BifType::Record::gtp_private_extension);
|
|
||||||
|
|
||||||
const uint8* d = ie->private_ext()->value().data();
|
|
||||||
int len = ie->private_ext()->value().length();
|
|
||||||
|
|
||||||
ev->Assign(0, ie->private_ext()->id());
|
|
||||||
ev->Assign(1, new zeek::String((const u_char*) d, len, false));
|
|
||||||
|
|
||||||
return ev;
|
|
||||||
}
|
|
||||||
|
|
||||||
static zeek::ValPtr BuildCause(const InformationElement* ie)
|
|
||||||
{
|
|
||||||
return zeek::val_mgr->Count(ie->cause()->value());
|
|
||||||
}
|
|
||||||
|
|
||||||
static zeek::ValPtr BuildReorderReq(const InformationElement* ie)
|
|
||||||
{
|
|
||||||
return zeek::val_mgr->Bool(ie->reorder_req()->req());
|
|
||||||
}
|
|
||||||
|
|
||||||
static zeek::ValPtr BuildChargingID(const InformationElement* ie)
|
|
||||||
{
|
|
||||||
return zeek::val_mgr->Count(ie->charging_id()->value());;
|
|
||||||
}
|
|
||||||
|
|
||||||
zeek::ValPtr BuildChargingGatewayAddr(const InformationElement* ie)
|
|
||||||
{
|
|
||||||
const uint8* d = ie->charging_gateway_addr()->value().data();
|
|
||||||
int len = ie->charging_gateway_addr()->value().length();
|
|
||||||
if ( len == 4 )
|
|
||||||
return zeek::make_intrusive<zeek::AddrVal>(zeek::IPAddr(IPv4, (const uint32*) d, zeek::IPAddr::Network));
|
|
||||||
else if ( len == 16 )
|
|
||||||
return zeek::make_intrusive<zeek::AddrVal>(zeek::IPAddr(IPv6, (const uint32*) d, zeek::IPAddr::Network));
|
|
||||||
else
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static zeek::ValPtr BuildTeardownInd(const InformationElement* ie)
|
|
||||||
{
|
|
||||||
return zeek::val_mgr->Bool(ie->teardown_ind()->ind());
|
|
||||||
}
|
|
||||||
|
|
||||||
void CreatePDP_Request(const ZeekAnalyzer& a, const GTPv1_Header* pdu)
|
|
||||||
{
|
|
||||||
if ( ! ::gtpv1_create_pdp_ctx_request ) return;
|
|
||||||
|
|
||||||
auto rv = zeek::make_intrusive<zeek::RecordVal>(
|
|
||||||
zeek::BifType::Record::gtp_create_pdp_ctx_request_elements);
|
|
||||||
|
|
||||||
const vector<InformationElement *> * v = pdu->create_pdp_ctx_request();
|
|
||||||
|
|
||||||
bool second_nsapi = false;
|
|
||||||
bool second_gsn_addr = false;
|
|
||||||
|
|
||||||
for ( size_t i = 0; i < v->size(); ++i )
|
|
||||||
{
|
|
||||||
const InformationElement* ie = (*v)[i];
|
|
||||||
|
|
||||||
switch ( ie->type() ) {
|
|
||||||
case GTPv1::TYPE_IMSI:
|
|
||||||
rv->Assign(0, BuildIMSI(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_RAI:
|
|
||||||
rv->Assign(1, BuildRAI(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_RECOVERY:
|
|
||||||
rv->Assign(2, BuildRecovery(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_SELECTION_MODE:
|
|
||||||
rv->Assign(3, BuildSelectionMode(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_TEID1:
|
|
||||||
rv->Assign(4, BuildTEID1(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_TEID_CONTROL_PLANE:
|
|
||||||
rv->Assign(5, BuildTEID_ControlPlane(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_NSAPI:
|
|
||||||
if ( second_nsapi )
|
|
||||||
rv->Assign(7, BuildNSAPI(ie));
|
|
||||||
else
|
|
||||||
{
|
|
||||||
second_nsapi = true;
|
|
||||||
rv->Assign(6, BuildNSAPI(ie));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_CHARGING_CHARACTERISTICS:
|
|
||||||
rv->Assign(8, BuildChargingCharacteristics(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_TRACE_REFERENCE:
|
|
||||||
rv->Assign(9, BuildTraceReference(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_TRACE_TYPE:
|
|
||||||
rv->Assign(10, BuildTraceType(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_END_USER_ADDR:
|
|
||||||
rv->Assign(11, BuildEndUserAddr(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_ACCESS_POINT_NAME:
|
|
||||||
rv->Assign(12, BuildAccessPointName(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_PROTO_CONFIG_OPTIONS:
|
|
||||||
rv->Assign(13, BuildProtoConfigOptions(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_GSN_ADDR:
|
|
||||||
if ( second_gsn_addr )
|
|
||||||
rv->Assign(15, BuildGSN_Addr(ie));
|
|
||||||
else
|
|
||||||
{
|
|
||||||
second_gsn_addr = true;
|
|
||||||
rv->Assign(14, BuildGSN_Addr(ie));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_MSISDN:
|
|
||||||
rv->Assign(16, BuildMSISDN(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_QOS_PROFILE:
|
|
||||||
rv->Assign(17, BuildQoS_Profile(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_TRAFFIC_FLOW_TEMPLATE:
|
|
||||||
rv->Assign(18, BuildTrafficFlowTemplate(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_TRIGGER_ID:
|
|
||||||
rv->Assign(19, BuildTriggerID(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_OMC_ID:
|
|
||||||
rv->Assign(20, BuildOMC_ID(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_PRIVATE_EXT:
|
|
||||||
rv->Assign(21, BuildPrivateExt(ie));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
a->Weird("gtp_invalid_info_element", zeek::util::fmt("%d", (*v)[i]->type()));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
zeek::BifEvent::enqueue_gtpv1_create_pdp_ctx_request(a, a->Conn(),
|
|
||||||
BuildGTPv1Hdr(pdu), std::move(rv));
|
|
||||||
}
|
|
||||||
|
|
||||||
void CreatePDP_Response(const ZeekAnalyzer& a, const GTPv1_Header* pdu)
|
|
||||||
{
|
|
||||||
if ( ! ::gtpv1_create_pdp_ctx_response )
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto rv = zeek::make_intrusive<zeek::RecordVal>(
|
|
||||||
zeek::BifType::Record::gtp_create_pdp_ctx_response_elements);
|
|
||||||
|
|
||||||
const vector<InformationElement *> * v = pdu->create_pdp_ctx_response();
|
|
||||||
|
|
||||||
bool second_gsn_addr = false;
|
|
||||||
|
|
||||||
for ( size_t i = 0; i < v->size(); ++i )
|
|
||||||
{
|
|
||||||
const InformationElement* ie = (*v)[i];
|
|
||||||
|
|
||||||
switch ( ie->type() ) {
|
|
||||||
case GTPv1::TYPE_CAUSE:
|
|
||||||
rv->Assign(0, BuildCause(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_REORDER_REQ:
|
|
||||||
rv->Assign(1, BuildReorderReq(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_RECOVERY:
|
|
||||||
rv->Assign(2, BuildRecovery(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_TEID1:
|
|
||||||
rv->Assign(3, BuildTEID1(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_TEID_CONTROL_PLANE:
|
|
||||||
rv->Assign(4, BuildTEID_ControlPlane(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_CHARGING_ID:
|
|
||||||
rv->Assign(5, BuildChargingID(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_END_USER_ADDR:
|
|
||||||
rv->Assign(6, BuildEndUserAddr(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_PROTO_CONFIG_OPTIONS:
|
|
||||||
rv->Assign(7, BuildProtoConfigOptions(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_GSN_ADDR:
|
|
||||||
if ( second_gsn_addr )
|
|
||||||
rv->Assign(9, BuildGSN_Addr(ie));
|
|
||||||
else
|
|
||||||
{
|
|
||||||
second_gsn_addr = true;
|
|
||||||
rv->Assign(8, BuildGSN_Addr(ie));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_QOS_PROFILE:
|
|
||||||
rv->Assign(10, BuildQoS_Profile(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_CHARGING_GATEWAY_ADDR:
|
|
||||||
rv->Assign(11, BuildChargingGatewayAddr(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_PRIVATE_EXT:
|
|
||||||
rv->Assign(12, BuildPrivateExt(ie));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
a->Weird("gtp_invalid_info_element", zeek::util::fmt("%d", (*v)[i]->type()));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
zeek::BifEvent::enqueue_gtpv1_create_pdp_ctx_response(a, a->Conn(),
|
|
||||||
BuildGTPv1Hdr(pdu), std::move(rv));
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdatePDP_Request(const ZeekAnalyzer& a, const GTPv1_Header* pdu)
|
|
||||||
{
|
|
||||||
if ( ! ::gtpv1_update_pdp_ctx_request )
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto rv = zeek::make_intrusive<zeek::RecordVal>(
|
|
||||||
zeek::BifType::Record::gtp_update_pdp_ctx_request_elements);
|
|
||||||
|
|
||||||
const vector<InformationElement *> * v = pdu->update_pdp_ctx_request();
|
|
||||||
|
|
||||||
bool second_gsn_addr = false;
|
|
||||||
|
|
||||||
for ( size_t i = 0; i < v->size(); ++i )
|
|
||||||
{
|
|
||||||
const InformationElement* ie = (*v)[i];
|
|
||||||
|
|
||||||
switch ( ie->type() ) {
|
|
||||||
case GTPv1::TYPE_IMSI:
|
|
||||||
rv->Assign(0, BuildIMSI(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_RAI:
|
|
||||||
rv->Assign(1, BuildRAI(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_RECOVERY:
|
|
||||||
rv->Assign(2, BuildRecovery(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_TEID1:
|
|
||||||
rv->Assign(3, BuildTEID1(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_TEID_CONTROL_PLANE:
|
|
||||||
rv->Assign(4, BuildTEID_ControlPlane(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_NSAPI:
|
|
||||||
rv->Assign(5, BuildNSAPI(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_TRACE_REFERENCE:
|
|
||||||
rv->Assign(6, BuildTraceReference(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_TRACE_TYPE:
|
|
||||||
rv->Assign(7, BuildTraceType(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_GSN_ADDR:
|
|
||||||
if ( second_gsn_addr )
|
|
||||||
rv->Assign(9, BuildGSN_Addr(ie));
|
|
||||||
else
|
|
||||||
{
|
|
||||||
second_gsn_addr = true;
|
|
||||||
rv->Assign(8, BuildGSN_Addr(ie));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_QOS_PROFILE:
|
|
||||||
rv->Assign(10, BuildQoS_Profile(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_TRAFFIC_FLOW_TEMPLATE:
|
|
||||||
rv->Assign(11, BuildTrafficFlowTemplate(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_TRIGGER_ID:
|
|
||||||
rv->Assign(12, BuildTriggerID(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_OMC_ID:
|
|
||||||
rv->Assign(13, BuildOMC_ID(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_PRIVATE_EXT:
|
|
||||||
rv->Assign(14, BuildPrivateExt(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_END_USER_ADDR:
|
|
||||||
rv->Assign(15, BuildEndUserAddr(ie));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
a->Weird("gtp_invalid_info_element", zeek::util::fmt("%d", (*v)[i]->type()));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
zeek::BifEvent::enqueue_gtpv1_update_pdp_ctx_request(a, a->Conn(),
|
|
||||||
BuildGTPv1Hdr(pdu), std::move(rv));
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdatePDP_Response(const ZeekAnalyzer& a, const GTPv1_Header* pdu)
|
|
||||||
{
|
|
||||||
if ( ! ::gtpv1_update_pdp_ctx_response )
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto rv = zeek::make_intrusive<zeek::RecordVal>(
|
|
||||||
zeek::BifType::Record::gtp_update_pdp_ctx_response_elements);
|
|
||||||
|
|
||||||
const vector<InformationElement *> * v = pdu->update_pdp_ctx_response();
|
|
||||||
|
|
||||||
bool second_gsn_addr = false;
|
|
||||||
|
|
||||||
for ( size_t i = 0; i < v->size(); ++i )
|
|
||||||
{
|
|
||||||
const InformationElement* ie = (*v)[i];
|
|
||||||
|
|
||||||
switch ( ie->type() ) {
|
|
||||||
case GTPv1::TYPE_CAUSE:
|
|
||||||
rv->Assign(0, BuildCause(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_RECOVERY:
|
|
||||||
rv->Assign(1, BuildRecovery(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_TEID1:
|
|
||||||
rv->Assign(2, BuildTEID1(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_TEID_CONTROL_PLANE:
|
|
||||||
rv->Assign(3, BuildTEID_ControlPlane(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_CHARGING_ID:
|
|
||||||
rv->Assign(4, BuildChargingID(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_GSN_ADDR:
|
|
||||||
if ( second_gsn_addr )
|
|
||||||
rv->Assign(6, BuildGSN_Addr(ie));
|
|
||||||
else
|
|
||||||
{
|
|
||||||
second_gsn_addr = true;
|
|
||||||
rv->Assign(5, BuildGSN_Addr(ie));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_QOS_PROFILE:
|
|
||||||
rv->Assign(7, BuildQoS_Profile(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_CHARGING_GATEWAY_ADDR:
|
|
||||||
rv->Assign(8, BuildChargingGatewayAddr(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_PRIVATE_EXT:
|
|
||||||
rv->Assign(9, BuildPrivateExt(ie));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
a->Weird("gtp_invalid_info_element", zeek::util::fmt("%d", (*v)[i]->type()));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
zeek::BifEvent::enqueue_gtpv1_update_pdp_ctx_response(a, a->Conn(),
|
|
||||||
BuildGTPv1Hdr(pdu), std::move(rv));
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeletePDP_Request(const ZeekAnalyzer& a, const GTPv1_Header* pdu)
|
|
||||||
{
|
|
||||||
if ( ! ::gtpv1_delete_pdp_ctx_request )
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto rv = zeek::make_intrusive<zeek::RecordVal>(
|
|
||||||
zeek::BifType::Record::gtp_delete_pdp_ctx_request_elements);
|
|
||||||
|
|
||||||
const vector<InformationElement *> * v = pdu->delete_pdp_ctx_request();
|
|
||||||
|
|
||||||
for ( size_t i = 0; i < v->size(); ++i )
|
|
||||||
{
|
|
||||||
const InformationElement* ie = (*v)[i];
|
|
||||||
|
|
||||||
switch ( ie->type() ) {
|
|
||||||
case GTPv1::TYPE_TEARDOWN_IND:
|
|
||||||
rv->Assign(0, BuildTeardownInd(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_NSAPI:
|
|
||||||
rv->Assign(1, BuildNSAPI(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_PRIVATE_EXT:
|
|
||||||
rv->Assign(2, BuildPrivateExt(ie));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
a->Weird("gtp_invalid_info_element", zeek::util::fmt("%d", (*v)[i]->type()));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
zeek::BifEvent::enqueue_gtpv1_delete_pdp_ctx_request(a, a->Conn(),
|
|
||||||
BuildGTPv1Hdr(pdu), std::move(rv));
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeletePDP_Response(const ZeekAnalyzer& a, const GTPv1_Header* pdu)
|
|
||||||
{
|
|
||||||
if ( ! ::gtpv1_delete_pdp_ctx_response )
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto rv = zeek::make_intrusive<zeek::RecordVal>(
|
|
||||||
zeek::BifType::Record::gtp_delete_pdp_ctx_response_elements);
|
|
||||||
|
|
||||||
const vector<InformationElement *> * v = pdu->delete_pdp_ctx_response();
|
|
||||||
|
|
||||||
for ( size_t i = 0; i < v->size(); ++i )
|
|
||||||
{
|
|
||||||
const InformationElement* ie = (*v)[i];
|
|
||||||
|
|
||||||
switch ( ie->type() ) {
|
|
||||||
case GTPv1::TYPE_CAUSE:
|
|
||||||
rv->Assign(0, BuildCause(ie));
|
|
||||||
break;
|
|
||||||
case GTPv1::TYPE_PRIVATE_EXT:
|
|
||||||
rv->Assign(1, BuildPrivateExt(ie));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
a->Weird("gtp_invalid_info_element", zeek::util::fmt("%d", (*v)[i]->type()));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
zeek::BifEvent::enqueue_gtpv1_delete_pdp_ctx_response(a, a->Conn(),
|
|
||||||
BuildGTPv1Hdr(pdu), std::move(rv));
|
|
||||||
}
|
|
||||||
%}
|
|
||||||
|
|
||||||
connection GTPv1_Conn(zeek_analyzer: ZeekAnalyzer)
|
|
||||||
{
|
|
||||||
upflow = GTPv1_Flow(true);
|
|
||||||
downflow = GTPv1_Flow(false);
|
|
||||||
|
|
||||||
%member{
|
|
||||||
bool valid_orig;
|
|
||||||
bool valid_resp;
|
|
||||||
%}
|
|
||||||
|
|
||||||
%init{
|
|
||||||
valid_orig = valid_resp = false;
|
|
||||||
%}
|
|
||||||
|
|
||||||
function valid(orig: bool): bool
|
|
||||||
%{
|
|
||||||
return orig ? valid_orig : valid_resp;
|
|
||||||
%}
|
|
||||||
|
|
||||||
function set_valid(orig: bool, val: bool): void
|
|
||||||
%{
|
|
||||||
if ( orig )
|
|
||||||
valid_orig = val;
|
|
||||||
else
|
|
||||||
valid_resp = val;
|
|
||||||
%}
|
|
||||||
}
|
|
||||||
|
|
||||||
flow GTPv1_Flow(is_orig: bool)
|
|
||||||
{
|
|
||||||
datagram = GTPv1_Header withcontext(connection, this);
|
|
||||||
|
|
||||||
function violate(r: string, pdu: GTPv1_Header): void
|
|
||||||
%{
|
|
||||||
ZeekAnalyzer a = connection()->zeek_analyzer();
|
|
||||||
const_bytestring b = ${pdu.sourcedata};
|
|
||||||
a->AnalyzerViolation(r.c_str(), (const char*) b.begin(), b.length());
|
|
||||||
%}
|
|
||||||
|
|
||||||
function process_gtpv1(pdu: GTPv1_Header): bool
|
|
||||||
%{
|
|
||||||
ZeekAnalyzer a = connection()->zeek_analyzer();
|
|
||||||
zeek::Connection* c = a->Conn();
|
|
||||||
const std::shared_ptr<zeek::EncapsulationStack> e = c->GetEncapsulation();
|
|
||||||
|
|
||||||
connection()->set_valid(is_orig(), false);
|
|
||||||
|
|
||||||
if ( e && e->Depth() >= zeek::BifConst::Tunnel::max_depth )
|
|
||||||
{
|
|
||||||
a->Weird("tunnel_depth");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( e && e->LastType() == BifEnum::Tunnel::GTPv1 )
|
|
||||||
{
|
|
||||||
// GTP is never tunneled in GTP so, this must be a regular packet
|
|
||||||
violate("GTP-in-GTP", pdu);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ${pdu.version} != 1 )
|
|
||||||
{
|
|
||||||
// Only know of GTPv1 with Version == 1
|
|
||||||
violate("GTPv1 bad Version", pdu);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! ${pdu.pt_flag} )
|
|
||||||
{
|
|
||||||
// Not interested in GTP'
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ::gtpv1_message )
|
|
||||||
zeek::BifEvent::enqueue_gtpv1_message(a, c, BuildGTPv1Hdr(pdu));
|
|
||||||
|
|
||||||
switch ( ${pdu.msg_type} ) {
|
|
||||||
case 16:
|
|
||||||
CreatePDP_Request(a, pdu);
|
|
||||||
return true;
|
|
||||||
case 17:
|
|
||||||
CreatePDP_Response(a, pdu);
|
|
||||||
return true;
|
|
||||||
case 18:
|
|
||||||
UpdatePDP_Request(a, pdu);
|
|
||||||
return true;
|
|
||||||
case 19:
|
|
||||||
UpdatePDP_Response(a, pdu);
|
|
||||||
return true;
|
|
||||||
case 20:
|
|
||||||
DeletePDP_Request(a, pdu);
|
|
||||||
return true;
|
|
||||||
case 21:
|
|
||||||
DeletePDP_Response(a, pdu);
|
|
||||||
return true;
|
|
||||||
case 255:
|
|
||||||
return process_g_pdu(pdu);
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
%}
|
|
||||||
|
|
||||||
function process_g_pdu(pdu: GTPv1_Header): bool
|
|
||||||
%{
|
|
||||||
ZeekAnalyzer a = connection()->zeek_analyzer();
|
|
||||||
zeek::Connection* c = a->Conn();
|
|
||||||
|
|
||||||
if ( ${pdu.packet}.length() < (int)sizeof(struct ip) )
|
|
||||||
{
|
|
||||||
violate("Truncated GTPv1", pdu);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const struct ip* ip = (const struct ip*) ${pdu.packet}.data();
|
|
||||||
|
|
||||||
if ( ip->ip_v != 4 && ip->ip_v != 6 )
|
|
||||||
{
|
|
||||||
violate("non-IP packet in GTPv1", pdu);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int hdr_len = 8;
|
|
||||||
|
|
||||||
if ( pdu->has_opt() )
|
|
||||||
hdr_len += 4;
|
|
||||||
|
|
||||||
if ( pdu->e_flag() && pdu->ext_hdrs() )
|
|
||||||
for ( const auto& eh : *pdu->ext_hdrs() )
|
|
||||||
hdr_len += 2 + eh->contents().length();
|
|
||||||
|
|
||||||
auto next_hdr = ip->ip_v == 6 ? IPPROTO_IPV6 : IPPROTO_IPV4;
|
|
||||||
zeek::RecordValPtr hdr_val;
|
|
||||||
|
|
||||||
if ( ::gtpv1_g_pdu_packet )
|
|
||||||
hdr_val = BuildGTPv1Hdr(pdu);
|
|
||||||
|
|
||||||
static_cast<zeek::analyzer::gtpv1::GTPv1_Analyzer*>(
|
|
||||||
connection()->zeek_analyzer())->SetInnerInfo(
|
|
||||||
hdr_len, next_hdr, std::move(hdr_val));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
%}
|
|
||||||
};
|
|
||||||
|
|
||||||
refine typeattr GTPv1_Header += &let { proc_gtpv1 = $context.flow.process_gtpv1(this); };
|
|
|
@ -1,496 +0,0 @@
|
||||||
|
|
||||||
type GTPv1_Header = record {
|
|
||||||
flags: uint8;
|
|
||||||
msg_type: uint8;
|
|
||||||
length: uint16;
|
|
||||||
teid: uint32;
|
|
||||||
|
|
||||||
opt: case has_opt of {
|
|
||||||
true -> opt_hdr: GTPv1_Opt_Header;
|
|
||||||
false -> no_opt: empty;
|
|
||||||
};
|
|
||||||
|
|
||||||
ext: case e_flag of {
|
|
||||||
true -> ext_hdrs: GTPv1_Ext_Header[] &until($element.next_type == 0);
|
|
||||||
false -> no_ext: empty;
|
|
||||||
};
|
|
||||||
|
|
||||||
msg: case msg_type of {
|
|
||||||
16 -> create_pdp_ctx_request: InformationElement[];
|
|
||||||
17 -> create_pdp_ctx_response: InformationElement[];
|
|
||||||
18 -> update_pdp_ctx_request: InformationElement[];
|
|
||||||
19 -> update_pdp_ctx_response: InformationElement[];
|
|
||||||
20 -> delete_pdp_ctx_request: InformationElement[];
|
|
||||||
21 -> delete_pdp_ctx_response: InformationElement[];
|
|
||||||
255 -> packet: bytestring &restofdata;
|
|
||||||
default -> unknown: bytestring &restofdata;
|
|
||||||
};
|
|
||||||
|
|
||||||
} &let {
|
|
||||||
version: uint8 = (flags & 0xE0) >> 5;
|
|
||||||
pt_flag: bool = flags & 0x10;
|
|
||||||
rsv: bool = flags & 0x08;
|
|
||||||
e_flag: bool = flags & 0x04;
|
|
||||||
s_flag: bool = flags & 0x02;
|
|
||||||
pn_flag: bool = flags & 0x01;
|
|
||||||
has_opt: bool = flags & 0x07;
|
|
||||||
} &byteorder = bigendian, &exportsourcedata;
|
|
||||||
|
|
||||||
type GTPv1_Opt_Header = record {
|
|
||||||
seq: uint16;
|
|
||||||
n_pdu: uint8;
|
|
||||||
next_type: uint8;
|
|
||||||
};
|
|
||||||
|
|
||||||
type GTPv1_Ext_Header = record {
|
|
||||||
length: uint8;
|
|
||||||
contents: bytestring &length=(length * 4 - 2);
|
|
||||||
next_type: uint8;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum InfoElementType {
|
|
||||||
TYPE_CAUSE = 1,
|
|
||||||
TYPE_IMSI = 2,
|
|
||||||
TYPE_RAI = 3,
|
|
||||||
TYPE_TLLI = 4,
|
|
||||||
TYPE_P_TMSI = 5,
|
|
||||||
TYPE_REORDER_REQ = 8,
|
|
||||||
TYPE_AUTHN_TRIPLET = 9,
|
|
||||||
TYPE_MAP_CAUSE = 11,
|
|
||||||
TYPE_P_TMSI_SIG = 12,
|
|
||||||
TYPE_MS_VALID = 13,
|
|
||||||
TYPE_RECOVERY = 14,
|
|
||||||
TYPE_SELECTION_MODE = 15,
|
|
||||||
TYPE_TEID1 = 16,
|
|
||||||
TYPE_TEID_CONTROL_PLANE = 17,
|
|
||||||
TYPE_TEID2 = 18,
|
|
||||||
TYPE_TEARDOWN_IND = 19,
|
|
||||||
TYPE_NSAPI = 20,
|
|
||||||
TYPE_RANAP_CAUSE = 21,
|
|
||||||
TYPE_RAB_CTX = 22,
|
|
||||||
TYPE_RADIO_PRIORITY_SMS = 23,
|
|
||||||
TYPE_RADIO_PRIORITY = 24,
|
|
||||||
TYPE_PACKET_FLOW_ID = 25,
|
|
||||||
TYPE_CHARGING_CHARACTERISTICS = 26,
|
|
||||||
TYPE_TRACE_REFERENCE = 27,
|
|
||||||
TYPE_TRACE_TYPE = 28,
|
|
||||||
TYPE_MS_NOT_REACHABLE_REASON = 29,
|
|
||||||
TYPE_CHARGING_ID = 127,
|
|
||||||
TYPE_END_USER_ADDR = 128,
|
|
||||||
TYPE_MM_CTX = 129,
|
|
||||||
TYPE_PDP_CTX = 130,
|
|
||||||
TYPE_ACCESS_POINT_NAME = 131,
|
|
||||||
TYPE_PROTO_CONFIG_OPTIONS = 132,
|
|
||||||
TYPE_GSN_ADDR = 133,
|
|
||||||
TYPE_MSISDN = 134,
|
|
||||||
TYPE_QOS_PROFILE = 135,
|
|
||||||
TYPE_AUTHN_QUINTUPLET = 136,
|
|
||||||
TYPE_TRAFFIC_FLOW_TEMPLATE = 137,
|
|
||||||
TYPE_TARGET_ID = 138,
|
|
||||||
TYPE_UTRAN_TRANSPARENT_CONTAINER = 139,
|
|
||||||
TYPE_RAB_SETUP_INFO = 140,
|
|
||||||
TYPE_EXT_HEADER_TYPE_LIST = 141,
|
|
||||||
TYPE_TRIGGER_ID = 142,
|
|
||||||
TYPE_OMC_ID = 143,
|
|
||||||
TYPE_CHARGING_GATEWAY_ADDR = 251,
|
|
||||||
TYPE_PRIVATE_EXT = 255,
|
|
||||||
};
|
|
||||||
|
|
||||||
type InformationElement = record {
|
|
||||||
type: uint8;
|
|
||||||
|
|
||||||
len: case is_tlv of {
|
|
||||||
true -> tlv_len: uint16;
|
|
||||||
false -> no_len: empty;
|
|
||||||
};
|
|
||||||
|
|
||||||
value: case type of {
|
|
||||||
TYPE_CAUSE -> cause: Cause;
|
|
||||||
TYPE_IMSI -> imsi: IMSI;
|
|
||||||
TYPE_RAI -> rai: RAI;
|
|
||||||
TYPE_TLLI -> tlli: TLLI;
|
|
||||||
TYPE_P_TMSI -> p_tmsi: P_TMSI;
|
|
||||||
TYPE_REORDER_REQ -> reorder_req: ReorderReq;
|
|
||||||
TYPE_AUTHN_TRIPLET -> authn_triplet: AuthN_Triplet;
|
|
||||||
TYPE_MAP_CAUSE -> map_cause: MAP_Cause;
|
|
||||||
TYPE_P_TMSI_SIG -> p_tmsi_sig: P_TMSI_Sig;
|
|
||||||
TYPE_MS_VALID -> ms_valid: MS_Valid;
|
|
||||||
TYPE_RECOVERY -> recovery: Recovery;
|
|
||||||
TYPE_SELECTION_MODE -> selection_mode: SelectionMode;
|
|
||||||
TYPE_TEID1 -> teid1: TEID1;
|
|
||||||
TYPE_TEID_CONTROL_PLANE -> teidcp: TEID_ControlPlane;
|
|
||||||
TYPE_TEID2 -> teid2: TEID2;
|
|
||||||
TYPE_TEARDOWN_IND -> teardown_ind: TeardownInd;
|
|
||||||
TYPE_NSAPI -> nsapi: NSAPI;
|
|
||||||
TYPE_RANAP_CAUSE -> ranap_cause: RANAP_Cause;
|
|
||||||
TYPE_RAB_CTX -> rab_ctx: RAB_Ctx;
|
|
||||||
TYPE_RADIO_PRIORITY_SMS -> radio_priority_sms: RadioPrioritySMS;
|
|
||||||
TYPE_RADIO_PRIORITY -> radio_priority: RadioPriority;
|
|
||||||
TYPE_PACKET_FLOW_ID -> packet_flow_id: PacketFlowID;
|
|
||||||
TYPE_CHARGING_CHARACTERISTICS -> charging_characteristics: ChargingCharacteristics;
|
|
||||||
TYPE_TRACE_REFERENCE -> trace_reference: TraceReference;
|
|
||||||
TYPE_TRACE_TYPE -> trace_type: TraceType;
|
|
||||||
TYPE_MS_NOT_REACHABLE_REASON -> ms_not_reachable_reason: MS_Not_Reachable_Reason;
|
|
||||||
TYPE_CHARGING_ID -> charging_id: ChargingID;
|
|
||||||
TYPE_END_USER_ADDR -> end_user_addr: EndUserAddr(length);
|
|
||||||
TYPE_MM_CTX -> mm_ctx: MM_Ctx(length);
|
|
||||||
TYPE_PDP_CTX -> pdp_ctx: PDP_Ctx(length);
|
|
||||||
TYPE_ACCESS_POINT_NAME -> ap_name: AP_Name(length);
|
|
||||||
TYPE_PROTO_CONFIG_OPTIONS -> proto_config_opts: ProtoConfigOpts(length);
|
|
||||||
TYPE_GSN_ADDR -> gsn_addr: GSN_Addr(length);
|
|
||||||
TYPE_MSISDN -> msisdn: MSISDN(length);
|
|
||||||
TYPE_QOS_PROFILE -> qos_profile: QoS_Profile(length);
|
|
||||||
TYPE_AUTHN_QUINTUPLET -> authn_quintuplet: AuthN_Quintuplet(length);
|
|
||||||
TYPE_TRAFFIC_FLOW_TEMPLATE -> traffic_flow_template: TrafficFlowTemplate(length);
|
|
||||||
TYPE_TARGET_ID -> target_id: TargetID(length);
|
|
||||||
TYPE_UTRAN_TRANSPARENT_CONTAINER -> utran_transparent_container: UTRAN_TransparentContainer(length);
|
|
||||||
TYPE_RAB_SETUP_INFO -> rab_setup_info: RAB_SetupInfo(length);
|
|
||||||
TYPE_EXT_HEADER_TYPE_LIST -> ext_hdr_type_list: ExtHdrTypeList(length);
|
|
||||||
TYPE_TRIGGER_ID -> trigger_id: TriggerID(length);
|
|
||||||
TYPE_OMC_ID -> omc_id: OMC_ID(length);
|
|
||||||
TYPE_CHARGING_GATEWAY_ADDR -> charging_gateway_addr: ChargingGatewayAddr(length);
|
|
||||||
TYPE_PRIVATE_EXT -> private_ext: PrivateExt(length);
|
|
||||||
default -> unknown: bytestring &length=length;
|
|
||||||
} &requires(length);
|
|
||||||
|
|
||||||
} &let {
|
|
||||||
is_tlv: bool = (type & 0x80);
|
|
||||||
length: uint16 = is_tlv ? tlv_len : Get_IE_Len(type);
|
|
||||||
};
|
|
||||||
|
|
||||||
type Cause = record {
|
|
||||||
value: uint8;
|
|
||||||
};
|
|
||||||
|
|
||||||
function decode_imsi(v: uint8[8]): uint64
|
|
||||||
%{
|
|
||||||
uint64 rval = 0;
|
|
||||||
uint8 digits[16];
|
|
||||||
for ( size_t i = 0; i < v->size(); ++i )
|
|
||||||
{
|
|
||||||
digits[2 * i + 1] = ((*v)[i] & 0xf0) >> 4;
|
|
||||||
digits[2 * i] = (*v)[i] & 0x0f;
|
|
||||||
}
|
|
||||||
int power = 0;
|
|
||||||
for ( int i = 15; i >= 0; --i )
|
|
||||||
{
|
|
||||||
if ( digits[i] == 0x0f ) continue;
|
|
||||||
rval += digits[i] * pow(10, power);
|
|
||||||
++power;
|
|
||||||
}
|
|
||||||
return rval;
|
|
||||||
%}
|
|
||||||
|
|
||||||
type IMSI = record {
|
|
||||||
tbcd_encoded_value: uint8[8];
|
|
||||||
} &let {
|
|
||||||
value: uint64 = decode_imsi(tbcd_encoded_value);
|
|
||||||
};
|
|
||||||
|
|
||||||
type RAI = record {
|
|
||||||
mcc2_mcc1: uint8;
|
|
||||||
mnc3_mcc3: uint8;
|
|
||||||
mnc2_mnc1: uint8;
|
|
||||||
lac: uint16;
|
|
||||||
rac: uint8;
|
|
||||||
} &let {
|
|
||||||
mcc1: uint8 = (mcc2_mcc1 & 0x0f);
|
|
||||||
mcc2: uint8 = ((mcc2_mcc1 & 0xf0)>>4);
|
|
||||||
mcc3: uint8 = (mnc3_mcc3 & 0x0f);
|
|
||||||
mcc: uint16 = mcc1 * 100 + mcc2 * 10 + mcc3;
|
|
||||||
mnc1: uint8 = (mnc2_mnc1 & 0x0f);
|
|
||||||
mnc2: uint8 = ((mnc2_mnc1 & 0xf0)>>4);
|
|
||||||
mnc3: uint8 = (mnc3_mcc3 & 0xf0)>>4;
|
|
||||||
mnc: uint16 = (mnc3 & 0x0f) ? mnc1 * 10 + mnc2 : mnc1 * 100 + mnc2 * 10 + mnc3;
|
|
||||||
};
|
|
||||||
|
|
||||||
type TLLI = record {
|
|
||||||
value: uint32;
|
|
||||||
};
|
|
||||||
|
|
||||||
type P_TMSI = record {
|
|
||||||
value: uint32;
|
|
||||||
};
|
|
||||||
|
|
||||||
type ReorderReq = record {
|
|
||||||
value: uint8;
|
|
||||||
} &let {
|
|
||||||
req: bool = value & 0x01;
|
|
||||||
};
|
|
||||||
|
|
||||||
type AuthN_Triplet = record {
|
|
||||||
rand: bytestring &length=16;
|
|
||||||
sres: uint32;
|
|
||||||
kc: uint64;
|
|
||||||
};
|
|
||||||
|
|
||||||
type MAP_Cause = record {
|
|
||||||
value: uint8;
|
|
||||||
};
|
|
||||||
|
|
||||||
type P_TMSI_Sig = record {
|
|
||||||
value: bytestring &length=3;
|
|
||||||
};
|
|
||||||
|
|
||||||
type MS_Valid = record {
|
|
||||||
value: uint8;
|
|
||||||
};
|
|
||||||
|
|
||||||
type Recovery = record {
|
|
||||||
restart_counter: uint8;
|
|
||||||
};
|
|
||||||
|
|
||||||
type SelectionMode = record {
|
|
||||||
value: uint8;
|
|
||||||
} &let {
|
|
||||||
mode: uint8 = value & 0x01;
|
|
||||||
};
|
|
||||||
|
|
||||||
type TEID1 = record {
|
|
||||||
value: uint32;
|
|
||||||
};
|
|
||||||
|
|
||||||
type TEID_ControlPlane = record {
|
|
||||||
value: uint32;
|
|
||||||
};
|
|
||||||
|
|
||||||
type TEID2 = record {
|
|
||||||
spare_nsapi: uint8;
|
|
||||||
teid2: uint32;
|
|
||||||
};
|
|
||||||
|
|
||||||
type TeardownInd = record {
|
|
||||||
value: uint8;
|
|
||||||
} &let {
|
|
||||||
ind: bool = value & 0x01;
|
|
||||||
};
|
|
||||||
|
|
||||||
type NSAPI = record {
|
|
||||||
xxxx_nsapi: uint8;
|
|
||||||
} &let {
|
|
||||||
nsapi: uint8 = xxxx_nsapi & 0x0f;
|
|
||||||
};
|
|
||||||
|
|
||||||
type RANAP_Cause = record {
|
|
||||||
value: uint8;
|
|
||||||
};
|
|
||||||
|
|
||||||
type RAB_Ctx = record {
|
|
||||||
spare_nsapi: uint8;
|
|
||||||
dl_gtpu_seq_num: uint16;
|
|
||||||
ul_gtpu_seq_num: uint16;
|
|
||||||
dl_pdcp_seq_num: uint16;
|
|
||||||
ul_pdcp_seq_num: uint16;
|
|
||||||
};
|
|
||||||
|
|
||||||
type RadioPrioritySMS = record {
|
|
||||||
value: uint8;
|
|
||||||
};
|
|
||||||
|
|
||||||
type RadioPriority = record {
|
|
||||||
nsapi_radio_priority: uint8;
|
|
||||||
};
|
|
||||||
|
|
||||||
type PacketFlowID = record {
|
|
||||||
rsv_nsapi: uint8;
|
|
||||||
packet_flow_id: uint8;
|
|
||||||
};
|
|
||||||
|
|
||||||
type ChargingCharacteristics = record {
|
|
||||||
value: uint16;
|
|
||||||
};
|
|
||||||
|
|
||||||
type TraceReference = record {
|
|
||||||
value: uint16;
|
|
||||||
};
|
|
||||||
|
|
||||||
type TraceType = record {
|
|
||||||
value: uint16;
|
|
||||||
};
|
|
||||||
|
|
||||||
type MS_Not_Reachable_Reason = record {
|
|
||||||
value: uint8;
|
|
||||||
};
|
|
||||||
|
|
||||||
type ChargingID = record {
|
|
||||||
value: uint32;
|
|
||||||
};
|
|
||||||
|
|
||||||
type EndUserAddr(n: uint16) = record {
|
|
||||||
spare_pdp_type_org: uint8;
|
|
||||||
pdp_type_num: uint8;
|
|
||||||
pdp_addr: bytestring &length=(n-2);
|
|
||||||
} &let {
|
|
||||||
pdp_type_org: uint8 = spare_pdp_type_org & 0x0f;
|
|
||||||
};
|
|
||||||
|
|
||||||
type MM_Ctx(n: uint16) = record {
|
|
||||||
spare_cksn_ksi: uint8;
|
|
||||||
security_params: uint8;
|
|
||||||
|
|
||||||
keys: case gsm_keys of {
|
|
||||||
true -> kc: uint64;
|
|
||||||
false -> ck_ik: bytestring &length=32;
|
|
||||||
};
|
|
||||||
|
|
||||||
vector_len: case have_triplets of {
|
|
||||||
true -> no_quint_len: empty;
|
|
||||||
false -> quint_len: uint16;
|
|
||||||
};
|
|
||||||
|
|
||||||
vectors: case have_triplets of {
|
|
||||||
true -> triplets: AuthN_Triplet[num_vectors];
|
|
||||||
false -> quintuplets: AuthN_Quintuplet(quint_len)[num_vectors];
|
|
||||||
} &requires(num_vectors);
|
|
||||||
|
|
||||||
drx_param: uint16;
|
|
||||||
ms_net_capability_len: uint8;
|
|
||||||
ms_net_capability: bytestring &length=ms_net_capability_len;
|
|
||||||
container_len: uint16;
|
|
||||||
container: bytestring &length=container_len;
|
|
||||||
|
|
||||||
} &let {
|
|
||||||
security_mode: uint8 = security_params >> 6;
|
|
||||||
gsm_keys: bool = security_mode & 0x01;
|
|
||||||
have_triplets: bool = (security_mode == 1);
|
|
||||||
num_vectors: uint8 = (security_params & 0x38) >> 3;
|
|
||||||
};
|
|
||||||
|
|
||||||
type PDP_Ctx(n: uint16) = record {
|
|
||||||
rsv_nsapi: uint8;
|
|
||||||
xxxx_sapi: uint8;
|
|
||||||
qos_sub_len: uint8;
|
|
||||||
qos_sub: QoS_Profile(qos_sub_len);
|
|
||||||
qos_req_len: uint8;
|
|
||||||
qos_req: QoS_Profile(qos_req_len);
|
|
||||||
qos_neg_len: uint8;
|
|
||||||
qos_neg: QoS_Profile(qos_neg_len);
|
|
||||||
snd: uint16;
|
|
||||||
snu: uint16;
|
|
||||||
send_npdu_num: uint8;
|
|
||||||
recv_npdu_num: uint8;
|
|
||||||
ul_teid_cp: TEID_ControlPlane;
|
|
||||||
ul_teid_data1: TEID1;
|
|
||||||
pdp_ctx_id: uint8;
|
|
||||||
spare_pdp_type_org: uint8;
|
|
||||||
pdp_type_num: uint8;
|
|
||||||
pdp_addr_len: uint8;
|
|
||||||
pdp_addr: bytestring &length=pdp_addr_len;
|
|
||||||
ggsn_addr_control_plane_len: uint8;
|
|
||||||
ggsn_addr_control_plane: bytestring &length=ggsn_addr_control_plane_len;
|
|
||||||
ggsn_addr_user_traffic_len: uint8;
|
|
||||||
ggsn_addr_user_traffic: bytestring &length=ggsn_addr_user_traffic_len;
|
|
||||||
apn_len: uint8;
|
|
||||||
apn: AP_Name(apn_len);
|
|
||||||
spare_transaction_id: uint8;
|
|
||||||
transaction_id: uint8;
|
|
||||||
};
|
|
||||||
|
|
||||||
type AP_Name(n: uint16) = record {
|
|
||||||
value: bytestring &length=n;
|
|
||||||
};
|
|
||||||
|
|
||||||
type ProtoConfigOpts(n: uint16) = record {
|
|
||||||
value: bytestring &length=n;
|
|
||||||
};
|
|
||||||
|
|
||||||
type GSN_Addr(n: uint16) = record {
|
|
||||||
value: bytestring &length=n;
|
|
||||||
};
|
|
||||||
|
|
||||||
type MSISDN(n: uint16) = record {
|
|
||||||
value: bytestring &length=n;
|
|
||||||
};
|
|
||||||
|
|
||||||
type QoS_Profile(n: uint16) = record {
|
|
||||||
alloc_retention_priority: uint8;
|
|
||||||
data: bytestring &length=n-1;
|
|
||||||
};
|
|
||||||
|
|
||||||
type AuthN_Quintuplet(n: uint16) = record {
|
|
||||||
rand: bytestring &length=16;
|
|
||||||
xres_len: uint8;
|
|
||||||
xres: bytestring &length=xres_len;
|
|
||||||
ck: bytestring &length=16;
|
|
||||||
ik: bytestring &length=16;
|
|
||||||
autn_len: uint8;
|
|
||||||
autn: bytestring &length=autn_len;
|
|
||||||
};
|
|
||||||
|
|
||||||
type TrafficFlowTemplate(n: uint16) = record {
|
|
||||||
value: bytestring &length=n;
|
|
||||||
};
|
|
||||||
|
|
||||||
type TargetID(n: uint16) = record {
|
|
||||||
value: bytestring &length=n;
|
|
||||||
};
|
|
||||||
|
|
||||||
type UTRAN_TransparentContainer(n: uint16) = record {
|
|
||||||
value: bytestring &length=n;
|
|
||||||
};
|
|
||||||
|
|
||||||
type RAB_SetupInfo(n: uint16) = record {
|
|
||||||
xxxx_nsapi: uint8;
|
|
||||||
|
|
||||||
have_teid: case n of {
|
|
||||||
1 -> no_teid: empty;
|
|
||||||
default -> teid: TEID1;
|
|
||||||
};
|
|
||||||
|
|
||||||
have_addr: case n of {
|
|
||||||
1 -> no_addr: empty;
|
|
||||||
default -> rnc_addr: bytestring &length=n-5;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
type ExtHdrTypeList(n: uint16) = record {
|
|
||||||
value: uint8[n];
|
|
||||||
};
|
|
||||||
|
|
||||||
type TriggerID(n: uint16) = record {
|
|
||||||
value: bytestring &length=n;
|
|
||||||
};
|
|
||||||
|
|
||||||
type OMC_ID(n: uint16) = record {
|
|
||||||
value: bytestring &length=n;
|
|
||||||
};
|
|
||||||
|
|
||||||
type ChargingGatewayAddr(n: uint16) = record {
|
|
||||||
value: bytestring &length=n;
|
|
||||||
};
|
|
||||||
|
|
||||||
type PrivateExt(n: uint16) = record {
|
|
||||||
id: uint16;
|
|
||||||
value: bytestring &length=n-2;
|
|
||||||
};
|
|
||||||
|
|
||||||
function Get_IE_Len(t: uint8): uint16 =
|
|
||||||
case t of {
|
|
||||||
TYPE_CAUSE -> 1;
|
|
||||||
TYPE_IMSI -> 8;
|
|
||||||
TYPE_RAI -> 6;
|
|
||||||
TYPE_TLLI -> 4;
|
|
||||||
TYPE_P_TMSI -> 4;
|
|
||||||
TYPE_REORDER_REQ -> 1;
|
|
||||||
TYPE_AUTHN_TRIPLET -> 28;
|
|
||||||
TYPE_MAP_CAUSE -> 1;
|
|
||||||
TYPE_P_TMSI_SIG -> 3;
|
|
||||||
TYPE_MS_VALID -> 1;
|
|
||||||
TYPE_RECOVERY -> 1;
|
|
||||||
TYPE_SELECTION_MODE -> 1;
|
|
||||||
TYPE_TEID1 -> 4;
|
|
||||||
TYPE_TEID_CONTROL_PLANE -> 4;
|
|
||||||
TYPE_TEID2 -> 5;
|
|
||||||
TYPE_TEARDOWN_IND -> 1;
|
|
||||||
TYPE_NSAPI -> 1;
|
|
||||||
TYPE_RANAP_CAUSE -> 1;
|
|
||||||
TYPE_RAB_CTX -> 9;
|
|
||||||
TYPE_RADIO_PRIORITY_SMS -> 1;
|
|
||||||
TYPE_RADIO_PRIORITY -> 1;
|
|
||||||
TYPE_PACKET_FLOW_ID -> 2;
|
|
||||||
TYPE_CHARGING_CHARACTERISTICS -> 2;
|
|
||||||
TYPE_TRACE_REFERENCE -> 2;
|
|
||||||
TYPE_TRACE_TYPE -> 2;
|
|
||||||
TYPE_MS_NOT_REACHABLE_REASON -> 1;
|
|
||||||
TYPE_CHARGING_ID -> 4;
|
|
||||||
};
|
|
|
@ -1,18 +0,0 @@
|
||||||
%include binpac.pac
|
|
||||||
%include zeek.pac
|
|
||||||
|
|
||||||
%extern{
|
|
||||||
#include "zeek/IP.h"
|
|
||||||
#include "zeek/TunnelEncapsulation.h"
|
|
||||||
#include "zeek/Reporter.h"
|
|
||||||
|
|
||||||
#include "zeek/analyzer/protocol/gtpv1/events.bif.h"
|
|
||||||
%}
|
|
||||||
|
|
||||||
analyzer GTPv1 withcontext {
|
|
||||||
connection: GTPv1_Conn;
|
|
||||||
flow: GTPv1_Flow;
|
|
||||||
};
|
|
||||||
|
|
||||||
%include gtpv1-protocol.pac
|
|
||||||
%include gtpv1-analyzer.pac
|
|
|
@ -1,9 +0,0 @@
|
||||||
|
|
||||||
include(ZeekPlugin)
|
|
||||||
|
|
||||||
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
|
||||||
|
|
||||||
zeek_plugin_begin(Zeek Teredo)
|
|
||||||
zeek_plugin_cc(Teredo.cc Plugin.cc)
|
|
||||||
zeek_plugin_bif(events.bif)
|
|
||||||
zeek_plugin_end()
|
|
|
@ -1,26 +0,0 @@
|
||||||
// See the file in the main distribution directory for copyright.
|
|
||||||
|
|
||||||
#include "zeek/plugin/Plugin.h"
|
|
||||||
|
|
||||||
#include "zeek/analyzer/Component.h"
|
|
||||||
#include "zeek/analyzer/protocol/teredo/Teredo.h"
|
|
||||||
|
|
||||||
namespace zeek::plugin::detail::Zeek_Teredo
|
|
||||||
{
|
|
||||||
|
|
||||||
class Plugin : public zeek::plugin::Plugin
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
zeek::plugin::Configuration Configure() override
|
|
||||||
{
|
|
||||||
AddComponent(new zeek::analyzer::Component(
|
|
||||||
"Teredo", zeek::analyzer::teredo::Teredo_Analyzer::Instantiate));
|
|
||||||
|
|
||||||
zeek::plugin::Configuration config;
|
|
||||||
config.name = "Zeek::Teredo";
|
|
||||||
config.description = "Teredo analyzer";
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
} plugin;
|
|
||||||
|
|
||||||
} // namespace zeek::plugin::detail::Zeek_Teredo
|
|
|
@ -1,237 +0,0 @@
|
||||||
#include "zeek/analyzer/protocol/teredo/Teredo.h"
|
|
||||||
|
|
||||||
#include "zeek/Conn.h"
|
|
||||||
#include "zeek/IP.h"
|
|
||||||
#include "zeek/Reporter.h"
|
|
||||||
#include "zeek/RunState.h"
|
|
||||||
#include "zeek/TunnelEncapsulation.h"
|
|
||||||
#include "zeek/ZeekString.h"
|
|
||||||
#include "zeek/analyzer/protocol/teredo/events.bif.h"
|
|
||||||
#include "zeek/packet_analysis/protocol/ip/IP.h"
|
|
||||||
#include "zeek/packet_analysis/protocol/iptunnel/IPTunnel.h"
|
|
||||||
|
|
||||||
namespace zeek::analyzer::teredo
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
|
|
||||||
bool TeredoEncapsulation::DoParse(const u_char* data, int& len, bool found_origin, bool found_auth)
|
|
||||||
{
|
|
||||||
if ( len < 2 )
|
|
||||||
{
|
|
||||||
Weird("truncated_Teredo");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t tag = ntohs((*((const uint16_t*)data)));
|
|
||||||
|
|
||||||
if ( tag == 0 )
|
|
||||||
{
|
|
||||||
// Origin Indication
|
|
||||||
if ( found_origin )
|
|
||||||
// can't have multiple origin indications
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if ( len < 8 )
|
|
||||||
{
|
|
||||||
Weird("truncated_Teredo_origin_indication");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
origin_indication = data;
|
|
||||||
len -= 8;
|
|
||||||
data += 8;
|
|
||||||
return DoParse(data, len, true, found_auth);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if ( tag == 1 )
|
|
||||||
{
|
|
||||||
// Authentication
|
|
||||||
if ( found_origin || found_auth )
|
|
||||||
// can't have multiple authentication headers and can't come after
|
|
||||||
// an origin indication
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if ( len < 4 )
|
|
||||||
{
|
|
||||||
Weird("truncated_Teredo_authentication");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t id_len = data[2];
|
|
||||||
uint8_t au_len = data[3];
|
|
||||||
uint16_t tot_len = 4 + id_len + au_len + 8 + 1;
|
|
||||||
|
|
||||||
if ( len < tot_len )
|
|
||||||
{
|
|
||||||
Weird("truncated_Teredo_authentication");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auth = data;
|
|
||||||
len -= tot_len;
|
|
||||||
data += tot_len;
|
|
||||||
return DoParse(data, len, found_origin, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if ( ((tag & 0xf000) >> 12) == 6 )
|
|
||||||
{
|
|
||||||
// IPv6
|
|
||||||
if ( len < 40 )
|
|
||||||
{
|
|
||||||
Weird("truncated_IPv6_in_Teredo");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// There's at least a possible IPv6 header, we'll decide what to do
|
|
||||||
// later if the payload length field doesn't match the actual length
|
|
||||||
// of the packet.
|
|
||||||
inner_ip = data;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
RecordValPtr TeredoEncapsulation::BuildVal(const std::shared_ptr<IP_Hdr>& inner) const
|
|
||||||
{
|
|
||||||
static auto teredo_hdr_type = id::find_type<RecordType>("teredo_hdr");
|
|
||||||
static auto teredo_auth_type = id::find_type<RecordType>("teredo_auth");
|
|
||||||
static auto teredo_origin_type = id::find_type<RecordType>("teredo_origin");
|
|
||||||
|
|
||||||
auto teredo_hdr = make_intrusive<RecordVal>(teredo_hdr_type);
|
|
||||||
|
|
||||||
if ( auth )
|
|
||||||
{
|
|
||||||
auto teredo_auth = make_intrusive<RecordVal>(teredo_auth_type);
|
|
||||||
uint8_t id_len = *((uint8_t*)(auth + 2));
|
|
||||||
uint8_t au_len = *((uint8_t*)(auth + 3));
|
|
||||||
uint64_t nonce = ntohll(*((uint64_t*)(auth + 4 + id_len + au_len)));
|
|
||||||
uint8_t conf = *((uint8_t*)(auth + 4 + id_len + au_len + 8));
|
|
||||||
teredo_auth->Assign(0, new String(auth + 4, id_len, true));
|
|
||||||
teredo_auth->Assign(1, new String(auth + 4 + id_len, au_len, true));
|
|
||||||
teredo_auth->Assign(2, nonce);
|
|
||||||
teredo_auth->Assign(3, conf);
|
|
||||||
teredo_hdr->Assign(0, std::move(teredo_auth));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( origin_indication )
|
|
||||||
{
|
|
||||||
auto teredo_origin = make_intrusive<RecordVal>(teredo_origin_type);
|
|
||||||
uint16_t port = ntohs(*((uint16_t*)(origin_indication + 2))) ^ 0xFFFF;
|
|
||||||
uint32_t addr = ntohl(*((uint32_t*)(origin_indication + 4))) ^ 0xFFFFFFFF;
|
|
||||||
teredo_origin->Assign(0, val_mgr->Port(port, TRANSPORT_UDP));
|
|
||||||
teredo_origin->Assign(1, make_intrusive<AddrVal>(htonl(addr)));
|
|
||||||
teredo_hdr->Assign(1, std::move(teredo_origin));
|
|
||||||
}
|
|
||||||
|
|
||||||
teredo_hdr->Assign(2, inner->ToPktHdrVal());
|
|
||||||
return teredo_hdr;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
void Teredo_Analyzer::Done()
|
|
||||||
{
|
|
||||||
Analyzer::Done();
|
|
||||||
Event(udp_session_done);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Teredo_Analyzer::DeliverPacket(int len, const u_char* data, bool orig, uint64_t seq,
|
|
||||||
const IP_Hdr* ip, int caplen)
|
|
||||||
{
|
|
||||||
Analyzer::DeliverPacket(len, data, orig, seq, ip, caplen);
|
|
||||||
|
|
||||||
if ( orig )
|
|
||||||
valid_orig = false;
|
|
||||||
else
|
|
||||||
valid_resp = false;
|
|
||||||
|
|
||||||
detail::TeredoEncapsulation te(this);
|
|
||||||
|
|
||||||
if ( ! te.Parse(data, len) )
|
|
||||||
{
|
|
||||||
AnalyzerViolation("Bad Teredo encapsulation", (const char*)data, len);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<EncapsulationStack> e = Conn()->GetEncapsulation();
|
|
||||||
|
|
||||||
if ( e && e->Depth() >= BifConst::Tunnel::max_depth )
|
|
||||||
{
|
|
||||||
Weird("tunnel_depth", true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<IP_Hdr> inner = nullptr;
|
|
||||||
int rslt = packet_analysis::IP::ParsePacket(len, te.InnerIP(), IPPROTO_IPV6, inner);
|
|
||||||
|
|
||||||
if ( rslt > 0 )
|
|
||||||
{
|
|
||||||
if ( inner->NextProto() == IPPROTO_NONE && inner->PayloadLen() == 0 )
|
|
||||||
// Teredo bubbles having data after IPv6 header isn't strictly a
|
|
||||||
// violation, but a little weird.
|
|
||||||
Weird("Teredo_bubble_with_payload", true);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AnalyzerViolation("Teredo payload length", (const char*)data, len);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( rslt == 0 || rslt > 0 )
|
|
||||||
{
|
|
||||||
if ( orig )
|
|
||||||
valid_orig = true;
|
|
||||||
else
|
|
||||||
valid_resp = true;
|
|
||||||
|
|
||||||
Confirm();
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AnalyzerViolation("Truncated Teredo or invalid inner IP version", (const char*)data, len);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ValPtr teredo_hdr;
|
|
||||||
|
|
||||||
if ( teredo_packet )
|
|
||||||
{
|
|
||||||
teredo_hdr = te.BuildVal(inner);
|
|
||||||
Conn()->EnqueueEvent(teredo_packet, nullptr, ConnVal(), teredo_hdr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( te.Authentication() && teredo_authentication )
|
|
||||||
{
|
|
||||||
if ( ! teredo_hdr )
|
|
||||||
teredo_hdr = te.BuildVal(inner);
|
|
||||||
|
|
||||||
Conn()->EnqueueEvent(teredo_authentication, nullptr, ConnVal(), teredo_hdr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( te.OriginIndication() && teredo_origin_indication )
|
|
||||||
{
|
|
||||||
if ( ! teredo_hdr )
|
|
||||||
teredo_hdr = te.BuildVal(inner);
|
|
||||||
|
|
||||||
Conn()->EnqueueEvent(teredo_origin_indication, nullptr, ConnVal(), teredo_hdr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( inner->NextProto() == IPPROTO_NONE && teredo_bubble )
|
|
||||||
{
|
|
||||||
if ( ! teredo_hdr )
|
|
||||||
teredo_hdr = te.BuildVal(inner);
|
|
||||||
|
|
||||||
Conn()->EnqueueEvent(teredo_bubble, nullptr, ConnVal(), teredo_hdr);
|
|
||||||
}
|
|
||||||
|
|
||||||
EncapsulatingConn ec(Conn(), BifEnum::Tunnel::TEREDO);
|
|
||||||
|
|
||||||
packet_analysis::IPTunnel::ip_tunnel_analyzer->ProcessEncapsulatedPacket(
|
|
||||||
run_state::network_time, nullptr, inner, e, ec);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace zeek::analyzer::teredo
|
|
|
@ -1,93 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "zeek/NetVar.h"
|
|
||||||
#include "zeek/Reporter.h"
|
|
||||||
#include "zeek/analyzer/Analyzer.h"
|
|
||||||
|
|
||||||
namespace zeek::analyzer::teredo
|
|
||||||
{
|
|
||||||
|
|
||||||
class Teredo_Analyzer final : public analyzer::Analyzer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit Teredo_Analyzer(Connection* conn)
|
|
||||||
: Analyzer("TEREDO", conn), valid_orig(false), valid_resp(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
~Teredo_Analyzer() override = default;
|
|
||||||
|
|
||||||
void Done() override;
|
|
||||||
|
|
||||||
void DeliverPacket(int len, const u_char* data, bool orig, uint64_t seq, const IP_Hdr* ip,
|
|
||||||
int caplen) override;
|
|
||||||
|
|
||||||
static analyzer::Analyzer* Instantiate(Connection* conn) { return new Teredo_Analyzer(conn); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Emits a weird only if the analyzer has previously been able to
|
|
||||||
* decapsulate a Teredo packet in both directions or if *force* param is
|
|
||||||
* set, since otherwise the weirds could happen frequently enough to be less
|
|
||||||
* than helpful. The *force* param is meant for cases where just one side
|
|
||||||
* has a valid encapsulation and so the weird would be informative.
|
|
||||||
*/
|
|
||||||
void Weird(const char* name, bool force = false) const
|
|
||||||
{
|
|
||||||
if ( AnalyzerConfirmed() || force )
|
|
||||||
reporter->Weird(Conn(), name, "", GetAnalyzerName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If the delayed confirmation option is set, then a valid encapsulation
|
|
||||||
* seen from both end points is required before confirming.
|
|
||||||
*/
|
|
||||||
void Confirm()
|
|
||||||
{
|
|
||||||
if ( ! BifConst::Tunnel::delay_teredo_confirmation || (valid_orig && valid_resp) )
|
|
||||||
AnalyzerConfirmation();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool valid_orig;
|
|
||||||
bool valid_resp;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
|
|
||||||
class TeredoEncapsulation
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit TeredoEncapsulation(const Teredo_Analyzer* ta)
|
|
||||||
: inner_ip(nullptr), origin_indication(nullptr), auth(nullptr), analyzer(ta)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether input data parsed as a valid Teredo encapsulation type.
|
|
||||||
* If it was valid, the len argument is decremented appropriately.
|
|
||||||
*/
|
|
||||||
bool Parse(const u_char* data, int& len) { return DoParse(data, len, false, false); }
|
|
||||||
|
|
||||||
const u_char* InnerIP() const { return inner_ip; }
|
|
||||||
|
|
||||||
const u_char* OriginIndication() const { return origin_indication; }
|
|
||||||
|
|
||||||
const u_char* Authentication() const { return auth; }
|
|
||||||
|
|
||||||
RecordValPtr BuildVal(const std::shared_ptr<IP_Hdr>& inner) const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool DoParse(const u_char* data, int& len, bool found_orig, bool found_au);
|
|
||||||
|
|
||||||
void Weird(const char* name) const { analyzer->Weird(name); }
|
|
||||||
|
|
||||||
const u_char* inner_ip;
|
|
||||||
const u_char* origin_indication;
|
|
||||||
const u_char* auth;
|
|
||||||
const Teredo_Analyzer* analyzer;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
} // namespace zeek::analyzer::teredo
|
|
|
@ -1,55 +0,0 @@
|
||||||
## Generated for any IPv6 packet encapsulated in a Teredo tunnel.
|
|
||||||
## See :rfc:`4380` for more information about the Teredo protocol.
|
|
||||||
##
|
|
||||||
## outer: The Teredo tunnel connection.
|
|
||||||
##
|
|
||||||
## inner: The Teredo-encapsulated IPv6 packet header and transport header.
|
|
||||||
##
|
|
||||||
## .. zeek:see:: teredo_authentication teredo_origin_indication teredo_bubble
|
|
||||||
##
|
|
||||||
## .. note:: Since this event may be raised on a per-packet basis, handling
|
|
||||||
## it may become particularly expensive for real-time analysis.
|
|
||||||
event teredo_packet%(outer: connection, inner: teredo_hdr%);
|
|
||||||
|
|
||||||
## 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.
|
|
||||||
##
|
|
||||||
## outer: The Teredo tunnel connection.
|
|
||||||
##
|
|
||||||
## inner: The Teredo-encapsulated IPv6 packet header and transport header.
|
|
||||||
##
|
|
||||||
## .. zeek:see:: teredo_packet teredo_origin_indication teredo_bubble
|
|
||||||
##
|
|
||||||
## .. note:: Since this event may be raised on a per-packet basis, handling
|
|
||||||
## it may become particularly expensive for real-time analysis.
|
|
||||||
event teredo_authentication%(outer: connection, inner: teredo_hdr%);
|
|
||||||
|
|
||||||
## Generated for IPv6 packets encapsulated in a Teredo tunnel that
|
|
||||||
## use the Teredo origin indication encapsulation method.
|
|
||||||
## See :rfc:`4380` for more information about the Teredo protocol.
|
|
||||||
##
|
|
||||||
## outer: The Teredo tunnel connection.
|
|
||||||
##
|
|
||||||
## inner: The Teredo-encapsulated IPv6 packet header and transport header.
|
|
||||||
##
|
|
||||||
## .. zeek:see:: teredo_packet teredo_authentication teredo_bubble
|
|
||||||
##
|
|
||||||
## .. note:: Since this event may be raised on a per-packet basis, handling
|
|
||||||
## it may become particularly expensive for real-time analysis.
|
|
||||||
event teredo_origin_indication%(outer: connection, inner: teredo_hdr%);
|
|
||||||
|
|
||||||
## Generated for Teredo bubble packets. That is, IPv6 packets encapsulated
|
|
||||||
## in a Teredo tunnel that have a Next Header value of :zeek:id:`IPPROTO_NONE`.
|
|
||||||
## See :rfc:`4380` for more information about the Teredo protocol.
|
|
||||||
##
|
|
||||||
## outer: The Teredo tunnel connection.
|
|
||||||
##
|
|
||||||
## inner: The Teredo-encapsulated IPv6 packet header and transport header.
|
|
||||||
##
|
|
||||||
## .. zeek:see:: teredo_packet teredo_authentication teredo_origin_indication
|
|
||||||
##
|
|
||||||
## .. note:: Since this event may be raised on a per-packet basis, handling
|
|
||||||
## it may become particularly expensive for real-time analysis.
|
|
||||||
event teredo_bubble%(outer: connection, inner: teredo_hdr%);
|
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
|
|
||||||
include(ZeekPlugin)
|
|
||||||
|
|
||||||
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
|
||||||
|
|
||||||
zeek_plugin_begin(Zeek VXLAN)
|
|
||||||
zeek_plugin_cc(VXLAN.cc Plugin.cc)
|
|
||||||
zeek_plugin_bif(events.bif)
|
|
||||||
zeek_plugin_end()
|
|
|
@ -1,26 +0,0 @@
|
||||||
// See the file in the main distribution directory for copyright.
|
|
||||||
|
|
||||||
#include "zeek/plugin/Plugin.h"
|
|
||||||
|
|
||||||
#include "zeek/analyzer/Component.h"
|
|
||||||
#include "zeek/analyzer/protocol/vxlan/VXLAN.h"
|
|
||||||
|
|
||||||
namespace zeek::plugin::detail::Zeek_VXLAN
|
|
||||||
{
|
|
||||||
|
|
||||||
class Plugin : public zeek::plugin::Plugin
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
zeek::plugin::Configuration Configure() override
|
|
||||||
{
|
|
||||||
AddComponent(new zeek::analyzer::Component(
|
|
||||||
"VXLAN", zeek::analyzer::vxlan::VXLAN_Analyzer::Instantiate));
|
|
||||||
|
|
||||||
zeek::plugin::Configuration config;
|
|
||||||
config.name = "Zeek::VXLAN";
|
|
||||||
config.description = "VXLAN analyzer";
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
} plugin;
|
|
||||||
|
|
||||||
} // namespace zeek::plugin::detail::Zeek_VXLAN
|
|
|
@ -1,102 +0,0 @@
|
||||||
// See the file in the main distribution directory for copyright.
|
|
||||||
|
|
||||||
#include "zeek/analyzer/protocol/vxlan/VXLAN.h"
|
|
||||||
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#include <pcap.h> // for the DLT_EN10MB constant definition
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "zeek/Conn.h"
|
|
||||||
#include "zeek/IP.h"
|
|
||||||
#include "zeek/Reporter.h"
|
|
||||||
#include "zeek/RunState.h"
|
|
||||||
#include "zeek/TunnelEncapsulation.h"
|
|
||||||
#include "zeek/analyzer/protocol/vxlan/events.bif.h"
|
|
||||||
#include "zeek/packet_analysis/Manager.h"
|
|
||||||
#include "zeek/packet_analysis/protocol/iptunnel/IPTunnel.h"
|
|
||||||
|
|
||||||
namespace zeek::analyzer::vxlan
|
|
||||||
{
|
|
||||||
|
|
||||||
void VXLAN_Analyzer::Done()
|
|
||||||
{
|
|
||||||
Analyzer::Done();
|
|
||||||
Event(udp_session_done);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VXLAN_Analyzer::DeliverPacket(int len, const u_char* data, bool orig, uint64_t seq,
|
|
||||||
const IP_Hdr* ip, int caplen)
|
|
||||||
{
|
|
||||||
Analyzer::DeliverPacket(len, data, orig, seq, ip, caplen);
|
|
||||||
|
|
||||||
// Outer Ethernet, IP, and UDP layers already skipped.
|
|
||||||
// Also, generic UDP analyzer already checked/guarantees caplen >= len.
|
|
||||||
|
|
||||||
constexpr auto vxlan_len = 8;
|
|
||||||
|
|
||||||
if ( len < vxlan_len )
|
|
||||||
{
|
|
||||||
AnalyzerViolation("VXLAN header truncation", (const char*)data, len);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( (data[0] & 0x08) == 0 )
|
|
||||||
{
|
|
||||||
AnalyzerViolation("VXLAN 'I' flag not set", (const char*)data, len);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<EncapsulationStack> outer = Conn()->GetEncapsulation();
|
|
||||||
|
|
||||||
if ( outer && outer->Depth() >= BifConst::Tunnel::max_depth )
|
|
||||||
{
|
|
||||||
Weird("tunnel_depth");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! outer )
|
|
||||||
outer = std::make_shared<EncapsulationStack>();
|
|
||||||
|
|
||||||
EncapsulatingConn inner(Conn(), BifEnum::Tunnel::VXLAN);
|
|
||||||
outer->Add(inner);
|
|
||||||
int encap_index = outer->Depth();
|
|
||||||
|
|
||||||
int vni = (data[4] << 16) + (data[5] << 8) + (data[6] << 0);
|
|
||||||
|
|
||||||
// Skip over the VXLAN header and create a new packet.
|
|
||||||
data += vxlan_len;
|
|
||||||
caplen -= vxlan_len;
|
|
||||||
len -= vxlan_len;
|
|
||||||
|
|
||||||
pkt_timeval ts;
|
|
||||||
ts.tv_sec = (time_t)run_state::current_timestamp;
|
|
||||||
ts.tv_usec = (suseconds_t)((run_state::current_timestamp - (double)ts.tv_sec) * 1000000);
|
|
||||||
Packet pkt(DLT_EN10MB, &ts, caplen, len, data);
|
|
||||||
pkt.encap = outer;
|
|
||||||
|
|
||||||
if ( ! packet_mgr->ProcessInnerPacket(&pkt) )
|
|
||||||
{
|
|
||||||
AnalyzerViolation("VXLAN invalid inner packet");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This isn't really an error. It's just that the inner packet wasn't an IP packet (like ARP).
|
|
||||||
// Just return without reporting a violation.
|
|
||||||
if ( ! pkt.ip_hdr )
|
|
||||||
return;
|
|
||||||
|
|
||||||
AnalyzerConfirmation();
|
|
||||||
|
|
||||||
if ( vxlan_packet )
|
|
||||||
{
|
|
||||||
EncapsulatingConn* ec = pkt.encap->At(encap_index);
|
|
||||||
if ( ec && ec->ip_hdr )
|
|
||||||
{
|
|
||||||
Conn()->EnqueueEvent(vxlan_packet, nullptr, ConnVal(), ec->ip_hdr->ToPktHdrVal(),
|
|
||||||
val_mgr->Count(vni));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace zeek::analyzer::vxlan
|
|
|
@ -1,23 +0,0 @@
|
||||||
// See the file in the main distribution directory for copyright.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "zeek/analyzer/Analyzer.h"
|
|
||||||
|
|
||||||
namespace zeek::analyzer::vxlan
|
|
||||||
{
|
|
||||||
|
|
||||||
class VXLAN_Analyzer final : public analyzer::Analyzer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit VXLAN_Analyzer(Connection* conn) : Analyzer("VXLAN", conn) { }
|
|
||||||
|
|
||||||
void Done() override;
|
|
||||||
|
|
||||||
void DeliverPacket(int len, const u_char* data, bool orig, uint64_t seq, const IP_Hdr* ip,
|
|
||||||
int caplen) override;
|
|
||||||
|
|
||||||
static analyzer::Analyzer* Instantiate(Connection* conn) { return new VXLAN_Analyzer(conn); }
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace zeek::analyzer::vxlan
|
|
|
@ -1,12 +0,0 @@
|
||||||
## Generated for any packet encapsulated in a VXLAN tunnel.
|
|
||||||
## See :rfc:`7348` for more information about the VXLAN protocol.
|
|
||||||
##
|
|
||||||
## outer: The VXLAN tunnel connection.
|
|
||||||
##
|
|
||||||
## inner: The VXLAN-encapsulated Ethernet packet header and transport header.
|
|
||||||
##
|
|
||||||
## vni: VXLAN Network Identifier.
|
|
||||||
##
|
|
||||||
## .. note:: Since this event may be raised on a per-packet basis, handling
|
|
||||||
## it may become particularly expensive for real-time analysis.
|
|
||||||
event vxlan_packet%(outer: connection, inner: pkt_hdr, vni: count%);
|
|
Loading…
Add table
Add a link
Reference in a new issue