mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
Initial VXLAN support, need -C flag to work when running bro
This commit is contained in:
parent
a36ac12e88
commit
f4088be8a6
13 changed files with 339 additions and 1 deletions
|
@ -85,7 +85,8 @@ export {
|
||||||
const ayiya_ports = { 5072/udp };
|
const ayiya_ports = { 5072/udp };
|
||||||
const teredo_ports = { 3544/udp };
|
const teredo_ports = { 3544/udp };
|
||||||
const gtpv1_ports = { 2152/udp, 2123/udp };
|
const gtpv1_ports = { 2152/udp, 2123/udp };
|
||||||
redef likely_server_ports += { ayiya_ports, teredo_ports, gtpv1_ports };
|
const vxlan_ports = { 4789/udp };
|
||||||
|
redef likely_server_ports += { ayiya_ports, teredo_ports, gtpv1_ports, vxlan_ports };
|
||||||
|
|
||||||
event bro_init() &priority=5
|
event bro_init() &priority=5
|
||||||
{
|
{
|
||||||
|
@ -93,6 +94,7 @@ event bro_init() &priority=5
|
||||||
|
|
||||||
Analyzer::register_for_ports(Analyzer::ANALYZER_AYIYA, ayiya_ports);
|
Analyzer::register_for_ports(Analyzer::ANALYZER_AYIYA, ayiya_ports);
|
||||||
Analyzer::register_for_ports(Analyzer::ANALYZER_TEREDO, teredo_ports);
|
Analyzer::register_for_ports(Analyzer::ANALYZER_TEREDO, teredo_ports);
|
||||||
|
Analyzer::register_for_ports(Analyzer::ANALYZER_VXLAN, vxlan_ports);
|
||||||
Analyzer::register_for_ports(Analyzer::ANALYZER_GTPV1, gtpv1_ports);
|
Analyzer::register_for_ports(Analyzer::ANALYZER_GTPV1, gtpv1_ports);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -88,6 +88,7 @@ public:
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if ( ec1.type == BifEnum::Tunnel::IP ||
|
if ( ec1.type == BifEnum::Tunnel::IP ||
|
||||||
|
ec1.type == BifEnum::Tunnel::VXLAN ||
|
||||||
ec1.type == BifEnum::Tunnel::GRE )
|
ec1.type == BifEnum::Tunnel::GRE )
|
||||||
// Reversing endpoints is still same tunnel.
|
// Reversing endpoints is still same tunnel.
|
||||||
return ec1.uid == ec2.uid && ec1.proto == ec2.proto &&
|
return ec1.uid == ec2.uid && ec1.proto == ec2.proto &&
|
||||||
|
|
|
@ -47,5 +47,6 @@ add_subdirectory(syslog)
|
||||||
add_subdirectory(tcp)
|
add_subdirectory(tcp)
|
||||||
add_subdirectory(teredo)
|
add_subdirectory(teredo)
|
||||||
add_subdirectory(udp)
|
add_subdirectory(udp)
|
||||||
|
add_subdirectory(vxlan)
|
||||||
add_subdirectory(xmpp)
|
add_subdirectory(xmpp)
|
||||||
add_subdirectory(zip)
|
add_subdirectory(zip)
|
||||||
|
|
9
src/analyzer/protocol/vxlan/CMakeLists.txt
Normal file
9
src/analyzer/protocol/vxlan/CMakeLists.txt
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
|
||||||
|
include(BroPlugin)
|
||||||
|
|
||||||
|
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
|
bro_plugin_begin(Bro VXLAN)
|
||||||
|
bro_plugin_cc(VXLAN.cc Plugin.cc)
|
||||||
|
bro_plugin_bif(events.bif)
|
||||||
|
bro_plugin_end()
|
25
src/analyzer/protocol/vxlan/Plugin.cc
Normal file
25
src/analyzer/protocol/vxlan/Plugin.cc
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
// See the file in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
|
||||||
|
#include "plugin/Plugin.h"
|
||||||
|
|
||||||
|
#include "VXLAN.h"
|
||||||
|
|
||||||
|
namespace plugin {
|
||||||
|
namespace Bro_VXLAN {
|
||||||
|
|
||||||
|
class Plugin : public plugin::Plugin {
|
||||||
|
public:
|
||||||
|
plugin::Configuration Configure()
|
||||||
|
{
|
||||||
|
AddComponent(new ::analyzer::Component("VXLAN", ::analyzer::vxlan::VXLAN_Analyzer::Instantiate));
|
||||||
|
|
||||||
|
plugin::Configuration config;
|
||||||
|
config.name = "Bro::VXLAN";
|
||||||
|
config.description = "VXLAN analyzer";
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
} plugin;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
169
src/analyzer/protocol/vxlan/VXLAN.cc
Normal file
169
src/analyzer/protocol/vxlan/VXLAN.cc
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
|
||||||
|
#include "VXLAN.h"
|
||||||
|
#include "TunnelEncapsulation.h"
|
||||||
|
#include "Conn.h"
|
||||||
|
#include "IP.h"
|
||||||
|
#include "../arp/ARP.h"
|
||||||
|
#include "Reporter.h"
|
||||||
|
|
||||||
|
#include "events.bif.h"
|
||||||
|
|
||||||
|
using namespace analyzer::vxlan;
|
||||||
|
|
||||||
|
void VXLAN_Analyzer::Done()
|
||||||
|
{
|
||||||
|
Analyzer::Done();
|
||||||
|
Event(udp_session_done);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VXLANEncapsulation::DoParse(const u_char* data, int& len)
|
||||||
|
{
|
||||||
|
int eth_len = 14;
|
||||||
|
int vxlan_len = 8;
|
||||||
|
int eth_mac = 6;
|
||||||
|
int proto = 0;
|
||||||
|
reporter->Error("VXLANEncapsulation::DoParse len: %d", len);
|
||||||
|
/* Note: outer Ethernet, IP, UDP layers already skipped */
|
||||||
|
if ( len < vxlan_len )
|
||||||
|
{
|
||||||
|
Weird("VXLAN_truncated missing VXLAN header");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* Flags (8 bits): where the I flag MUST be set to 1 for a valid
|
||||||
|
VXLAN Network ID (VNI). The other 7 bits (designated "R") are
|
||||||
|
reserved fields and MUST be set to zero on transmission and
|
||||||
|
ignored on receipt.*/
|
||||||
|
if ( ! (data[0] & 0x8) )
|
||||||
|
{
|
||||||
|
Weird("VXLAN_flags packet missing I flag set ");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ( len < vxlan_len + eth_len )
|
||||||
|
{
|
||||||
|
Weird("VXLAN_truncated missing inner packet header");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
printf("Checking packet ethertype for inner packet:\n");
|
||||||
|
uint16 proto_typ = ntohs(*((uint16*)(data+vxlan_len+2*eth_mac)));
|
||||||
|
if ( proto_typ == 0x0800 )
|
||||||
|
proto = IPPROTO_IPV4;
|
||||||
|
else if ( proto_typ == 0x86dd )
|
||||||
|
proto = IPPROTO_IPV6;
|
||||||
|
else {
|
||||||
|
Weird("VXLAN_ethertype inner packet should be ethertype: IPv4 or IPv6");
|
||||||
|
int i;
|
||||||
|
for (i=0; i < 2; i++)
|
||||||
|
printf("%02x ",data[vxlan_len+2*eth_mac+i]);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
data += vxlan_len + eth_len;
|
||||||
|
len -= vxlan_len + eth_len;
|
||||||
|
inner_ip = data;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
RecordVal* VXLANEncapsulation::BuildVal(const IP_Hdr* inner) const
|
||||||
|
{
|
||||||
|
static RecordType* vxlan_hdr_type = 0;
|
||||||
|
static RecordType* vxlan_auth_type = 0;
|
||||||
|
static RecordType* vxlan_origin_type = 0;
|
||||||
|
reporter->Error("VXLANEncapsulation::BuildVal");
|
||||||
|
|
||||||
|
RecordVal* vxlan_hdr = new RecordVal(vxlan_hdr_type);
|
||||||
|
vxlan_hdr->Assign(1, inner->BuildPktHdrVal());
|
||||||
|
return vxlan_hdr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VXLAN_Analyzer::DeliverPacket(int len, const u_char* data, bool orig,
|
||||||
|
uint64 seq, const IP_Hdr* ip, int caplen)
|
||||||
|
{
|
||||||
|
Analyzer::DeliverPacket(len, data, orig, seq, ip, caplen);
|
||||||
|
/* Note: it seems we get the packet AFTER UDP header. */
|
||||||
|
|
||||||
|
VXLANEncapsulation vx(this);
|
||||||
|
|
||||||
|
// If a carried packet has ethernet, this will help skip it.
|
||||||
|
int eth_len = 14;
|
||||||
|
int udp_len = 8;
|
||||||
|
int vlan_len = 4;
|
||||||
|
int vxlan_len = 8;
|
||||||
|
int eth_mac = 6;
|
||||||
|
int i = 0;
|
||||||
|
int vni= 0;
|
||||||
|
int proto = 0;
|
||||||
|
|
||||||
|
const EncapsulationStack* e = Conn()->GetEncapsulation();
|
||||||
|
IP_Hdr* inner = 0;
|
||||||
|
int rslt = sessions->ParseIPPacket(len, data + vxlan_len + eth_len, IPPROTO_IPV4, inner);
|
||||||
|
|
||||||
|
reporter->Info("VXLAN_Analyzer::DeliverPacket");
|
||||||
|
reporter->Info("len: %d", len);
|
||||||
|
printf("Packet hex:\n");
|
||||||
|
for (i=0; i < len; i++)
|
||||||
|
printf("%0x ",data[i]);
|
||||||
|
printf("\n");
|
||||||
|
/* Note: outer Ethernet, IP, UDP layers already skipped */
|
||||||
|
if ( len < vxlan_len )
|
||||||
|
{
|
||||||
|
Weird("VXLAN_truncated missing VXLAN header");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* Flags (8 bits): where the I flag MUST be set to 1 for a valid
|
||||||
|
VXLAN Network ID (VNI). The other 7 bits (designated "R") are
|
||||||
|
reserved fields and MUST be set to zero on transmission and
|
||||||
|
ignored on receipt.*/
|
||||||
|
if ( ! (data[0] & 0x8) )
|
||||||
|
{
|
||||||
|
Weird("VXLAN_flags packet missing I flag set ");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( len < vxlan_len + eth_len )
|
||||||
|
{
|
||||||
|
Weird("VXLAN_truncated missing inner packet header");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
printf("Checking packet ethertype for inner packet:\n");
|
||||||
|
uint16 proto_typ = ntohs(*((uint16*)(data+vxlan_len+2*eth_mac)));
|
||||||
|
switch (proto_typ)
|
||||||
|
{
|
||||||
|
case 0x0800:
|
||||||
|
proto = IPPROTO_IPV4;
|
||||||
|
break;
|
||||||
|
case 0x86dd:
|
||||||
|
proto = IPPROTO_IPV6;
|
||||||
|
break;
|
||||||
|
case 0x8100:
|
||||||
|
case 0x9100:
|
||||||
|
/* 802.1q / 802.1ad */
|
||||||
|
proto = proto_typ;
|
||||||
|
if (len < vxlan_len + eth_len + vlan_len)
|
||||||
|
{
|
||||||
|
Weird("VXLAN truncated inner packet VLAN ether header ");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* Set type then to next ethertype ? */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Weird("VXLAN_ethertype inner packet should be ethertype: VLAN, IPv4 or IPv6");
|
||||||
|
int i;
|
||||||
|
for (i=0; i < 2; i++)
|
||||||
|
printf("%02x ",data[vxlan_len+2*eth_mac+i]);
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Packet safety checks done\n");
|
||||||
|
vni = (data[4] << 16) + (data[5] << 8) + (data[6] << 0);
|
||||||
|
printf("VXLAN VNI %d\n",vni);
|
||||||
|
|
||||||
|
/* Do we want the inner packet with or without Ethernet header?
|
||||||
|
data += vxlan_len + udp_len + eth_len;
|
||||||
|
len -= vxlan_len + udp_len + eth_len;
|
||||||
|
caplen -= vxlan_len + udp_len + eth_len;
|
||||||
|
*/
|
||||||
|
data += udp_len + vxlan_len;
|
||||||
|
len -= udp_len + vxlan_len;
|
||||||
|
caplen -= udp_len + vxlan_len;
|
||||||
|
EncapsulatingConn ec(Conn(), BifEnum::Tunnel::VXLAN);
|
||||||
|
sessions->DoNextInnerPacket(network_time, 0, inner, e, ec);
|
||||||
|
}
|
87
src/analyzer/protocol/vxlan/VXLAN.h
Normal file
87
src/analyzer/protocol/vxlan/VXLAN.h
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
#ifndef ANALYZER_PROTOCOL_VXLAN_VXLAN_H
|
||||||
|
#define ANALYZER_PROTOCOL_VXLAN_VXLAN_H
|
||||||
|
|
||||||
|
#include "analyzer/Analyzer.h"
|
||||||
|
#include "NetVar.h"
|
||||||
|
#include "Reporter.h"
|
||||||
|
|
||||||
|
namespace analyzer { namespace vxlan {
|
||||||
|
|
||||||
|
class VXLAN_Analyzer : public analyzer::Analyzer {
|
||||||
|
public:
|
||||||
|
explicit VXLAN_Analyzer(Connection* conn) : Analyzer("VXLAN", conn),
|
||||||
|
valid_orig(false), valid_resp(false)
|
||||||
|
{}
|
||||||
|
|
||||||
|
~VXLAN_Analyzer() override
|
||||||
|
{}
|
||||||
|
|
||||||
|
void Done() override;
|
||||||
|
|
||||||
|
void DeliverPacket(int len, const u_char* data, bool orig,
|
||||||
|
uint64 seq, const IP_Hdr* ip, int caplen) override;
|
||||||
|
|
||||||
|
static analyzer::Analyzer* Instantiate(Connection* conn)
|
||||||
|
{ return new VXLAN_Analyzer(conn); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emits a weird only if the analyzer has previously been able to
|
||||||
|
* decapsulate a VXLAN 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 ( ProtocolConfirmed() || force )
|
||||||
|
reporter->Weird(Conn(), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the delayed confirmation option is set, then a valid encapsulation
|
||||||
|
* seen from both end points is required before confirming.
|
||||||
|
*/
|
||||||
|
/* copied from Teredo, do we want this too for VXLAN?
|
||||||
|
void Confirm()
|
||||||
|
{
|
||||||
|
if ( ! BifConst::Tunnel::delay_vxlan_confirmation ||
|
||||||
|
( valid_orig && valid_resp ) )
|
||||||
|
ProtocolConfirmation();
|
||||||
|
}*/
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool valid_orig;
|
||||||
|
bool valid_resp;
|
||||||
|
};
|
||||||
|
|
||||||
|
class VXLANEncapsulation {
|
||||||
|
public:
|
||||||
|
explicit VXLANEncapsulation(const VXLAN_Analyzer* ta)
|
||||||
|
: inner_ip(0), analyzer(ta)
|
||||||
|
{}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether input data parsed as a valid VXLAN encapsulation type.
|
||||||
|
* If it was valid, the len argument is decremented appropriately.
|
||||||
|
*/
|
||||||
|
bool Parse(const u_char* data, int& len)
|
||||||
|
{ return DoParse(data, len); }
|
||||||
|
|
||||||
|
const u_char* InnerIP() const
|
||||||
|
{ return inner_ip; }
|
||||||
|
|
||||||
|
RecordVal* BuildVal(const IP_Hdr* inner) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool DoParse(const u_char* data, int& len);
|
||||||
|
|
||||||
|
void Weird(const char* name) const
|
||||||
|
{ analyzer->Weird(name); }
|
||||||
|
|
||||||
|
const u_char* inner_ip;
|
||||||
|
const VXLAN_Analyzer* analyzer;
|
||||||
|
};
|
||||||
|
|
||||||
|
} } // namespace analyzer::*
|
||||||
|
|
||||||
|
#endif
|
12
src/analyzer/protocol/vxlan/events.bif
Normal file
12
src/analyzer/protocol/vxlan/events.bif
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
## 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.
|
||||||
|
##
|
||||||
|
## .. bro:see:: vxlan_authentication vxlan_origin_indication vxlan_bubble
|
||||||
|
##
|
||||||
|
## .. 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: vxlan_hdr%);
|
|
@ -19,6 +19,7 @@ const Tunnel::enable_ayiya: bool;
|
||||||
const Tunnel::enable_teredo: bool;
|
const Tunnel::enable_teredo: bool;
|
||||||
const Tunnel::enable_gtpv1: bool;
|
const Tunnel::enable_gtpv1: bool;
|
||||||
const Tunnel::enable_gre: bool;
|
const Tunnel::enable_gre: bool;
|
||||||
|
const Tunnel::enable_vxlan: bool;
|
||||||
const Tunnel::delay_teredo_confirmation: bool;
|
const Tunnel::delay_teredo_confirmation: bool;
|
||||||
const Tunnel::delay_gtp_confirmation: bool;
|
const Tunnel::delay_gtp_confirmation: bool;
|
||||||
const Tunnel::ip_tunnel_timeout: interval;
|
const Tunnel::ip_tunnel_timeout: interval;
|
||||||
|
|
|
@ -192,6 +192,7 @@ enum Type %{
|
||||||
GTPv1,
|
GTPv1,
|
||||||
HTTP,
|
HTTP,
|
||||||
GRE,
|
GRE,
|
||||||
|
VXLAN,
|
||||||
%}
|
%}
|
||||||
|
|
||||||
type EncapsulatingConn: record;
|
type EncapsulatingConn: record;
|
||||||
|
|
14
testing/btest/Baseline/core.tunnels.vxlan/conn.log
Normal file
14
testing/btest/Baseline/core.tunnels.vxlan/conn.log
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#separator \x09
|
||||||
|
#set_separator ,
|
||||||
|
#empty_field (empty)
|
||||||
|
#unset_field -
|
||||||
|
#path conn
|
||||||
|
#open 2018-10-18-11-51-46
|
||||||
|
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state local_orig local_resp missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes tunnel_parents
|
||||||
|
#types time string addr port addr port enum string interval count count string bool bool count string count count count count set[string]
|
||||||
|
1368908504.882198 CUY3VO38piNbzBWoCf 192.168.202.1 42710 192.168.203.1 4789 udp - - - - S0 - - 0 D 1 78 0 0 -
|
||||||
|
1368908504.882536 C938WE2Zxjsr1dQt8 192.168.203.1 52102 192.168.202.1 4789 udp - - - - S0 - - 0 D 1 78 0 0 -
|
||||||
|
1368908504.925960 CPPxeT3vy9lhCeFyzf 192.168.202.1 32894 192.168.203.1 4789 udp - 2.959399 424 0 S0 - - 0 D 4 536 0 0 -
|
||||||
|
1368908504.837063 CAL8II3MrNKoLygbR 192.168.203.1 45149 192.168.202.1 4789 udp - 3.004913 424 0 S0 - - 0 D 4 536 0 0 -
|
||||||
|
1368908504.837063 C3MYEy2ilZOiJASuTk 192.168.203.3 8 192.168.203.5 0 icmp - 3.048296 224 224 OTH - - 0 - 4 336 4 336 CAL8II3MrNKoLygbR,CPPxeT3vy9lhCeFyzf
|
||||||
|
#close 2018-10-18-11-51-46
|
13
testing/btest/Baseline/core.tunnels.vxlan/tunnel.log
Normal file
13
testing/btest/Baseline/core.tunnels.vxlan/tunnel.log
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#separator \x09
|
||||||
|
#set_separator ,
|
||||||
|
#empty_field (empty)
|
||||||
|
#unset_field -
|
||||||
|
#path tunnel
|
||||||
|
#open 2018-10-18-11-51-46
|
||||||
|
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p tunnel_type action
|
||||||
|
#types time string addr port addr port enum enum
|
||||||
|
1368908504.837063 CAL8II3MrNKoLygbR 192.168.203.1 45149 192.168.202.1 4789 Tunnel::VXLAN Tunnel::DISCOVER
|
||||||
|
1368908504.925960 CPPxeT3vy9lhCeFyzf 192.168.202.1 32894 192.168.203.1 4789 Tunnel::VXLAN Tunnel::DISCOVER
|
||||||
|
1368908507.885359 CPPxeT3vy9lhCeFyzf 192.168.202.1 32894 192.168.203.1 4789 Tunnel::VXLAN Tunnel::CLOSE
|
||||||
|
1368908507.885359 CAL8II3MrNKoLygbR 192.168.203.1 45149 192.168.202.1 4789 Tunnel::VXLAN Tunnel::CLOSE
|
||||||
|
#close 2018-10-18-11-51-46
|
3
testing/btest/core/tunnels/vxlan.test
Normal file
3
testing/btest/core/tunnels/vxlan.test
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# @TEST-EXEC: bro -r $TRACES/tunnels/vxlan-sample.pcap
|
||||||
|
# @TEST-EXEC: btest-diff conn.log
|
||||||
|
# @TEST-EXEC: btest-diff tunnel.log
|
Loading…
Add table
Add a link
Reference in a new issue