Several final fixes for PacketFilter framework.

- Fixed how the dpd_* variables are written.

- Fixed a bug with the shunting code.

- Updated a few tests.
This commit is contained in:
Seth Hall 2012-05-02 21:16:30 -04:00
parent 2ec7fbae62
commit 0c97c3c1de
17 changed files with 94 additions and 85 deletions

View file

@ -1,5 +1,4 @@
@load ./utils
@load ./main
@load ./shunt
@load ./load-balance
@load ./netstats

View file

@ -1,120 +0,0 @@
##! This script implements an automated BPF based load balancing solution for Bro clusters.
##! It is completely automated when multiple worker processes are configured for a single
##! interface on a host. One caveat is that in order for this script to work, your traffic
##! can't have any headers above the Ethernet header (vlan, mpls).
@load base/frameworks/cluster
@load base/frameworks/packet-filter
module PacketFilter;
export {
redef record Cluster::Node += {
## A BPF filter for load balancing traffic sniffed on a single interface
## across a number of processes. In normal uses, this will be assigned
## dynamically by the manager and installed by the workers.
lb_filter: string &optional;
};
## Control if BPF based load balancing is enabled on cluster deployments.
const enable_BPF_load_balancing = F &redef;
# Configure the cluster framework to enable the load balancing filter configuration.
#global send_filter: event(for_node: string, filter: string);
#global confirm_filter_installation: event(success: bool);
}
#redef Cluster::manager2worker_events += /LoadBalancing::send_filter/;
#redef Cluster::worker2manager_events += /LoadBalancing::confirm_filter_installation/;
@if ( Cluster::is_enabled() )
@if ( Cluster::local_node_type() == Cluster::MANAGER )
event bro_init() &priority=5
{
if ( ! enable_BPF_load_balancing )
return;
local worker_ip_interface: table[addr, string] of count = table();
for ( n in Cluster::nodes )
{
local this_node = Cluster::nodes[n];
# Only workers!
if ( this_node$node_type != Cluster::WORKER ||
! this_node?$interface )
next;
if ( [this_node$ip, this_node$interface] !in worker_ip_interface )
worker_ip_interface[this_node$ip, this_node$interface] = 0;
++worker_ip_interface[this_node$ip, this_node$interface];
}
# Now that we've counted up how many processes are running on an interface
# let's create the filters for each worker.
local lb_proc_track: table[addr, string] of count = table();
for ( no in Cluster::nodes )
{
local that_node = Cluster::nodes[no];
if ( that_node$node_type == Cluster::WORKER &&
that_node?$interface && [that_node$ip, that_node$interface] in worker_ip_interface )
{
if ( [that_node$ip, that_node$interface] !in lb_proc_track )
lb_proc_track[that_node$ip, that_node$interface] = 0;
local this_lb_proc = lb_proc_track[that_node$ip, that_node$interface];
local total_lb_procs = worker_ip_interface[that_node$ip, that_node$interface];
++lb_proc_track[that_node$ip, that_node$interface];
if ( total_lb_procs > 1 )
{
that_node$lb_filter = PacketFilter::sample_filter(total_lb_procs, this_lb_proc);
Communication::nodes[no]$capture_filter = that_node$lb_filter;
}
}
}
}
#event remote_connection_established(p: event_peer) &priority=-5
# {
# if ( is_remote_event() )
# return;
#
# local for_node = p$descr;
# # Send the filter to the peer.
# if ( for_node in Cluster::nodes &&
# Cluster::nodes[for_node]?$lb_filter )
# {
# local filter = Cluster::nodes[for_node]$lb_filter;
# event LoadBalancing::send_filter(for_node, filter);
# }
# }
#event LoadBalancing::confirm_filter_installation(success: bool)
# {
# # This doesn't really matter yet since we aren't getting back a meaningful success response.
# }
@endif
@if ( Cluster::local_node_type() == Cluster::WORKER )
#event LoadBalancing::send_filter(for_node: string, filter: string)
event remote_capture_filter(p: event_peer, filter: string)
{
#if ( for_node !in Cluster::nodes )
# return;
#
#if ( Cluster::node == for_node )
# {
restrict_filters["lb_filter"] = filter;
PacketFilter::install();
#event LoadBalancing::confirm_filter_installation(T);
# }
}
@endif
@endif

View file

@ -6,6 +6,7 @@
@load base/frameworks/notice
@load base/frameworks/protocols
@load ./utils
module PacketFilter;
@ -15,10 +16,10 @@ export {
## Add notice types related to packet filter errors.
redef enum Notice::Type += {
## This notice is generated if a packet filter is unable to be compiled.
## This notice is generated if a packet filter cannot be compiled.
Compile_Failure,
## This notice is generated if a packet filter is fails to install.
## Generated if a packet filter is fails to install.
Install_Failure,
## Generated when a notice takes too long to compile.
@ -60,7 +61,7 @@ export {
## used but MPLS or VLAN tags are on the traffic.
const restricted_filter = "" &redef;
## The maximum amount of time that you'd like to allow for filters to compile.
## The maximum amount of time that you'd like to allow for BPF filters to compile.
## If this time is exceeded, compensation measures may be taken by the framework
## to reduce the filter size. This threshold being crossed also results in
## the :bro:enum:`PacketFilter::Too_Long_To_Compile_Filter` notice.
@ -224,12 +225,16 @@ function build(): string
currently_building = T;
# Install the default capture filter.
local cfilter = "";
# Generate all of the plugin based filters.
for ( plugin in filter_plugins )
{
plugin$func();
}
local cfilter = "";
if ( |capture_filters| == 0 && ! enable_auto_protocol_capture_filters )
cfilter = default_capture_filter;
for ( id in capture_filters )
cfilter = combine_filters(cfilter, "or", capture_filters[id]);
@ -244,12 +249,6 @@ function build(): string
# Apply the dynamic restriction filters.
for ( filt in dynamic_restrict_filters )
rfilter = combine_filters(rfilter, "and", string_cat("not (", dynamic_restrict_filters[filt], ")"));
# Generate all of the plugin based filters.
for ( plugin in filter_plugins )
{
plugin$func();
}
# Finally, join them into one filter.
local filter = combine_filters(cfilter, "and", rfilter);
@ -270,7 +269,7 @@ function install(): bool
local tmp_filter = build();
#local ts = current_time();
local ts = current_time();
if ( ! precompile_pcap_filter(DefaultPcapFilter, tmp_filter) )
{
NOTICE([$note=Compile_Failure,
@ -281,15 +280,14 @@ function install(): bool
else
Reporter::warning(fmt("Bad pcap filter '%s'", tmp_filter));
}
local diff = current_time()-ts;
if ( diff > max_filter_compile_time )
NOTICE([$note=Too_Long_To_Compile_Filter,
$msg=fmt("A BPF filter is taking longer than %0.6f seconds to compile", diff)]);
# Set it to the current filter if it passed precompiling
current_filter = tmp_filter;
#local diff = current_time()-ts;
#if ( diff > max_filter_compile_time )
# NOTICE([$note=Too_Long_To_Compile_Filter,
# $msg=fmt("A BPF filter is taking longer than %0.6f seconds to compile", diff)]);
# Do an audit log for the packet filter.
local info: Info;
info$ts = network_time();

View file

@ -1,4 +1,6 @@
@load base/frameworks/notice
@load ./main
@load ./utils
module PacketFilter;
@ -49,7 +51,7 @@ global shunted_host_pairs: set[conn_id];
function shunt_filters()
{
# NOTE: this could wrongly match if a connection happens with the ports reversed.
local tcp_filter = "tcp and tcp[tcpflags] & (tcp-syn|tcp-fin|tcp-rst) == 0";
local tcp_filter = "";
local udp_filter = "";
for ( id in shunted_conns )
{
@ -61,6 +63,8 @@ function shunt_filters()
else if ( prot == tcp )
tcp_filter = combine_filters(tcp_filter, "and", filt);
}
if ( tcp_filter != "" )
tcp_filter = combine_filters("tcp and tcp[tcpflags] & (tcp-syn|tcp-fin|tcp-rst) == 0", "and", tcp_filter);
local conn_shunt_filter = combine_filters(tcp_filter, "and", udp_filter);
local hp_shunt_filter = "";
@ -68,7 +72,8 @@ function shunt_filters()
hp_shunt_filter = combine_filters(hp_shunt_filter, "and", fmt("host %s and host %s", id$orig_h, id$resp_h));
local filter = combine_filters(conn_shunt_filter, "and", hp_shunt_filter);
PacketFilter::exclude("shunt_filters", filter);
if ( filter != "" )
PacketFilter::exclude("shunt_filters", filter);
}
event bro_init() &priority=5

View file

@ -1,9 +1,10 @@
@load base/frameworks/packet-filter
@load base/frameworks/packet-filter/utils
module Protocols;
export {
const common_ports: table[string] of set[port] = {} &redef;
## Automatically creates a BPF filter for the specified protocol based
@ -15,14 +16,28 @@ export {
## Returns: BPF filter string.
global protocol_to_bpf: function(protocol: string): string;
## Create a BPF filter which matches all of the ports defined
## by the various protocol analysis scripts as "common ports"
## for the protocol.
global to_bpf: function(): string;
## Maps between human readable protocol identifiers (like "HTTP")
## and the internal Bro representation for an analyzer (like ANALYZER_HTTP).
## This is typically fully populated by the base protocol analyzer scripts.
const analyzer_map: table[string] of set[count] = {} &redef;
const analyzer_map: table[string] of set[AnalyzerTag] = {} &redef;
}
event bro_init() &priority=10
{
for ( proto in common_ports )
{
for ( p in common_ports[proto] )
dpd_analyzer_ports[p] = analyzer_map[proto];
for ( a in analyzer_map[proto] )
dpd_config[a] = [$ports=common_ports[proto]];
}
}
function protocol_to_bpf(protocol: string): string
{
# Return an empty string if an undefined protocol was given.
@ -42,8 +57,3 @@ function to_bpf(): string
output = PacketFilter::combine_filters(output, "or", protocol_to_bpf(p));
return output;
}

View file

@ -110,9 +110,9 @@ redef record connection += {
# Not attaching ANALYZER_DNS_UDP_BINPAC and ANALYZER_DNS_TCP_BINPAC right now.
global analyzers = { ANALYZER_DNS };
redef Protocols::analyzer_map["DNS"] = analyzers;
redef Protocols::analyzer_map += { ["DNS"] = analyzers };
global ports = { 53/udp, 53/tcp, 137/udp, 5353/udp, 5355/udp };
redef Protocols::common_ports["DNS"] = ports;
redef Protocols::common_ports += { ["DNS"] = ports };
event bro_init() &priority=5
{

View file

@ -95,9 +95,9 @@ redef record connection += {
};
global analyzers = { ANALYZER_FTP };
redef Protocols::analyzer_map["FTP"] = analyzers;
redef Protocols::analyzer_map += { ["FTP"] = analyzers };
global ports = { 21/tcp };
redef Protocols::common_ports["FTP"] = ports;
redef Protocols::common_ports += { ["FTP"] = ports };
# Establish the variable for tracking expected connections.
global ftp_data_expected: table[addr, port] of Info &create_expire=5mins;

View file

@ -113,13 +113,9 @@ event bro_init() &priority=5
global analyzers = { ANALYZER_HTTP, ANALYZER_HTTP_BINPAC };
redef Protocols::analyzer_map["HTTP"] = analyzers;
redef Protocols::analyzer_map += { ["HTTP"] = analyzers };
global ports = { 80/tcp, 81/tcp, 631/tcp, 1080/tcp, 3138/tcp, 8000/tcp, 8080/tcp, 8888/tcp };
redef Protocols::common_ports["HTTP"] = ports;
#redef dpd_config += {
# [[ANALYZER_HTTP, ANALYZER_HTTP_BINPAC]] = [$ports = Protocols::common_ports["HTTP"]],
#};
redef Protocols::common_ports += { ["HTTP"] = ports };
redef likely_server_ports += {
80/tcp, 81/tcp, 631/tcp, 1080/tcp, 3138/tcp,

View file

@ -39,9 +39,9 @@ redef record connection += {
};
global analyzers = { ANALYZER_IRC };
redef Protocols::analyzer_map["IRC"] = analyzers;
redef Protocols::analyzer_map += { ["IRC"] = analyzers };
global ports = { 6666/tcp, 6667/tcp, 6668/tcp, 6669/tcp, 7000/tcp };
redef Protocols::common_ports["IRC"] = ports;
redef Protocols::common_ports += { ["IRC"] = ports };
event bro_init() &priority=5
{

View file

@ -57,9 +57,6 @@ export {
const mail_path_capture = ALL_HOSTS &redef;
global log_smtp: event(rec: Info);
## Configure the default ports for SMTP analysis.
const ports = { 25/tcp, 587/tcp } &redef;
}
redef record connection += {
@ -68,8 +65,9 @@ redef record connection += {
};
global analyzers = { ANALYZER_SMTP };
redef Protocols::analyzer_map["SMTP"] = analyzers;
redef Protocols::common_ports["SMTP"] = ports;
redef Protocols::analyzer_map += { ["SMTP"] = analyzers };
const ports = { 25/tcp, 587/tcp } &redef;
redef Protocols::common_ports += { ["SMTP"] = ports };
event bro_init() &priority=5
{

View file

@ -75,9 +75,9 @@ export {
}
global analyzers = { ANALYZER_SSH };
redef Protocols::analyzer_map["SSH"] = analyzers;
redef Protocols::analyzer_map += { ["SSH"] = analyzers };
global ports = { 22/tcp };
redef Protocols::common_ports["SSH"] = ports;
redef Protocols::common_ports += { ["SSH"] = ports };
redef record connection += {
ssh: Info &optional;

View file

@ -73,10 +73,10 @@ event bro_init() &priority=5
}
global analyzers = { ANALYZER_SSL };
redef Protocols::analyzer_map["SSL"] = analyzers;
redef Protocols::analyzer_map += { ["SSL"] = analyzers };
global ports = { 443/tcp, 563/tcp, 585/tcp, 614/tcp, 636/tcp,
989/tcp, 990/tcp, 992/tcp, 993/tcp, 995/tcp, 5223/tcp };
redef Protocols::common_ports["SSL"] = ports;
redef Protocols::common_ports += { ["SSL"] = ports };
function set_session(c: connection)

View file

@ -26,9 +26,9 @@ export {
}
global analyzers = { ANALYZER_SYSLOG_BINPAC };
redef Protocols::analyzer_map["SYSLOG"] = analyzers;
redef Protocols::analyzer_map += { ["SYSLOG"] = analyzers };
global ports = { 514/udp };
redef Protocols::common_ports["SYSLOG"] = ports;
redef Protocols::common_ports += { ["SYSLOG"] = ports };
redef record connection += {
syslog: Info &optional;