Extend NetControl logging and fix bugs.

Netcontrol log now includes more information; before that, it had not
quite caught up to the new capabilities (like flow modifying and
redirection, as well as mac addresses).

Furthermore, this fixes a number of bugs with cluster mode (like
duplicate events), test failures due to updates in Bro, etc.
This commit is contained in:
Johanna Amann 2016-02-11 19:45:30 -08:00
parent 9f3c0c9bb4
commit a38327bd08
38 changed files with 466 additions and 267 deletions

View file

@ -64,3 +64,34 @@ event NetControl::cluster_netcontrol_remove_rule(id: string)
remove_rule_impl(id);
}
@endif
@if ( Cluster::local_node_type() == Cluster::MANAGER )
event rule_expire(r: Rule, p: PluginState) &priority=-5
{
rule_expire_impl(r, p);
}
event rule_added(r: Rule, p: PluginState, msg: string &default="") &priority=5
{
rule_added_impl(r, p, msg);
if ( r?$expire && ! p$plugin$can_expire )
schedule r$expire { rule_expire(r, p) };
}
event rule_removed(r: Rule, p: PluginState, msg: string &default="") &priority=-5
{
rule_removed_impl(r, p, msg);
}
event rule_timeout(r: Rule, i: FlowInfo, p: PluginState) &priority=-5
{
rule_timeout_impl(r, i, p);
}
event rule_error(r: Rule, p: PluginState, msg: string &default="") &priority=-5
{
rule_error_impl(r, p, msg);
}
@endif

View file

@ -116,7 +116,7 @@ export {
## 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) : vector of string;
global quarantine_host: function(infected: addr, dns: addr, quarantine: addr, t: interval, location: string &default="") : vector of string;
## Flushes all state.
global clear: function();
@ -197,7 +197,7 @@ export {
## r: The rule to be added
global NetControl::rule_policy: hook(r: Rule);
## Type of an entry in the PACF log.
## Type of an entry in the NetControl log.
type InfoCategory: enum {
## A log entry reflecting a framework message.
MESSAGE,
@ -207,7 +207,7 @@ export {
RULE
};
## State of an entry in the PACF log.
## State of an entry in the NetControl log.
type InfoState: enum {
REQUESTED,
SUCCEEDED,
@ -216,10 +216,12 @@ export {
TIMEOUT,
};
## The record type which contains column fields of the PACF log.
## 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.
@ -234,14 +236,24 @@ export {
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;
## Logcation where the underlying action was triggered.
## 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;
};
# type ShuntInfo: record {
# ## Time at which the recorded activity occurred.
# ts: time &log;
## 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);
@ -262,6 +274,7 @@ 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"]);
# Log::create_stream(NetControl::SHUNT, [$columns=ShuntInfo, $ev=log_netcontrol_shung, $path="netcontrol_shunt"]);
}
function entity_to_info(info: Info, e: Entity)
@ -284,6 +297,8 @@ function entity_to_info(info: Info, e: Entity)
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 )
@ -295,6 +310,15 @@ function entity_to_info(info: Info, e: Entity)
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:
@ -311,10 +335,46 @@ 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 )
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);
}
@ -328,13 +388,15 @@ function log_error(msg: string, p: PluginState)
Log::write(LOG, [$ts=network_time(), $category=ERROR, $msg=msg, $plugin=p$plugin$name(p)]);
}
function log_rule(r: Rule, cmd: string, state: InfoState, p: PluginState)
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);
@ -415,7 +477,7 @@ function redirect_flow(f: flow_id, out_port: count, t: interval, location: strin
$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, $c=out_port];
local r: Rule = [$ty=REDIRECT, $target=FORWARD, $entity=e, $expire=t, $location=location, $out_port=out_port];
return add_rule(r);
}
@ -559,7 +621,7 @@ function remove_rule_impl(id: string) : bool
return success;
}
event rule_expire(r: Rule, p: PluginState)
function rule_expire_impl(r: Rule, p: PluginState) &priority=-5
{
if ( [r$id,r$cid] !in rules )
# Removed already.
@ -569,41 +631,54 @@ event rule_expire(r: Rule, p: PluginState)
remove_single_rule(r$id, r$cid);
}
event rule_added(r: Rule, p: PluginState, msg: string &default="")
function rule_added_impl(r: Rule, p: PluginState, msg: string &default="")
{
log_rule(r, "ADD", SUCCEEDED, p);
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];
if ( r?$expire && ! p$plugin$can_expire )
schedule r$expire { rule_expire(r, p) };
}
event rule_removed(r: Rule, p: PluginState, msg: string &default="")
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];
log_rule(r, "REMOVE", SUCCEEDED, p);
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);
}
event rule_timeout(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];
log_rule(r, "EXPIRE", TIMEOUT, p);
}
event rule_error(r: Rule, p: PluginState, msg: string &default="")
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

View file

@ -16,3 +16,32 @@ function remove_rule(id: string) : bool
{
return remove_rule_impl(id);
}
event rule_expire(r: Rule, p: PluginState) &priority=-5
{
rule_expire_impl(r, p);
}
event rule_added(r: Rule, p: PluginState, msg: string &default="") &priority=5
{
rule_added_impl(r, p, msg);
if ( r?$expire && ! p$plugin$can_expire )
schedule r$expire { rule_expire(r, p) };
}
event rule_removed(r: Rule, p: PluginState, msg: string &default="") &priority=-5
{
rule_removed_impl(r, p, msg);
}
event rule_timeout(r: Rule, i: FlowInfo, p: PluginState) &priority=-5
{
rule_timeout_impl(r, i, p);
}
event rule_error(r: Rule, p: PluginState, msg: string &default="") &priority=-5
{
rule_error_impl(r, p, msg);
}

View file

@ -99,7 +99,7 @@ event NetControl::acld_rule_error(id: count, r: Rule, msg: string)
function acld_name(p: PluginState) : string
{
return fmt("PACF acld plugin - using broker topic %s", p$acld_config$acld_topic);
return fmt("Acld-%s", p$acld_config$acld_topic);
}
# check that subnet specifies an addr

View file

@ -89,7 +89,7 @@ event NetControl::broker_rule_timeout(id: count, r: Rule, i: FlowInfo)
function broker_name(p: PluginState) : string
{
return fmt("PACF Broker plugin - topic %s", p$broker_topic);
return fmt("Broker-%s", p$broker_topic);
}
function broker_add_rule_fun(p: PluginState, r: Rule) : bool

View file

@ -4,7 +4,7 @@
module NetControl;
export {
## Instantiates a debug plugin for the PACF framework. The debug
## Instantiates a debug plugin for the NetControl framework. The debug
## plugin simply logs the operations it receives.
##
## do_something: If true, the plugin will claim it supports all operations; if

View file

@ -41,7 +41,7 @@ export {
## buildup for quite a while if keeping this around...
const openflow_flow_timeout = 24hrs &redef;
## Instantiates an openflow plugin for the PACF framework.
## Instantiates an openflow plugin for the NetControl framework.
global create_openflow: function(controller: OpenFlow::Controller, config: OfConfig &default=[]) : PluginState;
}
@ -62,7 +62,7 @@ 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));
return fmt("Openflow-%s", p$of_controller$describe(p$of_controller$state));
}
function openflow_check_rule(p: PluginState, r: Rule) : bool
@ -256,7 +256,7 @@ function openflow_rule_to_flow_mod(p: PluginState, r: Rule) : OpenFlow::ofp_flow
else if ( r$ty == REDIRECT )
{
# redirect to port c
flow_mod$actions$out_ports = vector(r$c);
flow_mod$actions$out_ports = vector(r$out_port);
}
else
{

View file

@ -1,4 +1,4 @@
# PACF plugin for the PacketFilter handling that comes with
# NetControl 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.
@ -67,7 +67,7 @@ function packetfilter_remove_rule(p: PluginState, r: Rule) : bool
{
if ( ! packetfilter_check_rule(r) )
return F;
local e = r$entity;
if ( e$ty == ADDRESS )
{
@ -92,7 +92,7 @@ function packetfilter_remove_rule(p: PluginState, r: Rule) : bool
function packetfilter_name(p: PluginState) : string
{
return "PACF plugin for the Bro packetfilter";
return "Packetfilter";
}
global packetfilter_plugin = Plugin(

View file

@ -89,10 +89,7 @@ export {
priority: int &default=default_priority; ##< Priority if multiple rules match an entity (larger value is higher priority).
location: string &optional; ##< Optional string describing where/what installed the rule.
c: count &optional; ##< Argument for rule types requiring an count argument.
i: int &optional; ##< Argument for rule types requiring an integer argument.
d: double &optional; ##< Argument for rule types requiring a double argument.
s: string &optional; ##< Argument for rule types requiring a string argument.
out_port: count &optional; ##< Argument for bro:id:`REDIRECT` rules.
mod: FlowMod &optional; ##< Argument for :bro:id:`MODIFY` rules.
id: string &default=""; ##< Internally determined unique ID for this rule. Will be set when added.

View file

@ -38,7 +38,7 @@ export {
function broker_describe(state: ControllerState): string
{
return fmt("Broker Plugin - %s:%d - DPID: %d", state$broker_host, state$broker_port, state$broker_dpid);
return fmt("Broker-%s:%d-%d", state$broker_host, state$broker_port, state$broker_dpid);
}
function broker_flow_mod_fun(state: ControllerState, match: ofp_match, flow_mod: OpenFlow::ofp_flow_mod): bool

View file

@ -62,7 +62,7 @@ function log_flow_mod(state: ControllerState, match: ofp_match, flow_mod: OpenFl
function log_describe(state: ControllerState): string
{
return fmt("OpenFlog Log Plugin - DPID %d", state$log_dpid);
return fmt("Log-%d", state$log_dpid);
}
function log_new(dpid: count, success_event: bool &default=T): OpenFlow::Controller

View file

@ -173,7 +173,7 @@ function ryu_flow_clear(state: OpenFlow::ControllerState): bool
function ryu_describe(state: ControllerState): string
{
return fmt("Ryu Plugin - http://%s:%d - DPID: %d", state$ryu_host, state$ryu_port, state$ryu_dpid);
return fmt("Ryu-%d-http://%s:%d", state$ryu_dpid, state$ryu_host, state$ryu_port);
}
# Ryu controller constructor