Initial VXLAN support, need -C flag to work when running bro

This commit is contained in:
Henrik Lund Kramshoej 2018-10-17 09:23:21 +02:00 committed by Jon Siwek
parent a36ac12e88
commit f4088be8a6
13 changed files with 339 additions and 1 deletions

View file

@ -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);
} }

View file

@ -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 &&

View file

@ -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)

View 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()

View 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;
}
}

View 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);
}

View 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

View 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%);

View file

@ -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;

View file

@ -192,6 +192,7 @@ enum Type %{
GTPv1, GTPv1,
HTTP, HTTP,
GRE, GRE,
VXLAN,
%} %}
type EncapsulatingConn: record; type EncapsulatingConn: record;

View 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

View 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

View 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