mirror of
https://github.com/zeek/zeek.git
synced 2025-10-07 17:18:20 +00:00
Add IPv6 support to signature header conditions.
- "src-ip" and "dst-ip" conditions can now use IPv6 addresses/subnets. They must be written in colon-hexadecimal representation and enclosed in square brackets (e.g. [fe80::1]). Addresses #774. - "icmp6" is now a valid protocol for use with "ip-proto" and "header" conditions. This allows signatures to be written that can match against ICMPv6 payloads. Addresses #880. - "ip6" is now a valid protocol for use with the "header" condition. (also the "ip-proto" condition, but it results in a no-op in that case since signatures apply only to the inner-most IP packet when packets are tunneled). This allows signatures to match specifically against IPv6 packets (whereas "ip" only matches against IPv4 packets). - "ip-proto" conditions can now match against IPv6 packets. Before, IPv6 packets were just silently ignored which meant DPD based on signatures did not function for IPv6 -- protocol analyzers would only get attached to a connection over IPv6 based on the well-known ports set in the "dpd_config" table.
This commit is contained in:
parent
2915e04db4
commit
e835a55229
132 changed files with 1731 additions and 124 deletions
|
@ -1,4 +1,5 @@
|
|||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
|
@ -41,6 +42,23 @@ RuleHdrTest::RuleHdrTest(Prot arg_prot, uint32 arg_offset, uint32 arg_size,
|
|||
level = 0;
|
||||
}
|
||||
|
||||
RuleHdrTest::RuleHdrTest(Prot arg_prot, Comp arg_comp, vector<IPPrefix> arg_v)
|
||||
{
|
||||
prot = arg_prot;
|
||||
offset = 0;
|
||||
size = 0;
|
||||
comp = arg_comp;
|
||||
vals = new maskedvalue_list;
|
||||
prefix_vals = arg_v;
|
||||
sibling = 0;
|
||||
child = 0;
|
||||
pattern_rules = 0;
|
||||
pure_rules = 0;
|
||||
ruleset = new IntSet;
|
||||
id = ++idcounter;
|
||||
level = 0;
|
||||
}
|
||||
|
||||
Val* RuleMatcher::BuildRuleStateValue(const Rule* rule,
|
||||
const RuleEndpointState* state) const
|
||||
{
|
||||
|
@ -63,6 +81,8 @@ RuleHdrTest::RuleHdrTest(RuleHdrTest& h)
|
|||
loop_over_list(*h.vals, i)
|
||||
vals->append(new MaskedValue(*(*h.vals)[i]));
|
||||
|
||||
prefix_vals = h.prefix_vals;
|
||||
|
||||
for ( int j = 0; j < Rule::TYPES; ++j )
|
||||
{
|
||||
loop_over_list(h.psets[j], k)
|
||||
|
@ -114,6 +134,10 @@ bool RuleHdrTest::operator==(const RuleHdrTest& h)
|
|||
(*vals)[i]->mask != (*h.vals)[i]->mask )
|
||||
return false;
|
||||
|
||||
for ( size_t i = 0; i < prefix_vals.size(); ++i )
|
||||
if ( ! (prefix_vals[i] == h.prefix_vals[i]) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -129,6 +153,9 @@ void RuleHdrTest::PrintDebug()
|
|||
fprintf(stderr, " 0x%08x/0x%08x",
|
||||
(*vals)[i]->val, (*vals)[i]->mask);
|
||||
|
||||
for ( size_t i = 0; i < prefix_vals.size(); ++i )
|
||||
fprintf(stderr, " %s", prefix_vals[i].AsString().c_str());
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
|
@ -410,29 +437,129 @@ static inline uint32 getval(const u_char* data, int size)
|
|||
}
|
||||
|
||||
|
||||
// A line which can be inserted into the macros below for debugging
|
||||
// fprintf(stderr, "%.06f %08x & %08x %s %08x\n", network_time, v, (mvals)[i]->mask, #op, (mvals)[i]->val);
|
||||
|
||||
// Evaluate a value list (matches if at least one value matches).
|
||||
#define DO_MATCH_OR( mvals, v, op ) \
|
||||
{ \
|
||||
loop_over_list((mvals), i) \
|
||||
{ \
|
||||
if ( ((v) & (mvals)[i]->mask) op (mvals)[i]->val ) \
|
||||
goto match; \
|
||||
} \
|
||||
goto no_match; \
|
||||
template <typename FuncT>
|
||||
static inline bool match_or(const maskedvalue_list& mvals, uint32 v, FuncT comp)
|
||||
{
|
||||
loop_over_list(mvals, i)
|
||||
{
|
||||
if ( comp(v & mvals[i]->mask, mvals[i]->val) )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Evaluate a prefix list (matches if at least one value matches).
|
||||
template <typename FuncT>
|
||||
static inline bool match_or(const vector<IPPrefix>& prefixes, const IPAddr& a,
|
||||
FuncT comp)
|
||||
{
|
||||
for ( size_t i = 0; i < prefixes.size(); ++i )
|
||||
{
|
||||
IPAddr masked(a);
|
||||
masked.Mask(prefixes[i].LengthIPv6());
|
||||
if ( comp(masked, prefixes[i].Prefix()) )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Evaluate a value list (doesn't match if any value matches).
|
||||
#define DO_MATCH_NOT_AND( mvals, v, op ) \
|
||||
{ \
|
||||
loop_over_list((mvals), i) \
|
||||
{ \
|
||||
if ( ((v) & (mvals)[i]->mask) op (mvals)[i]->val ) \
|
||||
goto no_match; \
|
||||
} \
|
||||
goto match; \
|
||||
template <typename FuncT>
|
||||
static inline bool match_not_and(const maskedvalue_list& mvals, uint32 v,
|
||||
FuncT comp)
|
||||
{
|
||||
loop_over_list(mvals, i)
|
||||
{
|
||||
if ( comp(v & mvals[i]->mask, mvals[i]->val) )
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Evaluate a prefix list (doesn't match if any value matches).
|
||||
template <typename FuncT>
|
||||
static inline bool match_not_and(const vector<IPPrefix>& prefixes,
|
||||
const IPAddr& a, FuncT comp)
|
||||
{
|
||||
for ( size_t i = 0; i < prefixes.size(); ++i )
|
||||
{
|
||||
IPAddr masked(a);
|
||||
masked.Mask(prefixes[i].LengthIPv6());
|
||||
if ( comp(masked, prefixes[i].Prefix()) )
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool compare(const maskedvalue_list& mvals, uint32 v,
|
||||
RuleHdrTest::Comp comp)
|
||||
{
|
||||
switch ( comp ) {
|
||||
case RuleHdrTest::EQ:
|
||||
return match_or(mvals, v, std::equal_to<uint32>());
|
||||
break;
|
||||
|
||||
case RuleHdrTest::NE:
|
||||
return match_not_and(mvals, v, std::equal_to<uint32>());
|
||||
break;
|
||||
|
||||
case RuleHdrTest::LT:
|
||||
return match_or(mvals, v, std::less<uint32>());
|
||||
break;
|
||||
|
||||
case RuleHdrTest::GT:
|
||||
return match_or(mvals, v, std::greater<uint32>());
|
||||
break;
|
||||
|
||||
case RuleHdrTest::LE:
|
||||
return match_or(mvals, v, std::less_equal<uint32>());
|
||||
break;
|
||||
|
||||
case RuleHdrTest::GE:
|
||||
return match_or(mvals, v, std::greater_equal<uint32>());
|
||||
break;
|
||||
|
||||
default:
|
||||
reporter->InternalError("unknown comparison type");
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool compare(const vector<IPPrefix>& prefixes, const IPAddr& a,
|
||||
RuleHdrTest::Comp comp)
|
||||
{
|
||||
switch ( comp ) {
|
||||
case RuleHdrTest::EQ:
|
||||
return match_or(prefixes, a, std::equal_to<IPAddr>());
|
||||
break;
|
||||
|
||||
case RuleHdrTest::NE:
|
||||
return match_not_and(prefixes, a, std::equal_to<IPAddr>());
|
||||
break;
|
||||
|
||||
case RuleHdrTest::LT:
|
||||
return match_or(prefixes, a, std::less<IPAddr>());
|
||||
break;
|
||||
|
||||
case RuleHdrTest::GT:
|
||||
return match_or(prefixes, a, std::greater<IPAddr>());
|
||||
break;
|
||||
|
||||
case RuleHdrTest::LE:
|
||||
return match_or(prefixes, a, std::less_equal<IPAddr>());
|
||||
break;
|
||||
|
||||
case RuleHdrTest::GE:
|
||||
return match_or(prefixes, a, std::greater_equal<IPAddr>());
|
||||
break;
|
||||
|
||||
default:
|
||||
reporter->InternalError("unknown comparison type");
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
RuleEndpointState* RuleMatcher::InitEndpoint(Analyzer* analyzer,
|
||||
|
@ -492,66 +619,52 @@ RuleEndpointState* RuleMatcher::InitEndpoint(Analyzer* analyzer,
|
|||
|
||||
if ( ip )
|
||||
{
|
||||
// Get start of transport layer.
|
||||
const u_char* transport = ip->Payload();
|
||||
|
||||
// Descend the RuleHdrTest tree further.
|
||||
for ( RuleHdrTest* h = hdr_test->child; h;
|
||||
h = h->sibling )
|
||||
{
|
||||
const u_char* data;
|
||||
bool match = false;
|
||||
|
||||
// Evaluate the header test.
|
||||
switch ( h->prot ) {
|
||||
case RuleHdrTest::NEXT:
|
||||
match = compare(*h->vals, ip->NextProto(), h->comp);
|
||||
break;
|
||||
|
||||
case RuleHdrTest::IP:
|
||||
data = (const u_char*) ip->IP4_Hdr();
|
||||
if ( ! ip->IP4_Hdr() )
|
||||
continue;
|
||||
match = compare(*h->vals, getval((const u_char*)ip->IP4_Hdr() + h->offset, h->size), h->comp);
|
||||
break;
|
||||
|
||||
case RuleHdrTest::IPv6:
|
||||
if ( ! ip->IP6_Hdr() )
|
||||
continue;
|
||||
match = compare(*h->vals, getval((const u_char*)ip->IP6_Hdr() + h->offset, h->size), h->comp);
|
||||
break;
|
||||
|
||||
case RuleHdrTest::ICMP:
|
||||
case RuleHdrTest::ICMPv6:
|
||||
case RuleHdrTest::TCP:
|
||||
case RuleHdrTest::UDP:
|
||||
data = transport;
|
||||
match = compare(*h->vals, getval(ip->Payload() + h->offset, h->size), h->comp);
|
||||
break;
|
||||
|
||||
case RuleHdrTest::IPSrc:
|
||||
match = compare(h->prefix_vals, ip->IPHeaderSrcAddr(), h->comp);
|
||||
break;
|
||||
|
||||
case RuleHdrTest::IPDst:
|
||||
match = compare(h->prefix_vals, ip->IPHeaderDstAddr(), h->comp);
|
||||
break;
|
||||
|
||||
default:
|
||||
data = 0;
|
||||
reporter->InternalError("unknown protocol");
|
||||
break;
|
||||
}
|
||||
|
||||
// ### data can be nil here if it's an
|
||||
// IPv6 packet and we're doing an IP test.
|
||||
if ( ! data )
|
||||
continue;
|
||||
|
||||
// Sorry for the hidden gotos :-)
|
||||
switch ( h->comp ) {
|
||||
case RuleHdrTest::EQ:
|
||||
DO_MATCH_OR(*h->vals, getval(data + h->offset, h->size), ==);
|
||||
|
||||
case RuleHdrTest::NE:
|
||||
DO_MATCH_NOT_AND(*h->vals, getval(data + h->offset, h->size), ==);
|
||||
|
||||
case RuleHdrTest::LT:
|
||||
DO_MATCH_OR(*h->vals, getval(data + h->offset, h->size), <);
|
||||
|
||||
case RuleHdrTest::GT:
|
||||
DO_MATCH_OR(*h->vals, getval(data + h->offset, h->size), >);
|
||||
|
||||
case RuleHdrTest::LE:
|
||||
DO_MATCH_OR(*h->vals, getval(data + h->offset, h->size), <=);
|
||||
|
||||
case RuleHdrTest::GE:
|
||||
DO_MATCH_OR(*h->vals, getval(data + h->offset, h->size), >=);
|
||||
|
||||
default:
|
||||
reporter->InternalError("unknown comparision type");
|
||||
}
|
||||
|
||||
no_match:
|
||||
continue;
|
||||
|
||||
match:
|
||||
tests.append(h);
|
||||
if ( match )
|
||||
tests.append(h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1050,8 +1163,11 @@ static Val* get_bro_val(const char* label)
|
|||
}
|
||||
|
||||
|
||||
// Converts an atomic Val and appends it to the list
|
||||
static bool val_to_maskedval(Val* v, maskedvalue_list* append_to)
|
||||
// Converts an atomic Val and appends it to the list. For subnet types,
|
||||
// if the prefix_vector param isn't null, appending to that is preferred
|
||||
// over appending to the masked val list.
|
||||
static bool val_to_maskedval(Val* v, maskedvalue_list* append_to,
|
||||
vector<IPPrefix>* prefix_vector)
|
||||
{
|
||||
MaskedValue* mval = new MaskedValue;
|
||||
|
||||
|
@ -1071,29 +1187,37 @@ static bool val_to_maskedval(Val* v, maskedvalue_list* append_to)
|
|||
|
||||
case TYPE_SUBNET:
|
||||
{
|
||||
const uint32* n;
|
||||
uint32 m[4];
|
||||
v->AsSubNet().Prefix().GetBytes(&n);
|
||||
v->AsSubNetVal()->Mask().CopyIPv6(m);
|
||||
|
||||
for ( unsigned int i = 0; i < 4; ++i )
|
||||
m[i] = ntohl(m[i]);
|
||||
|
||||
bool is_v4_mask = m[0] == 0xffffffff &&
|
||||
m[1] == m[0] && m[2] == m[0];
|
||||
|
||||
if ( v->AsSubNet().Prefix().GetFamily() == IPv4 &&
|
||||
is_v4_mask )
|
||||
if ( prefix_vector )
|
||||
{
|
||||
mval->val = ntohl(*n);
|
||||
mval->mask = m[3];
|
||||
prefix_vector->push_back(v->AsSubNet());
|
||||
delete mval;
|
||||
return true;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
rules_error("IPv6 subnets not supported");
|
||||
mval->val = 0;
|
||||
mval->mask = 0;
|
||||
const uint32* n;
|
||||
uint32 m[4];
|
||||
v->AsSubNet().Prefix().GetBytes(&n);
|
||||
v->AsSubNetVal()->Mask().CopyIPv6(m);
|
||||
|
||||
for ( unsigned int i = 0; i < 4; ++i )
|
||||
m[i] = ntohl(m[i]);
|
||||
|
||||
bool is_v4_mask = m[0] == 0xffffffff &&
|
||||
m[1] == m[0] && m[2] == m[0];
|
||||
|
||||
|
||||
if ( v->AsSubNet().Prefix().GetFamily() == IPv4 && is_v4_mask )
|
||||
{
|
||||
mval->val = ntohl(*n);
|
||||
mval->mask = m[3];
|
||||
}
|
||||
else
|
||||
{
|
||||
rules_error("IPv6 subnets not supported");
|
||||
mval->val = 0;
|
||||
mval->mask = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1108,7 +1232,8 @@ static bool val_to_maskedval(Val* v, maskedvalue_list* append_to)
|
|||
return true;
|
||||
}
|
||||
|
||||
void id_to_maskedvallist(const char* id, maskedvalue_list* append_to)
|
||||
void id_to_maskedvallist(const char* id, maskedvalue_list* append_to,
|
||||
vector<IPPrefix>* prefix_vector)
|
||||
{
|
||||
Val* v = get_bro_val(id);
|
||||
if ( ! v )
|
||||
|
@ -1118,7 +1243,7 @@ void id_to_maskedvallist(const char* id, maskedvalue_list* append_to)
|
|||
{
|
||||
val_list* vals = v->AsTableVal()->ConvertToPureList()->Vals();
|
||||
loop_over_list(*vals, i )
|
||||
if ( ! val_to_maskedval((*vals)[i], append_to) )
|
||||
if ( ! val_to_maskedval((*vals)[i], append_to, prefix_vector) )
|
||||
{
|
||||
delete_vals(vals);
|
||||
return;
|
||||
|
@ -1128,7 +1253,7 @@ void id_to_maskedvallist(const char* id, maskedvalue_list* append_to)
|
|||
}
|
||||
|
||||
else
|
||||
val_to_maskedval(v, append_to);
|
||||
val_to_maskedval(v, append_to, prefix_vector);
|
||||
}
|
||||
|
||||
char* id_to_str(const char* id)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue