mirror of
https://github.com/zeek/zeek.git
synced 2025-10-05 08:08:19 +00:00
Adding support to de-capsulate tunnels. Checkpoint.
Re-organizing code. Adding UDP tunnel handlers. Using policy level redef'able consts to tune behavior. UDP port settings not working yet.
This commit is contained in:
parent
9c388a1809
commit
8910cd2dca
6 changed files with 216 additions and 40 deletions
|
@ -81,10 +81,14 @@ type endpoint_stats: record {
|
||||||
|
|
||||||
type AnalyzerID: count;
|
type AnalyzerID: count;
|
||||||
|
|
||||||
type tunnel_parent_t: record {
|
module Tunnel;
|
||||||
cid: conn_id;
|
export {
|
||||||
tunnel_type: tunneltype_t;
|
type parent_t: record {
|
||||||
};
|
cid: conn_id;
|
||||||
|
tunnel_type: tunneltype_t;
|
||||||
|
};
|
||||||
|
} # end export
|
||||||
|
module GLOBAL;
|
||||||
|
|
||||||
type connection: record {
|
type connection: record {
|
||||||
id: conn_id;
|
id: conn_id;
|
||||||
|
@ -97,7 +101,7 @@ type connection: record {
|
||||||
hot: count; # how hot; 0 = don't know or not hot
|
hot: count; # how hot; 0 = don't know or not hot
|
||||||
history: string;
|
history: string;
|
||||||
uid: string;
|
uid: string;
|
||||||
tunnel_parent: tunnel_parent_t &optional;
|
tunnel_parent: Tunnel::parent_t &optional;
|
||||||
};
|
};
|
||||||
|
|
||||||
type SYN_packet: record {
|
type SYN_packet: record {
|
||||||
|
@ -1489,6 +1493,28 @@ const skip_http_data = F &redef;
|
||||||
# UDP tunnels. See also: udp_tunnel_port, policy/udp-tunnel.bro.
|
# UDP tunnels. See also: udp_tunnel_port, policy/udp-tunnel.bro.
|
||||||
const parse_udp_tunnels = F &redef;
|
const parse_udp_tunnels = F &redef;
|
||||||
|
|
||||||
|
module Tunnel;
|
||||||
|
export {
|
||||||
|
# Whether to decapsulate IP tunnels (IPinIP, 6in4, 6to4)
|
||||||
|
const decapsulate_ip = F &redef;
|
||||||
|
|
||||||
|
# Whether to decapsulate URDP tunnels (e.g., Teredo, IPv4 in UDP)
|
||||||
|
const decapsulate_udp = F &redef;
|
||||||
|
|
||||||
|
# If decapsulating UDP: the set of ports for which to do so
|
||||||
|
const udp_tunnel_ports: set[port] = {
|
||||||
|
3544/udp, # Teredo
|
||||||
|
5072/udp, # AYIAY
|
||||||
|
} &redef;
|
||||||
|
|
||||||
|
# If udp_tunnel_allports is T udp_tunnel_ports is ignored and we
|
||||||
|
# check every UDP packet for tunnels.
|
||||||
|
const udp_tunnel_allports = F &redef;
|
||||||
|
} # end export
|
||||||
|
module GLOBAL;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Load the site utilities.
|
# Load the site utilities.
|
||||||
@load utils/site
|
@load utils/site
|
||||||
|
|
||||||
|
|
|
@ -131,10 +131,11 @@ NetSessions::NetSessions()
|
||||||
arp_analyzer = 0;
|
arp_analyzer = 0;
|
||||||
|
|
||||||
|
|
||||||
if ( 1 )
|
if ( BifConst::Tunnel::decapsulate_ip || BifConst::Tunnel::decapsulate_udp )
|
||||||
tunnel_handler = new TunnelHandler(this);
|
tunnel_handler = new TunnelHandler(this);
|
||||||
else
|
else
|
||||||
tunnel_handler = 0;
|
tunnel_handler = 0;
|
||||||
|
printf("tunnel_handler: %p\n", tunnel_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
NetSessions::~NetSessions()
|
NetSessions::~NetSessions()
|
||||||
|
@ -473,13 +474,20 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TunnelInfo *tunnel_info = tunnel_handler->DecapsulateTunnel(ip_hdr, len, caplen, hdr, pkt);
|
len -= ip_hdr_len; // remove IP header
|
||||||
if (tunnel_info)
|
caplen -= ip_hdr_len;
|
||||||
|
|
||||||
|
TunnelInfo *tunnel_info = 0;
|
||||||
|
if ( tunnel_handler )
|
||||||
{
|
{
|
||||||
ip4 = tunnel_info->child->IP4_Hdr();
|
tunnel_info = tunnel_handler->DecapsulateTunnel(ip_hdr, len, caplen, hdr, pkt);
|
||||||
ip_hdr = tunnel_info->child;
|
if (tunnel_info)
|
||||||
len -= tunnel_info->hdr_len;
|
{
|
||||||
caplen -= tunnel_info->hdr_len;
|
ip4 = tunnel_info->child->IP4_Hdr();
|
||||||
|
ip_hdr = tunnel_info->child;
|
||||||
|
len -= tunnel_info->hdr_len;
|
||||||
|
caplen -= tunnel_info->hdr_len;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int proto = ip_hdr->NextProto();
|
int proto = ip_hdr->NextProto();
|
||||||
|
@ -490,9 +498,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
len -= ip_hdr_len; // remove IP header
|
|
||||||
caplen -= ip_hdr_len;
|
|
||||||
|
|
||||||
uint32 min_hdr_len = (proto == IPPROTO_TCP) ? sizeof(struct tcphdr) :
|
uint32 min_hdr_len = (proto == IPPROTO_TCP) ? sizeof(struct tcphdr) :
|
||||||
(proto == IPPROTO_UDP ? sizeof(struct udphdr) : ICMP_MINLEN);
|
(proto == IPPROTO_UDP ? sizeof(struct udphdr) : ICMP_MINLEN);
|
||||||
|
|
||||||
|
|
|
@ -18,31 +18,151 @@
|
||||||
TunnelHandler::TunnelHandler(NetSessions *arg_s)
|
TunnelHandler::TunnelHandler(NetSessions *arg_s)
|
||||||
{
|
{
|
||||||
s = arg_s;
|
s = arg_s;
|
||||||
|
for (int i=0; i< 65536; i++)
|
||||||
|
udp_ports[i] = 0;
|
||||||
|
udp_ports[3544] = 1;
|
||||||
|
udp_ports[5072] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
TunnelInfo* TunnelHandler::DecapsulateTunnel(const IP_Hdr *ip_hdr, int len, int caplen,
|
TunnelInfo* TunnelHandler::DecapsulateTunnel(const IP_Hdr *ip_hdr, int len, int caplen,
|
||||||
const struct pcap_pkthdr* hdr, const u_char* const pkt)
|
const struct pcap_pkthdr* hdr, const u_char* const pkt)
|
||||||
{
|
{
|
||||||
TunnelInfo *tunnel_info = 0;
|
TunnelInfo *tunnel_info = 0;
|
||||||
|
|
||||||
switch (ip_hdr->NextProto()) {
|
switch (ip_hdr->NextProto()) {
|
||||||
#ifdef BROv6
|
#ifdef BROv6
|
||||||
case IPPROTO_IPV6: /* 6in4 and 6to4 */
|
case IPPROTO_IPV6: /* 6in4 and 6to4 */
|
||||||
if (len < (int)sizeof(struct ip6_hdr) || caplen < (int)sizeof(struct ip6_hdr))
|
if ( BifConst::Tunnel::decapsulate_ip )
|
||||||
{
|
{
|
||||||
s->Weird("truncated_header", hdr, pkt);
|
if (len < (int)sizeof(struct ip6_hdr) || caplen < (int)sizeof(struct ip6_hdr))
|
||||||
return 0;
|
{
|
||||||
}
|
s->Weird("truncated_header", hdr, pkt);
|
||||||
// TODO: check if IP6 header makes sense
|
return 0;
|
||||||
tunnel_info = new TunnelInfo();
|
}
|
||||||
tunnel_info->child = new IP_Hdr((const struct ip6_hdr*)ip_hdr->Payload());
|
// TODO: check if IP6 header makes sense
|
||||||
tunnel_info->tunneltype = BifEnum::IP6inIP;
|
tunnel_info = new TunnelInfo();
|
||||||
tunnel_info->hdr_len = ip_hdr->HdrLen();
|
tunnel_info->child = new IP_Hdr((const struct ip6_hdr*)ip_hdr->Payload());
|
||||||
tunnel_info->SetParentIPs(ip_hdr);
|
tunnel_info->tunneltype = BifEnum::Tunnel::IP6inIP;
|
||||||
return tunnel_info;
|
tunnel_info->hdr_len = tunnel_info->child->HdrLen();
|
||||||
|
tunnel_info->SetParentIPs(ip_hdr);
|
||||||
|
return tunnel_info;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
// TODO: IP in IP. Find test traces first. IP proto 0 and/or 4
|
||||||
|
case IPPROTO_UDP:
|
||||||
|
if ( BifConst::Tunnel::decapsulate_udp )
|
||||||
|
{
|
||||||
|
if (len < (int)sizeof(struct udphdr) || caplen < (int)sizeof(struct udphdr))
|
||||||
|
{
|
||||||
|
// No weird here. Main packet processing will raise it.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return HandleUDP(ip_hdr, len, caplen);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
} /* end switch */
|
} /* end switch */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TunnelInfo* TunnelHandler::HandleUDP(const IP_Hdr *ip_hdr, int len, int caplen)
|
||||||
|
{
|
||||||
|
// We already know we that we have a valid UDP header
|
||||||
|
const u_char *data = ip_hdr->Payload();
|
||||||
|
const struct udphdr* uh = (const struct udphdr*)data;
|
||||||
|
IP_Hdr *cand_ip_hdr = 0;
|
||||||
|
BifEnum::Tunnel::tunneltype_t tunneltype = BifEnum::Tunnel::NONE;
|
||||||
|
|
||||||
|
int hdr_len = sizeof(struct udphdr);
|
||||||
|
data += hdr_len;
|
||||||
|
|
||||||
|
int datalen = (int)ntohs(uh->uh_ulen);
|
||||||
|
datalen = min(datalen, min(len, caplen));
|
||||||
|
datalen -= hdr_len;
|
||||||
|
|
||||||
|
if ( BifConst::Tunnel::udp_tunnel_allports ||
|
||||||
|
udp_ports[ntohs(uh->uh_sport)] ||
|
||||||
|
udp_ports[ntohs(uh->uh_dport)] )
|
||||||
|
{
|
||||||
|
cand_ip_hdr = LookForIPHdr(data, datalen);
|
||||||
|
if (cand_ip_hdr)
|
||||||
|
{
|
||||||
|
tunneltype = (cand_ip_hdr->IP4_Hdr()) ?
|
||||||
|
BifEnum::Tunnel::IP4inUDP : BifEnum::Tunnel::IP6inUDP;
|
||||||
|
}
|
||||||
|
else if (datalen >= 8)
|
||||||
|
{
|
||||||
|
// Look for AYIAY tunnels
|
||||||
|
u_char id_byte = data[0];
|
||||||
|
u_char sig_byte = data[1];
|
||||||
|
u_char next_hdr = data[3];
|
||||||
|
|
||||||
|
// identity length field is high bits of id_byte.
|
||||||
|
// length in octets is 2 to the power of length field
|
||||||
|
int id_len = (1 << (id_byte>>4));
|
||||||
|
|
||||||
|
// signature length field is high bits of sig_byte
|
||||||
|
// length in octets 4 * length field
|
||||||
|
int sig_len = 4*(sig_byte>>4);
|
||||||
|
|
||||||
|
datalen -= 8 + id_len + sig_len;
|
||||||
|
data += 8 + id_len + sig_len;
|
||||||
|
if (datalen <= 0)
|
||||||
|
return 0;
|
||||||
|
cand_ip_hdr = LookForIPHdr(data, datalen);
|
||||||
|
if (cand_ip_hdr)
|
||||||
|
{
|
||||||
|
hdr_len += 8 + id_len + sig_len;
|
||||||
|
tunneltype = (cand_ip_hdr->IP4_Hdr()) ?
|
||||||
|
BifEnum::Tunnel::IP4inAYIAY : BifEnum::Tunnel::IP6inAYIAY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cand_ip_hdr)
|
||||||
|
{
|
||||||
|
TunnelInfo *tunnel_info = new TunnelInfo();
|
||||||
|
tunnel_info->child = cand_ip_hdr;
|
||||||
|
tunnel_info->tunneltype = tunneltype;
|
||||||
|
tunnel_info->SetParentIPs(ip_hdr);
|
||||||
|
tunnel_info->SetParentPorts(uh);
|
||||||
|
tunnel_info->hdr_len = hdr_len + cand_ip_hdr->HdrLen();
|
||||||
|
return tunnel_info;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
IP_Hdr* TunnelHandler::LookForIPHdr(const u_char *data, int datalen)
|
||||||
|
{
|
||||||
|
IP_Hdr *cand_ip_hdr = 0;
|
||||||
|
if (datalen < (int)sizeof(struct ip))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
const struct ip *ip4 = (const struct ip*)(data);
|
||||||
|
if (ip4->ip_v == 4)
|
||||||
|
cand_ip_hdr = new IP_Hdr((const struct ip*)ip4);
|
||||||
|
else if (ip4->ip_v == 6 && (datalen > (int)sizeof(struct ip6_hdr)))
|
||||||
|
cand_ip_hdr = new IP_Hdr((const struct ip6_hdr*)data);
|
||||||
|
|
||||||
|
if (cand_ip_hdr)
|
||||||
|
{
|
||||||
|
switch (cand_ip_hdr->NextProto()) {
|
||||||
|
case IPPROTO_UDP:
|
||||||
|
case IPPROTO_TCP:
|
||||||
|
case IPPROTO_ICMP:
|
||||||
|
if ((int)cand_ip_hdr->TotalLen() != datalen)
|
||||||
|
{
|
||||||
|
delete cand_ip_hdr;
|
||||||
|
cand_ip_hdr = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
delete cand_ip_hdr;
|
||||||
|
cand_ip_hdr = 0;
|
||||||
|
break;
|
||||||
|
} // end switch
|
||||||
|
}
|
||||||
|
return cand_ip_hdr;
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#ifndef tunnelhandler_h
|
#ifndef tunnelhandler_h
|
||||||
#define tunnelhandler_h
|
#define tunnelhandler_h
|
||||||
|
|
||||||
|
#include <netinet/udp.h>
|
||||||
#include "IP.h"
|
#include "IP.h"
|
||||||
#include "Conn.h"
|
#include "Conn.h"
|
||||||
#include "Sessions.h"
|
#include "Sessions.h"
|
||||||
|
@ -14,7 +15,7 @@ public:
|
||||||
TunnelInfo()
|
TunnelInfo()
|
||||||
{
|
{
|
||||||
child = 0;
|
child = 0;
|
||||||
tunneltype = BifEnum::NONE;
|
tunneltype = BifEnum::Tunnel::NONE;
|
||||||
hdr_len = 0;
|
hdr_len = 0;
|
||||||
parent.src_addr = parent.dst_addr = 0;
|
parent.src_addr = parent.dst_addr = 0;
|
||||||
parent.src_port = parent.dst_port = 0;
|
parent.src_port = parent.dst_port = 0;
|
||||||
|
@ -30,30 +31,39 @@ public:
|
||||||
parent.src_addr = ip_hdr->SrcAddr();
|
parent.src_addr = ip_hdr->SrcAddr();
|
||||||
parent.dst_addr = ip_hdr->DstAddr();
|
parent.dst_addr = ip_hdr->DstAddr();
|
||||||
}
|
}
|
||||||
void SetParentPorts(uint32 src_port, uint32 dst_port)
|
void SetParentPorts(const struct udphdr *uh)
|
||||||
{
|
{
|
||||||
parent.src_port = src_port;
|
parent.src_port = uh->uh_sport;
|
||||||
parent.dst_port = dst_port;
|
parent.dst_port = uh->uh_dport;
|
||||||
}
|
}
|
||||||
|
|
||||||
RecordVal* GetRecordVal() const
|
RecordVal* GetRecordVal() const
|
||||||
{
|
{
|
||||||
RecordVal *rv = new RecordVal(BifType::Record::tunnel_parent_t);
|
RecordVal *rv = new RecordVal(BifType::Record::Tunnel::parent_t);
|
||||||
|
TransportProto tproto;
|
||||||
|
switch(tunneltype) {
|
||||||
|
case BifEnum::Tunnel::IP6inIP:
|
||||||
|
case BifEnum::Tunnel::IP4inIP:
|
||||||
|
tproto = TRANSPORT_UNKNOWN;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
tproto = TRANSPORT_UDP;
|
||||||
|
} // end switch
|
||||||
|
|
||||||
RecordVal* id_val = new RecordVal(conn_id);
|
RecordVal* id_val = new RecordVal(conn_id);
|
||||||
id_val->Assign(0, new AddrVal(parent.src_addr));
|
id_val->Assign(0, new AddrVal(parent.src_addr));
|
||||||
id_val->Assign(1, new PortVal(ntohs(parent.src_port), TRANSPORT_UNKNOWN));
|
id_val->Assign(1, new PortVal(ntohs(parent.src_port), tproto));
|
||||||
id_val->Assign(2, new AddrVal(parent.dst_addr));
|
id_val->Assign(2, new AddrVal(parent.dst_addr));
|
||||||
id_val->Assign(3, new PortVal(ntohs(parent.dst_port), TRANSPORT_UNKNOWN));
|
id_val->Assign(3, new PortVal(ntohs(parent.dst_port), tproto));
|
||||||
rv->Assign(0, id_val);
|
rv->Assign(0, id_val);
|
||||||
rv->Assign(1, new EnumVal(tunneltype, BifType::Enum::tunneltype_t));
|
rv->Assign(1, new EnumVal(tunneltype, BifType::Enum::Tunnel::tunneltype_t));
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
IP_Hdr *child;
|
IP_Hdr *child;
|
||||||
ConnID parent;
|
ConnID parent;
|
||||||
int hdr_len;
|
int hdr_len;
|
||||||
BifEnum::tunneltype_t tunneltype;
|
BifEnum::Tunnel::tunneltype_t tunneltype;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TunnelHandler {
|
class TunnelHandler {
|
||||||
|
@ -61,12 +71,16 @@ public:
|
||||||
TunnelHandler(NetSessions *arg_s);
|
TunnelHandler(NetSessions *arg_s);
|
||||||
~TunnelHandler();
|
~TunnelHandler();
|
||||||
|
|
||||||
|
// Main entry point. Returns a nil if not tunneled.
|
||||||
TunnelInfo* DecapsulateTunnel(const IP_Hdr* ip_hdr, int len, int caplen,
|
TunnelInfo* DecapsulateTunnel(const IP_Hdr* ip_hdr, int len, int caplen,
|
||||||
/* need those for passing them back to NetSessions::Weird() */
|
// need those for passing them back to NetSessions::Weird()
|
||||||
const struct pcap_pkthdr* hdr, const u_char* const pkt);
|
const struct pcap_pkthdr* hdr, const u_char* const pkt);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
NetSessions *s;
|
NetSessions *s;
|
||||||
|
short udp_ports[65536]; // which UDP ports to decapsulate
|
||||||
|
IP_Hdr* LookForIPHdr(const u_char *data, int datalen);
|
||||||
|
TunnelInfo* HandleUDP(const IP_Hdr *ip_hdr, int len, int caplen);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -12,3 +12,7 @@ const NFS3::return_data: bool;
|
||||||
const NFS3::return_data_max: count;
|
const NFS3::return_data_max: count;
|
||||||
const NFS3::return_data_first_only: bool;
|
const NFS3::return_data_first_only: bool;
|
||||||
|
|
||||||
|
const Tunnel::decapsulate_ip: bool;
|
||||||
|
const Tunnel::decapsulate_udp: bool;
|
||||||
|
const Tunnel::udp_tunnel_ports: any;
|
||||||
|
const Tunnel::udp_tunnel_allports: bool;
|
||||||
|
|
|
@ -166,11 +166,18 @@ enum ID %{
|
||||||
Unknown,
|
Unknown,
|
||||||
%}
|
%}
|
||||||
|
|
||||||
module GLOBAL;
|
|
||||||
|
|
||||||
|
module Tunnel;
|
||||||
enum tunneltype_t %{
|
enum tunneltype_t %{
|
||||||
NONE,
|
NONE,
|
||||||
IP6inIP,
|
IP6inIP,
|
||||||
|
IP4inIP,
|
||||||
|
IP6inUDP,
|
||||||
|
IP4inUDP,
|
||||||
|
IP6inAYIAY,
|
||||||
|
IP4inAYIAY,
|
||||||
%}
|
%}
|
||||||
|
|
||||||
type tunnel_parent_t: record;
|
type parent_t: record;
|
||||||
|
|
||||||
|
module GLOBAL;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue