mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
Rename Pacf to NetControl
This commit is contained in:
parent
eb9fbd1258
commit
0e213352d7
61 changed files with 498 additions and 498 deletions
5
scripts/base/frameworks/netcontrol/plugins/__load__.bro
Normal file
5
scripts/base/frameworks/netcontrol/plugins/__load__.bro
Normal file
|
@ -0,0 +1,5 @@
|
|||
@load ./debug
|
||||
@load ./openflow
|
||||
@load ./packetfilter
|
||||
@load ./broker
|
||||
@load ./acld
|
230
scripts/base/frameworks/netcontrol/plugins/acld.bro
Normal file
230
scripts/base/frameworks/netcontrol/plugins/acld.bro
Normal file
|
@ -0,0 +1,230 @@
|
|||
# Acld plugin for the netcontrol framework.
|
||||
|
||||
module NetControl;
|
||||
|
||||
@load ../plugin
|
||||
@load base/frameworks/broker
|
||||
|
||||
export {
|
||||
type AclRule : record {
|
||||
command: string;
|
||||
cookie: count;
|
||||
arg: string;
|
||||
comment: string &optional;
|
||||
};
|
||||
|
||||
type AcldConfig: record {
|
||||
## The acld topic used to send events to
|
||||
acld_topic: string;
|
||||
## Broker host to connect to
|
||||
acld_host: addr;
|
||||
## Broker port to connect to
|
||||
acld_port: port;
|
||||
## Function that can decide weather to accept add request
|
||||
add_pred: function(p: PluginState, r: Rule, ar: AclRule): bool &optional &weaken;
|
||||
};
|
||||
|
||||
## Instantiates the acld plugin.
|
||||
global create_acld: function(config: AcldConfig) : PluginState;
|
||||
|
||||
redef record PluginState += {
|
||||
acld_config: AcldConfig &optional;
|
||||
## The ID of this acld instance - for the mapping to PluginStates
|
||||
acld_id: count &optional;
|
||||
};
|
||||
|
||||
global acld_add_rule: event(id: count, r: Rule, ar: AclRule);
|
||||
global acld_remove_rule: event(id: count, r: Rule, ar: AclRule);
|
||||
|
||||
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_error: event(id: count, r: Rule, msg: string);
|
||||
}
|
||||
|
||||
global netcontrol_acld_topics: set[string] = set();
|
||||
global netcontrol_acld_id: table[count] of PluginState = table();
|
||||
global netcontrol_acld_current_id: count = 0;
|
||||
|
||||
const acld_add_to_remove: table[string] of string = {
|
||||
["drop"] = "restore",
|
||||
["whitelist"] = "remwhitelist",
|
||||
["blockhosthost"] = "restorehosthost",
|
||||
["droptcpport"] = "restoretcpport",
|
||||
["dropudpport"] = "restoreudpport",
|
||||
["droptcpdsthostport"] ="restoretcpdsthostport",
|
||||
["dropudpdsthostport"] ="restoreudpdsthostport",
|
||||
["permittcpdsthostport"] ="unpermittcpdsthostport",
|
||||
["permitudpdsthostport"] ="unpermitudpdsthostport",
|
||||
["nullzero "] ="nonullzero"
|
||||
};
|
||||
|
||||
event NetControl::acld_rule_added(id: count, r: Rule, msg: string)
|
||||
{
|
||||
if ( id !in netcontrol_acld_id )
|
||||
{
|
||||
Reporter::error(fmt("NetControl acld plugin with id %d not found, aborting", id));
|
||||
return;
|
||||
}
|
||||
|
||||
local p = netcontrol_acld_id[id];
|
||||
|
||||
event NetControl::rule_added(r, p, msg);
|
||||
}
|
||||
|
||||
event NetControl::acld_rule_removed(id: count, r: Rule, msg: string)
|
||||
{
|
||||
if ( id !in netcontrol_acld_id )
|
||||
{
|
||||
Reporter::error(fmt("NetControl acld plugin with id %d not found, aborting", id));
|
||||
return;
|
||||
}
|
||||
|
||||
local p = netcontrol_acld_id[id];
|
||||
|
||||
event NetControl::rule_removed(r, p, msg);
|
||||
}
|
||||
|
||||
event NetControl::acld_rule_error(id: count, r: Rule, msg: string)
|
||||
{
|
||||
if ( id !in netcontrol_acld_id )
|
||||
{
|
||||
Reporter::error(fmt("NetControl acld plugin with id %d not found, aborting", id));
|
||||
return;
|
||||
}
|
||||
|
||||
local p = netcontrol_acld_id[id];
|
||||
|
||||
event NetControl::rule_error(r, p, msg);
|
||||
}
|
||||
|
||||
function acld_name(p: PluginState) : string
|
||||
{
|
||||
return fmt("PACF acld plugin - using broker topic %s", p$acld_config$acld_topic);
|
||||
}
|
||||
|
||||
# check that subnet specifies an addr
|
||||
function check_sn(sn: subnet) : bool
|
||||
{
|
||||
if ( is_v4_subnet(sn) && subnet_width(sn) == 32 )
|
||||
return T;
|
||||
if ( is_v6_subnet(sn) && subnet_width(sn) == 128 )
|
||||
return T;
|
||||
|
||||
Reporter::error(fmt("Acld: rule_to_acl_rule was given a subnet that does not specify a distinct address where needed - %s", sn));
|
||||
return F;
|
||||
}
|
||||
|
||||
function rule_to_acl_rule(r: Rule) : AclRule
|
||||
{
|
||||
local e = r$entity;
|
||||
|
||||
local command: string = "";
|
||||
local arg: string = "";
|
||||
|
||||
if ( e$ty == ADDRESS )
|
||||
{
|
||||
if ( r$ty == DROP )
|
||||
command = "drop";
|
||||
else if ( r$ty == WHITELIST )
|
||||
command = "whitelist";
|
||||
arg = cat(e$ip);
|
||||
}
|
||||
else if ( e$ty == FLOW )
|
||||
{
|
||||
local f = e$flow;
|
||||
if ( ( ! f?$src_h ) && ( ! f?$src_p ) && f?$dst_h && f?$dst_p && ( ! f?$src_m ) && ( ! f?$dst_m ) )
|
||||
{
|
||||
if ( !check_sn(f$dst_h) )
|
||||
command = ""; # invalid addr, do nothing
|
||||
else if ( is_tcp_port(f$dst_p) && r$ty == DROP )
|
||||
command = "droptcpdsthostport";
|
||||
else if ( is_tcp_port(f$dst_p) && r$ty == WHITELIST )
|
||||
command = "permittcpdsthostport";
|
||||
else if ( is_udp_port(f$dst_p) && r$ty == DROP)
|
||||
command = "dropucpdsthostport";
|
||||
else if ( is_udp_port(f$dst_p) && r$ty == WHITELIST)
|
||||
command = "permitucpdsthostport";
|
||||
|
||||
arg = fmt("%s %d", subnet_to_addr(f$dst_h), f$dst_p);
|
||||
}
|
||||
else if ( f?$src_h && ( ! f?$src_p ) && f?$dst_h && ( ! f?$dst_p ) && ( ! f?$src_m ) && ( ! f?$dst_m ) )
|
||||
{
|
||||
if ( !check_sn(f$src_h) || !check_sn(f$dst_h) )
|
||||
command = "";
|
||||
else if ( r$ty == DROP )
|
||||
command = "blockhosthost";
|
||||
arg = fmt("%s %s", subnet_to_addr(f$src_h), subnet_to_addr(f$dst_h));
|
||||
}
|
||||
else if ( ( ! f?$src_h ) && ( ! f?$src_p ) && ( ! f?$dst_h ) && f?$dst_p && ( ! f?$src_m ) && ( ! f?$dst_m ) )
|
||||
{
|
||||
if ( is_tcp_port(f$dst_p) && r$ty == DROP )
|
||||
command = "droptcpport";
|
||||
else if ( is_udp_port(f$dst_p) && r$ty == DROP )
|
||||
command = "dropudpport";
|
||||
arg = fmt("%d", f$dst_p);
|
||||
}
|
||||
}
|
||||
|
||||
local ar = AclRule($command=command, $cookie=r$cid, $arg=arg);
|
||||
if ( r?$location )
|
||||
ar$comment = r$location;
|
||||
return ar;
|
||||
}
|
||||
|
||||
function acld_add_rule_fun(p: PluginState, r: Rule) : bool
|
||||
{
|
||||
local ar = rule_to_acl_rule(r);
|
||||
|
||||
if ( p$acld_config?$add_pred )
|
||||
if ( ! p$acld_config$add_pred(p, r, ar) )
|
||||
return F;
|
||||
|
||||
if ( ar$command == "" )
|
||||
return F;
|
||||
|
||||
BrokerComm::event(p$acld_config$acld_topic, BrokerComm::event_args(acld_add_rule, p$acld_id, r, ar));
|
||||
return T;
|
||||
}
|
||||
|
||||
function acld_remove_rule_fun(p: PluginState, r: Rule) : bool
|
||||
{
|
||||
local ar = rule_to_acl_rule(r);
|
||||
if ( ar$command in acld_add_to_remove )
|
||||
ar$command = acld_add_to_remove[ar$command];
|
||||
else
|
||||
return F;
|
||||
|
||||
BrokerComm::event(p$acld_config$acld_topic, BrokerComm::event_args(acld_remove_rule, p$acld_id, r, ar));
|
||||
return T;
|
||||
}
|
||||
|
||||
function acld_init(p: PluginState)
|
||||
{
|
||||
BrokerComm::enable();
|
||||
BrokerComm::connect(cat(p$acld_config$acld_host), p$acld_config$acld_port, 1sec);
|
||||
BrokerComm::subscribe_to_events(p$acld_config$acld_topic);
|
||||
}
|
||||
|
||||
global acld_plugin = Plugin(
|
||||
$name=acld_name,
|
||||
$can_expire = F,
|
||||
$add_rule = acld_add_rule_fun,
|
||||
$remove_rule = acld_remove_rule_fun,
|
||||
$init = acld_init
|
||||
);
|
||||
|
||||
function create_acld(config: AcldConfig) : PluginState
|
||||
{
|
||||
if ( config$acld_topic in netcontrol_acld_topics )
|
||||
Reporter::warning(fmt("Topic %s was added to NetControl acld plugin twice. Possible duplication of commands", config$acld_topic));
|
||||
else
|
||||
add netcontrol_acld_topics[config$acld_topic];
|
||||
|
||||
local p: PluginState = [$acld_config=config, $plugin=acld_plugin, $acld_id=netcontrol_acld_current_id];
|
||||
|
||||
netcontrol_acld_id[netcontrol_acld_current_id] = p;
|
||||
++netcontrol_acld_current_id;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
147
scripts/base/frameworks/netcontrol/plugins/broker.bro
Normal file
147
scripts/base/frameworks/netcontrol/plugins/broker.bro
Normal file
|
@ -0,0 +1,147 @@
|
|||
# Broker plugin for the netcontrol framework. Sends the raw data structures
|
||||
# used in netcontrol on to Broker to allow for easy handling, e.g., of
|
||||
# command-line scripts.
|
||||
|
||||
module NetControl;
|
||||
|
||||
@load ../plugin
|
||||
@load base/frameworks/broker
|
||||
|
||||
export {
|
||||
## Instantiates the broker plugin.
|
||||
global create_broker: function(host: addr, host_port: port, topic: string, can_expire: bool &default=F) : PluginState;
|
||||
|
||||
redef record PluginState += {
|
||||
## The broker topic used to send events to
|
||||
broker_topic: string &optional;
|
||||
## The ID of this broker instance - for the mapping to PluginStates
|
||||
broker_id: count &optional;
|
||||
## Broker host to connect to
|
||||
broker_host: addr &optional;
|
||||
## Broker port to connect to
|
||||
broker_port: port &optional;
|
||||
};
|
||||
|
||||
global broker_add_rule: event(id: count, r: Rule);
|
||||
global broker_remove_rule: event(id: count, r: Rule);
|
||||
|
||||
global broker_rule_added: event(id: count, r: Rule, msg: string);
|
||||
global broker_rule_removed: event(id: count, r: Rule, msg: string);
|
||||
global broker_rule_error: event(id: count, r: Rule, msg: string);
|
||||
global broker_rule_timeout: event(id: count, r: Rule, i: FlowInfo);
|
||||
}
|
||||
|
||||
global netcontrol_broker_topics: set[string] = set();
|
||||
global netcontrol_broker_id: table[count] of PluginState = table();
|
||||
global netcontrol_broker_current_id: count = 0;
|
||||
|
||||
event NetControl::broker_rule_added(id: count, r: Rule, msg: string)
|
||||
{
|
||||
if ( id !in netcontrol_broker_id )
|
||||
{
|
||||
Reporter::error(fmt("NetControl broker plugin with id %d not found, aborting", id));
|
||||
return;
|
||||
}
|
||||
|
||||
local p = netcontrol_broker_id[id];
|
||||
|
||||
event NetControl::rule_added(r, p, msg);
|
||||
}
|
||||
|
||||
event NetControl::broker_rule_removed(id: count, r: Rule, msg: string)
|
||||
{
|
||||
if ( id !in netcontrol_broker_id )
|
||||
{
|
||||
Reporter::error(fmt("NetControl broker plugin with id %d not found, aborting", id));
|
||||
return;
|
||||
}
|
||||
|
||||
local p = netcontrol_broker_id[id];
|
||||
|
||||
event NetControl::rule_removed(r, p, msg);
|
||||
}
|
||||
|
||||
event NetControl::broker_rule_error(id: count, r: Rule, msg: string)
|
||||
{
|
||||
if ( id !in netcontrol_broker_id )
|
||||
{
|
||||
Reporter::error(fmt("NetControl broker plugin with id %d not found, aborting", id));
|
||||
return;
|
||||
}
|
||||
|
||||
local p = netcontrol_broker_id[id];
|
||||
|
||||
event NetControl::rule_error(r, p, msg);
|
||||
}
|
||||
|
||||
event NetControl::broker_rule_timeout(id: count, r: Rule, i: FlowInfo)
|
||||
{
|
||||
if ( id !in netcontrol_broker_id )
|
||||
{
|
||||
Reporter::error(fmt("NetControl broker plugin with id %d not found, aborting", id));
|
||||
return;
|
||||
}
|
||||
|
||||
local p = netcontrol_broker_id[id];
|
||||
|
||||
event NetControl::rule_timeout(r, i, p);
|
||||
}
|
||||
|
||||
function broker_name(p: PluginState) : string
|
||||
{
|
||||
return fmt("PACF Broker plugin - topic %s", p$broker_topic);
|
||||
}
|
||||
|
||||
function broker_add_rule_fun(p: PluginState, r: Rule) : bool
|
||||
{
|
||||
BrokerComm::event(p$broker_topic, BrokerComm::event_args(broker_add_rule, p$broker_id, r));
|
||||
return T;
|
||||
}
|
||||
|
||||
function broker_remove_rule_fun(p: PluginState, r: Rule) : bool
|
||||
{
|
||||
BrokerComm::event(p$broker_topic, BrokerComm::event_args(broker_remove_rule, p$broker_id, r));
|
||||
return T;
|
||||
}
|
||||
|
||||
function broker_init(p: PluginState)
|
||||
{
|
||||
BrokerComm::enable();
|
||||
BrokerComm::connect(cat(p$broker_host), p$broker_port, 1sec);
|
||||
BrokerComm::subscribe_to_events(p$broker_topic);
|
||||
}
|
||||
|
||||
global broker_plugin = Plugin(
|
||||
$name=broker_name,
|
||||
$can_expire = F,
|
||||
$add_rule = broker_add_rule_fun,
|
||||
$remove_rule = broker_remove_rule_fun,
|
||||
$init = broker_init
|
||||
);
|
||||
|
||||
global broker_plugin_can_expire = Plugin(
|
||||
$name=broker_name,
|
||||
$can_expire = T,
|
||||
$add_rule = broker_add_rule_fun,
|
||||
$remove_rule = broker_remove_rule_fun,
|
||||
$init = broker_init
|
||||
);
|
||||
|
||||
function create_broker(host: addr, host_port: port, topic: string, can_expire: bool &default=F) : PluginState
|
||||
{
|
||||
if ( topic in netcontrol_broker_topics )
|
||||
Reporter::warning(fmt("Topic %s was added to NetControl broker plugin twice. Possible duplication of commands", topic));
|
||||
else
|
||||
add netcontrol_broker_topics[topic];
|
||||
|
||||
local plugin = broker_plugin;
|
||||
if ( can_expire )
|
||||
plugin = broker_plugin_can_expire;
|
||||
|
||||
local p: PluginState = [$broker_host=host, $broker_port=host_port, $plugin=plugin, $broker_topic=topic, $broker_id=netcontrol_broker_current_id];
|
||||
|
||||
netcontrol_broker_id[netcontrol_broker_current_id] = p;
|
||||
++netcontrol_broker_current_id;
|
||||
|
||||
return p;
|
||||
}
|
95
scripts/base/frameworks/netcontrol/plugins/debug.bro
Normal file
95
scripts/base/frameworks/netcontrol/plugins/debug.bro
Normal file
|
@ -0,0 +1,95 @@
|
|||
|
||||
@load ../plugin
|
||||
|
||||
module NetControl;
|
||||
|
||||
export {
|
||||
## Instantiates a debug plugin for the PACF framework. The debug
|
||||
## plugin simply logs the operations it receives.
|
||||
##
|
||||
## do_something: If true, the plugin will claim it supports all operations; if
|
||||
## false, it will indicate it doesn't support any.
|
||||
global create_debug: function(do_something: bool) : PluginState;
|
||||
}
|
||||
|
||||
function do_something(p: PluginState) : bool
|
||||
{
|
||||
return p$config["all"] == "1";
|
||||
}
|
||||
|
||||
function debug_name(p: PluginState) : string
|
||||
{
|
||||
return fmt("Debug-%s", (do_something(p) ? "All" : "None"));
|
||||
}
|
||||
|
||||
function debug_log(p: PluginState, msg: string)
|
||||
{
|
||||
print fmt("netcontrol debug (%s): %s", debug_name(p), msg);
|
||||
}
|
||||
|
||||
function debug_init(p: PluginState)
|
||||
{
|
||||
debug_log(p, "init");
|
||||
}
|
||||
|
||||
function debug_done(p: PluginState)
|
||||
{
|
||||
debug_log(p, "init");
|
||||
}
|
||||
|
||||
function debug_add_rule(p: PluginState, r: Rule) : bool
|
||||
{
|
||||
local s = fmt("add_rule: %s", r);
|
||||
debug_log(p, s);
|
||||
|
||||
if ( do_something(p) )
|
||||
{
|
||||
event NetControl::rule_added(r, p);
|
||||
return T;
|
||||
}
|
||||
|
||||
return F;
|
||||
}
|
||||
|
||||
function debug_remove_rule(p: PluginState, r: Rule) : bool
|
||||
{
|
||||
local s = fmt("remove_rule: %s", r);
|
||||
debug_log(p, s);
|
||||
|
||||
event NetControl::rule_removed(r, p);
|
||||
return T;
|
||||
}
|
||||
|
||||
function debug_transaction_begin(p: PluginState)
|
||||
{
|
||||
debug_log(p, "transaction_begin");
|
||||
}
|
||||
|
||||
function debug_transaction_end(p: PluginState)
|
||||
{
|
||||
debug_log(p, "transaction_end");
|
||||
}
|
||||
|
||||
global debug_plugin = Plugin(
|
||||
$name=debug_name,
|
||||
$can_expire = F,
|
||||
$init = debug_init,
|
||||
$done = debug_done,
|
||||
$add_rule = debug_add_rule,
|
||||
$remove_rule = debug_remove_rule,
|
||||
$transaction_begin = debug_transaction_begin,
|
||||
$transaction_end = debug_transaction_end
|
||||
);
|
||||
|
||||
function create_debug(do_something: bool) : PluginState
|
||||
{
|
||||
local p: PluginState = [$plugin=debug_plugin];
|
||||
|
||||
# FIXME: Why's the default not working?
|
||||
p$config = table();
|
||||
p$config["all"] = (do_something ? "1" : "0");
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
402
scripts/base/frameworks/netcontrol/plugins/openflow.bro
Normal file
402
scripts/base/frameworks/netcontrol/plugins/openflow.bro
Normal file
|
@ -0,0 +1,402 @@
|
|||
@load ../plugin
|
||||
@load base/frameworks/openflow
|
||||
|
||||
module NetControl;
|
||||
|
||||
export {
|
||||
type OfConfig: record {
|
||||
monitor: bool &default=T;
|
||||
forward: bool &default=T;
|
||||
idle_timeout: count &default=0;
|
||||
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.
|
||||
|
||||
check_pred: function(p: PluginState, r: Rule): bool &optional &weaken;
|
||||
match_pred: function(p: PluginState, e: Entity, m: vector of OpenFlow::ofp_match): vector of OpenFlow::ofp_match &optional &weaken;
|
||||
flow_mod_pred: function(p: PluginState, r: Rule, m: OpenFlow::ofp_flow_mod): OpenFlow::ofp_flow_mod &optional &weaken;
|
||||
};
|
||||
|
||||
redef record PluginState += {
|
||||
## OpenFlow controller for NetControl OpenFlow plugin
|
||||
of_controller: OpenFlow::Controller &optional;
|
||||
## OpenFlow configuration record that is passed on initialization
|
||||
of_config: OfConfig &optional;
|
||||
};
|
||||
|
||||
type OfTable: record {
|
||||
p: PluginState;
|
||||
r: Rule;
|
||||
c: count &default=0; # how many replies did we see so far? needed for ids where we have multiple rules...
|
||||
packet_count: count &default=0;
|
||||
byte_count: count &default=0;
|
||||
duration_sec: double &default=0.0;
|
||||
};
|
||||
|
||||
## the time interval after which an openflow message is considered to be timed out
|
||||
## and we delete it from our internal tracking.
|
||||
const openflow_message_timeout = 20secs &redef;
|
||||
|
||||
## the time interval after we consider a flow timed out. This should be fairly high (or
|
||||
## even disabled) if you expect a lot of long flows. However, one also will have state
|
||||
## buildup for quite a while if keeping this around...
|
||||
const openflow_flow_timeout = 24hrs &redef;
|
||||
|
||||
## Instantiates an openflow plugin for the PACF framework.
|
||||
global create_openflow: function(controller: OpenFlow::Controller, config: OfConfig &default=[]) : PluginState;
|
||||
}
|
||||
|
||||
global of_messages: table[count, OpenFlow::ofp_flow_mod_command] of OfTable &create_expire=openflow_message_timeout
|
||||
&expire_func=function(t: table[count, OpenFlow::ofp_flow_mod_command] of OfTable, idx: any): interval
|
||||
{
|
||||
local rid: count;
|
||||
local command: OpenFlow::ofp_flow_mod_command;
|
||||
[rid, command] = idx;
|
||||
|
||||
local p = t[rid, command]$p;
|
||||
local r = t[rid, command]$r;
|
||||
event NetControl::rule_error(r, p, "Timeout during rule insertion/removal");
|
||||
return 0secs;
|
||||
};
|
||||
|
||||
global of_flows: table[count] of OfTable &create_expire=openflow_flow_timeout;
|
||||
|
||||
function openflow_name(p: PluginState) : string
|
||||
{
|
||||
return fmt("Openflow - %s", p$of_controller$describe(p$of_controller$state));
|
||||
}
|
||||
|
||||
function openflow_check_rule(p: PluginState, r: Rule) : bool
|
||||
{
|
||||
local c = p$of_config;
|
||||
|
||||
if ( p$of_config?$check_pred )
|
||||
return p$of_config$check_pred(p, r);
|
||||
|
||||
if ( r$target == MONITOR && c$monitor )
|
||||
return T;
|
||||
|
||||
if ( r$target == FORWARD && c$forward )
|
||||
return T;
|
||||
|
||||
return F;
|
||||
}
|
||||
|
||||
function openflow_match_pred(p: PluginState, e: Entity, m: vector of OpenFlow::ofp_match) : vector of OpenFlow::ofp_match
|
||||
{
|
||||
if ( p$of_config?$match_pred )
|
||||
return p$of_config$match_pred(p, e, m);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
function openflow_flow_mod_pred(p: PluginState, r: Rule, m: OpenFlow::ofp_flow_mod): OpenFlow::ofp_flow_mod
|
||||
{
|
||||
if ( p$of_config?$flow_mod_pred )
|
||||
return p$of_config$flow_mod_pred(p, r, m);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
function determine_dl_type(s: subnet): count
|
||||
{
|
||||
local pdl = OpenFlow::ETH_IPv4;
|
||||
if ( is_v6_subnet(s) )
|
||||
pdl = OpenFlow::ETH_IPv6;
|
||||
|
||||
return pdl;
|
||||
}
|
||||
|
||||
function determine_proto(p: port): count
|
||||
{
|
||||
local proto = OpenFlow::IP_TCP;
|
||||
if ( is_udp_port(p) )
|
||||
proto = OpenFlow::IP_UDP;
|
||||
else if ( is_icmp_port(p) )
|
||||
proto = OpenFlow::IP_ICMP;
|
||||
|
||||
return proto;
|
||||
}
|
||||
|
||||
function entity_to_match(p: PluginState, e: Entity): vector of OpenFlow::ofp_match
|
||||
{
|
||||
local v : vector of OpenFlow::ofp_match = vector();
|
||||
|
||||
if ( e$ty == CONNECTION )
|
||||
{
|
||||
v[|v|] = OpenFlow::match_conn(e$conn); # forward and...
|
||||
v[|v|] = OpenFlow::match_conn(e$conn, T); # reverse
|
||||
return openflow_match_pred(p, e, v);
|
||||
}
|
||||
|
||||
if ( e$ty == MAC )
|
||||
{
|
||||
v[|v|] = OpenFlow::ofp_match(
|
||||
$dl_src=e$mac
|
||||
);
|
||||
v[|v|] = OpenFlow::ofp_match(
|
||||
$dl_dst=e$mac
|
||||
);
|
||||
|
||||
return openflow_match_pred(p, e, v);
|
||||
}
|
||||
|
||||
local dl_type = OpenFlow::ETH_IPv4;
|
||||
|
||||
if ( e$ty == ADDRESS )
|
||||
{
|
||||
if ( is_v6_subnet(e$ip) )
|
||||
dl_type = OpenFlow::ETH_IPv6;
|
||||
|
||||
v[|v|] = OpenFlow::ofp_match(
|
||||
$dl_type=dl_type,
|
||||
$nw_src=e$ip
|
||||
);
|
||||
|
||||
v[|v|] = OpenFlow::ofp_match(
|
||||
$dl_type=dl_type,
|
||||
$nw_dst=e$ip
|
||||
);
|
||||
|
||||
return openflow_match_pred(p, e, v);
|
||||
}
|
||||
|
||||
local proto = OpenFlow::IP_TCP;
|
||||
|
||||
if ( e$ty == FLOW )
|
||||
{
|
||||
local m = OpenFlow::ofp_match();
|
||||
local f = e$flow;
|
||||
|
||||
if ( f?$src_m )
|
||||
m$dl_src=f$src_m;
|
||||
if ( f?$dst_m )
|
||||
m$dl_dst=f$dst_m;
|
||||
|
||||
if ( f?$src_h )
|
||||
{
|
||||
m$dl_type = determine_dl_type(f$src_h);
|
||||
m$nw_src = f$src_h;
|
||||
}
|
||||
|
||||
if ( f?$dst_h )
|
||||
{
|
||||
m$dl_type = determine_dl_type(f$dst_h);
|
||||
m$nw_dst = f$dst_h;
|
||||
}
|
||||
|
||||
if ( f?$src_p )
|
||||
{
|
||||
m$nw_proto = determine_proto(f$src_p);
|
||||
m$tp_src = port_to_count(f$src_p);
|
||||
}
|
||||
|
||||
if ( f?$dst_p )
|
||||
{
|
||||
m$nw_proto = determine_proto(f$dst_p);
|
||||
m$tp_dst = port_to_count(f$dst_p);
|
||||
}
|
||||
|
||||
v[|v|] = m;
|
||||
|
||||
return openflow_match_pred(p, e, v);
|
||||
}
|
||||
|
||||
Reporter::error(fmt("Entity type %s not supported for openflow yet", cat(e$ty)));
|
||||
return openflow_match_pred(p, e, v);
|
||||
}
|
||||
|
||||
function openflow_rule_to_flow_mod(p: PluginState, r: Rule) : OpenFlow::ofp_flow_mod
|
||||
{
|
||||
local c = p$of_config;
|
||||
|
||||
local flow_mod = OpenFlow::ofp_flow_mod(
|
||||
$cookie=OpenFlow::generate_cookie(r$cid*2), # leave one space for the cases in which we need two rules.
|
||||
$command=OpenFlow::OFPFC_ADD,
|
||||
$idle_timeout=c$idle_timeout,
|
||||
$priority=int_to_count(r$priority + c$priority_offset),
|
||||
$flags=OpenFlow::OFPFF_SEND_FLOW_REM # please notify us when flows are removed
|
||||
);
|
||||
|
||||
if ( r?$expire )
|
||||
flow_mod$hard_timeout = double_to_count(interval_to_double(r$expire));
|
||||
if ( c?$table_id )
|
||||
flow_mod$table_id = c$table_id;
|
||||
|
||||
if ( r$ty == DROP )
|
||||
{
|
||||
# default, nothing to do. We simply do not add an output port to the rule...
|
||||
}
|
||||
else if ( r$ty == WHITELIST )
|
||||
{
|
||||
# at the moment our interpretation of whitelist is to hand this off to the switches L2/L3 routing.
|
||||
flow_mod$actions$out_ports = vector(OpenFlow::OFPP_NORMAL);
|
||||
}
|
||||
else if ( r$ty == MODIFY )
|
||||
{
|
||||
# if no ports are given, just assume normal pipeline...
|
||||
flow_mod$actions$out_ports = vector(OpenFlow::OFPP_NORMAL);
|
||||
|
||||
local mod = r$mod;
|
||||
if ( mod?$redirect_port )
|
||||
flow_mod$actions$out_ports = vector(mod$redirect_port);
|
||||
|
||||
if ( mod?$src_h )
|
||||
flow_mod$actions$nw_src = mod$src_h;
|
||||
if ( mod?$dst_h )
|
||||
flow_mod$actions$nw_dst = mod$dst_h;
|
||||
if ( mod?$src_m )
|
||||
flow_mod$actions$dl_src = mod$src_m;
|
||||
if ( mod?$dst_m )
|
||||
flow_mod$actions$dl_dst = mod$dst_m;
|
||||
if ( mod?$src_p )
|
||||
flow_mod$actions$tp_src = mod$src_p;
|
||||
if ( mod?$dst_p )
|
||||
flow_mod$actions$tp_dst = mod$dst_p;
|
||||
}
|
||||
else if ( r$ty == REDIRECT )
|
||||
{
|
||||
# redirect to port c
|
||||
flow_mod$actions$out_ports = vector(r$c);
|
||||
}
|
||||
else
|
||||
{
|
||||
Reporter::error(fmt("Rule type %s not supported for openflow yet", cat(r$ty)));
|
||||
}
|
||||
|
||||
return openflow_flow_mod_pred(p, r, flow_mod);
|
||||
}
|
||||
|
||||
function openflow_add_rule(p: PluginState, r: Rule) : bool
|
||||
{
|
||||
if ( ! openflow_check_rule(p, r) )
|
||||
return F;
|
||||
|
||||
local flow_mod = openflow_rule_to_flow_mod(p, r);
|
||||
local matches = entity_to_match(p, r$entity);
|
||||
|
||||
for ( i in matches )
|
||||
{
|
||||
if ( OpenFlow::flow_mod(p$of_controller, matches[i], flow_mod) )
|
||||
{
|
||||
of_messages[r$cid, flow_mod$command] = OfTable($p=p, $r=r);
|
||||
flow_mod = copy(flow_mod);
|
||||
++flow_mod$cookie;
|
||||
}
|
||||
else
|
||||
event rule_error(r, p, "Error while executing OpenFlow::flow_mod");
|
||||
}
|
||||
|
||||
return T;
|
||||
}
|
||||
|
||||
function openflow_remove_rule(p: PluginState, r: Rule) : bool
|
||||
{
|
||||
if ( ! openflow_check_rule(p, r) )
|
||||
return F;
|
||||
|
||||
local flow_mod: OpenFlow::ofp_flow_mod = [
|
||||
$cookie=OpenFlow::generate_cookie(r$cid),
|
||||
$command=OpenFlow::OFPFC_DELETE
|
||||
];
|
||||
|
||||
if ( OpenFlow::flow_mod(p$of_controller, [], flow_mod) )
|
||||
of_messages[r$cid, flow_mod$command] = OfTable($p=p, $r=r);
|
||||
else
|
||||
{
|
||||
event rule_error(r, p, "Error while executing OpenFlow::flow_mod");
|
||||
return F;
|
||||
}
|
||||
|
||||
# if this was an address or mac match, we also need to remove the reverse
|
||||
if ( r$entity$ty == ADDRESS || r$entity$ty == MAC )
|
||||
{
|
||||
local flow_mod_2 = copy(flow_mod);
|
||||
++flow_mod_2$cookie;
|
||||
OpenFlow::flow_mod(p$of_controller, [], flow_mod_2);
|
||||
}
|
||||
|
||||
return T;
|
||||
}
|
||||
|
||||
event OpenFlow::flow_mod_success(match: OpenFlow::ofp_match, flow_mod: OpenFlow::ofp_flow_mod, msg: string) &priority=3
|
||||
{
|
||||
local id = OpenFlow::get_cookie_uid(flow_mod$cookie)/2;
|
||||
if ( [id, flow_mod$command] !in of_messages )
|
||||
return;
|
||||
|
||||
local r = of_messages[id,flow_mod$command]$r;
|
||||
local p = of_messages[id,flow_mod$command]$p;
|
||||
local c = of_messages[id,flow_mod$command]$c;
|
||||
|
||||
if ( r$entity$ty == ADDRESS || r$entity$ty == MAC )
|
||||
{
|
||||
++of_messages[id,flow_mod$command]$c;
|
||||
if ( of_messages[id,flow_mod$command]$c < 2 )
|
||||
return; # will do stuff once the second part arrives...
|
||||
}
|
||||
|
||||
delete of_messages[id,flow_mod$command];
|
||||
|
||||
if ( p$of_controller$supports_flow_removed )
|
||||
of_flows[id] = OfTable($p=p, $r=r);
|
||||
|
||||
if ( flow_mod$command == OpenFlow::OFPFC_ADD )
|
||||
event NetControl::rule_added(r, p, msg);
|
||||
else if ( flow_mod$command == OpenFlow::OFPFC_DELETE || flow_mod$command == OpenFlow::OFPFC_DELETE_STRICT )
|
||||
event NetControl::rule_removed(r, p, msg);
|
||||
}
|
||||
|
||||
event OpenFlow::flow_mod_failure(match: OpenFlow::ofp_match, flow_mod: OpenFlow::ofp_flow_mod, msg: string) &priority=3
|
||||
{
|
||||
local id = OpenFlow::get_cookie_uid(flow_mod$cookie)/2;
|
||||
if ( [id, flow_mod$command] !in of_messages )
|
||||
return;
|
||||
|
||||
local r = of_messages[id,flow_mod$command]$r;
|
||||
local p = of_messages[id,flow_mod$command]$p;
|
||||
delete of_messages[id,flow_mod$command];
|
||||
|
||||
event NetControl::rule_error(r, p, msg);
|
||||
}
|
||||
|
||||
event OpenFlow::flow_removed(match: OpenFlow::ofp_match, cookie: count, priority: count, reason: count, duration_sec: count, idle_timeout: count, packet_count: count, byte_count: count)
|
||||
{
|
||||
local id = OpenFlow::get_cookie_uid(cookie)/2;
|
||||
if ( id !in of_flows )
|
||||
return;
|
||||
|
||||
local rec = of_flows[id];
|
||||
local r = rec$r;
|
||||
local p = rec$p;
|
||||
|
||||
if ( r$entity$ty == ADDRESS || r$entity$ty == MAC )
|
||||
{
|
||||
++of_flows[id]$c;
|
||||
if ( of_flows[id]$c < 2 )
|
||||
return; # will do stuff once the second part arrives...
|
||||
else
|
||||
event NetControl::rule_timeout(r, FlowInfo($duration=double_to_interval((rec$duration_sec+duration_sec)/2), $packet_count=packet_count+rec$packet_count, $byte_count=byte_count+rec$byte_count), p);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
event NetControl::rule_timeout(r, FlowInfo($duration=double_to_interval(duration_sec+0.0), $packet_count=packet_count, $byte_count=byte_count), p);
|
||||
}
|
||||
|
||||
global openflow_plugin = Plugin(
|
||||
$name=openflow_name,
|
||||
$can_expire = T,
|
||||
# $init = openflow_init,
|
||||
# $done = openflow_done,
|
||||
$add_rule = openflow_add_rule,
|
||||
$remove_rule = openflow_remove_rule
|
||||
# $transaction_begin = openflow_transaction_begin,
|
||||
# $transaction_end = openflow_transaction_end
|
||||
);
|
||||
|
||||
function create_openflow(controller: OpenFlow::Controller, config: OfConfig &default=[]) : PluginState
|
||||
{
|
||||
local p: PluginState = [$plugin=openflow_plugin, $of_controller=controller, $of_config=config];
|
||||
|
||||
return p;
|
||||
}
|
113
scripts/base/frameworks/netcontrol/plugins/packetfilter.bro
Normal file
113
scripts/base/frameworks/netcontrol/plugins/packetfilter.bro
Normal file
|
@ -0,0 +1,113 @@
|
|||
# PACF plugin for the PacketFilter handling that comes with
|
||||
# Bro. Since the PacketFilter in Bro is quite limited in scope
|
||||
# and can only add/remove filters for addresses, this is quite
|
||||
# limited in scope at the moment.
|
||||
|
||||
module NetControl;
|
||||
|
||||
@load ../plugin
|
||||
|
||||
export {
|
||||
## Instantiates the packetfilter plugin.
|
||||
global create_packetfilter: function() : PluginState;
|
||||
}
|
||||
|
||||
# Check if we can handle this rule. If it specifies ports or
|
||||
# anything Bro cannot handle, simply ignore it for now.
|
||||
function packetfilter_check_rule(r: Rule) : bool
|
||||
{
|
||||
if ( r$ty != DROP )
|
||||
return F;
|
||||
|
||||
if ( r$target != MONITOR )
|
||||
return F;
|
||||
|
||||
local e = r$entity;
|
||||
if ( e$ty == ADDRESS )
|
||||
return T;
|
||||
|
||||
if ( e$ty != FLOW ) # everything else requires ports or MAC stuff
|
||||
return F;
|
||||
|
||||
if ( e$flow?$src_p || e$flow?$dst_p || e$flow?$src_m || e$flow?$dst_m )
|
||||
return F;
|
||||
|
||||
return T;
|
||||
}
|
||||
|
||||
|
||||
function packetfilter_add_rule(p: PluginState, r: Rule) : bool
|
||||
{
|
||||
if ( ! packetfilter_check_rule(r) )
|
||||
return F;
|
||||
|
||||
local e = r$entity;
|
||||
if ( e$ty == ADDRESS )
|
||||
{
|
||||
install_src_net_filter(e$ip, 0, 1.0);
|
||||
install_dst_net_filter(e$ip, 0, 1.0);
|
||||
return T;
|
||||
}
|
||||
|
||||
if ( e$ty == FLOW )
|
||||
{
|
||||
local f = e$flow;
|
||||
if ( f?$src_h )
|
||||
install_src_net_filter(f$src_h, 0, 1.0);
|
||||
if ( f?$dst_h )
|
||||
install_dst_net_filter(f$dst_h, 0, 1.0);
|
||||
|
||||
return T;
|
||||
}
|
||||
|
||||
return F;
|
||||
}
|
||||
|
||||
function packetfilter_remove_rule(p: PluginState, r: Rule) : bool
|
||||
{
|
||||
if ( ! packetfilter_check_rule(r) )
|
||||
return F;
|
||||
|
||||
local e = r$entity;
|
||||
if ( e$ty == ADDRESS )
|
||||
{
|
||||
uninstall_src_net_filter(e$ip);
|
||||
uninstall_dst_net_filter(e$ip);
|
||||
return T;
|
||||
}
|
||||
|
||||
if ( e$ty == FLOW )
|
||||
{
|
||||
local f = e$flow;
|
||||
if ( f?$src_h )
|
||||
uninstall_src_net_filter(f$src_h);
|
||||
if ( f?$dst_h )
|
||||
uninstall_dst_net_filter(f$dst_h);
|
||||
|
||||
return T;
|
||||
}
|
||||
|
||||
return F;
|
||||
}
|
||||
|
||||
function packetfilter_name(p: PluginState) : string
|
||||
{
|
||||
return "PACF plugin for the Bro packetfilter";
|
||||
}
|
||||
|
||||
global packetfilter_plugin = Plugin(
|
||||
$name=packetfilter_name,
|
||||
$can_expire = F,
|
||||
# $init = packetfilter_init,
|
||||
# $done = packetfilter_done,
|
||||
$add_rule = packetfilter_add_rule,
|
||||
$remove_rule = packetfilter_remove_rule
|
||||
);
|
||||
|
||||
function create_packetfilter() : PluginState
|
||||
{
|
||||
local p: PluginState = [$plugin=packetfilter_plugin];
|
||||
|
||||
return p;
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue