mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
Initial implementation of Lower-Level analyzers
This commit is contained in:
parent
f744d4c070
commit
b2e6c9ac9a
146 changed files with 3967 additions and 613 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -4,7 +4,7 @@ tmp
|
|||
|
||||
# Configuration and build directories for CLion
|
||||
.idea
|
||||
cmake-build-debug
|
||||
cmake-build-*
|
||||
|
||||
# skip DS Store for MacOS
|
||||
.DS_Store
|
||||
|
|
|
@ -5341,3 +5341,30 @@ event net_done(t: time)
|
|||
# execution would be another idea.
|
||||
@if ( __init_primary_bifs() )
|
||||
@endif
|
||||
|
||||
module LLAnalyzer;
|
||||
|
||||
# Defines a mapping for the LLAnalyzer's configuration tree. This
|
||||
# maps from a parent analyzer to a child analyzer through a numeric
|
||||
# identifier.
|
||||
export {
|
||||
type ConfigEntry : record {
|
||||
# The parent analyzer. This analyzer will check for the *identifier* in the
|
||||
# packet data to know whether to call the next analyzer. This field is optional.
|
||||
# If it is not included, the identifier will attach to the "root" analyzer. This
|
||||
# means that the identifier will be searched for the initial packet header instead
|
||||
# of later headers.
|
||||
parent : LLAnalyzer::Tag &optional;
|
||||
|
||||
# A numeric identifier that can be found in the packet data that denotes an
|
||||
# analyzer should be called.
|
||||
identifier : count;
|
||||
|
||||
# The analyzer that corresponds to the above identifier.
|
||||
analyzer : LLAnalyzer::Tag;
|
||||
};
|
||||
|
||||
const config_map : vector of LLAnalyzer::ConfigEntry &redef;
|
||||
}
|
||||
|
||||
@load base/llprotocols
|
||||
|
|
11
scripts/base/llprotocols/__load__.zeek
Normal file
11
scripts/base/llprotocols/__load__.zeek
Normal file
|
@ -0,0 +1,11 @@
|
|||
@load base/llprotocols/default
|
||||
@load base/llprotocols/ethernet
|
||||
@load base/llprotocols/fddi
|
||||
@load base/llprotocols/ieee802_11
|
||||
@load base/llprotocols/ieee802_11_radio
|
||||
@load base/llprotocols/linux_sll
|
||||
@load base/llprotocols/nflog
|
||||
@load base/llprotocols/null
|
||||
@load base/llprotocols/ppp_serial
|
||||
@load base/llprotocols/pppoe
|
||||
@load base/llprotocols/vlan
|
1
scripts/base/llprotocols/default/__load__.zeek
Normal file
1
scripts/base/llprotocols/default/__load__.zeek
Normal file
|
@ -0,0 +1 @@
|
|||
@load ./main
|
6
scripts/base/llprotocols/default/main.zeek
Normal file
6
scripts/base/llprotocols/default/main.zeek
Normal file
|
@ -0,0 +1,6 @@
|
|||
module LL_DEFAULT;
|
||||
|
||||
redef LLAnalyzer::config_map += {
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_DEFAULTANALYZER, $identifier=4, $analyzer=LLAnalyzer::LLANALYZER_IPV4),
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_DEFAULTANALYZER, $identifier=6, $analyzer=LLAnalyzer::LLANALYZER_IPV6)
|
||||
};
|
1
scripts/base/llprotocols/ethernet/__load__.zeek
Normal file
1
scripts/base/llprotocols/ethernet/__load__.zeek
Normal file
|
@ -0,0 +1 @@
|
|||
@load ./main
|
16
scripts/base/llprotocols/ethernet/main.zeek
Normal file
16
scripts/base/llprotocols/ethernet/main.zeek
Normal file
|
@ -0,0 +1,16 @@
|
|||
module LL_ETHERNET;
|
||||
|
||||
const DLT_EN10MB : count = 1;
|
||||
|
||||
redef LLAnalyzer::config_map += {
|
||||
LLAnalyzer::ConfigEntry($identifier=DLT_EN10MB, $analyzer=LLAnalyzer::LLANALYZER_ETHERNET),
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_ETHERNET, $identifier=0x8847, $analyzer=LLAnalyzer::LLANALYZER_MPLS),
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_ETHERNET, $identifier=0x0800, $analyzer=LLAnalyzer::LLANALYZER_IPV4),
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_ETHERNET, $identifier=0x86DD, $analyzer=LLAnalyzer::LLANALYZER_IPV6),
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_ETHERNET, $identifier=0x0806, $analyzer=LLAnalyzer::LLANALYZER_ARP),
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_ETHERNET, $identifier=0x8035, $analyzer=LLAnalyzer::LLANALYZER_ARP),
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_ETHERNET, $identifier=0x8100, $analyzer=LLAnalyzer::LLANALYZER_VLAN),
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_ETHERNET, $identifier=0x88A8, $analyzer=LLAnalyzer::LLANALYZER_VLAN),
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_ETHERNET, $identifier=0x9100, $analyzer=LLAnalyzer::LLANALYZER_VLAN),
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_ETHERNET, $identifier=0x8864, $analyzer=LLAnalyzer::LLANALYZER_PPPOE)
|
||||
};
|
1
scripts/base/llprotocols/fddi/__load__.zeek
Normal file
1
scripts/base/llprotocols/fddi/__load__.zeek
Normal file
|
@ -0,0 +1 @@
|
|||
@load ./main
|
7
scripts/base/llprotocols/fddi/main.zeek
Normal file
7
scripts/base/llprotocols/fddi/main.zeek
Normal file
|
@ -0,0 +1,7 @@
|
|||
module LL_FDDI;
|
||||
|
||||
const DLT_FDDI : count = 10;
|
||||
|
||||
redef LLAnalyzer::config_map += {
|
||||
LLAnalyzer::ConfigEntry($identifier=DLT_FDDI, $analyzer=LLAnalyzer::LLANALYZER_FDDI)
|
||||
};
|
1
scripts/base/llprotocols/ieee802_11/__load__.zeek
Normal file
1
scripts/base/llprotocols/ieee802_11/__load__.zeek
Normal file
|
@ -0,0 +1 @@
|
|||
@load ./main
|
11
scripts/base/llprotocols/ieee802_11/main.zeek
Normal file
11
scripts/base/llprotocols/ieee802_11/main.zeek
Normal file
|
@ -0,0 +1,11 @@
|
|||
module LL_IEEE802_11;
|
||||
|
||||
const DLT_IEEE802_11 : count = 105;
|
||||
|
||||
redef LLAnalyzer::config_map += {
|
||||
LLAnalyzer::ConfigEntry($identifier=DLT_IEEE802_11, $analyzer=LLAnalyzer::LLANALYZER_IEEE802_11),
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_IEEE802_11, $identifier=0x0800, $analyzer=LLAnalyzer::LLANALYZER_IPV4),
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_IEEE802_11, $identifier=0x86DD, $analyzer=LLAnalyzer::LLANALYZER_IPV6),
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_IEEE802_11, $identifier=0x0806, $analyzer=LLAnalyzer::LLANALYZER_ARP),
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_IEEE802_11, $identifier=0x8035, $analyzer=LLAnalyzer::LLANALYZER_ARP)
|
||||
};
|
1
scripts/base/llprotocols/ieee802_11_radio/__load__.zeek
Normal file
1
scripts/base/llprotocols/ieee802_11_radio/__load__.zeek
Normal file
|
@ -0,0 +1 @@
|
|||
@load ./main
|
9
scripts/base/llprotocols/ieee802_11_radio/main.zeek
Normal file
9
scripts/base/llprotocols/ieee802_11_radio/main.zeek
Normal file
|
@ -0,0 +1,9 @@
|
|||
module LL_IEEE802_11_RADIO;
|
||||
|
||||
const DLT_IEEE802_11_RADIO : count = 127;
|
||||
const DLT_IEEE802_11 : count = 105;
|
||||
|
||||
redef LLAnalyzer::config_map += {
|
||||
LLAnalyzer::ConfigEntry($identifier=DLT_IEEE802_11_RADIO, $analyzer=LLAnalyzer::LLANALYZER_IEEE802_11_RADIO),
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_IEEE802_11_RADIO, $identifier=DLT_IEEE802_11, $analyzer=LLAnalyzer::LLANALYZER_IEEE802_11)
|
||||
};
|
1
scripts/base/llprotocols/linux_sll/__load__.zeek
Normal file
1
scripts/base/llprotocols/linux_sll/__load__.zeek
Normal file
|
@ -0,0 +1 @@
|
|||
@load ./main
|
12
scripts/base/llprotocols/linux_sll/main.zeek
Normal file
12
scripts/base/llprotocols/linux_sll/main.zeek
Normal file
|
@ -0,0 +1,12 @@
|
|||
module LL_LINUX_SLL;
|
||||
|
||||
const DLT_LINUX_SLL : count = 113;
|
||||
|
||||
redef LLAnalyzer::config_map += {
|
||||
LLAnalyzer::ConfigEntry($identifier=DLT_LINUX_SLL, $analyzer=LLAnalyzer::LLANALYZER_LINUXSLL),
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_LINUXSLL, $identifier=0x0800, $analyzer=LLAnalyzer::LLANALYZER_IPV4),
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_LINUXSLL, $identifier=0x86DD, $analyzer=LLAnalyzer::LLANALYZER_IPV6),
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_LINUXSLL, $identifier=0x0806, $analyzer=LLAnalyzer::LLANALYZER_ARP),
|
||||
# RARP
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_LINUXSLL, $identifier=0x8035, $analyzer=LLAnalyzer::LLANALYZER_ARP)
|
||||
};
|
1
scripts/base/llprotocols/nflog/__load__.zeek
Normal file
1
scripts/base/llprotocols/nflog/__load__.zeek
Normal file
|
@ -0,0 +1 @@
|
|||
@load ./main
|
11
scripts/base/llprotocols/nflog/main.zeek
Normal file
11
scripts/base/llprotocols/nflog/main.zeek
Normal file
|
@ -0,0 +1,11 @@
|
|||
module LL_NFLOG;
|
||||
|
||||
const DLT_NFLOG : count = 239;
|
||||
const AF_INET : count = 2;
|
||||
const AF_INET6 : count = 10;
|
||||
|
||||
redef LLAnalyzer::config_map += {
|
||||
LLAnalyzer::ConfigEntry($identifier=DLT_NFLOG, $analyzer=LLAnalyzer::LLANALYZER_NFLOG),
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_NFLOG, $identifier=AF_INET, $analyzer=LLAnalyzer::LLANALYZER_IPV4),
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_NFLOG, $identifier=AF_INET6, $analyzer=LLAnalyzer::LLANALYZER_IPV6)
|
||||
};
|
1
scripts/base/llprotocols/null/__load__.zeek
Normal file
1
scripts/base/llprotocols/null/__load__.zeek
Normal file
|
@ -0,0 +1 @@
|
|||
@load ./main
|
19
scripts/base/llprotocols/null/main.zeek
Normal file
19
scripts/base/llprotocols/null/main.zeek
Normal file
|
@ -0,0 +1,19 @@
|
|||
module LL_NULL;
|
||||
|
||||
const DLT_NULL : count = 0;
|
||||
const AF_INET : count = 2;
|
||||
const AF_INET6 : count = 10;
|
||||
|
||||
redef LLAnalyzer::config_map += {
|
||||
LLAnalyzer::ConfigEntry($identifier=DLT_NULL, $analyzer=LLAnalyzer::LLANALYZER_NULL),
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_NULL, $identifier=AF_INET, $analyzer=LLAnalyzer::LLANALYZER_IPV4),
|
||||
|
||||
## From the Wireshark Wiki: AF_INET6ANALYZER, unfortunately, has different values in
|
||||
## {NetBSD,OpenBSD,BSD/OS}, {FreeBSD,DragonFlyBSD}, and {Darwin/Mac OS X}, so an IPv6
|
||||
## packet might have a link-layer header with 24, 28, or 30 as the AF_ value. As we
|
||||
## may be reading traces captured on platforms other than what we're running on, we
|
||||
## accept them all here.
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_NULL, $identifier=24, $analyzer=LLAnalyzer::LLANALYZER_IPV6),
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_NULL, $identifier=28, $analyzer=LLAnalyzer::LLANALYZER_IPV6),
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_NULL, $identifier=30, $analyzer=LLAnalyzer::LLANALYZER_IPV6)
|
||||
};
|
1
scripts/base/llprotocols/ppp_serial/__load__.zeek
Normal file
1
scripts/base/llprotocols/ppp_serial/__load__.zeek
Normal file
|
@ -0,0 +1 @@
|
|||
@load ./main
|
10
scripts/base/llprotocols/ppp_serial/main.zeek
Normal file
10
scripts/base/llprotocols/ppp_serial/main.zeek
Normal file
|
@ -0,0 +1,10 @@
|
|||
module LL_PPP_SERIAL;
|
||||
|
||||
const DLT_PPP_SERIAL : count = 50;
|
||||
|
||||
redef LLAnalyzer::config_map += {
|
||||
LLAnalyzer::ConfigEntry($identifier=DLT_PPP_SERIAL, $analyzer=LLAnalyzer::LLANALYZER_PPPSERIAL),
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_PPPSERIAL, $identifier=0x0281, $analyzer=LLAnalyzer::LLANALYZER_MPLS),
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_PPPSERIAL, $identifier=0x0021, $analyzer=LLAnalyzer::LLANALYZER_IPV4),
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_PPPSERIAL, $identifier=0x0057, $analyzer=LLAnalyzer::LLANALYZER_IPV6)
|
||||
};
|
1
scripts/base/llprotocols/pppoe/__load__.zeek
Normal file
1
scripts/base/llprotocols/pppoe/__load__.zeek
Normal file
|
@ -0,0 +1 @@
|
|||
@load ./main
|
6
scripts/base/llprotocols/pppoe/main.zeek
Normal file
6
scripts/base/llprotocols/pppoe/main.zeek
Normal file
|
@ -0,0 +1,6 @@
|
|||
module LL_PPPOE;
|
||||
|
||||
redef LLAnalyzer::config_map += {
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_PPPOE, $identifier=0x0021, $analyzer=LLAnalyzer::LLANALYZER_IPV4),
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_PPPOE, $identifier=0x0057, $analyzer=LLAnalyzer::LLANALYZER_IPV6)
|
||||
};
|
1
scripts/base/llprotocols/vlan/__load__.zeek
Normal file
1
scripts/base/llprotocols/vlan/__load__.zeek
Normal file
|
@ -0,0 +1 @@
|
|||
@load ./main
|
11
scripts/base/llprotocols/vlan/main.zeek
Normal file
11
scripts/base/llprotocols/vlan/main.zeek
Normal file
|
@ -0,0 +1,11 @@
|
|||
module LL_VLAN;
|
||||
|
||||
redef LLAnalyzer::config_map += {
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_VLAN, $identifier=0x8847, $analyzer=LLAnalyzer::LLANALYZER_MPLS),
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_VLAN, $identifier=0x0800, $analyzer=LLAnalyzer::LLANALYZER_IPV4),
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_VLAN, $identifier=0x86DD, $analyzer=LLAnalyzer::LLANALYZER_IPV6),
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_VLAN, $identifier=0x0806, $analyzer=LLAnalyzer::LLANALYZER_ARP),
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_VLAN, $identifier=0x8035, $analyzer=LLAnalyzer::LLANALYZER_ARP),
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_VLAN, $identifier=0x8100, $analyzer=LLAnalyzer::LLANALYZER_VLAN),
|
||||
LLAnalyzer::ConfigEntry($parent=LLAnalyzer::LLANALYZER_VLAN, $identifier=0x8864, $analyzer=LLAnalyzer::LLANALYZER_PPPOE)
|
||||
};
|
|
@ -146,6 +146,7 @@ set(bro_PLUGIN_LIBS CACHE INTERNAL "plugin libraries" FORCE)
|
|||
set(bro_PLUGIN_DEPS CACHE INTERNAL "plugin dependencies" FORCE)
|
||||
|
||||
add_subdirectory(analyzer)
|
||||
add_subdirectory(llanalyzer)
|
||||
add_subdirectory(broker)
|
||||
add_subdirectory(zeekygen)
|
||||
add_subdirectory(file_analysis)
|
||||
|
|
|
@ -349,8 +349,8 @@ protected:
|
|||
TransportProto proto;
|
||||
uint32_t orig_flow_label, resp_flow_label; // most recent IPv6 flow labels
|
||||
uint32_t vlan, inner_vlan; // VLAN this connection traverses, if available
|
||||
u_char orig_l2_addr[Packet::l2_addr_len]; // Link-layer originator address, if available
|
||||
u_char resp_l2_addr[Packet::l2_addr_len]; // Link-layer responder address, if available
|
||||
u_char orig_l2_addr[Packet::L2_ADDR_LEN]; // Link-layer originator address, if available
|
||||
u_char resp_l2_addr[Packet::L2_ADDR_LEN]; // Link-layer responder address, if available
|
||||
double start_time, last_time;
|
||||
double inactivity_timeout;
|
||||
RecordValPtr conn_val;
|
||||
|
|
|
@ -19,18 +19,19 @@ DebugLogger::Stream DebugLogger::streams[NUM_DBGS] = {
|
|||
{ "string", 0, false },
|
||||
{ "notifiers", 0, false },
|
||||
{ "main-loop", 0, false },
|
||||
{ "llanalyzer", 0, false },
|
||||
{ "dpd", 0, false },
|
||||
{ "tm", 0, false },
|
||||
{ "logging", 0, false },
|
||||
{"input", 0, false },
|
||||
{ "input", 0, false },
|
||||
{ "threading", 0, false },
|
||||
{ "file_analysis", 0, false },
|
||||
{ "plugins", 0, false },
|
||||
{ "zeekygen", 0, false },
|
||||
{ "pktio", 0, false },
|
||||
{ "broker", 0, false },
|
||||
{ "scripts", 0, false},
|
||||
{ "supervisor", 0, false}
|
||||
{ "scripts", 0, false },
|
||||
{ "supervisor", 0, false }
|
||||
};
|
||||
|
||||
DebugLogger::DebugLogger()
|
||||
|
|
|
@ -35,6 +35,7 @@ enum DebugStream {
|
|||
DBG_STRING, // String code
|
||||
DBG_NOTIFIERS, // Notifiers
|
||||
DBG_MAINLOOP, // Main IOSource loop
|
||||
DBG_LLANALYZER, // Low-Layer Analyzer Proof of Concept
|
||||
DBG_ANALYZER, // Analyzer framework
|
||||
DBG_TM, // Time-machine packet input via Brocolli
|
||||
DBG_LOGGING, // Logging streams
|
||||
|
|
|
@ -188,7 +188,6 @@ void NetSessions::NextPacket(double t, const Packet* pkt)
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
if ( dump_this_packet && ! zeek::detail::record_all_packets )
|
||||
DumpPacket(pkt);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "Desc.h"
|
||||
#include "IP.h"
|
||||
#include "iosource/Manager.h"
|
||||
#include "llanalyzer/Manager.h"
|
||||
#include "Var.h"
|
||||
|
||||
extern "C" {
|
||||
|
@ -45,7 +46,7 @@ void Packet::Init(int arg_link_type, pkt_timeval *arg_ts, uint32_t arg_caplen,
|
|||
data = arg_data;
|
||||
|
||||
time = ts.tv_sec + double(ts.tv_usec) / 1e6;
|
||||
hdr_size = GetLinkHeaderSize(arg_link_type);
|
||||
hdr_size = 0;
|
||||
eth_type = 0;
|
||||
vlan = 0;
|
||||
inner_vlan = 0;
|
||||
|
@ -58,14 +59,18 @@ void Packet::Init(int arg_link_type, pkt_timeval *arg_ts, uint32_t arg_caplen,
|
|||
l3_proto = L3_UNKNOWN;
|
||||
l3_checksummed = false;
|
||||
|
||||
if ( data && cap_len < hdr_size )
|
||||
{
|
||||
Weird("truncated_link_header");
|
||||
return;
|
||||
}
|
||||
// For ll-analyzer: cur_pos points to the next payload.
|
||||
cur_pos = data;
|
||||
|
||||
if ( data )
|
||||
ProcessLayer2();
|
||||
{
|
||||
// From here we assume that layer 2 is valid. If an ll-analyzer encounters
|
||||
// an issue, it will call Packet::Weird(), which sets l2_valid to false.
|
||||
l2_valid = true;
|
||||
llanalyzer_mgr->ProcessPacket(this);
|
||||
// Calculate header size after processing lower layers.
|
||||
hdr_size = cur_pos - data;
|
||||
}
|
||||
}
|
||||
|
||||
const IP_Hdr Packet::IP() const
|
||||
|
@ -79,521 +84,12 @@ void Packet::Weird(const char* name)
|
|||
l2_valid = false;
|
||||
}
|
||||
|
||||
int Packet::GetLinkHeaderSize(int link_type)
|
||||
const u_char* const Packet::GetEndOfData() const
|
||||
{
|
||||
switch ( link_type ) {
|
||||
case DLT_NULL:
|
||||
return 4;
|
||||
|
||||
case DLT_EN10MB:
|
||||
return 14;
|
||||
|
||||
case DLT_FDDI:
|
||||
return 13 + 8; // fddi_header + LLC
|
||||
|
||||
#ifdef DLT_LINUX_SLL
|
||||
case DLT_LINUX_SLL:
|
||||
return 16;
|
||||
#endif
|
||||
|
||||
case DLT_PPP_SERIAL: // PPP_SERIAL
|
||||
return 4;
|
||||
|
||||
case DLT_IEEE802_11: // 802.11 monitor
|
||||
return 34;
|
||||
|
||||
case DLT_IEEE802_11_RADIO: // 802.11 plus RadioTap
|
||||
return 59;
|
||||
|
||||
case DLT_NFLOG:
|
||||
// Linux netlink NETLINK NFLOG socket log messages
|
||||
// The actual header size is variable, but we return the minimum
|
||||
// expected size here, which is 4 bytes for the main header plus at
|
||||
// least 2 bytes each for the type and length values assoicated with
|
||||
// the final TLV carrying the packet payload.
|
||||
return 8;
|
||||
|
||||
case DLT_RAW:
|
||||
return 0;
|
||||
return data + cap_len;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Packet::ProcessLayer2()
|
||||
{
|
||||
l2_valid = true;
|
||||
|
||||
// Unfortunately some packets on the link might have MPLS labels
|
||||
// while others don't. That means we need to ask the link-layer if
|
||||
// labels are in place.
|
||||
bool have_mpls = false;
|
||||
|
||||
const u_char* pdata = data;
|
||||
const u_char* end_of_data = data + cap_len;
|
||||
|
||||
switch ( link_type ) {
|
||||
case DLT_NULL:
|
||||
{
|
||||
int protocol = (pdata[3] << 24) + (pdata[2] << 16) + (pdata[1] << 8) + pdata[0];
|
||||
pdata += GetLinkHeaderSize(link_type);
|
||||
|
||||
// From the Wireshark Wiki: "AF_INET6, unfortunately, has
|
||||
// different values in {NetBSD,OpenBSD,BSD/OS},
|
||||
// {FreeBSD,DragonFlyBSD}, and {Darwin/Mac OS X}, so an IPv6
|
||||
// packet might have a link-layer header with 24, 28, or 30
|
||||
// as the AF_ value." As we may be reading traces captured on
|
||||
// platforms other than what we're running on, we accept them
|
||||
// all here.
|
||||
|
||||
if ( protocol == AF_INET )
|
||||
l3_proto = L3_IPV4;
|
||||
else if ( protocol == 24 || protocol == 28 || protocol == 30 )
|
||||
l3_proto = L3_IPV6;
|
||||
else
|
||||
{
|
||||
Weird("non_ip_packet_in_null_transport");
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case DLT_EN10MB:
|
||||
{
|
||||
// Skip past Cisco FabricPath to encapsulated ethernet frame.
|
||||
if ( pdata[12] == 0x89 && pdata[13] == 0x03 )
|
||||
{
|
||||
auto constexpr cfplen = 16;
|
||||
|
||||
if ( pdata + cfplen + GetLinkHeaderSize(link_type) >= end_of_data )
|
||||
{
|
||||
Weird("truncated_link_header_cfp");
|
||||
return;
|
||||
}
|
||||
|
||||
pdata += cfplen;
|
||||
}
|
||||
|
||||
// Get protocol being carried from the ethernet frame.
|
||||
int protocol = (pdata[12] << 8) + pdata[13];
|
||||
|
||||
eth_type = protocol;
|
||||
l2_dst = pdata;
|
||||
l2_src = pdata + 6;
|
||||
|
||||
pdata += GetLinkHeaderSize(link_type);
|
||||
|
||||
bool saw_vlan = false;
|
||||
|
||||
while ( protocol == 0x8100 || protocol == 0x9100 ||
|
||||
protocol == 0x8864 )
|
||||
{
|
||||
switch ( protocol )
|
||||
{
|
||||
// VLAN carried over the ethernet frame.
|
||||
// 802.1q / 802.1ad
|
||||
case 0x8100:
|
||||
case 0x9100:
|
||||
{
|
||||
if ( pdata + 4 >= end_of_data )
|
||||
{
|
||||
Weird("truncated_link_header");
|
||||
return;
|
||||
}
|
||||
|
||||
auto& vlan_ref = saw_vlan ? inner_vlan : vlan;
|
||||
vlan_ref = ((pdata[0] << 8) + pdata[1]) & 0xfff;
|
||||
protocol = ((pdata[2] << 8) + pdata[3]);
|
||||
pdata += 4; // Skip the vlan header
|
||||
saw_vlan = true;
|
||||
eth_type = protocol;
|
||||
}
|
||||
break;
|
||||
|
||||
// PPPoE carried over the ethernet frame.
|
||||
case 0x8864:
|
||||
{
|
||||
if ( pdata + 8 >= end_of_data )
|
||||
{
|
||||
Weird("truncated_link_header");
|
||||
return;
|
||||
}
|
||||
|
||||
protocol = (pdata[6] << 8) + pdata[7];
|
||||
pdata += 8; // Skip the PPPoE session and PPP header
|
||||
|
||||
if ( protocol == 0x0021 )
|
||||
l3_proto = L3_IPV4;
|
||||
else if ( protocol == 0x0057 )
|
||||
l3_proto = L3_IPV6;
|
||||
else
|
||||
{
|
||||
// Neither IPv4 nor IPv6.
|
||||
Weird("non_ip_packet_in_pppoe_encapsulation");
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for MPLS in VLAN.
|
||||
if ( protocol == 0x8847 )
|
||||
have_mpls = true;
|
||||
|
||||
// Normal path to determine Layer 3 protocol.
|
||||
if ( ! have_mpls && l3_proto == L3_UNKNOWN )
|
||||
{
|
||||
if ( protocol == 0x800 )
|
||||
l3_proto = L3_IPV4;
|
||||
else if ( protocol == 0x86dd )
|
||||
l3_proto = L3_IPV6;
|
||||
else if ( protocol == 0x0806 || protocol == 0x8035 )
|
||||
l3_proto = L3_ARP;
|
||||
else
|
||||
{
|
||||
// Neither IPv4 nor IPv6.
|
||||
Weird("non_ip_packet_in_ethernet");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case DLT_PPP_SERIAL:
|
||||
{
|
||||
// Get PPP protocol.
|
||||
int protocol = (pdata[2] << 8) + pdata[3];
|
||||
pdata += GetLinkHeaderSize(link_type);
|
||||
|
||||
if ( protocol == 0x0281 )
|
||||
{
|
||||
// MPLS Unicast. Remove the pdata link layer and
|
||||
// denote a header size of zero before the IP header.
|
||||
have_mpls = true;
|
||||
}
|
||||
else if ( protocol == 0x0021 )
|
||||
l3_proto = L3_IPV4;
|
||||
else if ( protocol == 0x0057 )
|
||||
l3_proto = L3_IPV6;
|
||||
else
|
||||
{
|
||||
// Neither IPv4 nor IPv6.
|
||||
Weird("non_ip_packet_in_ppp_encapsulation");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DLT_IEEE802_11_RADIO:
|
||||
{
|
||||
if ( pdata + 3 >= end_of_data )
|
||||
{
|
||||
Weird("truncated_radiotap_header");
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip over the RadioTap header
|
||||
int rtheader_len = (pdata[3] << 8) + pdata[2];
|
||||
|
||||
if ( pdata + rtheader_len >= end_of_data )
|
||||
{
|
||||
Weird("truncated_radiotap_header");
|
||||
return;
|
||||
}
|
||||
|
||||
pdata += rtheader_len;
|
||||
// fallthrough
|
||||
}
|
||||
|
||||
case DLT_IEEE802_11:
|
||||
{
|
||||
u_char len_80211 = 24; // minimal length of data frames
|
||||
|
||||
if ( pdata + len_80211 >= end_of_data )
|
||||
{
|
||||
Weird("truncated_802_11_header");
|
||||
return;
|
||||
}
|
||||
|
||||
u_char fc_80211 = pdata[0]; // Frame Control field
|
||||
|
||||
// Skip non-data frame types (management & control).
|
||||
if ( ! ((fc_80211 >> 2) & 0x02) )
|
||||
return;
|
||||
|
||||
// Skip subtypes without data.
|
||||
if ( (fc_80211 >> 4) & 0x04 )
|
||||
return;
|
||||
|
||||
// 'To DS' and 'From DS' flags set indicate use of the 4th
|
||||
// address field.
|
||||
if ( (pdata[1] & 0x03) == 0x03 )
|
||||
len_80211 += l2_addr_len;
|
||||
|
||||
// Look for the QoS indicator bit.
|
||||
if ( (fc_80211 >> 4) & 0x08 )
|
||||
{
|
||||
// Skip in case of A-MSDU subframes indicated by QoS
|
||||
// control field.
|
||||
if ( pdata[len_80211] & 0x80)
|
||||
return;
|
||||
|
||||
len_80211 += 2;
|
||||
}
|
||||
|
||||
if ( pdata + len_80211 >= end_of_data )
|
||||
{
|
||||
Weird("truncated_802_11_header");
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine link-layer addresses based
|
||||
// on 'To DS' and 'From DS' flags
|
||||
switch ( pdata[1] & 0x03 ) {
|
||||
case 0x00:
|
||||
l2_src = pdata + 10;
|
||||
l2_dst = pdata + 4;
|
||||
break;
|
||||
|
||||
case 0x01:
|
||||
l2_src = pdata + 10;
|
||||
l2_dst = pdata + 16;
|
||||
break;
|
||||
|
||||
case 0x02:
|
||||
l2_src = pdata + 16;
|
||||
l2_dst = pdata + 4;
|
||||
break;
|
||||
|
||||
case 0x03:
|
||||
l2_src = pdata + 24;
|
||||
l2_dst = pdata + 16;
|
||||
break;
|
||||
}
|
||||
|
||||
// skip 802.11 data header
|
||||
pdata += len_80211;
|
||||
|
||||
if ( pdata + 8 >= end_of_data )
|
||||
{
|
||||
Weird("truncated_802_11_header");
|
||||
return;
|
||||
}
|
||||
// Check that the DSAP and SSAP are both SNAP and that the control
|
||||
// field indicates that this is an unnumbered frame.
|
||||
// The organization code (24bits) needs to also be zero to
|
||||
// indicate that this is encapsulated ethernet.
|
||||
if ( pdata[0] == 0xAA && pdata[1] == 0xAA && pdata[2] == 0x03 &&
|
||||
pdata[3] == 0 && pdata[4] == 0 && pdata[5] == 0 )
|
||||
{
|
||||
pdata += 6;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If this is a logical link control frame without the
|
||||
// possibility of having a protocol we care about, we'll
|
||||
// just skip it for now.
|
||||
return;
|
||||
}
|
||||
|
||||
int protocol = (pdata[0] << 8) + pdata[1];
|
||||
if ( protocol == 0x0800 )
|
||||
l3_proto = L3_IPV4;
|
||||
else if ( protocol == 0x86DD )
|
||||
l3_proto = L3_IPV6;
|
||||
else if ( protocol == 0x0806 || protocol == 0x8035 )
|
||||
l3_proto = L3_ARP;
|
||||
else
|
||||
{
|
||||
Weird("non_ip_packet_in_ieee802_11");
|
||||
return;
|
||||
}
|
||||
pdata += 2;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case DLT_NFLOG:
|
||||
{
|
||||
// See https://www.tcpdump.org/linktypes/LINKTYPE_NFLOG.html
|
||||
|
||||
uint8_t protocol = pdata[0];
|
||||
|
||||
if ( protocol == AF_INET )
|
||||
l3_proto = L3_IPV4;
|
||||
else if ( protocol == AF_INET6 )
|
||||
l3_proto = L3_IPV6;
|
||||
else
|
||||
{
|
||||
Weird("non_ip_in_nflog");
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t version = pdata[1];
|
||||
|
||||
if ( version != 0 )
|
||||
{
|
||||
Weird("unknown_nflog_version");
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip to TLVs.
|
||||
pdata += 4;
|
||||
|
||||
uint16_t tlv_len;
|
||||
uint16_t tlv_type;
|
||||
|
||||
while ( true )
|
||||
{
|
||||
if ( pdata + 4 >= end_of_data )
|
||||
{
|
||||
Weird("nflog_no_pcap_payload");
|
||||
return;
|
||||
}
|
||||
|
||||
// TLV Type and Length values are specified in host byte order
|
||||
// (libpcap should have done any needed byteswapping already).
|
||||
|
||||
tlv_len = *(reinterpret_cast<const uint16_t*>(pdata));
|
||||
tlv_type = *(reinterpret_cast<const uint16_t*>(pdata + 2));
|
||||
|
||||
auto constexpr nflog_type_payload = 9;
|
||||
|
||||
if ( tlv_type == nflog_type_payload )
|
||||
{
|
||||
// The raw packet payload follows this TLV.
|
||||
pdata += 4;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The Length value includes the 4 octets for the Type and
|
||||
// Length values, but TLVs are also implicitly padded to
|
||||
// 32-bit alignments (that padding may not be included in
|
||||
// the Length value).
|
||||
|
||||
if ( tlv_len < 4 )
|
||||
{
|
||||
Weird("nflog_bad_tlv_len");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto rem = tlv_len % 4;
|
||||
|
||||
if ( rem != 0 )
|
||||
tlv_len += 4 - rem;
|
||||
}
|
||||
|
||||
pdata += tlv_len;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
// Assume we're pointing at IP. Just figure out which version.
|
||||
pdata += GetLinkHeaderSize(link_type);
|
||||
if ( pdata + sizeof(struct ip) >= end_of_data )
|
||||
{
|
||||
Weird("truncated_link_header");
|
||||
return;
|
||||
}
|
||||
|
||||
const struct ip* ip = (const struct ip *)pdata;
|
||||
|
||||
if ( ip->ip_v == 4 )
|
||||
l3_proto = L3_IPV4;
|
||||
else if ( ip->ip_v == 6 )
|
||||
l3_proto = L3_IPV6;
|
||||
else
|
||||
{
|
||||
// Neither IPv4 nor IPv6.
|
||||
Weird("non_ip_packet");
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( have_mpls )
|
||||
{
|
||||
// Skip the MPLS label stack.
|
||||
bool end_of_stack = false;
|
||||
|
||||
while ( ! end_of_stack )
|
||||
{
|
||||
if ( pdata + 4 >= end_of_data )
|
||||
{
|
||||
Weird("truncated_link_header");
|
||||
return;
|
||||
}
|
||||
|
||||
end_of_stack = *(pdata + 2) & 0x01;
|
||||
pdata += 4;
|
||||
}
|
||||
|
||||
// We assume that what remains is IP
|
||||
if ( pdata + sizeof(struct ip) >= end_of_data )
|
||||
{
|
||||
Weird("no_ip_in_mpls_payload");
|
||||
return;
|
||||
}
|
||||
|
||||
const struct ip* ip = (const struct ip *)pdata;
|
||||
|
||||
if ( ip->ip_v == 4 )
|
||||
l3_proto = L3_IPV4;
|
||||
else if ( ip->ip_v == 6 )
|
||||
l3_proto = L3_IPV6;
|
||||
else
|
||||
{
|
||||
// Neither IPv4 nor IPv6.
|
||||
Weird("no_ip_in_mpls_payload");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
else if ( zeek::detail::encap_hdr_size )
|
||||
{
|
||||
// Blanket encapsulation. We assume that what remains is IP.
|
||||
if ( pdata + zeek::detail::encap_hdr_size + sizeof(struct ip) >= end_of_data )
|
||||
{
|
||||
Weird("no_ip_left_after_encap");
|
||||
return;
|
||||
}
|
||||
|
||||
pdata += zeek::detail::encap_hdr_size;
|
||||
|
||||
const struct ip* ip = (const struct ip *)pdata;
|
||||
|
||||
if ( ip->ip_v == 4 )
|
||||
l3_proto = L3_IPV4;
|
||||
else if ( ip->ip_v == 6 )
|
||||
l3_proto = L3_IPV6;
|
||||
else
|
||||
{
|
||||
// Neither IPv4 nor IPv6.
|
||||
Weird("no_ip_in_encap");
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// We've now determined (a) L3_IPV4 vs (b) L3_IPV6 vs (c) L3_ARP vs
|
||||
// (d) L3_UNKNOWN.
|
||||
|
||||
// Calculate how much header we've used up.
|
||||
hdr_size = (pdata - data);
|
||||
}
|
||||
|
||||
RecordValPtr Packet::ToRawPktHdrVal() const
|
||||
IntrusivePtr<RecordVal> Packet::ToRawPktHdrVal() const
|
||||
{
|
||||
static auto raw_pkt_hdr_type = id::find_type<RecordType>("raw_pkt_hdr");
|
||||
static auto l2_hdr_type = id::find_type<RecordType>("l2_hdr");
|
||||
|
@ -684,11 +180,31 @@ ValPtr Packet::FmtEUI48(const u_char* mac) const
|
|||
}
|
||||
|
||||
void Packet::Describe(ODesc* d) const
|
||||
{
|
||||
switch ( l3_proto )
|
||||
{
|
||||
case L3_ARP:
|
||||
d->Add("ARP");
|
||||
break;
|
||||
case L3_IPV4:
|
||||
d->Add("IPv4");
|
||||
break;
|
||||
case L3_IPV6:
|
||||
d->Add("IPv6");
|
||||
break;
|
||||
default:
|
||||
d->Add("Unknown L3 protocol");
|
||||
}
|
||||
|
||||
// Add IP-specific information
|
||||
if ( l3_proto == L3_IPV4 || l3_proto == L3_IPV6 )
|
||||
{
|
||||
const IP_Hdr ip = IP();
|
||||
d->Add(": ");
|
||||
d->Add(ip.SrcAddr());
|
||||
d->Add("->");
|
||||
d->Add(ip.DstAddr());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace zeek
|
||||
|
|
|
@ -127,7 +127,7 @@ public:
|
|||
|
||||
/**
|
||||
* Interprets the Layer 3 of the packet as IP and returns a
|
||||
* correspondign object.
|
||||
* corresponding object.
|
||||
*/
|
||||
const IP_Hdr IP() const;
|
||||
|
||||
|
@ -141,14 +141,11 @@ public:
|
|||
RecordVal* BuildPktHdrVal() const;
|
||||
|
||||
/**
|
||||
* Static method returning the link-layer header size for a given
|
||||
* link type.
|
||||
* Returns the end of the captured data for bound checking.
|
||||
*
|
||||
* @param link_type The link tyoe.
|
||||
*
|
||||
* @return The header size in bytes, or -1 if not known.
|
||||
* @return End of the packet data.
|
||||
*/
|
||||
static int GetLinkHeaderSize(int link_type);
|
||||
const u_char* const GetEndOfData() const;
|
||||
|
||||
/**
|
||||
* Describes the packet, with standard signature.
|
||||
|
@ -158,7 +155,14 @@ public:
|
|||
/**
|
||||
* Maximal length of a layer 2 address.
|
||||
*/
|
||||
static const int l2_addr_len = 6;
|
||||
static const int L2_ADDR_LEN = 6;
|
||||
|
||||
/**
|
||||
* Empty layer 2 address to be used as default value. For example, the
|
||||
* LinuxSLL llanalyzer doesn't have a destination address in the header
|
||||
* and thus sets it to this default address.
|
||||
*/
|
||||
static constexpr const u_char L2_EMPTY_ADDR[L2_ADDR_LEN] = { 0 };
|
||||
|
||||
// These are passed in through the constructor.
|
||||
std::string tag; /// Used in serialization
|
||||
|
@ -168,6 +172,7 @@ public:
|
|||
uint32_t len; /// Actual length on wire
|
||||
uint32_t cap_len; /// Captured packet length
|
||||
uint32_t link_type; /// pcap link_type (DLT_EN10MB, DLT_RAW, etc)
|
||||
const uint8_t* cur_pos; /// Pointer to the current start of unanalyzed payload data in the raw packet, used by llanalyzers
|
||||
|
||||
// These are computed from Layer 2 data. These fields are only valid if
|
||||
// Layer2Valid() returns true.
|
||||
|
@ -224,13 +229,10 @@ public:
|
|||
*/
|
||||
bool l3_checksummed;
|
||||
|
||||
private:
|
||||
// Calculate layer 2 attributes.
|
||||
void ProcessLayer2();
|
||||
|
||||
// Wrapper to generate a packet-level weird.
|
||||
// Wrapper to generate a packet-level weird. Has to be public for llanalyzers to use it.
|
||||
void Weird(const char* name);
|
||||
|
||||
private:
|
||||
// Renders an MAC address into its ASCII representation.
|
||||
ValPtr FmtEUI48(const u_char* mac) const;
|
||||
|
||||
|
|
|
@ -53,11 +53,6 @@ const char* PktDumper::ErrorMsg() const
|
|||
return errmsg.size() ? errmsg.c_str() : nullptr;
|
||||
}
|
||||
|
||||
int PktDumper::HdrSize() const
|
||||
{
|
||||
return is_open ? props.hdr_size : -1;
|
||||
}
|
||||
|
||||
void PktDumper::Opened(const Properties& arg_props)
|
||||
{
|
||||
is_open = true;
|
||||
|
|
|
@ -50,11 +50,6 @@ public:
|
|||
*/
|
||||
const char* ErrorMsg() const;
|
||||
|
||||
/**
|
||||
* Returns the size of the link-layer headers with this dumper.
|
||||
*/
|
||||
int HdrSize() const;
|
||||
|
||||
// PktDumper interface for derived classes to implement.
|
||||
|
||||
/**
|
||||
|
@ -97,7 +92,6 @@ protected:
|
|||
*/
|
||||
struct Properties {
|
||||
std::string path;
|
||||
int hdr_size;
|
||||
double open_time;
|
||||
};
|
||||
|
||||
|
|
|
@ -90,16 +90,6 @@ double PktSrc::CurrentPacketWallClock()
|
|||
|
||||
void PktSrc::Opened(const Properties& arg_props)
|
||||
{
|
||||
if ( Packet::GetLinkHeaderSize(arg_props.link_type) < 0 )
|
||||
{
|
||||
char buf[512];
|
||||
snprintf(buf, sizeof(buf),
|
||||
"unknown data link type 0x%x", arg_props.link_type);
|
||||
Error(buf);
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
props = arg_props;
|
||||
SetClosed(false);
|
||||
|
||||
|
|
|
@ -82,7 +82,6 @@ void PcapDumper::Open()
|
|||
}
|
||||
|
||||
props.open_time = run_state::network_time;
|
||||
props.hdr_size = Packet::GetLinkHeaderSize(pcap_datalink(pd));
|
||||
Opened(props);
|
||||
}
|
||||
|
||||
|
|
47
src/llanalyzer/Analyzer.cc
Normal file
47
src/llanalyzer/Analyzer.cc
Normal file
|
@ -0,0 +1,47 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include <algorithm>
|
||||
#include "Analyzer.h"
|
||||
|
||||
namespace zeek::llanalyzer {
|
||||
|
||||
Analyzer::Analyzer(std::string name)
|
||||
{
|
||||
Tag t = llanalyzer_mgr->GetComponentTag(name);
|
||||
|
||||
if ( ! t )
|
||||
reporter->InternalError("unknown llanalyzer name %s", name.c_str());
|
||||
|
||||
Init(t);
|
||||
}
|
||||
|
||||
Analyzer::Analyzer(const Tag& tag)
|
||||
{
|
||||
Init(tag);
|
||||
}
|
||||
|
||||
/* PRIVATE */
|
||||
void Analyzer::Init(const Tag& _tag)
|
||||
{
|
||||
tag = _tag;
|
||||
}
|
||||
|
||||
const Tag Analyzer::GetAnalyzerTag() const
|
||||
{
|
||||
assert(tag);
|
||||
return tag;
|
||||
}
|
||||
|
||||
const char* Analyzer::GetAnalyzerName() const
|
||||
{
|
||||
assert(tag);
|
||||
return llanalyzer_mgr->GetComponentName(tag).c_str();
|
||||
}
|
||||
|
||||
bool Analyzer::IsAnalyzer(const char* name)
|
||||
{
|
||||
assert(tag);
|
||||
return llanalyzer_mgr->GetComponentName(tag).compare(name) == 0;
|
||||
}
|
||||
|
||||
}
|
89
src/llanalyzer/Analyzer.h
Normal file
89
src/llanalyzer/Analyzer.h
Normal file
|
@ -0,0 +1,89 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
#pragma once
|
||||
|
||||
#include "Defines.h"
|
||||
#include "Manager.h"
|
||||
#include "Tag.h"
|
||||
#include <iosource/Packet.h>
|
||||
|
||||
namespace zeek::llanalyzer {
|
||||
|
||||
/**
|
||||
* Result of low layer analysis.
|
||||
*/
|
||||
enum class AnalyzerResult {
|
||||
Failed, // Analysis failed
|
||||
Continue, // Analysis succeded and an encapuslated protocol was determined
|
||||
Terminate // Analysis succeded and there is no further analysis to do
|
||||
};
|
||||
|
||||
using AnalysisResultTuple = std::tuple<AnalyzerResult, identifier_t>;
|
||||
|
||||
class Analyzer {
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param name The name for the type of analyzer. The name must match
|
||||
* the one the corresponding Component registers.
|
||||
*/
|
||||
explicit Analyzer(std::string name);
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param tag The tag for the type of analyzer. The tag must map to
|
||||
* the name the corresponding Component registers.
|
||||
*/
|
||||
explicit Analyzer(const Tag& tag);
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~Analyzer() = default;
|
||||
|
||||
/**
|
||||
* Returns the tag associated with the analyzer's type.
|
||||
*/
|
||||
const Tag GetAnalyzerTag() const;
|
||||
|
||||
/**
|
||||
* Returns a textual description of the analyzer's type. This is
|
||||
* what's passed to the constructor and usally corresponds to the
|
||||
* protocol name, e.g., "ARP".
|
||||
*/
|
||||
const char* GetAnalyzerName() const;
|
||||
|
||||
/**
|
||||
* Returns true if this analyzer's type matches the name passes in.
|
||||
* This is shortcut for comparing GetAnalyzerName() with the given
|
||||
* name.
|
||||
*
|
||||
* @param name The name to check.
|
||||
*/
|
||||
bool IsAnalyzer(const char* name);
|
||||
|
||||
/**
|
||||
* Analyzes the given packet. The analysis is supposed to start at cur_pos
|
||||
* of the packet, which points to the so far unanalyzed part of the packet.
|
||||
* If the analyzed protocol encapsulates another protocol, the packet's
|
||||
* cur_pos should be updated to point to that payload.
|
||||
*
|
||||
* @param packet The packet to analyze.
|
||||
*
|
||||
* @return A tuple of analysis result and identifier. The result indicates
|
||||
* how to proceed. If analysis can continue, the identifier determines the
|
||||
* encapsulated protocol.
|
||||
*/
|
||||
virtual std::tuple<AnalyzerResult, identifier_t> Analyze(Packet* packet) = 0;
|
||||
|
||||
protected:
|
||||
friend class Manager;
|
||||
|
||||
private:
|
||||
Tag tag;
|
||||
|
||||
void Init(const Tag& tag);
|
||||
};
|
||||
|
||||
} // llanalyzer namespace end
|
24
src/llanalyzer/AnalyzerSet.h
Normal file
24
src/llanalyzer/AnalyzerSet.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Analyzer.h"
|
||||
#include "Defines.h"
|
||||
|
||||
namespace zeek::llanalyzer {
|
||||
|
||||
class Analyzer;
|
||||
|
||||
class AnalyzerSet {
|
||||
public:
|
||||
virtual ~AnalyzerSet() = default;
|
||||
virtual Analyzer* Dispatch(identifier_t identifier) = 0;
|
||||
virtual void Reset() = 0;
|
||||
|
||||
protected:
|
||||
friend class Manager;
|
||||
|
||||
virtual void DumpDebug() const = 0;
|
||||
};
|
||||
|
||||
}
|
21
src/llanalyzer/CMakeLists.txt
Normal file
21
src/llanalyzer/CMakeLists.txt
Normal file
|
@ -0,0 +1,21 @@
|
|||
include(ZeekSubdir)
|
||||
|
||||
include_directories(BEFORE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
||||
|
||||
add_subdirectory(protocol)
|
||||
add_subdirectory(dispatchers)
|
||||
|
||||
set(llanalyzer_SRCS
|
||||
Analyzer.cc
|
||||
ProtocolAnalyzerSet.cc
|
||||
Manager.cc
|
||||
Component.cc
|
||||
Tag.cc
|
||||
Config.cc
|
||||
)
|
||||
|
||||
bro_add_subdir_library(llanalyzer ${llanalyzer_SRCS})
|
||||
add_dependencies(bro_llanalyzer generate_outputs)
|
33
src/llanalyzer/Component.cc
Normal file
33
src/llanalyzer/Component.cc
Normal file
|
@ -0,0 +1,33 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "Component.h"
|
||||
#include "Desc.h"
|
||||
#include "Manager.h"
|
||||
|
||||
using namespace zeek::llanalyzer;
|
||||
|
||||
Component::Component(const std::string& name, factory_callback arg_factory, Tag::subtype_t arg_subtype, bool arg_enabled)
|
||||
: plugin::Component(plugin::component::LLANALYZER, name),
|
||||
plugin::TaggedComponent<llanalyzer::Tag>(arg_subtype)
|
||||
{
|
||||
factory = arg_factory;
|
||||
enabled = arg_enabled;
|
||||
}
|
||||
|
||||
void Component::Initialize()
|
||||
{
|
||||
InitializeTag();
|
||||
llanalyzer_mgr->RegisterComponent(this, "LLANALYZER_");
|
||||
}
|
||||
|
||||
void Component::DoDescribe(ODesc* d) const
|
||||
{
|
||||
if ( factory )
|
||||
{
|
||||
d->Add("LLANALYZER_");
|
||||
d->Add(CanonicalName());
|
||||
d->Add(", ");
|
||||
}
|
||||
|
||||
d->Add(enabled ? "enabled" : "disabled");
|
||||
}
|
61
src/llanalyzer/Component.h
Normal file
61
src/llanalyzer/Component.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "zeek-config.h"
|
||||
#include "util.h"
|
||||
#include "Tag.h"
|
||||
|
||||
#include "plugin/Component.h"
|
||||
#include "plugin/TaggedComponent.h"
|
||||
|
||||
namespace zeek::llanalyzer {
|
||||
|
||||
class Analyzer;
|
||||
|
||||
class Component : public plugin::Component,
|
||||
public plugin::TaggedComponent<llanalyzer::Tag> {
|
||||
public:
|
||||
typedef Analyzer* (*factory_callback)();
|
||||
|
||||
Component(const std::string& name, factory_callback factory, Tag::subtype_t subtype = 0, bool enabled = true);
|
||||
~Component() override = default;
|
||||
|
||||
/**
|
||||
* Initialization function. This function has to be called before any
|
||||
* plugin component functionality is used; it is used to add the
|
||||
* plugin component to the list of components and to initialize tags
|
||||
*/
|
||||
void Initialize() override;
|
||||
|
||||
/**
|
||||
* Returns the analyzer's factory function.
|
||||
*/
|
||||
factory_callback Factory() const { return factory; }
|
||||
|
||||
/**
|
||||
* Returns true if the analyzer is currently enabled and hence
|
||||
* available for use.
|
||||
*/
|
||||
bool Enabled() const { return enabled; }
|
||||
|
||||
/**
|
||||
* Enables or disables this analyzer.
|
||||
*
|
||||
* @param arg_enabled True to enabled, false to disable.
|
||||
*
|
||||
*/
|
||||
void SetEnabled(bool arg_enabled) { enabled = arg_enabled; }
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Overriden from plugin::Component.
|
||||
*/
|
||||
void DoDescribe(ODesc* d) const override;
|
||||
|
||||
private:
|
||||
factory_callback factory; // The analyzer's factory callback.
|
||||
bool enabled; // True if the analyzer is enabled.
|
||||
};
|
||||
|
||||
}
|
87
src/llanalyzer/Config.cc
Normal file
87
src/llanalyzer/Config.cc
Normal file
|
@ -0,0 +1,87 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "Config.h"
|
||||
#include "Reporter.h"
|
||||
#include "DebugLogger.h"
|
||||
|
||||
namespace zeek::llanalyzer {
|
||||
|
||||
// ##############################
|
||||
// ####### DispatcherConfig #####
|
||||
// ##############################
|
||||
const std::string& DispatcherConfig::GetName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
const std::map<identifier_t, std::string>& DispatcherConfig::GetMappings() const
|
||||
{
|
||||
return mappings;
|
||||
}
|
||||
|
||||
void DispatcherConfig::AddMapping(identifier_t identifier,
|
||||
const std::string& analyzer_name)
|
||||
{
|
||||
DBG_LOG(DBG_LLANALYZER, "Adding configuration mapping: %s -> %#x -> %s",
|
||||
name.c_str(), identifier, analyzer_name.c_str());
|
||||
|
||||
if ( mappings.count(identifier) )
|
||||
reporter->InternalError("Invalid config, identifier %#x already exists "
|
||||
"for dispatcher set %s.",
|
||||
identifier, name.c_str());
|
||||
|
||||
mappings.emplace(identifier, analyzer_name);
|
||||
}
|
||||
|
||||
bool DispatcherConfig::operator==(const DispatcherConfig& rhs) const
|
||||
{
|
||||
return name == rhs.name;
|
||||
}
|
||||
|
||||
bool DispatcherConfig::operator!=(const DispatcherConfig& rhs) const
|
||||
{
|
||||
return ! (rhs == *this);
|
||||
}
|
||||
|
||||
// ##############################
|
||||
// ########### Config ###########
|
||||
// ##############################
|
||||
std::optional<std::reference_wrapper<DispatcherConfig>>
|
||||
Config::GetDispatcherConfig(const std::string& name)
|
||||
{
|
||||
auto it = std::find_if(
|
||||
dispatchers.begin(), dispatchers.end(),
|
||||
[&](const DispatcherConfig& conf) {
|
||||
return conf.GetName() == name;
|
||||
});
|
||||
|
||||
if ( it == dispatchers.end() )
|
||||
return {};
|
||||
else
|
||||
return {std::ref(*it)};
|
||||
}
|
||||
|
||||
const std::vector<DispatcherConfig>& Config::GetDispatchers() const
|
||||
{
|
||||
return dispatchers;
|
||||
}
|
||||
|
||||
DispatcherConfig& Config::AddDispatcherConfig(const std::string& name)
|
||||
{
|
||||
return dispatchers.emplace_back(name);
|
||||
}
|
||||
|
||||
void Config::AddMapping(const std::string& name, identifier_t identifier,
|
||||
const std::string& analyzer_name)
|
||||
{
|
||||
// Create dispatcher config if it does not exist yet
|
||||
std::optional<std::reference_wrapper<DispatcherConfig>> dispatch_config =
|
||||
GetDispatcherConfig(name);
|
||||
|
||||
if ( ! dispatch_config )
|
||||
AddDispatcherConfig(name).AddMapping(identifier, analyzer_name);
|
||||
else
|
||||
dispatch_config->get().AddMapping(identifier, analyzer_name);
|
||||
}
|
||||
|
||||
} // namespace llanalyzer
|
44
src/llanalyzer/Config.h
Normal file
44
src/llanalyzer/Config.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "Defines.h"
|
||||
|
||||
namespace zeek::llanalyzer {
|
||||
|
||||
class DispatcherConfig {
|
||||
public:
|
||||
explicit DispatcherConfig(const std::string name) : name(std::move(name)) { }
|
||||
|
||||
const std::string& GetName() const;
|
||||
const std::map<identifier_t, std::string>& GetMappings() const;
|
||||
|
||||
void AddMapping(identifier_t identifier, const std::string& analyzer_name);
|
||||
|
||||
bool operator==(const DispatcherConfig& rhs) const;
|
||||
bool operator!=(const DispatcherConfig& rhs) const;
|
||||
|
||||
private:
|
||||
const std::string name;
|
||||
std::map<identifier_t, std::string> mappings;
|
||||
};
|
||||
|
||||
class Config {
|
||||
|
||||
public:
|
||||
const std::vector<DispatcherConfig>& GetDispatchers() const;
|
||||
std::optional<std::reference_wrapper<DispatcherConfig>> GetDispatcherConfig(const std::string& name);
|
||||
DispatcherConfig& AddDispatcherConfig(const std::string& name);
|
||||
void AddMapping(const std::string& name, identifier_t identifier, const std::string& analyzer_name);
|
||||
|
||||
private:
|
||||
std::vector<DispatcherConfig> dispatchers;
|
||||
};
|
||||
|
||||
}
|
11
src/llanalyzer/Defines.h
Normal file
11
src/llanalyzer/Defines.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace zeek::llanalyzer {
|
||||
|
||||
using identifier_t = uint32_t;
|
||||
|
||||
}
|
285
src/llanalyzer/Manager.cc
Normal file
285
src/llanalyzer/Manager.cc
Normal file
|
@ -0,0 +1,285 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include <list>
|
||||
#include <pcap.h>
|
||||
|
||||
#include "Config.h"
|
||||
#include "Manager.h"
|
||||
#include "NetVar.h"
|
||||
#include "ProtocolAnalyzerSet.h"
|
||||
#include "plugin/Manager.h"
|
||||
|
||||
using namespace zeek::llanalyzer;
|
||||
|
||||
Manager::Manager()
|
||||
: plugin::ComponentManager<llanalyzer::Tag, llanalyzer::Component>("LLAnalyzer", "Tag")
|
||||
{
|
||||
}
|
||||
|
||||
Manager::~Manager()
|
||||
{
|
||||
delete analyzer_set;
|
||||
}
|
||||
|
||||
void Manager::InitPostScript()
|
||||
{
|
||||
auto llanalyzer_mapping = zeek::id::find("LLAnalyzer::config_map");
|
||||
if ( ! llanalyzer_mapping )
|
||||
return;
|
||||
|
||||
auto mapping_val = llanalyzer_mapping->GetVal()->AsVectorVal();
|
||||
if ( mapping_val->Size() == 0 )
|
||||
return;
|
||||
|
||||
Config configuration;
|
||||
for (unsigned int i = 0; i < mapping_val->Size(); i++)
|
||||
{
|
||||
auto* rv = mapping_val->At(i)->AsRecordVal();
|
||||
auto parent = rv->GetField("parent");
|
||||
std::string parent_name = parent ? Lookup(parent->AsEnumVal())->Name() : "ROOT";
|
||||
auto identifier = rv->GetField("identifier")->AsCount();
|
||||
auto analyzer = rv->GetField("analyzer")->AsEnumVal();
|
||||
|
||||
configuration.AddMapping(parent_name, identifier, Lookup(analyzer)->Name());
|
||||
}
|
||||
|
||||
analyzer_set = new ProtocolAnalyzerSet(configuration, "DefaultAnalyzer");
|
||||
}
|
||||
|
||||
void Manager::Done()
|
||||
{
|
||||
}
|
||||
|
||||
void Manager::DumpDebug()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
DBG_LOG(DBG_LLANALYZER, "Available llanalyzers after zeek_init():");
|
||||
for ( auto& current : GetComponents() )
|
||||
{
|
||||
DBG_LOG(DBG_LLANALYZER, " %s (%s)", current->Name().c_str(), IsEnabled(current->Tag()) ? "enabled" : "disabled");
|
||||
}
|
||||
|
||||
// Dump Analyzer Set
|
||||
if (analyzer_set)
|
||||
analyzer_set->DumpDebug();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Manager::EnableAnalyzer(const Tag& tag)
|
||||
{
|
||||
Component* p = Lookup(tag);
|
||||
|
||||
if ( ! p )
|
||||
return false;
|
||||
|
||||
DBG_LOG(DBG_LLANALYZER, "Enabling analyzer %s", p->Name().c_str());
|
||||
p->SetEnabled(true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Manager::EnableAnalyzer(EnumVal* val)
|
||||
{
|
||||
Component* p = Lookup(val);
|
||||
|
||||
if ( ! p )
|
||||
return false;
|
||||
|
||||
DBG_LOG(DBG_LLANALYZER, "Enabling analyzer %s", p->Name().c_str());
|
||||
p->SetEnabled(true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Manager::DisableAnalyzer(const Tag& tag)
|
||||
{
|
||||
Component* p = Lookup(tag);
|
||||
|
||||
if ( ! p )
|
||||
return false;
|
||||
|
||||
DBG_LOG(DBG_LLANALYZER, "Disabling analyzer %s", p->Name().c_str());
|
||||
p->SetEnabled(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Manager::DisableAnalyzer(EnumVal* val)
|
||||
{
|
||||
Component* p = Lookup(val);
|
||||
|
||||
if ( ! p )
|
||||
return false;
|
||||
|
||||
DBG_LOG(DBG_LLANALYZER, "Disabling analyzer %s", p->Name().c_str());
|
||||
p->SetEnabled(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Manager::DisableAllAnalyzers()
|
||||
{
|
||||
DBG_LOG(DBG_LLANALYZER, "Disabling all analyzers");
|
||||
|
||||
std::list<Component*> all_analyzers = GetComponents();
|
||||
for ( const auto& analyzer : all_analyzers )
|
||||
analyzer->SetEnabled(false);
|
||||
}
|
||||
|
||||
zeek::llanalyzer::Tag Manager::GetAnalyzerTag(const char* name)
|
||||
{
|
||||
return GetComponentTag(name);
|
||||
}
|
||||
|
||||
bool Manager::IsEnabled(Tag tag)
|
||||
{
|
||||
if ( ! tag )
|
||||
return false;
|
||||
|
||||
Component* p = Lookup(tag);
|
||||
|
||||
if ( ! p )
|
||||
return false;
|
||||
|
||||
return p->Enabled();
|
||||
}
|
||||
|
||||
bool Manager::IsEnabled(EnumVal* val)
|
||||
{
|
||||
Component* p = Lookup(val);
|
||||
|
||||
if ( ! p )
|
||||
return false;
|
||||
|
||||
return p->Enabled();
|
||||
}
|
||||
|
||||
Analyzer* Manager::InstantiateAnalyzer(const Tag& tag)
|
||||
{
|
||||
Component* c = Lookup(tag);
|
||||
|
||||
if ( ! c )
|
||||
{
|
||||
reporter->InternalWarning("request to instantiate unknown llanalyzer");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if ( ! c->Enabled() )
|
||||
return nullptr;
|
||||
|
||||
if ( ! c->Factory() )
|
||||
{
|
||||
reporter->InternalWarning("analyzer %s cannot be instantiated dynamically", GetComponentName(tag).c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Analyzer* a = c->Factory()();
|
||||
|
||||
if ( ! a )
|
||||
{
|
||||
reporter->InternalWarning("analyzer instantiation failed");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if ( tag != a->GetAnalyzerTag() )
|
||||
{
|
||||
reporter->InternalError("Mismatch of requested analyzer %s and instantiated analyzer %s. This usually means that the plugin author made a mistake.",
|
||||
GetComponentName(tag).c_str(), GetComponentName(a->GetAnalyzerTag()).c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
Analyzer* Manager::InstantiateAnalyzer(const std::string& name)
|
||||
{
|
||||
Tag tag = GetComponentTag(name);
|
||||
return tag ? InstantiateAnalyzer(tag) : nullptr;
|
||||
}
|
||||
|
||||
void Manager::ProcessPacket(Packet* packet)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
static size_t counter = 0;
|
||||
DBG_LOG(DBG_LLANALYZER, "Analyzing packet %ld, ts=%.3f...", ++counter, packet->time);
|
||||
#endif
|
||||
|
||||
if ( ! analyzer_set )
|
||||
return;
|
||||
|
||||
// Dispatch and analyze layers
|
||||
AnalyzerResult result = AnalyzerResult::Continue;
|
||||
identifier_t next_layer_id = packet->link_type;
|
||||
do
|
||||
{
|
||||
auto current_analyzer = analyzer_set->Dispatch(next_layer_id);
|
||||
|
||||
// Analyzer not found
|
||||
if ( current_analyzer == nullptr )
|
||||
{
|
||||
DBG_LOG(DBG_LLANALYZER, "Could not find analyzer for identifier %#x", next_layer_id);
|
||||
packet->Weird("no_suitable_analyzer_found");
|
||||
break;
|
||||
}
|
||||
|
||||
// Analyze this layer and get identifier of next layer protocol
|
||||
std::tie(result, next_layer_id) = current_analyzer->Analyze(packet);
|
||||
|
||||
#ifdef DEBUG
|
||||
switch ( result )
|
||||
{
|
||||
case AnalyzerResult::Continue:
|
||||
DBG_LOG(DBG_LLANALYZER, "Analysis in %s succeeded, next layer identifier is %#x.",
|
||||
current_analyzer->GetAnalyzerName(), next_layer_id);
|
||||
break;
|
||||
case AnalyzerResult::Terminate:
|
||||
DBG_LOG(DBG_LLANALYZER, "Done, last found layer identifier was %#x.", next_layer_id);
|
||||
break;
|
||||
case AnalyzerResult::Failed:
|
||||
DBG_LOG(DBG_LLANALYZER, "Analysis failed in %s", current_analyzer->GetAnalyzerName());
|
||||
}
|
||||
#endif
|
||||
|
||||
} while ( result == AnalyzerResult::Continue );
|
||||
|
||||
if ( result == AnalyzerResult::Terminate )
|
||||
CustomEncapsulationSkip(packet);
|
||||
|
||||
// Processing finished, reset analyzer set state for next packet
|
||||
analyzer_set->Reset();
|
||||
}
|
||||
|
||||
void Manager::CustomEncapsulationSkip(Packet* packet)
|
||||
{
|
||||
if ( zeek::detail::encap_hdr_size > 0 )
|
||||
{
|
||||
auto pdata = packet->cur_pos;
|
||||
|
||||
// Blanket encapsulation. We assume that what remains is IP.
|
||||
if ( pdata + zeek::detail::encap_hdr_size + sizeof(struct ip) >= packet->GetEndOfData() )
|
||||
{
|
||||
packet->Weird("no_ip_left_after_encap");
|
||||
return;
|
||||
}
|
||||
|
||||
pdata += zeek::detail::encap_hdr_size;
|
||||
|
||||
auto ip = (const struct ip*)pdata;
|
||||
|
||||
switch ( ip->ip_v )
|
||||
{
|
||||
case 4:
|
||||
packet->l3_proto = L3_IPV4;
|
||||
break;
|
||||
case 6:
|
||||
packet->l3_proto = L3_IPV6;
|
||||
break;
|
||||
default:
|
||||
{
|
||||
// Neither IPv4 nor IPv6.
|
||||
packet->Weird("no_ip_in_encap");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
167
src/llanalyzer/Manager.h
Normal file
167
src/llanalyzer/Manager.h
Normal file
|
@ -0,0 +1,167 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
|
||||
#include "Tag.h"
|
||||
#include "Analyzer.h"
|
||||
#include "Component.h"
|
||||
#include "AnalyzerSet.h"
|
||||
#include "plugin/ComponentManager.h"
|
||||
#include "iosource/Packet.h"
|
||||
|
||||
#include "../Dict.h"
|
||||
#include "../net_util.h"
|
||||
|
||||
namespace zeek::llanalyzer {
|
||||
|
||||
class AnalyzerSet;
|
||||
|
||||
class Manager : public plugin::ComponentManager<Tag, Component> {
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
Manager();
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~Manager();
|
||||
|
||||
/**
|
||||
* Second-stage initialization of the manager. This is called late
|
||||
* during Bro's initialization after any scripts are processed.
|
||||
*/
|
||||
void InitPostScript();
|
||||
|
||||
/**
|
||||
* Finished the manager's operations.
|
||||
*/
|
||||
void Done();
|
||||
|
||||
/**
|
||||
* Dumps out the state of all registered analyzers to the \c analyzer
|
||||
* debug stream. Should be called only after any \c zeek_init events
|
||||
* have executed to ensure that any of their changes are applied.
|
||||
*/
|
||||
void DumpDebug(); // Called after zeek_init() events.
|
||||
|
||||
/**
|
||||
* Enables an analyzer type. Only enabled analyzers will be
|
||||
* instantiated for new connections.
|
||||
*
|
||||
* @param tag The analyzer's tag.
|
||||
*
|
||||
* @return True if successful.
|
||||
*/
|
||||
bool EnableAnalyzer(const Tag& tag);
|
||||
|
||||
/**
|
||||
* Enables an analyzer type. Only enabled analyzers will be
|
||||
* instantiated for new connections.
|
||||
*
|
||||
* @param tag The analyzer's tag as an enum of script type \c
|
||||
* Analyzer::Tag.
|
||||
*
|
||||
* @return True if successful.
|
||||
*/
|
||||
bool EnableAnalyzer(EnumVal* tag);
|
||||
|
||||
/**
|
||||
* Enables an analyzer type. Disabled analyzers will not be
|
||||
* instantiated for new connections.
|
||||
*
|
||||
* @param tag The analyzer's tag.
|
||||
*
|
||||
* @return True if successful.
|
||||
*/
|
||||
bool DisableAnalyzer(const Tag& tag);
|
||||
|
||||
/**
|
||||
* Disables an analyzer type. Disabled analyzers will not be
|
||||
* instantiated for new connections.
|
||||
*
|
||||
* @param tag The analyzer's tag as an enum of script type \c
|
||||
* Analyzer::Tag.
|
||||
*
|
||||
* @return True if successful.
|
||||
*/
|
||||
bool DisableAnalyzer(EnumVal* tag);
|
||||
|
||||
/**
|
||||
* Disables all currently registered analyzers.
|
||||
*/
|
||||
void DisableAllAnalyzers();
|
||||
|
||||
/**
|
||||
* Returns the tag associated with an analyer name, or the tag
|
||||
* associated with an error if no such analyzer exists.
|
||||
*
|
||||
* @param name The canonical analyzer name to check.
|
||||
*/
|
||||
Tag GetAnalyzerTag(const char* name);
|
||||
|
||||
/**
|
||||
* Returns true if an analyzer is enabled.
|
||||
*
|
||||
* @param tag The analyzer's tag.
|
||||
*/
|
||||
bool IsEnabled(Tag tag);
|
||||
|
||||
/**
|
||||
* Returns true if an analyzer is enabled.
|
||||
*
|
||||
* @param tag The analyzer's tag as an enum of script type \c
|
||||
* Analyzer::Tag.
|
||||
*/
|
||||
bool IsEnabled(EnumVal* tag);
|
||||
|
||||
/**
|
||||
* Instantiates a new analyzer instance.
|
||||
*
|
||||
* @param tag The analyzer's tag.
|
||||
*
|
||||
* @return The new analyzer instance. Returns
|
||||
* null if tag is invalid, the requested analyzer is disabled, or the
|
||||
* analyzer can't be instantiated.
|
||||
*/
|
||||
Analyzer* InstantiateAnalyzer(const Tag& tag);
|
||||
|
||||
/**
|
||||
* Instantiates a new analyzer.
|
||||
*
|
||||
* @param name The name of the analyzer.
|
||||
*
|
||||
* @return The new analyzer instance. Returns
|
||||
* null if the name is not known or if the requested analyzer that is
|
||||
* disabled.
|
||||
*/
|
||||
Analyzer* InstantiateAnalyzer(const std::string& name);
|
||||
|
||||
/**
|
||||
* Processes a packet by applying the configured low layer analyzers.
|
||||
*
|
||||
* @param packet The packet to process.
|
||||
*/
|
||||
void ProcessPacket(Packet* packet);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Skips a fixed amount of packet data that is defined by encap_hdr_size.
|
||||
* It is assumed that an IP header follows.
|
||||
*
|
||||
* @param packet The packet to adapt.
|
||||
*/
|
||||
void CustomEncapsulationSkip(Packet* packet);
|
||||
|
||||
private:
|
||||
AnalyzerSet* analyzer_set = nullptr;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
extern zeek::llanalyzer::Manager* llanalyzer_mgr;
|
137
src/llanalyzer/ProtocolAnalyzerSet.cc
Normal file
137
src/llanalyzer/ProtocolAnalyzerSet.cc
Normal file
|
@ -0,0 +1,137 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "ProtocolAnalyzerSet.h"
|
||||
|
||||
namespace zeek::llanalyzer {
|
||||
|
||||
ProtocolAnalyzerSet::ProtocolAnalyzerSet(Config& configuration, const std::string& default_analyzer_name)
|
||||
{
|
||||
// Instantiate objects for all analyzers
|
||||
for ( const auto& current_dispatcher_config : configuration.GetDispatchers() )
|
||||
{
|
||||
for ( const auto& current_mapping : current_dispatcher_config.GetMappings() )
|
||||
{
|
||||
// Check if already instantiated
|
||||
if ( analyzers.count(current_mapping.second) != 0 )
|
||||
continue;
|
||||
|
||||
// Check if analyzer exists
|
||||
if ( Analyzer* newAnalyzer = llanalyzer_mgr->InstantiateAnalyzer(current_mapping.second) )
|
||||
analyzers.emplace(current_mapping.second, newAnalyzer);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate Dispatchers, starting at root
|
||||
root_dispatcher = GetDispatcher(configuration, "ROOT");
|
||||
if ( root_dispatcher == nullptr )
|
||||
reporter->InternalError("No dispatching configuration for ROOT of llanalyzer set.");
|
||||
|
||||
// Set up default analysis
|
||||
auto it = analyzers.find(default_analyzer_name);
|
||||
if ( it != analyzers.end() )
|
||||
default_analyzer = it->second;
|
||||
else
|
||||
default_analyzer = llanalyzer_mgr->InstantiateAnalyzer(default_analyzer_name);
|
||||
|
||||
default_dispatcher = nullptr;
|
||||
if ( default_analyzer != nullptr )
|
||||
default_dispatcher = GetDispatcher(configuration, default_analyzer_name);
|
||||
|
||||
current_state = root_dispatcher;
|
||||
}
|
||||
|
||||
ProtocolAnalyzerSet::~ProtocolAnalyzerSet()
|
||||
{
|
||||
bool delete_default = default_analyzer != nullptr;
|
||||
for ( const auto& current : analyzers )
|
||||
{
|
||||
if ( current.second == default_analyzer )
|
||||
delete_default = false;
|
||||
|
||||
delete current.second;
|
||||
}
|
||||
|
||||
if ( delete_default )
|
||||
delete default_analyzer;
|
||||
}
|
||||
|
||||
Analyzer* ProtocolAnalyzerSet::Dispatch(identifier_t identifier)
|
||||
{
|
||||
// Because leaf nodes (aka no more dispatching) can still have an existing analyzer that returns more identifiers,
|
||||
// current_state needs to be checked to be not null. In this case there would have been an analyzer dispatched
|
||||
// in the last layer, but no dispatcher for it (end of FSM)
|
||||
const Value* result = nullptr;
|
||||
if ( current_state )
|
||||
result = current_state->Lookup(identifier);
|
||||
|
||||
if ( result == nullptr )
|
||||
{
|
||||
if ( current_state != default_dispatcher )
|
||||
{
|
||||
// Switch to default analysis once
|
||||
current_state = default_dispatcher;
|
||||
return default_analyzer;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
current_state = result->dispatcher;
|
||||
return result->analyzer;
|
||||
}
|
||||
}
|
||||
|
||||
void ProtocolAnalyzerSet::Reset()
|
||||
{
|
||||
current_state = root_dispatcher;
|
||||
}
|
||||
|
||||
void ProtocolAnalyzerSet::DumpDebug() const
|
||||
{
|
||||
#ifdef DEBUG
|
||||
DBG_LOG(DBG_LLANALYZER, "ProtocolAnalyzerSet FSM:");
|
||||
for ( const auto& current : dispatchers )
|
||||
{
|
||||
DBG_LOG(DBG_LLANALYZER, " Dispatcher (%p): %s", current.second, current.first.c_str());
|
||||
current.second->DumpDebug();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Dispatcher* ProtocolAnalyzerSet::GetDispatcher(Config& configuration, const std::string& dispatcher_name)
|
||||
{
|
||||
// Is it already created?
|
||||
if ( dispatchers.count(dispatcher_name) != 0 )
|
||||
return dispatchers[dispatcher_name];
|
||||
|
||||
// Create new dispatcher from config
|
||||
std::optional<std::reference_wrapper<DispatcherConfig>> dispatcher_config = configuration.GetDispatcherConfig(dispatcher_name);
|
||||
if ( ! dispatcher_config )
|
||||
// No such dispatcher found, this is therefore implicitly a leaf
|
||||
return nullptr;
|
||||
|
||||
const auto& mappings = dispatcher_config->get().GetMappings();
|
||||
|
||||
Dispatcher* dispatcher = new dispatcher_impl();
|
||||
dispatchers.emplace(dispatcher_name, dispatcher);
|
||||
|
||||
for ( const auto& current_mapping : mappings )
|
||||
{
|
||||
// No analyzer with this name. Report warning and ignore.
|
||||
if ( analyzers.count(current_mapping.second) == 0 )
|
||||
{
|
||||
reporter->InternalWarning("No analyzer %s found for dispatching identifier %#x of %s, ignoring.",
|
||||
current_mapping.second.c_str(),
|
||||
current_mapping.first,
|
||||
dispatcher_name.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
dispatcher->Register(current_mapping.first, analyzers.at(current_mapping.second),
|
||||
GetDispatcher(configuration, current_mapping.second));
|
||||
}
|
||||
|
||||
return dispatcher;
|
||||
}
|
||||
|
||||
}
|
39
src/llanalyzer/ProtocolAnalyzerSet.h
Normal file
39
src/llanalyzer/ProtocolAnalyzerSet.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "AnalyzerSet.h"
|
||||
#include "Config.h"
|
||||
#include "dispatchers/Dispatcher.h"
|
||||
#include "dispatchers/UniversalDispatcher.h"
|
||||
#include "dispatchers/VectorDispatcher.h"
|
||||
|
||||
namespace zeek::llanalyzer {
|
||||
|
||||
class ProtocolAnalyzerSet : public AnalyzerSet {
|
||||
|
||||
public:
|
||||
explicit ProtocolAnalyzerSet(Config& configuration, const std::string& default_analyzer_name);
|
||||
~ProtocolAnalyzerSet() override;
|
||||
|
||||
Analyzer* Dispatch(identifier_t identifier) override;
|
||||
void Reset() override;
|
||||
|
||||
protected:
|
||||
void DumpDebug() const override;
|
||||
|
||||
private:
|
||||
using dispatcher_impl = VectorDispatcher;
|
||||
//using dispatcher_impl = UniversalDispatcher;
|
||||
|
||||
std::map<std::string, Analyzer*> analyzers;
|
||||
std::map<std::string, Dispatcher*> dispatchers;
|
||||
Dispatcher* root_dispatcher = nullptr;
|
||||
Dispatcher* default_dispatcher = nullptr;
|
||||
Dispatcher* current_state = nullptr;
|
||||
Analyzer* default_analyzer = nullptr;
|
||||
|
||||
Dispatcher* GetDispatcher(Config& configuration, const std::string& dispatcher_name);
|
||||
};
|
||||
|
||||
}
|
41
src/llanalyzer/Tag.cc
Normal file
41
src/llanalyzer/Tag.cc
Normal file
|
@ -0,0 +1,41 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "Tag.h"
|
||||
#include "Manager.h"
|
||||
|
||||
namespace zeek::llanalyzer {
|
||||
|
||||
Tag Tag::Error;
|
||||
|
||||
Tag::Tag(type_t type, subtype_t subtype)
|
||||
: zeek::Tag(llanalyzer_mgr->GetTagType(), type, subtype)
|
||||
{
|
||||
}
|
||||
|
||||
Tag& Tag::operator=(const Tag& other)
|
||||
{
|
||||
zeek::Tag::operator=(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const IntrusivePtr<EnumVal>& Tag::AsVal() const
|
||||
{
|
||||
return zeek::Tag::AsVal(llanalyzer_mgr->GetTagType());
|
||||
}
|
||||
|
||||
EnumVal* Tag::AsEnumVal() const
|
||||
{
|
||||
return AsVal().get();
|
||||
}
|
||||
|
||||
Tag::Tag(IntrusivePtr<EnumVal> val)
|
||||
: zeek::Tag(std::move(val))
|
||||
{
|
||||
}
|
||||
|
||||
Tag::Tag(EnumVal* val)
|
||||
: zeek::Tag({NewRef {}, val})
|
||||
{
|
||||
}
|
||||
|
||||
}
|
130
src/llanalyzer/Tag.h
Normal file
130
src/llanalyzer/Tag.h
Normal file
|
@ -0,0 +1,130 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "zeek-config.h"
|
||||
#include "../Tag.h"
|
||||
|
||||
namespace zeek::plugin {
|
||||
template <class T> class TaggedComponent;
|
||||
template <class T, class C> class ComponentManager;
|
||||
}
|
||||
namespace plugin {
|
||||
template <class T>
|
||||
using TaggedComponent [[deprecated("Remove in v4.1. Use zeek::plugin::TaggedComponent instead.")]] =
|
||||
zeek::plugin::TaggedComponent<T>;
|
||||
template <class T, class C>
|
||||
using ComponentManager [[deprecated("Remove in v4.1. Use zeek::plugin::ComponentManager instead.")]] =
|
||||
zeek::plugin::ComponentManager<T, C>;
|
||||
}
|
||||
|
||||
namespace zeek::llanalyzer {
|
||||
|
||||
class Manager;
|
||||
class Component;
|
||||
|
||||
/**
|
||||
* Class to identify a protocol analyzer type.
|
||||
*/
|
||||
class Tag : public zeek::Tag {
|
||||
public:
|
||||
/*
|
||||
* Copy constructor.
|
||||
*/
|
||||
Tag(const Tag& other) : zeek::Tag(other) { }
|
||||
|
||||
/**
|
||||
* Default constructor. This initializes the tag with an error value
|
||||
* that will make \c operator \c bool return false.
|
||||
*/
|
||||
Tag() : zeek::Tag() { }
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~Tag() = default;
|
||||
|
||||
/**
|
||||
* Returns false if the tag represents an error value rather than a
|
||||
* legal analyzer type.
|
||||
*/
|
||||
explicit operator bool() const { return *this != Tag(); }
|
||||
|
||||
/**
|
||||
* Assignment operator.
|
||||
*/
|
||||
Tag& operator=(const Tag& other);
|
||||
|
||||
/**
|
||||
* Compares two tags for equality.
|
||||
*/
|
||||
bool operator==(const Tag& other) const
|
||||
{
|
||||
return zeek::Tag::operator==(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two tags for inequality.
|
||||
*/
|
||||
bool operator!=(const Tag& other) const
|
||||
{
|
||||
return zeek::Tag::operator!=(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two tags for less-than relationship.
|
||||
*/
|
||||
bool operator<(const Tag& other) const
|
||||
{
|
||||
return zeek::Tag::operator<(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the \c Analyzer::Tag enum that corresponds to this tag.
|
||||
* The returned value does not have its ref-count increased.
|
||||
*
|
||||
* @param etype the script-layer enum type associated with the tag.
|
||||
*/
|
||||
const IntrusivePtr<EnumVal>& AsVal() const;
|
||||
|
||||
/**
|
||||
* Returns the \c Analyzer::Tag enum that corresponds to this tag.
|
||||
* The returned value does not have its ref-count increased.
|
||||
*
|
||||
* @param etype the script-layer enum type associated with the tag.
|
||||
*/
|
||||
[[deprecated("Remove in v4.1. Use AsVal() instead.")]]
|
||||
EnumVal* AsEnumVal() const;
|
||||
|
||||
static Tag Error;
|
||||
|
||||
protected:
|
||||
|
||||
friend class llanalyzer::Manager;
|
||||
friend class plugin::ComponentManager<Tag, Component>;
|
||||
friend class plugin::TaggedComponent<Tag>;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param type The main type. Note that the \a llanalyzer::Manager
|
||||
* manages the value space internally, so noone else should assign
|
||||
* any main types.
|
||||
*
|
||||
* @param subtype The sub type, which is left to an analyzer for
|
||||
* interpretation. By default it's set to zero.
|
||||
*/
|
||||
explicit Tag(type_t type, subtype_t subtype = 0);
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param val An enum value of script type \c Analyzer::Tag.
|
||||
*/
|
||||
explicit Tag(IntrusivePtr<EnumVal> val);
|
||||
|
||||
[[deprecated("Remove in v4.1. Construct from IntrusivePtr instead")]]
|
||||
explicit Tag(EnumVal* val);
|
||||
};
|
||||
|
||||
}
|
13
src/llanalyzer/dispatchers/CMakeLists.txt
Normal file
13
src/llanalyzer/dispatchers/CMakeLists.txt
Normal file
|
@ -0,0 +1,13 @@
|
|||
include(ZeekSubdir)
|
||||
|
||||
include_directories(BEFORE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
||||
|
||||
set(dispatcher_SRCS
|
||||
UniversalDispatcher.cc
|
||||
VectorDispatcher.cc
|
||||
)
|
||||
|
||||
bro_add_subdir_library(llanalyzer_dispatcher ${dispatcher_SRCS})
|
47
src/llanalyzer/dispatchers/Dispatcher.h
Normal file
47
src/llanalyzer/dispatchers/Dispatcher.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <utility>
|
||||
|
||||
#include "Analyzer.h"
|
||||
#include "Defines.h"
|
||||
|
||||
namespace zeek::llanalyzer {
|
||||
|
||||
class Dispatcher; // Forward decl for Value
|
||||
using register_pair = std::pair<identifier_t, std::pair<Analyzer*, Dispatcher*>>;
|
||||
using register_map = std::map<identifier_t, std::pair<Analyzer*, Dispatcher*>>;
|
||||
|
||||
class Value {
|
||||
public:
|
||||
Analyzer* analyzer;
|
||||
Dispatcher* dispatcher;
|
||||
|
||||
Value(Analyzer* analyzer, Dispatcher* dispatcher)
|
||||
: analyzer(analyzer), dispatcher(dispatcher)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class Dispatcher {
|
||||
public:
|
||||
virtual ~Dispatcher() = default;
|
||||
|
||||
virtual bool Register(identifier_t identifier, Analyzer* analyzer, Dispatcher* dispatcher) = 0;
|
||||
virtual void Register(const register_map& data)
|
||||
{
|
||||
for ( auto& current : data )
|
||||
Register(current.first, current.second.first, current.second.second);
|
||||
}
|
||||
|
||||
virtual const Value* Lookup(identifier_t identifier) const = 0;
|
||||
|
||||
virtual size_t Size() const = 0;
|
||||
virtual void Clear() = 0;
|
||||
|
||||
virtual void DumpDebug() const = 0;
|
||||
};
|
||||
|
||||
}
|
210
src/llanalyzer/dispatchers/UniversalDispatcher.cc
Normal file
210
src/llanalyzer/dispatchers/UniversalDispatcher.cc
Normal file
|
@ -0,0 +1,210 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "UniversalDispatcher.h"
|
||||
|
||||
namespace zeek::llanalyzer {
|
||||
|
||||
UniversalDispatcher::UniversalDispatcher() : generator(rd())
|
||||
{
|
||||
SetBins(2);
|
||||
|
||||
table = std::vector<pair_t>(ONE << m, {0, nullptr});
|
||||
|
||||
// Initialize random engine
|
||||
distribution_a = std::uniform_int_distribution<uint64_t>(1, ~static_cast<uint64_t>(0));
|
||||
distribution_b = std::uniform_int_distribution<uint64_t>(0, (ONE << w_minus_m) - ONE);
|
||||
|
||||
// Initialize random parameters
|
||||
RandomizeAB();
|
||||
}
|
||||
|
||||
UniversalDispatcher::~UniversalDispatcher()
|
||||
{
|
||||
FreeValues();
|
||||
}
|
||||
|
||||
bool UniversalDispatcher::Register(identifier_t identifier, Analyzer* analyzer, Dispatcher* dispatcher)
|
||||
{
|
||||
#if DEBUG > 1
|
||||
std::shared_ptr<void> deferred(nullptr, [=](...) {
|
||||
std::cout << "Inserted " << identifier << std::endl;
|
||||
});
|
||||
#endif
|
||||
|
||||
uint64_t hashed_id = Hash(identifier);
|
||||
if ( table[hashed_id].second == nullptr )
|
||||
{
|
||||
// Free bin, insert the value
|
||||
table[hashed_id] = std::make_pair(identifier, new Value(analyzer, dispatcher));
|
||||
return true;
|
||||
}
|
||||
else if ( table[hashed_id].first != identifier )
|
||||
{
|
||||
// The bin is not empty, but the content isn't the to-be-inserted identifier --> resolve collision
|
||||
|
||||
// Create intermediate representation with the new element in it, then rehash with that data
|
||||
std::vector<pair_t> intermediate = CreateIntermediate();
|
||||
intermediate.emplace_back(identifier, new Value(analyzer, dispatcher));
|
||||
|
||||
// Try increasing the #bins until it works or it can't get any larger.
|
||||
Rehash(intermediate);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Analyzer with this ID is already registered.
|
||||
return false;
|
||||
}
|
||||
|
||||
void UniversalDispatcher::Register(const register_map& data)
|
||||
{
|
||||
// Analyzer already registered
|
||||
for ( const auto& current : data )
|
||||
{
|
||||
if ( table[Hash(current.first)].second != nullptr )
|
||||
throw std::invalid_argument("Analyzer " + std::to_string(current.first) + " already registered!");
|
||||
}
|
||||
|
||||
// Create intermediate representation of current analyzer set, then add all new ones
|
||||
std::vector<pair_t> intermediate = CreateIntermediate();
|
||||
for ( const auto& current : data )
|
||||
intermediate.emplace_back(current.first, new Value(current.second.first, current.second.second));
|
||||
|
||||
Rehash(intermediate);
|
||||
}
|
||||
|
||||
Value* UniversalDispatcher::Lookup(identifier_t identifier) const
|
||||
{
|
||||
uint64_t hashed_id = Hash(identifier);
|
||||
|
||||
// The hashed_id can't be larger than the number of bins
|
||||
assert(hashed_id < table.size() && "Hashed ID is outside of the hash table range!");
|
||||
|
||||
pair_t entry = table[hashed_id];
|
||||
if ( entry.second != nullptr && entry.first == identifier )
|
||||
return entry.second;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t UniversalDispatcher::Size() const
|
||||
{
|
||||
size_t result = 0;
|
||||
for ( const auto& current : table )
|
||||
{
|
||||
if ( current.second != nullptr )
|
||||
result++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void UniversalDispatcher::Clear()
|
||||
{
|
||||
// Free all analyzers
|
||||
FreeValues();
|
||||
|
||||
SetBins(2);
|
||||
table = std::vector<pair_t>(ONE << m, {0, nullptr});
|
||||
RandomizeAB();
|
||||
}
|
||||
|
||||
size_t UniversalDispatcher::BucketCount()
|
||||
{
|
||||
return table.size();
|
||||
}
|
||||
|
||||
void UniversalDispatcher::Rehash()
|
||||
{
|
||||
// Intermediate representation is just the current table without nulls
|
||||
Rehash(CreateIntermediate());
|
||||
}
|
||||
|
||||
void UniversalDispatcher::DumpDebug() const
|
||||
{
|
||||
#ifdef DEBUG
|
||||
DBG_LOG(DBG_LLANALYZER, " Dispatcher elements (used/total): %lu/%lu", Size(), table.size());
|
||||
for ( size_t i = 0; i < table.size(); i++ )
|
||||
{
|
||||
if ( table[i].second != nullptr )
|
||||
DBG_LOG(DBG_LLANALYZER, " %#8x => %s, %p", table[i].first, table[i].second->analyzer->GetAnalyzerName(), table[i].second->dispatcher);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// #######################
|
||||
// ####### PRIVATE #######
|
||||
// #######################
|
||||
|
||||
void UniversalDispatcher::FreeValues()
|
||||
{
|
||||
for ( auto& current : table )
|
||||
{
|
||||
delete current.second;
|
||||
current.second = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void UniversalDispatcher::Rehash(const std::vector<pair_t>& intermediate)
|
||||
{
|
||||
while ( ! FindCollisionFreeHashFunction(intermediate) )
|
||||
{
|
||||
DBG_LOG(DBG_LLANALYZER, "Rehashing did not work. Increasing #bins to %" PRIu64 " (%" PRIu64 " bit).", (uint64_t)std::pow(2, m + 1), m + 1);
|
||||
SetBins(m + 1);
|
||||
}
|
||||
}
|
||||
|
||||
bool UniversalDispatcher::FindCollisionFreeHashFunction(const std::vector<pair_t>& intermediate)
|
||||
{
|
||||
// Don't even try if the number of values is larger than the number of buckets
|
||||
if ( ONE << m < intermediate.size() )
|
||||
return false;
|
||||
|
||||
// Remember the hash function parameters to not break the table if rehashing doesn't work
|
||||
uint64_t stored_a = a;
|
||||
uint64_t stored_b = b;
|
||||
|
||||
// Because the hash function hashes all values in the universe uniformly to m bins with probability 1/m
|
||||
// we should at least try a multiple of #bins times.
|
||||
for ( size_t i = 1; i <= (ONE << m); i++ )
|
||||
{
|
||||
// Step 1: Re-randomize hash function parameters
|
||||
RandomizeAB();
|
||||
|
||||
// Step 2: Create new table
|
||||
std::vector<pair_t> new_table(ONE << m, {0, nullptr});
|
||||
|
||||
// Step 3: Try to insert all elements into the new table with the new hash function
|
||||
bool finished = true;
|
||||
for ( const auto& current : intermediate )
|
||||
{
|
||||
uint64_t hashed_id = Hash(current.first);
|
||||
assert(hashed_id < new_table.size());
|
||||
if ( new_table[hashed_id].second == nullptr )
|
||||
{
|
||||
// Free bin, insert the value
|
||||
new_table[hashed_id] = current;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The bin is not empty which means there is a collision
|
||||
// (there are no duplicates in the intermediate representation so that can't be the case)
|
||||
finished = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Step 4: If the inserting finished without collisions, overwrite the previous table and exit
|
||||
if ( finished )
|
||||
{
|
||||
DBG_LOG(DBG_LLANALYZER, "Took %lu rehash(es) to resolve.", i);
|
||||
table = new_table;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Finding a collision free hash function failed. Revert the hash function parameters.
|
||||
a = stored_a;
|
||||
b = stored_b;
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
108
src/llanalyzer/dispatchers/UniversalDispatcher.h
Normal file
108
src/llanalyzer/dispatchers/UniversalDispatcher.h
Normal file
|
@ -0,0 +1,108 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <random>
|
||||
#include "Dispatcher.h"
|
||||
|
||||
namespace zeek::llanalyzer {
|
||||
|
||||
class UniversalDispatcher : public Dispatcher {
|
||||
public:
|
||||
UniversalDispatcher();
|
||||
~UniversalDispatcher() override;
|
||||
|
||||
bool Register(identifier_t identifier, Analyzer* analyzer, Dispatcher* dispatcher) override;
|
||||
void Register(const register_map& data) override;
|
||||
Value* Lookup(identifier_t identifier) const override;
|
||||
size_t Size() const override;
|
||||
void Clear() override;
|
||||
|
||||
void DumpDebug() const override;
|
||||
size_t BucketCount();
|
||||
|
||||
// Rehashes the hash table including re-randomization of the hash function.
|
||||
void Rehash();
|
||||
|
||||
private:
|
||||
using pair_t = std::pair<identifier_t, Value*>;
|
||||
static const uint64_t ONE = 1u;
|
||||
|
||||
// Chosen random constants for the currently selected collision free random hash function
|
||||
uint64_t a = 0; // Needs to be a random odd positive value < 2^(sizeof(uint64_t) * 8)
|
||||
uint64_t b = 0; // Needs to be a random non-negative value < 2^(((sizeof(uint64_t) * 8) - M)
|
||||
|
||||
// Current bits that define the number of bins. Initially 2 which means there are 2^2 = 4 bins.
|
||||
uint64_t m = 2;
|
||||
|
||||
// Current shift value which is the number of bits that are "insignificant" because of the universe size.
|
||||
uint64_t w_minus_m = 0;
|
||||
|
||||
// RNG
|
||||
std::random_device rd;
|
||||
std::mt19937_64 generator;
|
||||
std::uniform_int_distribution<uint64_t> distribution_a;
|
||||
std::uniform_int_distribution<uint64_t> distribution_b;
|
||||
|
||||
// Debug
|
||||
#if DEBUG > 0
|
||||
size_t nptr_counter = 0;
|
||||
size_t mismatch_counter = 0;
|
||||
size_t all_counter = 0;
|
||||
#endif
|
||||
|
||||
std::vector<pair_t> table;
|
||||
|
||||
void FreeValues();
|
||||
|
||||
void Rehash(const std::vector<pair_t>& intermediate);
|
||||
|
||||
/**
|
||||
* Tries to find a collision free hash function with the current number of buckets.
|
||||
*
|
||||
* @param intermediate The key-value set to store in the hashtable.
|
||||
* @return true, iff it found a collision-free hash function.
|
||||
*/
|
||||
bool FindCollisionFreeHashFunction(const std::vector<pair_t>& intermediate);
|
||||
|
||||
[[nodiscard]] inline uint64_t Hash(const uint64_t value) const
|
||||
{
|
||||
return (a * value + b) >> w_minus_m;
|
||||
}
|
||||
|
||||
inline void RandomizeAB()
|
||||
{
|
||||
do {
|
||||
a = distribution_a(generator);
|
||||
} while ( a % 2 == 0 );
|
||||
|
||||
b = distribution_b(generator);
|
||||
}
|
||||
|
||||
inline void SetBins(uint64_t new_m)
|
||||
{
|
||||
if ( new_m > (sizeof(uint64_t) * 8) )
|
||||
throw std::runtime_error("Number of bits for bin count too large.");
|
||||
|
||||
m = new_m;
|
||||
w_minus_m = sizeof(uint64_t) * 8 - m;
|
||||
distribution_b = std::uniform_int_distribution<uint64_t>(0, ((uint64_t)(1u) << w_minus_m) - (uint64_t)(1u));
|
||||
}
|
||||
|
||||
inline std::vector<pair_t> CreateIntermediate()
|
||||
{
|
||||
std::vector<pair_t> intermediate;
|
||||
for ( const auto& current : table )
|
||||
{
|
||||
if ( current.second != nullptr )
|
||||
{
|
||||
assert(current.second->analyzer != nullptr);
|
||||
intermediate.emplace_back(current.first, current.second);
|
||||
}
|
||||
}
|
||||
return intermediate;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
122
src/llanalyzer/dispatchers/VectorDispatcher.cc
Normal file
122
src/llanalyzer/dispatchers/VectorDispatcher.cc
Normal file
|
@ -0,0 +1,122 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "VectorDispatcher.h"
|
||||
|
||||
namespace zeek::llanalyzer {
|
||||
|
||||
VectorDispatcher::~VectorDispatcher()
|
||||
{
|
||||
FreeValues();
|
||||
}
|
||||
|
||||
bool VectorDispatcher::Register(identifier_t identifier, Analyzer* analyzer, Dispatcher* dispatcher)
|
||||
{
|
||||
// If the table has size 1 and the entry is nullptr, there was nothing added yet. Just add it.
|
||||
if ( table.size() == 1 && table[0] == nullptr )
|
||||
{
|
||||
table[0] = new Value(analyzer, dispatcher);
|
||||
lowest_identifier = identifier;
|
||||
return true;
|
||||
}
|
||||
|
||||
// If highestIdentifier == identifier, overwrite would happen -> no check needed, will return false
|
||||
if ( GetHighestIdentifier() < identifier )
|
||||
{
|
||||
table.resize(table.size() + (identifier - GetHighestIdentifier()), nullptr);
|
||||
}
|
||||
else if ( identifier < lowest_identifier )
|
||||
{
|
||||
// Lower than the lowest registered identifier. Shift up by lowerBound - identifier
|
||||
identifier_t distance = lowest_identifier - identifier;
|
||||
table.resize(table.size() + distance, nullptr);
|
||||
|
||||
// Shift values
|
||||
for ( ssize_t i = table.size() - 1; i >= 0; i-- )
|
||||
{
|
||||
if ( table[i] != nullptr )
|
||||
{
|
||||
table.at(i + distance) = table.at(i);
|
||||
table.at(i) = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
lowest_identifier = identifier;
|
||||
}
|
||||
|
||||
int64_t index = identifier - lowest_identifier;
|
||||
if ( table[index] == nullptr )
|
||||
{
|
||||
table[index] = new Value(analyzer, dispatcher);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void VectorDispatcher::Register(const register_map& data)
|
||||
{
|
||||
// Search smallest and largest identifier and resize vector
|
||||
const auto& lowest_new =
|
||||
std::min_element(data.begin(), data.end(),
|
||||
[](const register_pair& a, const register_pair& b) {
|
||||
return a.first < b.first;
|
||||
});
|
||||
|
||||
// Register lowest first in order to do shifting only once
|
||||
Register(lowest_new->first, lowest_new->second.first, lowest_new->second.second);
|
||||
for ( auto i = data.begin(); i != data.end(); i++ )
|
||||
{
|
||||
// Already added if i == lowest_new
|
||||
if ( i == lowest_new )
|
||||
continue;
|
||||
|
||||
if ( ! Register(i->first, i->second.first, i->second.second) )
|
||||
throw std::invalid_argument("Analyzer already registered!");
|
||||
}
|
||||
}
|
||||
|
||||
const Value* VectorDispatcher::Lookup(identifier_t identifier) const
|
||||
{
|
||||
int64_t index = identifier - lowest_identifier;
|
||||
if ( index >= 0 && index < static_cast<int64_t>(table.size()) && table[index] != nullptr )
|
||||
return table[index];
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t VectorDispatcher::Size() const
|
||||
{
|
||||
return std::count_if(table.begin(), table.end(), [](const auto* v) { return v != nullptr; });
|
||||
}
|
||||
|
||||
void VectorDispatcher::Clear()
|
||||
{
|
||||
FreeValues();
|
||||
table.clear();
|
||||
}
|
||||
|
||||
void VectorDispatcher::FreeValues()
|
||||
{
|
||||
for ( auto& current : table )
|
||||
{
|
||||
delete current;
|
||||
current = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void VectorDispatcher::DumpDebug() const
|
||||
{
|
||||
#ifdef DEBUG
|
||||
DBG_LOG(DBG_LLANALYZER, " Dispatcher elements (used/total): %lu/%lu", Size(), table.size());
|
||||
DBG_LOG(DBG_LLANALYZER, "TABLE SIZE %lu", table.size());
|
||||
for ( size_t i = 0; i < table.size(); i++ )
|
||||
{
|
||||
if ( table[i] != nullptr )
|
||||
DBG_LOG(DBG_LLANALYZER, " %#8lx => %s, %p", i+lowest_identifier, table[i]->analyzer->GetAnalyzerName(), table[i]->dispatcher);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
41
src/llanalyzer/dispatchers/VectorDispatcher.h
Normal file
41
src/llanalyzer/dispatchers/VectorDispatcher.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
#include "Dispatcher.h"
|
||||
|
||||
namespace zeek::llanalyzer {
|
||||
|
||||
class VectorDispatcher : public Dispatcher {
|
||||
public:
|
||||
VectorDispatcher()
|
||||
: table(std::vector<Value*>(1, nullptr))
|
||||
{ }
|
||||
|
||||
~VectorDispatcher() override;
|
||||
|
||||
bool Register(identifier_t identifier, Analyzer* analyzer, Dispatcher* dispatcher) override;
|
||||
void Register(const register_map& data) override;
|
||||
|
||||
const Value* Lookup(identifier_t identifier) const override;
|
||||
|
||||
size_t Size() const override;
|
||||
void Clear() override;
|
||||
|
||||
protected:
|
||||
void DumpDebug() const override;
|
||||
|
||||
private:
|
||||
identifier_t lowest_identifier = 0;
|
||||
std::vector<Value*> table;
|
||||
|
||||
void FreeValues();
|
||||
|
||||
inline identifier_t GetHighestIdentifier() const
|
||||
{
|
||||
return lowest_identifier + table.size() - 1;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
18
src/llanalyzer/protocol/CMakeLists.txt
Normal file
18
src/llanalyzer/protocol/CMakeLists.txt
Normal file
|
@ -0,0 +1,18 @@
|
|||
add_subdirectory(default)
|
||||
|
||||
add_subdirectory(wrapper)
|
||||
add_subdirectory(null)
|
||||
add_subdirectory(ethernet)
|
||||
add_subdirectory(vlan)
|
||||
add_subdirectory(pppoe)
|
||||
add_subdirectory(ppp_serial)
|
||||
add_subdirectory(ieee802_11)
|
||||
add_subdirectory(ieee802_11_radio)
|
||||
add_subdirectory(fddi)
|
||||
add_subdirectory(nflog)
|
||||
add_subdirectory(mpls)
|
||||
add_subdirectory(linux_sll)
|
||||
|
||||
add_subdirectory(arp)
|
||||
add_subdirectory(ipv4)
|
||||
add_subdirectory(ipv6)
|
19
src/llanalyzer/protocol/arp/ARP.cc
Normal file
19
src/llanalyzer/protocol/arp/ARP.cc
Normal file
|
@ -0,0 +1,19 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "ARP.h"
|
||||
|
||||
using namespace zeek::llanalyzer::ARP;
|
||||
|
||||
ARPAnalyzer::ARPAnalyzer()
|
||||
: zeek::llanalyzer::Analyzer("ARP")
|
||||
{
|
||||
}
|
||||
|
||||
std::tuple<zeek::llanalyzer::AnalyzerResult, zeek::llanalyzer::identifier_t> ARPAnalyzer::Analyze(Packet* packet)
|
||||
{
|
||||
// TODO: Make ARP analyzer a native LL analyzer
|
||||
packet->l3_proto = L3_ARP;
|
||||
|
||||
// Leave LL analyzer land
|
||||
return { AnalyzerResult::Terminate, 0 };
|
||||
}
|
23
src/llanalyzer/protocol/arp/ARP.h
Normal file
23
src/llanalyzer/protocol/arp/ARP.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <llanalyzer/Analyzer.h>
|
||||
#include <llanalyzer/Component.h>
|
||||
|
||||
namespace zeek::llanalyzer::ARP {
|
||||
|
||||
class ARPAnalyzer : public Analyzer {
|
||||
public:
|
||||
ARPAnalyzer();
|
||||
~ARPAnalyzer() override = default;
|
||||
|
||||
std::tuple<AnalyzerResult, identifier_t> Analyze(Packet* packet) override;
|
||||
|
||||
static Analyzer* Instantiate()
|
||||
{
|
||||
return new ARPAnalyzer();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
8
src/llanalyzer/protocol/arp/CMakeLists.txt
Normal file
8
src/llanalyzer/protocol/arp/CMakeLists.txt
Normal file
|
@ -0,0 +1,8 @@
|
|||
|
||||
include(ZeekPlugin)
|
||||
|
||||
include_directories(BEFORE $ {CMAKE_CURRENT_SOURCE_DIR} $ {CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
zeek_plugin_begin(LLAnalyzer ARP)
|
||||
zeek_plugin_cc(ARP.cc Plugin.cc)
|
||||
zeek_plugin_end()
|
24
src/llanalyzer/protocol/arp/Plugin.cc
Normal file
24
src/llanalyzer/protocol/arp/Plugin.cc
Normal file
|
@ -0,0 +1,24 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "plugin/Plugin.h"
|
||||
#include "ARP.h"
|
||||
#include "llanalyzer/Component.h"
|
||||
|
||||
namespace zeek::plugin::LLAnalyzer_ARP {
|
||||
|
||||
class Plugin : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure()
|
||||
{
|
||||
AddComponent(new zeek::llanalyzer::Component("ARP",
|
||||
zeek::llanalyzer::ARP::ARPAnalyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "LLAnalyzer::ARP";
|
||||
config.description = "ARP LL-Analyzer";
|
||||
return config;
|
||||
}
|
||||
|
||||
} plugin;
|
||||
|
||||
}
|
8
src/llanalyzer/protocol/default/CMakeLists.txt
Normal file
8
src/llanalyzer/protocol/default/CMakeLists.txt
Normal file
|
@ -0,0 +1,8 @@
|
|||
|
||||
include(ZeekPlugin)
|
||||
|
||||
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
zeek_plugin_begin(LLAnalyzer Default)
|
||||
zeek_plugin_cc(Default.cc Plugin.cc)
|
||||
zeek_plugin_end()
|
28
src/llanalyzer/protocol/default/Default.cc
Normal file
28
src/llanalyzer/protocol/default/Default.cc
Normal file
|
@ -0,0 +1,28 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "Default.h"
|
||||
#include "NetVar.h"
|
||||
|
||||
using namespace zeek::llanalyzer::Default;
|
||||
|
||||
DefaultAnalyzer::DefaultAnalyzer()
|
||||
: zeek::llanalyzer::Analyzer("DefaultAnalyzer")
|
||||
{
|
||||
}
|
||||
|
||||
std::tuple<zeek::llanalyzer::AnalyzerResult, zeek::llanalyzer::identifier_t> DefaultAnalyzer::Analyze(Packet* packet)
|
||||
{
|
||||
auto& pdata = packet->cur_pos;
|
||||
|
||||
// Assume we're pointing at IP. Just figure out which version.
|
||||
if ( pdata + sizeof(struct ip) >= packet->GetEndOfData() )
|
||||
{
|
||||
packet->Weird("default_ll_analyser_failed");
|
||||
return { AnalyzerResult::Failed, 0 };
|
||||
}
|
||||
|
||||
auto ip = (const struct ip *)pdata;
|
||||
identifier_t protocol = ip->ip_v;
|
||||
|
||||
return { AnalyzerResult::Continue, protocol };
|
||||
}
|
23
src/llanalyzer/protocol/default/Default.h
Normal file
23
src/llanalyzer/protocol/default/Default.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <llanalyzer/Analyzer.h>
|
||||
#include <llanalyzer/Component.h>
|
||||
|
||||
namespace zeek::llanalyzer::Default {
|
||||
|
||||
class DefaultAnalyzer : public Analyzer {
|
||||
public:
|
||||
DefaultAnalyzer();
|
||||
~DefaultAnalyzer() override = default;
|
||||
|
||||
std::tuple<AnalyzerResult, identifier_t> Analyze(Packet* packet) override;
|
||||
|
||||
static Analyzer* Instantiate()
|
||||
{
|
||||
return new DefaultAnalyzer();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
24
src/llanalyzer/protocol/default/Plugin.cc
Normal file
24
src/llanalyzer/protocol/default/Plugin.cc
Normal file
|
@ -0,0 +1,24 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "Default.h"
|
||||
#include "plugin/Plugin.h"
|
||||
#include "llanalyzer/Component.h"
|
||||
|
||||
namespace zeek::plugin::LLAnalyzer_Default {
|
||||
|
||||
class Plugin : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure()
|
||||
{
|
||||
AddComponent(new zeek::llanalyzer::Component("DefaultAnalyzer",
|
||||
zeek::llanalyzer::Default::DefaultAnalyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "LLAnalyzer::DefaultAnalyzer";
|
||||
config.description = "Default LL-Analyzer for IP fallback";
|
||||
return config;
|
||||
}
|
||||
|
||||
} plugin;
|
||||
|
||||
}
|
8
src/llanalyzer/protocol/ethernet/CMakeLists.txt
Normal file
8
src/llanalyzer/protocol/ethernet/CMakeLists.txt
Normal file
|
@ -0,0 +1,8 @@
|
|||
|
||||
include(ZeekPlugin)
|
||||
|
||||
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
zeek_plugin_begin(LLAnalyzer Ethernet)
|
||||
zeek_plugin_cc(Ethernet.cc Plugin.cc)
|
||||
zeek_plugin_end()
|
75
src/llanalyzer/protocol/ethernet/Ethernet.cc
Normal file
75
src/llanalyzer/protocol/ethernet/Ethernet.cc
Normal file
|
@ -0,0 +1,75 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "Ethernet.h"
|
||||
#include "NetVar.h"
|
||||
|
||||
using namespace zeek::llanalyzer::Ethernet;
|
||||
|
||||
EthernetAnalyzer::EthernetAnalyzer()
|
||||
: zeek::llanalyzer::Analyzer("Ethernet")
|
||||
{
|
||||
}
|
||||
|
||||
std::tuple<zeek::llanalyzer::AnalyzerResult, zeek::llanalyzer::identifier_t> EthernetAnalyzer::Analyze(Packet* packet)
|
||||
{
|
||||
auto& pdata = packet->cur_pos;
|
||||
auto end_of_data = packet->GetEndOfData();
|
||||
|
||||
// Skip past Cisco FabricPath to encapsulated ethernet frame.
|
||||
if ( pdata[12] == 0x89 && pdata[13] == 0x03 )
|
||||
{
|
||||
auto constexpr cfplen = 16;
|
||||
|
||||
if ( pdata + cfplen + 14 >= end_of_data )
|
||||
{
|
||||
packet->Weird("truncated_link_header_cfp");
|
||||
return { AnalyzerResult::Failed, 0 };
|
||||
}
|
||||
|
||||
pdata += cfplen;
|
||||
}
|
||||
|
||||
// Get protocol being carried from the ethernet frame.
|
||||
identifier_t protocol = (pdata[12] << 8) + pdata[13];
|
||||
|
||||
packet->eth_type = protocol;
|
||||
packet->l2_dst = pdata;
|
||||
packet->l2_src = pdata + 6;
|
||||
|
||||
// Ethernet II frames
|
||||
if ( protocol >= 1536 )
|
||||
{
|
||||
pdata += 14;
|
||||
return { AnalyzerResult::Continue, protocol };
|
||||
}
|
||||
|
||||
// Other ethernet frame types
|
||||
if ( protocol <= 1500 )
|
||||
{
|
||||
if ( pdata + 16 >= end_of_data )
|
||||
{
|
||||
packet->Weird("truncated_ethernet_frame");
|
||||
return { AnalyzerResult::Failed, 0 };
|
||||
}
|
||||
|
||||
// In the following we use undefined EtherTypes to signal uncommon
|
||||
// frame types. This allows specialized analyzers to take over.
|
||||
// Note that pdata remains at the start of the ethernet frame.
|
||||
|
||||
// IEEE 802.2 SNAP
|
||||
if ( pdata[14] == 0xAA && pdata[15] == 0xAA)
|
||||
return { AnalyzerResult::Continue, 1502 };
|
||||
|
||||
// Novell raw IEEE 802.3
|
||||
if ( pdata[14] == 0xFF && pdata[15] == 0xFF)
|
||||
return { AnalyzerResult::Continue, 1503 };
|
||||
|
||||
|
||||
// IEEE 802.2 LLC
|
||||
return { AnalyzerResult::Continue, 1501 };
|
||||
}
|
||||
|
||||
// Undefined (1500 < EtherType < 1536)
|
||||
packet->Weird("undefined_ether_type");
|
||||
return { AnalyzerResult::Failed, protocol };
|
||||
}
|
23
src/llanalyzer/protocol/ethernet/Ethernet.h
Normal file
23
src/llanalyzer/protocol/ethernet/Ethernet.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <llanalyzer/Analyzer.h>
|
||||
#include <llanalyzer/Component.h>
|
||||
|
||||
namespace zeek::llanalyzer::Ethernet {
|
||||
|
||||
class EthernetAnalyzer : public Analyzer {
|
||||
public:
|
||||
EthernetAnalyzer();
|
||||
~EthernetAnalyzer() override = default;
|
||||
|
||||
std::tuple<AnalyzerResult, identifier_t> Analyze(Packet* packet) override;
|
||||
|
||||
static Analyzer* Instantiate()
|
||||
{
|
||||
return new EthernetAnalyzer();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
24
src/llanalyzer/protocol/ethernet/Plugin.cc
Normal file
24
src/llanalyzer/protocol/ethernet/Plugin.cc
Normal file
|
@ -0,0 +1,24 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "Ethernet.h"
|
||||
#include "plugin/Plugin.h"
|
||||
#include "llanalyzer/Component.h"
|
||||
|
||||
namespace zeek::plugin::LLAnalyzer_Ethernet {
|
||||
|
||||
class Plugin : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure()
|
||||
{
|
||||
AddComponent(new zeek::llanalyzer::Component("Ethernet",
|
||||
zeek::llanalyzer::Ethernet::EthernetAnalyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "LLAnalyzer::Ethernet";
|
||||
config.description = "Ethernet LL-Analyzer";
|
||||
return config;
|
||||
}
|
||||
|
||||
} plugin;
|
||||
|
||||
}
|
8
src/llanalyzer/protocol/fddi/CMakeLists.txt
Normal file
8
src/llanalyzer/protocol/fddi/CMakeLists.txt
Normal file
|
@ -0,0 +1,8 @@
|
|||
|
||||
include(ZeekPlugin)
|
||||
|
||||
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
zeek_plugin_begin(LLAnalyzer FDDI)
|
||||
zeek_plugin_cc(FDDI.cc Plugin.cc)
|
||||
zeek_plugin_end()
|
27
src/llanalyzer/protocol/fddi/FDDI.cc
Normal file
27
src/llanalyzer/protocol/fddi/FDDI.cc
Normal file
|
@ -0,0 +1,27 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "FDDI.h"
|
||||
#include "NetVar.h"
|
||||
|
||||
using namespace zeek::llanalyzer::FDDI;
|
||||
|
||||
FDDIAnalyzer::FDDIAnalyzer()
|
||||
: zeek::llanalyzer::Analyzer("FDDI")
|
||||
{
|
||||
}
|
||||
|
||||
std::tuple<zeek::llanalyzer::AnalyzerResult, zeek::llanalyzer::identifier_t> FDDIAnalyzer::Analyze(Packet* packet)
|
||||
{
|
||||
auto& pdata = packet->cur_pos;
|
||||
auto hdr_size = 13 + 8; // FDDI header + LLC
|
||||
|
||||
if ( pdata + hdr_size >= packet->GetEndOfData() )
|
||||
{
|
||||
packet->Weird("FDDI_analyzer_failed");
|
||||
return { AnalyzerResult::Failed, 0 };
|
||||
}
|
||||
|
||||
// We just skip the header and hope for default analysis
|
||||
pdata += hdr_size;
|
||||
return { AnalyzerResult::Continue, -1 };
|
||||
}
|
23
src/llanalyzer/protocol/fddi/FDDI.h
Normal file
23
src/llanalyzer/protocol/fddi/FDDI.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <llanalyzer/Analyzer.h>
|
||||
#include <llanalyzer/Component.h>
|
||||
|
||||
namespace zeek::llanalyzer::FDDI {
|
||||
|
||||
class FDDIAnalyzer : public zeek::llanalyzer::Analyzer {
|
||||
public:
|
||||
FDDIAnalyzer();
|
||||
~FDDIAnalyzer() override = default;
|
||||
|
||||
std::tuple<AnalyzerResult, identifier_t> Analyze(Packet* packet) override;
|
||||
|
||||
static zeek::llanalyzer::Analyzer* Instantiate()
|
||||
{
|
||||
return new FDDIAnalyzer();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
24
src/llanalyzer/protocol/fddi/Plugin.cc
Normal file
24
src/llanalyzer/protocol/fddi/Plugin.cc
Normal file
|
@ -0,0 +1,24 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "FDDI.h"
|
||||
#include "plugin/Plugin.h"
|
||||
#include "llanalyzer/Component.h"
|
||||
|
||||
namespace zeek::plugin::LLAnalyzer_FDDI {
|
||||
|
||||
class Plugin : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure()
|
||||
{
|
||||
AddComponent(new zeek::llanalyzer::Component("FDDI",
|
||||
zeek::llanalyzer::FDDI::FDDIAnalyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "LLAnalyzer::FDDI";
|
||||
config.description = "FDDI LL-Analyzer";
|
||||
return config;
|
||||
}
|
||||
|
||||
} plugin;
|
||||
|
||||
}
|
8
src/llanalyzer/protocol/ieee802_11/CMakeLists.txt
Normal file
8
src/llanalyzer/protocol/ieee802_11/CMakeLists.txt
Normal file
|
@ -0,0 +1,8 @@
|
|||
|
||||
include(ZeekPlugin)
|
||||
|
||||
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
zeek_plugin_begin(LLAnalyzer IEEE802_11)
|
||||
zeek_plugin_cc(IEEE802_11.cc Plugin.cc)
|
||||
zeek_plugin_end()
|
113
src/llanalyzer/protocol/ieee802_11/IEEE802_11.cc
Normal file
113
src/llanalyzer/protocol/ieee802_11/IEEE802_11.cc
Normal file
|
@ -0,0 +1,113 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "IEEE802_11.h"
|
||||
#include "NetVar.h"
|
||||
|
||||
using namespace zeek::llanalyzer::IEEE802_11;
|
||||
|
||||
IEEE802_11Analyzer::IEEE802_11Analyzer()
|
||||
: zeek::llanalyzer::Analyzer("IEEE802_11")
|
||||
{
|
||||
}
|
||||
|
||||
std::tuple<zeek::llanalyzer::AnalyzerResult, zeek::llanalyzer::identifier_t> IEEE802_11Analyzer::Analyze(Packet* packet)
|
||||
{
|
||||
auto& pdata = packet->cur_pos;
|
||||
auto end_of_data = packet->GetEndOfData();
|
||||
|
||||
u_char len_80211 = 24; // minimal length of data frames
|
||||
|
||||
if ( pdata + len_80211 >= end_of_data )
|
||||
{
|
||||
packet->Weird("truncated_802_11_header");
|
||||
return { AnalyzerResult::Failed, 0 };
|
||||
}
|
||||
|
||||
u_char fc_80211 = pdata[0]; // Frame Control field
|
||||
|
||||
// Skip non-data frame types (management & control).
|
||||
if ( ! ((fc_80211 >> 2) & 0x02) )
|
||||
return { AnalyzerResult::Failed, 0 };
|
||||
|
||||
// Skip subtypes without data.
|
||||
if ( (fc_80211 >> 4) & 0x04 )
|
||||
return { AnalyzerResult::Failed, 0 };
|
||||
|
||||
// 'To DS' and 'From DS' flags set indicate use of the 4th
|
||||
// address field.
|
||||
if ( (pdata[1] & 0x03) == 0x03 )
|
||||
len_80211 += packet->L2_ADDR_LEN;
|
||||
|
||||
// Look for the QoS indicator bit.
|
||||
if ( (fc_80211 >> 4) & 0x08 )
|
||||
{
|
||||
// Skip in case of A-MSDU subframes indicated by QoS
|
||||
// control field.
|
||||
if ( pdata[len_80211] & 0x80 )
|
||||
return { AnalyzerResult::Failed, 0 };
|
||||
|
||||
len_80211 += 2;
|
||||
}
|
||||
|
||||
if ( pdata + len_80211 >= end_of_data )
|
||||
{
|
||||
packet->Weird("truncated_802_11_header");
|
||||
return { AnalyzerResult::Failed, 0 };
|
||||
}
|
||||
|
||||
// Determine link-layer addresses based
|
||||
// on 'To DS' and 'From DS' flags
|
||||
switch ( pdata[1] & 0x03 )
|
||||
{
|
||||
case 0x00:
|
||||
packet->l2_src = pdata + 10;
|
||||
packet->l2_dst = pdata + 4;
|
||||
break;
|
||||
|
||||
case 0x01:
|
||||
packet->l2_src = pdata + 10;
|
||||
packet->l2_dst = pdata + 16;
|
||||
break;
|
||||
|
||||
case 0x02:
|
||||
packet->l2_src = pdata + 16;
|
||||
packet->l2_dst = pdata + 4;
|
||||
break;
|
||||
|
||||
case 0x03:
|
||||
packet->l2_src = pdata + 24;
|
||||
packet->l2_dst = pdata + 16;
|
||||
break;
|
||||
}
|
||||
|
||||
// skip 802.11 data header
|
||||
pdata += len_80211;
|
||||
|
||||
if ( pdata + 8 >= end_of_data )
|
||||
{
|
||||
packet->Weird("truncated_802_11_header");
|
||||
return { AnalyzerResult::Failed, 0 };
|
||||
}
|
||||
|
||||
// Check that the DSAP and SSAP are both SNAP and that the control
|
||||
// field indicates that this is an unnumbered frame.
|
||||
// The organization code (24bits) needs to also be zero to
|
||||
// indicate that this is encapsulated ethernet.
|
||||
if ( pdata[0] == 0xAA && pdata[1] == 0xAA && pdata[2] == 0x03 &&
|
||||
pdata[3] == 0 && pdata[4] == 0 && pdata[5] == 0 )
|
||||
{
|
||||
pdata += 6;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If this is a logical link control frame without the
|
||||
// possibility of having a protocol we care about, we'll
|
||||
// just skip it for now.
|
||||
return { AnalyzerResult::Failed, 0 };
|
||||
}
|
||||
|
||||
identifier_t protocol = (pdata[0] << 8) + pdata[1];
|
||||
pdata += 2;
|
||||
|
||||
return { AnalyzerResult::Continue, protocol };
|
||||
}
|
23
src/llanalyzer/protocol/ieee802_11/IEEE802_11.h
Normal file
23
src/llanalyzer/protocol/ieee802_11/IEEE802_11.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <llanalyzer/Analyzer.h>
|
||||
#include <llanalyzer/Component.h>
|
||||
|
||||
namespace zeek::llanalyzer::IEEE802_11 {
|
||||
|
||||
class IEEE802_11Analyzer : public Analyzer {
|
||||
public:
|
||||
IEEE802_11Analyzer();
|
||||
~IEEE802_11Analyzer() override = default;
|
||||
|
||||
std::tuple<AnalyzerResult, identifier_t> Analyze(Packet* packet) override;
|
||||
|
||||
static Analyzer* Instantiate()
|
||||
{
|
||||
return new IEEE802_11Analyzer();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
24
src/llanalyzer/protocol/ieee802_11/Plugin.cc
Normal file
24
src/llanalyzer/protocol/ieee802_11/Plugin.cc
Normal file
|
@ -0,0 +1,24 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "IEEE802_11.h"
|
||||
#include "plugin/Plugin.h"
|
||||
#include "llanalyzer/Component.h"
|
||||
|
||||
namespace zeek::plugin::LLAnalyzer_IEEE802_11 {
|
||||
|
||||
class Plugin : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure()
|
||||
{
|
||||
AddComponent(new zeek::llanalyzer::Component("IEEE802_11",
|
||||
zeek::llanalyzer::IEEE802_11::IEEE802_11Analyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "LLAnalyzer::IEEE802_11";
|
||||
config.description = "IEEE 802.11 LL-Analyzer";
|
||||
return config;
|
||||
}
|
||||
|
||||
} plugin;
|
||||
|
||||
}
|
8
src/llanalyzer/protocol/ieee802_11_radio/CMakeLists.txt
Normal file
8
src/llanalyzer/protocol/ieee802_11_radio/CMakeLists.txt
Normal file
|
@ -0,0 +1,8 @@
|
|||
|
||||
include(ZeekPlugin)
|
||||
|
||||
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
zeek_plugin_begin(LLAnalyzer IEEE802_11_Radio)
|
||||
zeek_plugin_cc(IEEE802_11_Radio.cc Plugin.cc)
|
||||
zeek_plugin_end()
|
38
src/llanalyzer/protocol/ieee802_11_radio/IEEE802_11_Radio.cc
Normal file
38
src/llanalyzer/protocol/ieee802_11_radio/IEEE802_11_Radio.cc
Normal file
|
@ -0,0 +1,38 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include <pcap.h>
|
||||
|
||||
#include "IEEE802_11_Radio.h"
|
||||
#include "NetVar.h"
|
||||
|
||||
using namespace zeek::llanalyzer::IEEE802_11_Radio;
|
||||
|
||||
IEEE802_11_RadioAnalyzer::IEEE802_11_RadioAnalyzer()
|
||||
: zeek::llanalyzer::Analyzer("IEEE802_11_Radio")
|
||||
{
|
||||
}
|
||||
|
||||
std::tuple<zeek::llanalyzer::AnalyzerResult, zeek::llanalyzer::identifier_t> IEEE802_11_RadioAnalyzer::Analyze(Packet* packet)
|
||||
{
|
||||
auto pdata = packet->cur_pos;
|
||||
auto end_of_data = packet->GetEndOfData();
|
||||
|
||||
if ( pdata + 3 >= end_of_data )
|
||||
{
|
||||
packet->Weird("truncated_radiotap_header");
|
||||
return { AnalyzerResult::Failed, 0 };
|
||||
}
|
||||
|
||||
// Skip over the RadioTap header
|
||||
int rtheader_len = (pdata[3] << 8) + pdata[2];
|
||||
|
||||
if ( pdata + rtheader_len >= end_of_data )
|
||||
{
|
||||
packet->Weird("truncated_radiotap_header");
|
||||
return { AnalyzerResult::Failed, 0 };
|
||||
}
|
||||
|
||||
packet->cur_pos += rtheader_len;
|
||||
|
||||
return { AnalyzerResult::Continue, DLT_IEEE802_11 };
|
||||
}
|
23
src/llanalyzer/protocol/ieee802_11_radio/IEEE802_11_Radio.h
Normal file
23
src/llanalyzer/protocol/ieee802_11_radio/IEEE802_11_Radio.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <llanalyzer/Analyzer.h>
|
||||
#include <llanalyzer/Component.h>
|
||||
|
||||
namespace zeek::llanalyzer::IEEE802_11_Radio {
|
||||
|
||||
class IEEE802_11_RadioAnalyzer : public Analyzer {
|
||||
public:
|
||||
IEEE802_11_RadioAnalyzer();
|
||||
~IEEE802_11_RadioAnalyzer() override = default;
|
||||
|
||||
std::tuple<AnalyzerResult, identifier_t> Analyze(Packet* packet) override;
|
||||
|
||||
static Analyzer* Instantiate()
|
||||
{
|
||||
return new IEEE802_11_RadioAnalyzer();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
23
src/llanalyzer/protocol/ieee802_11_radio/Plugin.cc
Normal file
23
src/llanalyzer/protocol/ieee802_11_radio/Plugin.cc
Normal file
|
@ -0,0 +1,23 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "IEEE802_11_Radio.h"
|
||||
#include "plugin/Plugin.h"
|
||||
#include "llanalyzer/Component.h"
|
||||
|
||||
namespace zeek::plugin::LLAnalyzer_IEEE802_11_Radio {
|
||||
|
||||
class Plugin : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure()
|
||||
{
|
||||
AddComponent(new zeek::llanalyzer::Component("IEEE802_11_Radio",
|
||||
zeek::llanalyzer::IEEE802_11_Radio::IEEE802_11_RadioAnalyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "LLAnalyzer::IEEE802_11_Radio";
|
||||
config.description = "IEEE 802.11 Radiotap LL-Analyzer";
|
||||
return config;
|
||||
}
|
||||
|
||||
} plugin;
|
||||
}
|
8
src/llanalyzer/protocol/ipv4/CMakeLists.txt
Normal file
8
src/llanalyzer/protocol/ipv4/CMakeLists.txt
Normal file
|
@ -0,0 +1,8 @@
|
|||
|
||||
include(ZeekPlugin)
|
||||
|
||||
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
zeek_plugin_begin(LLAnalyzer IPv4)
|
||||
zeek_plugin_cc(IPv4.cc Plugin.cc)
|
||||
zeek_plugin_end()
|
18
src/llanalyzer/protocol/ipv4/IPv4.cc
Normal file
18
src/llanalyzer/protocol/ipv4/IPv4.cc
Normal file
|
@ -0,0 +1,18 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "IPv4.h"
|
||||
|
||||
using namespace zeek::llanalyzer::IPv4;
|
||||
|
||||
IPv4Analyzer::IPv4Analyzer()
|
||||
: zeek::llanalyzer::Analyzer("IPv4")
|
||||
{
|
||||
}
|
||||
|
||||
std::tuple<zeek::llanalyzer::AnalyzerResult, zeek::llanalyzer::identifier_t> IPv4Analyzer::Analyze(Packet* packet)
|
||||
{
|
||||
packet->l3_proto = L3_IPV4;
|
||||
|
||||
// Leave LL analyzer land
|
||||
return { AnalyzerResult::Terminate, 0 };
|
||||
}
|
23
src/llanalyzer/protocol/ipv4/IPv4.h
Normal file
23
src/llanalyzer/protocol/ipv4/IPv4.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <llanalyzer/Analyzer.h>
|
||||
#include <llanalyzer/Component.h>
|
||||
|
||||
namespace zeek::llanalyzer::IPv4 {
|
||||
|
||||
class IPv4Analyzer : public Analyzer {
|
||||
public:
|
||||
IPv4Analyzer();
|
||||
~IPv4Analyzer() override = default;
|
||||
|
||||
std::tuple<AnalyzerResult, identifier_t> Analyze(Packet* packet) override;
|
||||
|
||||
static Analyzer* Instantiate()
|
||||
{
|
||||
return new IPv4Analyzer();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
24
src/llanalyzer/protocol/ipv4/Plugin.cc
Normal file
24
src/llanalyzer/protocol/ipv4/Plugin.cc
Normal file
|
@ -0,0 +1,24 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "IPv4.h"
|
||||
#include "plugin/Plugin.h"
|
||||
#include "llanalyzer/Component.h"
|
||||
|
||||
namespace zeek::plugin::LLAnalyzer_IPv4 {
|
||||
|
||||
class Plugin : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure()
|
||||
{
|
||||
AddComponent(new zeek::llanalyzer::Component("IPv4",
|
||||
zeek::llanalyzer::IPv4::IPv4Analyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "LLAnalyzer::IPv4";
|
||||
config.description = "IPv4 LL-Analyzer";
|
||||
return config;
|
||||
}
|
||||
|
||||
} plugin;
|
||||
|
||||
}
|
8
src/llanalyzer/protocol/ipv6/CMakeLists.txt
Normal file
8
src/llanalyzer/protocol/ipv6/CMakeLists.txt
Normal file
|
@ -0,0 +1,8 @@
|
|||
|
||||
include(ZeekPlugin)
|
||||
|
||||
include_directories(BEFORE $ {CMAKE_CURRENT_SOURCE_DIR} $ {CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
zeek_plugin_begin(LLAnalyzer IPv6)
|
||||
zeek_plugin_cc(IPv6.cc Plugin.cc)
|
||||
zeek_plugin_end()
|
18
src/llanalyzer/protocol/ipv6/IPv6.cc
Normal file
18
src/llanalyzer/protocol/ipv6/IPv6.cc
Normal file
|
@ -0,0 +1,18 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "IPv6.h"
|
||||
|
||||
using namespace zeek::llanalyzer::IPv6;
|
||||
|
||||
IPv6Analyzer::IPv6Analyzer()
|
||||
: zeek::llanalyzer::Analyzer("IPv6")
|
||||
{
|
||||
}
|
||||
|
||||
std::tuple<zeek::llanalyzer::AnalyzerResult, zeek::llanalyzer::identifier_t> IPv6Analyzer::Analyze(Packet* packet)
|
||||
{
|
||||
packet->l3_proto = L3_IPV6;
|
||||
|
||||
// Leave LL analyzer land
|
||||
return { AnalyzerResult::Terminate, 0 };
|
||||
}
|
23
src/llanalyzer/protocol/ipv6/IPv6.h
Normal file
23
src/llanalyzer/protocol/ipv6/IPv6.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <llanalyzer/Analyzer.h>
|
||||
#include <llanalyzer/Component.h>
|
||||
|
||||
namespace zeek::llanalyzer::IPv6 {
|
||||
|
||||
class IPv6Analyzer : public Analyzer {
|
||||
public:
|
||||
IPv6Analyzer();
|
||||
~IPv6Analyzer() override = default;
|
||||
|
||||
std::tuple<AnalyzerResult, identifier_t> Analyze(Packet* packet) override;
|
||||
|
||||
static Analyzer* Instantiate()
|
||||
{
|
||||
return new IPv6Analyzer();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
23
src/llanalyzer/protocol/ipv6/Plugin.cc
Normal file
23
src/llanalyzer/protocol/ipv6/Plugin.cc
Normal file
|
@ -0,0 +1,23 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "plugin/Plugin.h"
|
||||
#include "IPv6.h"
|
||||
#include "llanalyzer/Component.h"
|
||||
|
||||
namespace zeek::plugin::LLAnalyzer_IPv6 {
|
||||
|
||||
class Plugin : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure()
|
||||
{
|
||||
AddComponent(new zeek::llanalyzer::Component("IPv6",
|
||||
zeek::llanalyzer::IPv6::IPv6Analyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "LLAnalyzer::IPv6";
|
||||
config.description = "IPv6 LL-Analyzer";
|
||||
return config;
|
||||
}
|
||||
} plugin;
|
||||
|
||||
}
|
8
src/llanalyzer/protocol/linux_sll/CMakeLists.txt
Normal file
8
src/llanalyzer/protocol/linux_sll/CMakeLists.txt
Normal file
|
@ -0,0 +1,8 @@
|
|||
|
||||
include(ZeekPlugin)
|
||||
|
||||
include_directories(BEFORE $ {CMAKE_CURRENT_SOURCE_DIR} $ {CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
zeek_plugin_begin(LLAnalyzer LinuxSLL)
|
||||
zeek_plugin_cc(LinuxSLL.cc Plugin.cc)
|
||||
zeek_plugin_end()
|
34
src/llanalyzer/protocol/linux_sll/LinuxSLL.cc
Normal file
34
src/llanalyzer/protocol/linux_sll/LinuxSLL.cc
Normal file
|
@ -0,0 +1,34 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "LinuxSLL.h"
|
||||
|
||||
using namespace zeek::llanalyzer::LinuxSLL;
|
||||
|
||||
LinuxSLLAnalyzer::LinuxSLLAnalyzer()
|
||||
: zeek::llanalyzer::Analyzer("LinuxSLL")
|
||||
{
|
||||
}
|
||||
|
||||
std::tuple<zeek::llanalyzer::AnalyzerResult, zeek::llanalyzer::identifier_t> LinuxSLLAnalyzer::Analyze(Packet* packet)
|
||||
{
|
||||
auto& pdata = packet->cur_pos;
|
||||
|
||||
if ( pdata + sizeof(SLLHeader) >= packet->GetEndOfData() )
|
||||
{
|
||||
packet->Weird("truncated_Linux_SLL_header");
|
||||
return { AnalyzerResult::Failed, 0 };
|
||||
}
|
||||
|
||||
//TODO: Handle different ARPHRD_types
|
||||
auto hdr = (const SLLHeader*)pdata;
|
||||
|
||||
identifier_t protocol = ntohs(hdr->protocol_type);
|
||||
packet->l2_src = (u_char*) &(hdr->addr);
|
||||
|
||||
// SLL doesn't include a destination address in the header, but not setting l2_dst to something
|
||||
// here will cause crashes elsewhere.
|
||||
packet->l2_dst = Packet::L2_EMPTY_ADDR;
|
||||
|
||||
pdata += sizeof(SLLHeader);
|
||||
return { AnalyzerResult::Continue, protocol };
|
||||
}
|
35
src/llanalyzer/protocol/linux_sll/LinuxSLL.h
Normal file
35
src/llanalyzer/protocol/linux_sll/LinuxSLL.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <llanalyzer/Analyzer.h>
|
||||
#include <llanalyzer/Component.h>
|
||||
|
||||
namespace zeek::llanalyzer::LinuxSLL {
|
||||
|
||||
class LinuxSLLAnalyzer : public Analyzer {
|
||||
public:
|
||||
LinuxSLLAnalyzer();
|
||||
~LinuxSLLAnalyzer() override = default;
|
||||
|
||||
std::tuple<AnalyzerResult, identifier_t> Analyze(Packet* packet) override;
|
||||
|
||||
static Analyzer* Instantiate()
|
||||
{
|
||||
return new LinuxSLLAnalyzer();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// Structure layout is based on https://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL.html
|
||||
struct SLLHeader
|
||||
{
|
||||
uint16_t packet_type;
|
||||
uint16_t arphrd_type;
|
||||
uint16_t addr_len;
|
||||
uint64_t addr;
|
||||
uint16_t protocol_type;
|
||||
} __attribute__((__packed__));
|
||||
};
|
||||
|
||||
}
|
24
src/llanalyzer/protocol/linux_sll/Plugin.cc
Normal file
24
src/llanalyzer/protocol/linux_sll/Plugin.cc
Normal file
|
@ -0,0 +1,24 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "plugin/Plugin.h"
|
||||
#include "LinuxSLL.h"
|
||||
#include "llanalyzer/Component.h"
|
||||
|
||||
namespace zeek::plugin::LLAnalyzer_LinuxSLL {
|
||||
|
||||
class Plugin : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure()
|
||||
{
|
||||
AddComponent(new zeek::llanalyzer::Component("LinuxSLL",
|
||||
zeek::llanalyzer::LinuxSLL::LinuxSLLAnalyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "LLAnalyzer::LinuxSLL";
|
||||
config.description = "Linux cooked capture (SLL) LL-Analyzer";
|
||||
return config;
|
||||
}
|
||||
|
||||
} plugin;
|
||||
|
||||
}
|
8
src/llanalyzer/protocol/mpls/CMakeLists.txt
Normal file
8
src/llanalyzer/protocol/mpls/CMakeLists.txt
Normal file
|
@ -0,0 +1,8 @@
|
|||
|
||||
include(ZeekPlugin)
|
||||
|
||||
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
zeek_plugin_begin(LLAnalyzer MPLS)
|
||||
zeek_plugin_cc(MPLS.cc Plugin.cc)
|
||||
zeek_plugin_end()
|
55
src/llanalyzer/protocol/mpls/MPLS.cc
Normal file
55
src/llanalyzer/protocol/mpls/MPLS.cc
Normal file
|
@ -0,0 +1,55 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "MPLS.h"
|
||||
|
||||
using namespace zeek::llanalyzer::MPLS;
|
||||
|
||||
MPLSAnalyzer::MPLSAnalyzer()
|
||||
: zeek::llanalyzer::Analyzer("MPLS")
|
||||
{
|
||||
}
|
||||
|
||||
std::tuple<zeek::llanalyzer::AnalyzerResult, zeek::llanalyzer::identifier_t> MPLSAnalyzer::Analyze(Packet* packet)
|
||||
{
|
||||
auto& pdata = packet->cur_pos;
|
||||
auto end_of_data = packet->GetEndOfData();
|
||||
|
||||
// Skip the MPLS label stack.
|
||||
bool end_of_stack = false;
|
||||
|
||||
while ( ! end_of_stack )
|
||||
{
|
||||
if ( pdata + 4 >= end_of_data )
|
||||
{
|
||||
packet->Weird("truncated_link_header");
|
||||
return { AnalyzerResult::Failed, 0 };
|
||||
}
|
||||
|
||||
end_of_stack = *(pdata + 2u) & 0x01;
|
||||
pdata += 4;
|
||||
}
|
||||
|
||||
// According to RFC3032 the encapsulated protocol is not encoded.
|
||||
// We assume that what remains is IP.
|
||||
if ( pdata + sizeof(struct ip) >= end_of_data )
|
||||
{
|
||||
packet->Weird("no_ip_in_mpls_payload");
|
||||
return { AnalyzerResult::Failed, 0 };
|
||||
}
|
||||
|
||||
auto ip = (const struct ip*)pdata;
|
||||
|
||||
if ( ip->ip_v == 4 )
|
||||
packet->l3_proto = L3_IPV4;
|
||||
else if ( ip->ip_v == 6 )
|
||||
packet->l3_proto = L3_IPV6;
|
||||
else
|
||||
{
|
||||
// Neither IPv4 nor IPv6.
|
||||
packet->Weird("no_ip_in_mpls_payload");
|
||||
return { AnalyzerResult::Failed, 0 };
|
||||
}
|
||||
|
||||
packet->hdr_size = (pdata - packet->data);
|
||||
return { AnalyzerResult::Terminate, 0 };
|
||||
}
|
23
src/llanalyzer/protocol/mpls/MPLS.h
Normal file
23
src/llanalyzer/protocol/mpls/MPLS.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <llanalyzer/Analyzer.h>
|
||||
#include <llanalyzer/Component.h>
|
||||
|
||||
namespace zeek::llanalyzer::MPLS {
|
||||
|
||||
class MPLSAnalyzer : public zeek::llanalyzer::Analyzer {
|
||||
public:
|
||||
MPLSAnalyzer();
|
||||
~MPLSAnalyzer() override = default;
|
||||
|
||||
std::tuple<AnalyzerResult, identifier_t> Analyze(Packet* packet) override;
|
||||
|
||||
static zeek::llanalyzer::Analyzer* Instantiate()
|
||||
{
|
||||
return new MPLSAnalyzer();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
24
src/llanalyzer/protocol/mpls/Plugin.cc
Normal file
24
src/llanalyzer/protocol/mpls/Plugin.cc
Normal file
|
@ -0,0 +1,24 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "MPLS.h"
|
||||
#include "plugin/Plugin.h"
|
||||
#include "llanalyzer/Component.h"
|
||||
|
||||
namespace zeek::plugin::LLAnalyzer_MPLS {
|
||||
|
||||
class Plugin : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure()
|
||||
{
|
||||
AddComponent(new zeek::llanalyzer::Component("MPLS",
|
||||
zeek::llanalyzer::MPLS::MPLSAnalyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "LLAnalyzer::MPLS";
|
||||
config.description = "MPLS LL-Analyzer";
|
||||
return config;
|
||||
}
|
||||
|
||||
} plugin;
|
||||
|
||||
}
|
8
src/llanalyzer/protocol/nflog/CMakeLists.txt
Normal file
8
src/llanalyzer/protocol/nflog/CMakeLists.txt
Normal file
|
@ -0,0 +1,8 @@
|
|||
|
||||
include(ZeekPlugin)
|
||||
|
||||
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
zeek_plugin_begin(LLAnalyzer NFLog)
|
||||
zeek_plugin_cc(NFLog.cc Plugin.cc)
|
||||
zeek_plugin_end()
|
80
src/llanalyzer/protocol/nflog/NFLog.cc
Normal file
80
src/llanalyzer/protocol/nflog/NFLog.cc
Normal file
|
@ -0,0 +1,80 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "NFLog.h"
|
||||
#include "NetVar.h"
|
||||
|
||||
using namespace zeek::llanalyzer::NFLog;
|
||||
|
||||
NFLogAnalyzer::NFLogAnalyzer()
|
||||
: zeek::llanalyzer::Analyzer("NFLog")
|
||||
{
|
||||
}
|
||||
|
||||
std::tuple<zeek::llanalyzer::AnalyzerResult, zeek::llanalyzer::identifier_t> NFLogAnalyzer::Analyze(Packet* packet) {
|
||||
auto& pdata = packet->cur_pos;
|
||||
auto end_of_data = packet->GetEndOfData();
|
||||
|
||||
// See https://www.tcpdump.org/linktypes/LINKTYPE_NFLOG.html
|
||||
identifier_t protocol = pdata[0];
|
||||
uint8_t version = pdata[1];
|
||||
|
||||
if ( version != 0 )
|
||||
{
|
||||
packet->Weird("unknown_nflog_version");
|
||||
return { AnalyzerResult::Failed, 0 };
|
||||
}
|
||||
|
||||
// Skip to TLVs.
|
||||
pdata += 4;
|
||||
|
||||
uint16_t tlv_len;
|
||||
uint16_t tlv_type;
|
||||
|
||||
while ( true )
|
||||
{
|
||||
if ( pdata + 4 >= end_of_data )
|
||||
{
|
||||
packet->Weird("nflog_no_pcap_payload");
|
||||
return { AnalyzerResult::Failed, 0 };
|
||||
}
|
||||
|
||||
// TLV Type and Length values are specified in host byte order
|
||||
// (libpcap should have done any needed byteswapping already).
|
||||
|
||||
tlv_len = *(reinterpret_cast<const uint16_t*>(pdata));
|
||||
tlv_type = *(reinterpret_cast<const uint16_t*>(pdata + 2));
|
||||
|
||||
auto constexpr nflog_type_payload = 9;
|
||||
|
||||
if ( tlv_type == nflog_type_payload )
|
||||
{
|
||||
// The raw packet payload follows this TLV.
|
||||
pdata += 4;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The Length value includes the 4 octets for the Type and
|
||||
// Length values, but TLVs are also implicitly padded to
|
||||
// 32-bit alignments (that padding may not be included in
|
||||
// the Length value).
|
||||
|
||||
if ( tlv_len < 4 )
|
||||
{
|
||||
packet->Weird("nflog_bad_tlv_len");
|
||||
return { AnalyzerResult::Failed, 0 };
|
||||
}
|
||||
else
|
||||
{
|
||||
auto rem = tlv_len % 4;
|
||||
|
||||
if ( rem != 0 )
|
||||
tlv_len += 4 - rem;
|
||||
}
|
||||
|
||||
pdata += tlv_len;
|
||||
}
|
||||
}
|
||||
|
||||
return { AnalyzerResult::Continue, protocol };
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue