mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00

This does not really have many user-facing changes. The one big change is that users now should initialize plugins in the NetControl::init() event instead of bro_init. Once all plugins finished initializing and the NetControl framework starts operations, the NetControl::init_done() event is raised. Rules that are sent to NetControl before the plugins have finished initializing are ignored - this is important when several plugins that require external connections have to be initialized at the beginning. Without this delay, rules could end up at the wrong plugin.
735 lines
20 KiB
Text
735 lines
20 KiB
Text
##! Bro's packet aquisition and control framework.
|
|
##!
|
|
##! This plugin-based framework allows to control the traffic that Bro monitors
|
|
##! as well as, if having access to the forwarding path, the traffic the network
|
|
##! forwards. By default, the framework lets evyerthing through, to both Bro
|
|
##! itself as well as on the network. Scripts can then add rules to impose
|
|
##! restrictions on entities, such as specific connections or IP addresses.
|
|
##!
|
|
##! This framework has two API: a high-level and low-level. The high-levem API
|
|
##! provides convinience functions for a set of common operations. The
|
|
##! low-level API provides full flexibility.
|
|
|
|
module NetControl;
|
|
|
|
@load ./plugin
|
|
@load ./types
|
|
|
|
export {
|
|
## The framework's logging stream identifier.
|
|
redef enum Log::ID += { LOG };
|
|
|
|
# ###
|
|
# ### Generic functions and events.
|
|
# ###
|
|
|
|
# Activates a plugin.
|
|
#
|
|
# plugin: The plugin to acticate.
|
|
#
|
|
# priority: The higher the priority, the earlier this plugin will be checked
|
|
# whether it supports an operation, relative to other plugins.
|
|
global activate: function(p: PluginState, priority: int);
|
|
|
|
# Event that is used to initialize plugins. Place all plugin initialization
|
|
# related functionality in this event.
|
|
global NetControl::init: event();
|
|
|
|
# Event that is raised once all plugins activated in ``NetControl::init`` have finished
|
|
# their initialization
|
|
global NetControl::init_done: event();
|
|
|
|
# ###
|
|
# ### High-level API.
|
|
# ###
|
|
|
|
# ### Note - other high level primitives are in catch-and-release.bro, shunt.bro and
|
|
# ### drop.bro
|
|
|
|
## Allows all traffic involving a specific IP address to be forwarded.
|
|
##
|
|
## a: The address to be whitelistet.
|
|
##
|
|
## t: How long to whitelist it, with 0 being indefinitly.
|
|
##
|
|
## location: An optional string describing whitelist was triddered.
|
|
##
|
|
## Returns: The id of the inserted rule on succes and zero on failure.
|
|
global whitelist_address: function(a: addr, t: interval, location: string &default="") : string;
|
|
|
|
## Allows all traffic involving a specific IP subnet to be forwarded.
|
|
##
|
|
## s: The subnet to be whitelistet.
|
|
##
|
|
## t: How long to whitelist it, with 0 being indefinitly.
|
|
##
|
|
## location: An optional string describing whitelist was triddered.
|
|
##
|
|
## Returns: The id of the inserted rule on succes and zero on failure.
|
|
global whitelist_subnet: function(s: subnet, t: interval, location: string &default="") : string;
|
|
|
|
## Redirects an uni-directional flow to another port.
|
|
##
|
|
## f: The flow to redirect.
|
|
##
|
|
## out_port: Port to redirect the flow to
|
|
##
|
|
## t: How long to leave the redirect in place, with 0 being indefinitly.
|
|
##
|
|
## location: An optional string describing where the redirect was triggered.
|
|
##
|
|
## Returns: The id of the inserted rule on succes and zero on failure.
|
|
global redirect_flow: function(f: flow_id, out_port: count, t: interval, location: string &default="") : string;
|
|
|
|
## Quarantines a host by redirecting rewriting DNS queries to the network dns server dns
|
|
## to the host. Host has to answer to all queries with its own address. Only http communication
|
|
## from infected to quarantinehost is allowed.
|
|
##
|
|
## infected: the host to quarantine
|
|
##
|
|
## dns: the network dns server
|
|
##
|
|
## quarantine: the quarantine server running a dns and a web server
|
|
##
|
|
## t: how long to leave the quarantine in place
|
|
##
|
|
## Returns: Vector of inserted rules on success, empty list on failure.
|
|
global quarantine_host: function(infected: addr, dns: addr, quarantine: addr, t: interval, location: string &default="") : vector of string;
|
|
|
|
## Flushes all state.
|
|
global clear: function();
|
|
|
|
# ###
|
|
# ### Low-level API.
|
|
# ###
|
|
|
|
###### Manipulation of rules.
|
|
|
|
## Installs a rule.
|
|
##
|
|
## r: The rule to install.
|
|
##
|
|
## Returns: If succesful, returns an ID string unique to the rule that can later
|
|
## be used to refer to it. If unsuccessful, returns an empty string. The ID is also
|
|
## assigned to ``r$id``. Note that "successful" means "a plugin knew how to handle
|
|
## the rule", it doesn't necessarily mean that it was indeed successfully put in
|
|
## place, because that might happen asynchronously and thus fail only later.
|
|
global add_rule: function(r: Rule) : string;
|
|
|
|
## Removes a rule.
|
|
##
|
|
## id: The rule to remove, specified as the ID returned by :bro:id:`add_rule` .
|
|
##
|
|
## Returns: True if succesful, the relevant plugin indicated that it knew how
|
|
## to handle the removal. Note that again "success" means the plugin accepted the
|
|
## removal. They might still fail to put it into effect, as that might happen
|
|
## asynchronously and thus go wrong at that point.
|
|
global remove_rule: function(id: string) : bool;
|
|
|
|
###### Asynchronous feedback on rules.
|
|
|
|
## Confirms that a rule was put in place.
|
|
##
|
|
## r: The rule now in place.
|
|
##
|
|
## plugin: The name of the plugin that put it into place.
|
|
##
|
|
## msg: An optional informational message by the plugin.
|
|
global rule_added: event(r: Rule, p: PluginState, msg: string &default="");
|
|
|
|
## Reports that a rule was removed due to a remove: function() call.
|
|
##
|
|
## r: The rule now removed.
|
|
##
|
|
## plugin: The name of the plugin that had the rule in place and now
|
|
## removed it.
|
|
##
|
|
## msg: An optional informational message by the plugin.
|
|
global rule_removed: event(r: Rule, p: PluginState, msg: string &default="");
|
|
|
|
## Reports that a rule was removed internally due to a timeout.
|
|
##
|
|
## r: The rule now removed.
|
|
##
|
|
## i: Additional flow information, if supported by the protocol.
|
|
##
|
|
## plugin: The name of the plugin that had the rule in place and now
|
|
## removed it.
|
|
##
|
|
## msg: An optional informational message by the plugin.
|
|
global rule_timeout: event(r: Rule, i: FlowInfo, p: PluginState);
|
|
|
|
## Reports an error when operating on a rule.
|
|
##
|
|
## r: The rule that encountered an error.
|
|
##
|
|
## plugin: The name of the plugin that reported the error.
|
|
##
|
|
## msg: An optional informational message by the plugin.
|
|
global rule_error: event(r: Rule, p: PluginState, msg: string &default="");
|
|
|
|
## Hook that allows the modification of rules passed to add_rule before they
|
|
## are passed on to the plugins. If one of the hooks uses break, the rule is
|
|
## ignored and not passed on to any plugin.
|
|
##
|
|
## r: The rule to be added
|
|
global NetControl::rule_policy: hook(r: Rule);
|
|
|
|
##### Plugin functions
|
|
|
|
## Function called by plugins once they finished their activation. After all
|
|
## plugins defined in bro_init finished to activate, rules will start to be sent
|
|
## to the plugins. Rules that scripts try to set before the backends are ready
|
|
## will be discarded.
|
|
global plugin_activated: function(p: PluginState);
|
|
|
|
## Type of an entry in the NetControl log.
|
|
type InfoCategory: enum {
|
|
## A log entry reflecting a framework message.
|
|
MESSAGE,
|
|
## A log entry reflecting a framework message.
|
|
ERROR,
|
|
## A log entry about about a rule.
|
|
RULE
|
|
};
|
|
|
|
## State of an entry in the NetControl log.
|
|
type InfoState: enum {
|
|
REQUESTED,
|
|
SUCCEEDED,
|
|
FAILED,
|
|
REMOVED,
|
|
TIMEOUT,
|
|
};
|
|
|
|
## The record type which contains column fields of the NetControl log.
|
|
type Info: record {
|
|
## Time at which the recorded activity occurred.
|
|
ts: time &log;
|
|
## ID of the rule; unique during each Bro run
|
|
rule_id: string &log &optional;
|
|
## Type of the log entry.
|
|
category: InfoCategory &log &optional;
|
|
## The command the log entry is about.
|
|
cmd: string &log &optional;
|
|
## State the log entry reflects.
|
|
state: InfoState &log &optional;
|
|
## String describing an action the entry is about.
|
|
action: string &log &optional;
|
|
## The target type of the action.
|
|
target: TargetType &log &optional;
|
|
## Type of the entity the log entry is about.
|
|
entity_type: string &log &optional;
|
|
## String describing the entity the log entry is about.
|
|
entity: string &log &optional;
|
|
## String describing the optional modification of the entry (e.h. redirect)
|
|
mod: string &log &optional;
|
|
## String with an additional message.
|
|
msg: string &log &optional;
|
|
## Number describing the priority of the log entry
|
|
priority: int &log &optional;
|
|
## Expiry time of the log entry
|
|
expire: interval &log &optional;
|
|
## Location where the underlying action was triggered.
|
|
location: string &log &optional;
|
|
## Plugin triggering the log entry.
|
|
plugin: string &log &optional;
|
|
};
|
|
|
|
|
|
## Event that can be handled to access the :bro:type:`NetControl::Info`
|
|
## record as it is sent on to the logging framework.
|
|
global log_netcontrol: event(rec: Info);
|
|
}
|
|
|
|
redef record Rule += {
|
|
##< Internally set to the plugin handling the rule.
|
|
_plugin_id: count &optional;
|
|
};
|
|
|
|
# Variable tracking the state of plugin activation. Once all plugins that
|
|
# have been added in bro_init are activated, this will switch to T and
|
|
# the event NetControl::init_done will be raised.
|
|
global plugins_active: bool = F;
|
|
# Set to true at the end of bro_init (with very low priority).
|
|
# Used to track when plugin activation could potentially be finished
|
|
global bro_init_done: bool = F;
|
|
|
|
# The counters that are used to generate the rule and plugin IDs
|
|
global rule_counter: count = 1;
|
|
global plugin_counter: count = 1;
|
|
|
|
# List of the currently active plugins
|
|
global plugins: vector of PluginState;
|
|
global plugin_ids: table[count] of PluginState;
|
|
|
|
# These tables hold informations about rules _after_ they have been
|
|
# succesfully added. Currently no information about the rules is held
|
|
# in these tables while they are in the process of being added.
|
|
global rules: table[string,count] of Rule; # Rules indexed by id and cid
|
|
global id_to_cids: table[string] of set[count]; # id to cid
|
|
|
|
event bro_init() &priority=5
|
|
{
|
|
Log::create_stream(NetControl::LOG, [$columns=Info, $ev=log_netcontrol, $path="netcontrol"]);
|
|
}
|
|
|
|
function entity_to_info(info: Info, e: Entity)
|
|
{
|
|
info$entity_type = fmt("%s", e$ty);
|
|
|
|
switch ( e$ty ) {
|
|
case ADDRESS:
|
|
info$entity = fmt("%s", e$ip);
|
|
break;
|
|
|
|
case CONNECTION:
|
|
info$entity = fmt("%s/%d<->%s/%d",
|
|
e$conn$orig_h, e$conn$orig_p,
|
|
e$conn$resp_h, e$conn$resp_p);
|
|
break;
|
|
|
|
case FLOW:
|
|
local ffrom_ip = "*";
|
|
local ffrom_port = "*";
|
|
local fto_ip = "*";
|
|
local fto_port = "*";
|
|
local ffrom_mac = "*";
|
|
local fto_mac = "*";
|
|
if ( e$flow?$src_h )
|
|
ffrom_ip = cat(e$flow$src_h);
|
|
if ( e$flow?$src_p )
|
|
ffrom_port = fmt("%d", e$flow$src_p);
|
|
if ( e$flow?$dst_h )
|
|
fto_ip = cat(e$flow$dst_h);
|
|
if ( e$flow?$dst_p )
|
|
fto_port = fmt("%d", e$flow$dst_p);
|
|
info$entity = fmt("%s/%s->%s/%s",
|
|
ffrom_ip, ffrom_port,
|
|
fto_ip, fto_port);
|
|
if ( e$flow?$src_m || e$flow?$dst_m )
|
|
{
|
|
if ( e$flow?$src_m )
|
|
ffrom_mac = e$flow$src_m;
|
|
if ( e$flow?$dst_m )
|
|
fto_mac = e$flow$dst_m;
|
|
|
|
info$entity = fmt("%s (%s->%s)", info$entity, ffrom_mac, fto_mac);
|
|
}
|
|
break;
|
|
|
|
case MAC:
|
|
info$entity = e$mac;
|
|
break;
|
|
|
|
default:
|
|
info$entity = "<unknown entity type>";
|
|
break;
|
|
}
|
|
}
|
|
|
|
function rule_to_info(info: Info, r: Rule)
|
|
{
|
|
info$action = fmt("%s", r$ty);
|
|
info$target = r$target;
|
|
info$rule_id = r$id;
|
|
info$expire = r$expire;
|
|
info$priority = r$priority;
|
|
|
|
if ( r?$location && r$location != "" )
|
|
info$location = r$location;
|
|
|
|
if ( r$ty == REDIRECT )
|
|
info$mod = fmt("-> %d", r$out_port);
|
|
|
|
if ( r$ty == MODIFY )
|
|
{
|
|
local mfrom_ip = "_";
|
|
local mfrom_port = "_";
|
|
local mto_ip = "_";
|
|
local mto_port = "_";
|
|
local mfrom_mac = "_";
|
|
local mto_mac = "_";
|
|
if ( r$mod?$src_h )
|
|
mfrom_ip = cat(r$mod$src_h);
|
|
if ( r$mod?$src_p )
|
|
mfrom_port = fmt("%d", r$mod$src_p);
|
|
if ( r$mod?$dst_h )
|
|
mto_ip = cat(r$mod$dst_h);
|
|
if ( r$mod?$dst_p )
|
|
mto_port = fmt("%d", r$mod$dst_p);
|
|
|
|
if ( r$mod?$src_m )
|
|
mfrom_mac = r$mod$src_m;
|
|
if ( r$mod?$dst_m )
|
|
mto_mac = r$mod$dst_m;
|
|
|
|
info$mod = fmt("Src: %s/%s (%s) Dst: %s/%s (%s)",
|
|
mfrom_ip, mfrom_port, mfrom_mac, mto_ip, mto_port, mto_mac);
|
|
|
|
if ( r$mod?$redirect_port )
|
|
info$mod = fmt("%s -> %d", info$mod, r$mod$redirect_port);
|
|
|
|
}
|
|
|
|
entity_to_info(info, r$entity);
|
|
}
|
|
|
|
function log_msg(msg: string, p: PluginState)
|
|
{
|
|
Log::write(LOG, [$ts=network_time(), $category=MESSAGE, $msg=msg, $plugin=p$plugin$name(p)]);
|
|
}
|
|
|
|
function log_error(msg: string, p: PluginState)
|
|
{
|
|
Log::write(LOG, [$ts=network_time(), $category=ERROR, $msg=msg, $plugin=p$plugin$name(p)]);
|
|
}
|
|
|
|
function log_msg_no_plugin(msg: string)
|
|
{
|
|
Log::write(LOG, [$ts=network_time(), $category=MESSAGE, $msg=msg]);
|
|
}
|
|
|
|
function log_rule(r: Rule, cmd: string, state: InfoState, p: PluginState, msg: string &default="")
|
|
{
|
|
local info: Info = [$ts=network_time()];
|
|
info$category = RULE;
|
|
info$cmd = cmd;
|
|
info$state = state;
|
|
info$plugin = p$plugin$name(p);
|
|
if ( msg != "" )
|
|
info$msg = msg;
|
|
|
|
rule_to_info(info, r);
|
|
|
|
Log::write(LOG, info);
|
|
}
|
|
|
|
function log_rule_error(r: Rule, msg: string, p: PluginState)
|
|
{
|
|
local info: Info = [$ts=network_time(), $category=ERROR, $msg=msg, $plugin=p$plugin$name(p)];
|
|
rule_to_info(info, r);
|
|
Log::write(LOG, info);
|
|
}
|
|
|
|
function log_rule_no_plugin(r: Rule, state: InfoState, msg: string)
|
|
{
|
|
local info: Info = [$ts=network_time()];
|
|
info$category = RULE;
|
|
info$state = state;
|
|
info$msg = msg;
|
|
|
|
rule_to_info(info, r);
|
|
|
|
Log::write(LOG, info);
|
|
}
|
|
|
|
function whitelist_address(a: addr, t: interval, location: string &default="") : string
|
|
{
|
|
local e: Entity = [$ty=ADDRESS, $ip=addr_to_subnet(a)];
|
|
local r: Rule = [$ty=WHITELIST, $priority=whitelist_priority, $target=FORWARD, $entity=e, $expire=t, $location=location];
|
|
|
|
return add_rule(r);
|
|
}
|
|
|
|
function whitelist_subnet(s: subnet, t: interval, location: string &default="") : string
|
|
{
|
|
local e: Entity = [$ty=ADDRESS, $ip=s];
|
|
local r: Rule = [$ty=WHITELIST, $priority=whitelist_priority, $target=FORWARD, $entity=e, $expire=t, $location=location];
|
|
|
|
return add_rule(r);
|
|
}
|
|
|
|
|
|
function redirect_flow(f: flow_id, out_port: count, t: interval, location: string &default="") : string
|
|
{
|
|
local flow = NetControl::Flow(
|
|
$src_h=addr_to_subnet(f$src_h),
|
|
$src_p=f$src_p,
|
|
$dst_h=addr_to_subnet(f$dst_h),
|
|
$dst_p=f$dst_p
|
|
);
|
|
local e: Entity = [$ty=FLOW, $flow=flow];
|
|
local r: Rule = [$ty=REDIRECT, $target=FORWARD, $entity=e, $expire=t, $location=location, $out_port=out_port];
|
|
|
|
return add_rule(r);
|
|
}
|
|
|
|
function quarantine_host(infected: addr, dns: addr, quarantine: addr, t: interval, location: string &default="") : vector of string
|
|
{
|
|
local orules: vector of string = vector();
|
|
local edrop: Entity = [$ty=FLOW, $flow=Flow($src_h=addr_to_subnet(infected))];
|
|
local rdrop: Rule = [$ty=DROP, $target=FORWARD, $entity=edrop, $expire=t, $location=location];
|
|
orules[|orules|] = add_rule(rdrop);
|
|
|
|
local todnse: Entity = [$ty=FLOW, $flow=Flow($src_h=addr_to_subnet(infected), $dst_h=addr_to_subnet(dns), $dst_p=53/udp)];
|
|
local todnsr = Rule($ty=MODIFY, $target=FORWARD, $entity=todnse, $expire=t, $location=location, $mod=FlowMod($dst_h=quarantine), $priority=+5);
|
|
orules[|orules|] = add_rule(todnsr);
|
|
|
|
local fromdnse: Entity = [$ty=FLOW, $flow=Flow($src_h=addr_to_subnet(dns), $src_p=53/udp, $dst_h=addr_to_subnet(infected))];
|
|
local fromdnsr = Rule($ty=MODIFY, $target=FORWARD, $entity=fromdnse, $expire=t, $location=location, $mod=FlowMod($src_h=dns), $priority=+5);
|
|
orules[|orules|] = add_rule(fromdnsr);
|
|
|
|
local wle: Entity = [$ty=FLOW, $flow=Flow($src_h=addr_to_subnet(infected), $dst_h=addr_to_subnet(quarantine), $dst_p=80/tcp)];
|
|
local wlr = Rule($ty=WHITELIST, $target=FORWARD, $entity=wle, $expire=t, $location=location, $priority=+5);
|
|
orules[|orules|] = add_rule(wlr);
|
|
|
|
return orules;
|
|
}
|
|
|
|
function check_plugins()
|
|
{
|
|
if ( plugins_active )
|
|
return;
|
|
|
|
local all_active = T;
|
|
for ( i in plugins )
|
|
{
|
|
local p = plugins[i];
|
|
if ( p$_activated == F )
|
|
all_active = F;
|
|
}
|
|
|
|
if ( all_active )
|
|
{
|
|
plugins_active = T;
|
|
log_msg_no_plugin("plugin initialization done");
|
|
event NetControl::init_done();
|
|
}
|
|
}
|
|
|
|
function plugin_activated(p: PluginState)
|
|
{
|
|
local id = p$_id;
|
|
if ( id !in plugin_ids )
|
|
{
|
|
log_error("unknown plugin activated", p);
|
|
return;
|
|
}
|
|
plugin_ids[id]$_activated = T;
|
|
log_msg("activation finished", p);
|
|
|
|
if ( bro_init_done )
|
|
check_plugins();
|
|
}
|
|
|
|
event bro_init() &priority=-5
|
|
{
|
|
event NetControl::init();
|
|
}
|
|
|
|
event NetControl::init() &priority=-20
|
|
{
|
|
bro_init_done = T;
|
|
|
|
check_plugins();
|
|
|
|
if ( plugins_active == F )
|
|
log_msg_no_plugin("waiting for plugins to initialize");
|
|
}
|
|
|
|
# Low-level functions that only runs on the manager (or standalone) Bro node.
|
|
|
|
function activate_impl(p: PluginState, priority: int)
|
|
{
|
|
p$_priority = priority;
|
|
plugins[|plugins|] = p;
|
|
sort(plugins, function(p1: PluginState, p2: PluginState) : int { return p2$_priority - p1$_priority; });
|
|
|
|
plugin_ids[plugin_counter] = p;
|
|
p$_id = plugin_counter;
|
|
++plugin_counter;
|
|
|
|
# perform one-time initialization
|
|
if ( p$plugin?$init )
|
|
{
|
|
log_msg(fmt("activating plugin with priority %d", priority), p);
|
|
p$plugin$init(p);
|
|
}
|
|
else
|
|
{
|
|
# no initialization necessary, mark plugin as active right away
|
|
plugin_activated(p);
|
|
}
|
|
|
|
}
|
|
|
|
function add_rule_impl(rule: Rule) : string
|
|
{
|
|
if ( ! plugins_active )
|
|
{
|
|
log_rule_no_plugin(rule, FAILED, "plugins not initialized yet");
|
|
return "";
|
|
}
|
|
|
|
rule$cid = ++rule_counter; # numeric id that can be used by plugins for their rules.
|
|
|
|
if ( ! rule?$id || rule$id == "" )
|
|
rule$id = cat(rule$cid);
|
|
|
|
if ( ! hook NetControl::rule_policy(rule) )
|
|
return "";
|
|
|
|
local accepted = F;
|
|
local priority: int = +0;
|
|
local r = rule;
|
|
|
|
for ( i in plugins )
|
|
{
|
|
local p = plugins[i];
|
|
|
|
if ( p$_activated == F )
|
|
next;
|
|
|
|
# in this case, rule was accepted by earlier plugin and thus plugin has same
|
|
# priority. accept, but give out new rule id.
|
|
if ( accepted == T && p$_priority == priority )
|
|
{
|
|
r = copy(rule);
|
|
r$cid = ++rule_counter;
|
|
}
|
|
else if ( accepted == T )
|
|
# in this case, rule was accepted by earlier plugin and this plugin has a lower
|
|
# priority. Abort and do not send there...
|
|
break;
|
|
|
|
# set before, in case the plugins sends and regenerates the plugin record later.
|
|
r$_plugin_id = p$_id;
|
|
|
|
if ( p$plugin$add_rule(p, r) )
|
|
{
|
|
accepted = T;
|
|
priority = p$_priority;
|
|
log_rule(r, "ADD", REQUESTED, p);
|
|
}
|
|
}
|
|
|
|
if ( accepted )
|
|
return rule$id;
|
|
|
|
log_rule_no_plugin(r, FAILED, "not supported");
|
|
return "";
|
|
}
|
|
|
|
function remove_single_rule(id: string, cid: count) : bool
|
|
{
|
|
if ( [id,cid] !in rules )
|
|
{
|
|
Reporter::error(fmt("Rule %s -- %d does not exist in NetControl::remove_single_rule", id, cid));
|
|
return F;
|
|
}
|
|
|
|
local r = rules[id,cid];
|
|
local p = plugin_ids[r$_plugin_id];
|
|
|
|
# remove the respective rules from its plugins..
|
|
if ( ! p$plugin$remove_rule(p, r) )
|
|
{
|
|
log_rule_error(r, "remove failed", p);
|
|
return F;
|
|
}
|
|
|
|
log_rule(r, "REMOVE", REQUESTED, p);
|
|
return T;
|
|
}
|
|
|
|
function remove_rule_impl(id: string) : bool
|
|
{
|
|
if ( id !in id_to_cids )
|
|
{
|
|
Reporter::error(fmt("Rule %s does not exist in NetControl::remove_rule", id));
|
|
return F;
|
|
}
|
|
|
|
local cids = id_to_cids[id];
|
|
|
|
local success = T;
|
|
for ( cid in cids )
|
|
{
|
|
if ( [id,cid] !in rules )
|
|
{
|
|
Reporter::error(fmt("Internal error in netcontrol::remove_rule - cid %d does not belong to rule %s", cid, id));
|
|
delete cids[cid];
|
|
next;
|
|
}
|
|
|
|
if ( ! remove_single_rule(id, cid) )
|
|
success = F;
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
function rule_expire_impl(r: Rule, p: PluginState) &priority=-5
|
|
{
|
|
if ( [r$id,r$cid] !in rules )
|
|
# Removed already.
|
|
return;
|
|
|
|
event rule_timeout(r, FlowInfo(), p);
|
|
remove_single_rule(r$id, r$cid);
|
|
}
|
|
|
|
function rule_added_impl(r: Rule, p: PluginState, msg: string &default="")
|
|
{
|
|
log_rule(r, "ADD", SUCCEEDED, p, msg);
|
|
|
|
rules[r$id,r$cid] = r;
|
|
if ( r$id !in id_to_cids )
|
|
id_to_cids[r$id] = set();
|
|
|
|
add id_to_cids[r$id][r$cid];
|
|
}
|
|
|
|
function rule_removed_impl(r: Rule, p: PluginState, msg: string &default="")
|
|
{
|
|
if ( [r$id,r$cid] !in rules )
|
|
{
|
|
log_rule_error(r, "Removal of non-existing rule", p);
|
|
return;
|
|
}
|
|
|
|
delete rules[r$id,r$cid];
|
|
delete id_to_cids[r$id][r$cid];
|
|
if ( |id_to_cids[r$id]| == 0 )
|
|
delete id_to_cids[r$id];
|
|
|
|
log_rule(r, "REMOVE", SUCCEEDED, p, msg);
|
|
}
|
|
|
|
function rule_timeout_impl(r: Rule, i: FlowInfo, p: PluginState)
|
|
{
|
|
delete rules[r$id,r$cid];
|
|
delete id_to_cids[r$id][r$cid];
|
|
if ( |id_to_cids[r$id]| == 0 )
|
|
delete id_to_cids[r$id];
|
|
|
|
local msg = "";
|
|
if ( i?$packet_count )
|
|
msg = fmt("Packets: %d", i$packet_count);
|
|
if ( i?$byte_count )
|
|
{
|
|
if ( msg != "" )
|
|
msg = msg + " ";
|
|
msg = fmt("%sBytes: %s", msg, i$byte_count);
|
|
}
|
|
|
|
log_rule(r, "EXPIRE", TIMEOUT, p, msg);
|
|
}
|
|
|
|
function rule_error_impl(r: Rule, p: PluginState, msg: string &default="")
|
|
{
|
|
log_rule_error(r, msg, p);
|
|
# errors can occur during deletion. Since this probably means we wo't hear
|
|
# from it again, let's just remove it if it exists...
|
|
delete rules[r$id,r$cid];
|
|
delete id_to_cids[r$id][r$cid];
|
|
if ( |id_to_cids[r$id]| == 0 )
|
|
delete id_to_cids[r$id];
|
|
}
|
|
|
|
function clear()
|
|
{
|
|
for ( [id,cid] in rules )
|
|
remove_single_rule(id, cid);
|
|
}
|