From 0bac1faa0967dc0071cb90ca82bd0bd3d35b5689 Mon Sep 17 00:00:00 2001 From: Johanna Amann Date: Mon, 14 Mar 2016 18:48:49 -0700 Subject: [PATCH 01/13] NetControl: add predicates to broker plugin I apparently just forgot to add these. --- scripts/base/frameworks/netcontrol/README | 3 + scripts/base/frameworks/netcontrol/main.bro | 2 +- .../base/frameworks/netcontrol/plugins/README | 1 + .../frameworks/netcontrol/plugins/broker.bro | 62 +++++++++++++++---- scripts/base/frameworks/openflow/README | 2 + .../base/frameworks/openflow/plugins/README | 1 + 6 files changed, 59 insertions(+), 12 deletions(-) create mode 100644 scripts/base/frameworks/netcontrol/README create mode 100644 scripts/base/frameworks/netcontrol/plugins/README create mode 100644 scripts/base/frameworks/openflow/README create mode 100644 scripts/base/frameworks/openflow/plugins/README diff --git a/scripts/base/frameworks/netcontrol/README b/scripts/base/frameworks/netcontrol/README new file mode 100644 index 0000000000..a8635da300 --- /dev/null +++ b/scripts/base/frameworks/netcontrol/README @@ -0,0 +1,3 @@ +The NetControl framework provides a way for Bro to interact with networking +hard- and software, e.g. for dropping and shunting IP addresses/connections, +etc. diff --git a/scripts/base/frameworks/netcontrol/main.bro b/scripts/base/frameworks/netcontrol/main.bro index 563188921d..e381931643 100644 --- a/scripts/base/frameworks/netcontrol/main.bro +++ b/scripts/base/frameworks/netcontrol/main.bro @@ -1,4 +1,4 @@ -##! Bro's packet aquisition and control framework. +##! Bro's NetControl 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 diff --git a/scripts/base/frameworks/netcontrol/plugins/README b/scripts/base/frameworks/netcontrol/plugins/README new file mode 100644 index 0000000000..12af1779c9 --- /dev/null +++ b/scripts/base/frameworks/netcontrol/plugins/README @@ -0,0 +1 @@ +Plugins for the NetControl framework diff --git a/scripts/base/frameworks/netcontrol/plugins/broker.bro b/scripts/base/frameworks/netcontrol/plugins/broker.bro index 619b6b607b..25430d2da4 100644 --- a/scripts/base/frameworks/netcontrol/plugins/broker.bro +++ b/scripts/base/frameworks/netcontrol/plugins/broker.bro @@ -12,15 +12,33 @@ 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 += { + type BrokerConfig: record { ## The broker topic used to send events to - broker_topic: string &optional; + topic: string &optional; ## The ID of this broker instance - for the mapping to PluginStates - broker_id: count &optional; + id: count &optional; ## Broker host to connect to - broker_host: addr &optional; + host: addr &optional; ## Broker port to connect to - broker_port: port &optional; + bport: port &optional; + + ## Do we accept rules for the monitor path? Default true + monitor: bool &default=T; + ## 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; + }; + + redef record PluginState += { + broker_config: BrokerConfig &optional; }; global broker_add_rule: event(id: count, r: Rule); @@ -91,26 +109,48 @@ event NetControl::broker_rule_timeout(id: count, r: Rule, i: FlowInfo) function broker_name(p: PluginState) : string { - return fmt("Broker-%s", p$broker_topic); + return fmt("Broker-%s", p$broker_config$topic); + } + +function broker_check_rule(p: PluginState, r: Rule) : bool + { + local c = p$broker_config; + + if ( p$broker_config?$check_pred ) + return p$broker_config$check_pred(p, r); + + if ( r$target == MONITOR && c$monitor ) + return T; + + if ( r$target == FORWARD && c$forward ) + return T; + + return F; } 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)); + if ( ! broker_check_rule(p, r) ) + return F; + + BrokerComm::event(p$broker_config$topic, BrokerComm::event_args(broker_add_rule, p$broker_config$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)); + if ( ! broker_check_rule(p, r) ) + return F; + + BrokerComm::event(p$broker_config$topic, BrokerComm::event_args(broker_remove_rule, p$broker_config$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); + BrokerComm::connect(cat(p$broker_config$host), p$broker_config$bport, 1sec); + BrokerComm::subscribe_to_events(p$broker_config$topic); } event BrokerComm::outgoing_connection_established(peer_address: string, peer_port: port, peer_name: string) @@ -149,7 +189,7 @@ function create_broker(host: addr, host_port: port, topic: string, can_expire: b 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]; + local p = PluginState($plugin=plugin, $broker_config=BrokerConfig($host=host, $bport=host_port, $topic=topic, $id=netcontrol_broker_current_id)); if ( [host_port, cat(host)] in netcontrol_broker_peers ) Reporter::warning(fmt("Peer %s:%s was added to NetControl broker plugin twice.", host, host_port)); diff --git a/scripts/base/frameworks/openflow/README b/scripts/base/frameworks/openflow/README new file mode 100644 index 0000000000..87fbc8b3cb --- /dev/null +++ b/scripts/base/frameworks/openflow/README @@ -0,0 +1,2 @@ +The OpenFlow framework exposes the datastructures and functions +necessary to interface to OpenFlow capable hardware. diff --git a/scripts/base/frameworks/openflow/plugins/README b/scripts/base/frameworks/openflow/plugins/README new file mode 100644 index 0000000000..d2f38e9e82 --- /dev/null +++ b/scripts/base/frameworks/openflow/plugins/README @@ -0,0 +1 @@ +Plugins for the OpenFlow framework. From 06414e5c4029c054580ba717e9b2f279e775fd69 Mon Sep 17 00:00:00 2001 From: Johanna Amann Date: Mon, 14 Mar 2016 21:10:12 -0700 Subject: [PATCH 02/13] NetControl: make new broker plugin options accessible --- .../frameworks/netcontrol/plugins/broker.bro | 30 +++++++++---------- .../base/frameworks/netcontrol/broker.bro | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/scripts/base/frameworks/netcontrol/plugins/broker.bro b/scripts/base/frameworks/netcontrol/plugins/broker.bro index 25430d2da4..4d4a0b481a 100644 --- a/scripts/base/frameworks/netcontrol/plugins/broker.bro +++ b/scripts/base/frameworks/netcontrol/plugins/broker.bro @@ -9,14 +9,9 @@ module NetControl; @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; - type BrokerConfig: record { ## The broker topic used to send events to topic: string &optional; - ## The ID of this broker instance - for the mapping to PluginStates - id: count &optional; ## Broker host to connect to host: addr &optional; ## Broker port to connect to @@ -37,8 +32,13 @@ export { check_pred: function(p: PluginState, r: Rule): bool &optional; }; + ## Instantiates the broker plugin. + global create_broker: function(config: BrokerConfig, can_expire: bool) : PluginState; + redef record PluginState += { broker_config: BrokerConfig &optional; + ## The ID of this broker instance - for the mapping to PluginStates + broker_id: count &optional; }; global broker_add_rule: event(id: count, r: Rule); @@ -133,7 +133,7 @@ function broker_add_rule_fun(p: PluginState, r: Rule) : bool if ( ! broker_check_rule(p, r) ) return F; - BrokerComm::event(p$broker_config$topic, BrokerComm::event_args(broker_add_rule, p$broker_config$id, r)); + BrokerComm::event(p$broker_config$topic, BrokerComm::event_args(broker_add_rule, p$broker_id, r)); return T; } @@ -142,7 +142,7 @@ function broker_remove_rule_fun(p: PluginState, r: Rule) : bool if ( ! broker_check_rule(p, r) ) return F; - BrokerComm::event(p$broker_config$topic, BrokerComm::event_args(broker_remove_rule, p$broker_config$id, r)); + BrokerComm::event(p$broker_config$topic, BrokerComm::event_args(broker_remove_rule, p$broker_id, r)); return T; } @@ -178,23 +178,23 @@ global broker_plugin_can_expire = Plugin( $init = broker_init ); -function create_broker(host: addr, host_port: port, topic: string, can_expire: bool &default=F) : PluginState +function create_broker(config: BrokerConfig, can_expire: bool) : PluginState { - if ( topic in netcontrol_broker_topics ) - Reporter::warning(fmt("Topic %s was added to NetControl broker plugin twice. Possible duplication of commands", topic)); + if ( config$topic in netcontrol_broker_topics ) + Reporter::warning(fmt("Topic %s was added to NetControl broker plugin twice. Possible duplication of commands", config$topic)); else - add netcontrol_broker_topics[topic]; + add netcontrol_broker_topics[config$topic]; local plugin = broker_plugin; if ( can_expire ) plugin = broker_plugin_can_expire; - local p = PluginState($plugin=plugin, $broker_config=BrokerConfig($host=host, $bport=host_port, $topic=topic, $id=netcontrol_broker_current_id)); + local p = PluginState($plugin=plugin, $broker_id=netcontrol_broker_current_id, $broker_config=config); - if ( [host_port, cat(host)] in netcontrol_broker_peers ) - Reporter::warning(fmt("Peer %s:%s was added to NetControl broker plugin twice.", host, host_port)); + if ( [config$bport, cat(config$host)] in netcontrol_broker_peers ) + Reporter::warning(fmt("Peer %s:%s was added to NetControl broker plugin twice.", config$host, config$bport)); else - netcontrol_broker_peers[host_port, cat(host)] = p; + netcontrol_broker_peers[config$bport, cat(config$host)] = p; netcontrol_broker_id[netcontrol_broker_current_id] = p; ++netcontrol_broker_current_id; diff --git a/testing/btest/scripts/base/frameworks/netcontrol/broker.bro b/testing/btest/scripts/base/frameworks/netcontrol/broker.bro index 56a76433f2..6b1474c3e3 100644 --- a/testing/btest/scripts/base/frameworks/netcontrol/broker.bro +++ b/testing/btest/scripts/base/frameworks/netcontrol/broker.bro @@ -18,7 +18,7 @@ redef exit_only_after_terminate = T; event NetControl::init() { suspend_processing(); - local netcontrol_broker = NetControl::create_broker(127.0.0.1, broker_port, "bro/event/netcontroltest", T); + local netcontrol_broker = NetControl::create_broker(NetControl::BrokerConfig($host=127.0.0.1, $bport=broker_port, $topic="bro/event/netcontroltest"), T); NetControl::activate(netcontrol_broker, 0); } From bbbfac3af9c77fb6e7e4b109a270c4d3d04db47b Mon Sep 17 00:00:00 2001 From: Johanna Amann Date: Wed, 16 Mar 2016 10:36:12 -0700 Subject: [PATCH 03/13] NetControl: Suppress duplicate "plugin activated" messages. --- scripts/base/frameworks/netcontrol/main.bro | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/base/frameworks/netcontrol/main.bro b/scripts/base/frameworks/netcontrol/main.bro index e381931643..d2510f3c58 100644 --- a/scripts/base/frameworks/netcontrol/main.bro +++ b/scripts/base/frameworks/netcontrol/main.bro @@ -532,6 +532,11 @@ function plugin_activated(p: PluginState) log_error("unknown plugin activated", p); return; } + + # Suppress duplicate activation + if ( plugin_ids[id]$_activated == T ) + return; + plugin_ids[id]$_activated = T; log_msg("activation finished", p); From 34ad4cf6384e4922efc26636eb542a890a9e00f4 Mon Sep 17 00:00:00 2001 From: Johanna Amann Date: Thu, 24 Mar 2016 15:06:07 -0700 Subject: [PATCH 04/13] NetControl: add rule exists as state besides added and failure. Rules that are already existing will, by default, not automatically be timed out by NetControl. --- .../base/frameworks/netcontrol/cluster.bro | 34 +++++++- scripts/base/frameworks/netcontrol/main.bro | 86 ++++++++++++++++--- .../frameworks/netcontrol/non-cluster.bro | 15 +++- .../frameworks/netcontrol/plugins/acld.bro | 14 +++ .../frameworks/netcontrol/plugins/broker.bro | 14 +++ .../send.netcontrol.log | 25 ++++++ .../send.send.out | 2 +- .../.stdout | 20 ++--- .../recv.recv.out | 1 - .../send.netcontrol.log | 25 +++--- .../send.send.out | 6 +- .../.stdout | 16 ++-- .../netcontrol.log | 5 +- .../netcontrol.log | 5 +- .../netcontrol.log | 5 +- .../base/frameworks/netcontrol/acld.bro | 12 ++- .../base/frameworks/netcontrol/broker.bro | 14 ++- 17 files changed, 230 insertions(+), 69 deletions(-) create mode 100644 testing/btest/Baseline/scripts.base.frameworks.netcontrol.acld/send.netcontrol.log diff --git a/scripts/base/frameworks/netcontrol/cluster.bro b/scripts/base/frameworks/netcontrol/cluster.bro index 7f635b4375..1f4738cf2e 100644 --- a/scripts/base/frameworks/netcontrol/cluster.bro +++ b/scripts/base/frameworks/netcontrol/cluster.bro @@ -11,13 +11,15 @@ export { ## This is the event used to transport remove_rule calls to the manager. global cluster_netcontrol_remove_rule: event(id: string); + + ## This is the event used to transport delete_rule calls to the manager. + global cluster_netcontrol_delete_rule: event(id: string); } ## Workers need ability to forward commands to manager. -redef Cluster::worker2manager_events += /NetControl::cluster_netcontrol_(add|remove)_rule/; +redef Cluster::worker2manager_events += /NetControl::cluster_netcontrol_(add|remove|delete)_rule/; ## Workers need to see the result events from the manager. -redef Cluster::manager2worker_events += /NetControl::rule_(added|removed|timeout|error)/; - +redef Cluster::manager2worker_events += /NetControl::rule_(added|removed|timeout|error|exists)/; function activate(p: PluginState, priority: int) { @@ -44,6 +46,17 @@ function add_rule(r: Rule) : string } } +function delete_rule(id: string) : bool + { + if ( Cluster::local_node_type() == Cluster::MANAGER ) + return delete_rule_impl(id); + else + { + event NetControl::cluster_netcontrol_delete_rule(id); + return T; # well, we can't know here. So - just hope... + } + } + function remove_rule(id: string) : bool { if ( Cluster::local_node_type() == Cluster::MANAGER ) @@ -56,6 +69,11 @@ function remove_rule(id: string) : bool } @if ( Cluster::local_node_type() == Cluster::MANAGER ) +event NetControl::cluster_netcontrol_delete_rule(id: string) + { + delete_rule_impl(id); + } + event NetControl::cluster_netcontrol_add_rule(r: Rule) { add_rule_impl(r); @@ -73,9 +91,17 @@ event rule_expire(r: Rule, p: PluginState) &priority=-5 rule_expire_impl(r, p); } +event rule_exists(r: Rule, p: PluginState, msg: string &default="") &priority=5 + { + rule_added_impl(r, p, T, msg); + + if ( r?$expire && r$expire > 0secs && ! p$plugin$can_expire ) + schedule r$expire { rule_expire(r, p) }; + } + event rule_added(r: Rule, p: PluginState, msg: string &default="") &priority=5 { - rule_added_impl(r, p, msg); + rule_added_impl(r, p, F, msg); if ( r?$expire && r$expire > 0secs && ! p$plugin$can_expire ) schedule r$expire { rule_expire(r, p) }; diff --git a/scripts/base/frameworks/netcontrol/main.bro b/scripts/base/frameworks/netcontrol/main.bro index d2510f3c58..be2d40fb18 100644 --- a/scripts/base/frameworks/netcontrol/main.bro +++ b/scripts/base/frameworks/netcontrol/main.bro @@ -126,6 +126,17 @@ export { ## asynchronously and thus go wrong at that point. global remove_rule: function(id: string) : bool; + ## Deletes a rule without removing in from the backends to which it has been + ## added before. This mean that no messages will be sent to the switches to which + ## the rule has been added; if it is not removed from them by a separate mechanism, + ## it will stay installed and not be removed later. + ## + ## id: The rule to delete, specified as the ID returned by :bro:id:`add_rule` . + ## + ## Returns: True if removal is successful, or sent to manager. + ## False if the rule could not be found. + global delete_rule: function(id: string) : bool; + ## Searches all rules affecting a certain IP address. ## ## ip: The ip address to search for @@ -151,6 +162,19 @@ export { ## msg: An optional informational message by the plugin. global rule_added: event(r: Rule, p: PluginState, msg: string &default=""); + ## Signals that a rule that was supposed to be put in place was already + ## existing at the specified plugin. Rules that already have been existing + ## continue to be tracked like normal, but no timeout calls will be sent + ## to the specified plugins. Removal of the rule from the hardware can + ## still be forced by manually issuing a remove_rule call. + ## + ## r: The rule that was already in place. + ## + ## p: The plugin that reported that the rule already was in place. + ## + ## msg: An optional informational message by the plugin. + global rule_exists: 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. @@ -211,6 +235,7 @@ export { type InfoState: enum { REQUESTED, SUCCEEDED, + EXISTS, FAILED, REMOVED, TIMEOUT, @@ -260,6 +285,8 @@ redef record Rule += { _plugin_ids: set[count] &default=count_set(); ##< Internally set to the plugins on which the rule is currently active. _active_plugin_ids: set[count] &default=count_set(); + ##< Internally set to plugins where the rule should not be removed upon timeout. + _no_expire_plugins: set[count] &default=count_set(); ##< Track if the rule was added succesfully by all responsible plugins. _added: bool &default=F; }; @@ -736,6 +763,29 @@ function add_rule_impl(rule: Rule) : string return ""; } +function rule_cleanup(r: Rule) + { + if ( |r$_active_plugin_ids| > 0 ) + return; + + remove_subnet_entry(r); + + delete rule_entities[r$entity, r$ty]; + delete rules[r$id]; + } + +function delete_rule_impl(id: string): bool + { + if ( id !in rules ) + return F; + + local rule = rules[id]; + + rule$_active_plugin_ids = set(); + + rule_cleanup(rule); + } + function remove_rule_plugin(r: Rule, p: PluginState): bool { local success = T; @@ -784,10 +834,21 @@ function rule_expire_impl(r: Rule, p: PluginState) &priority=-5 # Removed already. return; - event NetControl::rule_timeout(r, FlowInfo(), p); # timeout implementation will handle the removal + local rule = rules[r$id]; + + if ( p$_id in rule$_no_expire_plugins ) + { + # in this case - don't log anything, just remove the plugin from the rule + # and cleaup + delete rule$_active_plugin_ids[p$_id]; + delete rule$_no_expire_plugins[p$_id]; + rule_cleanup(rule); + } + else + event NetControl::rule_timeout(r, FlowInfo(), p); # timeout implementation will handle the removal } -function rule_added_impl(r: Rule, p: PluginState, msg: string &default="") +function rule_added_impl(r: Rule, p: PluginState, exists: bool, msg: string &default="") { if ( r$id !in rules ) { @@ -803,7 +864,15 @@ function rule_added_impl(r: Rule, p: PluginState, msg: string &default="") return; } - log_rule(r, "ADD", SUCCEEDED, p, msg); + # The rule was already existing on the backend. Mark this so we don't timeout + # it on this backend. + if ( exists ) + { + add rule$_no_expire_plugins[p$_id]; + log_rule(r, "ADD", EXISTS, p, msg); + } + else + log_rule(r, "ADD", SUCCEEDED, p, msg); add rule$_active_plugin_ids[p$_id]; if ( |rule$_plugin_ids| == |rule$_active_plugin_ids| ) @@ -813,17 +882,6 @@ function rule_added_impl(r: Rule, p: PluginState, msg: string &default="") } } -function rule_cleanup(r: Rule) - { - if ( |r$_active_plugin_ids| > 0 ) - return; - - remove_subnet_entry(r); - - delete rule_entities[r$entity, r$ty]; - delete rules[r$id]; - } - function rule_removed_impl(r: Rule, p: PluginState, msg: string &default="") { if ( r$id !in rules ) diff --git a/scripts/base/frameworks/netcontrol/non-cluster.bro b/scripts/base/frameworks/netcontrol/non-cluster.bro index 4098586be4..c7d579b0d5 100644 --- a/scripts/base/frameworks/netcontrol/non-cluster.bro +++ b/scripts/base/frameworks/netcontrol/non-cluster.bro @@ -12,6 +12,11 @@ function add_rule(r: Rule) : string return add_rule_impl(r); } +function delete_rule(id: string) : bool + { + return delete_rule_impl(id); + } + function remove_rule(id: string) : bool { return remove_rule_impl(id); @@ -22,9 +27,17 @@ event rule_expire(r: Rule, p: PluginState) &priority=-5 rule_expire_impl(r, p); } +event rule_exists(r: Rule, p: PluginState, msg: string &default="") &priority=5 + { + rule_added_impl(r, p, T, msg); + + if ( r?$expire && r$expire > 0secs && ! p$plugin$can_expire ) + schedule r$expire { rule_expire(r, p) }; + } + event rule_added(r: Rule, p: PluginState, msg: string &default="") &priority=5 { - rule_added_impl(r, p, msg); + rule_added_impl(r, p, F, msg); if ( r?$expire && r$expire > 0secs && ! p$plugin$can_expire ) schedule r$expire { rule_expire(r, p) }; diff --git a/scripts/base/frameworks/netcontrol/plugins/acld.bro b/scripts/base/frameworks/netcontrol/plugins/acld.bro index 76661bc857..6343bad335 100644 --- a/scripts/base/frameworks/netcontrol/plugins/acld.bro +++ b/scripts/base/frameworks/netcontrol/plugins/acld.bro @@ -64,6 +64,7 @@ export { ## Events that are sent from Broker to us 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_exists: event(id: count, r: Rule, msg: string); global acld_rule_error: event(id: count, r: Rule, msg: string); } @@ -98,6 +99,19 @@ event NetControl::acld_rule_added(id: count, r: Rule, msg: string) event NetControl::rule_added(r, p, msg); } +event NetControl::acld_rule_exists(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_exists(r, p, msg); + } + event NetControl::acld_rule_removed(id: count, r: Rule, msg: string) { if ( id !in netcontrol_acld_id ) diff --git a/scripts/base/frameworks/netcontrol/plugins/broker.bro b/scripts/base/frameworks/netcontrol/plugins/broker.bro index 4d4a0b481a..893814b428 100644 --- a/scripts/base/frameworks/netcontrol/plugins/broker.bro +++ b/scripts/base/frameworks/netcontrol/plugins/broker.bro @@ -46,6 +46,7 @@ export { 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_exists: 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); } @@ -68,6 +69,19 @@ event NetControl::broker_rule_added(id: count, r: Rule, msg: string) event NetControl::rule_added(r, p, msg); } +event NetControl::broker_rule_exists(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_exists(r, p, msg); + } + event NetControl::broker_rule_removed(id: count, r: Rule, msg: string) { if ( id !in netcontrol_broker_id ) diff --git a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.acld/send.netcontrol.log b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.acld/send.netcontrol.log new file mode 100644 index 0000000000..70c1a28ee2 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.acld/send.netcontrol.log @@ -0,0 +1,25 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path netcontrol +#open 2016-03-24-22-04-41 +#fields ts rule_id category cmd state action target entity_type entity mod msg priority expire location plugin +#types time string enum string enum string enum string string string string int interval string string +0.000000 - NetControl::MESSAGE - - - - - - - activating plugin with priority 0 - - - Acld-bro/event/netcontroltest +0.000000 - NetControl::MESSAGE - - - - - - - waiting for plugins to initialize - - - - +1458857080.863419 - NetControl::MESSAGE - - - - - - - activation finished - - - Acld-bro/event/netcontroltest +1458857080.863419 - NetControl::MESSAGE - - - - - - - plugin initialization done - - - - +1458857080.887618 2 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::FLOW 192.168.18.50/32/*->74.125.239.97/32/* - - 0 36000.000000 here Acld-bro/event/netcontroltest +1458857080.887618 3 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::FLOW */*->*/443 - - 0 36000.000000 there Acld-bro/event/netcontroltest +1458857080.887618 4 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 36000.000000 - Acld-bro/event/netcontroltest +1458857080.888169 2 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::FLOW 192.168.18.50/32/*->74.125.239.97/32/* - blockhosthost 0 36000.000000 here Acld-bro/event/netcontroltest +1458857080.888169 2 NetControl::RULE REMOVE NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::FLOW 192.168.18.50/32/*->74.125.239.97/32/* - - 0 36000.000000 here Acld-bro/event/netcontroltest +1458857080.888169 3 NetControl::RULE ADD NetControl::EXISTS NetControl::DROP NetControl::FORWARD NetControl::FLOW */*->*/443 - droptcpport 0 36000.000000 there Acld-bro/event/netcontroltest +1458857080.888169 3 NetControl::RULE REMOVE NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::FLOW */*->*/443 - - 0 36000.000000 there Acld-bro/event/netcontroltest +1458857080.888169 4 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - drop 0 36000.000000 - Acld-bro/event/netcontroltest +1458857080.888169 4 NetControl::RULE REMOVE NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 36000.000000 - Acld-bro/event/netcontroltest +1458857080.888169 2 NetControl::RULE REMOVE NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::FLOW 192.168.18.50/32/*->74.125.239.97/32/* - restorehosthost 0 36000.000000 here Acld-bro/event/netcontroltest +1458857080.888169 3 NetControl::RULE REMOVE NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::FLOW */*->*/443 - restoretcpport 0 36000.000000 there Acld-bro/event/netcontroltest +1458857080.888169 4 NetControl::RULE REMOVE NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - restore 0 36000.000000 - Acld-bro/event/netcontroltest +#close 2016-03-24-22-04-41 diff --git a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.acld/send.send.out b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.acld/send.send.out index fd7f00bb7c..9411a64a80 100644 --- a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.acld/send.send.out +++ b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.acld/send.send.out @@ -1,6 +1,6 @@ BrokerComm::outgoing_connection_established, 127.0.0.1, 9999/tcp rule added, [ty=NetControl::FLOW, conn=, flow=[src_h=192.168.18.50/32, src_p=, dst_h=74.125.239.97/32, dst_p=, src_m=, dst_m=], ip=, mac=], NetControl::DROP -rule added, [ty=NetControl::FLOW, conn=, flow=[src_h=, src_p=, dst_h=, dst_p=443/tcp, src_m=, dst_m=], ip=, mac=], NetControl::DROP +rule exists, [ty=NetControl::FLOW, conn=, flow=[src_h=, src_p=, dst_h=, dst_p=443/tcp, src_m=, dst_m=], ip=, mac=], NetControl::DROP rule added, [ty=NetControl::ADDRESS, conn=, flow=, ip=192.168.18.50/32, mac=], NetControl::DROP rule removed, [ty=NetControl::FLOW, conn=, flow=[src_h=192.168.18.50/32, src_p=, dst_h=74.125.239.97/32, dst_p=, src_m=, dst_m=], ip=, mac=], NetControl::DROP rule removed, [ty=NetControl::FLOW, conn=, flow=[src_h=, src_p=, dst_h=, dst_p=443/tcp, src_m=, dst_m=], ip=, mac=], NetControl::DROP diff --git a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.basic/.stdout b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.basic/.stdout index 846bb1b653..049f0eb0c6 100644 --- a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.basic/.stdout +++ b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.basic/.stdout @@ -1,11 +1,11 @@ netcontrol debug (Debug-All): init -netcontrol debug (Debug-All): add_rule: [ty=NetControl::DROP, target=NetControl::MONITOR, entity=[ty=NetControl::FLOW, conn=, flow=[src_h=192.168.17.1/32, src_p=32/tcp, dst_h=192.168.17.2/32, dst_p=32/tcp, src_m=, dst_m=], ip=, mac=], expire=30.0 secs, priority=0, location=, out_port=, mod=, id=2, cid=2, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _added=F] -netcontrol debug (Debug-All): add_rule: [ty=NetControl::DROP, target=NetControl::FORWARD, entity=[ty=NetControl::ADDRESS, conn=, flow=, ip=1.1.2.2/32, mac=], expire=15.0 secs, priority=0, location=Hi there, out_port=, mod=, id=3, cid=3, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _added=F] -netcontrol debug (Debug-All): add_rule: [ty=NetControl::WHITELIST, target=NetControl::FORWARD, entity=[ty=NetControl::ADDRESS, conn=, flow=, ip=1.2.3.4/32, mac=], expire=15.0 secs, priority=5, location=, out_port=, mod=, id=4, cid=4, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _added=F] -netcontrol debug (Debug-All): add_rule: [ty=NetControl::REDIRECT, target=NetControl::FORWARD, entity=[ty=NetControl::FLOW, conn=, flow=[src_h=192.168.17.1/32, src_p=32/tcp, dst_h=192.168.17.2/32, dst_p=32/tcp, src_m=, dst_m=], ip=, mac=], expire=30.0 secs, priority=0, location=, out_port=5, mod=, id=5, cid=5, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _added=F] -netcontrol debug (Debug-All): add_rule: [ty=NetControl::DROP, target=NetControl::FORWARD, entity=[ty=NetControl::FLOW, conn=, flow=[src_h=127.0.0.2/32, src_p=, dst_h=, dst_p=, src_m=, dst_m=], ip=, mac=], expire=15.0 secs, priority=0, location=, out_port=, mod=, id=6, cid=6, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _added=F] -netcontrol debug (Debug-All): add_rule: [ty=NetControl::MODIFY, target=NetControl::FORWARD, entity=[ty=NetControl::FLOW, conn=, flow=[src_h=127.0.0.2/32, src_p=, dst_h=8.8.8.8/32, dst_p=53/udp, src_m=, dst_m=], ip=, mac=], expire=15.0 secs, priority=5, location=, out_port=, mod=[src_h=, src_p=, dst_h=127.0.0.3, dst_p=, src_m=, dst_m=, redirect_port=], id=7, cid=7, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _added=F] -netcontrol debug (Debug-All): add_rule: [ty=NetControl::MODIFY, target=NetControl::FORWARD, entity=[ty=NetControl::FLOW, conn=, flow=[src_h=8.8.8.8/32, src_p=53/udp, dst_h=127.0.0.2/32, dst_p=, src_m=, dst_m=], ip=, mac=], expire=15.0 secs, priority=5, location=, out_port=, mod=[src_h=8.8.8.8, src_p=, dst_h=, dst_p=, src_m=, dst_m=, redirect_port=], id=8, cid=8, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _added=F] -netcontrol debug (Debug-All): add_rule: [ty=NetControl::WHITELIST, target=NetControl::FORWARD, entity=[ty=NetControl::FLOW, conn=, flow=[src_h=127.0.0.2/32, src_p=, dst_h=127.0.0.3/32, dst_p=80/tcp, src_m=, dst_m=], ip=, mac=], expire=15.0 secs, priority=5, location=, out_port=, mod=, id=9, cid=9, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _added=F] -netcontrol debug (Debug-All): add_rule: [ty=NetControl::DROP, target=NetControl::FORWARD, entity=[ty=NetControl::MAC, conn=, flow=, ip=, mac=FF:FF:FF:FF:FF:FF], expire=15.0 secs, priority=0, location=, out_port=, mod=, id=10, cid=10, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _added=F] -netcontrol debug (Debug-All): add_rule: [ty=NetControl::DROP, target=NetControl::FORWARD, entity=[ty=NetControl::FLOW, conn=, flow=[src_h=, src_p=, dst_h=, dst_p=, src_m=FF:FF:FF:FF:FF:FF, dst_m=], ip=, mac=], expire=15.0 secs, priority=0, location=, out_port=, mod=, id=11, cid=11, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _added=F] +netcontrol debug (Debug-All): add_rule: [ty=NetControl::DROP, target=NetControl::MONITOR, entity=[ty=NetControl::FLOW, conn=, flow=[src_h=192.168.17.1/32, src_p=32/tcp, dst_h=192.168.17.2/32, dst_p=32/tcp, src_m=, dst_m=], ip=, mac=], expire=30.0 secs, priority=0, location=, out_port=, mod=, id=2, cid=2, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _no_expire_plugins={\x0a\x0a}, _added=F] +netcontrol debug (Debug-All): add_rule: [ty=NetControl::DROP, target=NetControl::FORWARD, entity=[ty=NetControl::ADDRESS, conn=, flow=, ip=1.1.2.2/32, mac=], expire=15.0 secs, priority=0, location=Hi there, out_port=, mod=, id=3, cid=3, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _no_expire_plugins={\x0a\x0a}, _added=F] +netcontrol debug (Debug-All): add_rule: [ty=NetControl::WHITELIST, target=NetControl::FORWARD, entity=[ty=NetControl::ADDRESS, conn=, flow=, ip=1.2.3.4/32, mac=], expire=15.0 secs, priority=5, location=, out_port=, mod=, id=4, cid=4, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _no_expire_plugins={\x0a\x0a}, _added=F] +netcontrol debug (Debug-All): add_rule: [ty=NetControl::REDIRECT, target=NetControl::FORWARD, entity=[ty=NetControl::FLOW, conn=, flow=[src_h=192.168.17.1/32, src_p=32/tcp, dst_h=192.168.17.2/32, dst_p=32/tcp, src_m=, dst_m=], ip=, mac=], expire=30.0 secs, priority=0, location=, out_port=5, mod=, id=5, cid=5, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _no_expire_plugins={\x0a\x0a}, _added=F] +netcontrol debug (Debug-All): add_rule: [ty=NetControl::DROP, target=NetControl::FORWARD, entity=[ty=NetControl::FLOW, conn=, flow=[src_h=127.0.0.2/32, src_p=, dst_h=, dst_p=, src_m=, dst_m=], ip=, mac=], expire=15.0 secs, priority=0, location=, out_port=, mod=, id=6, cid=6, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _no_expire_plugins={\x0a\x0a}, _added=F] +netcontrol debug (Debug-All): add_rule: [ty=NetControl::MODIFY, target=NetControl::FORWARD, entity=[ty=NetControl::FLOW, conn=, flow=[src_h=127.0.0.2/32, src_p=, dst_h=8.8.8.8/32, dst_p=53/udp, src_m=, dst_m=], ip=, mac=], expire=15.0 secs, priority=5, location=, out_port=, mod=[src_h=, src_p=, dst_h=127.0.0.3, dst_p=, src_m=, dst_m=, redirect_port=], id=7, cid=7, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _no_expire_plugins={\x0a\x0a}, _added=F] +netcontrol debug (Debug-All): add_rule: [ty=NetControl::MODIFY, target=NetControl::FORWARD, entity=[ty=NetControl::FLOW, conn=, flow=[src_h=8.8.8.8/32, src_p=53/udp, dst_h=127.0.0.2/32, dst_p=, src_m=, dst_m=], ip=, mac=], expire=15.0 secs, priority=5, location=, out_port=, mod=[src_h=8.8.8.8, src_p=, dst_h=, dst_p=, src_m=, dst_m=, redirect_port=], id=8, cid=8, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _no_expire_plugins={\x0a\x0a}, _added=F] +netcontrol debug (Debug-All): add_rule: [ty=NetControl::WHITELIST, target=NetControl::FORWARD, entity=[ty=NetControl::FLOW, conn=, flow=[src_h=127.0.0.2/32, src_p=, dst_h=127.0.0.3/32, dst_p=80/tcp, src_m=, dst_m=], ip=, mac=], expire=15.0 secs, priority=5, location=, out_port=, mod=, id=9, cid=9, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _no_expire_plugins={\x0a\x0a}, _added=F] +netcontrol debug (Debug-All): add_rule: [ty=NetControl::DROP, target=NetControl::FORWARD, entity=[ty=NetControl::MAC, conn=, flow=, ip=, mac=FF:FF:FF:FF:FF:FF], expire=15.0 secs, priority=0, location=, out_port=, mod=, id=10, cid=10, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _no_expire_plugins={\x0a\x0a}, _added=F] +netcontrol debug (Debug-All): add_rule: [ty=NetControl::DROP, target=NetControl::FORWARD, entity=[ty=NetControl::FLOW, conn=, flow=[src_h=, src_p=, dst_h=, dst_p=, src_m=FF:FF:FF:FF:FF:FF, dst_m=], ip=, mac=], expire=15.0 secs, priority=0, location=, out_port=, mod=, id=11, cid=11, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _no_expire_plugins={\x0a\x0a}, _added=F] diff --git a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.broker/recv.recv.out b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.broker/recv.recv.out index 3b02eef7c7..20e37edd65 100644 --- a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.broker/recv.recv.out +++ b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.broker/recv.recv.out @@ -1,5 +1,4 @@ BrokerComm::incoming_connection_established add_rule, 0, [ty=NetControl::FLOW, conn=, flow=[src_h=10.10.1.4/32, src_p=1470/tcp, dst_h=74.53.140.153/32, dst_p=25/tcp, src_m=, dst_m=], ip=, mac=], NetControl::DROP add_rule, 0, [ty=NetControl::ADDRESS, conn=, flow=, ip=10.10.1.4/32, mac=], NetControl::DROP -remove_rule, 0, [ty=NetControl::FLOW, conn=, flow=[src_h=10.10.1.4/32, src_p=1470/tcp, dst_h=74.53.140.153/32, dst_p=25/tcp, src_m=, dst_m=], ip=, mac=], NetControl::DROP remove_rule, 0, [ty=NetControl::ADDRESS, conn=, flow=, ip=10.10.1.4/32, mac=], NetControl::DROP diff --git a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.broker/send.netcontrol.log b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.broker/send.netcontrol.log index fb1381e291..3a4b962b08 100644 --- a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.broker/send.netcontrol.log +++ b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.broker/send.netcontrol.log @@ -3,21 +3,18 @@ #empty_field (empty) #unset_field - #path netcontrol -#open 2016-03-08-22-15-15 +#open 2016-03-24-22-00-58 #fields ts rule_id category cmd state action target entity_type entity mod msg priority expire location plugin #types time string enum string enum string enum string string string string int interval string string 0.000000 - NetControl::MESSAGE - - - - - - - activating plugin with priority 0 - - - Broker-bro/event/netcontroltest 0.000000 - NetControl::MESSAGE - - - - - - - waiting for plugins to initialize - - - - -1457475314.791475 - NetControl::MESSAGE - - - - - - - activation finished - - - Broker-bro/event/netcontroltest -1457475314.791475 - NetControl::MESSAGE - - - - - - - plugin initialization done - - - - -1457475315.175411 2 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::MONITOR NetControl::FLOW 10.10.1.4/32/1470->74.53.140.153/32/25 - - 0 36000.000000 - Broker-bro/event/netcontroltest -1457475315.175411 3 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 10.10.1.4/32 - - 0 36000.000000 - Broker-bro/event/netcontroltest -1457475315.175443 2 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::MONITOR NetControl::FLOW 10.10.1.4/32/1470->74.53.140.153/32/25 - - 0 36000.000000 - Broker-bro/event/netcontroltest -1457475315.175443 2 NetControl::RULE REMOVE NetControl::REQUESTED NetControl::DROP NetControl::MONITOR NetControl::FLOW 10.10.1.4/32/1470->74.53.140.153/32/25 - - 0 36000.000000 - Broker-bro/event/netcontroltest -1457475315.175443 3 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 10.10.1.4/32 - - 0 36000.000000 - Broker-bro/event/netcontroltest -1457475315.175443 3 NetControl::RULE REMOVE NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 10.10.1.4/32 - - 0 36000.000000 - Broker-bro/event/netcontroltest -1457475315.175443 2 NetControl::RULE EXPIRE NetControl::TIMEOUT NetControl::DROP NetControl::MONITOR NetControl::FLOW 10.10.1.4/32/1470->74.53.140.153/32/25 - - 0 36000.000000 - Broker-bro/event/netcontroltest -1457475315.175443 2 NetControl::ERROR - - NetControl::DROP NetControl::MONITOR NetControl::FLOW 10.10.1.4/32/1470->74.53.140.153/32/25 - Removal of non-existing rule 0 36000.000000 - Broker-bro/event/netcontroltest -1457475315.175443 3 NetControl::RULE EXPIRE NetControl::TIMEOUT NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 10.10.1.4/32 - - 0 36000.000000 - Broker-bro/event/netcontroltest -1457475315.175443 3 NetControl::ERROR - - NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 10.10.1.4/32 - Removal of non-existing rule 0 36000.000000 - Broker-bro/event/netcontroltest -#close 2016-03-08-22-15-15 +1458856858.169980 - NetControl::MESSAGE - - - - - - - activation finished - - - Broker-bro/event/netcontroltest +1458856858.169980 - NetControl::MESSAGE - - - - - - - plugin initialization done - - - - +1458856858.553916 2 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::MONITOR NetControl::FLOW 10.10.1.4/32/1470->74.53.140.153/32/25 - - 0 36000.000000 - Broker-bro/event/netcontroltest +1458856858.553916 3 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 10.10.1.4/32 - - 0 36000.000000 - Broker-bro/event/netcontroltest +1458856858.553948 2 NetControl::RULE ADD NetControl::EXISTS NetControl::DROP NetControl::MONITOR NetControl::FLOW 10.10.1.4/32/1470->74.53.140.153/32/25 - - 0 36000.000000 - Broker-bro/event/netcontroltest +1458856858.553948 2 NetControl::RULE EXPIRE NetControl::TIMEOUT NetControl::DROP NetControl::MONITOR NetControl::FLOW 10.10.1.4/32/1470->74.53.140.153/32/25 - - 0 36000.000000 - Broker-bro/event/netcontroltest +1458856858.553948 3 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 10.10.1.4/32 - - 0 36000.000000 - Broker-bro/event/netcontroltest +1458856858.553948 3 NetControl::RULE REMOVE NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 10.10.1.4/32 - - 0 36000.000000 - Broker-bro/event/netcontroltest +1458856858.553948 3 NetControl::RULE REMOVE NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 10.10.1.4/32 - - 0 36000.000000 - Broker-bro/event/netcontroltest +#close 2016-03-24-22-00-59 diff --git a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.broker/send.send.out b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.broker/send.send.out index 31d94be31e..3c281726c5 100644 --- a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.broker/send.send.out +++ b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.broker/send.send.out @@ -1,7 +1,5 @@ BrokerComm::outgoing_connection_established, 127.0.0.1, 9999/tcp -rule added, [ty=NetControl::FLOW, conn=, flow=[src_h=10.10.1.4/32, src_p=1470/tcp, dst_h=74.53.140.153/32, dst_p=25/tcp, src_m=, dst_m=], ip=, mac=], NetControl::DROP -rule added, [ty=NetControl::ADDRESS, conn=, flow=, ip=10.10.1.4/32, mac=], NetControl::DROP +rule exists, [ty=NetControl::FLOW, conn=, flow=[src_h=10.10.1.4/32, src_p=1470/tcp, dst_h=74.53.140.153/32, dst_p=25/tcp, src_m=, dst_m=], ip=, mac=], NetControl::DROP rule timeout, [ty=NetControl::FLOW, conn=, flow=[src_h=10.10.1.4/32, src_p=1470/tcp, dst_h=74.53.140.153/32, dst_p=25/tcp, src_m=, dst_m=], ip=, mac=], NetControl::DROP, [duration=, packet_count=, byte_count=] -rule removed, [ty=NetControl::FLOW, conn=, flow=[src_h=10.10.1.4/32, src_p=1470/tcp, dst_h=74.53.140.153/32, dst_p=25/tcp, src_m=, dst_m=], ip=, mac=], NetControl::DROP -rule timeout, [ty=NetControl::ADDRESS, conn=, flow=, ip=10.10.1.4/32, mac=], NetControl::DROP, [duration=, packet_count=, byte_count=] +rule added, [ty=NetControl::ADDRESS, conn=, flow=, ip=10.10.1.4/32, mac=], NetControl::DROP rule removed, [ty=NetControl::ADDRESS, conn=, flow=, ip=10.10.1.4/32, mac=], NetControl::DROP diff --git a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.delete-internal-state/.stdout b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.delete-internal-state/.stdout index 7d21c082f7..f21a0b559c 100644 --- a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.delete-internal-state/.stdout +++ b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.delete-internal-state/.stdout @@ -1,12 +1,12 @@ netcontrol debug (Debug-All): init -netcontrol debug (Debug-All): add_rule: [ty=NetControl::DROP, target=NetControl::MONITOR, entity=[ty=NetControl::FLOW, conn=, flow=[src_h=192.168.18.50/32, src_p=56981/tcp, dst_h=74.125.239.97/32, dst_p=443/tcp, src_m=, dst_m=], ip=, mac=], expire=0 secs, priority=0, location=, out_port=, mod=, id=2, cid=2, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _added=F] -netcontrol debug (Debug-All): add_rule: [ty=NetControl::DROP, target=NetControl::FORWARD, entity=[ty=NetControl::ADDRESS, conn=, flow=, ip=192.168.18.50/32, mac=], expire=0 secs, priority=0, location=, out_port=, mod=, id=3, cid=3, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _added=F] -netcontrol debug (Debug-All): add_rule: [ty=NetControl::WHITELIST, target=NetControl::FORWARD, entity=[ty=NetControl::ADDRESS, conn=, flow=, ip=192.168.18.50/32, mac=], expire=0 secs, priority=5, location=, out_port=, mod=, id=4, cid=4, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _added=F] -netcontrol debug (Debug-All): add_rule: [ty=NetControl::REDIRECT, target=NetControl::FORWARD, entity=[ty=NetControl::FLOW, conn=, flow=[src_h=192.168.18.50/32, src_p=56981/tcp, dst_h=74.125.239.97/32, dst_p=443/tcp, src_m=, dst_m=], ip=, mac=], expire=0 secs, priority=0, location=, out_port=5, mod=, id=5, cid=5, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _added=F] -netcontrol debug (Debug-All): remove_rule: [ty=NetControl::DROP, target=NetControl::MONITOR, entity=[ty=NetControl::FLOW, conn=, flow=[src_h=192.168.18.50/32, src_p=56981/tcp, dst_h=74.125.239.97/32, dst_p=443/tcp, src_m=, dst_m=], ip=, mac=], expire=0 secs, priority=0, location=, out_port=, mod=, id=2, cid=2, _plugin_ids={\x0a\x091\x0a}, _active_plugin_ids={\x0a\x091\x0a}, _added=T] -netcontrol debug (Debug-All): remove_rule: [ty=NetControl::DROP, target=NetControl::FORWARD, entity=[ty=NetControl::ADDRESS, conn=, flow=, ip=192.168.18.50/32, mac=], expire=0 secs, priority=0, location=, out_port=, mod=, id=3, cid=3, _plugin_ids={\x0a\x091\x0a}, _active_plugin_ids={\x0a\x091\x0a}, _added=T] -netcontrol debug (Debug-All): remove_rule: [ty=NetControl::WHITELIST, target=NetControl::FORWARD, entity=[ty=NetControl::ADDRESS, conn=, flow=, ip=192.168.18.50/32, mac=], expire=0 secs, priority=5, location=, out_port=, mod=, id=4, cid=4, _plugin_ids={\x0a\x091\x0a}, _active_plugin_ids={\x0a\x091\x0a}, _added=T] -netcontrol debug (Debug-All): remove_rule: [ty=NetControl::REDIRECT, target=NetControl::FORWARD, entity=[ty=NetControl::FLOW, conn=, flow=[src_h=192.168.18.50/32, src_p=56981/tcp, dst_h=74.125.239.97/32, dst_p=443/tcp, src_m=, dst_m=], ip=, mac=], expire=0 secs, priority=0, location=, out_port=5, mod=, id=5, cid=5, _plugin_ids={\x0a\x091\x0a}, _active_plugin_ids={\x0a\x091\x0a}, _added=T] +netcontrol debug (Debug-All): add_rule: [ty=NetControl::DROP, target=NetControl::MONITOR, entity=[ty=NetControl::FLOW, conn=, flow=[src_h=192.168.18.50/32, src_p=56981/tcp, dst_h=74.125.239.97/32, dst_p=443/tcp, src_m=, dst_m=], ip=, mac=], expire=0 secs, priority=0, location=, out_port=, mod=, id=2, cid=2, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _no_expire_plugins={\x0a\x0a}, _added=F] +netcontrol debug (Debug-All): add_rule: [ty=NetControl::DROP, target=NetControl::FORWARD, entity=[ty=NetControl::ADDRESS, conn=, flow=, ip=192.168.18.50/32, mac=], expire=0 secs, priority=0, location=, out_port=, mod=, id=3, cid=3, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _no_expire_plugins={\x0a\x0a}, _added=F] +netcontrol debug (Debug-All): add_rule: [ty=NetControl::WHITELIST, target=NetControl::FORWARD, entity=[ty=NetControl::ADDRESS, conn=, flow=, ip=192.168.18.50/32, mac=], expire=0 secs, priority=5, location=, out_port=, mod=, id=4, cid=4, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _no_expire_plugins={\x0a\x0a}, _added=F] +netcontrol debug (Debug-All): add_rule: [ty=NetControl::REDIRECT, target=NetControl::FORWARD, entity=[ty=NetControl::FLOW, conn=, flow=[src_h=192.168.18.50/32, src_p=56981/tcp, dst_h=74.125.239.97/32, dst_p=443/tcp, src_m=, dst_m=], ip=, mac=], expire=0 secs, priority=0, location=, out_port=5, mod=, id=5, cid=5, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _no_expire_plugins={\x0a\x0a}, _added=F] +netcontrol debug (Debug-All): remove_rule: [ty=NetControl::DROP, target=NetControl::MONITOR, entity=[ty=NetControl::FLOW, conn=, flow=[src_h=192.168.18.50/32, src_p=56981/tcp, dst_h=74.125.239.97/32, dst_p=443/tcp, src_m=, dst_m=], ip=, mac=], expire=0 secs, priority=0, location=, out_port=, mod=, id=2, cid=2, _plugin_ids={\x0a\x091\x0a}, _active_plugin_ids={\x0a\x091\x0a}, _no_expire_plugins={\x0a\x0a}, _added=T] +netcontrol debug (Debug-All): remove_rule: [ty=NetControl::DROP, target=NetControl::FORWARD, entity=[ty=NetControl::ADDRESS, conn=, flow=, ip=192.168.18.50/32, mac=], expire=0 secs, priority=0, location=, out_port=, mod=, id=3, cid=3, _plugin_ids={\x0a\x091\x0a}, _active_plugin_ids={\x0a\x091\x0a}, _no_expire_plugins={\x0a\x0a}, _added=T] +netcontrol debug (Debug-All): remove_rule: [ty=NetControl::WHITELIST, target=NetControl::FORWARD, entity=[ty=NetControl::ADDRESS, conn=, flow=, ip=192.168.18.50/32, mac=], expire=0 secs, priority=5, location=, out_port=, mod=, id=4, cid=4, _plugin_ids={\x0a\x091\x0a}, _active_plugin_ids={\x0a\x091\x0a}, _no_expire_plugins={\x0a\x0a}, _added=T] +netcontrol debug (Debug-All): remove_rule: [ty=NetControl::REDIRECT, target=NetControl::FORWARD, entity=[ty=NetControl::FLOW, conn=, flow=[src_h=192.168.18.50/32, src_p=56981/tcp, dst_h=74.125.239.97/32, dst_p=443/tcp, src_m=, dst_m=], ip=, mac=], expire=0 secs, priority=0, location=, out_port=5, mod=, id=5, cid=5, _plugin_ids={\x0a\x091\x0a}, _active_plugin_ids={\x0a\x091\x0a}, _no_expire_plugins={\x0a\x0a}, _added=T] Dumping state { diff --git a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.multiple/netcontrol.log b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.multiple/netcontrol.log index 986c1cd5a2..c9422d86c2 100644 --- a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.multiple/netcontrol.log +++ b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.multiple/netcontrol.log @@ -3,7 +3,7 @@ #empty_field (empty) #unset_field - #path netcontrol -#open 2016-03-09-23-40-32 +#open 2016-03-18-21-54-39 #fields ts rule_id category cmd state action target entity_type entity mod msg priority expire location plugin #types time string enum string enum string enum string string string string int interval string string 0.000000 - NetControl::MESSAGE - - - - - - - activating plugin with priority 10 - - - Debug-All @@ -13,7 +13,6 @@ 0.000000 - NetControl::MESSAGE - - - - - - - activating plugin with priority 0 - - - Debug-All 0.000000 - NetControl::MESSAGE - - - - - - - activation finished - - - Debug-All 0.000000 - NetControl::MESSAGE - - - - - - - plugin initialization done - - - - -0.000000 - NetControl::MESSAGE - - - - - - - activation finished - - - Openflow-Log-42 1398529018.678276 2 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::MONITOR NetControl::FLOW 192.168.18.50/32/56981->74.125.239.97/32/443 - - 0 0.000000 - Debug-All 1398529018.678276 2 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::MONITOR NetControl::FLOW 192.168.18.50/32/56981->74.125.239.97/32/443 - - 0 0.000000 - Openflow-Log-42 1398529018.678276 3 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 0.000000 - Debug-All @@ -46,4 +45,4 @@ 1398529020.091883 3 NetControl::RULE REMOVE NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 0.000000 - Openflow-Log-42 1398529020.091883 4 NetControl::RULE REMOVE NetControl::SUCCEEDED NetControl::WHITELIST NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 5 0.000000 - Openflow-Log-42 1398529020.091883 5 NetControl::RULE REMOVE NetControl::SUCCEEDED NetControl::REDIRECT NetControl::FORWARD NetControl::FLOW 192.168.18.50/32/56981->74.125.239.97/32/443 -> 5 - 0 0.000000 - Openflow-Log-42 -#close 2016-03-09-23-40-32 +#close 2016-03-18-21-54-40 diff --git a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.openflow/netcontrol.log b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.openflow/netcontrol.log index abab12a0c9..3aae79368f 100644 --- a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.openflow/netcontrol.log +++ b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.openflow/netcontrol.log @@ -3,13 +3,12 @@ #empty_field (empty) #unset_field - #path netcontrol -#open 2016-03-09-23-28-53 +#open 2016-03-18-21-54-48 #fields ts rule_id category cmd state action target entity_type entity mod msg priority expire location plugin #types time string enum string enum string enum string string string string int interval string string 0.000000 - NetControl::MESSAGE - - - - - - - activating plugin with priority 0 - - - Openflow-Log-42 0.000000 - NetControl::MESSAGE - - - - - - - activation finished - - - Openflow-Log-42 0.000000 - NetControl::MESSAGE - - - - - - - plugin initialization done - - - - -0.000000 - NetControl::MESSAGE - - - - - - - activation finished - - - Openflow-Log-42 1254722767.875996 2 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::MONITOR NetControl::FLOW 10.10.1.4/32/1470->74.53.140.153/32/25 - - 0 30.000000 - Openflow-Log-42 1254722767.875996 3 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 74.53.140.153/32 - - 0 15.000000 - Openflow-Log-42 1254722767.875996 2 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::MONITOR NetControl::FLOW 10.10.1.4/32/1470->74.53.140.153/32/25 - - 0 30.000000 - Openflow-Log-42 @@ -22,4 +21,4 @@ 1437831799.610433 7 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 17.167.150.73/32 - - 0 15.000000 - Openflow-Log-42 1437831799.610433 6 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::MONITOR NetControl::FLOW 192.168.133.100/32/49655->17.167.150.73/32/443 - - 0 30.000000 - Openflow-Log-42 1437831799.610433 7 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 17.167.150.73/32 - - 0 15.000000 - Openflow-Log-42 -#close 2016-03-09-23-28-53 +#close 2016-03-18-21-54-48 diff --git a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.quarantine-openflow/netcontrol.log b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.quarantine-openflow/netcontrol.log index 0da63fd6f5..68719ad6eb 100644 --- a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.quarantine-openflow/netcontrol.log +++ b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.quarantine-openflow/netcontrol.log @@ -3,13 +3,12 @@ #empty_field (empty) #unset_field - #path netcontrol -#open 2016-03-08-22-48-10 +#open 2016-03-18-21-54-53 #fields ts rule_id category cmd state action target entity_type entity mod msg priority expire location plugin #types time string enum string enum string enum string string string string int interval string string 0.000000 - NetControl::MESSAGE - - - - - - - activating plugin with priority 0 - - - Openflow-Log-42 0.000000 - NetControl::MESSAGE - - - - - - - activation finished - - - Openflow-Log-42 0.000000 - NetControl::MESSAGE - - - - - - - plugin initialization done - - - - -0.000000 - NetControl::MESSAGE - - - - - - - activation finished - - - Openflow-Log-42 1398529018.678276 2 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::FLOW 192.168.18.50/32/*->*/* - - 0 36000.000000 - Openflow-Log-42 1398529018.678276 3 NetControl::RULE ADD NetControl::REQUESTED NetControl::MODIFY NetControl::FORWARD NetControl::FLOW 192.168.18.50/32/*->8.8.8.8/32/53 Src: _/_ (_) Dst: 192.169.18.1/_ (_) - 5 36000.000000 - Openflow-Log-42 1398529018.678276 4 NetControl::RULE ADD NetControl::REQUESTED NetControl::MODIFY NetControl::FORWARD NetControl::FLOW 8.8.8.8/32/53->192.168.18.50/32/* Src: 8.8.8.8/_ (_) Dst: _/_ (_) - 5 36000.000000 - Openflow-Log-42 @@ -18,4 +17,4 @@ 1398529018.678276 3 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::MODIFY NetControl::FORWARD NetControl::FLOW 192.168.18.50/32/*->8.8.8.8/32/53 Src: _/_ (_) Dst: 192.169.18.1/_ (_) - 5 36000.000000 - Openflow-Log-42 1398529018.678276 4 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::MODIFY NetControl::FORWARD NetControl::FLOW 8.8.8.8/32/53->192.168.18.50/32/* Src: 8.8.8.8/_ (_) Dst: _/_ (_) - 5 36000.000000 - Openflow-Log-42 1398529018.678276 5 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::WHITELIST NetControl::FORWARD NetControl::FLOW 192.168.18.50/32/*->192.169.18.1/32/80 - - 5 36000.000000 - Openflow-Log-42 -#close 2016-03-08-22-48-10 +#close 2016-03-18-21-54-53 diff --git a/testing/btest/scripts/base/frameworks/netcontrol/acld.bro b/testing/btest/scripts/base/frameworks/netcontrol/acld.bro index dfeaee1055..8c50f317fb 100644 --- a/testing/btest/scripts/base/frameworks/netcontrol/acld.bro +++ b/testing/btest/scripts/base/frameworks/netcontrol/acld.bro @@ -4,6 +4,7 @@ # @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 send/netcontrol.log # @TEST-EXEC: btest-diff recv/recv.out # @TEST-EXEC: btest-diff send/send.out @@ -67,6 +68,12 @@ event NetControl::rule_added(r: NetControl::Rule, p: NetControl::PluginState, ms NetControl::remove_rule(r$id); } +event NetControl::rule_exists(r: NetControl::Rule, p: NetControl::PluginState, msg: string) + { + print "rule exists", r$entity, r$ty; + NetControl::remove_rule(r$id); + } + event NetControl::rule_removed(r: NetControl::Rule, p: NetControl::PluginState, msg: string) { print "rule removed", r$entity, r$ty; @@ -98,7 +105,10 @@ event NetControl::acld_add_rule(id: count, r: NetControl::Rule, ar: NetControl:: { print "add_rule", id, r$entity, r$ty, ar; - BrokerComm::event("bro/event/netcontroltest", BrokerComm::event_args(NetControl::acld_rule_added, id, r, ar$command)); + if ( r$cid != 3 ) + BrokerComm::event("bro/event/netcontroltest", BrokerComm::event_args(NetControl::acld_rule_added, id, r, ar$command)); + else + BrokerComm::event("bro/event/netcontroltest", BrokerComm::event_args(NetControl::acld_rule_exists, id, r, ar$command)); } event NetControl::acld_remove_rule(id: count, r: NetControl::Rule, ar: NetControl::AclRule) diff --git a/testing/btest/scripts/base/frameworks/netcontrol/broker.bro b/testing/btest/scripts/base/frameworks/netcontrol/broker.bro index 6b1474c3e3..ed3dc85c04 100644 --- a/testing/btest/scripts/base/frameworks/netcontrol/broker.bro +++ b/testing/btest/scripts/base/frameworks/netcontrol/broker.bro @@ -53,6 +53,11 @@ event NetControl::rule_added(r: NetControl::Rule, p: NetControl::PluginState, ms NetControl::remove_rule(r$id); } +event NetControl::rule_exists(r: NetControl::Rule, p: NetControl::PluginState, msg: string) + { + print "rule exists", r$entity, r$ty; + } + event NetControl::rule_removed(r: NetControl::Rule, p: NetControl::PluginState, msg: string) { print "rule removed", r$entity, r$ty; @@ -89,14 +94,19 @@ event NetControl::broker_add_rule(id: count, r: NetControl::Rule) { print "add_rule", id, r$entity, r$ty; - BrokerComm::event("bro/event/netcontroltest", BrokerComm::event_args(NetControl::broker_rule_added, id, r, "")); + if ( r$cid == 3 ) + BrokerComm::event("bro/event/netcontroltest", BrokerComm::event_args(NetControl::broker_rule_added, id, r, "")); + if ( r$cid == 2 ) + BrokerComm::event("bro/event/netcontroltest", BrokerComm::event_args(NetControl::broker_rule_exists, id, r, "")); + + if ( r$cid == 2 ) + BrokerComm::event("bro/event/netcontroltest", BrokerComm::event_args(NetControl::broker_rule_timeout, id, r, NetControl::FlowInfo())); } event NetControl::broker_remove_rule(id: count, r: NetControl::Rule) { print "remove_rule", id, r$entity, r$ty; - BrokerComm::event("bro/event/netcontroltest", BrokerComm::event_args(NetControl::broker_rule_timeout, id, r, NetControl::FlowInfo())); BrokerComm::event("bro/event/netcontroltest", BrokerComm::event_args(NetControl::broker_rule_removed, id, r, "")); if ( r$cid == 3 ) From ee132b6da446f7129c47c9b90797d8a0d1254115 Mon Sep 17 00:00:00 2001 From: Johanna Amann Date: Thu, 24 Mar 2016 15:21:36 -0700 Subject: [PATCH 05/13] NetControl: fix acld whitelist command --- scripts/base/frameworks/netcontrol/plugins/acld.bro | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/base/frameworks/netcontrol/plugins/acld.bro b/scripts/base/frameworks/netcontrol/plugins/acld.bro index 6343bad335..4f2ec0857b 100644 --- a/scripts/base/frameworks/netcontrol/plugins/acld.bro +++ b/scripts/base/frameworks/netcontrol/plugins/acld.bro @@ -75,7 +75,7 @@ global netcontrol_acld_current_id: count = 0; const acld_add_to_remove: table[string] of string = { ["drop"] = "restore", - ["whitelist"] = "remwhitelist", + ["addwhitelist"] = "remwhitelist", ["blockhosthost"] = "restorehosthost", ["droptcpport"] = "restoretcpport", ["dropudpport"] = "restoreudpport", @@ -167,7 +167,7 @@ function rule_to_acl_rule(p: PluginState, r: Rule) : AclRule if ( r$ty == DROP ) command = "drop"; else if ( r$ty == WHITELIST ) - command = "whitelist"; + command = "addwhitelist"; arg = cat(e$ip); } else if ( e$ty == FLOW ) From 6779325520b6466331fb3ddc1f1a331f96b80e22 Mon Sep 17 00:00:00 2001 From: Johanna Amann Date: Fri, 20 May 2016 10:42:12 -0700 Subject: [PATCH 06/13] NetControl: find_rules_subnet works in cluster mode This introduces two new events, NetControl::rule_new and NetControl::rule_destroyed, which are raised when rules are first added and then deleted from the internal state tracking. --- .../base/frameworks/netcontrol/cluster.bro | 27 ++++++++++-- scripts/base/frameworks/netcontrol/main.bro | 41 +++++++++++++++++-- .../worker-1..stdout | 4 ++ .../worker-2..stdout | 3 ++ .../frameworks/netcontrol/basic-cluster.bro | 11 ++++- 5 files changed, 78 insertions(+), 8 deletions(-) create mode 100644 testing/btest/Baseline/scripts.base.frameworks.netcontrol.basic-cluster/worker-1..stdout create mode 100644 testing/btest/Baseline/scripts.base.frameworks.netcontrol.basic-cluster/worker-2..stdout diff --git a/scripts/base/frameworks/netcontrol/cluster.bro b/scripts/base/frameworks/netcontrol/cluster.bro index 1f4738cf2e..b07c119372 100644 --- a/scripts/base/frameworks/netcontrol/cluster.bro +++ b/scripts/base/frameworks/netcontrol/cluster.bro @@ -19,7 +19,7 @@ export { ## Workers need ability to forward commands to manager. redef Cluster::worker2manager_events += /NetControl::cluster_netcontrol_(add|remove|delete)_rule/; ## Workers need to see the result events from the manager. -redef Cluster::manager2worker_events += /NetControl::rule_(added|removed|timeout|error|exists)/; +redef Cluster::manager2worker_events += /NetControl::rule_(added|removed|timeout|error|exists|new|destroyed)/; function activate(p: PluginState, priority: int) { @@ -83,9 +83,7 @@ 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); @@ -123,3 +121,26 @@ event rule_error(r: Rule, p: PluginState, msg: string &default="") &priority=-5 } @endif +# Workers use the events to keep track in their local state tables +@if ( Cluster::local_node_type() != Cluster::MANAGER ) + +event rule_new(r: Rule) &priority=5 + { + if ( r$id in rules ) + return; + + rules[r$id] = r; + + add_subnet_entry(r); + } + +event rule_destroyed(r: Rule) &priority=5 + { + if ( r$id !in rules ) + return; + + remove_subnet_entry(r); + delete rules[r$id]; + } + +@endif diff --git a/scripts/base/frameworks/netcontrol/main.bro b/scripts/base/frameworks/netcontrol/main.bro index f8e4ea26bf..2a5b3c42b1 100644 --- a/scripts/base/frameworks/netcontrol/main.bro +++ b/scripts/base/frameworks/netcontrol/main.bro @@ -136,12 +136,16 @@ export { ## ## id: The rule to delete, specified as the ID returned by :bro:id:`add_rule` . ## - ## Returns: True if removal is successful, or sent to manager. + ## Returns: True if removal is successful, or sent to manager. ## False if the rule could not be found. global delete_rule: function(id: string) : bool; ## Searches all rules affecting a certain IP address. ## + ## This function works on both the manager and workers of a cluster. Note that on + ## the worker, the internal rule variables (starting with _) will not reflect the + ## current state. + ## ## ip: The ip address to search for ## ## Returns: vector of all rules affecting the IP address @@ -149,6 +153,10 @@ export { ## Searches all rules affecting a certain subnet. ## + ## This function works on both the manager and workers of a cluster. Note that on + ## the worker, the internal rule variables (starting with _) will not reflect the + ## current state. + ## ## sn: The subnet to search for ## ## Returns: vector of all rules affecting the subnet @@ -156,7 +164,7 @@ export { ###### Asynchronous feedback on rules. - ## Confirms that a rule was put in place. + ## Confirms that a rule was put in place by a plugin. ## ## r: The rule now in place. ## @@ -178,7 +186,8 @@ export { ## msg: An optional informational message by the plugin. global rule_exists: event(r: Rule, p: PluginState, msg: string &default=""); - ## Reports that a rule was removed due to a remove: function() call. + ## Reports that a plugin reports a rule was removed due to a + ## remove: function() vall. ## ## r: The rule now removed. ## @@ -188,7 +197,7 @@ export { ## 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. + ## Reports that a rule was removed from a plugin due to a timeout. ## ## r: The rule now removed. ## @@ -209,6 +218,26 @@ export { ## msg: An optional informational message by the plugin. global rule_error: event(r: Rule, p: PluginState, msg: string &default=""); + ## This event is raised when a new rule is created by the NetControl framework + ## due to a call to add_rule. From this moment, until the rule_destroyed event + ## is raised, the rule is tracked internally by the NetControl framewory. + ## + ## Note that this event does not mean that a rule was succesfully added by + ## any backend; it just means that the rule has been accepted and addition + ## to the specified backend is queued. To get information when rules are actually + ## installed by the hardware, use the rule_added, rule_exists, rule_removed, rule_timeout + ## and rule_error events. + global rule_new: event(r: Rule); + + ## This event is raised when a rule is deleted from the NetControl framework, + ## because it is no longer in use. This can be caused by the fact that a rule + ## was removed by all plugins to which it was added, by the fact that it timed out + ## or due to rule errors. + ## + ## To get the cause or a rule remove, hook the rule_removed, rule_timeout and + ## rule_error calls. + global rule_destroyed: event(r: Rule); + ## 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. @@ -759,6 +788,8 @@ function add_rule_impl(rule: Rule) : string add_subnet_entry(rule); + event NetControl::rule_new(rule); + return rule$id; } @@ -775,6 +806,8 @@ function rule_cleanup(r: Rule) delete rule_entities[r$entity, r$ty]; delete rules[r$id]; + + event NetControl::rule_destroyed(r); } function delete_rule_impl(id: string): bool diff --git a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.basic-cluster/worker-1..stdout b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.basic-cluster/worker-1..stdout new file mode 100644 index 0000000000..9c961bff21 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.basic-cluster/worker-1..stdout @@ -0,0 +1,4 @@ +Rule added, worker-1:2, 2 +Rule added, worker-1:3, 3 +1 +Rule destroyed, worker-1:3, 3, 0 diff --git a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.basic-cluster/worker-2..stdout b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.basic-cluster/worker-2..stdout new file mode 100644 index 0000000000..c638f34077 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.basic-cluster/worker-2..stdout @@ -0,0 +1,3 @@ +Rule added, worker-2:2, 4 +Rule added, worker-2:3, 5 +1 diff --git a/testing/btest/scripts/base/frameworks/netcontrol/basic-cluster.bro b/testing/btest/scripts/base/frameworks/netcontrol/basic-cluster.bro index 5c42f0d8eb..051dd3eb82 100644 --- a/testing/btest/scripts/base/frameworks/netcontrol/basic-cluster.bro +++ b/testing/btest/scripts/base/frameworks/netcontrol/basic-cluster.bro @@ -6,7 +6,8 @@ # @TEST-EXEC: sleep 1 # @TEST-EXEC: btest-bg-run worker-2 "cp ../cluster-layout.bro . && CLUSTER_NODE=worker-2 bro --pseudo-realtime -C -r $TRACES/tls/ecdhe.pcap %INPUT" # @TEST-EXEC: btest-bg-wait 20 -# @TEST-EXEC: btest-diff manager-1/netcontrol.log +# @TEST-EXEC: btest-diff worker-1/.stdout +# @TEST-EXEC: btest-diff worker-2/.stdout @TEST-START-FILE cluster-layout.bro redef Cluster::nodes = { @@ -59,4 +60,12 @@ event remote_connection_closed(p: event_peer) { event NetControl::rule_added(r: NetControl::Rule, p: NetControl::PluginState, msg: string &default="") { print "Rule added", r$id, r$cid; + if ( r$entity?$ip ) + print |NetControl::find_rules_subnet(r$entity$ip)|; + } + +event NetControl::rule_destroyed(r: NetControl::Rule) + { + if ( r$entity?$ip ) + print "Rule destroyed", r$id, r$cid, |NetControl::find_rules_subnet(r$entity$ip)|; } From 9f7b23b179fbe2431686fa047dce4a2e058717f1 Mon Sep 17 00:00:00 2001 From: Johanna Amann Date: Mon, 23 May 2016 12:34:10 -0700 Subject: [PATCH 07/13] NetControl: rewrite catch and release and small fixes. This commit rewrites catch and release, fixing issues with it and making it fully cluster capable. A dedicated netcontrol_catch_release.log is also added. This is not quite done yet; a few more log messages are missing. There should hopefully not be many big issues left. --- .../netcontrol/catch-and-release.bro | 379 ++++++++++++++++-- .../base/frameworks/netcontrol/cluster.bro | 14 + scripts/base/frameworks/netcontrol/drop.bro | 12 + scripts/base/frameworks/netcontrol/main.bro | 3 +- .../netcontrol.log | 18 + .../netcontrol_catch_release.log | 12 + .../manager-1.netcontrol.log | 16 + .../manager-1.netcontrol_catch_release.log | 12 + .../worker-2..stdout | 6 + .../netcontrol.log | 18 +- .../netcontrol_catch_release.log | 16 + .../frameworks/netcontrol/basic-cluster.bro | 12 +- .../netcontrol/catch-and-release-cluster.bro | 114 ++++++ .../netcontrol/catch-and-release.bro | 52 ++- 14 files changed, 617 insertions(+), 67 deletions(-) create mode 100644 testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-2/netcontrol.log create mode 100644 testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-2/netcontrol_catch_release.log create mode 100644 testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-cluster/manager-1.netcontrol.log create mode 100644 testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-cluster/manager-1.netcontrol_catch_release.log create mode 100644 testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-cluster/worker-2..stdout create mode 100644 testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release/netcontrol_catch_release.log create mode 100644 testing/btest/scripts/base/frameworks/netcontrol/catch-and-release-cluster.bro diff --git a/scripts/base/frameworks/netcontrol/catch-and-release.bro b/scripts/base/frameworks/netcontrol/catch-and-release.bro index a95954ac07..68da74a63d 100644 --- a/scripts/base/frameworks/netcontrol/catch-and-release.bro +++ b/scripts/base/frameworks/netcontrol/catch-and-release.bro @@ -6,99 +6,394 @@ module NetControl; @load ./drop export { + + redef enum Log::ID += { CATCH_RELEASE }; + + # The record that is used for storing information about current blocks that are + # part of catch and release. + type BlockInfo: record { + # Absolute time indicating until when a block is inserted using NetControl + block_until: time &optional; + # Absolute time indicating until when an IP address is watched to reblock it + watch_until: time; + # Number of times an IP address was reblocked + num_reblocked: count &default=0; + # Number indicating at which catch and release interval we currently are + current_interval: count; + # ID of the inserted block, if any. + current_block_id: string; + }; + + type CatchReleaseActions: enum { + INFO, + ADDED, + DROP, + DROPPED, + UNBLOCK, + RESTORED, + FORGOTTEN, + SEEN_AGAIN + }; + + type CatchReleaseInfo: record { + ts: time &log; + rule_id: string &log &optional; + ip: addr &log; + action: CatchReleaseActions &log; + block_interval: interval &log &optional; + watch_interval: interval &log &optional; + blocked_until: time &log &optional; + watched_until: time &log &optional; + num_blocked: count &log &optional; + location: string &log &optional; + message: string &log &optional; + }; + ## Stops all packets involving an IP address from being forwarded. This function ## uses catch-and-release functionality, where the IP address is only dropped for ## a short amount of time that is incremented steadily when the IP is encountered ## again. ## + ## In cluster mode, this function works on workers as well as the manager. On managers, + ## the returned :bro:see:`NetControl::BlockInfo` record will not contain the block ID, + ## which will be assigned on the manager. + ## ## a: The address to be dropped. ## ## t: How long to drop it, with 0 being indefinitly. ## ## location: An optional string describing where the drop was triggered. ## - ## Returns: The id of the inserted rule on succes and zero on failure. - global drop_address_catch_release: function(a: addr, location: string &default="") : string; + ## Returns: The :bro:see:`NetControl::BlockInfo` record containing information about + ## the inserted block. + global drop_address_catch_release: function(a: addr, location: string &default="") : BlockInfo; - ## Time intervals for which a subsequent drops of the same IP take - ## effect. + ## Removes an address from being watched with catch and release. Returns true if the + ## address was found and removed; returns false if it was unknown to catch and release. + ## + ## If the address is currently blocked, and the block was inserted by catch and release, + ## the block is removed. + ## + ## a: The address to be unblocked. + ## + ## Returns: True if the address was unblocked. + global unblock_address_catch_release: function(a: addr) : bool; + + ## This function can be called to notify the cach and release script that activity by + ## an IP address was seen. If the respective IP address is currently monitored by catch and + ## release and not blocked, the block will be re-instated. See the documentation of watch_new_connection + ## which events the catch and release functionality usually monitors for activity. + ## + ## a: The address that was seen and should be re-dropped if it is being watched + global catch_release_seen: function(a: addr); + + ## Get the :bro:see:`NetControl::BlockInfo` record for an address currently blocked by catch and release. + ## If the address is unknown to catch and release, the watch_until time will be set to 0. + ## + ## In cluster mode, this function works on the manager and workers. On workers, the data will + ## lag slightly behind the manager; if you add a block, it will not be instantly available via + ## this function. + ## + ## a: The address to get information about. + ## + ## Returns: The :bro:see:`NetControl::BlockInfo` record containing information about + ## the inserted block. + global get_catch_release_info: function(a: addr) : BlockInfo; + + ## If true, catch_release_seen is called on the connection originator in new_connection, + ## connection_established, partial_connection, connection_attempt, connection_rejected, + ## connection_reset and connection_pending + const watch_connections = T &redef; + + ## Time intervals for which a subsequent drops of the same IP take + ## effect. const catch_release_intervals: vector of interval = vector(10min, 1hr, 24hrs, 7days) &redef; + + ## Event that can be handled to access the :bro:type:`NetControl::CatchReleaseInfo` + ## record as it is sent on to the logging framework. + global log_netcontrol_catch_release: event(rec: CatchReleaseInfo); + + # Cluster events for catch and release + global catch_release_block_new: event(a: addr, b: BlockInfo); + global catch_release_block_delete: event(a: addr); + global catch_release_add: event(a: addr, location: string); + global catch_release_delete: event(a: addr); + global catch_release_encountered: event(a: addr); } -function per_block_interval(t: table[addr] of count, idx: addr): interval +event bro_init() &priority=5 { - local ct = t[idx]; - - # watch for the time of the next block... - local blocktime = catch_release_intervals[ct]; - if ( (ct+1) in catch_release_intervals ) - blocktime = catch_release_intervals[ct+1]; - - return blocktime; + Log::create_stream(NetControl::CATCH_RELEASE, [$columns=CatchReleaseInfo, $ev=log_netcontrol_catch_release, $path="netcontrol_catch_release"]); } -# This is the internally maintained table containing all the currently going on catch-and-release -# blocks. -global blocks: table[addr] of count = {} +function per_block_interval(t: table[addr] of BlockInfo, idx: addr): interval + { + local remaining_time = t[idx]$watch_until - network_time(); + if ( remaining_time < 0secs ) + remaining_time = 0secs; + + return remaining_time; + } + +# This is the internally maintained table containing all the addresses that are currently being +# watched to see if they will re-surface. After the time is reached, monitoring of that specific +# IP will stop. +global blocks: table[addr] of BlockInfo = {} &create_expire=0secs &expire_func=per_block_interval; -function current_block_interval(s: set[addr], idx: addr): interval - { - if ( idx !in blocks ) - { - Reporter::error(fmt("Address %s not in blocks while inserting into current_blocks!", idx)); - return 0sec; - } - return catch_release_intervals[blocks[idx]]; +@if ( Cluster::is_enabled() ) +@load base/frameworks/cluster +redef Cluster::manager2worker_events += /NetControl::catch_release_block_(new|delete)/; +redef Cluster::worker2manager_events += /NetControl::catch_release_(add|delete|seen)/; +@endif + +@if ( Cluster::is_enabled() && Cluster::local_node_type() == Cluster::MANAGER ) +event catch_release_add(a: addr, location: string) + { + drop_address_catch_release(a, location); } -global current_blocks: set[addr] = set() - &create_expire=0secs - &expire_func=current_block_interval; +event catch_release_delete(a: addr) + { + unblock_address_catch_release(a); + } -function drop_address_catch_release(a: addr, location: string &default=""): string +event catch_release_encountered(a: addr) + { + catch_release_seen(a); + } +@endif + +@if ( Cluster::is_enabled() && Cluster::local_node_type() != Cluster::MANAGER ) +event catch_release_block_new(a: addr, b: BlockInfo) + { + blocks[a] = b; + } + +event catch_release_block_delete(a: addr) { + if ( a in blocks ) + delete blocks[a]; + } +@endif + +@if ( Cluster::is_enabled() && Cluster::local_node_type() == Cluster::MANAGER ) +@endif + +function get_catch_release_info(a: addr): BlockInfo + { + if ( a in blocks ) + return blocks[a]; + + return BlockInfo($watch_until=double_to_time(0), $current_interval=0, $current_block_id=""); + } + +function get_watch_interval(current_interval: count): interval + { + if ( (current_interval + 1) in catch_release_intervals ) + return catch_release_intervals[current_interval+1]; + else + return catch_release_intervals[current_interval]; + } + +function populate_log_record(ip: addr, bi: BlockInfo, action: CatchReleaseActions): CatchReleaseInfo + { + local log = CatchReleaseInfo($ts=network_time(), $ip=ip, $action=action, + $block_interval=catch_release_intervals[bi$current_interval], + $watch_interval=get_watch_interval(bi$current_interval), + $watched_until=bi$watch_until, + $num_blocked=bi$num_reblocked+1 + ); + + if ( bi?$block_until ) + log$blocked_until = bi$block_until; + + if ( bi?$current_block_id && bi$current_block_id != "" ) + log$rule_id = bi$current_block_id; + + return log; + } + +function drop_address_catch_release(a: addr, location: string &default=""): BlockInfo + { + local bi: BlockInfo; + local log: CatchReleaseInfo; + if ( a in blocks ) { - Reporter::warning(fmt("Address %s already blocked using catch-and-release - ignoring duplicate", a)); - return ""; + log = populate_log_record(a, blocks[a], INFO); + log$message = "Already blocked using catch-and-release - ignoring duplicate"; + Log::write(CATCH_RELEASE, log); + + return blocks[a]; + } + + local e = Entity($ty=ADDRESS, $ip=addr_to_subnet(a)); + if ( [e,DROP] in rule_entities ) + { + local r = rule_entities[e,DROP]; + + bi = BlockInfo($watch_until=network_time()+catch_release_intervals[1], $current_interval=0, $current_block_id=r$id); +@if ( ! Cluster::is_enabled() || ( Cluster::is_enabled() && Cluster::local_node_type() == Cluster::MANAGER ) ) + log = populate_log_record(a, bi, ADDED); + log$message = "Address already blocked outside of catch-and-release. Catch and release will monitor and only actively block if it appears in network traffic."; + Log::write(CATCH_RELEASE, log); + blocks[a] = bi; + event NetControl::catch_release_block_new(a, bi); +@endif +@if ( Cluster::is_enabled() && Cluster::local_node_type() != Cluster::MANAGER ) + event NetControl::catch_release_add(a, location); +@endif + return bi; } local block_interval = catch_release_intervals[0]; + +@if ( ! Cluster::is_enabled() || ( Cluster::is_enabled() && Cluster::local_node_type() == Cluster::MANAGER ) ) local ret = drop_address(a, block_interval, location); + if ( ret != "" ) { - blocks[a] = 0; - add current_blocks[a]; + bi = BlockInfo($watch_until=network_time()+catch_release_intervals[1], $block_until=network_time()+block_interval, $current_interval=0, $current_block_id=ret); + blocks[a] = bi; + event NetControl::catch_release_block_new(a, bi); + blocks[a] = bi; + log = populate_log_record(a, bi, DROP); + Log::write(CATCH_RELEASE, log); + return bi; } + Reporter::error(fmt("Catch and release could not add block for %s; failing.", a)); + return BlockInfo($watch_until=double_to_time(0), $current_interval=0, $current_block_id=""); +@endif + +@if ( Cluster::is_enabled() && Cluster::local_node_type() != Cluster::MANAGER ) + bi = BlockInfo($watch_until=network_time()+catch_release_intervals[1], $block_until=network_time()+block_interval, $current_interval=0, $current_block_id=""); + event NetControl::catch_release_add(a, location); + return bi; +@endif - return ret; } -function check_conn(a: addr) +function unblock_address_catch_release(a: addr): bool { + if ( a !in blocks ) + return F; + +@if ( ! Cluster::is_enabled() || ( Cluster::is_enabled() && Cluster::local_node_type() == Cluster::MANAGER ) ) + local bi = blocks[a]; + local log = populate_log_record(a, bi, UNBLOCK); + Log::write(CATCH_RELEASE, log); + delete blocks[a]; + if ( bi?$block_until && bi$block_until > network_time() && bi$current_block_id != "" ) + remove_rule(bi$current_block_id); +@endif +@if ( Cluster::is_enabled() && Cluster::local_node_type() == Cluster::MANAGER ) + event NetControl::catch_release_block_delete(a); +@endif +@if ( Cluster::is_enabled() && Cluster::local_node_type() != Cluster::MANAGER ) + event NetControl::catch_release_delete(a); +@endif + + return T; + } + +function catch_release_seen(a: addr) + { + local e = Entity($ty=ADDRESS, $ip=addr_to_subnet(a)); + if ( a in blocks ) { - if ( a in current_blocks ) - # block has not been applied yet? +@if ( ! Cluster::is_enabled() || ( Cluster::is_enabled() && Cluster::local_node_type() == Cluster::MANAGER ) ) + local bi = blocks[a]; + local log: CatchReleaseInfo; + + if ( [e,DROP] in rule_entities ) + { + # This should be blocked - block has not been applied yet by hardware? Ignore for the moment... + log = populate_log_record(a, bi, INFO); + log$action = INFO; + log$message = "Block seen while in rule_entities. No action taken."; + Log::write(CATCH_RELEASE, log); return; + } # ok, this one returned again while still in the backoff period. - local try = blocks[a]; + + local try = bi$current_interval; if ( (try+1) in catch_release_intervals ) ++try; - blocks[a] = try; - add current_blocks[a]; + bi$current_interval = try; + if ( (try+1) in catch_release_intervals ) + bi$watch_until = network_time() + catch_release_intervals[try+1]; + else + bi$watch_until = network_time() + catch_release_intervals[try]; + + bi$block_until = network_time() + catch_release_intervals[try]; + ++bi$num_reblocked; + local block_interval = catch_release_intervals[try]; - drop_address(a, block_interval, "Re-drop by catch-and-release"); + local drop = drop_address(a, block_interval, "Re-drop by catch-and-release"); + bi$current_block_id = drop; + + blocks[a] = bi; + + log = populate_log_record(a, bi, SEEN_AGAIN); + Log::write(CATCH_RELEASE, log); +@endif +@if ( Cluster::is_enabled() && Cluster::local_node_type() == Cluster::MANAGER ) + event NetControl::catch_release_block_new(a, bi); +@endif +@if ( Cluster::is_enabled() && Cluster::local_node_type() != Cluster::MANAGER ) + event NetControl::catch_release_encountered(a); +@endif + + return; } + + return; } event new_connection(c: connection) { - # let's only check originating connections... - check_conn(c$id$orig_h); + if ( watch_connections ) + catch_release_seen(c$id$orig_h); + } + +event connection_established(c: connection) + { + if ( watch_connections ) + catch_release_seen(c$id$orig_h); + } + +event partial_connection(c: connection) + { + if ( watch_connections ) + catch_release_seen(c$id$orig_h); + } + +event connection_attempt(c: connection) + { + if ( watch_connections ) + catch_release_seen(c$id$orig_h); + } + +event connection_rejected(c: connection) + { + if ( watch_connections ) + catch_release_seen(c$id$orig_h); + } + +event connection_reset(c: connection) + { + if ( watch_connections ) + catch_release_seen(c$id$orig_h); + } + +event connection_pending(c: connection) + { + if ( watch_connections ) + catch_release_seen(c$id$orig_h); } diff --git a/scripts/base/frameworks/netcontrol/cluster.bro b/scripts/base/frameworks/netcontrol/cluster.bro index b07c119372..31c3d91e7e 100644 --- a/scripts/base/frameworks/netcontrol/cluster.bro +++ b/scripts/base/frameworks/netcontrol/cluster.bro @@ -38,6 +38,16 @@ function add_rule(r: Rule) : string return add_rule_impl(r); else { + # we sync rule entities accross the cluster, so we + # acually can test if the rule already exists. If yes, + # refuse insertion already at the node. + + if ( [r$entity, r$ty] in rule_entities ) + { + log_rule_no_plugin(r, FAILED, "discarded duplicate insertion"); + return ""; + } + if ( r$id == "" ) r$id = cat(Cluster::node, ":", ++local_rule_count); @@ -130,6 +140,7 @@ event rule_new(r: Rule) &priority=5 return; rules[r$id] = r; + rule_entities[r$entity, r$ty] = r; add_subnet_entry(r); } @@ -140,6 +151,9 @@ event rule_destroyed(r: Rule) &priority=5 return; remove_subnet_entry(r); + if ( [r$entity, r$ty] in rule_entities ) + delete rule_entities[r$entity, r$ty]; + delete rules[r$id]; } diff --git a/scripts/base/frameworks/netcontrol/drop.bro b/scripts/base/frameworks/netcontrol/drop.bro index 63c70f0e88..8209df2f51 100644 --- a/scripts/base/frameworks/netcontrol/drop.bro +++ b/scripts/base/frameworks/netcontrol/drop.bro @@ -44,6 +44,12 @@ export { location: string &log &optional; }; + ## Hook that allows the modification of rules passed to drop_* before they + ## are passed on. If one of the hooks uses break, the rule is ignored. + ## + ## r: The rule to be added + global NetControl::drop_rule_policy: hook(r: Rule); + ## Event that can be handled to access the :bro:type:`NetControl::ShuntInfo` ## record as it is sent on to the logging framework. global log_netcontrol_drop: event(rec: DropInfo); @@ -59,6 +65,9 @@ function drop_connection(c: conn_id, t: interval, location: string &default="") local e: Entity = [$ty=CONNECTION, $conn=c]; local r: Rule = [$ty=DROP, $target=FORWARD, $entity=e, $expire=t, $location=location]; + if ( ! hook NetControl::drop_rule_policy(r) ) + return ""; + local id = add_rule(r); # Error should already be logged @@ -80,6 +89,9 @@ function drop_address(a: addr, t: interval, location: string &default="") : stri local e: Entity = [$ty=ADDRESS, $ip=addr_to_subnet(a)]; local r: Rule = [$ty=DROP, $target=FORWARD, $entity=e, $expire=t, $location=location]; + if ( ! hook NetControl::drop_rule_policy(r) ) + return ""; + local id = add_rule(r); # Error should already be logged diff --git a/scripts/base/frameworks/netcontrol/main.bro b/scripts/base/frameworks/netcontrol/main.bro index 2a5b3c42b1..cc2998aa82 100644 --- a/scripts/base/frameworks/netcontrol/main.bro +++ b/scripts/base/frameworks/netcontrol/main.bro @@ -259,7 +259,7 @@ export { MESSAGE, ## A log entry reflecting a framework message. ERROR, - ## A log entry about about a rule. + ## A log entry about a rule. RULE }; @@ -820,6 +820,7 @@ function delete_rule_impl(id: string): bool rule$_active_plugin_ids = set(); rule_cleanup(rule); + return T; } function remove_rule_plugin(r: Rule, p: PluginState): bool diff --git a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-2/netcontrol.log b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-2/netcontrol.log new file mode 100644 index 0000000000..3650d267fe --- /dev/null +++ b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-2/netcontrol.log @@ -0,0 +1,18 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path netcontrol +#open 2016-05-23-23-09-43 +#fields ts rule_id category cmd state action target entity_type entity mod msg priority expire location plugin +#types time string enum string enum string enum string string string string int interval string string +0.000000 - NetControl::MESSAGE - - - - - - - activating plugin with priority 0 - - - Debug-All +0.000000 - NetControl::MESSAGE - - - - - - - activation finished - - - Debug-All +0.000000 - NetControl::MESSAGE - - - - - - - plugin initialization done - - - - +1398529018.678276 2 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 120.000000 - Debug-All +1398529018.678276 2 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 120.000000 - Debug-All +1398529018.678276 3 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 3600.000000 Re-drop by catch-and-release Debug-All +1398529018.678276 3 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 3600.000000 Re-drop by catch-and-release Debug-All +1398529018.678276 4 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 86400.000000 Re-drop by catch-and-release Debug-All +1398529018.678276 4 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 86400.000000 Re-drop by catch-and-release Debug-All +#close 2016-05-23-23-09-43 diff --git a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-2/netcontrol_catch_release.log b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-2/netcontrol_catch_release.log new file mode 100644 index 0000000000..8cd26677d2 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-2/netcontrol_catch_release.log @@ -0,0 +1,12 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path netcontrol_catch_release +#open 2016-05-23-23-10-22 +#fields ts rule_id ip action block_interval watch_interval blocked_until watched_until num_blocked location message +#types time string addr enum interval interval time time count string string +1398529018.678276 2 192.168.18.50 NetControl::ADDED 600.000000 3600.000000 - 1398532618.678276 1 - Address already blocked outside of catch-and-release. Catch and release will monitor and only actively block if it appears in network traffic. +1398529018.678276 3 192.168.18.50 NetControl::SEEN_AGAIN 3600.000000 86400.000000 1398532618.678276 1398615418.678276 2 - - +1398529018.678276 4 192.168.18.50 NetControl::SEEN_AGAIN 86400.000000 604800.000000 1398615418.678276 1399133818.678276 3 - - +#close 2016-05-23-23-10-22 diff --git a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-cluster/manager-1.netcontrol.log b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-cluster/manager-1.netcontrol.log new file mode 100644 index 0000000000..c9b54ddc4a --- /dev/null +++ b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-cluster/manager-1.netcontrol.log @@ -0,0 +1,16 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path netcontrol +#open 2016-05-23-23-12-19 +#fields ts rule_id category cmd state action target entity_type entity mod msg priority expire location plugin +#types time string enum string enum string enum string string string string int interval string string +1464045139.397783 - NetControl::MESSAGE - - - - - - - activating plugin with priority 0 - - - Debug-All +1464045139.397783 - NetControl::MESSAGE - - - - - - - activation finished - - - Debug-All +1464045139.397783 - NetControl::MESSAGE - - - - - - - plugin initialization done - - - - +1464045142.528981 2 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 600.000000 - Debug-All +1464045142.528981 2 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 600.000000 - Debug-All +1464045143.525648 2 NetControl::RULE REMOVE NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 600.000000 - Debug-All +1464045143.525648 2 NetControl::RULE REMOVE NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 600.000000 - Debug-All +#close 2016-05-23-23-12-24 diff --git a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-cluster/manager-1.netcontrol_catch_release.log b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-cluster/manager-1.netcontrol_catch_release.log new file mode 100644 index 0000000000..2ac2de0b0b --- /dev/null +++ b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-cluster/manager-1.netcontrol_catch_release.log @@ -0,0 +1,12 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path netcontrol_catch_release +#open 2016-05-23-23-12-22 +#fields ts rule_id ip action block_interval watch_interval blocked_until watched_until num_blocked location message +#types time string addr enum interval interval time time count string string +1464045142.528981 2 192.168.18.50 NetControl::DROP 600.000000 3600.000000 1464045742.528981 1464048742.528981 1 - - +1464045143.525648 2 192.168.18.50 NetControl::UNBLOCK 600.000000 3600.000000 1464045742.528981 1464048742.528981 1 - - +1464045141.938582 2 192.168.18.50 NetControl::INFO 600.000000 3600.000000 1464045742.528981 1464048742.528981 1 - Already blocked using catch-and-release - ignoring duplicate +#close 2016-05-23-23-12-24 diff --git a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-cluster/worker-2..stdout b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-cluster/worker-2..stdout new file mode 100644 index 0000000000..0f9cf720cd --- /dev/null +++ b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-cluster/worker-2..stdout @@ -0,0 +1,6 @@ +Suspend, worker-2 +New block, 192.168.18.50, [block_until=1464045742.528981, watch_until=1464048742.528981, num_reblocked=0, current_interval=0, current_block_id=2] +Resume, worker-2 +Connection established +Info, [block_until=1464045742.528981, watch_until=1464048742.528981, num_reblocked=0, current_interval=0, current_block_id=2] +Delete block, 192.168.18.50 diff --git a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release/netcontrol.log b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release/netcontrol.log index f3bd6fafe0..c212997d65 100644 --- a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release/netcontrol.log +++ b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release/netcontrol.log @@ -3,16 +3,22 @@ #empty_field (empty) #unset_field - #path netcontrol -#open 2016-03-09-23-42-34 +#open 2016-05-23-23-08-40 #fields ts rule_id category cmd state action target entity_type entity mod msg priority expire location plugin #types time string enum string enum string enum string string string string int interval string string 0.000000 - NetControl::MESSAGE - - - - - - - activating plugin with priority 0 - - - Debug-All 0.000000 - NetControl::MESSAGE - - - - - - - activation finished - - - Debug-All 0.000000 - NetControl::MESSAGE - - - - - - - plugin initialization done - - - - 1398529018.678276 2 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 600.000000 - Debug-All -1398529018.678276 3 NetControl::RULE - NetControl::FAILED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - discarded duplicate insertion 0 3600.000000 Re-drop by catch-and-release - -1398529018.678276 4 NetControl::RULE - NetControl::FAILED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - discarded duplicate insertion 0 86400.000000 Re-drop by catch-and-release - -1398529018.678276 5 NetControl::RULE - NetControl::FAILED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - discarded duplicate insertion 0 604800.000000 Re-drop by catch-and-release - -1398529018.678276 6 NetControl::RULE - NetControl::FAILED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - discarded duplicate insertion 0 604800.000000 Re-drop by catch-and-release - 1398529018.678276 2 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 600.000000 - Debug-All -#close 2016-03-09-23-42-34 +1398529018.678276 3 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 3600.000000 Re-drop by catch-and-release Debug-All +1398529018.678276 3 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 3600.000000 Re-drop by catch-and-release Debug-All +1398529018.678276 4 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 86400.000000 Re-drop by catch-and-release Debug-All +1398529018.678276 4 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 86400.000000 Re-drop by catch-and-release Debug-All +1398529018.678276 5 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 604800.000000 Re-drop by catch-and-release Debug-All +1398529018.678276 5 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 604800.000000 Re-drop by catch-and-release Debug-All +1398529018.678276 6 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 604800.000000 Re-drop by catch-and-release Debug-All +1398529018.678276 6 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 604800.000000 Re-drop by catch-and-release Debug-All +1398529018.678276 7 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 604800.000000 Re-drop by catch-and-release Debug-All +1398529018.678276 7 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 604800.000000 Re-drop by catch-and-release Debug-All +#close 2016-05-23-23-08-40 diff --git a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release/netcontrol_catch_release.log b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release/netcontrol_catch_release.log new file mode 100644 index 0000000000..6bc7acf5d4 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release/netcontrol_catch_release.log @@ -0,0 +1,16 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path netcontrol_catch_release +#open 2016-05-23-23-10-12 +#fields ts rule_id ip action block_interval watch_interval blocked_until watched_until num_blocked location message +#types time string addr enum interval interval time time count string string +1398529018.678276 2 192.168.18.50 NetControl::DROP 600.000000 3600.000000 1398529618.678276 1398532618.678276 1 - - +1398529018.678276 2 192.168.18.50 NetControl::INFO 600.000000 3600.000000 1398529618.678276 1398532618.678276 1 - Already blocked using catch-and-release - ignoring duplicate +1398529018.678276 3 192.168.18.50 NetControl::SEEN_AGAIN 3600.000000 86400.000000 1398532618.678276 1398615418.678276 2 - - +1398529018.678276 4 192.168.18.50 NetControl::SEEN_AGAIN 86400.000000 604800.000000 1398615418.678276 1399133818.678276 3 - - +1398529018.678276 5 192.168.18.50 NetControl::SEEN_AGAIN 604800.000000 604800.000000 1399133818.678276 1399133818.678276 4 - - +1398529018.678276 6 192.168.18.50 NetControl::SEEN_AGAIN 604800.000000 604800.000000 1399133818.678276 1399133818.678276 5 - - +1398529018.678276 7 192.168.18.50 NetControl::SEEN_AGAIN 604800.000000 604800.000000 1399133818.678276 1399133818.678276 6 - - +#close 2016-05-23-23-10-12 diff --git a/testing/btest/scripts/base/frameworks/netcontrol/basic-cluster.bro b/testing/btest/scripts/base/frameworks/netcontrol/basic-cluster.bro index 051dd3eb82..9bbb3beb77 100644 --- a/testing/btest/scripts/base/frameworks/netcontrol/basic-cluster.bro +++ b/testing/btest/scripts/base/frameworks/netcontrol/basic-cluster.bro @@ -27,6 +27,11 @@ event bro_init() { suspend_processing(); } + +event remote_connection_handshake_done(p: event_peer) + { + continue_processing(); + } @endif event NetControl::init() @@ -35,13 +40,6 @@ event NetControl::init() NetControl::activate(netcontrol_debug, 0); } -@if ( Cluster::local_node_type() == Cluster::WORKER ) -event remote_connection_handshake_done(p: event_peer) - { - continue_processing(); - } -@endif - event connection_established(c: connection) { local id = c$id; diff --git a/testing/btest/scripts/base/frameworks/netcontrol/catch-and-release-cluster.bro b/testing/btest/scripts/base/frameworks/netcontrol/catch-and-release-cluster.bro new file mode 100644 index 0000000000..4377adeefd --- /dev/null +++ b/testing/btest/scripts/base/frameworks/netcontrol/catch-and-release-cluster.bro @@ -0,0 +1,114 @@ +# @TEST-SERIALIZE: comm +# +# @TEST-EXEC: btest-bg-run manager-1 "cp ../cluster-layout.bro . && CLUSTER_NODE=manager-1 bro %INPUT" +# @TEST-EXEC: sleep 1 +# @TEST-EXEC: btest-bg-run worker-1 "cp ../cluster-layout.bro . && CLUSTER_NODE=worker-1 bro --pseudo-realtime -C -r $TRACES/tls/ecdhe.pcap %INPUT" +# @TEST-EXEC: btest-bg-run worker-2 "cp ../cluster-layout.bro . && CLUSTER_NODE=worker-2 bro --pseudo-realtime -C -r $TRACES/tls/ecdhe.pcap %INPUT" +# @TEST-EXEC: btest-bg-wait 15 +# @TEST-EXEC: TEST_DIFF_CANONIFIER='grep -v ^# | $SCRIPTS/diff-remove-timestamps' btest-diff manager-1/netcontrol.log +# @TEST-EXEC: btest-diff manager-1/netcontrol_catch_release.log +# @TEST-EXEC: btest-diff worker-2/.stdout + +@TEST-START-FILE cluster-layout.bro +redef Cluster::nodes = { + ["manager-1"] = [$node_type=Cluster::MANAGER, $ip=127.0.0.1, $p=37757/tcp, $workers=set("worker-1", "worker-2")], + ["worker-1"] = [$node_type=Cluster::WORKER, $ip=127.0.0.1, $p=37760/tcp, $manager="manager-1", $interface="eth0"], + ["worker-2"] = [$node_type=Cluster::WORKER, $ip=127.0.0.1, $p=37761/tcp, $manager="manager-1", $interface="eth0"], +}; +@TEST-END-FILE + +redef Log::default_rotation_interval = 0secs; + +@load base/frameworks/netcontrol + +global ready_for_data_1: event(); +global ready_for_data_2: event(); +redef Cluster::manager2worker_events += /^ready_for_data_(1|2)$/; + +@if ( Cluster::local_node_type() == Cluster::MANAGER ) + +global peer_count = 0; +event remote_connection_handshake_done(p: event_peer) &priority=-5 + { + ++peer_count; + if ( peer_count == 2 ) + { + event ready_for_data_1(); + schedule 1sec { ready_for_data_2() }; + } + } + +@endif + +@if ( Cluster::local_node_type() == Cluster::WORKER ) +event bro_init() + { + print "Suspend", Cluster::node; + suspend_processing(); + } + +@endif + +@if ( Cluster::node == "worker-1" ) +event ready_for_data_1() + { + print "Resume", Cluster::node; + continue_processing(); + } +@endif + +@if ( Cluster::node == "worker-2" ) +event ready_for_data_2() + { + print "Resume", Cluster::node; + continue_processing(); + } +@endif + +event NetControl::init() + { + local netcontrol_debug = NetControl::create_debug(T); + NetControl::activate(netcontrol_debug, 0); + } + +global i: count = 0; + +event connection_established(c: connection) + { + print "Connection established"; + local id = c$id; + local info = NetControl::get_catch_release_info(id$orig_h); + print "Info", info; + NetControl::drop_address_catch_release(id$orig_h); + if ( info$current_block_id != "" ) + { + NetControl::unblock_address_catch_release(id$orig_h); + } + } + +event NetControl::catch_release_block_new(a: addr, b: NetControl::BlockInfo) + { + print "New block", a, b; + } + +event NetControl::catch_release_block_delete(a: addr) + { + print "Delete block", a; + } + +event terminate_me() { + print "Terminate"; + terminate(); +} + +event remote_connection_closed(p: event_peer) { + schedule 1sec { terminate_me() }; +} + +@if ( Cluster::local_node_type() == Cluster::MANAGER ) +event NetControl::rule_added(r: NetControl::Rule, p: NetControl::PluginState, msg: string) + { + print "Scheduling terminate"; + schedule 3sec { terminate_me() }; + } +@endif diff --git a/testing/btest/scripts/base/frameworks/netcontrol/catch-and-release.bro b/testing/btest/scripts/base/frameworks/netcontrol/catch-and-release.bro index a809833ecf..8bba808952 100644 --- a/testing/btest/scripts/base/frameworks/netcontrol/catch-and-release.bro +++ b/testing/btest/scripts/base/frameworks/netcontrol/catch-and-release.bro @@ -1,5 +1,6 @@ # @TEST-EXEC: bro -r $TRACES/tls/ecdhe.pcap %INPUT # @TEST-EXEC: TEST_DIFF_CANONIFIER='grep -v ^# | $SCRIPTS/diff-sort' btest-diff netcontrol.log +# @TEST-EXEC: btest-diff netcontrol_catch_release.log @load base/frameworks/netcontrol @@ -9,7 +10,7 @@ event NetControl::init() NetControl::activate(netcontrol_debug, 0); } -module NetControl; +global i: count = 0; event connection_established(c: connection) { @@ -17,15 +18,44 @@ event connection_established(c: connection) NetControl::drop_address_catch_release(id$orig_h); # second one should be ignored because duplicate NetControl::drop_address_catch_release(id$orig_h); - - # mean call directly into framework - simulate new connection - delete current_blocks[id$orig_h]; - check_conn(id$orig_h); - delete current_blocks[id$orig_h]; - check_conn(id$orig_h); - delete current_blocks[id$orig_h]; - check_conn(id$orig_h); - delete current_blocks[id$orig_h]; - check_conn(id$orig_h); + } + +event NetControl::rule_added(r: NetControl::Rule, p: NetControl::PluginState, msg: string &default="") + { + if ( ++i == 6 ) + return; + + # delete directly, without notifying anything. + NetControl::delete_rule(r$id); + NetControl::catch_release_seen(subnet_to_addr(r$entity$ip)); + } + +@TEST-START-NEXT + +@load base/frameworks/netcontrol + +event NetControl::init() + { + local netcontrol_debug = NetControl::create_debug(T); + NetControl::activate(netcontrol_debug, 0); + } + +global i: count = 0; + +event connection_established(c: connection) + { + local id = c$id; + NetControl::drop_address(id$orig_h, 2min); + NetControl::drop_address_catch_release(id$orig_h); + } + +event NetControl::rule_added(r: NetControl::Rule, p: NetControl::PluginState, msg: string &default="") + { + if ( ++i == 3 ) + return; + + # delete directly, without notifying anything. + NetControl::delete_rule(r$id); + NetControl::catch_release_seen(subnet_to_addr(r$entity$ip)); } From 296c5611ec48b4976976bdf27fabbd3b71427d36 Mon Sep 17 00:00:00 2001 From: Johanna Amann Date: Thu, 26 May 2016 16:53:42 -0700 Subject: [PATCH 08/13] NetControl: more catch and release logging and cluster fix --- .../netcontrol/catch-and-release.bro | 122 ++++++++++++++---- .../netcontrol_catch_release.log | 7 +- .../manager-1.netcontrol.log | 25 ++-- .../manager-1.netcontrol_catch_release.log | 16 ++- .../worker-2..stdout | 6 +- .../netcontrol_catch_release.log | 10 +- .../netcontrol/catch-and-release-cluster.bro | 17 ++- 7 files changed, 155 insertions(+), 48 deletions(-) diff --git a/scripts/base/frameworks/netcontrol/catch-and-release.bro b/scripts/base/frameworks/netcontrol/catch-and-release.bro index 68da74a63d..7160ee8c72 100644 --- a/scripts/base/frameworks/netcontrol/catch-and-release.bro +++ b/scripts/base/frameworks/netcontrol/catch-and-release.bro @@ -22,6 +22,8 @@ export { current_interval: count; # ID of the inserted block, if any. current_block_id: string; + # User specified string + location: string &optional; }; type CatchReleaseActions: enum { @@ -126,12 +128,47 @@ event bro_init() &priority=5 Log::create_stream(NetControl::CATCH_RELEASE, [$columns=CatchReleaseInfo, $ev=log_netcontrol_catch_release, $path="netcontrol_catch_release"]); } +function get_watch_interval(current_interval: count): interval + { + if ( (current_interval + 1) in catch_release_intervals ) + return catch_release_intervals[current_interval+1]; + else + return catch_release_intervals[current_interval]; + } + +function populate_log_record(ip: addr, bi: BlockInfo, action: CatchReleaseActions): CatchReleaseInfo + { + local log = CatchReleaseInfo($ts=network_time(), $ip=ip, $action=action, + $block_interval=catch_release_intervals[bi$current_interval], + $watch_interval=get_watch_interval(bi$current_interval), + $watched_until=bi$watch_until, + $num_blocked=bi$num_reblocked+1 + ); + + if ( bi?$block_until ) + log$blocked_until = bi$block_until; + + if ( bi?$current_block_id && bi$current_block_id != "" ) + log$rule_id = bi$current_block_id; + + if ( bi?$location ) + log$location = bi$location; + + return log; + } + function per_block_interval(t: table[addr] of BlockInfo, idx: addr): interval { local remaining_time = t[idx]$watch_until - network_time(); if ( remaining_time < 0secs ) remaining_time = 0secs; + if ( remaining_time == 0secs ) + { + local log = populate_log_record(idx, t[idx], FORGOTTEN); + Log::write(CATCH_RELEASE, log); + } + return remaining_time; } @@ -146,7 +183,60 @@ global blocks: table[addr] of BlockInfo = {} @if ( Cluster::is_enabled() ) @load base/frameworks/cluster redef Cluster::manager2worker_events += /NetControl::catch_release_block_(new|delete)/; -redef Cluster::worker2manager_events += /NetControl::catch_release_(add|delete|seen)/; +redef Cluster::worker2manager_events += /NetControl::catch_release_(add|delete|encountered)/; +@endif + +function cr_check_rule(r: Rule): bool + { + if ( r$ty == DROP && r$entity$ty == ADDRESS ) + { + local ip = r$entity$ip; + if ( ( is_v4_subnet(ip) && subnet_width(ip) == 32 ) || ( is_v6_subnet(ip) && subnet_width(ip) == 128 ) ) + { + if ( subnet_to_addr(ip) in blocks ) + return T; + } + } + + return F; + } + +@if ( ! Cluster::is_enabled() || ( Cluster::is_enabled() && Cluster::local_node_type() == Cluster::MANAGER ) ) + +event rule_added(r: Rule, p: PluginState, msg: string &default="") + { + if ( !cr_check_rule(r) ) + return; + + local ip = subnet_to_addr(r$entity$ip); + local bi = blocks[ip]; + + local log = populate_log_record(ip, bi, DROPPED); + if ( msg != "" ) + log$message = msg; + Log::write(CATCH_RELEASE, log); + } + + +event rule_timeout(r: Rule, i: FlowInfo, p: PluginState) + { + if ( !cr_check_rule(r) ) + return; + + local ip = subnet_to_addr(r$entity$ip); + local bi = blocks[ip]; + + local log = populate_log_record(ip, bi, UNBLOCK); + if ( bi?$block_until ) + { + local difference: interval = network_time() - bi$block_until; + if ( interval_to_double(difference) > 60 || interval_to_double(difference) < -60 ) + log$message = fmt("Difference betweek network_time and block time excessive: %f", difference); + } + + Log::write(CATCH_RELEASE, log); + } + @endif @if ( Cluster::is_enabled() && Cluster::local_node_type() == Cluster::MANAGER ) @@ -190,32 +280,6 @@ function get_catch_release_info(a: addr): BlockInfo return BlockInfo($watch_until=double_to_time(0), $current_interval=0, $current_block_id=""); } -function get_watch_interval(current_interval: count): interval - { - if ( (current_interval + 1) in catch_release_intervals ) - return catch_release_intervals[current_interval+1]; - else - return catch_release_intervals[current_interval]; - } - -function populate_log_record(ip: addr, bi: BlockInfo, action: CatchReleaseActions): CatchReleaseInfo - { - local log = CatchReleaseInfo($ts=network_time(), $ip=ip, $action=action, - $block_interval=catch_release_intervals[bi$current_interval], - $watch_interval=get_watch_interval(bi$current_interval), - $watched_until=bi$watch_until, - $num_blocked=bi$num_reblocked+1 - ); - - if ( bi?$block_until ) - log$blocked_until = bi$block_until; - - if ( bi?$current_block_id && bi$current_block_id != "" ) - log$rule_id = bi$current_block_id; - - return log; - } - function drop_address_catch_release(a: addr, location: string &default=""): BlockInfo { local bi: BlockInfo; @@ -236,6 +300,8 @@ function drop_address_catch_release(a: addr, location: string &default=""): Bloc local r = rule_entities[e,DROP]; bi = BlockInfo($watch_until=network_time()+catch_release_intervals[1], $current_interval=0, $current_block_id=r$id); + if ( location != "" ) + bi$location = location; @if ( ! Cluster::is_enabled() || ( Cluster::is_enabled() && Cluster::local_node_type() == Cluster::MANAGER ) ) log = populate_log_record(a, bi, ADDED); log$message = "Address already blocked outside of catch-and-release. Catch and release will monitor and only actively block if it appears in network traffic."; @@ -257,6 +323,8 @@ function drop_address_catch_release(a: addr, location: string &default=""): Bloc if ( ret != "" ) { bi = BlockInfo($watch_until=network_time()+catch_release_intervals[1], $block_until=network_time()+block_interval, $current_interval=0, $current_block_id=ret); + if ( location != "" ) + bi$location = location; blocks[a] = bi; event NetControl::catch_release_block_new(a, bi); blocks[a] = bi; diff --git a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-2/netcontrol_catch_release.log b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-2/netcontrol_catch_release.log index 8cd26677d2..d964706fa0 100644 --- a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-2/netcontrol_catch_release.log +++ b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-2/netcontrol_catch_release.log @@ -3,10 +3,13 @@ #empty_field (empty) #unset_field - #path netcontrol_catch_release -#open 2016-05-23-23-10-22 +#open 2016-05-26-23-20-50 #fields ts rule_id ip action block_interval watch_interval blocked_until watched_until num_blocked location message #types time string addr enum interval interval time time count string string 1398529018.678276 2 192.168.18.50 NetControl::ADDED 600.000000 3600.000000 - 1398532618.678276 1 - Address already blocked outside of catch-and-release. Catch and release will monitor and only actively block if it appears in network traffic. +1398529018.678276 2 192.168.18.50 NetControl::DROPPED 600.000000 3600.000000 - 1398532618.678276 1 - - 1398529018.678276 3 192.168.18.50 NetControl::SEEN_AGAIN 3600.000000 86400.000000 1398532618.678276 1398615418.678276 2 - - +1398529018.678276 3 192.168.18.50 NetControl::DROPPED 3600.000000 86400.000000 1398532618.678276 1398615418.678276 2 - - 1398529018.678276 4 192.168.18.50 NetControl::SEEN_AGAIN 86400.000000 604800.000000 1398615418.678276 1399133818.678276 3 - - -#close 2016-05-23-23-10-22 +1398529018.678276 4 192.168.18.50 NetControl::DROPPED 86400.000000 604800.000000 1398615418.678276 1399133818.678276 3 - - +#close 2016-05-26-23-20-50 diff --git a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-cluster/manager-1.netcontrol.log b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-cluster/manager-1.netcontrol.log index c9b54ddc4a..748e22f84f 100644 --- a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-cluster/manager-1.netcontrol.log +++ b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-cluster/manager-1.netcontrol.log @@ -3,14 +3,21 @@ #empty_field (empty) #unset_field - #path netcontrol -#open 2016-05-23-23-12-19 +#open 2016-05-26-23-42-55 #fields ts rule_id category cmd state action target entity_type entity mod msg priority expire location plugin #types time string enum string enum string enum string string string string int interval string string -1464045139.397783 - NetControl::MESSAGE - - - - - - - activating plugin with priority 0 - - - Debug-All -1464045139.397783 - NetControl::MESSAGE - - - - - - - activation finished - - - Debug-All -1464045139.397783 - NetControl::MESSAGE - - - - - - - plugin initialization done - - - - -1464045142.528981 2 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 600.000000 - Debug-All -1464045142.528981 2 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 600.000000 - Debug-All -1464045143.525648 2 NetControl::RULE REMOVE NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 600.000000 - Debug-All -1464045143.525648 2 NetControl::RULE REMOVE NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 600.000000 - Debug-All -#close 2016-05-23-23-12-24 +1464306175.160038 - NetControl::MESSAGE - - - - - - - activating plugin with priority 0 - - - Debug-All +1464306175.160038 - NetControl::MESSAGE - - - - - - - activation finished - - - Debug-All +1464306175.160038 - NetControl::MESSAGE - - - - - - - plugin initialization done - - - - +1464306178.277359 2 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 600.000000 - Debug-All +1464306178.277359 worker-1:2 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 8.8.8.8/32 - - 0 0.100000 - Debug-All +1464306178.277359 2 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 600.000000 - Debug-All +1464306178.277359 worker-1:2 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 8.8.8.8/32 - - 0 0.100000 - Debug-All +1464306178.378183 worker-1:2 NetControl::RULE EXPIRE NetControl::TIMEOUT NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 8.8.8.8/32 - - 0 0.100000 - Debug-All +1464306178.378183 worker-1:2 NetControl::RULE REMOVE NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 8.8.8.8/32 - - 0 0.100000 - Debug-All +1464306178.378183 worker-1:2 NetControl::RULE REMOVE NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 8.8.8.8/32 - - 0 0.100000 - Debug-All +1464306179.270933 2 NetControl::RULE REMOVE NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 600.000000 - Debug-All +1464306179.270933 2 NetControl::RULE REMOVE NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 600.000000 - Debug-All +1464306179.270933 4 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 8.8.8.8/32 - - 0 3600.000000 Re-drop by catch-and-release Debug-All +1464306179.270933 4 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 8.8.8.8/32 - - 0 3600.000000 Re-drop by catch-and-release Debug-All +#close 2016-05-26-23-42-59 diff --git a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-cluster/manager-1.netcontrol_catch_release.log b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-cluster/manager-1.netcontrol_catch_release.log index 2ac2de0b0b..fa2555514e 100644 --- a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-cluster/manager-1.netcontrol_catch_release.log +++ b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-cluster/manager-1.netcontrol_catch_release.log @@ -3,10 +3,16 @@ #empty_field (empty) #unset_field - #path netcontrol_catch_release -#open 2016-05-23-23-12-22 +#open 2016-05-26-23-42-58 #fields ts rule_id ip action block_interval watch_interval blocked_until watched_until num_blocked location message #types time string addr enum interval interval time time count string string -1464045142.528981 2 192.168.18.50 NetControl::DROP 600.000000 3600.000000 1464045742.528981 1464048742.528981 1 - - -1464045143.525648 2 192.168.18.50 NetControl::UNBLOCK 600.000000 3600.000000 1464045742.528981 1464048742.528981 1 - - -1464045141.938582 2 192.168.18.50 NetControl::INFO 600.000000 3600.000000 1464045742.528981 1464048742.528981 1 - Already blocked using catch-and-release - ignoring duplicate -#close 2016-05-23-23-12-24 +1464306178.277359 2 192.168.18.50 NetControl::DROP 600.000000 3600.000000 1464306778.277359 1464309778.277359 1 - - +1464306178.277359 2 192.168.18.50 NetControl::DROPPED 600.000000 3600.000000 1464306778.277359 1464309778.277359 1 - - +1464306178.277359 worker-1:2 8.8.8.8 NetControl::ADDED 600.000000 3600.000000 - 1464309778.277359 1 - Address already blocked outside of catch-and-release. Catch and release will monitor and only actively block if it appears in network traffic. +1464306178.378183 worker-1:2 8.8.8.8 NetControl::UNBLOCK 600.000000 3600.000000 - 1464309778.277359 1 - - +1464306179.270933 2 192.168.18.50 NetControl::INFO 600.000000 3600.000000 1464306778.277359 1464309778.277359 1 - Block seen while in rule_entities. No action taken. +1464306179.270933 2 192.168.18.50 NetControl::UNBLOCK 600.000000 3600.000000 1464306778.277359 1464309778.277359 1 - - +1464306179.270933 4 8.8.8.8 NetControl::SEEN_AGAIN 3600.000000 86400.000000 1464309779.270933 1464392579.270933 2 - - +1464306179.270933 4 8.8.8.8 NetControl::DROPPED 3600.000000 86400.000000 1464309779.270933 1464392579.270933 2 - - +1464306177.678733 2 192.168.18.50 NetControl::INFO 600.000000 3600.000000 1464306778.277359 1464309778.277359 1 - Already blocked using catch-and-release - ignoring duplicate +#close 2016-05-26-23-42-59 diff --git a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-cluster/worker-2..stdout b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-cluster/worker-2..stdout index 0f9cf720cd..f23caada2b 100644 --- a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-cluster/worker-2..stdout +++ b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-cluster/worker-2..stdout @@ -1,6 +1,8 @@ Suspend, worker-2 -New block, 192.168.18.50, [block_until=1464045742.528981, watch_until=1464048742.528981, num_reblocked=0, current_interval=0, current_block_id=2] +New block, 192.168.18.50, [block_until=1464306778.277359, watch_until=1464309778.277359, num_reblocked=0, current_interval=0, current_block_id=2, location=] +New block, 8.8.8.8, [block_until=, watch_until=1464309778.277359, num_reblocked=0, current_interval=0, current_block_id=worker-1:2, location=] Resume, worker-2 Connection established -Info, [block_until=1464045742.528981, watch_until=1464048742.528981, num_reblocked=0, current_interval=0, current_block_id=2] +Info, [block_until=1464306778.277359, watch_until=1464309778.277359, num_reblocked=0, current_interval=0, current_block_id=2, location=] Delete block, 192.168.18.50 +New block, 8.8.8.8, [block_until=1464309779.270933, watch_until=1464392579.270933, num_reblocked=1, current_interval=1, current_block_id=4, location=] diff --git a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release/netcontrol_catch_release.log b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release/netcontrol_catch_release.log index 6bc7acf5d4..672924c4f3 100644 --- a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release/netcontrol_catch_release.log +++ b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release/netcontrol_catch_release.log @@ -3,14 +3,20 @@ #empty_field (empty) #unset_field - #path netcontrol_catch_release -#open 2016-05-23-23-10-12 +#open 2016-05-26-23-20-44 #fields ts rule_id ip action block_interval watch_interval blocked_until watched_until num_blocked location message #types time string addr enum interval interval time time count string string 1398529018.678276 2 192.168.18.50 NetControl::DROP 600.000000 3600.000000 1398529618.678276 1398532618.678276 1 - - 1398529018.678276 2 192.168.18.50 NetControl::INFO 600.000000 3600.000000 1398529618.678276 1398532618.678276 1 - Already blocked using catch-and-release - ignoring duplicate +1398529018.678276 2 192.168.18.50 NetControl::DROPPED 600.000000 3600.000000 1398529618.678276 1398532618.678276 1 - - 1398529018.678276 3 192.168.18.50 NetControl::SEEN_AGAIN 3600.000000 86400.000000 1398532618.678276 1398615418.678276 2 - - +1398529018.678276 3 192.168.18.50 NetControl::DROPPED 3600.000000 86400.000000 1398532618.678276 1398615418.678276 2 - - 1398529018.678276 4 192.168.18.50 NetControl::SEEN_AGAIN 86400.000000 604800.000000 1398615418.678276 1399133818.678276 3 - - +1398529018.678276 4 192.168.18.50 NetControl::DROPPED 86400.000000 604800.000000 1398615418.678276 1399133818.678276 3 - - 1398529018.678276 5 192.168.18.50 NetControl::SEEN_AGAIN 604800.000000 604800.000000 1399133818.678276 1399133818.678276 4 - - +1398529018.678276 5 192.168.18.50 NetControl::DROPPED 604800.000000 604800.000000 1399133818.678276 1399133818.678276 4 - - 1398529018.678276 6 192.168.18.50 NetControl::SEEN_AGAIN 604800.000000 604800.000000 1399133818.678276 1399133818.678276 5 - - +1398529018.678276 6 192.168.18.50 NetControl::DROPPED 604800.000000 604800.000000 1399133818.678276 1399133818.678276 5 - - 1398529018.678276 7 192.168.18.50 NetControl::SEEN_AGAIN 604800.000000 604800.000000 1399133818.678276 1399133818.678276 6 - - -#close 2016-05-23-23-10-12 +1398529018.678276 7 192.168.18.50 NetControl::DROPPED 604800.000000 604800.000000 1399133818.678276 1399133818.678276 6 - - +#close 2016-05-26-23-20-44 diff --git a/testing/btest/scripts/base/frameworks/netcontrol/catch-and-release-cluster.bro b/testing/btest/scripts/base/frameworks/netcontrol/catch-and-release-cluster.bro index 4377adeefd..4175f23a0e 100644 --- a/testing/btest/scripts/base/frameworks/netcontrol/catch-and-release-cluster.bro +++ b/testing/btest/scripts/base/frameworks/netcontrol/catch-and-release-cluster.bro @@ -34,7 +34,7 @@ event remote_connection_handshake_done(p: event_peer) &priority=-5 if ( peer_count == 2 ) { event ready_for_data_1(); - schedule 1sec { ready_for_data_2() }; + schedule 1.5sec { ready_for_data_2() }; } } @@ -86,6 +86,21 @@ event connection_established(c: connection) } } +@if ( Cluster::node == "worker-1" ) +event connection_established(c: connection) + { + NetControl::drop_address(8.8.8.8, 0.1secs); + NetControl::drop_address_catch_release(8.8.8.8); + } +@endif + +@if ( Cluster::node == "worker-2" ) +event connection_established(c: connection) + { + NetControl::catch_release_seen(8.8.8.8); + } +@endif + event NetControl::catch_release_block_new(a: addr, b: NetControl::BlockInfo) { print "New block", a, b; From 2f748257851622489c8bef14b7f68a6f3edda9ca Mon Sep 17 00:00:00 2001 From: Johanna Amann Date: Fri, 27 May 2016 08:51:06 -0700 Subject: [PATCH 09/13] NetControl: fix several small logging issues forgotten messages are only logged on the manager (or standalone host) now. Logs are not written by default anymore when Bro encounters traffic that should have been blocked. --- .../frameworks/netcontrol/catch-and-release.bro | 16 ++++++++++++++++ .../netcontrol/catch-and-release-cluster.bro | 1 + 2 files changed, 17 insertions(+) diff --git a/scripts/base/frameworks/netcontrol/catch-and-release.bro b/scripts/base/frameworks/netcontrol/catch-and-release.bro index 7160ee8c72..f47edd8794 100644 --- a/scripts/base/frameworks/netcontrol/catch-and-release.bro +++ b/scripts/base/frameworks/netcontrol/catch-and-release.bro @@ -107,6 +107,10 @@ export { ## connection_reset and connection_pending const watch_connections = T &redef; + ## If true, catch and release warns if packets of an IP address are still seen after it + ## should have been blocked. + const catch_release_warn_blocked_ip_encountered = F &redef; + ## Time intervals for which a subsequent drops of the same IP take ## effect. const catch_release_intervals: vector of interval = vector(10min, 1hr, 24hrs, 7days) &redef; @@ -123,6 +127,9 @@ export { global catch_release_encountered: event(a: addr); } +# set that is used to only send seen notifications to the master every ~30 seconds. +global catch_release_recently_notified: set[addr] &create_expire=30secs; + event bro_init() &priority=5 { Log::create_stream(NetControl::CATCH_RELEASE, [$columns=CatchReleaseInfo, $ev=log_netcontrol_catch_release, $path="netcontrol_catch_release"]); @@ -163,11 +170,13 @@ function per_block_interval(t: table[addr] of BlockInfo, idx: addr): interval if ( remaining_time < 0secs ) remaining_time = 0secs; +@if ( ! Cluster::is_enabled() || ( Cluster::is_enabled() && Cluster::local_node_type() == Cluster::MANAGER ) ) if ( remaining_time == 0secs ) { local log = populate_log_record(idx, t[idx], FORGOTTEN); Log::write(CATCH_RELEASE, log); } +@endif return remaining_time; } @@ -379,6 +388,9 @@ function catch_release_seen(a: addr) if ( [e,DROP] in rule_entities ) { + if ( catch_release_warn_blocked_ip_encountered == F ) + return; + # This should be blocked - block has not been applied yet by hardware? Ignore for the moment... log = populate_log_record(a, bi, INFO); log$action = INFO; @@ -415,7 +427,11 @@ function catch_release_seen(a: addr) event NetControl::catch_release_block_new(a, bi); @endif @if ( Cluster::is_enabled() && Cluster::local_node_type() != Cluster::MANAGER ) + if ( a in catch_release_recently_notified ) + return; + event NetControl::catch_release_encountered(a); + add catch_release_recently_notified[a]; @endif return; diff --git a/testing/btest/scripts/base/frameworks/netcontrol/catch-and-release-cluster.bro b/testing/btest/scripts/base/frameworks/netcontrol/catch-and-release-cluster.bro index 4175f23a0e..83a66b35ca 100644 --- a/testing/btest/scripts/base/frameworks/netcontrol/catch-and-release-cluster.bro +++ b/testing/btest/scripts/base/frameworks/netcontrol/catch-and-release-cluster.bro @@ -20,6 +20,7 @@ redef Cluster::nodes = { redef Log::default_rotation_interval = 0secs; @load base/frameworks/netcontrol +redef NetControl::catch_release_warn_blocked_ip_encountered = T; global ready_for_data_1: event(); global ready_for_data_2: event(); From 990836e86889f82ea470939a9120f5a5d19e279d Mon Sep 17 00:00:00 2001 From: Johanna Amann Date: Tue, 31 May 2016 11:52:42 -0700 Subject: [PATCH 10/13] NetControl: slightly update catch and release logging Re-drops now contain the location of the original drop. --- .../netcontrol/catch-and-release.bro | 7 ++-- .../netcontrol.log | 12 +++---- .../netcontrol_catch_release.log | 16 +++++----- .../manager-1.netcontrol.log | 32 +++++++++---------- .../netcontrol.log | 24 +++++++------- .../netcontrol/catch-and-release.bro | 2 +- 6 files changed, 48 insertions(+), 45 deletions(-) diff --git a/scripts/base/frameworks/netcontrol/catch-and-release.bro b/scripts/base/frameworks/netcontrol/catch-and-release.bro index f47edd8794..8b3c389b6c 100644 --- a/scripts/base/frameworks/netcontrol/catch-and-release.bro +++ b/scripts/base/frameworks/netcontrol/catch-and-release.bro @@ -240,7 +240,7 @@ event rule_timeout(r: Rule, i: FlowInfo, p: PluginState) { local difference: interval = network_time() - bi$block_until; if ( interval_to_double(difference) > 60 || interval_to_double(difference) < -60 ) - log$message = fmt("Difference betweek network_time and block time excessive: %f", difference); + log$message = fmt("Difference between network_time and block time excessive: %f", difference); } Log::write(CATCH_RELEASE, log); @@ -415,7 +415,10 @@ function catch_release_seen(a: addr) ++bi$num_reblocked; local block_interval = catch_release_intervals[try]; - local drop = drop_address(a, block_interval, "Re-drop by catch-and-release"); + local location = ""; + if ( bi?$location ) + location = bi$location; + local drop = drop_address(a, block_interval, fmt("Re-drop by catch-and-release: %s", location)); bi$current_block_id = drop; blocks[a] = bi; diff --git a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-2/netcontrol.log b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-2/netcontrol.log index 3650d267fe..5d45e5aea9 100644 --- a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-2/netcontrol.log +++ b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-2/netcontrol.log @@ -3,7 +3,7 @@ #empty_field (empty) #unset_field - #path netcontrol -#open 2016-05-23-23-09-43 +#open 2016-05-31-18-51-29 #fields ts rule_id category cmd state action target entity_type entity mod msg priority expire location plugin #types time string enum string enum string enum string string string string int interval string string 0.000000 - NetControl::MESSAGE - - - - - - - activating plugin with priority 0 - - - Debug-All @@ -11,8 +11,8 @@ 0.000000 - NetControl::MESSAGE - - - - - - - plugin initialization done - - - - 1398529018.678276 2 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 120.000000 - Debug-All 1398529018.678276 2 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 120.000000 - Debug-All -1398529018.678276 3 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 3600.000000 Re-drop by catch-and-release Debug-All -1398529018.678276 3 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 3600.000000 Re-drop by catch-and-release Debug-All -1398529018.678276 4 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 86400.000000 Re-drop by catch-and-release Debug-All -1398529018.678276 4 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 86400.000000 Re-drop by catch-and-release Debug-All -#close 2016-05-23-23-09-43 +1398529018.678276 3 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 3600.000000 Re-drop by catch-and-release: test drop Debug-All +1398529018.678276 3 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 3600.000000 Re-drop by catch-and-release: test drop Debug-All +1398529018.678276 4 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 86400.000000 Re-drop by catch-and-release: test drop Debug-All +1398529018.678276 4 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 86400.000000 Re-drop by catch-and-release: test drop Debug-All +#close 2016-05-31-18-51-29 diff --git a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-2/netcontrol_catch_release.log b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-2/netcontrol_catch_release.log index d964706fa0..552eb96a92 100644 --- a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-2/netcontrol_catch_release.log +++ b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-2/netcontrol_catch_release.log @@ -3,13 +3,13 @@ #empty_field (empty) #unset_field - #path netcontrol_catch_release -#open 2016-05-26-23-20-50 +#open 2016-05-31-18-51-29 #fields ts rule_id ip action block_interval watch_interval blocked_until watched_until num_blocked location message #types time string addr enum interval interval time time count string string -1398529018.678276 2 192.168.18.50 NetControl::ADDED 600.000000 3600.000000 - 1398532618.678276 1 - Address already blocked outside of catch-and-release. Catch and release will monitor and only actively block if it appears in network traffic. -1398529018.678276 2 192.168.18.50 NetControl::DROPPED 600.000000 3600.000000 - 1398532618.678276 1 - - -1398529018.678276 3 192.168.18.50 NetControl::SEEN_AGAIN 3600.000000 86400.000000 1398532618.678276 1398615418.678276 2 - - -1398529018.678276 3 192.168.18.50 NetControl::DROPPED 3600.000000 86400.000000 1398532618.678276 1398615418.678276 2 - - -1398529018.678276 4 192.168.18.50 NetControl::SEEN_AGAIN 86400.000000 604800.000000 1398615418.678276 1399133818.678276 3 - - -1398529018.678276 4 192.168.18.50 NetControl::DROPPED 86400.000000 604800.000000 1398615418.678276 1399133818.678276 3 - - -#close 2016-05-26-23-20-50 +1398529018.678276 2 192.168.18.50 NetControl::ADDED 600.000000 3600.000000 - 1398532618.678276 1 test drop Address already blocked outside of catch-and-release. Catch and release will monitor and only actively block if it appears in network traffic. +1398529018.678276 2 192.168.18.50 NetControl::DROPPED 600.000000 3600.000000 - 1398532618.678276 1 test drop - +1398529018.678276 3 192.168.18.50 NetControl::SEEN_AGAIN 3600.000000 86400.000000 1398532618.678276 1398615418.678276 2 test drop - +1398529018.678276 3 192.168.18.50 NetControl::DROPPED 3600.000000 86400.000000 1398532618.678276 1398615418.678276 2 test drop - +1398529018.678276 4 192.168.18.50 NetControl::SEEN_AGAIN 86400.000000 604800.000000 1398615418.678276 1399133818.678276 3 test drop - +1398529018.678276 4 192.168.18.50 NetControl::DROPPED 86400.000000 604800.000000 1398615418.678276 1399133818.678276 3 test drop - +#close 2016-05-31-18-51-29 diff --git a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-cluster/manager-1.netcontrol.log b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-cluster/manager-1.netcontrol.log index 748e22f84f..4325784591 100644 --- a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-cluster/manager-1.netcontrol.log +++ b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release-cluster/manager-1.netcontrol.log @@ -3,21 +3,21 @@ #empty_field (empty) #unset_field - #path netcontrol -#open 2016-05-26-23-42-55 +#open 2016-05-31-18-51-46 #fields ts rule_id category cmd state action target entity_type entity mod msg priority expire location plugin #types time string enum string enum string enum string string string string int interval string string -1464306175.160038 - NetControl::MESSAGE - - - - - - - activating plugin with priority 0 - - - Debug-All -1464306175.160038 - NetControl::MESSAGE - - - - - - - activation finished - - - Debug-All -1464306175.160038 - NetControl::MESSAGE - - - - - - - plugin initialization done - - - - -1464306178.277359 2 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 600.000000 - Debug-All -1464306178.277359 worker-1:2 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 8.8.8.8/32 - - 0 0.100000 - Debug-All -1464306178.277359 2 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 600.000000 - Debug-All -1464306178.277359 worker-1:2 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 8.8.8.8/32 - - 0 0.100000 - Debug-All -1464306178.378183 worker-1:2 NetControl::RULE EXPIRE NetControl::TIMEOUT NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 8.8.8.8/32 - - 0 0.100000 - Debug-All -1464306178.378183 worker-1:2 NetControl::RULE REMOVE NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 8.8.8.8/32 - - 0 0.100000 - Debug-All -1464306178.378183 worker-1:2 NetControl::RULE REMOVE NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 8.8.8.8/32 - - 0 0.100000 - Debug-All -1464306179.270933 2 NetControl::RULE REMOVE NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 600.000000 - Debug-All -1464306179.270933 2 NetControl::RULE REMOVE NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 600.000000 - Debug-All -1464306179.270933 4 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 8.8.8.8/32 - - 0 3600.000000 Re-drop by catch-and-release Debug-All -1464306179.270933 4 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 8.8.8.8/32 - - 0 3600.000000 Re-drop by catch-and-release Debug-All -#close 2016-05-26-23-42-59 +1464720706.881330 - NetControl::MESSAGE - - - - - - - activating plugin with priority 0 - - - Debug-All +1464720706.881330 - NetControl::MESSAGE - - - - - - - activation finished - - - Debug-All +1464720706.881330 - NetControl::MESSAGE - - - - - - - plugin initialization done - - - - +1464720710.013657 2 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 600.000000 - Debug-All +1464720710.013657 worker-1:2 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 8.8.8.8/32 - - 0 0.100000 - Debug-All +1464720710.013657 2 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 600.000000 - Debug-All +1464720710.013657 worker-1:2 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 8.8.8.8/32 - - 0 0.100000 - Debug-All +1464720710.113687 worker-1:2 NetControl::RULE EXPIRE NetControl::TIMEOUT NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 8.8.8.8/32 - - 0 0.100000 - Debug-All +1464720710.113687 worker-1:2 NetControl::RULE REMOVE NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 8.8.8.8/32 - - 0 0.100000 - Debug-All +1464720710.113687 worker-1:2 NetControl::RULE REMOVE NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 8.8.8.8/32 - - 0 0.100000 - Debug-All +1464720711.498477 2 NetControl::RULE REMOVE NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 600.000000 - Debug-All +1464720711.498477 2 NetControl::RULE REMOVE NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 600.000000 - Debug-All +1464720711.498477 4 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 8.8.8.8/32 - - 0 3600.000000 Re-drop by catch-and-release: Debug-All +1464720711.498477 4 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 8.8.8.8/32 - - 0 3600.000000 Re-drop by catch-and-release: Debug-All +#close 2016-05-31-18-51-51 diff --git a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release/netcontrol.log b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release/netcontrol.log index c212997d65..d06be0682c 100644 --- a/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release/netcontrol.log +++ b/testing/btest/Baseline/scripts.base.frameworks.netcontrol.catch-and-release/netcontrol.log @@ -3,7 +3,7 @@ #empty_field (empty) #unset_field - #path netcontrol -#open 2016-05-23-23-08-40 +#open 2016-05-31-18-51-24 #fields ts rule_id category cmd state action target entity_type entity mod msg priority expire location plugin #types time string enum string enum string enum string string string string int interval string string 0.000000 - NetControl::MESSAGE - - - - - - - activating plugin with priority 0 - - - Debug-All @@ -11,14 +11,14 @@ 0.000000 - NetControl::MESSAGE - - - - - - - plugin initialization done - - - - 1398529018.678276 2 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 600.000000 - Debug-All 1398529018.678276 2 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 600.000000 - Debug-All -1398529018.678276 3 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 3600.000000 Re-drop by catch-and-release Debug-All -1398529018.678276 3 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 3600.000000 Re-drop by catch-and-release Debug-All -1398529018.678276 4 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 86400.000000 Re-drop by catch-and-release Debug-All -1398529018.678276 4 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 86400.000000 Re-drop by catch-and-release Debug-All -1398529018.678276 5 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 604800.000000 Re-drop by catch-and-release Debug-All -1398529018.678276 5 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 604800.000000 Re-drop by catch-and-release Debug-All -1398529018.678276 6 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 604800.000000 Re-drop by catch-and-release Debug-All -1398529018.678276 6 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 604800.000000 Re-drop by catch-and-release Debug-All -1398529018.678276 7 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 604800.000000 Re-drop by catch-and-release Debug-All -1398529018.678276 7 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 604800.000000 Re-drop by catch-and-release Debug-All -#close 2016-05-23-23-08-40 +1398529018.678276 3 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 3600.000000 Re-drop by catch-and-release: Debug-All +1398529018.678276 3 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 3600.000000 Re-drop by catch-and-release: Debug-All +1398529018.678276 4 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 86400.000000 Re-drop by catch-and-release: Debug-All +1398529018.678276 4 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 86400.000000 Re-drop by catch-and-release: Debug-All +1398529018.678276 5 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 604800.000000 Re-drop by catch-and-release: Debug-All +1398529018.678276 5 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 604800.000000 Re-drop by catch-and-release: Debug-All +1398529018.678276 6 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 604800.000000 Re-drop by catch-and-release: Debug-All +1398529018.678276 6 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 604800.000000 Re-drop by catch-and-release: Debug-All +1398529018.678276 7 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 604800.000000 Re-drop by catch-and-release: Debug-All +1398529018.678276 7 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.50/32 - - 0 604800.000000 Re-drop by catch-and-release: Debug-All +#close 2016-05-31-18-51-24 diff --git a/testing/btest/scripts/base/frameworks/netcontrol/catch-and-release.bro b/testing/btest/scripts/base/frameworks/netcontrol/catch-and-release.bro index 8bba808952..66daa06d69 100644 --- a/testing/btest/scripts/base/frameworks/netcontrol/catch-and-release.bro +++ b/testing/btest/scripts/base/frameworks/netcontrol/catch-and-release.bro @@ -46,7 +46,7 @@ event connection_established(c: connection) { local id = c$id; NetControl::drop_address(id$orig_h, 2min); - NetControl::drop_address_catch_release(id$orig_h); + NetControl::drop_address_catch_release(id$orig_h, "test drop"); } event NetControl::rule_added(r: NetControl::Rule, p: NetControl::PluginState, msg: string &default="") From 3b55a917ac5ab9323322468b538c9640de24a357 Mon Sep 17 00:00:00 2001 From: Johanna Amann Date: Wed, 22 Jun 2016 16:01:26 -0700 Subject: [PATCH 11/13] Use NetControl for ACTION_DROP of notice framework. So far, this action did nothing... --- scripts/base/frameworks/notice/actions/drop.bro | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/scripts/base/frameworks/notice/actions/drop.bro b/scripts/base/frameworks/notice/actions/drop.bro index aaed27bc4a..2dc374b154 100644 --- a/scripts/base/frameworks/notice/actions/drop.bro +++ b/scripts/base/frameworks/notice/actions/drop.bro @@ -2,13 +2,13 @@ ##! dropping functionality. @load ../main +@load base/frameworks/netcontrol module Notice; export { redef enum Action += { - ## Drops the address via Drop::drop_address, and generates an - ## alarm. + ## Drops the address via :bro:see:`NetControl::drop_address_catch_release`. ACTION_DROP }; @@ -23,9 +23,13 @@ hook notice(n: Notice::Info) { if ( ACTION_DROP in n$actions ) { - #local drop = React::drop_address(n$src, ""); - #local addl = drop?$sub ? fmt(" %s", drop$sub) : ""; - #n$dropped = drop$note != Drop::AddressDropIgnored; - #n$msg += fmt(" [%s%s]", drop$note, addl); + local ci = NetControl::get_catch_release_info(n$src); + if ( ci$watch_until == double_to_time(0) ) + { + # we have not seen this one yet. Drop it. + local addl = n?$msg ? fmt("ACTION_DROP: %s", n?$msg) : "ACTION_DROP"; + local res = NetControl::drop_address_catch_release(n$src, addl); + n$dropped = res$watch_until != double_to_time(0); + } } } From f1267b0b9450dec5a9784ac52ac1ee358e251d3c Mon Sep 17 00:00:00 2001 From: Johanna Amann Date: Wed, 22 Jun 2016 16:02:48 -0700 Subject: [PATCH 12/13] Write NetControl framework documentation. In the process, some of the script documentation of the NetControl framework was also updated. --- doc/frameworks/index.rst | 1 + doc/frameworks/input.rst | 2 +- .../netcontrol-1-drop-with-debug.bro | 10 + doc/frameworks/netcontrol-10-use-skeleton.bro | 10 + doc/frameworks/netcontrol-2-ssh-guesser.bro | 16 + doc/frameworks/netcontrol-3-ssh-guesser.bro | 16 + doc/frameworks/netcontrol-4-drop.bro | 26 + doc/frameworks/netcontrol-5-hook.bro | 22 + doc/frameworks/netcontrol-6-find.bro | 17 + doc/frameworks/netcontrol-7-catch-release.bro | 10 + doc/frameworks/netcontrol-8-multiple.bro | 29 + doc/frameworks/netcontrol-9-skeleton.bro | 39 ++ doc/frameworks/netcontrol-architecture.png | Bin 0 -> 103171 bytes doc/frameworks/netcontrol-openflow.png | Bin 0 -> 85573 bytes doc/frameworks/netcontrol-rules.png | Bin 0 -> 91598 bytes doc/frameworks/netcontrol.rst | 633 ++++++++++++++++++ doc/script-reference/log-files.rst | 17 + .../netcontrol/catch-and-release.bro | 41 +- scripts/base/frameworks/netcontrol/main.bro | 46 +- scripts/base/frameworks/netcontrol/plugin.bro | 92 +-- .../frameworks/netcontrol/plugins/broker.bro | 2 + .../netcontrol/plugins/openflow.bro | 38 +- scripts/base/frameworks/netcontrol/types.bro | 53 +- .../canonified_loaded_scripts.log | 60 +- .../btest/Baseline/coverage.find-bro-logs/out | 1 + .../output | 14 + .../output | 14 + .../output | 20 + .../output | 20 + .../output | 30 + .../output | 26 + .../output | 21 + .../output | 14 + .../output | 33 + .../output | 43 ++ ....sphinx.netcontrol-1-drop-with-debug.bro#1 | 32 + ....sphinx.netcontrol-1-drop-with-debug.bro#2 | 18 + ...-doc.sphinx.netcontrol-2-ssh-guesser.bro#1 | 32 + ...-doc.sphinx.netcontrol-3-ssh-guesser.bro#1 | 32 + ...-doc.sphinx.netcontrol-3-ssh-guesser.bro#2 | 18 + .../btest-doc.sphinx.netcontrol-4-drop.bro#1 | 32 + .../btest-doc.sphinx.netcontrol-5-hook.bro#1 | 10 + .../btest-doc.sphinx.netcontrol-6-find.bro#1 | 12 + ...oc.sphinx.netcontrol-7-catch-release.bro#1 | 10 + ...oc.sphinx.netcontrol-7-catch-release.bro#2 | 19 + ...est-doc.sphinx.netcontrol-8-multiple.bro#1 | 10 + ...est-doc.sphinx.netcontrol-8-multiple.bro#2 | 28 + ...est-doc.sphinx.netcontrol-8-multiple.bro#3 | 21 + ...est-doc.sphinx.netcontrol-8-multiple.bro#4 | 15 + ...est-doc.sphinx.netcontrol-9-skeleton.bro#1 | 15 + testing/btest/Baseline/plugins.hooks/output | 48 +- .../all-events-no-args.log | 10 +- .../all-events.log | 28 +- ...rks_netcontrol-1-drop-with-debug_bro.btest | 14 + ...works_netcontrol-10-use-skeleton_bro.btest | 14 + ...meworks_netcontrol-2-ssh-guesser_bro.btest | 20 + ...meworks_netcontrol-3-ssh-guesser_bro.btest | 20 + ...doc_frameworks_netcontrol-4-drop_bro.btest | 30 + ...doc_frameworks_netcontrol-5-hook_bro.btest | 26 + ...doc_frameworks_netcontrol-6-find_bro.btest | 21 + ...works_netcontrol-7-catch-release_bro.btest | 14 + ...frameworks_netcontrol-8-multiple_bro.btest | 33 + ...frameworks_netcontrol-9-skeleton_bro.btest | 43 ++ .../netcontrol-1-drop-with-debug.bro.btest | 2 + .../netcontrol-1-drop-with-debug.bro.btest#2 | 1 + .../sphinx/netcontrol-2-ssh-guesser.bro.btest | 2 + .../sphinx/netcontrol-3-ssh-guesser.bro.btest | 2 + .../netcontrol-3-ssh-guesser.bro.btest#2 | 1 + .../doc/sphinx/netcontrol-4-drop.bro.btest | 2 + .../doc/sphinx/netcontrol-5-hook.bro.btest | 1 + .../doc/sphinx/netcontrol-6-find.bro.btest | 1 + .../netcontrol-7-catch-release.bro.btest | 1 + .../netcontrol-7-catch-release.bro.btest#2 | 1 + .../sphinx/netcontrol-8-multiple.bro.btest | 1 + .../sphinx/netcontrol-8-multiple.bro.btest#2 | 1 + .../sphinx/netcontrol-8-multiple.bro.btest#3 | 1 + .../sphinx/netcontrol-8-multiple.bro.btest#4 | 1 + .../sphinx/netcontrol-9-skeleton.bro.btest | 1 + 78 files changed, 1918 insertions(+), 142 deletions(-) create mode 100644 doc/frameworks/netcontrol-1-drop-with-debug.bro create mode 100644 doc/frameworks/netcontrol-10-use-skeleton.bro create mode 100644 doc/frameworks/netcontrol-2-ssh-guesser.bro create mode 100644 doc/frameworks/netcontrol-3-ssh-guesser.bro create mode 100644 doc/frameworks/netcontrol-4-drop.bro create mode 100644 doc/frameworks/netcontrol-5-hook.bro create mode 100644 doc/frameworks/netcontrol-6-find.bro create mode 100644 doc/frameworks/netcontrol-7-catch-release.bro create mode 100644 doc/frameworks/netcontrol-8-multiple.bro create mode 100644 doc/frameworks/netcontrol-9-skeleton.bro create mode 100644 doc/frameworks/netcontrol-architecture.png create mode 100644 doc/frameworks/netcontrol-openflow.png create mode 100644 doc/frameworks/netcontrol-rules.png create mode 100644 doc/frameworks/netcontrol.rst create mode 100644 testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-1-drop-with-debug_bro/output create mode 100644 testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-10-use-skeleton_bro/output create mode 100644 testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-2-ssh-guesser_bro/output create mode 100644 testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-3-ssh-guesser_bro/output create mode 100644 testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-4-drop_bro/output create mode 100644 testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-5-hook_bro/output create mode 100644 testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-6-find_bro/output create mode 100644 testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-7-catch-release_bro/output create mode 100644 testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-8-multiple_bro/output create mode 100644 testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-9-skeleton_bro/output create mode 100644 testing/btest/Baseline/doc.sphinx.netcontrol-1-drop-with-debug.bro/btest-doc.sphinx.netcontrol-1-drop-with-debug.bro#1 create mode 100644 testing/btest/Baseline/doc.sphinx.netcontrol-1-drop-with-debug.bro/btest-doc.sphinx.netcontrol-1-drop-with-debug.bro#2 create mode 100644 testing/btest/Baseline/doc.sphinx.netcontrol-2-ssh-guesser.bro/btest-doc.sphinx.netcontrol-2-ssh-guesser.bro#1 create mode 100644 testing/btest/Baseline/doc.sphinx.netcontrol-3-ssh-guesser.bro/btest-doc.sphinx.netcontrol-3-ssh-guesser.bro#1 create mode 100644 testing/btest/Baseline/doc.sphinx.netcontrol-3-ssh-guesser.bro/btest-doc.sphinx.netcontrol-3-ssh-guesser.bro#2 create mode 100644 testing/btest/Baseline/doc.sphinx.netcontrol-4-drop.bro/btest-doc.sphinx.netcontrol-4-drop.bro#1 create mode 100644 testing/btest/Baseline/doc.sphinx.netcontrol-5-hook.bro/btest-doc.sphinx.netcontrol-5-hook.bro#1 create mode 100644 testing/btest/Baseline/doc.sphinx.netcontrol-6-find.bro/btest-doc.sphinx.netcontrol-6-find.bro#1 create mode 100644 testing/btest/Baseline/doc.sphinx.netcontrol-7-catch-release.bro/btest-doc.sphinx.netcontrol-7-catch-release.bro#1 create mode 100644 testing/btest/Baseline/doc.sphinx.netcontrol-7-catch-release.bro/btest-doc.sphinx.netcontrol-7-catch-release.bro#2 create mode 100644 testing/btest/Baseline/doc.sphinx.netcontrol-8-multiple.bro/btest-doc.sphinx.netcontrol-8-multiple.bro#1 create mode 100644 testing/btest/Baseline/doc.sphinx.netcontrol-8-multiple.bro/btest-doc.sphinx.netcontrol-8-multiple.bro#2 create mode 100644 testing/btest/Baseline/doc.sphinx.netcontrol-8-multiple.bro/btest-doc.sphinx.netcontrol-8-multiple.bro#3 create mode 100644 testing/btest/Baseline/doc.sphinx.netcontrol-8-multiple.bro/btest-doc.sphinx.netcontrol-8-multiple.bro#4 create mode 100644 testing/btest/Baseline/doc.sphinx.netcontrol-9-skeleton.bro/btest-doc.sphinx.netcontrol-9-skeleton.bro#1 create mode 100644 testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-1-drop-with-debug_bro.btest create mode 100644 testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-10-use-skeleton_bro.btest create mode 100644 testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-2-ssh-guesser_bro.btest create mode 100644 testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-3-ssh-guesser_bro.btest create mode 100644 testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-4-drop_bro.btest create mode 100644 testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-5-hook_bro.btest create mode 100644 testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-6-find_bro.btest create mode 100644 testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-7-catch-release_bro.btest create mode 100644 testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-8-multiple_bro.btest create mode 100644 testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-9-skeleton_bro.btest create mode 100644 testing/btest/doc/sphinx/netcontrol-1-drop-with-debug.bro.btest create mode 100644 testing/btest/doc/sphinx/netcontrol-1-drop-with-debug.bro.btest#2 create mode 100644 testing/btest/doc/sphinx/netcontrol-2-ssh-guesser.bro.btest create mode 100644 testing/btest/doc/sphinx/netcontrol-3-ssh-guesser.bro.btest create mode 100644 testing/btest/doc/sphinx/netcontrol-3-ssh-guesser.bro.btest#2 create mode 100644 testing/btest/doc/sphinx/netcontrol-4-drop.bro.btest create mode 100644 testing/btest/doc/sphinx/netcontrol-5-hook.bro.btest create mode 100644 testing/btest/doc/sphinx/netcontrol-6-find.bro.btest create mode 100644 testing/btest/doc/sphinx/netcontrol-7-catch-release.bro.btest create mode 100644 testing/btest/doc/sphinx/netcontrol-7-catch-release.bro.btest#2 create mode 100644 testing/btest/doc/sphinx/netcontrol-8-multiple.bro.btest create mode 100644 testing/btest/doc/sphinx/netcontrol-8-multiple.bro.btest#2 create mode 100644 testing/btest/doc/sphinx/netcontrol-8-multiple.bro.btest#3 create mode 100644 testing/btest/doc/sphinx/netcontrol-8-multiple.bro.btest#4 create mode 100644 testing/btest/doc/sphinx/netcontrol-9-skeleton.bro.btest diff --git a/doc/frameworks/index.rst b/doc/frameworks/index.rst index 028f95af21..4f87df3b53 100644 --- a/doc/frameworks/index.rst +++ b/doc/frameworks/index.rst @@ -11,6 +11,7 @@ Frameworks input intel logging + netcontrol notice signatures sumstats diff --git a/doc/frameworks/input.rst b/doc/frameworks/input.rst index aa2dce6417..01c1658d34 100644 --- a/doc/frameworks/input.rst +++ b/doc/frameworks/input.rst @@ -7,7 +7,7 @@ Input Framework .. rst-class:: opening - Bro now features a flexible input framework that allows users + Bro features a flexible input framework that allows users to import data into Bro. Data is either read into Bro tables or converted to events which can then be handled by scripts. This document gives an overview of how to use the input framework diff --git a/doc/frameworks/netcontrol-1-drop-with-debug.bro b/doc/frameworks/netcontrol-1-drop-with-debug.bro new file mode 100644 index 0000000000..d4bbcde042 --- /dev/null +++ b/doc/frameworks/netcontrol-1-drop-with-debug.bro @@ -0,0 +1,10 @@ +event NetControl::init() + { + local debug_plugin = NetControl::create_debug(T); + NetControl::activate(debug_plugin, 0); + } + +event connection_established(c: connection) + { + NetControl::drop_connection(c$id, 20 secs); + } diff --git a/doc/frameworks/netcontrol-10-use-skeleton.bro b/doc/frameworks/netcontrol-10-use-skeleton.bro new file mode 100644 index 0000000000..4f683dfd83 --- /dev/null +++ b/doc/frameworks/netcontrol-10-use-skeleton.bro @@ -0,0 +1,10 @@ +event NetControl::init() + { + local skeleton_plugin = NetControl::create_skeleton(""); + NetControl::activate(skeleton_plugin, 0); + } + +event connection_established(c: connection) + { + NetControl::drop_connection(c$id, 20 secs); + } diff --git a/doc/frameworks/netcontrol-2-ssh-guesser.bro b/doc/frameworks/netcontrol-2-ssh-guesser.bro new file mode 100644 index 0000000000..2b8757cdea --- /dev/null +++ b/doc/frameworks/netcontrol-2-ssh-guesser.bro @@ -0,0 +1,16 @@ + +@load protocols/ssh/detect-bruteforcing + +redef SSH::password_guesses_limit=10; + +event NetControl::init() + { + local debug_plugin = NetControl::create_debug(T); + NetControl::activate(debug_plugin, 0); + } + +hook Notice::policy(n: Notice::Info) + { + if ( n$note == SSH::Password_Guessing ) + NetControl::drop_address(n$src, 60min); + } diff --git a/doc/frameworks/netcontrol-3-ssh-guesser.bro b/doc/frameworks/netcontrol-3-ssh-guesser.bro new file mode 100644 index 0000000000..6f6065350c --- /dev/null +++ b/doc/frameworks/netcontrol-3-ssh-guesser.bro @@ -0,0 +1,16 @@ + +@load protocols/ssh/detect-bruteforcing + +redef SSH::password_guesses_limit=10; + +event NetControl::init() + { + local debug_plugin = NetControl::create_debug(T); + NetControl::activate(debug_plugin, 0); + } + +hook Notice::policy(n: Notice::Info) + { + if ( n$note == SSH::Password_Guessing ) + add n$actions[Notice::ACTION_DROP]; + } diff --git a/doc/frameworks/netcontrol-4-drop.bro b/doc/frameworks/netcontrol-4-drop.bro new file mode 100644 index 0000000000..b95822736d --- /dev/null +++ b/doc/frameworks/netcontrol-4-drop.bro @@ -0,0 +1,26 @@ +function our_drop_connection(c: conn_id, t: interval) + { + # As a first step, create the NetControl::Entity that we want to block + local e = NetControl::Entity($ty=NetControl::CONNECTION, $conn=c); + # Then, use the entity to create the rule to drop the entity in the forward path + local r = NetControl::Rule($ty=NetControl::DROP, + $target=NetControl::FORWARD, $entity=e, $expire=t); + + # Add the rule + local id = NetControl::add_rule(r); + + if ( id == "" ) + print "Error while dropping"; + } + +event NetControl::init() + { + local debug_plugin = NetControl::create_debug(T); + NetControl::activate(debug_plugin, 0); + } + +event connection_established(c: connection) + { + our_drop_connection(c$id, 20 secs); + } + diff --git a/doc/frameworks/netcontrol-5-hook.bro b/doc/frameworks/netcontrol-5-hook.bro new file mode 100644 index 0000000000..dee8d5547a --- /dev/null +++ b/doc/frameworks/netcontrol-5-hook.bro @@ -0,0 +1,22 @@ +hook NetControl::rule_policy(r: NetControl::Rule) + { + if ( r$ty == NetControl::DROP && + r$entity$ty == NetControl::CONNECTION && + r$entity$conn$orig_h in 192.168.0.0/16 ) + { + print "Ignored connection from", r$entity$conn$orig_h; + break; + } + } + +event NetControl::init() + { + local debug_plugin = NetControl::create_debug(T); + NetControl::activate(debug_plugin, 0); + } + +event connection_established(c: connection) + { + NetControl::drop_connection(c$id, 20 secs); + } + diff --git a/doc/frameworks/netcontrol-6-find.bro b/doc/frameworks/netcontrol-6-find.bro new file mode 100644 index 0000000000..9e7677dfac --- /dev/null +++ b/doc/frameworks/netcontrol-6-find.bro @@ -0,0 +1,17 @@ +event NetControl::init() + { + local netcontrol_debug = NetControl::create_debug(T); + NetControl::activate(netcontrol_debug, 0); + } + +event connection_established(c: connection) + { + if ( |NetControl::find_rules_addr(c$id$orig_h)| > 0 ) + { + print "Rule already exists"; + return; + } + + NetControl::drop_connection(c$id, 20 secs); + print "Rule added"; + } diff --git a/doc/frameworks/netcontrol-7-catch-release.bro b/doc/frameworks/netcontrol-7-catch-release.bro new file mode 100644 index 0000000000..189a89e68d --- /dev/null +++ b/doc/frameworks/netcontrol-7-catch-release.bro @@ -0,0 +1,10 @@ +event NetControl::init() + { + local debug_plugin = NetControl::create_debug(T); + NetControl::activate(debug_plugin, 0); + } + +event connection_established(c: connection) + { + NetControl::drop_address_catch_release(c$id$orig_h); + } diff --git a/doc/frameworks/netcontrol-8-multiple.bro b/doc/frameworks/netcontrol-8-multiple.bro new file mode 100644 index 0000000000..4d134a577c --- /dev/null +++ b/doc/frameworks/netcontrol-8-multiple.bro @@ -0,0 +1,29 @@ +function our_openflow_check(p: NetControl::PluginState, r: NetControl::Rule): bool + { + if ( r$ty == NetControl::DROP && + r$entity$ty == NetControl::ADDRESS && + subnet_width(r$entity$ip) == 32 && + subnet_to_addr(r$entity$ip) in 192.168.17.0/24 ) + return F; + + return T; + } + +event NetControl::init() + { + # Add debug plugin with low priority + local debug_plugin = NetControl::create_debug(T); + NetControl::activate(debug_plugin, 0); + + # Instantiate OpenFlow debug plugin with higher priority + local of_controller = OpenFlow::log_new(42); + local netcontrol_of = NetControl::create_openflow(of_controller, [$check_pred=our_openflow_check]); + NetControl::activate(netcontrol_of, 10); + } + +event NetControl::init_done() + { + NetControl::drop_address(10.0.0.1, 1min); + NetControl::drop_address(192.168.17.2, 1min); + NetControl::drop_address(192.168.18.2, 1min); + } diff --git a/doc/frameworks/netcontrol-9-skeleton.bro b/doc/frameworks/netcontrol-9-skeleton.bro new file mode 100644 index 0000000000..442d74582b --- /dev/null +++ b/doc/frameworks/netcontrol-9-skeleton.bro @@ -0,0 +1,39 @@ +module NetControl; + +export { + ## Instantiates the plugin. + global create_skeleton: function(argument: string) : PluginState; +} + +function skeleton_name(p: PluginState) : string + { + return "NetControl skeleton plugin"; + } + +function skeleton_add_rule_fun(p: PluginState, r: Rule) : bool + { + print "add", r; + event NetControl::rule_added(r, p); + return T; + } + + function skeleton_remove_rule_fun(p: PluginState, r: Rule) : bool + { + print "remove", r; + event NetControl::rule_removed(r, p); + return T; + } + +global skeleton_plugin = Plugin( + $name = skeleton_name, + $can_expire = F, + $add_rule = skeleton_add_rule_fun, + $remove_rule = skeleton_remove_rule_fun + ); + +function create_skeleton(argument: string) : PluginState + { + local p = PluginState($plugin=skeleton_plugin); + + return p; + } diff --git a/doc/frameworks/netcontrol-architecture.png b/doc/frameworks/netcontrol-architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..4e23c550030a53e0f066ba4c5e59372ca74a9cb5 GIT binary patch literal 103171 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 QUGU!(c{RBlS+l_Z2T+o?x&QzG literal 0 HcmV?d00001 diff --git a/doc/frameworks/netcontrol-openflow.png b/doc/frameworks/netcontrol-openflow.png new file mode 100644 index 0000000000000000000000000000000000000000..1c2690fb828a7f8377199431aff67c1fcc6e31f8 GIT binary patch literal 85573 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 literal 0 HcmV?d00001 diff --git a/doc/frameworks/netcontrol-rules.png b/doc/frameworks/netcontrol-rules.png new file mode 100644 index 0000000000000000000000000000000000000000..5141c81cebbcb6f63e3448185f1ff4c370b999f2 GIT binary patch literal 91598 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. The source of this + plugin is contained in :doc:`/scripts/base/frameworks/netcontrol/plugins/acld.bro`. + + * - PacketFilter plugin + - This plugin adds uses the Bro process-level packet filter (see + :bro:see:`install_src_net_filter` and + :bro:see:`install_dst_net_filter`). Since the functionality of the + PacketFilter is limited, this plugin is mostly for demonstration purposes. The source of this + plugin is contained in :doc:`/scripts/base/frameworks/netcontrol/plugins/packetfilter.bro`. + + * - Debug plugin + - The debug plugin simply outputs its action to the standard output. The source of this + plugin is contained in :doc:`/scripts/base/frameworks/netcontrol/plugins/debug.bro`. + +Activating plugins +****************** + +In the API reference part of this document, we already used the debug plugin. To +use the plugin, we first had to instantiate it by calling +:bro:see:`NetControl::NetControl::create_debug` and then add it to NetControl by +calling :bro:see:`NetControl::activate`. + +As we already hinted before, NetControl supports having several plugins that are +active at the same time. The second argument to the `NetControl::activate` +function is the priority of the backend that was just added. Each rule is sent +to all plugins in order, from highest priority to lowest priority. The backend +can then choose if it accepts the rule and pushes it out to the hardware that it +manages. Or, it can opt to reject the rule. In this case, the NetControl +framework will try to apply the rule to the backend with the next lower +priority. If no backend accepts a rule, the rule insertion is marked as failed. + +The choice if a rule is accepted or rejected stays completely with each plugin. +The debug plugin we used so far just accepts all rules. However, for other +plugins you can specify what rules they will accept. Consider, for example, a +network with two OpenFlow switches. The first switch forwards packets from the +network to the external world, the second switch sits in front of your Bro +cluster to provide packet shunting. In this case, you can add two OpenFlow +backends to NetControl. When you create the instances using +:bro:see:`NetControl::create_openflow`, you set the `monitor` and `forward` +attributes of the configuration in :bro:see:`NetControl::OfConfig` +appropriately. Afterwards, one of the backends will only accept rules for the +monitor path; the other backend will only accept rules for the forward path. + +Commonly, plugins also support predicate functions, that allow the user to +specify restrictions on the rules that they will accept. This can for example be +used if you have a network where certain switches are responsible for specified +subnets. The predicate can examine the subnet of the rule and only accept the +rule if the rule matches the subnet that the specific switch is responsible for. + +To give an example, the following script adds two backends to NetControl. One +backend is the NetControl debug backend, which just outputs the rules to the +console. The second backend is an OpenFlow backend, which uses the OpenFlow +debug mode that outputs the openflow rules to openflow.log. The OpenFlow +backend uses a predicate function to only accept rules with a source address in +the 192.168.17.0/24 network; all other rules will be passed on to the debug +plugin. We manually block a few addresses in the +:bro:see:`NetControl::init_done` event to verify the correct functionality. + +.. btest-include:: ${DOC_ROOT}/frameworks/netcontrol-8-multiple.bro + +.. btest:: netcontrol-8-multiple.bro + + @TEST-EXEC: btest-rst-cmd bro ${DOC_ROOT}/frameworks/netcontrol-8-multiple.bro + +As you can see, only the single block affecting the 192.168.17.0/24 network is +output to the command line. The other two lines are handled by the OpenFlow +plugin. We can verify this by looking at netcontrol.log. The plugin column shows +which plugin handled a rule and reveals that two rules were handled by OpenFlow: + +.. btest:: netcontrol-8-multiple.bro + + @TEST-EXEC: btest-rst-cmd cat netcontrol.log + +Furthermore, openflow.log also shows the two added rules, converted to OpenFlow +flow mods: + +.. btest:: netcontrol-8-multiple.bro + + @TEST-EXEC: btest-rst-cmd cat openflow.log + +.. note:: + + You might have asked yourself what happens when you add two or more with the + same priority. In this case, the rule is sent to all the backends + simultaneously. This can be useful, for example when you have redundant + switches that should keep the same rule state. + +Interfacing with external hardware +********************************** + +Now that we know which plugins exist, and how they can be added to NetControl, +it is time to discuss how we can interface Bro with actual hardware. The typical +way to accomplish this is to use the Bro communication library (Broker), which +can be used to exchange Bro events with external programs and scripts. The +NetControl plugins can use Broker to send events to external programs, which can +then take action depending on these events. + +The following figure shows this architecture with the example of the OpenFlow +plugin. The OpenFlow plugin uses Broker to send events to an external python +script, which uses the `Ryu SDN controller `_ to +communicate with the Switch. + +.. figure:: netcontrol-openflow.png + :width: 600 + :align: center + :alt: NetControl and OpenFlow architecture. + :target: ../_images/netcontrol-openflow.png + + NetControl and OpenFlow architecture (click to enlarge). + +The python scripts that are used to interface with the available NetControl +plugins are contained in the `bro-netcontrol` repository (`github link `_). +The repository contains scripts for the OpenFlow as well as the acld plugin. +Furthermore, it contains a script for the broker plugin which can be used to +call configureable command-line programs when used with the broker plugin. + +The repository also contains documentation on how to install these connectors. +The `netcontrol` directory contains an API that allows you to write your own +connectors to the broker plugin. + +.. note:: + + Note that the API of the Broker communication library is not finalized yet. + You might have to rewrite any scripts for use in future Bro versions. + +Writing plugins +--------------- + +In addition to using the plugins that are part of NetControl, you can write your +own plugins to interface with hard- or software that we currently do not support +out of the Box. + +Creating your own plugin is easy; besides a bit of boilerplate, you only need to +create two functions: one that is called when a rule is added, and one that is +called when a rule is removed. The following script creates a minimal plugin +that just outputs a rule when it is added or removed. Note that you have to +raise the :bro:see:`NetControl::rule_added` and +:bro:see:`NetControl::rule_removed` events in your plugin to let NetControl know +when a rule was added and removed successfully. + +.. btest-include:: ${DOC_ROOT}/frameworks/netcontrol-9-skeleton.bro + +This example is already fully functional and we can use it with a script similar +to our very first example: + +.. btest-include:: ${DOC_ROOT}/frameworks/netcontrol-10-use-skeleton.bro + +.. btest:: netcontrol-9-skeleton.bro + + @TEST-EXEC: btest-rst-cmd bro -C -r ${TRACES}/tls/ecdhe.pcap ${DOC_ROOT}/frameworks/netcontrol-9-skeleton.bro ${DOC_ROOT}/frameworks/netcontrol-10-use-skeleton.bro + +If you want to write your own plugins, it will be worthwhile to look at the +plugins that ship with the NetControl framework to see how they define the +predicates and interact with Broker. diff --git a/doc/script-reference/log-files.rst b/doc/script-reference/log-files.rst index 3c1720afd1..f7a4682f3a 100644 --- a/doc/script-reference/log-files.rst +++ b/doc/script-reference/log-files.rst @@ -71,6 +71,23 @@ Files | x509.log | X.509 certificate info | :bro:type:`X509::Info` | +----------------------------+---------------------------------------+---------------------------------+ +NetControl +---------- + ++------------------------------+---------------------------------------+------------------------------------------+ +| Log File | Description | Field Descriptions | ++==============================+=======================================+==========================================+ +| netcontrol.log | NetControl actions | :bro:type:`NetControl::Info` | ++------------------------------+---------------------------------------+------------------------------------------+ +| netcontrol_drop.log | NetControl actions | :bro:type:`NetControl::DropInfo` | ++------------------------------+---------------------------------------+------------------------------------------+ +| netcontrol_shunt.log | NetControl shunt actions | :bro:type:`NetControl::ShuntInfo` | ++------------------------------+---------------------------------------+------------------------------------------+ +| netcontrol_catch_release.log | NetControl catch and release actions | :bro:type:`NetControl::CatchReleaseInfo` | ++------------------------------+---------------------------------------+------------------------------------------+ +| openflow.log | OpenFlow debug log | :bro:type:`OpenFlow::Info` | ++------------------------------+---------------------------------------+------------------------------------------+ + Detection --------- diff --git a/scripts/base/frameworks/netcontrol/catch-and-release.bro b/scripts/base/frameworks/netcontrol/catch-and-release.bro index 8b3c389b6c..e9c1100887 100644 --- a/scripts/base/frameworks/netcontrol/catch-and-release.bro +++ b/scripts/base/frameworks/netcontrol/catch-and-release.bro @@ -2,6 +2,7 @@ module NetControl; +@load base/frameworks/cluster @load ./main @load ./drop @@ -9,45 +10,67 @@ export { redef enum Log::ID += { CATCH_RELEASE }; - # The record that is used for storing information about current blocks that are - # part of catch and release. + ## Thhis record is used is used for storing information about current blocks that are + ## part of catch and release. type BlockInfo: record { - # Absolute time indicating until when a block is inserted using NetControl + ## Absolute time indicating until when a block is inserted using NetControl block_until: time &optional; - # Absolute time indicating until when an IP address is watched to reblock it + ## Absolute time indicating until when an IP address is watched to reblock it watch_until: time; - # Number of times an IP address was reblocked + ## Number of times an IP address was reblocked num_reblocked: count &default=0; - # Number indicating at which catch and release interval we currently are + ## Number indicating at which catch and release interval we currently are current_interval: count; - # ID of the inserted block, if any. + ## ID of the inserted block, if any. current_block_id: string; - # User specified string + ## User specified string location: string &optional; }; + ## The enum that contains the different kinds of messages that are logged by + ## catch and release type CatchReleaseActions: enum { + ## Log lines marked with info are purely informational; no action was taken INFO, + ## A rule for the specified IP address already existed in NetControl (outside + ## of catch-and-release). Catch and release did not add a new rule, but is now + ## watching the IP address and will add a new rule after the current rule expired. ADDED, + ## A drop was requested by catch and release DROP, + ## A address was succesfully blocked by catch and release DROPPED, + ## An address was unblocked after the timeout expired UNBLOCK, - RESTORED, + ## An address was forgotten because it did not reappear within the `watch_until` interval FORGOTTEN, + ## A watched IP address was seen again; catch and release will re-block it. SEEN_AGAIN }; + ## The record type that is used for representing and logging type CatchReleaseInfo: record { + ## The absolute time indicating when the action for this log-line occured. ts: time &log; + ## The rule id that this log lone refers to. rule_id: string &log &optional; + ## The IP address that this line refers to. ip: addr &log; + ## The action that was taken in this log-line. action: CatchReleaseActions &log; + ## The current block_interaval (for how long the address is blocked). block_interval: interval &log &optional; + ## The current watch_interval (for how long the address will be watched and re-block if it reappears). watch_interval: interval &log &optional; + ## The absolute time until which the address is blocked. blocked_until: time &log &optional; + ## The absolute time until which the address will be monitored. watched_until: time &log &optional; + ## Number of times that this address was blocked in the current cycle. num_blocked: count &log &optional; + ## The user specified location string. location: string &log &optional; + ## Additional informational string by the catch and release framework about this log-line. message: string &log &optional; }; diff --git a/scripts/base/frameworks/netcontrol/main.bro b/scripts/base/frameworks/netcontrol/main.bro index cc2998aa82..9f91aa405b 100644 --- a/scripts/base/frameworks/netcontrol/main.bro +++ b/scripts/base/frameworks/netcontrol/main.bro @@ -81,9 +81,11 @@ export { ## 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. + ## Quarantines a host. This requires a special quarantine server, which runs a HTTP server explaining + ## the quarantine and a DNS server which resolves all requests to the quarantine server. DNS queries + ## from the host to the network dns server will be rewritten and will be sent to the quarantine server + ## instead. Only http communication infected to quarantinehost is allowed. All other network communication + ## is blocked. ## ## infected: the host to quarantine ## @@ -96,7 +98,7 @@ export { ## 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. + ## Flushes all state by calling :bro:see:`NetControl::remove_rule` on all currently active rules. global clear: function(); # ### @@ -120,7 +122,7 @@ export { ## Removes a rule. ## - ## id: The rule to remove, specified as the ID returned by :bro:id:`NetControl::add_rule`. + ## id: The rule to remove, specified as the ID returned by :bro:see:`NetControl::add_rule`. ## ## Returns: True if succesful, the relevant plugin indicated that it knew ## how to handle the removal. Note that again "success" means the @@ -134,10 +136,10 @@ export { ## the rule has been added; if it is not removed from them by a separate mechanism, ## it will stay installed and not be removed later. ## - ## id: The rule to delete, specified as the ID returned by :bro:id:`add_rule` . + ## id: The rule to delete, specified as the ID returned by :bro:see:`add_rule` . ## ## Returns: True if removal is successful, or sent to manager. - ## False if the rule could not be found. + ## False if the rule could not be found. global delete_rule: function(id: string) : bool; ## Searches all rules affecting a certain IP address. @@ -152,6 +154,14 @@ export { global find_rules_addr: function(ip: addr) : vector of Rule; ## Searches all rules affecting a certain subnet. + ## + ## A rule affects a subnet, if it covers the whole subnet. Note especially that + ## this function will not reveal all rules that are covered by a subnet. + ## + ## For example, a search for 192.168.17.0/8 will reveal a rule that exists for + ## 192.168.0.0/16, since this rule affects the subnet. However, it will not reveal + ## a more specific rule for 192.168.17.1/32, which does not directy affect the whole + ## subnet. ## ## This function works on both the manager and workers of a cluster. Note that on ## the worker, the internal rule variables (starting with _) will not reflect the @@ -263,14 +273,14 @@ export { RULE }; - ## State of an entry in the NetControl log. + ## State of an entry in the NetControl log. type InfoState: enum { - REQUESTED, - SUCCEEDED, - EXISTS, - FAILED, - REMOVED, - TIMEOUT, + REQUESTED, ##< The request to add/remove a rule was sent to the respective backend + SUCCEEDED, ##< A rule was succesfully added by a backend + EXISTS, ##< A backend reported that a rule was already existing + FAILED, ##< A rule addition failed + REMOVED, ##< A rule was succesfully removed by a backend + TIMEOUT, ##< A rule timeout was triggered by the NetControl framework or a backend }; ## The record type defining the column fields of the NetControl log. @@ -313,13 +323,13 @@ export { } redef record Rule += { - ##< Internally set to the plugins handling the rule. + ## Internally set to the plugins handling the rule. _plugin_ids: set[count] &default=count_set(); - ##< Internally set to the plugins on which the rule is currently active. + ## Internally set to the plugins on which the rule is currently active. _active_plugin_ids: set[count] &default=count_set(); - ##< Internally set to plugins where the rule should not be removed upon timeout. + ## Internally set to plugins where the rule should not be removed upon timeout. _no_expire_plugins: set[count] &default=count_set(); - ##< Track if the rule was added succesfully by all responsible plugins. + ## Track if the rule was added succesfully by all responsible plugins. _added: bool &default=F; }; diff --git a/scripts/base/frameworks/netcontrol/plugin.bro b/scripts/base/frameworks/netcontrol/plugin.bro index 7d0ee13a81..9acb611893 100644 --- a/scripts/base/frameworks/netcontrol/plugin.bro +++ b/scripts/base/frameworks/netcontrol/plugin.bro @@ -1,11 +1,13 @@ -##! Plugin interface for NetControl backends. +##! This file defines the plugin interface for NetControl. module NetControl; @load ./types export { - ## State for a plugin instance. + ## This record keeps the per instance state of a plugin. + ## + ## Individual plugins commonly extend this record to suit their needs. type PluginState: record { ## Table for a plugin to store custom, instance-specfific state. config: table[string] of string &default=table(); @@ -20,69 +22,69 @@ export { _activated: bool &default=F; }; - # Definition of a plugin. - # - # Generally a plugin needs to implement only what it can support. By - # returning failure, it indicates that it can't support something and the - # the framework will then try another plugin, if available; or inform the - # that the operation failed. If a function isn't implemented by a plugin, - # that's considered an implicit failure to support the operation. - # - # If plugin accepts a rule operation, it *must* generate one of the reporting - # events ``rule_{added,remove,error}`` to signal if it indeed worked out; - # this is separate from accepting the operation because often a plugin - # will only know later (i.e., asynchrously) if that was an error for - # something it thought it could handle. + ## Definition of a plugin. + ## + ## Generally a plugin needs to implement only what it can support. By + ## returning failure, it indicates that it can't support something and the + ## the framework will then try another plugin, if available; or inform the + ## that the operation failed. If a function isn't implemented by a plugin, + ## that's considered an implicit failure to support the operation. + ## + ## If plugin accepts a rule operation, it *must* generate one of the reporting + ## events ``rule_{added,remove,error}`` to signal if it indeed worked out; + ## this is separate from accepting the operation because often a plugin + ## will only know later (i.e., asynchrously) if that was an error for + ## something it thought it could handle. type Plugin: record { - # Returns a descriptive name of the plugin instance, suitable for use in logging - # messages. Note that this function is not optional. + ## Returns a descriptive name of the plugin instance, suitable for use in logging + ## messages. Note that this function is not optional. name: function(state: PluginState) : string; - ## If true, plugin can expire rules itself. If false, + ## If true, plugin can expire rules itself. If false, the NetControl ## framework will manage rule expiration. can_expire: bool; - # One-time initialization function called when plugin gets registered, and - # before any other methods are called. - # - # If this function is provided, NetControl assumes that the plugin has to - # perform, potentially lengthy, initialization before the plugin will become - # active. In this case, the plugin has to call ``NetControl::plugin_activated``, - # once initialization finishes. + ## One-time initialization function called when plugin gets registered, and + ## before any other methods are called. + ## + ## If this function is provided, NetControl assumes that the plugin has to + ## perform, potentially lengthy, initialization before the plugin will become + ## active. In this case, the plugin has to call ``NetControl::plugin_activated``, + ## once initialization finishes. init: function(state: PluginState) &optional; - # One-time finalization function called when a plugin is shutdown; no further - # functions will be called afterwords. + ## One-time finalization function called when a plugin is shutdown; no further + ## functions will be called afterwords. done: function(state: PluginState) &optional; - # Implements the add_rule() operation. If the plugin accepts the rule, - # it returns true, false otherwise. The rule will already have its - # ``id`` field set, which the plugin may use for identification - # purposes. + ## Implements the add_rule() operation. If the plugin accepts the rule, + ## it returns true, false otherwise. The rule will already have its + ## ``id`` field set, which the plugin may use for identification + ## purposes. add_rule: function(state: PluginState, r: Rule) : bool &optional; - # Implements the remove_rule() operation. This will only be called for - # rules that the plugins has previously accepted with add_rule(). The - # ``id`` field will match that of the add_rule() call. Generally, - # a plugin that accepts an add_rule() should also accept the - # remove_rule(). + ## Implements the remove_rule() operation. This will only be called for + ## rules that the plugins has previously accepted with add_rule(). The + ## ``id`` field will match that of the add_rule() call. Generally, + ## a plugin that accepts an add_rule() should also accept the + ## remove_rule(). remove_rule: function(state: PluginState, r: Rule) : bool &optional; - # A transaction groups a number of operations. The plugin can add them internally - # and postpone putting them into effect until committed. This allows to build a - # configuration of multiple rules at once, including replaying a previous state. + ## A transaction groups a number of operations. The plugin can add them internally + ## and postpone putting them into effect until committed. This allows to build a + ## configuration of multiple rules at once, including replaying a previous state. transaction_begin: function(state: PluginState) &optional; transaction_end: function(state: PluginState) &optional; }; - # Table for a plugin to store instance-specific configuration information. - # - # Note, it would be nicer to pass the Plugin instance to all the below, instead - # of this state table. However Bro's type resolver has trouble with refering to a - # record type from inside itself. + ## Table for a plugin to store instance-specific configuration information. + ## + ## Note, it would be nicer to pass the Plugin instance to all the below, instead + ## of this state table. However Bro's type resolver has trouble with refering to a + ## record type from inside itself. redef record PluginState += { ## The plugin that the state belongs to. (Defined separately - ## because of cyclic type dependency.) + ## because of cyclic type dependency.) plugin: Plugin &optional; }; diff --git a/scripts/base/frameworks/netcontrol/plugins/broker.bro b/scripts/base/frameworks/netcontrol/plugins/broker.bro index ab97734fc9..da8e942ae7 100644 --- a/scripts/base/frameworks/netcontrol/plugins/broker.bro +++ b/scripts/base/frameworks/netcontrol/plugins/broker.bro @@ -11,6 +11,7 @@ module NetControl; @ifdef ( Broker::__enable ) export { + ## This record specifies the configuration that is passed to :bro:see:`NetControl::create_broker`. type BrokerConfig: record { ## The broker topic used to send events to topic: string &optional; @@ -38,6 +39,7 @@ export { global create_broker: function(config: BrokerConfig, can_expire: bool) : PluginState; redef record PluginState += { + ## OpenFlow controller for NetControl Broker plugin broker_config: BrokerConfig &optional; ## The ID of this broker instance - for the mapping to PluginStates broker_id: count &optional; diff --git a/scripts/base/frameworks/netcontrol/plugins/openflow.bro b/scripts/base/frameworks/netcontrol/plugins/openflow.bro index 44a8bb2f1a..e47c8ba713 100644 --- a/scripts/base/frameworks/netcontrol/plugins/openflow.bro +++ b/scripts/base/frameworks/netcontrol/plugins/openflow.bro @@ -7,22 +7,46 @@ module NetControl; export { + ## This record specifies the configuration that is passed to :bro:see:`NetControl::create_openflow`. type OfConfig: record { - monitor: bool &default=T; - forward: bool &default=T; - idle_timeout: count &default=0; - table_id: count &optional; + monitor: bool &default=T; ##< accept rules that target the monitor path + forward: bool &default=T; ##< accept rules that target the forward path + idle_timeout: count &default=0; ##< default OpenFlow idle timeout + table_id: count &optional; ##< default OpenFlow table ID. 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 + ## p: Current plugin state. ## - ## r: The rule to be inserted or removed + ## r: The rule to be inserted or removed. ## - ## Returns: T if the rule can be handled by the current backend, F otherwhise + ## Returns: T if the rule can be handled by the current backend, F otherwhise. check_pred: function(p: PluginState, r: Rule): bool &optional; + + ## This predicate is called each time an OpenFlow match record is created. + ## The predicate can modify the match structure before it is sent on to the + ## device. + ## + ## p: Current plugin state. + ## + ## r: The rule to be inserted or removed. + ## + ## m: The openflow match structures that were generated for this rules. + ## + ## Returns: The modified OpenFlow match structures that will be used in place the structures passed in m. match_pred: function(p: PluginState, e: Entity, m: vector of OpenFlow::ofp_match): vector of OpenFlow::ofp_match &optional; + + ## This predicate is called before an FlowMod message is sent to the OpenFlow + ## device. It can modify the FlowMod message before it is passed on. + ## + ## p: Current plugin state. + ## + ## r: The rule to be inserted or removed. + ## + ## m: The OpenFlow FlowMod message. + ## + ## Returns: The modified FloMod message that is used in lieu of m. flow_mod_pred: function(p: PluginState, r: Rule, m: OpenFlow::ofp_flow_mod): OpenFlow::ofp_flow_mod &optional; }; diff --git a/scripts/base/frameworks/netcontrol/types.bro b/scripts/base/frameworks/netcontrol/types.bro index 3147420c99..dce3ed4223 100644 --- a/scripts/base/frameworks/netcontrol/types.bro +++ b/scripts/base/frameworks/netcontrol/types.bro @@ -1,30 +1,45 @@ -##! Types used by the NetControl framework. +##! This file defines the that are used by the NetControl framework. +##! +##! The most important type defined in this file is :bro:see:`NetControl::Rule`, +##! which is used to describe all rules that can be expressed by the NetControl framework. module NetControl; export { + ## The default priority that is used when creating rules. const default_priority: int = +0 &redef; + + ## The default priority that is used when using the high-level functions to + ## push whitelist entries to the backends (:bro:see:`NetControl::whitelist_address` and + ## :bro:see:`NetControl::whitelist_subnet`). + ## + ## Note that this priority is not automatically used when manually creating rules + ## that have a :bro:see:`NetControl::RuleType` of :bro:enum:`NetControl::WHITELIST`. const whitelist_priority: int = +5 &redef; - ## Type of a :bro:id:`Entity` for defining an action. + ## The EntityType is used in :bro:id:`Entity` for defining the entity that a rule + ## applies to. type EntityType: enum { ADDRESS, ##< Activity involving a specific IP address. - CONNECTION, ##< All of a bi-directional connection's activity. - FLOW, ##< All of a uni-directional flow's activity. Can contain wildcards. + CONNECTION, ##< Activity involving all of a bi-directional connection's activity. + FLOW, ##< Actitivy involving a uni-directional flow's activity. Can contain wildcards. MAC, ##< Activity involving a MAC address. }; - ## Type for defining a flow. + ## Flow is used in :bro:id:`Entity` together with :bro:enum:`NetControl::FLOW` to specify + ## a uni-directional flow that a :bro:id:`Rule` applies to. + ## + ## If optional fields are not set, they are interpreted as wildcarded. type Flow: record { src_h: subnet &optional; ##< The source IP address/subnet. src_p: port &optional; ##< The source port number. dst_h: subnet &optional; ##< The destination IP address/subnet. - dst_p: port &optional; ##< The desintation port number. + dst_p: port &optional; ##< The destination port number. src_m: string &optional; ##< The source MAC address. dst_m: string &optional; ##< The destination MAC address. }; - ## Type defining the enity an :bro:id:`Rule` is operating on. + ## Type defining the entity an :bro:id:`Rule` is operating on. type Entity: record { ty: EntityType; ##< Type of entity. conn: conn_id &optional; ##< Used with :bro:enum:`NetControl::CONNECTION`. @@ -33,32 +48,36 @@ export { mac: string &optional; ##< Used with :bro:enum:`NetControl::MAC`. }; - ## Target of :bro:id:`Rule` action. + ## The :bro:id`TargetType` defined the target of a :bro:id:`Rule`. + ## + ## Rules can either be applied to the forward path, affecting all network traffic, or + ## on the monitor path, only affecting the traffic that is sent to Bro. The second + ## is mostly used for shunting, which allows Bro to tell the networking hardware that + ## it wants to no longer see traffic that it identified as benign. type TargetType: enum { FORWARD, #< Apply rule actively to traffic on forwarding path. MONITOR, #< Apply rule passively to traffic sent to Bro for monitoring. }; - ## Type of rules that the framework supports. Each type lists the + ## Type of rules that the framework supports. Each type lists the extra ## :bro:id:`Rule` argument(s) it uses, if any. ## ## Plugins may extend this type to define their own. type RuleType: enum { - ## Stop forwarding all packets matching entity. + ## Stop forwarding all packets matching the entity. ## - ## No arguments. + ## No additional arguments. DROP, - ## Begin modifying all packets matching entity. + ## Modify all packets matching entity. The packets + ## will be modified according to the `mod` entry of + ## the rule. ## - ## .. todo:: - ## Define arguments. MODIFY, - ## Begin redirecting all packets matching entity. + ## Redirect all packets matching entity to a different switch port, + ## given in the `out_port` argument of the rule. ## - ## .. todo:: - ## c: output port to redirect traffic to. REDIRECT, ## Whitelists all packets of an entity, meaning no restrictions will be applied. diff --git a/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log b/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log index 477b4cc1b3..e0765e0446 100644 --- a/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log +++ b/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log @@ -3,7 +3,7 @@ #empty_field (empty) #unset_field - #path loaded_scripts -#open 2016-06-07-19-22-42 +#open 2016-06-22-22-50-49 #fields name #types string scripts/base/init-bare.bro @@ -155,14 +155,38 @@ scripts/base/init-default.bro scripts/base/frameworks/notice/main.bro scripts/base/frameworks/notice/weird.bro scripts/base/frameworks/notice/actions/drop.bro + scripts/base/frameworks/netcontrol/__load__.bro + scripts/base/frameworks/netcontrol/types.bro + scripts/base/frameworks/netcontrol/main.bro + scripts/base/frameworks/netcontrol/plugin.bro + scripts/base/frameworks/netcontrol/plugins/__load__.bro + scripts/base/frameworks/netcontrol/plugins/debug.bro + scripts/base/frameworks/netcontrol/plugins/openflow.bro + scripts/base/frameworks/openflow/__load__.bro + scripts/base/frameworks/openflow/consts.bro + scripts/base/frameworks/openflow/types.bro + scripts/base/frameworks/openflow/main.bro + scripts/base/frameworks/openflow/plugins/__load__.bro + scripts/base/frameworks/openflow/plugins/ryu.bro + scripts/base/utils/json.bro + scripts/base/frameworks/openflow/plugins/log.bro + scripts/base/frameworks/openflow/plugins/broker.bro + scripts/base/frameworks/cluster/__load__.bro + scripts/base/frameworks/cluster/main.bro + scripts/base/frameworks/control/__load__.bro + scripts/base/frameworks/control/main.bro + scripts/base/frameworks/openflow/non-cluster.bro + scripts/base/frameworks/netcontrol/plugins/packetfilter.bro + scripts/base/frameworks/netcontrol/plugins/broker.bro + scripts/base/frameworks/netcontrol/plugins/acld.bro + scripts/base/frameworks/netcontrol/drop.bro + scripts/base/frameworks/netcontrol/shunt.bro + scripts/base/frameworks/netcontrol/catch-and-release.bro + scripts/base/frameworks/netcontrol/non-cluster.bro scripts/base/frameworks/notice/actions/email_admin.bro scripts/base/frameworks/notice/actions/page.bro scripts/base/frameworks/notice/actions/add-geodata.bro scripts/base/frameworks/notice/extend-email/hostnames.bro - scripts/base/frameworks/cluster/__load__.bro - scripts/base/frameworks/cluster/main.bro - scripts/base/frameworks/control/__load__.bro - scripts/base/frameworks/control/main.bro scripts/base/frameworks/notice/non-cluster.bro scripts/base/frameworks/notice/actions/pp-alarms.bro scripts/base/frameworks/dpd/__load__.bro @@ -196,30 +220,6 @@ scripts/base/init-default.bro scripts/base/frameworks/sumstats/non-cluster.bro scripts/base/frameworks/tunnels/__load__.bro scripts/base/frameworks/tunnels/main.bro - scripts/base/frameworks/openflow/__load__.bro - scripts/base/frameworks/openflow/consts.bro - scripts/base/frameworks/openflow/types.bro - scripts/base/frameworks/openflow/main.bro - scripts/base/frameworks/openflow/plugins/__load__.bro - scripts/base/frameworks/openflow/plugins/ryu.bro - scripts/base/utils/json.bro - scripts/base/frameworks/openflow/plugins/log.bro - scripts/base/frameworks/openflow/plugins/broker.bro - scripts/base/frameworks/openflow/non-cluster.bro - scripts/base/frameworks/netcontrol/__load__.bro - scripts/base/frameworks/netcontrol/types.bro - scripts/base/frameworks/netcontrol/main.bro - scripts/base/frameworks/netcontrol/plugin.bro - scripts/base/frameworks/netcontrol/plugins/__load__.bro - scripts/base/frameworks/netcontrol/plugins/debug.bro - scripts/base/frameworks/netcontrol/plugins/openflow.bro - scripts/base/frameworks/netcontrol/plugins/packetfilter.bro - scripts/base/frameworks/netcontrol/plugins/broker.bro - scripts/base/frameworks/netcontrol/plugins/acld.bro - scripts/base/frameworks/netcontrol/drop.bro - scripts/base/frameworks/netcontrol/shunt.bro - scripts/base/frameworks/netcontrol/catch-and-release.bro - scripts/base/frameworks/netcontrol/non-cluster.bro scripts/base/protocols/conn/__load__.bro scripts/base/protocols/conn/main.bro scripts/base/protocols/conn/contents.bro @@ -311,4 +311,4 @@ scripts/base/init-default.bro scripts/base/misc/find-checksum-offloading.bro scripts/base/misc/find-filtered-trace.bro scripts/policy/misc/loaded-scripts.bro -#close 2016-06-07-19-22-42 +#close 2016-06-22-22-50-50 diff --git a/testing/btest/Baseline/coverage.find-bro-logs/out b/testing/btest/Baseline/coverage.find-bro-logs/out index f7b7398bc8..65e1f24366 100644 --- a/testing/btest/Baseline/coverage.find-bro-logs/out +++ b/testing/btest/Baseline/coverage.find-bro-logs/out @@ -23,6 +23,7 @@ modbus modbus_register_change mysql net_control +netcontrol_catch_release netcontrol_drop netcontrol_shunt notice diff --git a/testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-1-drop-with-debug_bro/output b/testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-1-drop-with-debug_bro/output new file mode 100644 index 0000000000..b451d5aa4f --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-1-drop-with-debug_bro/output @@ -0,0 +1,14 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +netcontrol-1-drop-with-debug.bro + +event NetControl::init() + { + local debug_plugin = NetControl::create_debug(T); + NetControl::activate(debug_plugin, 0); + } + +event connection_established(c: connection) + { + NetControl::drop_connection(c$id, 20 secs); + } diff --git a/testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-10-use-skeleton_bro/output b/testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-10-use-skeleton_bro/output new file mode 100644 index 0000000000..331afbc80d --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-10-use-skeleton_bro/output @@ -0,0 +1,14 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +netcontrol-10-use-skeleton.bro + +event NetControl::init() + { + local skeleton_plugin = NetControl::create_skeleton(""); + NetControl::activate(skeleton_plugin, 0); + } + +event connection_established(c: connection) + { + NetControl::drop_connection(c$id, 20 secs); + } diff --git a/testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-2-ssh-guesser_bro/output b/testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-2-ssh-guesser_bro/output new file mode 100644 index 0000000000..87c8cdda7a --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-2-ssh-guesser_bro/output @@ -0,0 +1,20 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +netcontrol-2-ssh-guesser.bro + + +@load protocols/ssh/detect-bruteforcing + +redef SSH::password_guesses_limit=10; + +event NetControl::init() + { + local debug_plugin = NetControl::create_debug(T); + NetControl::activate(debug_plugin, 0); + } + +hook Notice::policy(n: Notice::Info) + { + if ( n$note == SSH::Password_Guessing ) + NetControl::drop_address(n$src, 60min); + } diff --git a/testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-3-ssh-guesser_bro/output b/testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-3-ssh-guesser_bro/output new file mode 100644 index 0000000000..228856f00a --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-3-ssh-guesser_bro/output @@ -0,0 +1,20 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +netcontrol-3-ssh-guesser.bro + + +@load protocols/ssh/detect-bruteforcing + +redef SSH::password_guesses_limit=10; + +event NetControl::init() + { + local debug_plugin = NetControl::create_debug(T); + NetControl::activate(debug_plugin, 0); + } + +hook Notice::policy(n: Notice::Info) + { + if ( n$note == SSH::Password_Guessing ) + add n$actions[Notice::ACTION_DROP]; + } diff --git a/testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-4-drop_bro/output b/testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-4-drop_bro/output new file mode 100644 index 0000000000..e7b15fd91b --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-4-drop_bro/output @@ -0,0 +1,30 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +netcontrol-4-drop.bro + +function our_drop_connection(c: conn_id, t: interval) + { + # As a first step, create the NetControl::Entity that we want to block + local e = NetControl::Entity($ty=NetControl::CONNECTION, $conn=c); + # Then, use the entity to create the rule to drop the entity in the forward path + local r = NetControl::Rule($ty=NetControl::DROP, + $target=NetControl::FORWARD, $entity=e, $expire=t); + + # Add the rule + local id = NetControl::add_rule(r); + + if ( id == "" ) + print "Error while dropping"; + } + +event NetControl::init() + { + local debug_plugin = NetControl::create_debug(T); + NetControl::activate(debug_plugin, 0); + } + +event connection_established(c: connection) + { + our_drop_connection(c$id, 20 secs); + } + diff --git a/testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-5-hook_bro/output b/testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-5-hook_bro/output new file mode 100644 index 0000000000..d27e3f9a6a --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-5-hook_bro/output @@ -0,0 +1,26 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +netcontrol-5-hook.bro + +hook NetControl::rule_policy(r: NetControl::Rule) + { + if ( r$ty == NetControl::DROP && + r$entity$ty == NetControl::CONNECTION && + r$entity$conn$orig_h in 192.168.0.0/16 ) + { + print "Ignored connection from", r$entity$conn$orig_h; + break; + } + } + +event NetControl::init() + { + local debug_plugin = NetControl::create_debug(T); + NetControl::activate(debug_plugin, 0); + } + +event connection_established(c: connection) + { + NetControl::drop_connection(c$id, 20 secs); + } + diff --git a/testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-6-find_bro/output b/testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-6-find_bro/output new file mode 100644 index 0000000000..bcc5199590 --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-6-find_bro/output @@ -0,0 +1,21 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +netcontrol-6-find.bro + +event NetControl::init() + { + local netcontrol_debug = NetControl::create_debug(T); + NetControl::activate(netcontrol_debug, 0); + } + +event connection_established(c: connection) + { + if ( |NetControl::find_rules_addr(c$id$orig_h)| > 0 ) + { + print "Rule already exists"; + return; + } + + NetControl::drop_connection(c$id, 20 secs); + print "Rule added"; + } diff --git a/testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-7-catch-release_bro/output b/testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-7-catch-release_bro/output new file mode 100644 index 0000000000..aa10d8cc01 --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-7-catch-release_bro/output @@ -0,0 +1,14 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +netcontrol-7-catch-release.bro + +event NetControl::init() + { + local debug_plugin = NetControl::create_debug(T); + NetControl::activate(debug_plugin, 0); + } + +event connection_established(c: connection) + { + NetControl::drop_address_catch_release(c$id$orig_h); + } diff --git a/testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-8-multiple_bro/output b/testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-8-multiple_bro/output new file mode 100644 index 0000000000..f9bac69f44 --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-8-multiple_bro/output @@ -0,0 +1,33 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +netcontrol-8-multiple.bro + +function our_openflow_check(p: NetControl::PluginState, r: NetControl::Rule): bool + { + if ( r$ty == NetControl::DROP && + r$entity$ty == NetControl::ADDRESS && + subnet_width(r$entity$ip) == 32 && + subnet_to_addr(r$entity$ip) in 192.168.17.0/24 ) + return F; + + return T; + } + +event NetControl::init() + { + # Add debug plugin with low priority + local debug_plugin = NetControl::create_debug(T); + NetControl::activate(debug_plugin, 0); + + # Instantiate OpenFlow debug plugin with higher priority + local of_controller = OpenFlow::log_new(42); + local netcontrol_of = NetControl::create_openflow(of_controller, [$check_pred=our_openflow_check]); + NetControl::activate(netcontrol_of, 10); + } + +event NetControl::init_done() + { + NetControl::drop_address(10.0.0.1, 1min); + NetControl::drop_address(192.168.17.2, 1min); + NetControl::drop_address(192.168.18.2, 1min); + } diff --git a/testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-9-skeleton_bro/output b/testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-9-skeleton_bro/output new file mode 100644 index 0000000000..dc23f832dd --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.include-doc_frameworks_netcontrol-9-skeleton_bro/output @@ -0,0 +1,43 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +netcontrol-9-skeleton.bro + +module NetControl; + +export { + ## Instantiates the plugin. + global create_skeleton: function(argument: string) : PluginState; +} + +function skeleton_name(p: PluginState) : string + { + return "NetControl skeleton plugin"; + } + +function skeleton_add_rule_fun(p: PluginState, r: Rule) : bool + { + print "add", r; + event NetControl::rule_added(r, p); + return T; + } + + function skeleton_remove_rule_fun(p: PluginState, r: Rule) : bool + { + print "remove", r; + event NetControl::rule_removed(r, p); + return T; + } + +global skeleton_plugin = Plugin( + $name = skeleton_name, + $can_expire = F, + $add_rule = skeleton_add_rule_fun, + $remove_rule = skeleton_remove_rule_fun + ); + +function create_skeleton(argument: string) : PluginState + { + local p = PluginState($plugin=skeleton_plugin); + + return p; + } diff --git a/testing/btest/Baseline/doc.sphinx.netcontrol-1-drop-with-debug.bro/btest-doc.sphinx.netcontrol-1-drop-with-debug.bro#1 b/testing/btest/Baseline/doc.sphinx.netcontrol-1-drop-with-debug.bro/btest-doc.sphinx.netcontrol-1-drop-with-debug.bro#1 new file mode 100644 index 0000000000..91f41babb3 --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.netcontrol-1-drop-with-debug.bro/btest-doc.sphinx.netcontrol-1-drop-with-debug.bro#1 @@ -0,0 +1,32 @@ +.. rst-class:: btest-cmd + + .. code-block:: none + :linenos: + :emphasize-lines: 1,1 + + # bro -C -r tls/ecdhe.pcap netcontrol-1-drop-with-debug.bro + netcontrol debug (Debug-All): init + netcontrol debug (Debug-All): add_rule: [ty=NetControl::DROP, target=NetControl::FORWARD, entity=[ty=NetControl::CONNECTION, conn=[orig_h=192.168.18.50, orig_p=56981/tcp, resp_h=74.125.239.97, resp_p=443/tcp], flow=, ip=, mac=], expire=20.0 secs, priority=0, location=, out_port=, mod=, id=2, cid=2, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _no_expire_plugins={\x0a\x0a}, _added=F] + +.. rst-class:: btest-cmd + + .. code-block:: none + :linenos: + :emphasize-lines: 1,1 + + # cat netcontrol.log + #separator \x09 + #set_separator , + #empty_field (empty) + #unset_field - + #path netcontrol + #open 2016-06-22-22-58-31 + #fields ts rule_id category cmd state action target entity_type entity mod msg priority expire location plugin + #types time string enum string enum string enum string string string string int interval string string + 0.000000 - NetControl::MESSAGE - - - - - - - activating plugin with priority 0 - - - Debug-All + 0.000000 - NetControl::MESSAGE - - - - - - - activation finished - - - Debug-All + 0.000000 - NetControl::MESSAGE - - - - - - - plugin initialization done - - - - + 1398529018.678276 2 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::CONNECTION 192.168.18.50/56981<->74.125.239.97/443 - - 0 20.000000 - Debug-All + 1398529018.678276 2 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::CONNECTION 192.168.18.50/56981<->74.125.239.97/443 - - 0 20.000000 - Debug-All + #close 2016-06-22-22-58-31 + diff --git a/testing/btest/Baseline/doc.sphinx.netcontrol-1-drop-with-debug.bro/btest-doc.sphinx.netcontrol-1-drop-with-debug.bro#2 b/testing/btest/Baseline/doc.sphinx.netcontrol-1-drop-with-debug.bro/btest-doc.sphinx.netcontrol-1-drop-with-debug.bro#2 new file mode 100644 index 0000000000..5c361dba1c --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.netcontrol-1-drop-with-debug.bro/btest-doc.sphinx.netcontrol-1-drop-with-debug.bro#2 @@ -0,0 +1,18 @@ +.. rst-class:: btest-cmd + + .. code-block:: none + :linenos: + :emphasize-lines: 1,1 + + # cat netcontrol_drop.log + #separator \x09 + #set_separator , + #empty_field (empty) + #unset_field - + #path netcontrol_drop + #open 2016-06-22-22-58-31 + #fields ts rule_id orig_h orig_p resp_h resp_p expire location + #types time string addr port addr port interval string + 1398529018.678276 2 192.168.18.50 56981 74.125.239.97 443 20.000000 - + #close 2016-06-22-22-58-31 + diff --git a/testing/btest/Baseline/doc.sphinx.netcontrol-2-ssh-guesser.bro/btest-doc.sphinx.netcontrol-2-ssh-guesser.bro#1 b/testing/btest/Baseline/doc.sphinx.netcontrol-2-ssh-guesser.bro/btest-doc.sphinx.netcontrol-2-ssh-guesser.bro#1 new file mode 100644 index 0000000000..da4c7a78d1 --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.netcontrol-2-ssh-guesser.bro/btest-doc.sphinx.netcontrol-2-ssh-guesser.bro#1 @@ -0,0 +1,32 @@ +.. rst-class:: btest-cmd + + .. code-block:: none + :linenos: + :emphasize-lines: 1,1 + + # bro -C -r ssh/sshguess.pcap netcontrol-2-ssh-guesser.bro + netcontrol debug (Debug-All): init + netcontrol debug (Debug-All): add_rule: [ty=NetControl::DROP, target=NetControl::FORWARD, entity=[ty=NetControl::ADDRESS, conn=, flow=, ip=192.168.56.1/32, mac=], expire=1.0 hr, priority=0, location=, out_port=, mod=, id=2, cid=2, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _no_expire_plugins={\x0a\x0a}, _added=F] + +.. rst-class:: btest-cmd + + .. code-block:: none + :linenos: + :emphasize-lines: 1,1 + + # cat netcontrol.log + #separator \x09 + #set_separator , + #empty_field (empty) + #unset_field - + #path netcontrol + #open 2016-06-22-22-58-36 + #fields ts rule_id category cmd state action target entity_type entity mod msg priority expire location plugin + #types time string enum string enum string enum string string string string int interval string string + 0.000000 - NetControl::MESSAGE - - - - - - - activating plugin with priority 0 - - - Debug-All + 0.000000 - NetControl::MESSAGE - - - - - - - activation finished - - - Debug-All + 0.000000 - NetControl::MESSAGE - - - - - - - plugin initialization done - - - - + 1427726711.398575 2 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.56.1/32 - - 0 3600.000000 - Debug-All + 1427726711.398575 2 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.56.1/32 - - 0 3600.000000 - Debug-All + #close 2016-06-22-22-58-36 + diff --git a/testing/btest/Baseline/doc.sphinx.netcontrol-3-ssh-guesser.bro/btest-doc.sphinx.netcontrol-3-ssh-guesser.bro#1 b/testing/btest/Baseline/doc.sphinx.netcontrol-3-ssh-guesser.bro/btest-doc.sphinx.netcontrol-3-ssh-guesser.bro#1 new file mode 100644 index 0000000000..d70b371a01 --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.netcontrol-3-ssh-guesser.bro/btest-doc.sphinx.netcontrol-3-ssh-guesser.bro#1 @@ -0,0 +1,32 @@ +.. rst-class:: btest-cmd + + .. code-block:: none + :linenos: + :emphasize-lines: 1,1 + + # bro -C -r ssh/sshguess.pcap netcontrol-3-ssh-guesser.bro + netcontrol debug (Debug-All): init + netcontrol debug (Debug-All): add_rule: [ty=NetControl::DROP, target=NetControl::FORWARD, entity=[ty=NetControl::ADDRESS, conn=, flow=, ip=192.168.56.1/32, mac=], expire=10.0 mins, priority=0, location=ACTION_DROP: T, out_port=, mod=, id=2, cid=2, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _no_expire_plugins={\x0a\x0a}, _added=F] + +.. rst-class:: btest-cmd + + .. code-block:: none + :linenos: + :emphasize-lines: 1,1 + + # cat netcontrol.log + #separator \x09 + #set_separator , + #empty_field (empty) + #unset_field - + #path netcontrol + #open 2016-06-22-22-58-38 + #fields ts rule_id category cmd state action target entity_type entity mod msg priority expire location plugin + #types time string enum string enum string enum string string string string int interval string string + 0.000000 - NetControl::MESSAGE - - - - - - - activating plugin with priority 0 - - - Debug-All + 0.000000 - NetControl::MESSAGE - - - - - - - activation finished - - - Debug-All + 0.000000 - NetControl::MESSAGE - - - - - - - plugin initialization done - - - - + 1427726711.398575 2 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.56.1/32 - - 0 600.000000 ACTION_DROP: T Debug-All + 1427726711.398575 2 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.56.1/32 - - 0 600.000000 ACTION_DROP: T Debug-All + #close 2016-06-22-22-58-38 + diff --git a/testing/btest/Baseline/doc.sphinx.netcontrol-3-ssh-guesser.bro/btest-doc.sphinx.netcontrol-3-ssh-guesser.bro#2 b/testing/btest/Baseline/doc.sphinx.netcontrol-3-ssh-guesser.bro/btest-doc.sphinx.netcontrol-3-ssh-guesser.bro#2 new file mode 100644 index 0000000000..a768fde679 --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.netcontrol-3-ssh-guesser.bro/btest-doc.sphinx.netcontrol-3-ssh-guesser.bro#2 @@ -0,0 +1,18 @@ +.. rst-class:: btest-cmd + + .. code-block:: none + :linenos: + :emphasize-lines: 1,1 + + # cat notice.log + #separator \x09 + #set_separator , + #empty_field (empty) + #unset_field - + #path notice + #open 2016-06-22-22-58-38 + #fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p fuid file_mime_type file_desc proto note msg sub src dst p n peer_descr actions suppress_for dropped remote_location.country_code remote_location.region remote_location.city remote_location.latitude remote_location.longitude + #types time string addr port addr port string string string enum enum string string addr addr port count string set[enum] interval bool string string string double double + 1427726711.398575 - - - - - - - - - SSH::Password_Guessing 192.168.56.1 appears to be guessing SSH passwords (seen in 10 connections). Sampled servers: 192.168.56.103, 192.168.56.103, 192.168.56.103, 192.168.56.103, 192.168.56.103 192.168.56.1 - - - bro Notice::ACTION_DROP,Notice::ACTION_LOG 3600.000000 T - - - - - + #close 2016-06-22-22-58-38 + diff --git a/testing/btest/Baseline/doc.sphinx.netcontrol-4-drop.bro/btest-doc.sphinx.netcontrol-4-drop.bro#1 b/testing/btest/Baseline/doc.sphinx.netcontrol-4-drop.bro/btest-doc.sphinx.netcontrol-4-drop.bro#1 new file mode 100644 index 0000000000..437d9ba58f --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.netcontrol-4-drop.bro/btest-doc.sphinx.netcontrol-4-drop.bro#1 @@ -0,0 +1,32 @@ +.. rst-class:: btest-cmd + + .. code-block:: none + :linenos: + :emphasize-lines: 1,1 + + # bro -C -r tls/ecdhe.pcap netcontrol-4-drop.bro + netcontrol debug (Debug-All): init + netcontrol debug (Debug-All): add_rule: [ty=NetControl::DROP, target=NetControl::FORWARD, entity=[ty=NetControl::CONNECTION, conn=[orig_h=192.168.18.50, orig_p=56981/tcp, resp_h=74.125.239.97, resp_p=443/tcp], flow=, ip=, mac=], expire=20.0 secs, priority=0, location=, out_port=, mod=, id=2, cid=2, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _no_expire_plugins={\x0a\x0a}, _added=F] + +.. rst-class:: btest-cmd + + .. code-block:: none + :linenos: + :emphasize-lines: 1,1 + + # cat netcontrol.log + #separator \x09 + #set_separator , + #empty_field (empty) + #unset_field - + #path netcontrol + #open 2016-06-22-22-58-42 + #fields ts rule_id category cmd state action target entity_type entity mod msg priority expire location plugin + #types time string enum string enum string enum string string string string int interval string string + 0.000000 - NetControl::MESSAGE - - - - - - - activating plugin with priority 0 - - - Debug-All + 0.000000 - NetControl::MESSAGE - - - - - - - activation finished - - - Debug-All + 0.000000 - NetControl::MESSAGE - - - - - - - plugin initialization done - - - - + 1398529018.678276 2 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::CONNECTION 192.168.18.50/56981<->74.125.239.97/443 - - 0 20.000000 - Debug-All + 1398529018.678276 2 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::CONNECTION 192.168.18.50/56981<->74.125.239.97/443 - - 0 20.000000 - Debug-All + #close 2016-06-22-22-58-42 + diff --git a/testing/btest/Baseline/doc.sphinx.netcontrol-5-hook.bro/btest-doc.sphinx.netcontrol-5-hook.bro#1 b/testing/btest/Baseline/doc.sphinx.netcontrol-5-hook.bro/btest-doc.sphinx.netcontrol-5-hook.bro#1 new file mode 100644 index 0000000000..0dd5d01130 --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.netcontrol-5-hook.bro/btest-doc.sphinx.netcontrol-5-hook.bro#1 @@ -0,0 +1,10 @@ +.. rst-class:: btest-cmd + + .. code-block:: none + :linenos: + :emphasize-lines: 1,1 + + # bro -C -r tls/ecdhe.pcap netcontrol-5-hook.bro + netcontrol debug (Debug-All): init + Ignored connection from, 192.168.18.50 + diff --git a/testing/btest/Baseline/doc.sphinx.netcontrol-6-find.bro/btest-doc.sphinx.netcontrol-6-find.bro#1 b/testing/btest/Baseline/doc.sphinx.netcontrol-6-find.bro/btest-doc.sphinx.netcontrol-6-find.bro#1 new file mode 100644 index 0000000000..66846d738d --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.netcontrol-6-find.bro/btest-doc.sphinx.netcontrol-6-find.bro#1 @@ -0,0 +1,12 @@ +.. rst-class:: btest-cmd + + .. code-block:: none + :linenos: + :emphasize-lines: 1,1 + + # bro -C -r tls/google-duplicate.trace netcontrol-6-find.bro + netcontrol debug (Debug-All): init + netcontrol debug (Debug-All): add_rule: [ty=NetControl::DROP, target=NetControl::FORWARD, entity=[ty=NetControl::CONNECTION, conn=[orig_h=192.168.4.149, orig_p=60623/tcp, resp_h=74.125.239.129, resp_p=443/tcp], flow=, ip=, mac=], expire=20.0 secs, priority=0, location=, out_port=, mod=, id=2, cid=2, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _no_expire_plugins={\x0a\x0a}, _added=F] + Rule added + Rule already exists + diff --git a/testing/btest/Baseline/doc.sphinx.netcontrol-7-catch-release.bro/btest-doc.sphinx.netcontrol-7-catch-release.bro#1 b/testing/btest/Baseline/doc.sphinx.netcontrol-7-catch-release.bro/btest-doc.sphinx.netcontrol-7-catch-release.bro#1 new file mode 100644 index 0000000000..ed2d956171 --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.netcontrol-7-catch-release.bro/btest-doc.sphinx.netcontrol-7-catch-release.bro#1 @@ -0,0 +1,10 @@ +.. rst-class:: btest-cmd + + .. code-block:: none + :linenos: + :emphasize-lines: 1,1 + + # bro -C -r tls/ecdhe.pcap netcontrol-7-catch-release.bro + netcontrol debug (Debug-All): init + netcontrol debug (Debug-All): add_rule: [ty=NetControl::DROP, target=NetControl::FORWARD, entity=[ty=NetControl::ADDRESS, conn=, flow=, ip=192.168.18.50/32, mac=], expire=10.0 mins, priority=0, location=, out_port=, mod=, id=2, cid=2, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _no_expire_plugins={\x0a\x0a}, _added=F] + diff --git a/testing/btest/Baseline/doc.sphinx.netcontrol-7-catch-release.bro/btest-doc.sphinx.netcontrol-7-catch-release.bro#2 b/testing/btest/Baseline/doc.sphinx.netcontrol-7-catch-release.bro/btest-doc.sphinx.netcontrol-7-catch-release.bro#2 new file mode 100644 index 0000000000..df2080fc59 --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.netcontrol-7-catch-release.bro/btest-doc.sphinx.netcontrol-7-catch-release.bro#2 @@ -0,0 +1,19 @@ +.. rst-class:: btest-cmd + + .. code-block:: none + :linenos: + :emphasize-lines: 1,1 + + # cat netcontrol_catch_release.log + #separator \x09 + #set_separator , + #empty_field (empty) + #unset_field - + #path netcontrol_catch_release + #open 2016-06-22-22-58-49 + #fields ts rule_id ip action block_interval watch_interval blocked_until watched_until num_blocked location message + #types time string addr enum interval interval time time count string string + 1398529018.678276 2 192.168.18.50 NetControl::DROP 600.000000 3600.000000 1398529618.678276 1398532618.678276 1 - - + 1398529018.678276 2 192.168.18.50 NetControl::DROPPED 600.000000 3600.000000 1398529618.678276 1398532618.678276 1 - - + #close 2016-06-22-22-58-49 + diff --git a/testing/btest/Baseline/doc.sphinx.netcontrol-8-multiple.bro/btest-doc.sphinx.netcontrol-8-multiple.bro#1 b/testing/btest/Baseline/doc.sphinx.netcontrol-8-multiple.bro/btest-doc.sphinx.netcontrol-8-multiple.bro#1 new file mode 100644 index 0000000000..3f48475e7e --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.netcontrol-8-multiple.bro/btest-doc.sphinx.netcontrol-8-multiple.bro#1 @@ -0,0 +1,10 @@ +.. rst-class:: btest-cmd + + .. code-block:: none + :linenos: + :emphasize-lines: 1,1 + + # bro netcontrol-8-multiple.bro + netcontrol debug (Debug-All): init + netcontrol debug (Debug-All): add_rule: [ty=NetControl::DROP, target=NetControl::FORWARD, entity=[ty=NetControl::ADDRESS, conn=, flow=, ip=192.168.17.2/32, mac=], expire=1.0 min, priority=0, location=, out_port=, mod=, id=3, cid=3, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _no_expire_plugins={\x0a\x0a}, _added=F] + diff --git a/testing/btest/Baseline/doc.sphinx.netcontrol-8-multiple.bro/btest-doc.sphinx.netcontrol-8-multiple.bro#2 b/testing/btest/Baseline/doc.sphinx.netcontrol-8-multiple.bro/btest-doc.sphinx.netcontrol-8-multiple.bro#2 new file mode 100644 index 0000000000..435078d4fb --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.netcontrol-8-multiple.bro/btest-doc.sphinx.netcontrol-8-multiple.bro#2 @@ -0,0 +1,28 @@ +.. rst-class:: btest-cmd + + .. code-block:: none + :linenos: + :emphasize-lines: 1,1 + + # cat netcontrol.log + #separator \x09 + #set_separator , + #empty_field (empty) + #unset_field - + #path netcontrol + #open 2016-06-22-22-58-52 + #fields ts rule_id category cmd state action target entity_type entity mod msg priority expire location plugin + #types time string enum string enum string enum string string string string int interval string string + 1466636332.844326 - NetControl::MESSAGE - - - - - - - activating plugin with priority 0 - - - Debug-All + 1466636332.844326 - NetControl::MESSAGE - - - - - - - activation finished - - - Debug-All + 1466636332.844326 - NetControl::MESSAGE - - - - - - - activating plugin with priority 10 - - - Openflow-Log-42 + 1466636332.844326 - NetControl::MESSAGE - - - - - - - activation finished - - - Openflow-Log-42 + 1466636332.844326 - NetControl::MESSAGE - - - - - - - plugin initialization done - - - - + 1466636332.844326 2 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 10.0.0.1/32 - - 0 60.000000 - Openflow-Log-42 + 1466636332.844326 3 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.17.2/32 - - 0 60.000000 - Debug-All + 1466636332.844326 4 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.2/32 - - 0 60.000000 - Openflow-Log-42 + 1466636332.844326 3 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.17.2/32 - - 0 60.000000 - Debug-All + 1466636332.844326 2 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 10.0.0.1/32 - - 0 60.000000 - Openflow-Log-42 + 1466636332.844326 4 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.2/32 - - 0 60.000000 - Openflow-Log-42 + #close 2016-06-22-22-58-52 + diff --git a/testing/btest/Baseline/doc.sphinx.netcontrol-8-multiple.bro/btest-doc.sphinx.netcontrol-8-multiple.bro#3 b/testing/btest/Baseline/doc.sphinx.netcontrol-8-multiple.bro/btest-doc.sphinx.netcontrol-8-multiple.bro#3 new file mode 100644 index 0000000000..7094c08b74 --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.netcontrol-8-multiple.bro/btest-doc.sphinx.netcontrol-8-multiple.bro#3 @@ -0,0 +1,21 @@ +.. rst-class:: btest-cmd + + .. code-block:: none + :linenos: + :emphasize-lines: 1,1 + + # cat openflow.log + #separator \x09 + #set_separator , + #empty_field (empty) + #unset_field - + #path openflow + #open 2016-06-22-22-58-52 + #fields ts dpid match.in_port match.dl_src match.dl_dst match.dl_vlan match.dl_vlan_pcp match.dl_type match.nw_tos match.nw_proto match.nw_src match.nw_dst match.tp_src match.tp_dst flow_mod.cookie flow_mod.table_id flow_mod.command flow_mod.idle_timeout flow_mod.hard_timeout flow_mod.priority flow_mod.out_port flow_mod.out_group flow_mod.flags flow_mod.actions.out_ports flow_mod.actions.vlan_vid flow_mod.actions.vlan_pcp flow_mod.actions.vlan_strip flow_mod.actions.dl_src flow_mod.actions.dl_dst flow_mod.actions.nw_tos flow_mod.actions.nw_src flow_mod.actions.nw_dst flow_mod.actions.tp_src flow_mod.actions.tp_dst + #types time count count string string count count count count count subnet subnet count count count count enum count count count count count count vector[count] count count bool string string count addr addr count count + 1466636332.844326 42 - - - - - 2048 - - 10.0.0.1/32 - - - 4398046511108 - OpenFlow::OFPFC_ADD 0 60 0 - - 1 (empty) - - F - - - - - - - + 1466636332.844326 42 - - - - - 2048 - - - 10.0.0.1/32 - - 4398046511109 - OpenFlow::OFPFC_ADD 0 60 0 - - 1 (empty) - - F - - - - - - - + 1466636332.844326 42 - - - - - 2048 - - 192.168.18.2/32 - - - 4398046511112 - OpenFlow::OFPFC_ADD 0 60 0 - - 1 (empty) - - F - - - - - - - + 1466636332.844326 42 - - - - - 2048 - - - 192.168.18.2/32 - - 4398046511113 - OpenFlow::OFPFC_ADD 0 60 0 - - 1 (empty) - - F - - - - - - - + #close 2016-06-22-22-58-52 + diff --git a/testing/btest/Baseline/doc.sphinx.netcontrol-8-multiple.bro/btest-doc.sphinx.netcontrol-8-multiple.bro#4 b/testing/btest/Baseline/doc.sphinx.netcontrol-8-multiple.bro/btest-doc.sphinx.netcontrol-8-multiple.bro#4 new file mode 100644 index 0000000000..941d9336c9 --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.netcontrol-8-multiple.bro/btest-doc.sphinx.netcontrol-8-multiple.bro#4 @@ -0,0 +1,15 @@ +.. rst-class:: btest-cmd + + .. code-block:: none + :linenos: + :emphasize-lines: 1,1 + + # bro -C -r tls/ecdhe.pcap netcontrol-10-use-skeleton.bro + add, [ty=NetControl::DROP, target=NetControl::FORWARD, entity=[ty=NetControl::CONNECTION, conn=[orig_h=192.168.18.50, orig_p=56981/tcp, resp_h=74.125.239.97, resp_p=443/tcp], flow=, ip=, mac=], expire=20.0 secs, priority=0, location=, out_port=, mod=, id=2, cid=2, _plugin_ids={ + + }, _active_plugin_ids={ + + }, _no_expire_plugins={ + + }, _added=F] + diff --git a/testing/btest/Baseline/doc.sphinx.netcontrol-9-skeleton.bro/btest-doc.sphinx.netcontrol-9-skeleton.bro#1 b/testing/btest/Baseline/doc.sphinx.netcontrol-9-skeleton.bro/btest-doc.sphinx.netcontrol-9-skeleton.bro#1 new file mode 100644 index 0000000000..941d9336c9 --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.netcontrol-9-skeleton.bro/btest-doc.sphinx.netcontrol-9-skeleton.bro#1 @@ -0,0 +1,15 @@ +.. rst-class:: btest-cmd + + .. code-block:: none + :linenos: + :emphasize-lines: 1,1 + + # bro -C -r tls/ecdhe.pcap netcontrol-10-use-skeleton.bro + add, [ty=NetControl::DROP, target=NetControl::FORWARD, entity=[ty=NetControl::CONNECTION, conn=[orig_h=192.168.18.50, orig_p=56981/tcp, resp_h=74.125.239.97, resp_p=443/tcp], flow=, ip=, mac=], expire=20.0 secs, priority=0, location=, out_port=, mod=, id=2, cid=2, _plugin_ids={ + + }, _active_plugin_ids={ + + }, _no_expire_plugins={ + + }, _added=F] + diff --git a/testing/btest/Baseline/plugins.hooks/output b/testing/btest/Baseline/plugins.hooks/output index 91f56d8d5b..5a0c16daea 100644 --- a/testing/btest/Baseline/plugins.hooks/output +++ b/testing/btest/Baseline/plugins.hooks/output @@ -172,6 +172,7 @@ 0.000000 MetaHookPost CallFunction(Log::__add_filter, , (Intel::LOG, [name=default, writer=Log::WRITER_ASCII, pred=, path=intel, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}])) -> 0.000000 MetaHookPost CallFunction(Log::__add_filter, , (KRB::LOG, [name=default, writer=Log::WRITER_ASCII, pred=, path=kerberos, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}])) -> 0.000000 MetaHookPost CallFunction(Log::__add_filter, , (Modbus::LOG, [name=default, writer=Log::WRITER_ASCII, pred=, path=modbus, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}])) -> +0.000000 MetaHookPost CallFunction(Log::__add_filter, , (NetControl::CATCH_RELEASE, [name=default, writer=Log::WRITER_ASCII, pred=, path=netcontrol_catch_release, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}])) -> 0.000000 MetaHookPost CallFunction(Log::__add_filter, , (NetControl::DROP, [name=default, writer=Log::WRITER_ASCII, pred=, path=netcontrol_drop, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}])) -> 0.000000 MetaHookPost CallFunction(Log::__add_filter, , (NetControl::LOG, [name=default, writer=Log::WRITER_ASCII, pred=, path=netcontrol, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}])) -> 0.000000 MetaHookPost CallFunction(Log::__add_filter, , (NetControl::SHUNT, [name=default, writer=Log::WRITER_ASCII, pred=, path=netcontrol_shunt, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}])) -> @@ -212,6 +213,7 @@ 0.000000 MetaHookPost CallFunction(Log::__create_stream, , (Intel::LOG, [columns=, ev=Intel::log_intel, path=intel])) -> 0.000000 MetaHookPost CallFunction(Log::__create_stream, , (KRB::LOG, [columns=, ev=KRB::log_krb, path=kerberos])) -> 0.000000 MetaHookPost CallFunction(Log::__create_stream, , (Modbus::LOG, [columns=, ev=Modbus::log_modbus, path=modbus])) -> +0.000000 MetaHookPost CallFunction(Log::__create_stream, , (NetControl::CATCH_RELEASE, [columns=, ev=NetControl::log_netcontrol_catch_release, path=netcontrol_catch_release])) -> 0.000000 MetaHookPost CallFunction(Log::__create_stream, , (NetControl::DROP, [columns=, ev=NetControl::log_netcontrol_drop, path=netcontrol_drop])) -> 0.000000 MetaHookPost CallFunction(Log::__create_stream, , (NetControl::LOG, [columns=, ev=NetControl::log_netcontrol, path=netcontrol])) -> 0.000000 MetaHookPost CallFunction(Log::__create_stream, , (NetControl::SHUNT, [columns=, ev=NetControl::log_netcontrol_shunt, path=netcontrol_shunt])) -> @@ -238,7 +240,7 @@ 0.000000 MetaHookPost CallFunction(Log::__create_stream, , (Weird::LOG, [columns=, ev=Weird::log_weird, path=weird])) -> 0.000000 MetaHookPost CallFunction(Log::__create_stream, , (X509::LOG, [columns=, ev=X509::log_x509, path=x509])) -> 0.000000 MetaHookPost CallFunction(Log::__create_stream, , (mysql::LOG, [columns=, ev=MySQL::log_mysql, path=mysql])) -> -0.000000 MetaHookPost CallFunction(Log::__write, , (PacketFilter::LOG, [ts=1466281781.049315, node=bro, filter=ip or not ip, init=T, success=T])) -> +0.000000 MetaHookPost CallFunction(Log::__write, , (PacketFilter::LOG, [ts=1466636352.007236, node=bro, filter=ip or not ip, init=T, success=T])) -> 0.000000 MetaHookPost CallFunction(Log::add_default_filter, , (Cluster::LOG)) -> 0.000000 MetaHookPost CallFunction(Log::add_default_filter, , (Communication::LOG)) -> 0.000000 MetaHookPost CallFunction(Log::add_default_filter, , (Conn::LOG)) -> @@ -253,6 +255,7 @@ 0.000000 MetaHookPost CallFunction(Log::add_default_filter, , (Intel::LOG)) -> 0.000000 MetaHookPost CallFunction(Log::add_default_filter, , (KRB::LOG)) -> 0.000000 MetaHookPost CallFunction(Log::add_default_filter, , (Modbus::LOG)) -> +0.000000 MetaHookPost CallFunction(Log::add_default_filter, , (NetControl::CATCH_RELEASE)) -> 0.000000 MetaHookPost CallFunction(Log::add_default_filter, , (NetControl::DROP)) -> 0.000000 MetaHookPost CallFunction(Log::add_default_filter, , (NetControl::LOG)) -> 0.000000 MetaHookPost CallFunction(Log::add_default_filter, , (NetControl::SHUNT)) -> @@ -293,6 +296,7 @@ 0.000000 MetaHookPost CallFunction(Log::add_filter, , (Intel::LOG, [name=default, writer=Log::WRITER_ASCII, pred=, path=, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}])) -> 0.000000 MetaHookPost CallFunction(Log::add_filter, , (KRB::LOG, [name=default, writer=Log::WRITER_ASCII, pred=, path=, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}])) -> 0.000000 MetaHookPost CallFunction(Log::add_filter, , (Modbus::LOG, [name=default, writer=Log::WRITER_ASCII, pred=, path=, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}])) -> +0.000000 MetaHookPost CallFunction(Log::add_filter, , (NetControl::CATCH_RELEASE, [name=default, writer=Log::WRITER_ASCII, pred=, path=, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}])) -> 0.000000 MetaHookPost CallFunction(Log::add_filter, , (NetControl::DROP, [name=default, writer=Log::WRITER_ASCII, pred=, path=, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}])) -> 0.000000 MetaHookPost CallFunction(Log::add_filter, , (NetControl::LOG, [name=default, writer=Log::WRITER_ASCII, pred=, path=, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}])) -> 0.000000 MetaHookPost CallFunction(Log::add_filter, , (NetControl::SHUNT, [name=default, writer=Log::WRITER_ASCII, pred=, path=, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}])) -> @@ -333,6 +337,7 @@ 0.000000 MetaHookPost CallFunction(Log::create_stream, , (Intel::LOG, [columns=, ev=Intel::log_intel, path=intel])) -> 0.000000 MetaHookPost CallFunction(Log::create_stream, , (KRB::LOG, [columns=, ev=KRB::log_krb, path=kerberos])) -> 0.000000 MetaHookPost CallFunction(Log::create_stream, , (Modbus::LOG, [columns=, ev=Modbus::log_modbus, path=modbus])) -> +0.000000 MetaHookPost CallFunction(Log::create_stream, , (NetControl::CATCH_RELEASE, [columns=, ev=NetControl::log_netcontrol_catch_release, path=netcontrol_catch_release])) -> 0.000000 MetaHookPost CallFunction(Log::create_stream, , (NetControl::DROP, [columns=, ev=NetControl::log_netcontrol_drop, path=netcontrol_drop])) -> 0.000000 MetaHookPost CallFunction(Log::create_stream, , (NetControl::LOG, [columns=, ev=NetControl::log_netcontrol, path=netcontrol])) -> 0.000000 MetaHookPost CallFunction(Log::create_stream, , (NetControl::SHUNT, [columns=, ev=NetControl::log_netcontrol_shunt, path=netcontrol_shunt])) -> @@ -359,7 +364,7 @@ 0.000000 MetaHookPost CallFunction(Log::create_stream, , (Weird::LOG, [columns=, ev=Weird::log_weird, path=weird])) -> 0.000000 MetaHookPost CallFunction(Log::create_stream, , (X509::LOG, [columns=, ev=X509::log_x509, path=x509])) -> 0.000000 MetaHookPost CallFunction(Log::create_stream, , (mysql::LOG, [columns=, ev=MySQL::log_mysql, path=mysql])) -> -0.000000 MetaHookPost CallFunction(Log::write, , (PacketFilter::LOG, [ts=1466281781.049315, node=bro, filter=ip or not ip, init=T, success=T])) -> +0.000000 MetaHookPost CallFunction(Log::write, , (PacketFilter::LOG, [ts=1466636352.007236, node=bro, filter=ip or not ip, init=T, success=T])) -> 0.000000 MetaHookPost CallFunction(NetControl::check_plugins, , ()) -> 0.000000 MetaHookPost CallFunction(NetControl::init, , ()) -> 0.000000 MetaHookPost CallFunction(Notice::want_pp, , ()) -> @@ -392,7 +397,7 @@ 0.000000 MetaHookPost CallFunction(reading_live_traffic, , ()) -> 0.000000 MetaHookPost CallFunction(reading_traces, , ()) -> 0.000000 MetaHookPost CallFunction(set_to_regex, , ({}, (^\.?|\.)(~~)$)) -> -0.000000 MetaHookPost CallFunction(strftime, , (%Y, 1466281781.048782)) -> +0.000000 MetaHookPost CallFunction(strftime, , (%Y, 1466636352.006823)) -> 0.000000 MetaHookPost CallFunction(string_to_pattern, , ((^\.?|\.)()$, F)) -> 0.000000 MetaHookPost CallFunction(sub, , ((^\.?|\.)(~~)$, <...>/, )) -> 0.000000 MetaHookPost CallFunction(to_count, , (2016)) -> @@ -834,6 +839,7 @@ 0.000000 MetaHookPre CallFunction(Log::__add_filter, , (Intel::LOG, [name=default, writer=Log::WRITER_ASCII, pred=, path=intel, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}])) 0.000000 MetaHookPre CallFunction(Log::__add_filter, , (KRB::LOG, [name=default, writer=Log::WRITER_ASCII, pred=, path=kerberos, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}])) 0.000000 MetaHookPre CallFunction(Log::__add_filter, , (Modbus::LOG, [name=default, writer=Log::WRITER_ASCII, pred=, path=modbus, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}])) +0.000000 MetaHookPre CallFunction(Log::__add_filter, , (NetControl::CATCH_RELEASE, [name=default, writer=Log::WRITER_ASCII, pred=, path=netcontrol_catch_release, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}])) 0.000000 MetaHookPre CallFunction(Log::__add_filter, , (NetControl::DROP, [name=default, writer=Log::WRITER_ASCII, pred=, path=netcontrol_drop, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}])) 0.000000 MetaHookPre CallFunction(Log::__add_filter, , (NetControl::LOG, [name=default, writer=Log::WRITER_ASCII, pred=, path=netcontrol, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}])) 0.000000 MetaHookPre CallFunction(Log::__add_filter, , (NetControl::SHUNT, [name=default, writer=Log::WRITER_ASCII, pred=, path=netcontrol_shunt, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}])) @@ -874,6 +880,7 @@ 0.000000 MetaHookPre CallFunction(Log::__create_stream, , (Intel::LOG, [columns=, ev=Intel::log_intel, path=intel])) 0.000000 MetaHookPre CallFunction(Log::__create_stream, , (KRB::LOG, [columns=, ev=KRB::log_krb, path=kerberos])) 0.000000 MetaHookPre CallFunction(Log::__create_stream, , (Modbus::LOG, [columns=, ev=Modbus::log_modbus, path=modbus])) +0.000000 MetaHookPre CallFunction(Log::__create_stream, , (NetControl::CATCH_RELEASE, [columns=, ev=NetControl::log_netcontrol_catch_release, path=netcontrol_catch_release])) 0.000000 MetaHookPre CallFunction(Log::__create_stream, , (NetControl::DROP, [columns=, ev=NetControl::log_netcontrol_drop, path=netcontrol_drop])) 0.000000 MetaHookPre CallFunction(Log::__create_stream, , (NetControl::LOG, [columns=, ev=NetControl::log_netcontrol, path=netcontrol])) 0.000000 MetaHookPre CallFunction(Log::__create_stream, , (NetControl::SHUNT, [columns=, ev=NetControl::log_netcontrol_shunt, path=netcontrol_shunt])) @@ -900,7 +907,7 @@ 0.000000 MetaHookPre CallFunction(Log::__create_stream, , (Weird::LOG, [columns=, ev=Weird::log_weird, path=weird])) 0.000000 MetaHookPre CallFunction(Log::__create_stream, , (X509::LOG, [columns=, ev=X509::log_x509, path=x509])) 0.000000 MetaHookPre CallFunction(Log::__create_stream, , (mysql::LOG, [columns=, ev=MySQL::log_mysql, path=mysql])) -0.000000 MetaHookPre CallFunction(Log::__write, , (PacketFilter::LOG, [ts=1466281781.049315, node=bro, filter=ip or not ip, init=T, success=T])) +0.000000 MetaHookPre CallFunction(Log::__write, , (PacketFilter::LOG, [ts=1466636352.007236, node=bro, filter=ip or not ip, init=T, success=T])) 0.000000 MetaHookPre CallFunction(Log::add_default_filter, , (Cluster::LOG)) 0.000000 MetaHookPre CallFunction(Log::add_default_filter, , (Communication::LOG)) 0.000000 MetaHookPre CallFunction(Log::add_default_filter, , (Conn::LOG)) @@ -915,6 +922,7 @@ 0.000000 MetaHookPre CallFunction(Log::add_default_filter, , (Intel::LOG)) 0.000000 MetaHookPre CallFunction(Log::add_default_filter, , (KRB::LOG)) 0.000000 MetaHookPre CallFunction(Log::add_default_filter, , (Modbus::LOG)) +0.000000 MetaHookPre CallFunction(Log::add_default_filter, , (NetControl::CATCH_RELEASE)) 0.000000 MetaHookPre CallFunction(Log::add_default_filter, , (NetControl::DROP)) 0.000000 MetaHookPre CallFunction(Log::add_default_filter, , (NetControl::LOG)) 0.000000 MetaHookPre CallFunction(Log::add_default_filter, , (NetControl::SHUNT)) @@ -955,6 +963,7 @@ 0.000000 MetaHookPre CallFunction(Log::add_filter, , (Intel::LOG, [name=default, writer=Log::WRITER_ASCII, pred=, path=, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}])) 0.000000 MetaHookPre CallFunction(Log::add_filter, , (KRB::LOG, [name=default, writer=Log::WRITER_ASCII, pred=, path=, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}])) 0.000000 MetaHookPre CallFunction(Log::add_filter, , (Modbus::LOG, [name=default, writer=Log::WRITER_ASCII, pred=, path=, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}])) +0.000000 MetaHookPre CallFunction(Log::add_filter, , (NetControl::CATCH_RELEASE, [name=default, writer=Log::WRITER_ASCII, pred=, path=, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}])) 0.000000 MetaHookPre CallFunction(Log::add_filter, , (NetControl::DROP, [name=default, writer=Log::WRITER_ASCII, pred=, path=, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}])) 0.000000 MetaHookPre CallFunction(Log::add_filter, , (NetControl::LOG, [name=default, writer=Log::WRITER_ASCII, pred=, path=, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}])) 0.000000 MetaHookPre CallFunction(Log::add_filter, , (NetControl::SHUNT, [name=default, writer=Log::WRITER_ASCII, pred=, path=, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}])) @@ -995,6 +1004,7 @@ 0.000000 MetaHookPre CallFunction(Log::create_stream, , (Intel::LOG, [columns=, ev=Intel::log_intel, path=intel])) 0.000000 MetaHookPre CallFunction(Log::create_stream, , (KRB::LOG, [columns=, ev=KRB::log_krb, path=kerberos])) 0.000000 MetaHookPre CallFunction(Log::create_stream, , (Modbus::LOG, [columns=, ev=Modbus::log_modbus, path=modbus])) +0.000000 MetaHookPre CallFunction(Log::create_stream, , (NetControl::CATCH_RELEASE, [columns=, ev=NetControl::log_netcontrol_catch_release, path=netcontrol_catch_release])) 0.000000 MetaHookPre CallFunction(Log::create_stream, , (NetControl::DROP, [columns=, ev=NetControl::log_netcontrol_drop, path=netcontrol_drop])) 0.000000 MetaHookPre CallFunction(Log::create_stream, , (NetControl::LOG, [columns=, ev=NetControl::log_netcontrol, path=netcontrol])) 0.000000 MetaHookPre CallFunction(Log::create_stream, , (NetControl::SHUNT, [columns=, ev=NetControl::log_netcontrol_shunt, path=netcontrol_shunt])) @@ -1021,7 +1031,7 @@ 0.000000 MetaHookPre CallFunction(Log::create_stream, , (Weird::LOG, [columns=, ev=Weird::log_weird, path=weird])) 0.000000 MetaHookPre CallFunction(Log::create_stream, , (X509::LOG, [columns=, ev=X509::log_x509, path=x509])) 0.000000 MetaHookPre CallFunction(Log::create_stream, , (mysql::LOG, [columns=, ev=MySQL::log_mysql, path=mysql])) -0.000000 MetaHookPre CallFunction(Log::write, , (PacketFilter::LOG, [ts=1466281781.049315, node=bro, filter=ip or not ip, init=T, success=T])) +0.000000 MetaHookPre CallFunction(Log::write, , (PacketFilter::LOG, [ts=1466636352.007236, node=bro, filter=ip or not ip, init=T, success=T])) 0.000000 MetaHookPre CallFunction(NetControl::check_plugins, , ()) 0.000000 MetaHookPre CallFunction(NetControl::init, , ()) 0.000000 MetaHookPre CallFunction(Notice::want_pp, , ()) @@ -1054,7 +1064,7 @@ 0.000000 MetaHookPre CallFunction(reading_live_traffic, , ()) 0.000000 MetaHookPre CallFunction(reading_traces, , ()) 0.000000 MetaHookPre CallFunction(set_to_regex, , ({}, (^\.?|\.)(~~)$)) -0.000000 MetaHookPre CallFunction(strftime, , (%Y, 1466281781.048782)) +0.000000 MetaHookPre CallFunction(strftime, , (%Y, 1466636352.006823)) 0.000000 MetaHookPre CallFunction(string_to_pattern, , ((^\.?|\.)()$, F)) 0.000000 MetaHookPre CallFunction(sub, , ((^\.?|\.)(~~)$, <...>/, )) 0.000000 MetaHookPre CallFunction(to_count, , (2016)) @@ -1495,6 +1505,7 @@ 0.000000 | HookCallFunction Log::__add_filter(Intel::LOG, [name=default, writer=Log::WRITER_ASCII, pred=, path=intel, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}]) 0.000000 | HookCallFunction Log::__add_filter(KRB::LOG, [name=default, writer=Log::WRITER_ASCII, pred=, path=kerberos, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}]) 0.000000 | HookCallFunction Log::__add_filter(Modbus::LOG, [name=default, writer=Log::WRITER_ASCII, pred=, path=modbus, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}]) +0.000000 | HookCallFunction Log::__add_filter(NetControl::CATCH_RELEASE, [name=default, writer=Log::WRITER_ASCII, pred=, path=netcontrol_catch_release, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}]) 0.000000 | HookCallFunction Log::__add_filter(NetControl::DROP, [name=default, writer=Log::WRITER_ASCII, pred=, path=netcontrol_drop, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}]) 0.000000 | HookCallFunction Log::__add_filter(NetControl::LOG, [name=default, writer=Log::WRITER_ASCII, pred=, path=netcontrol, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}]) 0.000000 | HookCallFunction Log::__add_filter(NetControl::SHUNT, [name=default, writer=Log::WRITER_ASCII, pred=, path=netcontrol_shunt, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}]) @@ -1535,6 +1546,7 @@ 0.000000 | HookCallFunction Log::__create_stream(Intel::LOG, [columns=, ev=Intel::log_intel, path=intel]) 0.000000 | HookCallFunction Log::__create_stream(KRB::LOG, [columns=, ev=KRB::log_krb, path=kerberos]) 0.000000 | HookCallFunction Log::__create_stream(Modbus::LOG, [columns=, ev=Modbus::log_modbus, path=modbus]) +0.000000 | HookCallFunction Log::__create_stream(NetControl::CATCH_RELEASE, [columns=, ev=NetControl::log_netcontrol_catch_release, path=netcontrol_catch_release]) 0.000000 | HookCallFunction Log::__create_stream(NetControl::DROP, [columns=, ev=NetControl::log_netcontrol_drop, path=netcontrol_drop]) 0.000000 | HookCallFunction Log::__create_stream(NetControl::LOG, [columns=, ev=NetControl::log_netcontrol, path=netcontrol]) 0.000000 | HookCallFunction Log::__create_stream(NetControl::SHUNT, [columns=, ev=NetControl::log_netcontrol_shunt, path=netcontrol_shunt]) @@ -1561,7 +1573,7 @@ 0.000000 | HookCallFunction Log::__create_stream(Weird::LOG, [columns=, ev=Weird::log_weird, path=weird]) 0.000000 | HookCallFunction Log::__create_stream(X509::LOG, [columns=, ev=X509::log_x509, path=x509]) 0.000000 | HookCallFunction Log::__create_stream(mysql::LOG, [columns=, ev=MySQL::log_mysql, path=mysql]) -0.000000 | HookCallFunction Log::__write(PacketFilter::LOG, [ts=1466281781.049315, node=bro, filter=ip or not ip, init=T, success=T]) +0.000000 | HookCallFunction Log::__write(PacketFilter::LOG, [ts=1466636352.007236, node=bro, filter=ip or not ip, init=T, success=T]) 0.000000 | HookCallFunction Log::add_default_filter(Cluster::LOG) 0.000000 | HookCallFunction Log::add_default_filter(Communication::LOG) 0.000000 | HookCallFunction Log::add_default_filter(Conn::LOG) @@ -1576,6 +1588,7 @@ 0.000000 | HookCallFunction Log::add_default_filter(Intel::LOG) 0.000000 | HookCallFunction Log::add_default_filter(KRB::LOG) 0.000000 | HookCallFunction Log::add_default_filter(Modbus::LOG) +0.000000 | HookCallFunction Log::add_default_filter(NetControl::CATCH_RELEASE) 0.000000 | HookCallFunction Log::add_default_filter(NetControl::DROP) 0.000000 | HookCallFunction Log::add_default_filter(NetControl::LOG) 0.000000 | HookCallFunction Log::add_default_filter(NetControl::SHUNT) @@ -1616,6 +1629,7 @@ 0.000000 | HookCallFunction Log::add_filter(Intel::LOG, [name=default, writer=Log::WRITER_ASCII, pred=, path=, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}]) 0.000000 | HookCallFunction Log::add_filter(KRB::LOG, [name=default, writer=Log::WRITER_ASCII, pred=, path=, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}]) 0.000000 | HookCallFunction Log::add_filter(Modbus::LOG, [name=default, writer=Log::WRITER_ASCII, pred=, path=, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}]) +0.000000 | HookCallFunction Log::add_filter(NetControl::CATCH_RELEASE, [name=default, writer=Log::WRITER_ASCII, pred=, path=, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}]) 0.000000 | HookCallFunction Log::add_filter(NetControl::DROP, [name=default, writer=Log::WRITER_ASCII, pred=, path=, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}]) 0.000000 | HookCallFunction Log::add_filter(NetControl::LOG, [name=default, writer=Log::WRITER_ASCII, pred=, path=, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}]) 0.000000 | HookCallFunction Log::add_filter(NetControl::SHUNT, [name=default, writer=Log::WRITER_ASCII, pred=, path=, path_func=, include=, exclude=, log_local=T, log_remote=T, interv=0 secs, postprocessor=, config={}]) @@ -1656,6 +1670,7 @@ 0.000000 | HookCallFunction Log::create_stream(Intel::LOG, [columns=, ev=Intel::log_intel, path=intel]) 0.000000 | HookCallFunction Log::create_stream(KRB::LOG, [columns=, ev=KRB::log_krb, path=kerberos]) 0.000000 | HookCallFunction Log::create_stream(Modbus::LOG, [columns=, ev=Modbus::log_modbus, path=modbus]) +0.000000 | HookCallFunction Log::create_stream(NetControl::CATCH_RELEASE, [columns=, ev=NetControl::log_netcontrol_catch_release, path=netcontrol_catch_release]) 0.000000 | HookCallFunction Log::create_stream(NetControl::DROP, [columns=, ev=NetControl::log_netcontrol_drop, path=netcontrol_drop]) 0.000000 | HookCallFunction Log::create_stream(NetControl::LOG, [columns=, ev=NetControl::log_netcontrol, path=netcontrol]) 0.000000 | HookCallFunction Log::create_stream(NetControl::SHUNT, [columns=, ev=NetControl::log_netcontrol_shunt, path=netcontrol_shunt]) @@ -1682,7 +1697,7 @@ 0.000000 | HookCallFunction Log::create_stream(Weird::LOG, [columns=, ev=Weird::log_weird, path=weird]) 0.000000 | HookCallFunction Log::create_stream(X509::LOG, [columns=, ev=X509::log_x509, path=x509]) 0.000000 | HookCallFunction Log::create_stream(mysql::LOG, [columns=, ev=MySQL::log_mysql, path=mysql]) -0.000000 | HookCallFunction Log::write(PacketFilter::LOG, [ts=1466281781.049315, node=bro, filter=ip or not ip, init=T, success=T]) +0.000000 | HookCallFunction Log::write(PacketFilter::LOG, [ts=1466636352.007236, node=bro, filter=ip or not ip, init=T, success=T]) 0.000000 | HookCallFunction NetControl::check_plugins() 0.000000 | HookCallFunction NetControl::init() 0.000000 | HookCallFunction Notice::want_pp() @@ -1715,7 +1730,7 @@ 0.000000 | HookCallFunction reading_live_traffic() 0.000000 | HookCallFunction reading_traces() 0.000000 | HookCallFunction set_to_regex({}, (^\.?|\.)(~~)$) -0.000000 | HookCallFunction strftime(%Y, 1466281781.048782) +0.000000 | HookCallFunction strftime(%Y, 1466636352.006823) 0.000000 | HookCallFunction string_to_pattern((^\.?|\.)()$, F) 0.000000 | HookCallFunction sub((^\.?|\.)(~~)$, <...>/, ) 0.000000 | HookCallFunction to_count(2016) @@ -1730,7 +1745,8 @@ 0.000000 | HookQueueEvent filter_change_tracking() 1362692526.869344 MetaHookPost BroObjDtor() -> 1362692526.869344 MetaHookPost CallFunction(ChecksumOffloading::check, , ()) -> -1362692526.869344 MetaHookPost CallFunction(NetControl::check_conn, , (141.142.228.5)) -> +1362692526.869344 MetaHookPost CallFunction(NetControl::catch_release_seen, , (141.142.228.5)) -> +1362692526.869344 MetaHookPost CallFunction(addr_to_subnet, , (141.142.228.5)) -> 1362692526.869344 MetaHookPost CallFunction(filter_change_tracking, , ()) -> 1362692526.869344 MetaHookPost CallFunction(get_net_stats, , ()) -> 1362692526.869344 MetaHookPost CallFunction(new_connection, , ([id=[orig_h=141.142.228.5, orig_p=59856<...>/tcp], orig=[size=0, state=0, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=c8:bc:c8:96:d2:a0], resp=[size=0, state=0, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=00:10:db:88:d2:ef], start_time=1362692526.869344, duration=0.0, service={}, history=, uid=CXWv6p3arKYeMETxOg, tunnel=, vlan=, inner_vlan=, dpd=, conn=, extract_orig=F, extract_resp=F, thresholds=, dhcp=, dnp3=, dns=, dns_state=, ftp=, ftp_data_reuse=F, ssl=, http=, http_state=, irc=, krb=, modbus=, mysql=, radius=, rdp=, rfb=, sip=, sip_state=, snmp=, smtp=, smtp_state=, socks=, ssh=, syslog=])) -> @@ -1741,7 +1757,8 @@ 1362692526.869344 MetaHookPost UpdateNetworkTime(1362692526.869344) -> 1362692526.869344 MetaHookPre BroObjDtor() 1362692526.869344 MetaHookPre CallFunction(ChecksumOffloading::check, , ()) -1362692526.869344 MetaHookPre CallFunction(NetControl::check_conn, , (141.142.228.5)) +1362692526.869344 MetaHookPre CallFunction(NetControl::catch_release_seen, , (141.142.228.5)) +1362692526.869344 MetaHookPre CallFunction(addr_to_subnet, , (141.142.228.5)) 1362692526.869344 MetaHookPre CallFunction(filter_change_tracking, , ()) 1362692526.869344 MetaHookPre CallFunction(get_net_stats, , ()) 1362692526.869344 MetaHookPre CallFunction(new_connection, , ([id=[orig_h=141.142.228.5, orig_p=59856<...>/tcp], orig=[size=0, state=0, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=c8:bc:c8:96:d2:a0], resp=[size=0, state=0, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=00:10:db:88:d2:ef], start_time=1362692526.869344, duration=0.0, service={}, history=, uid=CXWv6p3arKYeMETxOg, tunnel=, vlan=, inner_vlan=, dpd=, conn=, extract_orig=F, extract_resp=F, thresholds=, dhcp=, dnp3=, dns=, dns_state=, ftp=, ftp_data_reuse=F, ssl=, http=, http_state=, irc=, krb=, modbus=, mysql=, radius=, rdp=, rfb=, sip=, sip_state=, snmp=, smtp=, smtp_state=, socks=, ssh=, syslog=])) @@ -1753,7 +1770,8 @@ 1362692526.869344 | HookBroObjDtor 1362692526.869344 | HookUpdateNetworkTime 1362692526.869344 1362692526.869344 | HookCallFunction ChecksumOffloading::check() -1362692526.869344 | HookCallFunction NetControl::check_conn(141.142.228.5) +1362692526.869344 | HookCallFunction NetControl::catch_release_seen(141.142.228.5) +1362692526.869344 | HookCallFunction addr_to_subnet(141.142.228.5) 1362692526.869344 | HookCallFunction filter_change_tracking() 1362692526.869344 | HookCallFunction get_net_stats() 1362692526.869344 | HookCallFunction new_connection([id=[orig_h=141.142.228.5, orig_p=59856<...>/tcp], orig=[size=0, state=0, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=c8:bc:c8:96:d2:a0], resp=[size=0, state=0, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=00:10:db:88:d2:ef], start_time=1362692526.869344, duration=0.0, service={}, history=, uid=CXWv6p3arKYeMETxOg, tunnel=, vlan=, inner_vlan=, dpd=, conn=, extract_orig=F, extract_resp=F, thresholds=, dhcp=, dnp3=, dns=, dns_state=, ftp=, ftp_data_reuse=F, ssl=, http=, http_state=, irc=, krb=, modbus=, mysql=, radius=, rdp=, rfb=, sip=, sip_state=, snmp=, smtp=, smtp_state=, socks=, ssh=, syslog=]) @@ -1762,15 +1780,21 @@ 1362692526.869344 | HookQueueEvent filter_change_tracking() 1362692526.869344 | HookQueueEvent new_connection([id=[orig_h=141.142.228.5, orig_p=59856<...>/tcp], orig=[size=0, state=0, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=c8:bc:c8:96:d2:a0], resp=[size=0, state=0, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=00:10:db:88:d2:ef], start_time=1362692526.869344, duration=0.0, service={}, history=, uid=CXWv6p3arKYeMETxOg, tunnel=, vlan=, inner_vlan=, dpd=, conn=, extract_orig=F, extract_resp=F, thresholds=, dhcp=, dnp3=, dns=, dns_state=, ftp=, ftp_data_reuse=F, ssl=, http=, http_state=, irc=, krb=, modbus=, mysql=, radius=, rdp=, rfb=, sip=, sip_state=, snmp=, smtp=, smtp_state=, socks=, ssh=, syslog=]) 1362692526.869344 | RequestObjDtor ChecksumOffloading::check() +1362692526.939084 MetaHookPost CallFunction(NetControl::catch_release_seen, , (141.142.228.5)) -> +1362692526.939084 MetaHookPost CallFunction(addr_to_subnet, , (141.142.228.5)) -> 1362692526.939084 MetaHookPost CallFunction(connection_established, , ([id=[orig_h=141.142.228.5, orig_p=59856<...>/tcp], orig=[size=0, state=4, num_pkts=1, num_bytes_ip=64, flow_label=0, l2_addr=c8:bc:c8:96:d2:a0], resp=[size=0, state=4, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=00:10:db:88:d2:ef], start_time=1362692526.869344, duration=0.06974, service={}, history=Sh, uid=CXWv6p3arKYeMETxOg, tunnel=, vlan=, inner_vlan=, dpd=, conn=, extract_orig=F, extract_resp=F, thresholds=, dhcp=, dnp3=, dns=, dns_state=, ftp=, ftp_data_reuse=F, ssl=, http=, http_state=, irc=, krb=, modbus=, mysql=, radius=, rdp=, rfb=, sip=, sip_state=, snmp=, smtp=, smtp_state=, socks=, ssh=, syslog=])) -> 1362692526.939084 MetaHookPost DrainEvents() -> 1362692526.939084 MetaHookPost QueueEvent(connection_established([id=[orig_h=141.142.228.5, orig_p=59856<...>/tcp], orig=[size=0, state=4, num_pkts=1, num_bytes_ip=64, flow_label=0, l2_addr=c8:bc:c8:96:d2:a0], resp=[size=0, state=4, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=00:10:db:88:d2:ef], start_time=1362692526.869344, duration=0.06974, service={}, history=Sh, uid=CXWv6p3arKYeMETxOg, tunnel=, vlan=, inner_vlan=, dpd=, conn=, extract_orig=F, extract_resp=F, thresholds=, dhcp=, dnp3=, dns=, dns_state=, ftp=, ftp_data_reuse=F, ssl=, http=, http_state=, irc=, krb=, modbus=, mysql=, radius=, rdp=, rfb=, sip=, sip_state=, snmp=, smtp=, smtp_state=, socks=, ssh=, syslog=])) -> false 1362692526.939084 MetaHookPost UpdateNetworkTime(1362692526.939084) -> +1362692526.939084 MetaHookPre CallFunction(NetControl::catch_release_seen, , (141.142.228.5)) +1362692526.939084 MetaHookPre CallFunction(addr_to_subnet, , (141.142.228.5)) 1362692526.939084 MetaHookPre CallFunction(connection_established, , ([id=[orig_h=141.142.228.5, orig_p=59856<...>/tcp], orig=[size=0, state=4, num_pkts=1, num_bytes_ip=64, flow_label=0, l2_addr=c8:bc:c8:96:d2:a0], resp=[size=0, state=4, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=00:10:db:88:d2:ef], start_time=1362692526.869344, duration=0.06974, service={}, history=Sh, uid=CXWv6p3arKYeMETxOg, tunnel=, vlan=, inner_vlan=, dpd=, conn=, extract_orig=F, extract_resp=F, thresholds=, dhcp=, dnp3=, dns=, dns_state=, ftp=, ftp_data_reuse=F, ssl=, http=, http_state=, irc=, krb=, modbus=, mysql=, radius=, rdp=, rfb=, sip=, sip_state=, snmp=, smtp=, smtp_state=, socks=, ssh=, syslog=])) 1362692526.939084 MetaHookPre DrainEvents() 1362692526.939084 MetaHookPre QueueEvent(connection_established([id=[orig_h=141.142.228.5, orig_p=59856<...>/tcp], orig=[size=0, state=4, num_pkts=1, num_bytes_ip=64, flow_label=0, l2_addr=c8:bc:c8:96:d2:a0], resp=[size=0, state=4, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=00:10:db:88:d2:ef], start_time=1362692526.869344, duration=0.06974, service={}, history=Sh, uid=CXWv6p3arKYeMETxOg, tunnel=, vlan=, inner_vlan=, dpd=, conn=, extract_orig=F, extract_resp=F, thresholds=, dhcp=, dnp3=, dns=, dns_state=, ftp=, ftp_data_reuse=F, ssl=, http=, http_state=, irc=, krb=, modbus=, mysql=, radius=, rdp=, rfb=, sip=, sip_state=, snmp=, smtp=, smtp_state=, socks=, ssh=, syslog=])) 1362692526.939084 MetaHookPre UpdateNetworkTime(1362692526.939084) 1362692526.939084 | HookUpdateNetworkTime 1362692526.939084 +1362692526.939084 | HookCallFunction NetControl::catch_release_seen(141.142.228.5) +1362692526.939084 | HookCallFunction addr_to_subnet(141.142.228.5) 1362692526.939084 | HookCallFunction connection_established([id=[orig_h=141.142.228.5, orig_p=59856<...>/tcp], orig=[size=0, state=4, num_pkts=1, num_bytes_ip=64, flow_label=0, l2_addr=c8:bc:c8:96:d2:a0], resp=[size=0, state=4, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=00:10:db:88:d2:ef], start_time=1362692526.869344, duration=0.06974, service={}, history=Sh, uid=CXWv6p3arKYeMETxOg, tunnel=, vlan=, inner_vlan=, dpd=, conn=, extract_orig=F, extract_resp=F, thresholds=, dhcp=, dnp3=, dns=, dns_state=, ftp=, ftp_data_reuse=F, ssl=, http=, http_state=, irc=, krb=, modbus=, mysql=, radius=, rdp=, rfb=, sip=, sip_state=, snmp=, smtp=, smtp_state=, socks=, ssh=, syslog=]) 1362692526.939084 | HookDrainEvents 1362692526.939084 | HookQueueEvent connection_established([id=[orig_h=141.142.228.5, orig_p=59856<...>/tcp], orig=[size=0, state=4, num_pkts=1, num_bytes_ip=64, flow_label=0, l2_addr=c8:bc:c8:96:d2:a0], resp=[size=0, state=4, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=00:10:db:88:d2:ef], start_time=1362692526.869344, duration=0.06974, service={}, history=Sh, uid=CXWv6p3arKYeMETxOg, tunnel=, vlan=, inner_vlan=, dpd=, conn=, extract_orig=F, extract_resp=F, thresholds=, dhcp=, dnp3=, dns=, dns_state=, ftp=, ftp_data_reuse=F, ssl=, http=, http_state=, irc=, krb=, modbus=, mysql=, radius=, rdp=, rfb=, sip=, sip_state=, snmp=, smtp=, smtp_state=, socks=, ssh=, syslog=]) diff --git a/testing/btest/Baseline/scripts.policy.misc.dump-events/all-events-no-args.log b/testing/btest/Baseline/scripts.policy.misc.dump-events/all-events-no-args.log index 6b80273111..64cbb5f748 100644 --- a/testing/btest/Baseline/scripts.policy.misc.dump-events/all-events-no-args.log +++ b/testing/btest/Baseline/scripts.policy.misc.dump-events/all-events-no-args.log @@ -1,6 +1,6 @@ 0.000000 bro_init - 0.000000 filter_change_tracking 0.000000 NetControl::init + 0.000000 filter_change_tracking 1254722767.492060 ChecksumOffloading::check 1254722767.492060 filter_change_tracking 1254722767.492060 new_connection @@ -107,6 +107,7 @@ 1437831776.764391 connection_state_remove 1437831776.764391 filter_change_tracking 1437831776.764391 new_connection +1437831777.107399 partial_connection 1437831787.856895 new_connection 1437831787.861602 connection_established 1437831787.867142 smtp_reply @@ -152,7 +153,9 @@ 1437831787.905375 smtp_request 1437831787.914113 smtp_reply 1437831798.533593 new_connection +1437831798.533765 partial_connection 1437831799.262632 new_connection +1437831799.410135 partial_connection 1437831799.461152 new_connection 1437831799.610433 connection_established 1437831799.611764 ssl_extension_server_name @@ -206,10 +209,15 @@ 1437831800.045701 ssl_established 1437831800.217854 net_done 1437831800.217854 filter_change_tracking +1437831800.217854 connection_pending 1437831800.217854 connection_state_remove +1437831800.217854 connection_pending 1437831800.217854 connection_state_remove +1437831800.217854 connection_pending 1437831800.217854 connection_state_remove +1437831800.217854 connection_pending 1437831800.217854 connection_state_remove +1437831800.217854 connection_pending 1437831800.217854 connection_state_remove 1437831800.217854 bro_done 1437831800.217854 ChecksumOffloading::check diff --git a/testing/btest/Baseline/scripts.policy.misc.dump-events/all-events.log b/testing/btest/Baseline/scripts.policy.misc.dump-events/all-events.log index 445456bb3b..632f3aa7f7 100644 --- a/testing/btest/Baseline/scripts.policy.misc.dump-events/all-events.log +++ b/testing/btest/Baseline/scripts.policy.misc.dump-events/all-events.log @@ -1,6 +1,6 @@ 0.000000 bro_init - 0.000000 filter_change_tracking 0.000000 NetControl::init + 0.000000 filter_change_tracking 1254722767.492060 ChecksumOffloading::check 1254722767.492060 filter_change_tracking 1254722767.492060 new_connection @@ -504,6 +504,9 @@ 1437831776.764391 new_connection [0] c: connection = [id=[orig_h=192.168.133.100, orig_p=49285/tcp, resp_h=66.196.121.26, resp_p=5050/tcp], orig=[size=0, state=0, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=58:b0:35:86:54:8d], resp=[size=0, state=0, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=cc:b2:55:f4:62:92], start_time=1437831776.764391, duration=0.0, service={\x0a\x0a}, history=, uid=CRJuHdVW0XPVINV8a, tunnel=, vlan=, inner_vlan=, dpd=, conn=, extract_orig=F, extract_resp=F, thresholds=, dhcp=, dnp3=, dns=, dns_state=, ftp=, ftp_data_reuse=F, ssl=, http=, http_state=, irc=, krb=, modbus=, mysql=, radius=, rdp=, rfb=, sip=, sip_state=, snmp=, smtp=, smtp_state=, socks=, ssh=, syslog=] +1437831777.107399 partial_connection + [0] c: connection = [id=[orig_h=192.168.133.100, orig_p=49285/tcp, resp_h=66.196.121.26, resp_p=5050/tcp], orig=[size=41, state=3, num_pkts=1, num_bytes_ip=93, flow_label=0, l2_addr=58:b0:35:86:54:8d], resp=[size=0, state=3, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=cc:b2:55:f4:62:92], start_time=1437831776.764391, duration=0.343008, service={\x0a\x0a}, history=Da, uid=CRJuHdVW0XPVINV8a, tunnel=, vlan=, inner_vlan=, dpd=, conn=, extract_orig=F, extract_resp=F, thresholds=, dhcp=, dnp3=, dns=, dns_state=, ftp=, ftp_data_reuse=F, ssl=, http=, http_state=, irc=, krb=, modbus=, mysql=, radius=, rdp=, rfb=, sip=, sip_state=, snmp=, smtp=, smtp_state=, socks=, ssh=, syslog=] + 1437831787.856895 new_connection [0] c: connection = [id=[orig_h=192.168.133.100, orig_p=49648/tcp, resp_h=192.168.133.102, resp_p=25/tcp], orig=[size=0, state=0, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=58:b0:35:86:54:8d], resp=[size=0, state=0, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=00:08:ca:cc:ad:4c], start_time=1437831787.856895, duration=0.0, service={\x0a\x0a}, history=, uid=CPbrpk1qSsw6ESzHV4, tunnel=, vlan=, inner_vlan=, dpd=, conn=, extract_orig=F, extract_resp=F, thresholds=, dhcp=, dnp3=, dns=, dns_state=, ftp=, ftp_data_reuse=F, ssl=, http=, http_state=, irc=, krb=, modbus=, mysql=, radius=, rdp=, rfb=, sip=, sip_state=, snmp=, smtp=, smtp_state=, socks=, ssh=, syslog=] @@ -742,9 +745,15 @@ 1437831798.533593 new_connection [0] c: connection = [id=[orig_h=192.168.133.100, orig_p=49336/tcp, resp_h=74.125.71.189, resp_p=443/tcp], orig=[size=0, state=0, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=cc:b2:55:f4:62:92], resp=[size=0, state=0, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=58:b0:35:86:54:8d], start_time=1437831798.533593, duration=0.0, service={\x0a\x0a}, history=, uid=C6pKV8GSxOnSLghOa, tunnel=, vlan=, inner_vlan=, dpd=, conn=, extract_orig=F, extract_resp=F, thresholds=, dhcp=, dnp3=, dns=, dns_state=, ftp=, ftp_data_reuse=F, ssl=, http=, http_state=, irc=, krb=, modbus=, mysql=, radius=, rdp=, rfb=, sip=, sip_state=, snmp=, smtp=, smtp_state=, socks=, ssh=, syslog=] +1437831798.533765 partial_connection + [0] c: connection = [id=[orig_h=192.168.133.100, orig_p=49336/tcp, resp_h=74.125.71.189, resp_p=443/tcp], orig=[size=0, state=3, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=cc:b2:55:f4:62:92], resp=[size=85, state=3, num_pkts=3, num_bytes_ip=411, flow_label=0, l2_addr=58:b0:35:86:54:8d], start_time=1437831798.533593, duration=0.000172, service={\x0a\x0a}, history=dA, uid=C6pKV8GSxOnSLghOa, tunnel=, vlan=, inner_vlan=, dpd=, conn=, extract_orig=F, extract_resp=F, thresholds=, dhcp=, dnp3=, dns=, dns_state=, ftp=, ftp_data_reuse=F, ssl=, http=, http_state=, irc=, krb=, modbus=, mysql=, radius=, rdp=, rfb=, sip=, sip_state=, snmp=, smtp=, smtp_state=, socks=, ssh=, syslog=] + 1437831799.262632 new_connection [0] c: connection = [id=[orig_h=192.168.133.100, orig_p=49153/tcp, resp_h=17.172.238.21, resp_p=5223/tcp], orig=[size=0, state=0, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=58:b0:35:86:54:8d], resp=[size=0, state=0, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=cc:b2:55:f4:62:92], start_time=1437831799.262632, duration=0.0, service={\x0a\x0a}, history=, uid=CIPOse170MGiRM1Qf4, tunnel=, vlan=, inner_vlan=, dpd=, conn=, extract_orig=F, extract_resp=F, thresholds=, dhcp=, dnp3=, dns=, dns_state=, ftp=, ftp_data_reuse=F, ssl=, http=, http_state=, irc=, krb=, modbus=, mysql=, radius=, rdp=, rfb=, sip=, sip_state=, snmp=, smtp=, smtp_state=, socks=, ssh=, syslog=] +1437831799.410135 partial_connection + [0] c: connection = [id=[orig_h=192.168.133.100, orig_p=49153/tcp, resp_h=17.172.238.21, resp_p=5223/tcp], orig=[size=714, state=3, num_pkts=1, num_bytes_ip=766, flow_label=0, l2_addr=58:b0:35:86:54:8d], resp=[size=0, state=3, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=cc:b2:55:f4:62:92], start_time=1437831799.262632, duration=0.147503, service={\x0a\x0a}, history=Da, uid=CIPOse170MGiRM1Qf4, tunnel=, vlan=, inner_vlan=, dpd=, conn=, extract_orig=F, extract_resp=F, thresholds=, dhcp=, dnp3=, dns=, dns_state=, ftp=, ftp_data_reuse=F, ssl=, http=, http_state=, irc=, krb=, modbus=, mysql=, radius=, rdp=, rfb=, sip=, sip_state=, snmp=, smtp=, smtp_state=, socks=, ssh=, syslog=] + 1437831799.461152 new_connection [0] c: connection = [id=[orig_h=192.168.133.100, orig_p=49655/tcp, resp_h=17.167.150.73, resp_p=443/tcp], orig=[size=0, state=0, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=58:b0:35:86:54:8d], resp=[size=0, state=0, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=cc:b2:55:f4:62:92], start_time=1437831799.461152, duration=0.0, service={\x0a\x0a}, history=, uid=C7XEbhP654jzLoe3a, tunnel=, vlan=, inner_vlan=, dpd=, conn=, extract_orig=F, extract_resp=F, thresholds=, dhcp=, dnp3=, dns=, dns_state=, ftp=, ftp_data_reuse=F, ssl=, http=, http_state=, irc=, krb=, modbus=, mysql=, radius=, rdp=, rfb=, sip=, sip_state=, snmp=, smtp=, smtp_state=, socks=, ssh=, syslog=] @@ -985,18 +994,33 @@ [0] t: time = 1437831800.217854 1437831800.217854 filter_change_tracking +1437831800.217854 connection_pending + [0] c: connection = [id=[orig_h=192.168.133.100, orig_p=49648/tcp, resp_h=192.168.133.102, resp_p=25/tcp], orig=[size=969, state=4, num_pkts=17, num_bytes_ip=1865, flow_label=0, l2_addr=58:b0:35:86:54:8d], resp=[size=162, state=4, num_pkts=10, num_bytes_ip=690, flow_label=0, l2_addr=00:08:ca:cc:ad:4c], start_time=1437831787.856895, duration=0.05732, service={\x0aSMTP\x0a}, history=ShAdDa, uid=CPbrpk1qSsw6ESzHV4, tunnel=, vlan=, inner_vlan=, dpd=, conn=, extract_orig=F, extract_resp=F, thresholds=, dhcp=, dnp3=, dns=, dns_state=, ftp=, ftp_data_reuse=F, ssl=, http=, http_state=, irc=, krb=, modbus=, mysql=, radius=, rdp=, rfb=, sip=, sip_state=, snmp=, smtp=[ts=1437831787.914113, uid=CPbrpk1qSsw6ESzHV4, id=[orig_h=192.168.133.100, orig_p=49648/tcp, resp_h=192.168.133.102, resp_p=25/tcp], trans_depth=2, helo=[192.168.133.100], mailfrom=, rcptto=, date=, from=, to=, cc=, reply_to=, msg_id=, in_reply_to=, subject=, x_originating_ip=, first_received=, second_received=, last_reply=, path=[192.168.133.102, 192.168.133.100], user_agent=, tls=F, process_received_from=T, has_client_activity=F, entity=, fuids=[]], smtp_state=[helo=[192.168.133.100], messages_transferred=1, pending_messages=, mime_depth=1], socks=, ssh=, syslog=] + 1437831800.217854 connection_state_remove [0] c: connection = [id=[orig_h=192.168.133.100, orig_p=49648/tcp, resp_h=192.168.133.102, resp_p=25/tcp], orig=[size=969, state=4, num_pkts=17, num_bytes_ip=1865, flow_label=0, l2_addr=58:b0:35:86:54:8d], resp=[size=162, state=4, num_pkts=10, num_bytes_ip=690, flow_label=0, l2_addr=00:08:ca:cc:ad:4c], start_time=1437831787.856895, duration=0.05732, service={\x0aSMTP\x0a}, history=ShAdDa, uid=CPbrpk1qSsw6ESzHV4, tunnel=, vlan=, inner_vlan=, dpd=, conn=, extract_orig=F, extract_resp=F, thresholds=, dhcp=, dnp3=, dns=, dns_state=, ftp=, ftp_data_reuse=F, ssl=, http=, http_state=, irc=, krb=, modbus=, mysql=, radius=, rdp=, rfb=, sip=, sip_state=, snmp=, smtp=[ts=1437831787.914113, uid=CPbrpk1qSsw6ESzHV4, id=[orig_h=192.168.133.100, orig_p=49648/tcp, resp_h=192.168.133.102, resp_p=25/tcp], trans_depth=2, helo=[192.168.133.100], mailfrom=, rcptto=, date=, from=, to=, cc=, reply_to=, msg_id=, in_reply_to=, subject=, x_originating_ip=, first_received=, second_received=, last_reply=, path=[192.168.133.102, 192.168.133.100], user_agent=, tls=F, process_received_from=T, has_client_activity=F, entity=, fuids=[]], smtp_state=[helo=[192.168.133.100], messages_transferred=1, pending_messages=, mime_depth=1], socks=, ssh=, syslog=] +1437831800.217854 connection_pending + [0] c: connection = [id=[orig_h=192.168.133.100, orig_p=49153/tcp, resp_h=17.172.238.21, resp_p=5223/tcp], orig=[size=714, state=3, num_pkts=1, num_bytes_ip=766, flow_label=0, l2_addr=58:b0:35:86:54:8d], resp=[size=0, state=3, num_pkts=1, num_bytes_ip=52, flow_label=0, l2_addr=cc:b2:55:f4:62:92], start_time=1437831799.262632, duration=0.147503, service={\x0a\x0a}, history=Da, uid=CIPOse170MGiRM1Qf4, tunnel=, vlan=, inner_vlan=, dpd=, conn=, extract_orig=F, extract_resp=F, thresholds=, dhcp=, dnp3=, dns=, dns_state=, ftp=, ftp_data_reuse=F, ssl=, http=, http_state=, irc=, krb=, modbus=, mysql=, radius=, rdp=, rfb=, sip=, sip_state=, snmp=, smtp=, smtp_state=, socks=, ssh=, syslog=] + 1437831800.217854 connection_state_remove [0] c: connection = [id=[orig_h=192.168.133.100, orig_p=49153/tcp, resp_h=17.172.238.21, resp_p=5223/tcp], orig=[size=714, state=3, num_pkts=1, num_bytes_ip=766, flow_label=0, l2_addr=58:b0:35:86:54:8d], resp=[size=0, state=3, num_pkts=1, num_bytes_ip=52, flow_label=0, l2_addr=cc:b2:55:f4:62:92], start_time=1437831799.262632, duration=0.147503, service={\x0a\x0a}, history=Da, uid=CIPOse170MGiRM1Qf4, tunnel=, vlan=, inner_vlan=, dpd=, conn=, extract_orig=F, extract_resp=F, thresholds=, dhcp=, dnp3=, dns=, dns_state=, ftp=, ftp_data_reuse=F, ssl=, http=, http_state=, irc=, krb=, modbus=, mysql=, radius=, rdp=, rfb=, sip=, sip_state=, snmp=, smtp=, smtp_state=, socks=, ssh=, syslog=] -1437831800.217854 connection_state_remove +1437831800.217854 connection_pending [0] c: connection = [id=[orig_h=192.168.133.100, orig_p=49285/tcp, resp_h=66.196.121.26, resp_p=5050/tcp], orig=[size=41, state=3, num_pkts=1, num_bytes_ip=93, flow_label=0, l2_addr=58:b0:35:86:54:8d], resp=[size=0, state=3, num_pkts=1, num_bytes_ip=52, flow_label=0, l2_addr=cc:b2:55:f4:62:92], start_time=1437831776.764391, duration=0.343008, service={\x0a\x0a}, history=Da, uid=CRJuHdVW0XPVINV8a, tunnel=, vlan=, inner_vlan=, dpd=, conn=, extract_orig=F, extract_resp=F, thresholds=, dhcp=, dnp3=, dns=, dns_state=, ftp=, ftp_data_reuse=F, ssl=, http=, http_state=, irc=, krb=, modbus=, mysql=, radius=, rdp=, rfb=, sip=, sip_state=, snmp=, smtp=, smtp_state=, socks=, ssh=, syslog=] 1437831800.217854 connection_state_remove + [0] c: connection = [id=[orig_h=192.168.133.100, orig_p=49285/tcp, resp_h=66.196.121.26, resp_p=5050/tcp], orig=[size=41, state=3, num_pkts=1, num_bytes_ip=93, flow_label=0, l2_addr=58:b0:35:86:54:8d], resp=[size=0, state=3, num_pkts=1, num_bytes_ip=52, flow_label=0, l2_addr=cc:b2:55:f4:62:92], start_time=1437831776.764391, duration=0.343008, service={\x0a\x0a}, history=Da, uid=CRJuHdVW0XPVINV8a, tunnel=, vlan=, inner_vlan=, dpd=, conn=, extract_orig=F, extract_resp=F, thresholds=, dhcp=, dnp3=, dns=, dns_state=, ftp=, ftp_data_reuse=F, ssl=, http=, http_state=, irc=, krb=, modbus=, mysql=, radius=, rdp=, rfb=, sip=, sip_state=, snmp=, smtp=, smtp_state=, socks=, ssh=, syslog=] + +1437831800.217854 connection_pending [0] c: connection = [id=[orig_h=192.168.133.100, orig_p=49655/tcp, resp_h=17.167.150.73, resp_p=443/tcp], orig=[size=2249, state=4, num_pkts=15, num_bytes_ip=2873, flow_label=0, l2_addr=58:b0:35:86:54:8d], resp=[size=3653, state=4, num_pkts=13, num_bytes_ip=4185, flow_label=0, l2_addr=cc:b2:55:f4:62:92], start_time=1437831799.461152, duration=0.756702, service={\x0aSSL\x0a}, history=ShADda, uid=C7XEbhP654jzLoe3a, tunnel=, vlan=, inner_vlan=, dpd=, conn=, extract_orig=F, extract_resp=F, thresholds=, dhcp=, dnp3=, dns=, dns_state=, ftp=, ftp_data_reuse=F, ssl=[ts=1437831799.611764, uid=C7XEbhP654jzLoe3a, id=[orig_h=192.168.133.100, orig_p=49655/tcp, resp_h=17.167.150.73, resp_p=443/tcp], version=TLSv12, cipher=TLS_RSA_WITH_RC4_128_MD5, curve=, server_name=p31-keyvalueservice.icloud.com, session_id=, resumed=F, client_ticket_empty_session_seen=F, client_key_exchange_seen=T, last_alert=, next_protocol=, analyzer_id=, established=T, logged=T, delay_tokens=, cert_chain=[[ts=1437831799.764576, fuid=F1vce92FT1oRjKI328, tx_hosts={\x0a\x0917.167.150.73\x0a}, rx_hosts={\x0a\x09192.168.133.100\x0a}, conn_uids={\x0aC7XEbhP654jzLoe3a\x0a}, source=SSL, depth=0, analyzers={\x0aX509,\x0aMD5,\x0aSHA1\x0a}, mime_type=application/pkix-cert, filename=, duration=0 secs, local_orig=, is_orig=F, seen_bytes=1406, total_bytes=, missing_bytes=0, overflow_bytes=0, timedout=F, parent_fuid=, md5=, sha1=f5ccb1a724133607548b00d8eb402efca3076d58, sha256=, x509=[ts=1437831799.764576, id=F1vce92FT1oRjKI328, certificate=[version=3, serial=053FCE9BA6805B00, subject=C=US,ST=California,O=Apple Inc.,OU=management:idms.group.506364,CN=*.icloud.com, issuer=C=US,O=Apple Inc.,OU=Certification Authority,CN=Apple IST CA 2 - G1, cn=*.icloud.com, not_valid_before=1424184331.0, not_valid_after=1489848331.0, key_alg=rsaEncryption, sig_alg=sha256WithRSAEncryption, key_type=rsa, key_length=2048, exponent=65537, curve=], handle=, extensions=[[name=Authority Information Access, short_name=authorityInfoAccess, oid=1.3.6.1.5.5.7.1.1, critical=F, value=OCSP - URI:http://ocsp.apple.com/ocsp04-appleistca2g101\x0a], [name=X509v3 Subject Key Identifier, short_name=subjectKeyIdentifier, oid=2.5.29.14, critical=F, value=8E:51:A1:0E:0A:9B:1C:04:F7:59:D3:69:2E:23:16:91:0E:AD:06:FB], [name=X509v3 Basic Constraints, short_name=basicConstraints, oid=2.5.29.19, critical=T, value=CA:FALSE], [name=X509v3 Authority Key Identifier, short_name=authorityKeyIdentifier, oid=2.5.29.35, critical=F, value=keyid:D8:7A:94:44:7C:90:70:90:16:9E:DD:17:9C:01:44:03:86:D6:2A:29\x0a], [name=X509v3 Certificate Policies, short_name=certificatePolicies, oid=2.5.29.32, critical=F, value=Policy: 1.2.840.113635.100.5.11.4\x0a User Notice:\x0a Explicit Text: Reliance on this certificate by any party assumes acceptance of any applicable terms and conditions of use and/or certification practice statements.\x0a CPS: http://www.apple.com/certificateauthority/rpa\x0a], [name=X509v3 CRL Distribution Points, short_name=crlDistributionPoints, oid=2.5.29.31, critical=F, value=\x0aFull Name:\x0a URI:http://crl.apple.com/appleistca2g1.crl\x0a], [name=X509v3 Key Usage, short_name=keyUsage, oid=2.5.29.15, critical=T, value=Digital Signature, Key Encipherment], [name=X509v3 Extended Key Usage, short_name=extendedKeyUsage, oid=2.5.29.37, critical=F, value=TLS Web Server Authentication, TLS Web Client Authentication], [name=X509v3 Subject Alternative Name, short_name=subjectAltName, oid=2.5.29.17, critical=F, value=DNS:*.icloud.com]], san=[dns=[*.icloud.com], uri=, email=, ip=, other_fields=F], basic_constraints=[ca=F, path_len=]], extracted=], [ts=1437831799.764576, fuid=Fxp53s3wA5G3zdEJg8, tx_hosts={\x0a\x0917.167.150.73\x0a}, rx_hosts={\x0a\x09192.168.133.100\x0a}, conn_uids={\x0aC7XEbhP654jzLoe3a\x0a}, source=SSL, depth=0, analyzers={\x0aX509,\x0aMD5,\x0aSHA1\x0a}, mime_type=application/pkix-cert, filename=, duration=0 secs, local_orig=, is_orig=F, seen_bytes=1092, total_bytes=, missing_bytes=0, overflow_bytes=0, timedout=F, parent_fuid=, md5=, sha1=8e8321ca08b08e3726fe1d82996884eeb5f0d655, sha256=, x509=[ts=1437831799.764576, id=Fxp53s3wA5G3zdEJg8, certificate=[version=3, serial=023A74, subject=C=US,O=Apple Inc.,OU=Certification Authority,CN=Apple IST CA 2 - G1, issuer=CN=GeoTrust Global CA,O=GeoTrust Inc.,C=US, cn=Apple IST CA 2 - G1, not_valid_before=1402933322.0, not_valid_after=1653061322.0, key_alg=rsaEncryption, sig_alg=sha256WithRSAEncryption, key_type=rsa, key_length=2048, exponent=65537, curve=], handle=, extensions=[[name=X509v3 Authority Key Identifier, short_name=authorityKeyIdentifier, oid=2.5.29.35, critical=F, value=keyid:C0:7A:98:68:8D:89:FB:AB:05:64:0C:11:7D:AA:7D:65:B8:CA:CC:4E\x0a], [name=X509v3 Subject Key Identifier, short_name=subjectKeyIdentifier, oid=2.5.29.14, critical=F, value=D8:7A:94:44:7C:90:70:90:16:9E:DD:17:9C:01:44:03:86:D6:2A:29], [name=X509v3 Basic Constraints, short_name=basicConstraints, oid=2.5.29.19, critical=T, value=CA:TRUE, pathlen:0], [name=X509v3 Key Usage, short_name=keyUsage, oid=2.5.29.15, critical=T, value=Certificate Sign, CRL Sign], [name=X509v3 CRL Distribution Points, short_name=crlDistributionPoints, oid=2.5.29.31, critical=F, value=\x0aFull Name:\x0a URI:http://g.symcb.com/crls/gtglobal.crl\x0a], [name=Authority Information Access, short_name=authorityInfoAccess, oid=1.3.6.1.5.5.7.1.1, critical=F, value=OCSP - URI:http://g.symcd.com\x0a], [name=X509v3 Certificate Policies, short_name=certificatePolicies, oid=2.5.29.32, critical=F, value=Policy: 2.16.840.1.113733.1.7.54\x0a CPS: http://www.geotrust.com/resources/cps\x0a]], san=, basic_constraints=[ca=T, path_len=0]], extracted=]], cert_chain_fuids=[F1vce92FT1oRjKI328, Fxp53s3wA5G3zdEJg8], client_cert_chain=[], client_cert_chain_fuids=[], subject=C=US,ST=California,O=Apple Inc.,OU=management:idms.group.506364,CN=*.icloud.com, issuer=C=US,O=Apple Inc.,OU=Certification Authority,CN=Apple IST CA 2 - G1, client_subject=, client_issuer=, server_depth=0, client_depth=0], http=, http_state=, irc=, krb=, modbus=, mysql=, radius=, rdp=, rfb=, sip=, sip_state=, snmp=, smtp=, smtp_state=, socks=, ssh=, syslog=] +1437831800.217854 connection_state_remove + [0] c: connection = [id=[orig_h=192.168.133.100, orig_p=49655/tcp, resp_h=17.167.150.73, resp_p=443/tcp], orig=[size=2249, state=4, num_pkts=15, num_bytes_ip=2873, flow_label=0, l2_addr=58:b0:35:86:54:8d], resp=[size=3653, state=4, num_pkts=13, num_bytes_ip=4185, flow_label=0, l2_addr=cc:b2:55:f4:62:92], start_time=1437831799.461152, duration=0.756702, service={\x0aSSL\x0a}, history=ShADda, uid=C7XEbhP654jzLoe3a, tunnel=, vlan=, inner_vlan=, dpd=, conn=, extract_orig=F, extract_resp=F, thresholds=, dhcp=, dnp3=, dns=, dns_state=, ftp=, ftp_data_reuse=F, ssl=[ts=1437831799.611764, uid=C7XEbhP654jzLoe3a, id=[orig_h=192.168.133.100, orig_p=49655/tcp, resp_h=17.167.150.73, resp_p=443/tcp], version=TLSv12, cipher=TLS_RSA_WITH_RC4_128_MD5, curve=, server_name=p31-keyvalueservice.icloud.com, session_id=, resumed=F, client_ticket_empty_session_seen=F, client_key_exchange_seen=T, last_alert=, next_protocol=, analyzer_id=, established=T, logged=T, delay_tokens=, cert_chain=[[ts=1437831799.764576, fuid=F1vce92FT1oRjKI328, tx_hosts={\x0a\x0917.167.150.73\x0a}, rx_hosts={\x0a\x09192.168.133.100\x0a}, conn_uids={\x0aC7XEbhP654jzLoe3a\x0a}, source=SSL, depth=0, analyzers={\x0aX509,\x0aMD5,\x0aSHA1\x0a}, mime_type=application/pkix-cert, filename=, duration=0 secs, local_orig=, is_orig=F, seen_bytes=1406, total_bytes=, missing_bytes=0, overflow_bytes=0, timedout=F, parent_fuid=, md5=, sha1=f5ccb1a724133607548b00d8eb402efca3076d58, sha256=, x509=[ts=1437831799.764576, id=F1vce92FT1oRjKI328, certificate=[version=3, serial=053FCE9BA6805B00, subject=C=US,ST=California,O=Apple Inc.,OU=management:idms.group.506364,CN=*.icloud.com, issuer=C=US,O=Apple Inc.,OU=Certification Authority,CN=Apple IST CA 2 - G1, cn=*.icloud.com, not_valid_before=1424184331.0, not_valid_after=1489848331.0, key_alg=rsaEncryption, sig_alg=sha256WithRSAEncryption, key_type=rsa, key_length=2048, exponent=65537, curve=], handle=, extensions=[[name=Authority Information Access, short_name=authorityInfoAccess, oid=1.3.6.1.5.5.7.1.1, critical=F, value=OCSP - URI:http://ocsp.apple.com/ocsp04-appleistca2g101\x0a], [name=X509v3 Subject Key Identifier, short_name=subjectKeyIdentifier, oid=2.5.29.14, critical=F, value=8E:51:A1:0E:0A:9B:1C:04:F7:59:D3:69:2E:23:16:91:0E:AD:06:FB], [name=X509v3 Basic Constraints, short_name=basicConstraints, oid=2.5.29.19, critical=T, value=CA:FALSE], [name=X509v3 Authority Key Identifier, short_name=authorityKeyIdentifier, oid=2.5.29.35, critical=F, value=keyid:D8:7A:94:44:7C:90:70:90:16:9E:DD:17:9C:01:44:03:86:D6:2A:29\x0a], [name=X509v3 Certificate Policies, short_name=certificatePolicies, oid=2.5.29.32, critical=F, value=Policy: 1.2.840.113635.100.5.11.4\x0a User Notice:\x0a Explicit Text: Reliance on this certificate by any party assumes acceptance of any applicable terms and conditions of use and/or certification practice statements.\x0a CPS: http://www.apple.com/certificateauthority/rpa\x0a], [name=X509v3 CRL Distribution Points, short_name=crlDistributionPoints, oid=2.5.29.31, critical=F, value=\x0aFull Name:\x0a URI:http://crl.apple.com/appleistca2g1.crl\x0a], [name=X509v3 Key Usage, short_name=keyUsage, oid=2.5.29.15, critical=T, value=Digital Signature, Key Encipherment], [name=X509v3 Extended Key Usage, short_name=extendedKeyUsage, oid=2.5.29.37, critical=F, value=TLS Web Server Authentication, TLS Web Client Authentication], [name=X509v3 Subject Alternative Name, short_name=subjectAltName, oid=2.5.29.17, critical=F, value=DNS:*.icloud.com]], san=[dns=[*.icloud.com], uri=, email=, ip=, other_fields=F], basic_constraints=[ca=F, path_len=]], extracted=], [ts=1437831799.764576, fuid=Fxp53s3wA5G3zdEJg8, tx_hosts={\x0a\x0917.167.150.73\x0a}, rx_hosts={\x0a\x09192.168.133.100\x0a}, conn_uids={\x0aC7XEbhP654jzLoe3a\x0a}, source=SSL, depth=0, analyzers={\x0aX509,\x0aMD5,\x0aSHA1\x0a}, mime_type=application/pkix-cert, filename=, duration=0 secs, local_orig=, is_orig=F, seen_bytes=1092, total_bytes=, missing_bytes=0, overflow_bytes=0, timedout=F, parent_fuid=, md5=, sha1=8e8321ca08b08e3726fe1d82996884eeb5f0d655, sha256=, x509=[ts=1437831799.764576, id=Fxp53s3wA5G3zdEJg8, certificate=[version=3, serial=023A74, subject=C=US,O=Apple Inc.,OU=Certification Authority,CN=Apple IST CA 2 - G1, issuer=CN=GeoTrust Global CA,O=GeoTrust Inc.,C=US, cn=Apple IST CA 2 - G1, not_valid_before=1402933322.0, not_valid_after=1653061322.0, key_alg=rsaEncryption, sig_alg=sha256WithRSAEncryption, key_type=rsa, key_length=2048, exponent=65537, curve=], handle=, extensions=[[name=X509v3 Authority Key Identifier, short_name=authorityKeyIdentifier, oid=2.5.29.35, critical=F, value=keyid:C0:7A:98:68:8D:89:FB:AB:05:64:0C:11:7D:AA:7D:65:B8:CA:CC:4E\x0a], [name=X509v3 Subject Key Identifier, short_name=subjectKeyIdentifier, oid=2.5.29.14, critical=F, value=D8:7A:94:44:7C:90:70:90:16:9E:DD:17:9C:01:44:03:86:D6:2A:29], [name=X509v3 Basic Constraints, short_name=basicConstraints, oid=2.5.29.19, critical=T, value=CA:TRUE, pathlen:0], [name=X509v3 Key Usage, short_name=keyUsage, oid=2.5.29.15, critical=T, value=Certificate Sign, CRL Sign], [name=X509v3 CRL Distribution Points, short_name=crlDistributionPoints, oid=2.5.29.31, critical=F, value=\x0aFull Name:\x0a URI:http://g.symcb.com/crls/gtglobal.crl\x0a], [name=Authority Information Access, short_name=authorityInfoAccess, oid=1.3.6.1.5.5.7.1.1, critical=F, value=OCSP - URI:http://g.symcd.com\x0a], [name=X509v3 Certificate Policies, short_name=certificatePolicies, oid=2.5.29.32, critical=F, value=Policy: 2.16.840.1.113733.1.7.54\x0a CPS: http://www.geotrust.com/resources/cps\x0a]], san=, basic_constraints=[ca=T, path_len=0]], extracted=]], cert_chain_fuids=[F1vce92FT1oRjKI328, Fxp53s3wA5G3zdEJg8], client_cert_chain=[], client_cert_chain_fuids=[], subject=C=US,ST=California,O=Apple Inc.,OU=management:idms.group.506364,CN=*.icloud.com, issuer=C=US,O=Apple Inc.,OU=Certification Authority,CN=Apple IST CA 2 - G1, client_subject=, client_issuer=, server_depth=0, client_depth=0], http=, http_state=, irc=, krb=, modbus=, mysql=, radius=, rdp=, rfb=, sip=, sip_state=, snmp=, smtp=, smtp_state=, socks=, ssh=, syslog=] + +1437831800.217854 connection_pending + [0] c: connection = [id=[orig_h=192.168.133.100, orig_p=49336/tcp, resp_h=74.125.71.189, resp_p=443/tcp], orig=[size=0, state=3, num_pkts=3, num_bytes_ip=156, flow_label=0, l2_addr=cc:b2:55:f4:62:92], resp=[size=85, state=3, num_pkts=3, num_bytes_ip=411, flow_label=0, l2_addr=58:b0:35:86:54:8d], start_time=1437831798.533593, duration=0.000221, service={\x0a\x0a}, history=dA, uid=C6pKV8GSxOnSLghOa, tunnel=, vlan=, inner_vlan=, dpd=, conn=, extract_orig=F, extract_resp=F, thresholds=, dhcp=, dnp3=, dns=, dns_state=, ftp=, ftp_data_reuse=F, ssl=, http=, http_state=, irc=, krb=, modbus=, mysql=, radius=, rdp=, rfb=, sip=, sip_state=, snmp=, smtp=, smtp_state=, socks=, ssh=, syslog=] + 1437831800.217854 connection_state_remove [0] c: connection = [id=[orig_h=192.168.133.100, orig_p=49336/tcp, resp_h=74.125.71.189, resp_p=443/tcp], orig=[size=0, state=3, num_pkts=3, num_bytes_ip=156, flow_label=0, l2_addr=cc:b2:55:f4:62:92], resp=[size=85, state=3, num_pkts=3, num_bytes_ip=411, flow_label=0, l2_addr=58:b0:35:86:54:8d], start_time=1437831798.533593, duration=0.000221, service={\x0a\x0a}, history=dA, uid=C6pKV8GSxOnSLghOa, tunnel=, vlan=, inner_vlan=, dpd=, conn=, extract_orig=F, extract_resp=F, thresholds=, dhcp=, dnp3=, dns=, dns_state=, ftp=, ftp_data_reuse=F, ssl=, http=, http_state=, irc=, krb=, modbus=, mysql=, radius=, rdp=, rfb=, sip=, sip_state=, snmp=, smtp=, smtp_state=, socks=, ssh=, syslog=] diff --git a/testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-1-drop-with-debug_bro.btest b/testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-1-drop-with-debug_bro.btest new file mode 100644 index 0000000000..b451d5aa4f --- /dev/null +++ b/testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-1-drop-with-debug_bro.btest @@ -0,0 +1,14 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +netcontrol-1-drop-with-debug.bro + +event NetControl::init() + { + local debug_plugin = NetControl::create_debug(T); + NetControl::activate(debug_plugin, 0); + } + +event connection_established(c: connection) + { + NetControl::drop_connection(c$id, 20 secs); + } diff --git a/testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-10-use-skeleton_bro.btest b/testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-10-use-skeleton_bro.btest new file mode 100644 index 0000000000..331afbc80d --- /dev/null +++ b/testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-10-use-skeleton_bro.btest @@ -0,0 +1,14 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +netcontrol-10-use-skeleton.bro + +event NetControl::init() + { + local skeleton_plugin = NetControl::create_skeleton(""); + NetControl::activate(skeleton_plugin, 0); + } + +event connection_established(c: connection) + { + NetControl::drop_connection(c$id, 20 secs); + } diff --git a/testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-2-ssh-guesser_bro.btest b/testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-2-ssh-guesser_bro.btest new file mode 100644 index 0000000000..87c8cdda7a --- /dev/null +++ b/testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-2-ssh-guesser_bro.btest @@ -0,0 +1,20 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +netcontrol-2-ssh-guesser.bro + + +@load protocols/ssh/detect-bruteforcing + +redef SSH::password_guesses_limit=10; + +event NetControl::init() + { + local debug_plugin = NetControl::create_debug(T); + NetControl::activate(debug_plugin, 0); + } + +hook Notice::policy(n: Notice::Info) + { + if ( n$note == SSH::Password_Guessing ) + NetControl::drop_address(n$src, 60min); + } diff --git a/testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-3-ssh-guesser_bro.btest b/testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-3-ssh-guesser_bro.btest new file mode 100644 index 0000000000..228856f00a --- /dev/null +++ b/testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-3-ssh-guesser_bro.btest @@ -0,0 +1,20 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +netcontrol-3-ssh-guesser.bro + + +@load protocols/ssh/detect-bruteforcing + +redef SSH::password_guesses_limit=10; + +event NetControl::init() + { + local debug_plugin = NetControl::create_debug(T); + NetControl::activate(debug_plugin, 0); + } + +hook Notice::policy(n: Notice::Info) + { + if ( n$note == SSH::Password_Guessing ) + add n$actions[Notice::ACTION_DROP]; + } diff --git a/testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-4-drop_bro.btest b/testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-4-drop_bro.btest new file mode 100644 index 0000000000..e7b15fd91b --- /dev/null +++ b/testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-4-drop_bro.btest @@ -0,0 +1,30 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +netcontrol-4-drop.bro + +function our_drop_connection(c: conn_id, t: interval) + { + # As a first step, create the NetControl::Entity that we want to block + local e = NetControl::Entity($ty=NetControl::CONNECTION, $conn=c); + # Then, use the entity to create the rule to drop the entity in the forward path + local r = NetControl::Rule($ty=NetControl::DROP, + $target=NetControl::FORWARD, $entity=e, $expire=t); + + # Add the rule + local id = NetControl::add_rule(r); + + if ( id == "" ) + print "Error while dropping"; + } + +event NetControl::init() + { + local debug_plugin = NetControl::create_debug(T); + NetControl::activate(debug_plugin, 0); + } + +event connection_established(c: connection) + { + our_drop_connection(c$id, 20 secs); + } + diff --git a/testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-5-hook_bro.btest b/testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-5-hook_bro.btest new file mode 100644 index 0000000000..d27e3f9a6a --- /dev/null +++ b/testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-5-hook_bro.btest @@ -0,0 +1,26 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +netcontrol-5-hook.bro + +hook NetControl::rule_policy(r: NetControl::Rule) + { + if ( r$ty == NetControl::DROP && + r$entity$ty == NetControl::CONNECTION && + r$entity$conn$orig_h in 192.168.0.0/16 ) + { + print "Ignored connection from", r$entity$conn$orig_h; + break; + } + } + +event NetControl::init() + { + local debug_plugin = NetControl::create_debug(T); + NetControl::activate(debug_plugin, 0); + } + +event connection_established(c: connection) + { + NetControl::drop_connection(c$id, 20 secs); + } + diff --git a/testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-6-find_bro.btest b/testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-6-find_bro.btest new file mode 100644 index 0000000000..bcc5199590 --- /dev/null +++ b/testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-6-find_bro.btest @@ -0,0 +1,21 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +netcontrol-6-find.bro + +event NetControl::init() + { + local netcontrol_debug = NetControl::create_debug(T); + NetControl::activate(netcontrol_debug, 0); + } + +event connection_established(c: connection) + { + if ( |NetControl::find_rules_addr(c$id$orig_h)| > 0 ) + { + print "Rule already exists"; + return; + } + + NetControl::drop_connection(c$id, 20 secs); + print "Rule added"; + } diff --git a/testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-7-catch-release_bro.btest b/testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-7-catch-release_bro.btest new file mode 100644 index 0000000000..aa10d8cc01 --- /dev/null +++ b/testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-7-catch-release_bro.btest @@ -0,0 +1,14 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +netcontrol-7-catch-release.bro + +event NetControl::init() + { + local debug_plugin = NetControl::create_debug(T); + NetControl::activate(debug_plugin, 0); + } + +event connection_established(c: connection) + { + NetControl::drop_address_catch_release(c$id$orig_h); + } diff --git a/testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-8-multiple_bro.btest b/testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-8-multiple_bro.btest new file mode 100644 index 0000000000..f9bac69f44 --- /dev/null +++ b/testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-8-multiple_bro.btest @@ -0,0 +1,33 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +netcontrol-8-multiple.bro + +function our_openflow_check(p: NetControl::PluginState, r: NetControl::Rule): bool + { + if ( r$ty == NetControl::DROP && + r$entity$ty == NetControl::ADDRESS && + subnet_width(r$entity$ip) == 32 && + subnet_to_addr(r$entity$ip) in 192.168.17.0/24 ) + return F; + + return T; + } + +event NetControl::init() + { + # Add debug plugin with low priority + local debug_plugin = NetControl::create_debug(T); + NetControl::activate(debug_plugin, 0); + + # Instantiate OpenFlow debug plugin with higher priority + local of_controller = OpenFlow::log_new(42); + local netcontrol_of = NetControl::create_openflow(of_controller, [$check_pred=our_openflow_check]); + NetControl::activate(netcontrol_of, 10); + } + +event NetControl::init_done() + { + NetControl::drop_address(10.0.0.1, 1min); + NetControl::drop_address(192.168.17.2, 1min); + NetControl::drop_address(192.168.18.2, 1min); + } diff --git a/testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-9-skeleton_bro.btest b/testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-9-skeleton_bro.btest new file mode 100644 index 0000000000..dc23f832dd --- /dev/null +++ b/testing/btest/doc/sphinx/include-doc_frameworks_netcontrol-9-skeleton_bro.btest @@ -0,0 +1,43 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +netcontrol-9-skeleton.bro + +module NetControl; + +export { + ## Instantiates the plugin. + global create_skeleton: function(argument: string) : PluginState; +} + +function skeleton_name(p: PluginState) : string + { + return "NetControl skeleton plugin"; + } + +function skeleton_add_rule_fun(p: PluginState, r: Rule) : bool + { + print "add", r; + event NetControl::rule_added(r, p); + return T; + } + + function skeleton_remove_rule_fun(p: PluginState, r: Rule) : bool + { + print "remove", r; + event NetControl::rule_removed(r, p); + return T; + } + +global skeleton_plugin = Plugin( + $name = skeleton_name, + $can_expire = F, + $add_rule = skeleton_add_rule_fun, + $remove_rule = skeleton_remove_rule_fun + ); + +function create_skeleton(argument: string) : PluginState + { + local p = PluginState($plugin=skeleton_plugin); + + return p; + } diff --git a/testing/btest/doc/sphinx/netcontrol-1-drop-with-debug.bro.btest b/testing/btest/doc/sphinx/netcontrol-1-drop-with-debug.bro.btest new file mode 100644 index 0000000000..ca5a6aec02 --- /dev/null +++ b/testing/btest/doc/sphinx/netcontrol-1-drop-with-debug.bro.btest @@ -0,0 +1,2 @@ +@TEST-EXEC: btest-rst-cmd bro -C -r ${TRACES}/tls/ecdhe.pcap ${DOC_ROOT}/frameworks/netcontrol-1-drop-with-debug.bro +@TEST-EXEC: btest-rst-cmd cat netcontrol.log diff --git a/testing/btest/doc/sphinx/netcontrol-1-drop-with-debug.bro.btest#2 b/testing/btest/doc/sphinx/netcontrol-1-drop-with-debug.bro.btest#2 new file mode 100644 index 0000000000..03d4fe15f4 --- /dev/null +++ b/testing/btest/doc/sphinx/netcontrol-1-drop-with-debug.bro.btest#2 @@ -0,0 +1 @@ +@TEST-EXEC: btest-rst-cmd cat netcontrol_drop.log diff --git a/testing/btest/doc/sphinx/netcontrol-2-ssh-guesser.bro.btest b/testing/btest/doc/sphinx/netcontrol-2-ssh-guesser.bro.btest new file mode 100644 index 0000000000..76b3ef2568 --- /dev/null +++ b/testing/btest/doc/sphinx/netcontrol-2-ssh-guesser.bro.btest @@ -0,0 +1,2 @@ +@TEST-EXEC: btest-rst-cmd bro -C -r ${TRACES}/ssh/sshguess.pcap ${DOC_ROOT}/frameworks/netcontrol-2-ssh-guesser.bro +@TEST-EXEC: btest-rst-cmd cat netcontrol.log diff --git a/testing/btest/doc/sphinx/netcontrol-3-ssh-guesser.bro.btest b/testing/btest/doc/sphinx/netcontrol-3-ssh-guesser.bro.btest new file mode 100644 index 0000000000..4a8b749f0f --- /dev/null +++ b/testing/btest/doc/sphinx/netcontrol-3-ssh-guesser.bro.btest @@ -0,0 +1,2 @@ +@TEST-EXEC: btest-rst-cmd bro -C -r ${TRACES}/ssh/sshguess.pcap ${DOC_ROOT}/frameworks/netcontrol-3-ssh-guesser.bro +@TEST-EXEC: btest-rst-cmd cat netcontrol.log diff --git a/testing/btest/doc/sphinx/netcontrol-3-ssh-guesser.bro.btest#2 b/testing/btest/doc/sphinx/netcontrol-3-ssh-guesser.bro.btest#2 new file mode 100644 index 0000000000..8447c8cf90 --- /dev/null +++ b/testing/btest/doc/sphinx/netcontrol-3-ssh-guesser.bro.btest#2 @@ -0,0 +1 @@ +@TEST-EXEC: btest-rst-cmd cat notice.log diff --git a/testing/btest/doc/sphinx/netcontrol-4-drop.bro.btest b/testing/btest/doc/sphinx/netcontrol-4-drop.bro.btest new file mode 100644 index 0000000000..44808d18a4 --- /dev/null +++ b/testing/btest/doc/sphinx/netcontrol-4-drop.bro.btest @@ -0,0 +1,2 @@ +@TEST-EXEC: btest-rst-cmd bro -C -r ${TRACES}/tls/ecdhe.pcap ${DOC_ROOT}/frameworks/netcontrol-4-drop.bro +@TEST-EXEC: btest-rst-cmd cat netcontrol.log diff --git a/testing/btest/doc/sphinx/netcontrol-5-hook.bro.btest b/testing/btest/doc/sphinx/netcontrol-5-hook.bro.btest new file mode 100644 index 0000000000..d2d7ab4d28 --- /dev/null +++ b/testing/btest/doc/sphinx/netcontrol-5-hook.bro.btest @@ -0,0 +1 @@ +@TEST-EXEC: btest-rst-cmd bro -C -r ${TRACES}/tls/ecdhe.pcap ${DOC_ROOT}/frameworks/netcontrol-5-hook.bro diff --git a/testing/btest/doc/sphinx/netcontrol-6-find.bro.btest b/testing/btest/doc/sphinx/netcontrol-6-find.bro.btest new file mode 100644 index 0000000000..dd8abab8f3 --- /dev/null +++ b/testing/btest/doc/sphinx/netcontrol-6-find.bro.btest @@ -0,0 +1 @@ +@TEST-EXEC: btest-rst-cmd bro -C -r ${TRACES}/tls/google-duplicate.trace ${DOC_ROOT}/frameworks/netcontrol-6-find.bro diff --git a/testing/btest/doc/sphinx/netcontrol-7-catch-release.bro.btest b/testing/btest/doc/sphinx/netcontrol-7-catch-release.bro.btest new file mode 100644 index 0000000000..ec49c2d2ba --- /dev/null +++ b/testing/btest/doc/sphinx/netcontrol-7-catch-release.bro.btest @@ -0,0 +1 @@ +@TEST-EXEC: btest-rst-cmd bro -C -r ${TRACES}/tls/ecdhe.pcap ${DOC_ROOT}/frameworks/netcontrol-7-catch-release.bro diff --git a/testing/btest/doc/sphinx/netcontrol-7-catch-release.bro.btest#2 b/testing/btest/doc/sphinx/netcontrol-7-catch-release.bro.btest#2 new file mode 100644 index 0000000000..72a79f9639 --- /dev/null +++ b/testing/btest/doc/sphinx/netcontrol-7-catch-release.bro.btest#2 @@ -0,0 +1 @@ +@TEST-EXEC: btest-rst-cmd cat netcontrol_catch_release.log diff --git a/testing/btest/doc/sphinx/netcontrol-8-multiple.bro.btest b/testing/btest/doc/sphinx/netcontrol-8-multiple.bro.btest new file mode 100644 index 0000000000..790bac070d --- /dev/null +++ b/testing/btest/doc/sphinx/netcontrol-8-multiple.bro.btest @@ -0,0 +1 @@ +@TEST-EXEC: btest-rst-cmd bro ${DOC_ROOT}/frameworks/netcontrol-8-multiple.bro diff --git a/testing/btest/doc/sphinx/netcontrol-8-multiple.bro.btest#2 b/testing/btest/doc/sphinx/netcontrol-8-multiple.bro.btest#2 new file mode 100644 index 0000000000..24ef5ee2f9 --- /dev/null +++ b/testing/btest/doc/sphinx/netcontrol-8-multiple.bro.btest#2 @@ -0,0 +1 @@ +@TEST-EXEC: btest-rst-cmd cat netcontrol.log diff --git a/testing/btest/doc/sphinx/netcontrol-8-multiple.bro.btest#3 b/testing/btest/doc/sphinx/netcontrol-8-multiple.bro.btest#3 new file mode 100644 index 0000000000..ad47aa86bf --- /dev/null +++ b/testing/btest/doc/sphinx/netcontrol-8-multiple.bro.btest#3 @@ -0,0 +1 @@ +@TEST-EXEC: btest-rst-cmd cat openflow.log diff --git a/testing/btest/doc/sphinx/netcontrol-8-multiple.bro.btest#4 b/testing/btest/doc/sphinx/netcontrol-8-multiple.bro.btest#4 new file mode 100644 index 0000000000..76b34fa474 --- /dev/null +++ b/testing/btest/doc/sphinx/netcontrol-8-multiple.bro.btest#4 @@ -0,0 +1 @@ +@TEST-EXEC: btest-rst-cmd bro -C -r ${TRACES}/tls/ecdhe.pcap ${DOC_ROOT}/frameworks/netcontrol-9-skeleton.bro ${DOC_ROOT}/frameworks/netcontrol-10-use-skeleton.bro diff --git a/testing/btest/doc/sphinx/netcontrol-9-skeleton.bro.btest b/testing/btest/doc/sphinx/netcontrol-9-skeleton.bro.btest new file mode 100644 index 0000000000..76b34fa474 --- /dev/null +++ b/testing/btest/doc/sphinx/netcontrol-9-skeleton.bro.btest @@ -0,0 +1 @@ +@TEST-EXEC: btest-rst-cmd bro -C -r ${TRACES}/tls/ecdhe.pcap ${DOC_ROOT}/frameworks/netcontrol-9-skeleton.bro ${DOC_ROOT}/frameworks/netcontrol-10-use-skeleton.bro From 743d4672bd2dd4e1cae45dc35a88f436e692e828 Mon Sep 17 00:00:00 2001 From: Johanna Amann Date: Thu, 23 Jun 2016 13:07:31 -0700 Subject: [PATCH 13/13] SMTP does not need to pull in the notice framework. This caused test baseline changes in one of the test: notice now ties in netcontrol due to ACTION_DROP. Catch and release uses the new_connection event, which was not before triggered and can cause uids to be generated for connections that are not usually assigned uids in bare mode. --- scripts/base/protocols/smtp/main.bro | 1 - scripts/policy/protocols/smtp/blocklists.bro | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/base/protocols/smtp/main.bro b/scripts/base/protocols/smtp/main.bro index a4b290fc89..cd0e730d8e 100644 --- a/scripts/base/protocols/smtp/main.bro +++ b/scripts/base/protocols/smtp/main.bro @@ -1,4 +1,3 @@ -@load base/frameworks/notice @load base/utils/addrs @load base/utils/directions-and-hosts @load base/utils/email diff --git a/scripts/policy/protocols/smtp/blocklists.bro b/scripts/policy/protocols/smtp/blocklists.bro index 57aef4ee48..aa7b951cbb 100644 --- a/scripts/policy/protocols/smtp/blocklists.bro +++ b/scripts/policy/protocols/smtp/blocklists.bro @@ -1,6 +1,7 @@ -##! Watch for various SPAM blocklist URLs in SMTP error messages. +##! Watch for various SPAM blocklist URLs in SMTP error messages. @load base/protocols/smtp +@load base/frameworks/notice module SMTP;