原文地址:https://www.bro.org/sphinx/frameworks/netcontrol.html
Bro可以通过使用网络控制框架和网络设备连接(比如交换机,软、硬件防火墙)。网络控制框架对活动的响应(active response)提供了一个灵活、统一的接口,并将复杂的异构网络设备(heterogeneous network equipment)隐藏到一个面向任务的API(一个可以通过bro脚本轻松调用的API)中。本文对如何在不同的场景下使用网络控制框架给出了一个概要性描述。倘若您想更深入地了解它是如何在实际中运用的,那么请看看下面的单元测试(unit tests),应该会很有帮助。
网络控制体系结构(NetControl Architecture)
上图便是网络控制框架的基本体系结构了。从概念上来理解,网络控制框架坐落于用户提供的脚本(使用了bro的事件机制)和网络设备(既可以是硬件设备也可以是软件设备)之间,它(网络控制框架)可以用来执行命令。
网络控制框架支持很多高级调用,比如NetControl::drop_address函数,或者是低层次的语法规则。在给网络控制框架添加一条规则之后,网络控制框架会给它的一个或者多个后端(backends)发送规则。每一个后端都会对一个硬件或者软件设备负责。网络控制框架会在它的整个声明周期中跟踪这些规则并且汇报状态(比如success、failure和timeouts)给用户脚本。
这些后端是通过使用一个基于插件的API实现的,这是一个典型的例子base/frameworks/netcontrol/plugins/broker.bro。如何写插件NetControl Plugin。
网络控制API(NetControl API)
高级网络控制API(High-level NetControl API)
这部分我们将介绍高级网络控制API。网络控制使用后端和外部设备通信(这些外部设备可以实现规则--rules)。在你使用网络控制的时候,至少要有一个活动后端。在我们的例子中,我们将使用一个调试插件来创建一个后端。这个插件会将标准输出的所有动作输出。
后端应该在NetControl::init事件中初始化,并在插件实例初始化之后调用NetControl::activate函数。调试插件可以进行如下的初始化:
event NetControl::init()
{
local debug_plugin = NetControl::create_debug(T);
NetControl::activate(debug_plugin, 0);
}
在给网络控制框架添加至少一个后端之后,框架就会投入使用并向后端发送新增的规则。
网络控制框架包含了一些可以让用户断开某些地址和网络的连接,避开网络流量,等等。下表描述了当前可用的高级函数。
函数 | 描述 |
NetControl::drop_address | 调用此函数让网络控制框架阻止包含某个IP的数据包的转发。 |
NetControl::drop_connection | 调用此函数阻止某个特定连接(由它的五元组标识的)上的所有数据包的转发。 |
NetControl::drop_address_catch_release | 调用此函数导致某一个特定的源IP的所有报文都被阻塞,这个函数具备捕捉和释放(catch-and-release)功能并且为了保有规则在网络硬件中的空间,这个IP很快就会被丢弃。当在网络流量中再次发现这个IP的之后,立刻丢弃。想要知道更多信息,看Catch and Release。 |
NetControl::shunt_flow | 调用此函数让网络控制框架停止转发单向流量到Bro中。这允许Bro通过将有益的流量分流的途径来保存资源。 |
NetControl::redirect_flow | 调用此函数让网络控制框架重定向一个单向流到网络设备的另一个部分上去。 |
NetControl::quarantine_host | 调用这个函数允许Bro通过从一个特殊的DNS服务器上发送DNS流量的方法来隔离一个主机,这个特殊的DNS服务器会将所有的请求指向该主机自身。这个隔离的主机仅允许在特殊的服务器之间存在,它将给用户产生一个详细描述下一步的警告信息。 |
NetControl::whitelist_address | 调用这个函数让网络控制框架给网络硬件推送一个IP地址组成的白名单入口。 |
NetControl::whitelist_subnet | 调用这个函数让网络控制框架给网络硬件推送一个子网的白名单入口。 |
在添加后端之后,所有这些函数都可以立即使用并开始发送规则到新增的后端。下面是一个非常简单的例子,这个脚本会简单粗暴地阻塞所有将要建立的连接的流量。
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);
}
运行这个脚本,加载的文件中有一个连接。这将导致调试插件打印一行到标准输入中,包含所添加的规则的信息。它还会产生一个叫作netcontrol.log的日志文件,这个日志文件包含了网络控制框架的所有活动的信息。
# 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=<uninitialized>, ip=<uninitialized>, mac=<uninitialized>], expire=20.0 secs, priority=0, location=, out_port=<uninitialized>, mod=<uninitialized>, id=2, cid=2, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _no_expire_plugins={\x0a\x0a}, _added=F]
# cat netcontrol.log
#separator \x09
#set_separator ,
#empty_field (empty)
#unset_field -
#path netcontrol
#open 2018-11-22-14-05-14
#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 2018-11-22-14-05-14
上例中,netcontrol.log包含了几条NetControl::MESSAGE入口,表示调试插件已经初始化并添加。此后,有两条NetControl::RULE入口,第一个表示请求添加一条规则(状态是NetControl::REQUESTED)。下一行表示规则已经成功添加(状态时NetControl::SUCCEEDED)。日志行的提醒给出了新增规则的更多信息,在我们例子中是一个五元组。
除了netcontrol.log,drop命令也创建了一个叫作netcontrol_drop.log的日志文件。这个日志文件就简洁得多了,它仅包含网络控制框架制定的丢弃信息:
# cat netcontrol_drop.log
#separator \x09
#set_separator ,
#empty_field (empty)
#unset_field -
#path netcontrol_drop
#open 2018-11-22-14-05-14
#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 2018-11-22-14-05-14
尽管这个阻塞所有连接的例子不是很有用,但也能看出高级API提供了一种采取措施的简单途径,比如当一个主机在做一些有害活动的时候。给一个更加现实的例子,下面的代码自动阻塞一个已经被辨别出来的SSH猜测者(SSH guesser)。
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);
}
# 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=<uninitialized>, flow=<uninitialized>, ip=192.168.56.1/32, mac=<uninitialized>], expire=1.0 hr, priority=0, location=, out_port=<uninitialized>, mod=<uninitialized>, id=2, cid=2, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _no_expire_plugins={\x0a\x0a}, _added=F]
# cat netcontrol.log
#separator \x09
#set_separator ,
#empty_field (empty)
#unset_field -
#path netcontrol
#open 2018-11-22-14-05-16
#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 - - - -
1427726759.303199 2 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.56.1/32 - - 0 3600.000000 - Debug-All
1427726759.303199 2 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.56.1/32 - - 0 3600.000000 - Debug-All
#close 2018-11-22-14-05-16
注意在这个例子中,没有直接调用NetControl,我们还使用了通知框架的Notice::ACTION_DROP动作。
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];
}
# 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=<uninitialized>, flow=<uninitialized>, ip=192.168.56.1/32, mac=<uninitialized>], expire=10.0 mins, priority=0, location=ACTION_DROP: T, out_port=<uninitialized>, mod=<uninitialized>, id=2, cid=2, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _no_expire_plugins={\x0a\x0a}, _added=F]
# cat netcontrol.log
#separator \x09
#set_separator ,
#empty_field (empty)
#unset_field -
#path netcontrol
#open 2018-11-22-14-05-17
#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 - - - -
1427726759.303199 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
1427726759.303199 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 2018-11-22-14-05-17
使用通知框架的Notice::ACTION_DROP动作还会导致每当网络控制框架实施阻塞的时候将notice.log中被丢弃的列置为True:
# cat notice.log
#separator \x09
#set_separator ,
#empty_field (empty)
#unset_field -
#path notice
#open 2018-11-22-14-05-17
#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
1427726759.303199 - - - - - - - - - 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 F - - - - -
#close 2018-11-22-14-05-17
规则API(Rule API)
正如上一节中所说的那样,除了高级API,网络控制框架也支持基于规则的API,这种API允许添加规则时的更好的灵活性。实际上,所有的高层次函数都是使用低层次的规则API来实现的,这些高层级的API仅仅将它们的参数转换为低层次规则,并将这些规则直接添加到网络控制框架中去(通过调用NetControl::add_rule方法)。
下面的图片展示了网络控制规则的主要构件:
用于构成规则的类型定义在base/frameworks/netcontrol/types.bro。
规则被定义为NetControl::Rule形式的记录。规则有类型(type),这个类型表示执行何种动作。可能的动作有:丢弃(drop)包,修改(modify)包,重定向(redirect)包或者用白名单(whitelist)过滤包。规则的目标(target)指示了这个规则是否应用在转发路径上并且影响了那些在网络中转发的包,或者是这个规则是否影响了监视器的路径并仅仅影响了发送给bro的包,而不是贯穿于网络的包。图中的实体(entity)指示了应用了规则的地址、连接。此外,每一个规则有一个timeout(可以留空),一个priority(高优先级的规则覆盖低优先级的规则的)字段。另外location串有关于每个可提供的规则的更多文本信息。
对某些规则类型,还要多出两个字段。比如,当你插入一个重定向规则的时候,你需要指明包应当要重定向到的端口。诸如此类的字段在NetControl::Rule文本中有详细描述。
下例给出了如何构建你自己的规则,我们要写我们自己的NetControl::drop_connection函数。我们的函数和网络控制框架提供的函数之间的唯一的区别就是网络控制框架函数有额外的功能,比如日志方面的功能。
再一次,我们用下面这个简单的例子来测试我们的函数,这个例子简单粗暴地丢弃网络中的所有连接:
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);
}
# 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=<uninitialized>, ip=<uninitialized>, mac=<uninitialized>], expire=20.0 secs, priority=0, location=<uninitialized>, out_port=<uninitialized>, mod=<uninitialized>, id=2, cid=2, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _no_expire_plugins={\x0a\x0a}, _added=F]
# cat netcontrol.log
#separator \x09
#set_separator ,
#empty_field (empty)
#unset_field -
#path netcontrol
#open 2018-11-22-14-05-18
#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 2018-11-22-14-05-18
最后的这个例子表明NetControl::add_rule返回一个对于每一个规则而言独一无二的字符串标识符(如果Bro重启了的话就不能保证它是独一无二的了)。这个ID可以在后期用于手动地移除规则(通过使用NetControl::remove_rule)。
与NetControl::add_rule类似,所有的高级函数会返回它们的规则ID,这些规则也可以通过相同的方法移除。
与规则交互(Interacting with Rules)
网络控制框架提供了很多不同的方法来和规则交互。在框架应用某条规则之前,你都可以应用各种各样的钩子来修改或者丢弃这些规则。此外,在规则为网络控制框架所管理的时候,也有很多事件,利用这些事件就可以跟踪某条规则的生命周期。也可以查询或者获取当前活动规则的集合。
规则策略(Rule Policy)
钩子NetControl::rule_policy提供了在规则被发送到后端之前就可以修改或者丢弃规则的机制。钩子可以看作是多体的函数(multi-bodied functions)并且使用钩子就和事件处理差不多。钩子和事件相比,钩子是立即执行的。钩子也可以有优先级来给出它们应用的顺序。钩子可以使用break关键字来表示处理应该终止,如果任何NetControl::rule_policy钩子使用了break,这条规则应该直接丢弃,不做后续的处理了。
下面是一个简单的例子,这个例子告诉Bro,丢弃所有来自于192.168.*网络的连接的规则。
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);
}
# bro -C -r tls/ecdhe.pcap netcontrol-5-hook.bro
netcontrol debug (Debug-All): init
Ignored connection from, 192.168.18.50
网络控制事件(NetControl Events)
除了钩子,网络控制框架提供了一系列事件,这些事件让用户可以追踪规则以及框架的状态。
我们已经遇到并使用了网络控制框架的一个事件,那就是NetControl::init,这是用于初始化框架的。在框架结束初始化并准备接收规则的时候,NetControl::init_done事件就会产生。
当给框架添加规则的时候,事件将会按照如下的顺序发生:
事件 | 描述 |
NetControl::rule_new | 当网络控制框架通过NetControl::add_rule产生一个新的规则是产生的信号。此时,规则还没有被添加到后端。 |
NetControl::rule_added | 当一条新的规则成功地添加到后端的时候产生此信号。 |
NetControl::rule_exists | 当后端告知此条规则已经存在的时候就不产生NetControl::rule_added,而是产生这个事件。 |
NetControl::rule_timeout | 当达到了一条规则的超时条件的时候,如果硬件不支持自动超时,那么网络控制框架就会自动地调用NetControl::remove_rule。 |
NetControl::rule_removed | 当从后端成功地移除一个规则的时候产生。 |
NetControl::rule_destroyed | 这个事件附属于NetControl::rule_added,并且报告这个规则再也不由网络控制框架跟踪了。这个事件当某个规则从所有的后端中移除的时候产生。 |
NetControl::rule_error | 当规则操作的过程中出错的话,就产生这个事件。 |
查找活动规则(Finding active rules)
网络控制框架提供了两个方法来查找当前活动规则:NetControl::find_rules_addr查找所有的影响某个IP地址的规则,NetControl::find_rules_subnet查找所有影响某个特定子网的规则。
试想,举个例子,Bro实例监视在边界的流量的情况(在没有配置任何防火墙以及交换规则的时候)。这种情况下,Bro可以看到来自那些被阻塞的IP地址所尝试的连接。此例中,NetControl::find_rules_addr方法可以用来检测某个地址是否在过去曾经被阻塞。
下面是一个简单的例子,使用一个包含来自同一个IP地址的两条连接的跟踪。在第一条连接之后,这个脚本辨识出这个地址已经在第二条连接中被阻塞了。
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";
}
# 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=<uninitialized>, ip=<uninitialized>, mac=<uninitialized>], expire=20.0 secs, priority=0, location=, out_port=<uninitialized>, mod=<uninitialized>, 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
除了阻塞功能,NetControl::get_catch_release_info函数提供的捕捉和释放功能可以检查某个地址是否已经被阻塞了并获取这个块的信息。函数NetControl::unblock_address_catch_release函数可以将前面的地址解除阻塞。
注意:
由于捕捉和释放(Catch and release)有除了网络控制框架所提供的跟踪之外属于它们自己的连接跟踪,所以移除由捕捉和释放添加的规则的时候仅仅调用NetControl::remove_rule是不够的。你还要使用NetControl::unblock_address_catch_release。
网络控制插件(NetControl Plugins)
使用现存的插件(Using the existing plugins)
在文档的API部分,我们专门使用了调试插件,将它的输出打印到屏幕上去。除了这个调试插件,Bro提供了一些可用于作为网络控制框架和网络硬件和软件的接口的插件。
网络控制框架现有的插件有:
插件名 | 描述 |
OpenFlow插件 | 这是最具特色的插件,它允许网络控制框架和OpenFlow交换机交互。这个插件的源在base/frameworks/netcontrol/plugins/openflow.bro. |
中间人插件(Broker plugin) | 这个库提供了使用新的Bro通信库(Bro)来发送网络控制命令的一般方法。外部程序可以接收规则并采取动作,我们提供了一个示例脚本,这个示例脚本调用用网络控制框架触发的命令行程序。该插件的源是base/frameworks/netcontrol/plugins/broker.bro. |
acld插件 | 此插件对acld守护进程体工支持,可以和若干交换机和路由器交互。当前版本的acld可以从LBL ftp server中获取。此插件的源在base/frameworks/netcontrol/plugins/acld.bro. |
包过滤器插件 | 此插件使用Bro进程级包过滤器(请看install_src_net_filter和install_dst_net_filter)。由于PacketFilter的功能被限制了,此插件一般作演示使用。此插件的源在base/frameworks/netcontrol/plugins/packetfilter.bro. |
调试插件 | 调试插件简单地将它的动作输出到标准输出中。此插件的源base/frameworks/netcontrol/plugins/debug.bro. |
激活插件(Activating plugins)
在本文的API引用部分,我们已经使用了调试插件。为了使用插件,我们先通过调用NetControl::create_debug来将它实例化,然后通过调用NetControl::activate将它添加到网络控制框架中去。
正如我们先前所提示的那样,网络控制框架支持同时拥有多个活动的插件。NetContro::activate的第二个参数是刚刚添加的后端的优先级。每一条规则都会按照顺序发送给所有的插件,从高优先级到低优先级的顺序。后端就可以选择是否接受这个规则以及是否将这个规则推送给它所管理的硬件。在这种情况下,网络控制框架会尝试以稍低一级的优先级来将规则应用到后端上。如果没有后端接受到规则,这次的规则插入就失败了。
对某条规则是接受还是拒绝的请求和插件的类型有关(按照我的理解翻译的)。我们认为调试插件会接受所有规则。然而,其他的插件你可以指定它们接受那些规则。试想,举个例子,一个网络中有两个OpenFlow交换机。第一个交换机将网络内部的包转发到外部,第二台交换机坐落在你的Bro簇的前面进行包分流。这种情况下,我们可以添加两个OpenFlow后端到网络控制框架中。当你使用NetControl::create_openflow进行实例化的时候,你在NetControl::OfConfig中恰当地设置监视和转发属性。此后,这些后端之一仅会为监视器路径接受规则,其他的后端仅会为转发路径接受规则。
通常,插件也提供了预测功能,允许用户指明他们想要接受的规则的限制条件。当你有仅对某些子网负责的交换机的时候,这个功能就可以派上用场。预测功能会检测这些规则的子网并且只接受匹配指定交换机所负责的子网的规则的规则。
再举个例子,下面的脚本给网络控制框架添加了两个后端。一个后端是OpenFlow后端,它使用OpenFlow调试模式,将OpenFlow规则输出到openflow.log文件中去。OpenFlow后端使用了预测功能仅接受规则在192.168.17.0/24网络中的源地址,所有其他的规则都会传送给调试插件。我们在NetControl::init_done事件中手动阻塞一些地址去验证此功能的正确性。
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);
}
# 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=<uninitialized>, flow=<uninitialized>, ip=192.168.17.2/32, mac=<uninitialized>], expire=1.0 min, priority=0, location=, out_port=<uninitialized>, mod=<uninitialized>, id=3, cid=3, _plugin_ids={\x0a\x0a}, _active_plugin_ids={\x0a\x0a}, _no_expire_plugins={\x0a\x0a}, _added=F]
正如你所看到的一样,仅有影响192.168.17.0/24网络的块输出到了命令行。另外两行由OpenFlow插件来处理。我们可以通过查看netcontrol.log文件来验证。插件这一列显示了哪个插件处理了一条规则并揭示了有两条规则是由OpenFlow来处理的。
# cat netcontrol.log
#separator \x09
#set_separator ,
#empty_field (empty)
#unset_field -
#path netcontrol
#open 2018-11-22-14-05-23
#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
1542895523.407420 - NetControl::MESSAGE - - - - - - - activating plugin with priority 0 - - - Debug-All
1542895523.407420 - NetControl::MESSAGE - - - - - - - activation finished - - - Debug-All
1542895523.407420 - NetControl::MESSAGE - - - - - - - activating plugin with priority 10 - - - Openflow-Log-42
1542895523.407420 - NetControl::MESSAGE - - - - - - - activation finished - - - Openflow-Log-42
1542895523.407420 - NetControl::MESSAGE - - - - - - - plugin initialization done - - - -
1542895523.407420 2 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 10.0.0.1/32 - - 0 60.000000 - Openflow-Log-42
1542895523.407420 3 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.17.2/32 - - 0 60.000000 - Debug-All
1542895523.407420 4 NetControl::RULE ADD NetControl::REQUESTED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.2/32 - - 0 60.000000 - Openflow-Log-42
1542895523.407420 3 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.17.2/32 - - 0 60.000000 - Debug-All
1542895523.407420 2 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 10.0.0.1/32 - - 0 60.000000 - Openflow-Log-42
1542895523.407420 4 NetControl::RULE ADD NetControl::SUCCEEDED NetControl::DROP NetControl::FORWARD NetControl::ADDRESS 192.168.18.2/32 - - 0 60.000000 - Openflow-Log-42
#close 2018-11-22-14-05-23
此外,openflow.log也显示了这两条规则,转换到OpenFlow流方法:
# cat openflow.log
#separator \x09
#set_separator ,
#empty_field (empty)
#unset_field -
#path openflow
#open 2018-11-22-14-05-23
#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
1542895523.407420 42 - - - - - 2048 - - 10.0.0.1/32 - - - 4398046511108 - OpenFlow::OFPFC_ADD 0 60 0 - - 1 (empty) - - F - - - - - - -
1542895523.407420 42 - - - - - 2048 - - - 10.0.0.1/32 - - 4398046511109 - OpenFlow::OFPFC_ADD 0 60 0 - - 1 (empty) - - F - - - - - - -
1542895523.407420 42 - - - - - 2048 - - 192.168.18.2/32 - - - 4398046511112 - OpenFlow::OFPFC_ADD 0 60 0 - - 1 (empty) - - F - - - - - - -
1542895523.407420 42 - - - - - 2048 - - - 192.168.18.2/32 - - 4398046511113 - OpenFlow::OFPFC_ADD 0 60 0 - - 1 (empty) - - F - - - - - - -
#close 2018-11-22-14-05-23
注意:
你可能会有疑问,如果添加两个或者多个同样优先级的规则的话,会怎么样?在这种情况下,规则会同时发送给所有的后端。这样是很有用的,比如当你有冗余的交换机的时候(这些交换机应该保持一样的规则状态)。
和外部硬件交互(Interfacing with external hardware)
既然我们已经知道了有哪些插件存在以及它们是如何添加到网络控制框架中的,接下来就让我们看看我们如何让Bro和实际硬件交互。实现这种交互的一个典型的方法就是使用Bro通信库(Broker),这个我们可以用于将Bro事件和外部程序以及脚本交换。网络控制插件可以使用Broker来发送事件到外部程序中去,外部程序可以基于这些事件来采取措施。
下面的图显示了使用OpenFlow插件的例子的体系结构。OpenFlow插件使用Broker来发送事件到一个外部的Python脚本(此脚本使用Ryu SDN controller来和交换机通信)。
这个Python脚本用于和可获得的NetControl插件交互(包含在bro-netcontrol的github仓库中)。这个仓库包含了OpenFlow和acld插件的脚本。此外,它还包含了用于broker插件调用可配置的命令行程序的脚本。
此仓库还包含了如何安装这些连接器的文本。在netcontrol目录下包含一个让你写自己的连接器到broker插件的API。
注意:
Broker通信库的API还没有完全完结。你在未来的新的Bro版本中可能要重写一些关于它的脚本。
写插件(Writing plugins)
除了使用作为网络控制框架的一部分出现的插件,你需要写你自己的插件来与我们尚未专门以盒的形式(是不是封装好弄成现成的插件的意思?)支持的硬件或软件交互。
创建我们自己的插件实际上很简单,除了套用前面的模子,你只要创建两个函数:一个是当一条规则添加的时候调用的,另一个是当一条规则被移除的时候调用的。注意,你要产生NetControl::rule_added和NetControl::rule_removed事件在你的插件中,让网络控制框架知道一条规则被成功地添加和移除。
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, reason: string &default="") : 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;
}
这个例子已经具备完整的功能,我们可以在脚本中使用它,就象我们的第一个例子一样:
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);
}
# 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=<uninitialized>, ip=<uninitialized>, mac=<uninitialized>], expire=20.0 secs, priority=0, location=, out_port=<uninitialized>, mod=<uninitialized>, id=2, cid=2, _plugin_ids={
}, _active_plugin_ids={
}, _no_expire_plugins={
}, _added=F]
如果你想要写你自己的插件,那么去看看网络控制框架已经有的插件来了解它们是如何定义预测功能的以及它们是如何和Broker交互的,这会很有帮助。