mirror of
https://github.com/zeek/zeek.git
synced 2025-10-08 01:28:20 +00:00
Refactor IP-in-IP tunnel support.
UDP tunnel support removed for now, to be re-added in specific analyzers later, but IP-in-IP is now decapsulated recursively so nested tunnels can be seen and the inner packets get sent through the IP fragment reassembler if necessary.
This commit is contained in:
parent
4062fc1776
commit
b51dd191d7
21 changed files with 300 additions and 323 deletions
19
src/Conn.cc
19
src/Conn.cc
|
@ -112,7 +112,8 @@ unsigned int Connection::external_connections = 0;
|
|||
|
||||
IMPLEMENT_SERIAL(Connection, SER_CONNECTION);
|
||||
|
||||
Connection::Connection(NetSessions* s, HashKey* k, double t, const ConnID* id, TunnelParent* arg_tunnel_parent)
|
||||
Connection::Connection(NetSessions* s, HashKey* k, double t, const ConnID* id,
|
||||
const Encapsulation& arg_encap)
|
||||
{
|
||||
sessions = s;
|
||||
key = k;
|
||||
|
@ -156,7 +157,7 @@ Connection::Connection(NetSessions* s, HashKey* k, double t, const ConnID* id, T
|
|||
|
||||
uid = 0; // Will set later.
|
||||
|
||||
tunnel_parent = arg_tunnel_parent;
|
||||
encapsulation = arg_encap;
|
||||
|
||||
if ( conn_timer_mgr )
|
||||
{
|
||||
|
@ -182,7 +183,6 @@ Connection::~Connection()
|
|||
Unref(conn_val);
|
||||
}
|
||||
|
||||
delete tunnel_parent;
|
||||
delete key;
|
||||
delete root_analyzer;
|
||||
delete conn_timer_mgr;
|
||||
|
@ -192,6 +192,15 @@ Connection::~Connection()
|
|||
--external_connections;
|
||||
}
|
||||
|
||||
void Connection::CheckEncapsulation(const Encapsulation& arg_encap)
|
||||
{
|
||||
if ( encapsulation != arg_encap )
|
||||
{
|
||||
Event(tunnel_changed, 0, arg_encap.GetVectorVal());
|
||||
encapsulation = arg_encap;
|
||||
}
|
||||
}
|
||||
|
||||
void Connection::Done()
|
||||
{
|
||||
finished = 1;
|
||||
|
@ -346,8 +355,8 @@ RecordVal* Connection::BuildConnVal()
|
|||
|
||||
char tmp[20];
|
||||
conn_val->Assign(9, new StringVal(uitoa_n(uid, tmp, sizeof(tmp), 62)));
|
||||
if ( tunnel_parent )
|
||||
conn_val->Assign(10, tunnel_parent->GetRecordVal());
|
||||
if ( encapsulation.Depth() > 0 )
|
||||
conn_val->Assign(10, encapsulation.GetVectorVal());
|
||||
}
|
||||
|
||||
if ( root_analyzer )
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "RuleMatcher.h"
|
||||
#include "AnalyzerTags.h"
|
||||
#include "IPAddr.h"
|
||||
#include "TunnelHandler.h"
|
||||
|
||||
class Connection;
|
||||
class ConnectionTimer;
|
||||
|
@ -51,9 +52,12 @@ class Analyzer;
|
|||
|
||||
class Connection : public BroObj {
|
||||
public:
|
||||
Connection(NetSessions* s, HashKey* k, double t, const ConnID* id, TunnelParent *arg_tunnel_parent);
|
||||
Connection(NetSessions* s, HashKey* k, double t, const ConnID* id,
|
||||
const Encapsulation& arg_encap);
|
||||
virtual ~Connection();
|
||||
|
||||
void CheckEncapsulation(const Encapsulation& arg_encap);
|
||||
|
||||
// Invoked when connection is about to be removed. Use Ref(this)
|
||||
// inside Done to keep the connection object around (though it'll
|
||||
// no longer be accessible from the dictionary of active
|
||||
|
@ -276,7 +280,7 @@ protected:
|
|||
double inactivity_timeout;
|
||||
RecordVal* conn_val;
|
||||
LoginConn* login_conn; // either nil, or this
|
||||
TunnelParent* tunnel_parent; // nil if not tunneled
|
||||
Encapsulation encapsulation; // tunnels
|
||||
int suppress_event; // suppress certain events to once per conn.
|
||||
|
||||
unsigned int installed_status_timer:1;
|
||||
|
|
|
@ -30,9 +30,6 @@ int partial_connection_ok;
|
|||
int tcp_SYN_ack_ok;
|
||||
int tcp_match_undelivered;
|
||||
|
||||
int encap_hdr_size;
|
||||
int udp_tunnel_port;
|
||||
|
||||
double frag_timeout;
|
||||
|
||||
double tcp_SYN_timeout;
|
||||
|
@ -322,10 +319,6 @@ void init_net_var()
|
|||
tcp_SYN_ack_ok = opt_internal_int("tcp_SYN_ack_ok");
|
||||
tcp_match_undelivered = opt_internal_int("tcp_match_undelivered");
|
||||
|
||||
encap_hdr_size = opt_internal_int("encap_hdr_size");
|
||||
|
||||
udp_tunnel_port = opt_internal_int("udp_tunnel_port") & ~UDP_PORT_MASK;
|
||||
|
||||
frag_timeout = opt_internal_double("frag_timeout");
|
||||
|
||||
tcp_SYN_timeout = opt_internal_double("tcp_SYN_timeout");
|
||||
|
|
|
@ -33,9 +33,6 @@ extern int partial_connection_ok;
|
|||
extern int tcp_SYN_ack_ok;
|
||||
extern int tcp_match_undelivered;
|
||||
|
||||
extern int encap_hdr_size;
|
||||
extern int udp_tunnel_port;
|
||||
|
||||
extern double frag_timeout;
|
||||
|
||||
extern double tcp_SYN_timeout;
|
||||
|
|
102
src/Sessions.cc
102
src/Sessions.cc
|
@ -126,12 +126,6 @@ NetSessions::NetSessions()
|
|||
arp_analyzer = new ARP_Analyzer();
|
||||
else
|
||||
arp_analyzer = 0;
|
||||
|
||||
|
||||
if ( BifConst::Tunnel::decapsulate_ip || BifConst::Tunnel::decapsulate_udp )
|
||||
tunnel_handler = new TunnelHandler(this);
|
||||
else
|
||||
tunnel_handler = 0;
|
||||
}
|
||||
|
||||
NetSessions::~NetSessions()
|
||||
|
@ -185,6 +179,8 @@ void NetSessions::NextPacket(double t, const struct pcap_pkthdr* hdr,
|
|||
if ( record_all_packets )
|
||||
DumpPacket(hdr, pkt);
|
||||
|
||||
Encapsulation encapsulation;
|
||||
|
||||
if ( pkt_elem && pkt_elem->IPHdr() )
|
||||
// Fast path for "normal" IP packets if an IP_Hdr is
|
||||
// already extracted when doing PacketSort. Otherwise
|
||||
|
@ -192,7 +188,7 @@ void NetSessions::NextPacket(double t, const struct pcap_pkthdr* hdr,
|
|||
// difference here is that header extraction in
|
||||
// PacketSort does not generate Weird events.
|
||||
|
||||
DoNextPacket(t, hdr, pkt_elem->IPHdr(), pkt, hdr_size);
|
||||
DoNextPacket(t, hdr, pkt_elem->IPHdr(), pkt, hdr_size, encapsulation);
|
||||
|
||||
else
|
||||
{
|
||||
|
@ -217,7 +213,7 @@ void NetSessions::NextPacket(double t, const struct pcap_pkthdr* hdr,
|
|||
if ( ip->ip_v == 4 )
|
||||
{
|
||||
IP_Hdr ip_hdr(ip, false);
|
||||
DoNextPacket(t, hdr, &ip_hdr, pkt, hdr_size);
|
||||
DoNextPacket(t, hdr, &ip_hdr, pkt, hdr_size, encapsulation);
|
||||
}
|
||||
|
||||
else if ( ip->ip_v == 6 )
|
||||
|
@ -229,7 +225,7 @@ void NetSessions::NextPacket(double t, const struct pcap_pkthdr* hdr,
|
|||
}
|
||||
|
||||
IP_Hdr ip_hdr((const struct ip6_hdr*) (pkt + hdr_size), false, caplen);
|
||||
DoNextPacket(t, hdr, &ip_hdr, pkt, hdr_size);
|
||||
DoNextPacket(t, hdr, &ip_hdr, pkt, hdr_size, encapsulation);
|
||||
}
|
||||
|
||||
else if ( ARP_Analyzer::IsARP(pkt, hdr_size) )
|
||||
|
@ -351,7 +347,7 @@ int NetSessions::CheckConnectionTag(Connection* conn)
|
|||
|
||||
void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
|
||||
const IP_Hdr* ip_hdr, const u_char* const pkt,
|
||||
int hdr_size)
|
||||
int hdr_size, Encapsulation& encapsulation)
|
||||
{
|
||||
uint32 caplen = hdr->caplen - hdr_size;
|
||||
const struct ip* ip4 = ip_hdr->IP4_Hdr();
|
||||
|
@ -458,24 +454,10 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
|
|||
}
|
||||
#endif
|
||||
|
||||
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();
|
||||
ip_hdr = tunnel_info->child;
|
||||
len -= tunnel_info->hdr_len;
|
||||
caplen -= tunnel_info->hdr_len;
|
||||
}
|
||||
}
|
||||
|
||||
int proto = ip_hdr->NextProto();
|
||||
|
||||
if ( CheckHeaderTrunc(proto, len, caplen, hdr, pkt) )
|
||||
{
|
||||
delete tunnel_info;
|
||||
Remove(f);
|
||||
return;
|
||||
}
|
||||
|
@ -540,9 +522,51 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
|
|||
break;
|
||||
}
|
||||
|
||||
case IPPROTO_IP:
|
||||
case IPPROTO_IPV4:
|
||||
case IPPROTO_IPV6:
|
||||
{
|
||||
if ( ! BifConst::Tunnel::decapsulate_ip )
|
||||
{
|
||||
reporter->Weird(ip_hdr->SrcAddr(), ip_hdr->DstAddr(), "ip_tunnel");
|
||||
Remove(f);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( encapsulation.Depth() >= BifConst::Tunnel::max_depth )
|
||||
{
|
||||
reporter->Weird(ip_hdr->SrcAddr(), ip_hdr->DstAddr(), "tunnel_depth");
|
||||
Remove(f);
|
||||
return;
|
||||
}
|
||||
|
||||
IP_Hdr* inner_ip;
|
||||
if ( proto == IPPROTO_IPV6 )
|
||||
inner_ip = new IP_Hdr((const struct ip6_hdr*) data, false, caplen);
|
||||
else
|
||||
inner_ip = new IP_Hdr((const struct ip*) data, false);
|
||||
|
||||
struct pcap_pkthdr fake_hdr;
|
||||
fake_hdr.caplen = fake_hdr.len = caplen;
|
||||
fake_hdr.ts = hdr->ts;
|
||||
|
||||
EncapsulatingConn ec(ip_hdr->SrcAddr(), ip_hdr->DstAddr(),
|
||||
ip_hdr->IP4_Hdr() ?
|
||||
( proto == IPPROTO_IPV6 ?
|
||||
BifEnum::Tunnel::IP6_IN_IP4 : BifEnum::Tunnel::IP4_IN_IP4 ) :
|
||||
( proto == IPPROTO_IPV6 ?
|
||||
BifEnum::Tunnel::IP6_IN_IP6 : BifEnum::Tunnel::IP4_IN_IP6 ));
|
||||
encapsulation.Add(ec);
|
||||
|
||||
DoNextPacket(t, &fake_hdr, inner_ip, data, 0, encapsulation);
|
||||
|
||||
delete inner_ip;
|
||||
Remove(f);
|
||||
return;
|
||||
}
|
||||
|
||||
default:
|
||||
Weird(fmt("unknown_protocol_%d", proto), hdr, pkt);
|
||||
delete tunnel_info;
|
||||
Remove(f);
|
||||
return;
|
||||
}
|
||||
|
@ -558,7 +582,7 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
|
|||
conn = (Connection*) d->Lookup(h);
|
||||
if ( ! conn )
|
||||
{
|
||||
conn = NewConn(h, t, &id, data, proto, tunnel_info);
|
||||
conn = NewConn(h, t, &id, data, proto, encapsulation);
|
||||
if ( conn )
|
||||
d->Insert(h, conn);
|
||||
}
|
||||
|
@ -569,7 +593,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
|
|||
if ( consistent < 0 )
|
||||
{
|
||||
delete h;
|
||||
delete tunnel_info;
|
||||
Remove(f);
|
||||
return;
|
||||
}
|
||||
|
@ -580,18 +603,20 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
|
|||
conn->Event(connection_reused, 0);
|
||||
|
||||
Remove(conn);
|
||||
conn = NewConn(h, t, &id, data, proto, tunnel_info);
|
||||
conn = NewConn(h, t, &id, data, proto, encapsulation);
|
||||
if ( conn )
|
||||
d->Insert(h, conn);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete h;
|
||||
conn->CheckEncapsulation(encapsulation);
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! conn )
|
||||
{
|
||||
delete h;
|
||||
delete tunnel_info;
|
||||
Remove(f);
|
||||
return;
|
||||
}
|
||||
|
@ -618,8 +643,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
|
|||
record_packet, record_content,
|
||||
hdr, pkt, hdr_size);
|
||||
|
||||
delete tunnel_info;
|
||||
|
||||
if ( f )
|
||||
{
|
||||
// Above we already recorded the fragment in its entirety.
|
||||
|
@ -651,11 +674,19 @@ bool NetSessions::CheckHeaderTrunc(int proto, uint32 len, uint32 caplen,
|
|||
case IPPROTO_UDP:
|
||||
min_hdr_len = sizeof(struct udphdr);
|
||||
break;
|
||||
case IPPROTO_IP:
|
||||
case IPPROTO_IPV4:
|
||||
min_hdr_len = sizeof(struct ip);
|
||||
break;
|
||||
case IPPROTO_IPV6:
|
||||
min_hdr_len = sizeof(struct ip6_hdr);
|
||||
break;
|
||||
case IPPROTO_ICMP:
|
||||
case IPPROTO_ICMPV6:
|
||||
default:
|
||||
// Use for all other packets.
|
||||
min_hdr_len = ICMP_MINLEN;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( len < min_hdr_len )
|
||||
|
@ -962,14 +993,14 @@ void NetSessions::GetStats(SessionStats& s) const
|
|||
}
|
||||
|
||||
Connection* NetSessions::NewConn(HashKey* k, double t, const ConnID* id,
|
||||
const u_char* data, int proto, TunnelInfo* tunnel_info)
|
||||
const u_char* data, int proto,
|
||||
const Encapsulation& encapsulation)
|
||||
{
|
||||
// FIXME: This should be cleaned up a bit, it's too protocol-specific.
|
||||
// But I'm not yet sure what the right abstraction for these things is.
|
||||
int src_h = ntohs(id->src_port);
|
||||
int dst_h = ntohs(id->dst_port);
|
||||
int flags = 0;
|
||||
TunnelParent *tunnel_parent = 0;
|
||||
|
||||
// Hmm... This is not great.
|
||||
TransportProto tproto = TRANSPORT_UNKNOWN;
|
||||
|
@ -1019,10 +1050,7 @@ Connection* NetSessions::NewConn(HashKey* k, double t, const ConnID* id,
|
|||
id = &flip_id;
|
||||
}
|
||||
|
||||
if ( tunnel_info )
|
||||
tunnel_parent = new TunnelParent(&(tunnel_info->parent));
|
||||
|
||||
Connection* conn = new Connection(this, k, t, id, tunnel_parent);
|
||||
Connection* conn = new Connection(this, k, t, id, encapsulation);
|
||||
conn->SetTransport(tproto);
|
||||
dpm->BuildInitialAnalyzerTree(tproto, conn, data);
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
struct pcap_pkthdr;
|
||||
|
||||
class Encapsulation;
|
||||
class Connection;
|
||||
class ConnID;
|
||||
class OSFingerprint;
|
||||
|
@ -26,9 +27,6 @@ class Discarder;
|
|||
class SteppingStoneManager;
|
||||
class PacketFilter;
|
||||
|
||||
class TunnelHandler;
|
||||
class TunnelInfo;
|
||||
|
||||
class PacketSortElement;
|
||||
|
||||
struct SessionStats {
|
||||
|
@ -145,7 +143,7 @@ protected:
|
|||
friend class TimerMgrExpireTimer;
|
||||
|
||||
Connection* NewConn(HashKey* k, double t, const ConnID* id,
|
||||
const u_char* data, int proto, TunnelInfo *tunnel_info);
|
||||
const u_char* data, int proto, const Encapsulation& encapsulation);
|
||||
|
||||
// Check whether the tag of the current packet is consistent with
|
||||
// the given connection. Returns:
|
||||
|
@ -178,7 +176,7 @@ protected:
|
|||
|
||||
void DoNextPacket(double t, const struct pcap_pkthdr* hdr,
|
||||
const IP_Hdr* ip_hdr, const u_char* const pkt,
|
||||
int hdr_size);
|
||||
int hdr_size, Encapsulation& encapsulation);
|
||||
|
||||
void NextPacketSecondary(double t, const struct pcap_pkthdr* hdr,
|
||||
const u_char* const pkt, int hdr_size,
|
||||
|
@ -216,8 +214,6 @@ protected:
|
|||
int num_packets_processed;
|
||||
PacketProfiler* pkt_profiler;
|
||||
|
||||
TunnelHandler *tunnel_handler;
|
||||
|
||||
// We may use independent timer managers for different sets of related
|
||||
// activity. The managers are identified by an unique tag.
|
||||
typedef std::map<TimerMgr::Tag, TimerMgr*> TimerMgrMap;
|
||||
|
|
|
@ -1,178 +1,52 @@
|
|||
// $Id: Sessions.cc 7075 2010-09-13 02:39:38Z vern $
|
||||
//
|
||||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "TunnelHandler.h"
|
||||
#include "Conn.h"
|
||||
#include "Sessions.h"
|
||||
|
||||
|
||||
TunnelHandler::TunnelHandler(NetSessions *arg_s)
|
||||
RecordVal* EncapsulatingConn::GetRecordVal() const
|
||||
{
|
||||
s = arg_s;
|
||||
PortVal *pv = 0;
|
||||
TableVal *udp_tunnel_ports = BifConst::Tunnel::udp_tunnel_ports->AsTableVal();
|
||||
// Find UDP ports we want to analyze. Store them in an array for faster
|
||||
// lookup.
|
||||
for ( int i = 0; i< 65536; i++ )
|
||||
{
|
||||
if ( pv )
|
||||
Unref(pv);
|
||||
pv = new PortVal(i, TRANSPORT_UDP);
|
||||
if ( udp_tunnel_ports->Lookup(pv, false) )
|
||||
udp_ports[i] = 1;
|
||||
else
|
||||
udp_ports[i] = 0;
|
||||
}
|
||||
Unref(pv);
|
||||
}
|
||||
|
||||
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() ) {
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
// TODO: check if IP6 header makes sense
|
||||
tunnel_info = new TunnelInfo();
|
||||
tunnel_info->child = new IP_Hdr((const struct ip6_hdr*)ip_hdr->Payload(), false, caplen);
|
||||
tunnel_info->parent.tunneltype = BifEnum::Tunnel::IP6_IN_IP;
|
||||
tunnel_info->hdr_len = tunnel_info->child->HdrLen();
|
||||
tunnel_info->SetParentIPs(ip_hdr);
|
||||
return tunnel_info;
|
||||
}
|
||||
break;
|
||||
// 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);
|
||||
}
|
||||
|
||||
RecordVal *rv =
|
||||
new RecordVal(BifType::Record::Tunnel::EncapsulatingConn);
|
||||
TransportProto tproto;
|
||||
switch ( type ) {
|
||||
case BifEnum::Tunnel::IP6_IN_IP4:
|
||||
case BifEnum::Tunnel::IP4_IN_IP4:
|
||||
case BifEnum::Tunnel::IP6_IN_IP6:
|
||||
case BifEnum::Tunnel::IP4_IN_IP6:
|
||||
tproto = TRANSPORT_UNKNOWN;
|
||||
break;
|
||||
default:
|
||||
tproto = TRANSPORT_UDP;
|
||||
break;
|
||||
} /* end switch */
|
||||
return 0;
|
||||
} // end switch
|
||||
|
||||
RecordVal* id_val = new RecordVal(conn_id);
|
||||
id_val->Assign(0, new AddrVal(src_addr));
|
||||
id_val->Assign(1, new PortVal(ntohs(src_port), tproto));
|
||||
id_val->Assign(2, new AddrVal(dst_addr));
|
||||
id_val->Assign(3, new PortVal(ntohs(dst_port), tproto));
|
||||
rv->Assign(0, id_val);
|
||||
rv->Assign(1, new EnumVal(type, BifType::Enum::Tunnel::Type));
|
||||
return rv;
|
||||
}
|
||||
|
||||
TunnelInfo* TunnelHandler::HandleUDP(const IP_Hdr *ip_hdr, int len, int caplen)
|
||||
bool operator==(const Encapsulation& e1, const Encapsulation& e2)
|
||||
{
|
||||
// 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 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 )
|
||||
if ( e1.conns )
|
||||
if ( e2.conns )
|
||||
{
|
||||
// Found and IP hdr directly in the UDP payload
|
||||
tunneltype = (cand_ip_hdr->IP4_Hdr()) ?
|
||||
BifEnum::Tunnel::IP4_IN_UDP : BifEnum::Tunnel::IP6_IN_UDP;
|
||||
if ( e1.conns->size() != e2.conns->size() )
|
||||
return false;
|
||||
else
|
||||
for ( size_t i = 0; i < e1.conns->size(); ++i )
|
||||
if ( (*e1.conns)[i] != (*e2.conns)[i] )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
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::IP4_IN_AYIAY : BifEnum::Tunnel::IP6_IN_AYIAY;
|
||||
}
|
||||
}
|
||||
if ( cand_ip_hdr )
|
||||
{
|
||||
TunnelInfo *tunnel_info = new TunnelInfo();
|
||||
tunnel_info->child = cand_ip_hdr;
|
||||
tunnel_info->parent.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, false);
|
||||
else if ( ip4->ip_v == 6 && (datalen > (int)sizeof(struct ip6_hdr)) )
|
||||
cand_ip_hdr = new IP_Hdr((const struct ip6_hdr*)data, false, datalen);
|
||||
|
||||
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;
|
||||
else
|
||||
return false;
|
||||
else
|
||||
if ( e2.conns )
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -3,105 +3,109 @@
|
|||
#ifndef tunnelhandler_h
|
||||
#define tunnelhandler_h
|
||||
|
||||
#include <netinet/udp.h>
|
||||
#include "net_util.h"
|
||||
#include "IP.h"
|
||||
#include "config.h"
|
||||
#include "NetVar.h"
|
||||
#include "IPAddr.h"
|
||||
#include "Conn.h"
|
||||
#include "Sessions.h"
|
||||
#include "Val.h"
|
||||
#include <vector>
|
||||
|
||||
class TunnelParent {
|
||||
class EncapsulatingConn {
|
||||
public:
|
||||
TunnelParent()
|
||||
EncapsulatingConn()
|
||||
: src_port(0), dst_port(0), type(BifEnum::Tunnel::NONE) {}
|
||||
|
||||
EncapsulatingConn(const IPAddr& s, const IPAddr& d,
|
||||
BifEnum::Tunnel::Type t)
|
||||
: src_addr(s), dst_addr(d), src_port(0), dst_port(0), type(t) {}
|
||||
|
||||
EncapsulatingConn(const IPAddr& s, const IPAddr& d, uint16 sp, uint16 dp,
|
||||
BifEnum::Tunnel::Type t)
|
||||
: src_addr(s), dst_addr(d), src_port(sp), dst_port(dp), type(t) {}
|
||||
|
||||
EncapsulatingConn(const EncapsulatingConn& other)
|
||||
: src_addr(other.src_addr), dst_addr(other.dst_addr),
|
||||
src_port(other.src_port), dst_port(other.dst_port),
|
||||
type(other.type) {}
|
||||
|
||||
~EncapsulatingConn() {}
|
||||
|
||||
RecordVal* GetRecordVal() const;
|
||||
|
||||
friend bool operator==(const EncapsulatingConn& ec1,
|
||||
const EncapsulatingConn& ec2)
|
||||
{
|
||||
tunneltype = BifEnum::Tunnel::NONE;
|
||||
src_port = dst_port = 0;
|
||||
return ec1.type == ec2.type && ec1.src_addr == ec2.src_addr &&
|
||||
ec1.src_port == ec2.src_port && ec1.dst_port == ec2.dst_port;
|
||||
}
|
||||
|
||||
TunnelParent(TunnelParent *other)
|
||||
friend bool operator!=(const EncapsulatingConn& ec1,
|
||||
const EncapsulatingConn& ec2)
|
||||
{
|
||||
tunneltype = other->tunneltype;
|
||||
src_addr = other->src_addr;
|
||||
dst_addr = other->dst_addr;
|
||||
src_port = other->src_port;
|
||||
dst_port = other->dst_port;
|
||||
}
|
||||
|
||||
RecordVal* GetRecordVal() const
|
||||
{
|
||||
RecordVal *rv = new RecordVal(BifType::Record::Tunnel::Parent);
|
||||
TransportProto tproto;
|
||||
switch ( tunneltype ) {
|
||||
case BifEnum::Tunnel::IP6_IN_IP:
|
||||
case BifEnum::Tunnel::IP4_IN_IP:
|
||||
tproto = TRANSPORT_UNKNOWN;
|
||||
break;
|
||||
default:
|
||||
tproto = TRANSPORT_UDP;
|
||||
} // end switch
|
||||
|
||||
RecordVal* id_val = new RecordVal(conn_id);
|
||||
id_val->Assign(0, new AddrVal(src_addr));
|
||||
id_val->Assign(1, new PortVal(ntohs(src_port), tproto));
|
||||
id_val->Assign(2, new AddrVal(dst_addr));
|
||||
id_val->Assign(3, new PortVal(ntohs(dst_port), tproto));
|
||||
rv->Assign(0, id_val);
|
||||
rv->Assign(1, new EnumVal(tunneltype, BifType::Enum::Tunnel::Tunneltype));
|
||||
return rv;
|
||||
return ! ( ec1 == ec2 );
|
||||
}
|
||||
|
||||
IPAddr src_addr;
|
||||
IPAddr dst_addr;
|
||||
uint16 src_port;
|
||||
uint16 dst_port;
|
||||
BifEnum::Tunnel::Tunneltype tunneltype;
|
||||
BifEnum::Tunnel::Type type;
|
||||
};
|
||||
|
||||
class TunnelInfo {
|
||||
class Encapsulation {
|
||||
public:
|
||||
TunnelInfo()
|
||||
Encapsulation() : conns(0) {}
|
||||
|
||||
Encapsulation(const Encapsulation& other)
|
||||
{
|
||||
child = 0;
|
||||
hdr_len = 0;
|
||||
}
|
||||
~TunnelInfo()
|
||||
{
|
||||
if (child) delete child;
|
||||
if ( other.conns )
|
||||
conns = new vector<EncapsulatingConn>(*(other.conns));
|
||||
else
|
||||
conns = 0;
|
||||
}
|
||||
|
||||
void SetParentIPs(const IP_Hdr *ip_hdr)
|
||||
Encapsulation& operator=(const Encapsulation& other)
|
||||
{
|
||||
parent.src_addr = ip_hdr->SrcAddr();
|
||||
parent.dst_addr = ip_hdr->DstAddr();
|
||||
}
|
||||
void SetParentPorts(const struct udphdr *uh)
|
||||
{
|
||||
parent.src_port = uh->uh_sport;
|
||||
parent.dst_port = uh->uh_dport;
|
||||
if ( this == &other ) return *this;
|
||||
delete conns;
|
||||
if ( other.conns )
|
||||
conns = new vector<EncapsulatingConn>(*(other.conns));
|
||||
else
|
||||
conns = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
IP_Hdr *child;
|
||||
TunnelParent parent;
|
||||
int hdr_len;
|
||||
~Encapsulation() { delete conns; }
|
||||
|
||||
void Add(const EncapsulatingConn& c)
|
||||
{
|
||||
if ( ! conns )
|
||||
conns = new vector<EncapsulatingConn>();
|
||||
conns->push_back(c);
|
||||
}
|
||||
|
||||
size_t Depth() const
|
||||
{
|
||||
return conns ? conns->size() : 0;
|
||||
}
|
||||
|
||||
VectorVal* GetVectorVal() const
|
||||
{
|
||||
VectorVal* vv = new VectorVal(new VectorType(
|
||||
BifType::Record::Tunnel::EncapsulatingConn->Ref()));
|
||||
if ( conns )
|
||||
for ( size_t i = 0; i < conns->size(); ++i )
|
||||
vv->Assign(i, (*conns)[i].GetRecordVal(), 0);
|
||||
return vv;
|
||||
}
|
||||
|
||||
friend bool operator==(const Encapsulation& e1, const Encapsulation& e2);
|
||||
|
||||
friend bool operator!=(const Encapsulation& e1, const Encapsulation& e2)
|
||||
{
|
||||
return ! ( e1 == e2 );
|
||||
}
|
||||
|
||||
vector<EncapsulatingConn>* conns;
|
||||
};
|
||||
|
||||
class TunnelHandler {
|
||||
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()
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
const ignore_keep_alive_rexmit: bool;
|
||||
const skip_http_data: bool;
|
||||
const parse_udp_tunnels: bool;
|
||||
const use_conn_size_analyzer: bool;
|
||||
const report_gaps_for_partial: bool;
|
||||
|
||||
|
@ -16,3 +15,4 @@ const Tunnel::decapsulate_ip: bool;
|
|||
const Tunnel::decapsulate_udp: bool;
|
||||
const Tunnel::udp_tunnel_ports: any;
|
||||
const Tunnel::udp_tunnel_allports: bool;
|
||||
const Tunnel::max_depth: count;
|
||||
|
|
|
@ -141,6 +141,17 @@ event dns_mapping_altered%(dm: dns_mapping, old_addrs: addr_set, new_addrs: addr
|
|||
## event.
|
||||
event new_connection%(c: connection%);
|
||||
|
||||
## Generated for a connection whose tunneling has changed. This could
|
||||
## be from a previously seen connection now being encapsulated in a tunnel,
|
||||
## or from the outer encapsulation changing. Note that the connection's
|
||||
## *tunnel* field is NOT automatically assigned to the new encapsulation value
|
||||
## internally after this event is raised.
|
||||
##
|
||||
## c: The connection whose tunnel/encapsulation changed.
|
||||
##
|
||||
## e: The new encapsulation.
|
||||
event tunnel_changed%(c: connection, e: encapsulating_conns%);
|
||||
|
||||
## Generated when reassembly starts for a TCP connection. The event is raised
|
||||
## at the moment when Bro's TCP analyzer enables stream reassembly for a
|
||||
## connection.
|
||||
|
|
|
@ -170,16 +170,18 @@ enum ID %{
|
|||
|
||||
|
||||
module Tunnel;
|
||||
enum Tunneltype %{
|
||||
enum Type %{
|
||||
NONE,
|
||||
IP6_IN_IP,
|
||||
IP4_IN_IP,
|
||||
IP6_IN_IP4,
|
||||
IP4_IN_IP4,
|
||||
IP6_IN_IP6,
|
||||
IP4_IN_IP6,
|
||||
IP6_IN_UDP,
|
||||
IP4_IN_UDP,
|
||||
IP6_IN_AYIAY,
|
||||
IP4_IN_AYIAY,
|
||||
%}
|
||||
|
||||
type Parent: record;
|
||||
type EncapsulatingConn: record;
|
||||
|
||||
module GLOBAL;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue