Merge branch 'topic/timw/parse-packet-results'

* topic/timw/parse-packet-results:
  Make result of IP::ParsePacket easier to understand
  Remove reporter warning for bad IP protocols
This commit is contained in:
Tim Wojtulewicz 2022-08-22 10:56:47 -07:00
commit 6e0e1f71db
8 changed files with 74 additions and 41 deletions

17
CHANGES
View file

@ -1,3 +1,20 @@
5.1.0-dev.424 | 2022-08-22 10:56:47 -0700
* Merge branch 'topic/timw/parse-packet-results' (Tim Wojtulewicz, Corelight)
* topic/timw/parse-packet-results:
Make result of IP::ParsePacket easier to understand
Remove reporter warning for bad IP protocols
* Make result of IP::ParsePacket easier to understand (Tim Wojtulewicz, Corelight)
* Remove reporter warning for bad IP protocols (Tim Wojtulewicz, Corelight)
It turns out that this can be *very* spammy on networks where we're receiving
lots of these packets, and can fill up the reporter log very quickly. Weirds are
already reported in all of these cases anyways, so it doesn't make sense to log
a reporter warning too.
5.1.0-dev.421 | 2022-08-19 15:23:22 -0700 5.1.0-dev.421 | 2022-08-19 15:23:22 -0700
* Remove unified2 file analyzer (Arne Welzel, Corelight) * Remove unified2 file analyzer (Arne Welzel, Corelight)

6
NEWS
View file

@ -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
----------------- -----------------

View file

@ -1 +1 @@
5.1.0-dev.421 5.1.0-dev.424

View file

@ -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;

View file

@ -283,39 +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
{ {
zeek::reporter->InternalWarning("Bad IP protocol version in IP::ParsePacket"); return ParseResult::BadProtocol;
return -1;
} }
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;
} }

View file

@ -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);
} }

View file

@ -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;
} }

View file

@ -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,22 +206,21 @@ 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 )
if ( packet->is_orig )
or_it->second.valid_orig = true;
else
or_it->second.valid_resp = true;
Confirm(or_it->second.valid_orig, or_it->second.valid_resp);
}
else
{ {
AnalyzerViolation("Truncated Teredo or invalid inner IP version", conn, (const char*)data, AnalyzerViolation("Truncated Teredo or invalid inner IP version", conn, (const char*)data,
len); len);
return false; return false;
} }
if ( packet->is_orig )
or_it->second.valid_orig = true;
else
or_it->second.valid_resp = true;
Confirm(or_it->second.valid_orig, or_it->second.valid_resp);
ValPtr teredo_hdr; ValPtr teredo_hdr;
if ( teredo_packet ) if ( teredo_packet )