mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
Add filter_subnet_table bif
This bif works similar to the matching_subnet bif. The difference is that, instead of returning a vector of the subnets that match, we return a filtered view of the original set/table only containing the changed subnets. This commit also fixes a small bug in TableVal::UpdateTimestamp (ReadOperation only has to be called when LoggingAccess() is true).
This commit is contained in:
parent
f5ce4785ea
commit
a6cb85d86a
7 changed files with 153 additions and 23 deletions
|
@ -62,9 +62,9 @@ void* PrefixTable::Insert(const Val* value, void* data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
list<IPPrefix> PrefixTable::FindAll(const IPAddr& addr, int width) const
|
list<tuple<IPPrefix,void*>> PrefixTable::FindAll(const IPAddr& addr, int width) const
|
||||||
{
|
{
|
||||||
std::list<IPPrefix> out;
|
std::list<tuple<IPPrefix,void*>> out;
|
||||||
prefix_t* prefix = MakePrefix(addr, width);
|
prefix_t* prefix = MakePrefix(addr, width);
|
||||||
|
|
||||||
int elems = 0;
|
int elems = 0;
|
||||||
|
@ -73,14 +73,14 @@ list<IPPrefix> PrefixTable::FindAll(const IPAddr& addr, int width) const
|
||||||
patricia_search_all(tree, prefix, &list, &elems);
|
patricia_search_all(tree, prefix, &list, &elems);
|
||||||
|
|
||||||
for ( int i = 0; i < elems; ++i )
|
for ( int i = 0; i < elems; ++i )
|
||||||
out.push_back(PrefixToIPPrefix(list[i]->prefix));
|
out.push_back(std::make_tuple(PrefixToIPPrefix(list[i]->prefix), list[i]->data));
|
||||||
|
|
||||||
Deref_Prefix(prefix);
|
Deref_Prefix(prefix);
|
||||||
free(list);
|
free(list);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
list<IPPrefix> PrefixTable::FindAll(const SubNetVal* value) const
|
list<tuple<IPPrefix,void*>> PrefixTable::FindAll(const SubNetVal* value) const
|
||||||
{
|
{
|
||||||
return FindAll(value->AsSubNet().Prefix(), value->AsSubNet().LengthIPv6());
|
return FindAll(value->AsSubNet().Prefix(), value->AsSubNet().LengthIPv6());
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,8 +37,8 @@ public:
|
||||||
void* Lookup(const Val* value, bool exact = false) const;
|
void* Lookup(const Val* value, bool exact = false) const;
|
||||||
|
|
||||||
// Returns list of all found matches or empty list otherwise.
|
// Returns list of all found matches or empty list otherwise.
|
||||||
list<IPPrefix> FindAll(const IPAddr& addr, int width) const;
|
list<tuple<IPPrefix,void*>> FindAll(const IPAddr& addr, int width) const;
|
||||||
list<IPPrefix> FindAll(const SubNetVal* value) const;
|
list<tuple<IPPrefix,void*>> FindAll(const SubNetVal* value) const;
|
||||||
|
|
||||||
// Returns pointer to data or nil if not found.
|
// Returns pointer to data or nil if not found.
|
||||||
void* Remove(const IPAddr& addr, int width);
|
void* Remove(const IPAddr& addr, int width);
|
||||||
|
|
50
src/Val.cc
50
src/Val.cc
|
@ -1833,6 +1833,54 @@ Val* TableVal::Lookup(Val* index, bool use_default_val)
|
||||||
return def;
|
return def;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VectorVal* TableVal::LookupSubnets(const SubNetVal* search)
|
||||||
|
{
|
||||||
|
if ( ! subnets )
|
||||||
|
reporter->InternalError("LookupSubnets called on wrong table type");
|
||||||
|
|
||||||
|
VectorVal* result = new VectorVal(internal_type("subnet_vec")->AsVectorType());
|
||||||
|
|
||||||
|
auto matches = subnets->FindAll(search);
|
||||||
|
for ( auto element : matches )
|
||||||
|
{
|
||||||
|
SubNetVal* s = new SubNetVal(get<0>(element));
|
||||||
|
result->Assign(result->Size(), s);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
TableVal* TableVal::LookupSubnetValues(const SubNetVal* search)
|
||||||
|
{
|
||||||
|
if ( ! subnets )
|
||||||
|
reporter->InternalError("LookupSubnetValues called on wrong table type");
|
||||||
|
|
||||||
|
TableVal* nt = new TableVal(this->Type()->Ref()->AsTableType());
|
||||||
|
|
||||||
|
auto matches = subnets->FindAll(search);
|
||||||
|
for ( auto element : matches )
|
||||||
|
{
|
||||||
|
SubNetVal* s = new SubNetVal(get<0>(element));
|
||||||
|
TableEntryVal* entry = reinterpret_cast<TableEntryVal*>(get<1>(element));
|
||||||
|
|
||||||
|
if ( entry && entry->Value() )
|
||||||
|
nt->Assign(s, entry->Value()->Ref());
|
||||||
|
else
|
||||||
|
nt->Assign(s, 0); // set
|
||||||
|
|
||||||
|
if ( entry )
|
||||||
|
{
|
||||||
|
entry->SetExpireAccess(network_time);
|
||||||
|
if ( LoggingAccess() && attrs->FindAttr(ATTR_EXPIRE_READ) )
|
||||||
|
ReadOperation(s, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
Unref(s); // assign does not consume index
|
||||||
|
}
|
||||||
|
|
||||||
|
return nt;
|
||||||
|
}
|
||||||
|
|
||||||
bool TableVal::UpdateTimestamp(Val* index)
|
bool TableVal::UpdateTimestamp(Val* index)
|
||||||
{
|
{
|
||||||
TableEntryVal* v;
|
TableEntryVal* v;
|
||||||
|
@ -1854,7 +1902,7 @@ bool TableVal::UpdateTimestamp(Val* index)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
v->SetExpireAccess(network_time);
|
v->SetExpireAccess(network_time);
|
||||||
if ( attrs->FindAttr(ATTR_EXPIRE_READ) )
|
if ( LoggingAccess() && attrs->FindAttr(ATTR_EXPIRE_READ) )
|
||||||
ReadOperation(index, v);
|
ReadOperation(index, v);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
10
src/Val.h
10
src/Val.h
|
@ -790,6 +790,16 @@ public:
|
||||||
// need to Ref/Unref it when calling the default function.
|
// need to Ref/Unref it when calling the default function.
|
||||||
Val* Lookup(Val* index, bool use_default_val = true);
|
Val* Lookup(Val* index, bool use_default_val = true);
|
||||||
|
|
||||||
|
// For a table[subnet]/set[subnet], return all subnets that cover
|
||||||
|
// the given subnet.
|
||||||
|
// Causes an internal error if called for any other kind of table.
|
||||||
|
VectorVal* LookupSubnets(const SubNetVal* s);
|
||||||
|
|
||||||
|
// For a set[subnet]/table[subnet], return a new table that only contains
|
||||||
|
// entries that cover the given subnet.
|
||||||
|
// Causes an internal error if called for any other kind of table.
|
||||||
|
TableVal* LookupSubnetValues(const SubNetVal* s);
|
||||||
|
|
||||||
// Sets the timestamp for the given index to network time.
|
// Sets the timestamp for the given index to network time.
|
||||||
// Returns false if index does not exist.
|
// Returns false if index does not exist.
|
||||||
bool UpdateTimestamp(Val* index);
|
bool UpdateTimestamp(Val* index);
|
||||||
|
|
35
src/bro.bif
35
src/bro.bif
|
@ -1031,7 +1031,7 @@ function clear_table%(v: any%): any
|
||||||
return 0;
|
return 0;
|
||||||
%}
|
%}
|
||||||
|
|
||||||
## Gets all subnets that match a given subnet from a set/table[subnet]
|
## Gets all subnets that contain a given subnet from a set/table[subnet]
|
||||||
##
|
##
|
||||||
## search: the subnet to search for.
|
## search: the subnet to search for.
|
||||||
##
|
##
|
||||||
|
@ -1046,23 +1046,26 @@ function matching_subnets%(search: subnet, t: any%): subnet_vec
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PrefixTable* pt = t->AsTableVal()->Subnets();
|
return t->AsTableVal()->LookupSubnets(search);
|
||||||
if ( ! pt )
|
%}
|
||||||
|
|
||||||
|
## For a set[subnet]/table[subnet], create a new table that contains all entries that
|
||||||
|
## contain a given subnet.
|
||||||
|
##
|
||||||
|
## search: the subnet to search for.
|
||||||
|
##
|
||||||
|
## t: the set[subnet] or table[subnet].
|
||||||
|
##
|
||||||
|
## Returns: A new table that contains all the entries that cover the subnet searched for.
|
||||||
|
function filter_subnet_table%(search: subnet, t: any%): any
|
||||||
|
%{
|
||||||
|
if ( t->Type()->Tag() != TYPE_TABLE || ! t->Type()->AsTableType()->IsSubNetIndex() )
|
||||||
{
|
{
|
||||||
reporter->Error("matching_subnets encountered nonexisting prefix table.");
|
reporter->Error("filter_subnet_table needs to be called on a set[subnet]/table[subnet].");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
VectorVal* result_v = new VectorVal(internal_type("subnet_vec")->AsVectorType());
|
return t->AsTableVal()->LookupSubnetValues(search);
|
||||||
|
|
||||||
auto matches = pt->FindAll(search);
|
|
||||||
for ( auto element : matches )
|
|
||||||
{
|
|
||||||
SubNetVal* s = new SubNetVal(element);
|
|
||||||
result_v->Assign(result_v->Size(), s);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result_v;
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
## Checks if a specific subnet is a member of a set/table[subnet].
|
## Checks if a specific subnet is a member of a set/table[subnet].
|
||||||
|
@ -1078,14 +1081,14 @@ function check_subnet%(search: subnet, t: any%): bool
|
||||||
%{
|
%{
|
||||||
if ( t->Type()->Tag() != TYPE_TABLE || ! t->Type()->AsTableType()->IsSubNetIndex() )
|
if ( t->Type()->Tag() != TYPE_TABLE || ! t->Type()->AsTableType()->IsSubNetIndex() )
|
||||||
{
|
{
|
||||||
reporter->Error("matching_subnets needs to be called on a set[subnet]/table[subnet].");
|
reporter->Error("check_subnet needs to be called on a set[subnet]/table[subnet].");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PrefixTable* pt = t->AsTableVal()->Subnets();
|
const PrefixTable* pt = t->AsTableVal()->Subnets();
|
||||||
if ( ! pt )
|
if ( ! pt )
|
||||||
{
|
{
|
||||||
reporter->Error("matching_subnets encountered nonexisting prefix table.");
|
reporter->Error("check_subnet encountered nonexisting prefix table.");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
20
testing/btest/Baseline/bifs.filter_subnet_table/output
Normal file
20
testing/btest/Baseline/bifs.filter_subnet_table/output
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
10.0.0.0/8,
|
||||||
|
10.2.0.2/31,
|
||||||
|
10.2.0.0/16
|
||||||
|
}
|
||||||
|
{
|
||||||
|
[10.0.0.0/8] = a,
|
||||||
|
[10.2.0.2/31] = c,
|
||||||
|
[10.2.0.0/16] = b
|
||||||
|
}
|
||||||
|
{
|
||||||
|
[10.0.0.0/8] = a,
|
||||||
|
[10.3.0.0/16] = e
|
||||||
|
}
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
49
testing/btest/bifs/filter_subnet_table.bro
Normal file
49
testing/btest/bifs/filter_subnet_table.bro
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
# @TEST-EXEC: bro -b %INPUT >output
|
||||||
|
# @TEST-EXEC: btest-diff output
|
||||||
|
|
||||||
|
global testa: set[subnet] = {
|
||||||
|
10.0.0.0/8,
|
||||||
|
10.2.0.0/16,
|
||||||
|
10.2.0.2/31,
|
||||||
|
10.1.0.0/16,
|
||||||
|
10.3.0.0/16,
|
||||||
|
5.0.0.0/8,
|
||||||
|
5.5.0.0/25,
|
||||||
|
5.2.0.0/32,
|
||||||
|
7.2.0.0/32,
|
||||||
|
[2607:f8b0:4008:807::200e]/64,
|
||||||
|
[2607:f8b0:4007:807::200e]/64,
|
||||||
|
[2607:f8b0:4007:807::200e]/128
|
||||||
|
};
|
||||||
|
|
||||||
|
global testb: table[subnet] of string = {
|
||||||
|
[10.0.0.0/8] = "a",
|
||||||
|
[10.2.0.0/16] = "b",
|
||||||
|
[10.2.0.2/31] = "c",
|
||||||
|
[10.1.0.0/16] = "d",
|
||||||
|
[10.3.0.0/16] = "e",
|
||||||
|
[5.0.0.0/8] = "f",
|
||||||
|
[5.5.0.0/25] = "g",
|
||||||
|
[5.2.0.0/32] = "h",
|
||||||
|
[7.2.0.0/32] = "i",
|
||||||
|
[[2607:f8b0:4008:807::200e]/64] = "j",
|
||||||
|
[[2607:f8b0:4007:807::200e]/64] = "k",
|
||||||
|
[[2607:f8b0:4007:807::200e]/128] = "l"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
event bro_init()
|
||||||
|
{
|
||||||
|
local c = filter_subnet_table(10.2.0.2/32, testa);
|
||||||
|
print c;
|
||||||
|
c = filter_subnet_table(10.2.0.2/32, testb);
|
||||||
|
print c;
|
||||||
|
c = filter_subnet_table(10.3.0.2/32, testb);
|
||||||
|
print c;
|
||||||
|
c = filter_subnet_table(1.0.0.0/8, testb);
|
||||||
|
print c;
|
||||||
|
|
||||||
|
local unspecified: table[subnet] of string = table();
|
||||||
|
c = filter_subnet_table(10.2.0.2/32, unspecified);
|
||||||
|
print c;
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue