mirror of
https://github.com/zeek/zeek.git
synced 2025-10-05 16:18: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 tunnel_parent_t: record {
|
||||
module Tunnel;
|
||||
export {
|
||||
type parent_t: record {
|
||||
cid: conn_id;
|
||||
tunnel_type: tunneltype_t;
|
||||
};
|
||||
};
|
||||
} # end export
|
||||
module GLOBAL;
|
||||
|
||||
type connection: record {
|
||||
id: conn_id;
|
||||
|
@ -97,7 +101,7 @@ type connection: record {
|
|||
hot: count; # how hot; 0 = don't know or not hot
|
||||
history: string;
|
||||
uid: string;
|
||||
tunnel_parent: tunnel_parent_t &optional;
|
||||
tunnel_parent: Tunnel::parent_t &optional;
|
||||
};
|
||||
|
||||
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.
|
||||
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 utils/site
|
||||
|
||||
|
|
|
@ -131,10 +131,11 @@ NetSessions::NetSessions()
|
|||
arp_analyzer = 0;
|
||||
|
||||
|
||||
if ( 1 )
|
||||
if ( BifConst::Tunnel::decapsulate_ip || BifConst::Tunnel::decapsulate_udp )
|
||||
tunnel_handler = new TunnelHandler(this);
|
||||
else
|
||||
tunnel_handler = 0;
|
||||
printf("tunnel_handler: %p\n", tunnel_handler);
|
||||
}
|
||||
|
||||
NetSessions::~NetSessions()
|
||||
|
@ -473,7 +474,13 @@ 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
|
||||
caplen -= ip_hdr_len;
|
||||
|
||||
TunnelInfo *tunnel_info = 0;
|
||||
if ( tunnel_handler )
|
||||
{
|
||||
tunnel_info = tunnel_handler->DecapsulateTunnel(ip_hdr, len, caplen, hdr, pkt);
|
||||
if (tunnel_info)
|
||||
{
|
||||
ip4 = tunnel_info->child->IP4_Hdr();
|
||||
|
@ -481,6 +488,7 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
|
|||
len -= tunnel_info->hdr_len;
|
||||
caplen -= tunnel_info->hdr_len;
|
||||
}
|
||||
}
|
||||
|
||||
int proto = ip_hdr->NextProto();
|
||||
if ( proto != IPPROTO_TCP && proto != IPPROTO_UDP &&
|
||||
|
@ -490,9 +498,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
|
|||
return;
|
||||
}
|
||||
|
||||
len -= ip_hdr_len; // remove IP header
|
||||
caplen -= ip_hdr_len;
|
||||
|
||||
uint32 min_hdr_len = (proto == IPPROTO_TCP) ? sizeof(struct tcphdr) :
|
||||
(proto == IPPROTO_UDP ? sizeof(struct udphdr) : ICMP_MINLEN);
|
||||
|
||||
|
|
|
@ -18,15 +18,22 @@
|
|||
TunnelHandler::TunnelHandler(NetSessions *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,
|
||||
const struct pcap_pkthdr* hdr, const u_char* const pkt)
|
||||
{
|
||||
TunnelInfo *tunnel_info = 0;
|
||||
|
||||
switch (ip_hdr->NextProto()) {
|
||||
#ifdef BROv6
|
||||
case IPPROTO_IPV6: /* 6in4 and 6to4 */
|
||||
if ( BifConst::Tunnel::decapsulate_ip )
|
||||
{
|
||||
if (len < (int)sizeof(struct ip6_hdr) || caplen < (int)sizeof(struct ip6_hdr))
|
||||
{
|
||||
s->Weird("truncated_header", hdr, pkt);
|
||||
|
@ -35,14 +42,127 @@ TunnelInfo* TunnelHandler::DecapsulateTunnel(const IP_Hdr *ip_hdr, int len, int
|
|||
// TODO: check if IP6 header makes sense
|
||||
tunnel_info = new TunnelInfo();
|
||||
tunnel_info->child = new IP_Hdr((const struct ip6_hdr*)ip_hdr->Payload());
|
||||
tunnel_info->tunneltype = BifEnum::IP6inIP;
|
||||
tunnel_info->hdr_len = ip_hdr->HdrLen();
|
||||
tunnel_info->tunneltype = BifEnum::Tunnel::IP6inIP;
|
||||
tunnel_info->hdr_len = tunnel_info->child->HdrLen();
|
||||
tunnel_info->SetParentIPs(ip_hdr);
|
||||
return tunnel_info;
|
||||
}
|
||||
break;
|
||||
#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:
|
||||
break;
|
||||
} /* end switch */
|
||||
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
|
||||
#define tunnelhandler_h
|
||||
|
||||
#include <netinet/udp.h>
|
||||
#include "IP.h"
|
||||
#include "Conn.h"
|
||||
#include "Sessions.h"
|
||||
|
@ -14,7 +15,7 @@ public:
|
|||
TunnelInfo()
|
||||
{
|
||||
child = 0;
|
||||
tunneltype = BifEnum::NONE;
|
||||
tunneltype = BifEnum::Tunnel::NONE;
|
||||
hdr_len = 0;
|
||||
parent.src_addr = parent.dst_addr = 0;
|
||||
parent.src_port = parent.dst_port = 0;
|
||||
|
@ -30,30 +31,39 @@ public:
|
|||
parent.src_addr = ip_hdr->SrcAddr();
|
||||
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.dst_port = dst_port;
|
||||
parent.src_port = uh->uh_sport;
|
||||
parent.dst_port = uh->uh_dport;
|
||||
}
|
||||
|
||||
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);
|
||||
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(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(1, new EnumVal(tunneltype, BifType::Enum::tunneltype_t));
|
||||
rv->Assign(1, new EnumVal(tunneltype, BifType::Enum::Tunnel::tunneltype_t));
|
||||
return rv;
|
||||
}
|
||||
|
||||
IP_Hdr *child;
|
||||
ConnID parent;
|
||||
int hdr_len;
|
||||
BifEnum::tunneltype_t tunneltype;
|
||||
BifEnum::Tunnel::tunneltype_t tunneltype;
|
||||
};
|
||||
|
||||
class TunnelHandler {
|
||||
|
@ -61,12 +71,16 @@ public:
|
|||
TunnelHandler(NetSessions *arg_s);
|
||||
~TunnelHandler();
|
||||
|
||||
// Main entry point. Returns a nil if not tunneled.
|
||||
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);
|
||||
|
||||
protected:
|
||||
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_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,
|
||||
%}
|
||||
|
||||
module GLOBAL;
|
||||
|
||||
module Tunnel;
|
||||
enum tunneltype_t %{
|
||||
NONE,
|
||||
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