mirror of
https://github.com/zeek/zeek.git
synced 2025-10-03 15:18:20 +00:00
Adding missing files.
This commit is contained in:
parent
fcf8cef949
commit
f69edd1437
4 changed files with 556 additions and 0 deletions
117
src/iosource/Layer2.cc
Normal file
117
src/iosource/Layer2.cc
Normal file
|
@ -0,0 +1,117 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "IP.h"
|
||||
#include "Type.h"
|
||||
#include "Val.h"
|
||||
#include "Var.h"
|
||||
#include "NetVar.h"
|
||||
#include "iosource/Layer2.h"
|
||||
#include "iosource/Packet.h"
|
||||
|
||||
extern "C" {
|
||||
#include <pcap.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_arp.h>
|
||||
#ifdef HAVE_NET_ETHERNET_H
|
||||
#include <net/ethernet.h>
|
||||
#elif defined(HAVE_SYS_ETHERNET_H)
|
||||
#include <sys/ethernet.h>
|
||||
#elif defined(HAVE_NETINET_IF_ETHER_H)
|
||||
#include <netinet/if_ether.h>
|
||||
#elif defined(HAVE_NET_ETHERTYPES_H)
|
||||
#include <net/ethertypes.h>
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Val *L2_Hdr::fmt_eui48(const u_char *mac) const
|
||||
{
|
||||
char buf[20];
|
||||
snprintf(buf, sizeof buf, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
return new StringVal(buf);
|
||||
}
|
||||
|
||||
RecordVal* L2_Hdr::BuildPktHdrVal() const
|
||||
{
|
||||
static RecordType* l2_hdr_type = 0;
|
||||
static RecordType* raw_pkt_hdr_type = 0;
|
||||
|
||||
if ( ! raw_pkt_hdr_type )
|
||||
{
|
||||
raw_pkt_hdr_type = internal_type("raw_pkt_hdr")->AsRecordType();
|
||||
l2_hdr_type = internal_type("l2_hdr")->AsRecordType();
|
||||
}
|
||||
|
||||
RecordVal* pkt_hdr = new RecordVal(raw_pkt_hdr_type);
|
||||
RecordVal* l2_hdr = new RecordVal(l2_hdr_type);
|
||||
|
||||
int is_ethernet = (pkt->link_type == DLT_EN10MB) ? 1 : 0;
|
||||
|
||||
int l3 = BifEnum::L3_UNKNOWN;
|
||||
|
||||
if ( pkt->l3_proto == L3_IPV4 )
|
||||
l3 = BifEnum::L3_IPV4;
|
||||
|
||||
else if ( pkt->l3_proto == L3_IPV6 )
|
||||
l3 = BifEnum::L3_IPV6;
|
||||
|
||||
else if ( pkt->l3_proto == L3_ARP )
|
||||
l3 = BifEnum::L3_ARP;
|
||||
|
||||
// l2_hdr layout:
|
||||
// encap: link_encap; ##< L2 link encapsulation
|
||||
// len: count; ##< Total frame length on wire
|
||||
// cap_len: count; ##< Captured length
|
||||
// src: string &optional; ##< L2 source (if ethernet)
|
||||
// dst: string &optional; ##< L2 destination (if ethernet)
|
||||
// vlan: count &optional; ##< VLAN tag if any (and ethernet)
|
||||
// ethertype: count &optional; ##< If ethernet
|
||||
// proto: layer3_proto; ##< L3 proto
|
||||
|
||||
if ( is_ethernet )
|
||||
{
|
||||
// Ethernet header layout is:
|
||||
// dst[6bytes] src[6bytes] ethertype[2bytes]...
|
||||
l2_hdr->Assign(0, new EnumVal(BifEnum::LINK_ETHERNET, BifType::Enum::link_encap));
|
||||
l2_hdr->Assign(3, fmt_eui48(pkt->data + 6)); // src
|
||||
l2_hdr->Assign(4, fmt_eui48(pkt->data)); // dst
|
||||
|
||||
if ( pkt->vlan )
|
||||
l2_hdr->Assign(5, new Val(pkt->vlan, TYPE_COUNT));
|
||||
|
||||
l2_hdr->Assign(6, new Val(pkt->eth_type, TYPE_COUNT));
|
||||
|
||||
if ( pkt->eth_type == ETHERTYPE_ARP || pkt->eth_type == ETHERTYPE_REVARP )
|
||||
// We also identify ARP for L3 over ethernet
|
||||
l3 = BifEnum::L3_ARP;
|
||||
}
|
||||
else
|
||||
l2_hdr->Assign(0, new EnumVal(BifEnum::LINK_UNKNOWN, BifType::Enum::link_encap));
|
||||
|
||||
l2_hdr->Assign(1, new Val(pkt->len, TYPE_COUNT));
|
||||
l2_hdr->Assign(2, new Val(pkt->cap_len, TYPE_COUNT));
|
||||
|
||||
l2_hdr->Assign(7, new EnumVal(l3, BifType::Enum::layer3_proto));
|
||||
|
||||
pkt_hdr->Assign(0, l2_hdr);
|
||||
|
||||
if ( pkt->l3_proto == L3_IPV4 )
|
||||
{
|
||||
IP_Hdr ip_hdr((const struct ip*)(pkt->data + pkt->hdr_size), false);
|
||||
return ip_hdr.BuildPktHdrVal(pkt_hdr, 1);
|
||||
}
|
||||
|
||||
else if ( pkt->l3_proto == L3_IPV6 )
|
||||
{
|
||||
IP_Hdr ip6_hdr((const struct ip6_hdr*)(pkt->data + pkt->hdr_size), false, pkt->cap_len);
|
||||
return ip6_hdr.BuildPktHdrVal(pkt_hdr, 1);
|
||||
}
|
||||
|
||||
else
|
||||
return pkt_hdr;
|
||||
}
|
||||
|
33
src/iosource/Layer2.h
Normal file
33
src/iosource/Layer2.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
#ifndef l2_h
|
||||
#define l2_h
|
||||
|
||||
#include "config.h"
|
||||
#include "net_util.h"
|
||||
#include "IP.h"
|
||||
#include "Reporter.h"
|
||||
#include "Val.h"
|
||||
#include "Type.h"
|
||||
#include <vector>
|
||||
|
||||
class Packet;
|
||||
|
||||
/**
|
||||
* A class that wraps an L2 packet.
|
||||
*/
|
||||
class L2_Hdr {
|
||||
public:
|
||||
L2_Hdr(const Packet *arg_pkt) : pkt(arg_pkt) { }
|
||||
~L2_Hdr() { }
|
||||
|
||||
/**
|
||||
* Returns a raw_pkt_hdr RecordVal, which includes L2 and also
|
||||
* everything in IP_Hdr (i.e. IP4/6 + tcp/udp/icmp)
|
||||
*/
|
||||
RecordVal* BuildPktHdrVal() const;
|
||||
|
||||
private:
|
||||
Val *fmt_eui48(const u_char *mac) const;
|
||||
const Packet *pkt;
|
||||
};
|
||||
|
||||
#endif
|
270
src/iosource/Packet.cc
Normal file
270
src/iosource/Packet.cc
Normal file
|
@ -0,0 +1,270 @@
|
|||
|
||||
#include "Packet.h"
|
||||
#include "Sessions.h"
|
||||
|
||||
void Packet::Weird(const char* name)
|
||||
{
|
||||
sessions->Weird(name, this);
|
||||
l2_valid = false;
|
||||
}
|
||||
|
||||
int Packet::GetLinkHeaderSize(int link_type)
|
||||
{
|
||||
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_RAW:
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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:
|
||||
{
|
||||
// Get protocol being carried from the ethernet frame.
|
||||
int protocol = (pdata[12] << 8) + pdata[13];
|
||||
pdata += GetLinkHeaderSize(link_type);
|
||||
eth_type = protocol;
|
||||
|
||||
switch ( protocol )
|
||||
{
|
||||
// MPLS carried over the ethernet frame.
|
||||
case 0x8847:
|
||||
have_mpls = true;
|
||||
break;
|
||||
|
||||
// VLAN carried over the ethernet frame.
|
||||
// 802.1q / 802.1ad
|
||||
case 0x8100:
|
||||
case 0x9100:
|
||||
vlan = ((pdata[0] << 8) + pdata[1]) & 0xfff;
|
||||
protocol = ((pdata[2] << 8) + pdata[3]);
|
||||
pdata += 4; // Skip the vlan header
|
||||
|
||||
// Check for MPLS in VLAN.
|
||||
if ( protocol == 0x8847 )
|
||||
{
|
||||
have_mpls = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Check for double-tagged (802.1ad)
|
||||
if ( protocol == 0x8100 || protocol == 0x9100 )
|
||||
{
|
||||
protocol = ((pdata[2] << 8) + pdata[3]);
|
||||
pdata += 4; // Skip the vlan header
|
||||
}
|
||||
|
||||
eth_type = protocol;
|
||||
break;
|
||||
|
||||
// PPPoE carried over the ethernet frame.
|
||||
case 0x8864:
|
||||
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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
// Assume we're pointing at IP. Just figure out which version.
|
||||
pdata += GetLinkHeaderSize(link_type);
|
||||
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 )
|
||||
{
|
||||
end_of_stack = *(pdata + 2) & 0x01;
|
||||
pdata += 4;
|
||||
|
||||
if ( pdata >= pdata + cap_len )
|
||||
{
|
||||
Weird("no_mpls_payload");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// We assume that what remains is IP
|
||||
if ( pdata + sizeof(struct ip) >= data + cap_len )
|
||||
{
|
||||
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 ( encap_hdr_size )
|
||||
{
|
||||
// Blanket encapsulation. We assume that what remains is IP.
|
||||
pdata += encap_hdr_size;
|
||||
if ( pdata + sizeof(struct ip) >= data + cap_len )
|
||||
{
|
||||
Weird("no_ip_left_after_encap");
|
||||
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_encap");
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// We've now determined (a) L3_IPV4 vs (b) L3_IPV6 vs
|
||||
// (c) L3_ARP vs (d) L3_UNKNOWN (0 == anything else)
|
||||
l3_proto = l3_proto;
|
||||
|
||||
// Calculate how much header we've used up.
|
||||
hdr_size = (pdata - data);
|
||||
}
|
||||
|
136
src/iosource/Packet.h
Normal file
136
src/iosource/Packet.h
Normal file
|
@ -0,0 +1,136 @@
|
|||
#ifndef packet_h
|
||||
#define packet_h
|
||||
|
||||
#include "Desc.h"
|
||||
#include "IP.h"
|
||||
#include "NetVar.h"
|
||||
|
||||
enum Layer3Proto {
|
||||
L3_UNKNOWN = -1,
|
||||
L3_IPV4 = 1,
|
||||
L3_IPV6 = 2,
|
||||
L3_ARP = 3,
|
||||
};
|
||||
|
||||
// A link-layer packet.
|
||||
//
|
||||
// Note that for serialization we don't use much of the support provided by
|
||||
// the serialization framework. Serialize/Unserialize do all the work by
|
||||
// themselves. In particular, Packets aren't derived from SerialObj. They are
|
||||
// completely seperate and self-contained entities, and we don't need any of
|
||||
// the sophisticated features like object caching.
|
||||
|
||||
class Packet {
|
||||
public:
|
||||
Packet()
|
||||
{
|
||||
struct timeval ts = {0, 0};
|
||||
Init(0, &ts, 0, 0, 0);
|
||||
}
|
||||
// Construct and initialize from packet data.
|
||||
//
|
||||
// arg_free: If true makes an internal copy of the *data*. If false,
|
||||
// stores just a pointer to *data*, which must remain valid.
|
||||
Packet(int arg_link_type, struct timeval *arg_ts, uint32 arg_caplen,
|
||||
uint32 arg_len, const u_char *arg_data, int arg_free = false,
|
||||
std::string arg_tag = std::string(""))
|
||||
{
|
||||
Init(arg_link_type, arg_ts, arg_caplen, arg_len, arg_data, arg_free, arg_tag);
|
||||
}
|
||||
|
||||
~Packet()
|
||||
{
|
||||
if ( free )
|
||||
delete [] data;
|
||||
}
|
||||
|
||||
// Initialize with data from pointer.
|
||||
//
|
||||
// arg_free: If true makes an internal copy of the *data*. If false,
|
||||
// stores just a pointer to *data*, which must remain valid.
|
||||
void Init(int arg_link_type, struct timeval *arg_ts, uint32 arg_caplen,
|
||||
uint32 arg_len, const u_char *arg_data, int arg_free = false,
|
||||
std::string arg_tag = std::string(""), uint32 arg_hdrsize = 0)
|
||||
{
|
||||
link_type = arg_link_type;
|
||||
ts = *arg_ts;
|
||||
cap_len = arg_caplen;
|
||||
len = arg_len;
|
||||
free = arg_free;
|
||||
|
||||
if ( free )
|
||||
{
|
||||
data = new u_char[cap_len];
|
||||
memcpy(const_cast<u_char *>(data), arg_data, cap_len);
|
||||
}
|
||||
else
|
||||
data = arg_data;
|
||||
|
||||
hdr_size = arg_hdrsize;
|
||||
l3_proto = L3_UNKNOWN;
|
||||
tag = arg_tag;
|
||||
time = ts.tv_sec + double(ts.tv_usec) / 1e6;
|
||||
eth_type = 0;
|
||||
vlan = 0;
|
||||
|
||||
l2_valid = false;
|
||||
|
||||
if ( data )
|
||||
ProcessLayer2();
|
||||
}
|
||||
|
||||
const IP_Hdr IP() const
|
||||
{ return IP_Hdr((struct ip *) (data + hdr_size), false); }
|
||||
|
||||
// Returns true if parsing the Layer 2 fields failed, including when
|
||||
// no data was passed into the constructor in the first place.
|
||||
bool Layer2Valid()
|
||||
{
|
||||
return l2_valid;
|
||||
}
|
||||
|
||||
void Describe(ODesc* d) const;
|
||||
|
||||
/**
|
||||
* Helper method to return the header size for a given link tyoe.
|
||||
*
|
||||
* @param link_type The link tyoe.
|
||||
*
|
||||
* @return The header size in bytes, or -1 if not known.
|
||||
*/
|
||||
static int GetLinkHeaderSize(int link_type);
|
||||
|
||||
bool Serialize(SerialInfo* info) const;
|
||||
static Packet* Unserialize(UnserialInfo* info);
|
||||
|
||||
// These are passed in through the constructor.
|
||||
std::string tag; /// Used in serialization
|
||||
double time; /// Timestamp reconstituted as float
|
||||
struct timeval ts; /// Capture timestamp
|
||||
const u_char* data; /// Packet data.
|
||||
uint32 len; /// Actual length on wire
|
||||
uint32 cap_len; /// Captured packet length
|
||||
uint32 link_type; /// pcap link_type (DLT_EN10MB, DLT_RAW, etc)
|
||||
|
||||
// These are computed from Layer 2 data. These fields are only valid if
|
||||
// Layer2Valid() returns true.
|
||||
uint32 hdr_size; /// Layer 2 header size
|
||||
Layer3Proto l3_proto; /// Layer 3 protocol identified (if any)
|
||||
uint32 eth_type; /// If L2==ethernet, innermost ethertype field
|
||||
uint32 vlan; /// (Outermost) VLan tag if any, else 0
|
||||
|
||||
private:
|
||||
// Calculate layer 2 attributes. Sets
|
||||
void ProcessLayer2();
|
||||
|
||||
// Wrapper to generate a packet-level weird.
|
||||
void Weird(const char* name);
|
||||
|
||||
// should we delete associated packet memory upon destruction.
|
||||
bool free;
|
||||
|
||||
// True if L2 processing succeeded.
|
||||
bool l2_valid;
|
||||
};
|
||||
|
||||
#endif // packet_h
|
Loading…
Add table
Add a link
Reference in a new issue