mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
Make result of IP::ParsePacket easier to understand
This commit is contained in:
parent
40b1452905
commit
aa79356963
6 changed files with 56 additions and 39 deletions
6
NEWS
6
NEWS
|
@ -54,6 +54,12 @@ Breaking Changes
|
||||||
- The unified2 analyzer and accompanying scripts have been removed without
|
- The unified2 analyzer and accompanying scripts have been removed without
|
||||||
deprecation.
|
deprecation.
|
||||||
|
|
||||||
|
- The return value of ``packet_analysis::IP::ParsePacket`` has changed to return
|
||||||
|
enum values. This makes it easier to look at the result and immediately know
|
||||||
|
what it means. Unfortunately, because we can't overload a method on the return
|
||||||
|
value alone, we aren't able to deprecate the original version of the method.
|
||||||
|
This may cause build of packages to fail if they were using this method.
|
||||||
|
|
||||||
New Functionality
|
New Functionality
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
|
|
@ -55,9 +55,9 @@ bool GTPv1_Analyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* pack
|
||||||
// but on the other hand we duplicate this work here. maybe this header could just be stored
|
// but on the other hand we duplicate this work here. maybe this header could just be stored
|
||||||
// and reused in the IP analyzer somehow?
|
// and reused in the IP analyzer somehow?
|
||||||
std::shared_ptr<IP_Hdr> inner = nullptr;
|
std::shared_ptr<IP_Hdr> inner = nullptr;
|
||||||
int result = packet_analysis::IP::ParsePacket(len, data, next_header, inner);
|
auto result = packet_analysis::IP::ParsePacket(len, data, next_header, inner);
|
||||||
|
|
||||||
if ( result == 0 )
|
if ( result == packet_analysis::IP::ParseResult::Ok )
|
||||||
{
|
{
|
||||||
cm_it->second->set_valid(packet->is_orig, true);
|
cm_it->second->set_valid(packet->is_orig, true);
|
||||||
|
|
||||||
|
@ -72,13 +72,13 @@ bool GTPv1_Analyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* pack
|
||||||
gtp_hdr_val = nullptr;
|
gtp_hdr_val = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ( result == -2 )
|
else if ( result == packet_analysis::IP::ParseResult::BadProtocol )
|
||||||
{
|
{
|
||||||
AnalyzerViolation("Invalid IP version in wrapped packet", packet->session);
|
AnalyzerViolation("Invalid IP version in wrapped packet", packet->session);
|
||||||
gtp_hdr_val = nullptr;
|
gtp_hdr_val = nullptr;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if ( result < 0 )
|
else if ( result == packet_analysis::IP::ParseResult::CaplenTooSmall )
|
||||||
{
|
{
|
||||||
AnalyzerViolation("Truncated GTPv1", packet->session);
|
AnalyzerViolation("Truncated GTPv1", packet->session);
|
||||||
gtp_hdr_val = nullptr;
|
gtp_hdr_val = nullptr;
|
||||||
|
|
|
@ -283,38 +283,38 @@ bool IPAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet)
|
||||||
return return_val;
|
return return_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
int zeek::packet_analysis::IP::ParsePacket(int caplen, const u_char* const pkt, int proto,
|
ParseResult zeek::packet_analysis::IP::ParsePacket(int caplen, const u_char* const pkt, int proto,
|
||||||
std::shared_ptr<zeek::IP_Hdr>& inner)
|
std::shared_ptr<zeek::IP_Hdr>& inner)
|
||||||
{
|
{
|
||||||
if ( proto == IPPROTO_IPV6 )
|
if ( proto == IPPROTO_IPV6 )
|
||||||
{
|
{
|
||||||
if ( caplen < (int)sizeof(struct ip6_hdr) )
|
if ( caplen < (int)sizeof(struct ip6_hdr) )
|
||||||
return -1;
|
return ParseResult::CaplenTooSmall;
|
||||||
|
|
||||||
const struct ip6_hdr* ip6 = (const struct ip6_hdr*)pkt;
|
const struct ip6_hdr* ip6 = (const struct ip6_hdr*)pkt;
|
||||||
inner = std::make_shared<zeek::IP_Hdr>(ip6, false, caplen);
|
inner = std::make_shared<zeek::IP_Hdr>(ip6, false, caplen);
|
||||||
if ( (ip6->ip6_ctlun.ip6_un2_vfc & 0xF0) != 0x60 )
|
if ( (ip6->ip6_ctlun.ip6_un2_vfc & 0xF0) != 0x60 )
|
||||||
return -2;
|
return ParseResult::BadProtocol;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if ( proto == IPPROTO_IPV4 )
|
else if ( proto == IPPROTO_IPV4 )
|
||||||
{
|
{
|
||||||
if ( caplen < (int)sizeof(struct ip) )
|
if ( caplen < (int)sizeof(struct ip) )
|
||||||
return -1;
|
return ParseResult::BadProtocol;
|
||||||
|
|
||||||
const struct ip* ip4 = (const struct ip*)pkt;
|
const struct ip* ip4 = (const struct ip*)pkt;
|
||||||
inner = std::make_shared<zeek::IP_Hdr>(ip4, false);
|
inner = std::make_shared<zeek::IP_Hdr>(ip4, false);
|
||||||
if ( ip4->ip_v != 4 )
|
if ( ip4->ip_v != 4 )
|
||||||
return -2;
|
return ParseResult::BadProtocol;
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return -2;
|
return ParseResult::BadProtocol;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( (uint32_t)caplen != inner->TotalLen() )
|
if ( (uint32_t)caplen != inner->TotalLen() )
|
||||||
return (uint32_t)caplen < inner->TotalLen() ? -1 : 1;
|
return (uint32_t)caplen < inner->TotalLen() ? ParseResult::CaplenTooSmall
|
||||||
|
: ParseResult::CaplenTooLarge;
|
||||||
|
|
||||||
return 0;
|
return ParseResult::Ok;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,14 @@ private:
|
||||||
zeek::detail::Discarder* discarder = nullptr;
|
zeek::detail::Discarder* discarder = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class ParseResult
|
||||||
|
{
|
||||||
|
Ok = 0,
|
||||||
|
CaplenTooSmall = -1,
|
||||||
|
BadProtocol = -2,
|
||||||
|
CaplenTooLarge = 1
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a wrapper IP_Hdr object if \a pkt appears to be a valid IPv4
|
* 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,
|
* or IPv6 header based on whether it's long enough to contain such a header,
|
||||||
|
@ -49,13 +57,17 @@ private:
|
||||||
* @param inner The inner IP packet wrapper pointer to be allocated/assigned
|
* @param inner The inner IP packet wrapper pointer to be allocated/assigned
|
||||||
* if \a pkt looks like a valid IP packet or at least long enough
|
* if \a pkt looks like a valid IP packet or at least long enough
|
||||||
* to hold an IP header.
|
* to hold an IP header.
|
||||||
* @return 0 If the inner IP packet appeared valid, else -1 if \a caplen
|
* @return ParseResult::Ok if the inner IP packet appeared valid.
|
||||||
* is greater than the supposed IP packet's payload length field, -2
|
* ParseResult::CaplenTooSmall if \a caplen is greater than the
|
||||||
* if the version of the inner header does not match proto or
|
* supposed packet's payload length field. \a inner may still be
|
||||||
* 1 if \a caplen is less than the supposed packet's payload length.
|
* non-null if \a caplen is too small but still large enough to
|
||||||
* In the -1 case, \a inner may still be non-null if \a caplen was
|
* be an IP header. ParseResult::CaplenTooLarge if \a caplen is
|
||||||
* long enough to be an IP header, and \a inner is always non-null
|
* larger than the supposed packet's payload length field.
|
||||||
* for other return values.
|
* ParseResult::BadProtocol if either \a proto isn't IPPROTO_IPV4
|
||||||
|
* or IPPROTO_IPV6 or if \a proto does not match the protocol
|
||||||
|
* in the header's version field.
|
||||||
*/
|
*/
|
||||||
int ParsePacket(int caplen, const u_char* const pkt, int proto, std::shared_ptr<IP_Hdr>& inner);
|
ParseResult ParsePacket(int caplen, const u_char* const pkt, int proto,
|
||||||
|
std::shared_ptr<IP_Hdr>& inner);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,15 +50,15 @@ bool IPTunnelAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* pa
|
||||||
if ( gre_version != 0 )
|
if ( gre_version != 0 )
|
||||||
{
|
{
|
||||||
// Check for a valid inner packet first.
|
// Check for a valid inner packet first.
|
||||||
int result = packet_analysis::IP::ParsePacket(len, data, proto, inner);
|
auto result = packet_analysis::IP::ParsePacket(len, data, proto, inner);
|
||||||
if ( result == -2 )
|
if ( result == packet_analysis::IP::ParseResult::BadProtocol )
|
||||||
Weird("invalid_inner_IP_version", packet);
|
Weird("invalid_inner_IP_version", packet);
|
||||||
else if ( result < 0 )
|
else if ( result < packet_analysis::IP::ParseResult::CaplenTooSmall )
|
||||||
Weird("truncated_inner_IP", packet);
|
Weird("truncated_inner_IP", packet);
|
||||||
else if ( result > 0 )
|
else if ( result > packet_analysis::IP::ParseResult::CaplenTooLarge )
|
||||||
Weird("inner_IP_payload_length_mismatch", packet);
|
Weird("inner_IP_payload_length_mismatch", packet);
|
||||||
|
|
||||||
if ( result != 0 )
|
if ( result != packet_analysis::IP::ParseResult::Ok )
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -192,8 +192,8 @@ bool TeredoAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* pack
|
||||||
// but on the other hand we duplicate this work here. maybe this header could just be stored
|
// but on the other hand we duplicate this work here. maybe this header could just be stored
|
||||||
// and reused in the IP analyzer somehow?
|
// and reused in the IP analyzer somehow?
|
||||||
std::shared_ptr<IP_Hdr> inner = nullptr;
|
std::shared_ptr<IP_Hdr> inner = nullptr;
|
||||||
int rslt = packet_analysis::IP::ParsePacket(len, te.InnerIP(), IPPROTO_IPV6, inner);
|
auto result = packet_analysis::IP::ParsePacket(len, te.InnerIP(), IPPROTO_IPV6, inner);
|
||||||
if ( rslt > 0 )
|
if ( result == packet_analysis::IP::ParseResult::CaplenTooLarge )
|
||||||
{
|
{
|
||||||
if ( inner->NextProto() == IPPROTO_NONE && inner->PayloadLen() == 0 )
|
if ( inner->NextProto() == IPPROTO_NONE && inner->PayloadLen() == 0 )
|
||||||
// Teredo bubbles having data after IPv6 header isn't strictly a
|
// Teredo bubbles having data after IPv6 header isn't strictly a
|
||||||
|
@ -206,21 +206,20 @@ bool TeredoAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* pack
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( rslt == 0 || rslt > 0 )
|
if ( result == packet_analysis::IP::ParseResult::CaplenTooSmall ||
|
||||||
|
result == packet_analysis::IP::ParseResult::BadProtocol )
|
||||||
{
|
{
|
||||||
|
AnalyzerViolation("Truncated Teredo or invalid inner IP version", conn, (const char*)data,
|
||||||
|
len);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if ( packet->is_orig )
|
if ( packet->is_orig )
|
||||||
or_it->second.valid_orig = true;
|
or_it->second.valid_orig = true;
|
||||||
else
|
else
|
||||||
or_it->second.valid_resp = true;
|
or_it->second.valid_resp = true;
|
||||||
|
|
||||||
Confirm(or_it->second.valid_orig, or_it->second.valid_resp);
|
Confirm(or_it->second.valid_orig, or_it->second.valid_resp);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AnalyzerViolation("Truncated Teredo or invalid inner IP version", conn, (const char*)data,
|
|
||||||
len);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ValPtr teredo_hdr;
|
ValPtr teredo_hdr;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue