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 teredo_ports = { 3544/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
|
||||
{
|
||||
|
@ -93,6 +94,7 @@ event bro_init() &priority=5
|
|||
|
||||
Analyzer::register_for_ports(Analyzer::ANALYZER_AYIYA, ayiya_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);
|
||||
}
|
||||
|
||||
|
|
|
@ -88,6 +88,7 @@ public:
|
|||
return false;
|
||||
|
||||
if ( ec1.type == BifEnum::Tunnel::IP ||
|
||||
ec1.type == BifEnum::Tunnel::VXLAN ||
|
||||
ec1.type == BifEnum::Tunnel::GRE )
|
||||
// Reversing endpoints is still same tunnel.
|
||||
return ec1.uid == ec2.uid && ec1.proto == ec2.proto &&
|
||||
|
|
|
@ -47,5 +47,6 @@ add_subdirectory(syslog)
|
|||
add_subdirectory(tcp)
|
||||
add_subdirectory(teredo)
|
||||
add_subdirectory(udp)
|
||||
add_subdirectory(vxlan)
|
||||
add_subdirectory(xmpp)
|
||||
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_gtpv1: bool;
|
||||
const Tunnel::enable_gre: bool;
|
||||
const Tunnel::enable_vxlan: bool;
|
||||
const Tunnel::delay_teredo_confirmation: bool;
|
||||
const Tunnel::delay_gtp_confirmation: bool;
|
||||
const Tunnel::ip_tunnel_timeout: interval;
|
||||
|
|
|
@ -192,6 +192,7 @@ enum Type %{
|
|||
GTPv1,
|
||||
HTTP,
|
||||
GRE,
|
||||
VXLAN,
|
||||
%}
|
||||
|
||||
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