mirror of
https://github.com/zeek/zeek.git
synced 2025-10-12 19:48:20 +00:00
Refactor some of the NetSessions routines that recurse on IP packets.
Separating the IP packet validation/parsing from the recursive call to DoNextPacket to make it easier for analyzers to get access to the inner IP_Hdr.
This commit is contained in:
parent
976e8db155
commit
b52436a53b
4 changed files with 110 additions and 71 deletions
102
src/Sessions.cc
102
src/Sessions.cc
|
@ -538,6 +538,23 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for a valid inner packet first.
|
||||||
|
IP_Hdr* inner = 0;
|
||||||
|
int result = ParseIPPacket(caplen, data, proto, inner);
|
||||||
|
|
||||||
|
if ( result < 0 )
|
||||||
|
reporter->Weird(ip_hdr->SrcAddr(), ip_hdr->DstAddr(),
|
||||||
|
"truncated_inner_IP");
|
||||||
|
else if ( result > 0 )
|
||||||
|
reporter->Weird(ip_hdr->SrcAddr(), ip_hdr->DstAddr(),
|
||||||
|
"inner_IP_payload_mismatch");
|
||||||
|
|
||||||
|
if ( result != 0 )
|
||||||
|
{
|
||||||
|
Remove(f);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Encapsulation* outer = new Encapsulation(encapsulation);
|
Encapsulation* outer = new Encapsulation(encapsulation);
|
||||||
|
|
||||||
// Look up to see if we've already seen this IP tunnel, identified
|
// Look up to see if we've already seen this IP tunnel, identified
|
||||||
|
@ -561,14 +578,9 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
|
||||||
else
|
else
|
||||||
outer->Add(it->second);
|
outer->Add(it->second);
|
||||||
|
|
||||||
int result = DoNextInnerPacket(t, hdr, caplen, data, proto, outer);
|
DoNextInnerPacket(t, hdr, inner, outer);
|
||||||
if ( result < 0 )
|
|
||||||
reporter->Weird(ip_hdr->SrcAddr(), ip_hdr->DstAddr(),
|
|
||||||
"truncated_inner_IP");
|
|
||||||
else if ( result > 0 )
|
|
||||||
reporter->Weird(ip_hdr->SrcAddr(), ip_hdr->DstAddr(),
|
|
||||||
"inner_IP_payload_mismatch");
|
|
||||||
|
|
||||||
|
delete inner;
|
||||||
delete outer;
|
delete outer;
|
||||||
Remove(f);
|
Remove(f);
|
||||||
return;
|
return;
|
||||||
|
@ -576,12 +588,11 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
|
||||||
|
|
||||||
case IPPROTO_NONE:
|
case IPPROTO_NONE:
|
||||||
{
|
{
|
||||||
if ( encapsulation &&
|
// If the packet is encapsulated in Teredo, then it was a bubble and
|
||||||
encapsulation->LastType() == BifEnum::Tunnel::TEREDO )
|
// the Teredo analyzer may have raised an event for that, else we're
|
||||||
{
|
// not sure the reason for the No Next header in the packet.
|
||||||
// TODO: raise bubble packet event
|
if ( ! ( encapsulation &&
|
||||||
}
|
encapsulation->LastType() == BifEnum::Tunnel::TEREDO ) )
|
||||||
else
|
|
||||||
Weird("ipv6_no_next", hdr, pkt);
|
Weird("ipv6_no_next", hdr, pkt);
|
||||||
|
|
||||||
Remove(f);
|
Remove(f);
|
||||||
|
@ -688,43 +699,50 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int NetSessions::DoNextInnerPacket(double t, const struct pcap_pkthdr* hdr,
|
void NetSessions::DoNextInnerPacket(double t, const struct pcap_pkthdr* hdr,
|
||||||
int caplen, const u_char* const pkt, int proto,
|
const IP_Hdr* inner, const Encapsulation* outer)
|
||||||
const Encapsulation* outer)
|
|
||||||
{
|
{
|
||||||
IP_Hdr* inner_ip = 0;
|
|
||||||
|
|
||||||
if ( proto == IPPROTO_IPV6 )
|
|
||||||
{
|
|
||||||
if ( caplen < (int)sizeof(struct ip6_hdr) )
|
|
||||||
return -1;
|
|
||||||
inner_ip = new IP_Hdr((const struct ip6_hdr*) pkt, false, caplen);
|
|
||||||
}
|
|
||||||
else if ( proto == IPPROTO_IPV4 )
|
|
||||||
{
|
|
||||||
if ( caplen < (int)sizeof(struct ip) )
|
|
||||||
return -1;
|
|
||||||
inner_ip = new IP_Hdr((const struct ip*) pkt, false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
reporter->InternalError("Bad IP protocol version in DoNextInnerPacket");
|
|
||||||
|
|
||||||
if ( (uint32)caplen != inner_ip->TotalLen() )
|
|
||||||
{
|
|
||||||
delete inner_ip;
|
|
||||||
return (uint32)caplen < inner_ip->TotalLen() ? -1 : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct pcap_pkthdr fake_hdr;
|
struct pcap_pkthdr fake_hdr;
|
||||||
fake_hdr.caplen = fake_hdr.len = caplen;
|
fake_hdr.caplen = fake_hdr.len = inner->TotalLen();
|
||||||
if ( hdr )
|
if ( hdr )
|
||||||
fake_hdr.ts = hdr->ts;
|
fake_hdr.ts = hdr->ts;
|
||||||
else
|
else
|
||||||
fake_hdr.ts.tv_sec = fake_hdr.ts.tv_usec = 0;
|
fake_hdr.ts.tv_sec = fake_hdr.ts.tv_usec = 0;
|
||||||
|
|
||||||
DoNextPacket(t, &fake_hdr, inner_ip, pkt, 0, outer);
|
const u_char* pkt = 0;
|
||||||
|
if ( inner->IP4_Hdr() )
|
||||||
|
pkt = (const u_char*) inner->IP4_Hdr();
|
||||||
|
else
|
||||||
|
pkt = (const u_char*) inner->IP6_Hdr();
|
||||||
|
|
||||||
|
DoNextPacket(t, &fake_hdr, inner, pkt, 0, outer);
|
||||||
|
}
|
||||||
|
|
||||||
|
int NetSessions::ParseIPPacket(int caplen, const u_char* const pkt, int proto,
|
||||||
|
IP_Hdr*& inner)
|
||||||
|
{
|
||||||
|
if ( proto == IPPROTO_IPV6 )
|
||||||
|
{
|
||||||
|
if ( caplen < (int)sizeof(struct ip6_hdr) )
|
||||||
|
return -1;
|
||||||
|
inner = new IP_Hdr((const struct ip6_hdr*) pkt, false, caplen);
|
||||||
|
}
|
||||||
|
else if ( proto == IPPROTO_IPV4 )
|
||||||
|
{
|
||||||
|
if ( caplen < (int)sizeof(struct ip) )
|
||||||
|
return -1;
|
||||||
|
inner = new IP_Hdr((const struct ip*) pkt, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
reporter->InternalError("Bad IP protocol version in DoNextInnerPacket");
|
||||||
|
|
||||||
|
if ( (uint32)caplen != inner->TotalLen() )
|
||||||
|
{
|
||||||
|
delete inner;
|
||||||
|
inner = 0;
|
||||||
|
return (uint32)caplen < inner->TotalLen() ? -1 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
delete inner_ip;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -139,28 +139,37 @@ public:
|
||||||
int hdr_size, const Encapsulation* encapsulation);
|
int hdr_size, const Encapsulation* encapsulation);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper that recurses on DoNextPacket for encapsulated IP packets, if
|
* Wrapper that recurses on DoNextPacket for encapsulated IP packets.
|
||||||
* they appear to be valid based on whether \a pkt is long enough to be an
|
|
||||||
* IP header and also that the payload length field of that header matches
|
|
||||||
* matches the actual length of \a pkt given by \a caplen.
|
|
||||||
*
|
*
|
||||||
* @param t Network time.
|
* @param t Network time.
|
||||||
* @param hdr If the outer pcap header is available, this pointer can be set
|
* @param hdr If the outer pcap header is available, this pointer can be set
|
||||||
* so that the fake pcap header passed to DoNextPacket will use
|
* so that the fake pcap header passed to DoNextPacket will use
|
||||||
* the same timeval. The caplen and len fields of the fake pcap
|
* the same timeval. The caplen and len fields of the fake pcap
|
||||||
* header are always set to \a caplen.
|
* header are always set to the TotalLength() of \a inner.
|
||||||
|
* @param outer The encapsulation information for the inner IP packet.
|
||||||
|
*/
|
||||||
|
void DoNextInnerPacket(double t, const struct pcap_pkthdr* hdr,
|
||||||
|
const IP_Hdr* inner, const Encapsulation* outer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a wrapper IP_Hdr object if \a pkt appears to be a valid IPv4
|
||||||
|
* or IPv6 header based on whether it's long enough to contain such a header
|
||||||
|
* and also that the payload length field of that header matches the actual
|
||||||
|
* length of \a pkt given by \a caplen.
|
||||||
|
*
|
||||||
* @param caplen The length of \a pkt in bytes.
|
* @param caplen The length of \a pkt in bytes.
|
||||||
* @param pkt The inner IP packet data.
|
* @param pkt The inner IP packet data.
|
||||||
* @param proto Either IPPROTO_IPV6 or IPPROTO_IPV4 to indicate which IP
|
* @param proto Either IPPROTO_IPV6 or IPPROTO_IPV4 to indicate which IP
|
||||||
* protocol \a pkt corresponds to.
|
* protocol \a pkt corresponds to.
|
||||||
* @param outer_encap The encapsulation information for the inner IP packet.
|
* @param inner The inner IP packet wrapper pointer to be allocated/assigned
|
||||||
* @return 0 If the inner IP packet was valid and passed to DoNextPacket,
|
* if \a pkt looks like a valid IP packet.
|
||||||
* else -1 if the \a caplen was greater than the supposed IP
|
* @return 0 If the inner IP packet appeared valid in which case the caller
|
||||||
* packet's payload length field or 1 if \a caplen was less than
|
* is responsible for deallocating \a inner, else -1 if \a caplen
|
||||||
* the supposed IP packet's payload length.
|
* is greater than the supposed IP packet's payload length field or
|
||||||
|
* 1 if \a caplen is less than the supposed packet's payload length.
|
||||||
*/
|
*/
|
||||||
int DoNextInnerPacket(double t, const struct pcap_pkthdr* hdr, int caplen,
|
int ParseIPPacket(int caplen, const u_char* const pkt, int proto,
|
||||||
const u_char* const pkt, int proto, const Encapsulation* outer);
|
IP_Hdr*& inner);
|
||||||
|
|
||||||
unsigned int ConnectionMemoryUsage();
|
unsigned int ConnectionMemoryUsage();
|
||||||
unsigned int ConnectionMemoryUsageConnVals();
|
unsigned int ConnectionMemoryUsageConnVals();
|
||||||
|
|
|
@ -109,20 +109,26 @@ void Teredo_Analyzer::DeliverPacket(int len, const u_char* data, bool orig,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: raise Teredo-specific events
|
IP_Hdr* inner = 0;
|
||||||
|
int rslt = sessions->ParseIPPacket(len, te.InnerIP(), IPPROTO_IPV6, inner);
|
||||||
|
|
||||||
|
if ( rslt == 0 )
|
||||||
|
ProtocolConfirmation();
|
||||||
|
else if ( rslt < 0 )
|
||||||
|
ProtocolViolation("Truncated Teredo", (const char*) data, len);
|
||||||
|
else
|
||||||
|
ProtocolViolation("Teredo payload length", (const char*) data, len);
|
||||||
|
|
||||||
|
if ( rslt != 0 ) return;
|
||||||
|
|
||||||
|
// TODO: raise Teredo-specific events for bubbles, origin/authentication
|
||||||
|
|
||||||
Encapsulation* outer = new Encapsulation(e);
|
Encapsulation* outer = new Encapsulation(e);
|
||||||
EncapsulatingConn ec(Conn(), BifEnum::Tunnel::TEREDO);
|
EncapsulatingConn ec(Conn(), BifEnum::Tunnel::TEREDO);
|
||||||
outer->Add(ec);
|
outer->Add(ec);
|
||||||
|
|
||||||
int result = sessions->DoNextInnerPacket(network_time, 0, len, te.InnerIP(),
|
sessions->DoNextInnerPacket(network_time, 0, inner, outer);
|
||||||
IPPROTO_IPV6, outer);
|
|
||||||
if ( result == 0 )
|
|
||||||
ProtocolConfirmation();
|
|
||||||
else if ( result < 0 )
|
|
||||||
ProtocolViolation("Truncated Teredo", (const char*) data, len);
|
|
||||||
else
|
|
||||||
ProtocolViolation("Teredo payload length", (const char*) data, len);
|
|
||||||
|
|
||||||
|
delete inner;
|
||||||
delete outer;
|
delete outer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,13 +52,10 @@ flow AYIYA_Flow
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Encapsulation* outer = new Encapsulation(e);
|
IP_Hdr* inner = 0;
|
||||||
EncapsulatingConn ec(c, BifEnum::Tunnel::AYIYA);
|
int result = sessions->ParseIPPacket(${pdu.packet}.length(),
|
||||||
outer->Add(ec);
|
${pdu.packet}.data(), ${pdu.next_header}, inner);
|
||||||
|
|
||||||
int result = sessions->DoNextInnerPacket(network_time(), 0,
|
|
||||||
${pdu.packet}.length(), ${pdu.packet}.data(),
|
|
||||||
${pdu.next_header}, outer);
|
|
||||||
if ( result == 0 )
|
if ( result == 0 )
|
||||||
connection()->bro_analyzer()->ProtocolConfirmation();
|
connection()->bro_analyzer()->ProtocolConfirmation();
|
||||||
else if ( result < 0 )
|
else if ( result < 0 )
|
||||||
|
@ -70,6 +67,15 @@ flow AYIYA_Flow
|
||||||
"AYIYA payload length", (const char*) ${pdu.packet}.data(),
|
"AYIYA payload length", (const char*) ${pdu.packet}.data(),
|
||||||
${pdu.packet}.length());
|
${pdu.packet}.length());
|
||||||
|
|
||||||
|
if ( result != 0 ) return false;
|
||||||
|
|
||||||
|
Encapsulation* outer = new Encapsulation(e);
|
||||||
|
EncapsulatingConn ec(c, BifEnum::Tunnel::AYIYA);
|
||||||
|
outer->Add(ec);
|
||||||
|
|
||||||
|
sessions->DoNextInnerPacket(network_time(), 0, inner, outer);
|
||||||
|
|
||||||
|
delete inner;
|
||||||
delete outer;
|
delete outer;
|
||||||
return (result == 0) ? true : false;
|
return (result == 0) ? true : false;
|
||||||
%}
|
%}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue