Add check_subnet bif that allows exact membership test for subnet tables.

This commit also fixes a few small bugs introduced in the last patricia
tree commit.
This commit is contained in:
Johanna Amann 2016-03-09 16:52:25 -08:00
parent 7ef431808d
commit 692662abcc
4 changed files with 82 additions and 5 deletions

View file

@ -106,7 +106,7 @@ list<IPPrefix> PrefixTable::FindAll(const IPAddr& addr, int width) const
list<IPPrefix> PrefixTable::FindAll(const SubNetVal* value) const
{
return FindAll(value->AsSubNet().Prefix(), value->AsSubNet().LengthIPv6());
return FindAll(value->AsSubNet().Prefix(), value->AsSubNet().Length());
}
void* PrefixTable::Lookup(const IPAddr& addr, int width, bool exact) const
@ -132,12 +132,12 @@ void* PrefixTable::Lookup(const Val* value, bool exact) const
switch ( value->Type()->Tag() ) {
case TYPE_ADDR:
return Lookup(value->AsAddr(), 128, exact);
return Lookup(value->AsAddr(), value->AsAddr().GetFamily() == IPv4 ? 32 : 128, exact);
break;
case TYPE_SUBNET:
return Lookup(value->AsSubNet().Prefix(),
value->AsSubNet().LengthIPv6(), exact);
value->AsSubNet().Length(), exact);
break;
default:
@ -171,12 +171,12 @@ void* PrefixTable::Remove(const Val* value)
switch ( value->Type()->Tag() ) {
case TYPE_ADDR:
return Remove(value->AsAddr(), 128);
return Remove(value->AsAddr(), value->AsAddr().GetFamily() == IPv4 ? 32 : 128);
break;
case TYPE_SUBNET:
return Remove(value->AsSubNet().Prefix(),
value->AsSubNet().LengthIPv6());
value->AsSubNet().Length());
break;
default:

View file

@ -1065,6 +1065,36 @@ function matching_subnets%(search: subnet, t: any%): subnet_vec
return result_v;
%}
## Checks if a specific subnet is a member of a set/table[subnet].
## In difference to the in operator, this performs an exact match, not
## a longest prefix match
##
## search: the subnet to search for.
##
## t: the set[subnet] or table[subnet].
##
##
## Returns: True if the exact subnet is a member, false otherwise.
function check_subnet%(search: subnet, t: any%): bool
%{
if ( t->Type()->Tag() != TYPE_TABLE || ! t->Type()->AsTableType()->IsSubNetIndex() )
{
reporter->Error("matching_subnets needs to be called on a set[subnet]/table[subnet].");
return nullptr;
}
const PrefixTable* pt = t->AsTableVal()->Subnets();
if ( !pt )
{
reporter->Error("matching_subnets encountered nonexisting prefix table.");
return nullptr;
}
void* res = pt->Lookup(search, true);
return new Val (res != nullptr, TYPE_BOOL);
%}
## Checks whether two objects reference the same internal object. This function
## uses equality comparison of C++ raw pointer values to determine if the two
## objects are the same.

View file

@ -0,0 +1,8 @@
in says: 10.2.0.2/32 is member
check_subnet says: 10.2.0.2/32 is no member
in says: 10.2.0.2/31 is member
check_subnet says: 10.2.0.2/31 is member
in says: 10.0.0.0/9 is member
check_subnet says: 10.0.0.0/9 is no member
in says: 10.0.0.0/8 is member
check_subnet says: 10.0.0.0/8 is member

View file

@ -0,0 +1,39 @@
# @TEST-EXEC: bro -b %INPUT >output
# @TEST-EXEC: btest-diff output
global testt: 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
};
function check_member(s: subnet)
{
if ( s in testt )
print fmt("in says: %s is member", s);
else
print fmt("in says: %s is no member", s);
if ( check_subnet(s, testt) )
print fmt("check_subnet says: %s is member", s);
else
print fmt("check_subnet says: %s is no member", s);
}
event bro_init()
{
check_member(10.2.0.2/32);
check_member(10.2.0.2/31);
check_member(10.6.0.0/9);
check_member(10.2.0.0/8);
}