Add rule hooks to the acld plugin.

The hook name is NetControl::acld_rule_policy and allows the
modification of acld rules before they are sent out to the network.

This allows, e.g. network policies to use nullzero instead of drop in
certain circumstances.
This commit is contained in:
Johanna Amann 2016-03-08 11:25:15 -08:00
parent 69b62be5d4
commit d9459fc59a
5 changed files with 193 additions and 8 deletions

View file

@ -21,8 +21,19 @@ export {
acld_host: addr; acld_host: addr;
## Broker port to connect to ## Broker port to connect to
acld_port: port; acld_port: port;
## Function that can decide weather to accept add request ## Do we accept rules for the monitor path? Default false
add_pred: function(p: PluginState, r: Rule, ar: AclRule): bool &optional; monitor: bool &default=F;
## Do we accept rules for the forward path? Default true
forward: bool &default=T;
## Predicate that is called on rule insertion or removal.
##
## p: Current plugin state
##
## r: The rule to be inserted or removed
##
## Returns: T if the rule can be handled by the current backend, F otherwhise
check_pred: function(p: PluginState, r: Rule): bool &optional;
}; };
## Instantiates the acld plugin. ## Instantiates the acld plugin.
@ -34,9 +45,23 @@ export {
acld_id: count &optional; acld_id: count &optional;
}; };
## Hook that is called after a rule is converted to an acld rule.
## The hook may modify the rule before it is sent to acld.
## Setting the acld command to F will cause the rule to be rejected
## by the plugin
##
## p: Current plugin state
##
## r: The rule to be inserted or removed
##
## ar: The acld rule to be inserted or removed
global NetControl::acld_rule_policy: hook(p: PluginState, r: Rule, ar: AclRule);
## Events that are sent from us to Broker
global acld_add_rule: event(id: count, r: Rule, ar: AclRule); global acld_add_rule: event(id: count, r: Rule, ar: AclRule);
global acld_remove_rule: event(id: count, r: Rule, ar: AclRule); global acld_remove_rule: event(id: count, r: Rule, ar: AclRule);
## Events that are sent from Broker to us
global acld_rule_added: event(id: count, r: Rule, msg: string); global acld_rule_added: event(id: count, r: Rule, msg: string);
global acld_rule_removed: event(id: count, r: Rule, msg: string); global acld_rule_removed: event(id: count, r: Rule, msg: string);
global acld_rule_error: event(id: count, r: Rule, msg: string); global acld_rule_error: event(id: count, r: Rule, msg: string);
@ -115,7 +140,7 @@ function check_sn(sn: subnet) : bool
return F; return F;
} }
function rule_to_acl_rule(r: Rule) : AclRule function rule_to_acl_rule(p: PluginState, r: Rule) : AclRule
{ {
local e = r$entity; local e = r$entity;
@ -169,17 +194,35 @@ function rule_to_acl_rule(r: Rule) : AclRule
local ar = AclRule($command=command, $cookie=r$cid, $arg=arg); local ar = AclRule($command=command, $cookie=r$cid, $arg=arg);
if ( r?$location ) if ( r?$location )
ar$comment = r$location; ar$comment = r$location;
hook NetControl::acld_rule_policy(p, r, ar);
return ar; return ar;
} }
function acld_check_rule(p: PluginState, r: Rule) : bool
{
local c = p$acld_config;
if ( p$acld_config?$check_pred )
return p$acld_config$check_pred(p, r);
if ( r$target == MONITOR && c$monitor )
return T;
if ( r$target == FORWARD && c$forward )
return T;
return F;
}
function acld_add_rule_fun(p: PluginState, r: Rule) : bool function acld_add_rule_fun(p: PluginState, r: Rule) : bool
{ {
local ar = rule_to_acl_rule(r); if ( ! acld_check_rule(p, r) )
if ( p$acld_config?$add_pred )
if ( ! p$acld_config$add_pred(p, r, ar) )
return F; return F;
local ar = rule_to_acl_rule(p, r);
if ( ar$command == "" ) if ( ar$command == "" )
return F; return F;
@ -189,7 +232,10 @@ function acld_add_rule_fun(p: PluginState, r: Rule) : bool
function acld_remove_rule_fun(p: PluginState, r: Rule) : bool function acld_remove_rule_fun(p: PluginState, r: Rule) : bool
{ {
local ar = rule_to_acl_rule(r); if ( ! acld_check_rule(p, r) )
return F;
local ar = rule_to_acl_rule(p, r);
if ( ar$command in acld_add_to_remove ) if ( ar$command in acld_add_to_remove )
ar$command = acld_add_to_remove[ar$command]; ar$command = acld_add_to_remove[ar$command];
else else

View file

@ -12,6 +12,13 @@ export {
table_id: count &optional; table_id: count &optional;
priority_offset: int &default=+0; ##< add this to all rule priorities. Can be useful if you want the openflow priorities be offset from the netcontrol priorities without having to write a filter function. priority_offset: int &default=+0; ##< add this to all rule priorities. Can be useful if you want the openflow priorities be offset from the netcontrol priorities without having to write a filter function.
## Predicate that is called on rule insertion or removal.
##
## p: Current plugin state
##
## r: The rule to be inserted or removed
##
## Returns: T if the rule can be handled by the current backend, F otherwhise
check_pred: function(p: PluginState, r: Rule): bool &optional; check_pred: function(p: PluginState, r: Rule): bool &optional;
match_pred: function(p: PluginState, e: Entity, m: vector of OpenFlow::ofp_match): vector of OpenFlow::ofp_match &optional; match_pred: function(p: PluginState, e: Entity, m: vector of OpenFlow::ofp_match): vector of OpenFlow::ofp_match &optional;
flow_mod_pred: function(p: PluginState, r: Rule, m: OpenFlow::ofp_flow_mod): OpenFlow::ofp_flow_mod &optional; flow_mod_pred: function(p: PluginState, r: Rule, m: OpenFlow::ofp_flow_mod): OpenFlow::ofp_flow_mod &optional;

View file

@ -0,0 +1,7 @@
BrokerComm::incoming_connection_established
add_rule, 0, [ty=NetControl::DROP, target=NetControl::FORWARD, entity=[ty=NetControl::FLOW, conn=<uninitialized>, flow=[src_h=192.168.18.50/32, src_p=<uninitialized>, dst_h=74.125.239.97/32, dst_p=<uninitialized>, src_m=<uninitialized>, dst_m=<uninitialized>], ip=<uninitialized>, mac=<uninitialized>], expire=36000.0, priority=0, location=here, out_port=<uninitialized>, mod=<uninitialized>, id=2, cid=2, _plugin_id=1], [command=blockhosthost, cookie=2, arg=192.168.18.50 74.125.239.97, comment=here]
add_rule, 0, [ty=NetControl::DROP, target=NetControl::FORWARD, entity=[ty=NetControl::FLOW, conn=<uninitialized>, flow=[src_h=<uninitialized>, src_p=<uninitialized>, dst_h=<uninitialized>, dst_p=443/tcp, src_m=<uninitialized>, dst_m=<uninitialized>], ip=<uninitialized>, mac=<uninitialized>], expire=36000.0, priority=0, location=there, out_port=<uninitialized>, mod=<uninitialized>, id=3, cid=3, _plugin_id=1], [command=droptcpport, cookie=3, arg=443, comment=there]
add_rule, 0, [ty=NetControl::DROP, target=NetControl::FORWARD, entity=[ty=NetControl::ADDRESS, conn=<uninitialized>, flow=<uninitialized>, ip=192.168.18.50/32, mac=<uninitialized>], expire=36000.0, priority=0, location=, out_port=<uninitialized>, mod=<uninitialized>, id=4, cid=4, _plugin_id=1], [command=nullzero, cookie=4, arg=192.168.18.50/32, comment=]
remove_rule, 0, [ty=NetControl::DROP, target=NetControl::FORWARD, entity=[ty=NetControl::FLOW, conn=<uninitialized>, flow=[src_h=192.168.18.50/32, src_p=<uninitialized>, dst_h=74.125.239.97/32, dst_p=<uninitialized>, src_m=<uninitialized>, dst_m=<uninitialized>], ip=<uninitialized>, mac=<uninitialized>], expire=36000.0, priority=0, location=here, out_port=<uninitialized>, mod=<uninitialized>, id=2, cid=2, _plugin_id=1], [command=restorehosthost, cookie=2, arg=192.168.18.50 74.125.239.97, comment=here]
remove_rule, 0, [ty=NetControl::DROP, target=NetControl::FORWARD, entity=[ty=NetControl::FLOW, conn=<uninitialized>, flow=[src_h=<uninitialized>, src_p=<uninitialized>, dst_h=<uninitialized>, dst_p=443/tcp, src_m=<uninitialized>, dst_m=<uninitialized>], ip=<uninitialized>, mac=<uninitialized>], expire=36000.0, priority=0, location=there, out_port=<uninitialized>, mod=<uninitialized>, id=3, cid=3, _plugin_id=1], [command=restoretcpport, cookie=3, arg=443, comment=there]
remove_rule, 0, [ty=NetControl::DROP, target=NetControl::FORWARD, entity=[ty=NetControl::ADDRESS, conn=<uninitialized>, flow=<uninitialized>, ip=192.168.18.50/32, mac=<uninitialized>], expire=36000.0, priority=0, location=, out_port=<uninitialized>, mod=<uninitialized>, id=4, cid=4, _plugin_id=1], [command=nonullzero, cookie=4, arg=192.168.18.50/32, comment=]

View file

@ -0,0 +1,7 @@
BrokerComm::outgoing_connection_established, 127.0.0.1, 9999/tcp
rule added, [ty=NetControl::DROP, target=NetControl::FORWARD, entity=[ty=NetControl::FLOW, conn=<uninitialized>, flow=[src_h=192.168.18.50/32, src_p=<uninitialized>, dst_h=74.125.239.97/32, dst_p=<uninitialized>, src_m=<uninitialized>, dst_m=<uninitialized>], ip=<uninitialized>, mac=<uninitialized>], expire=36000.0, priority=0, location=here, out_port=<uninitialized>, mod=<uninitialized>, id=2, cid=2, _plugin_id=1]
rule added, [ty=NetControl::DROP, target=NetControl::FORWARD, entity=[ty=NetControl::FLOW, conn=<uninitialized>, flow=[src_h=<uninitialized>, src_p=<uninitialized>, dst_h=<uninitialized>, dst_p=443/tcp, src_m=<uninitialized>, dst_m=<uninitialized>], ip=<uninitialized>, mac=<uninitialized>], expire=36000.0, priority=0, location=there, out_port=<uninitialized>, mod=<uninitialized>, id=3, cid=3, _plugin_id=1]
rule added, [ty=NetControl::DROP, target=NetControl::FORWARD, entity=[ty=NetControl::ADDRESS, conn=<uninitialized>, flow=<uninitialized>, ip=192.168.18.50/32, mac=<uninitialized>], expire=36000.0, priority=0, location=, out_port=<uninitialized>, mod=<uninitialized>, id=4, cid=4, _plugin_id=1]
rule removed, [ty=NetControl::DROP, target=NetControl::FORWARD, entity=[ty=NetControl::FLOW, conn=<uninitialized>, flow=[src_h=192.168.18.50/32, src_p=<uninitialized>, dst_h=74.125.239.97/32, dst_p=<uninitialized>, src_m=<uninitialized>, dst_m=<uninitialized>], ip=<uninitialized>, mac=<uninitialized>], expire=36000.0, priority=0, location=here, out_port=<uninitialized>, mod=<uninitialized>, id=2, cid=2, _plugin_id=1]
rule removed, [ty=NetControl::DROP, target=NetControl::FORWARD, entity=[ty=NetControl::FLOW, conn=<uninitialized>, flow=[src_h=<uninitialized>, src_p=<uninitialized>, dst_h=<uninitialized>, dst_p=443/tcp, src_m=<uninitialized>, dst_m=<uninitialized>], ip=<uninitialized>, mac=<uninitialized>], expire=36000.0, priority=0, location=there, out_port=<uninitialized>, mod=<uninitialized>, id=3, cid=3, _plugin_id=1]
rule removed, [ty=NetControl::DROP, target=NetControl::FORWARD, entity=[ty=NetControl::ADDRESS, conn=<uninitialized>, flow=<uninitialized>, ip=192.168.18.50/32, mac=<uninitialized>], expire=36000.0, priority=0, location=, out_port=<uninitialized>, mod=<uninitialized>, id=4, cid=4, _plugin_id=1]

View file

@ -0,0 +1,118 @@
# @TEST-SERIALIZE: brokercomm
# @TEST-REQUIRES: grep -q ENABLE_BROKER $BUILD/CMakeCache.txt
# @TEST-EXEC: btest-bg-run recv "bro -b ../recv.bro broker_port=$BROKER_PORT >recv.out"
# @TEST-EXEC: btest-bg-run send "bro -b -r $TRACES/tls/ecdhe.pcap --pseudo-realtime ../send.bro broker_port=$BROKER_PORT >send.out"
# @TEST-EXEC: btest-bg-wait 20
# @TEST-EXEC: btest-diff recv/recv.out
# @TEST-EXEC: btest-diff send/send.out
@TEST-START-FILE send.bro
@load base/frameworks/netcontrol
const broker_port: port &redef;
redef exit_only_after_terminate = T;
event bro_init()
{
suspend_processing();
local netcontrol_acld = NetControl::create_acld(NetControl::AcldConfig($acld_host=127.0.0.1, $acld_port=broker_port, $acld_topic="bro/event/netcontroltest"));
NetControl::activate(netcontrol_acld, 0);
}
event BrokerComm::outgoing_connection_established(peer_address: string,
peer_port: port,
peer_name: string)
{
print "BrokerComm::outgoing_connection_established", peer_address, peer_port;
continue_processing();
}
event BrokerComm::outgoing_connection_broken(peer_address: string,
peer_port: port)
{
terminate();
}
hook NetControl::acld_rule_policy(p: NetControl::PluginState, r: NetControl::Rule, ar: NetControl::AclRule)
{
# use nullzero instead of drop for address drops
if ( r$ty == NetControl::DROP && r$entity$ty == NetControl::ADDRESS && ar$command == "drop" )
ar$command = "nullzero";
}
event connection_established(c: connection)
{
local id = c$id;
local flow1 = NetControl::Flow(
$src_h=addr_to_subnet(c$id$orig_h),
$dst_h=addr_to_subnet(c$id$resp_h)
);
local e1: NetControl::Entity = [$ty=NetControl::FLOW, $flow=flow1];
local r1: NetControl::Rule = [$ty=NetControl::DROP, $target=NetControl::FORWARD, $entity=e1, $expire=10hrs, $location="here"];
local flow2 = NetControl::Flow(
$dst_p=c$id$resp_p
);
local e2: NetControl::Entity = [$ty=NetControl::FLOW, $flow=flow2];
local r2: NetControl::Rule = [$ty=NetControl::DROP, $target=NetControl::FORWARD, $entity=e2, $expire=10hrs, $location="there"];
NetControl::add_rule(r1);
NetControl::add_rule(r2);
NetControl::drop_address(id$orig_h, 10hrs);
}
event NetControl::rule_added(r: NetControl::Rule, p: NetControl::PluginState, msg: string)
{
print "rule added", r;
NetControl::remove_rule(r$id);
}
event NetControl::rule_removed(r: NetControl::Rule, p: NetControl::PluginState, msg: string)
{
print "rule removed", r;
}
@TEST-END-FILE
@TEST-START-FILE recv.bro
@load base/frameworks/netcontrol
@load base/frameworks/broker
const broker_port: port &redef;
redef exit_only_after_terminate = T;
event bro_init()
{
BrokerComm::enable();
BrokerComm::subscribe_to_events("bro/event/netcontroltest");
BrokerComm::listen(broker_port, "127.0.0.1");
}
event BrokerComm::incoming_connection_established(peer_name: string)
{
print "BrokerComm::incoming_connection_established";
}
event NetControl::acld_add_rule(id: count, r: NetControl::Rule, ar: NetControl::AclRule)
{
print "add_rule", id, r, ar;
BrokerComm::event("bro/event/netcontroltest", BrokerComm::event_args(NetControl::acld_rule_added, id, r, ar$command));
}
event NetControl::acld_remove_rule(id: count, r: NetControl::Rule, ar: NetControl::AclRule)
{
print "remove_rule", id, r, ar;
BrokerComm::event("bro/event/netcontroltest", BrokerComm::event_args(NetControl::acld_rule_removed, id, r, ar$command));
if ( r$cid == 4 )
terminate();
}
@TEST-END-FILE