From 0c97c3c1de57cd64279cfc94b92a1f2d92c76f1b Mon Sep 17 00:00:00 2001 From: Seth Hall Date: Wed, 2 May 2012 21:16:30 -0400 Subject: [PATCH] Several final fixes for PacketFilter framework. - Fixed how the dpd_* variables are written. - Fixed a bug with the shunting code. - Updated a few tests. --- .../frameworks/packet-filter/__load__.bro | 1 - .../base/frameworks/packet-filter/main.bro | 36 +++++++++--------- .../base/frameworks/packet-filter/shunt.bro | 9 ++++- scripts/base/frameworks/protocols/main.bro | 24 ++++++++---- scripts/base/protocols/dns/main.bro | 4 +- scripts/base/protocols/ftp/main.bro | 4 +- scripts/base/protocols/http/main.bro | 8 +--- scripts/base/protocols/irc/main.bro | 4 +- scripts/base/protocols/smtp/main.bro | 8 ++-- scripts/base/protocols/ssh/main.bro | 4 +- scripts/base/protocols/ssl/main.bro | 4 +- scripts/base/protocols/syslog/main.bro | 4 +- .../misc/load-balancing.bro} | 38 ++++++++++++------- src/main.cc | 7 ++-- .../Baseline/core.print-bpf-filters/conn.log | 2 +- .../Baseline/core.print-bpf-filters/output | 14 ++----- testing/btest/core/print-bpf-filters.bro | 8 ++-- 17 files changed, 94 insertions(+), 85 deletions(-) rename scripts/{base/frameworks/packet-filter/load-balance.bro => policy/misc/load-balancing.bro} (79%) diff --git a/scripts/base/frameworks/packet-filter/__load__.bro b/scripts/base/frameworks/packet-filter/__load__.bro index 14da4e4893..45c2488c00 100644 --- a/scripts/base/frameworks/packet-filter/__load__.bro +++ b/scripts/base/frameworks/packet-filter/__load__.bro @@ -1,5 +1,4 @@ @load ./utils @load ./main @load ./shunt -@load ./load-balance @load ./netstats diff --git a/scripts/base/frameworks/packet-filter/main.bro b/scripts/base/frameworks/packet-filter/main.bro index 9ffd8cc4c3..c5a0677add 100644 --- a/scripts/base/frameworks/packet-filter/main.bro +++ b/scripts/base/frameworks/packet-filter/main.bro @@ -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(); diff --git a/scripts/base/frameworks/packet-filter/shunt.bro b/scripts/base/frameworks/packet-filter/shunt.bro index be33f8085a..fcbdac85aa 100644 --- a/scripts/base/frameworks/packet-filter/shunt.bro +++ b/scripts/base/frameworks/packet-filter/shunt.bro @@ -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 diff --git a/scripts/base/frameworks/protocols/main.bro b/scripts/base/frameworks/protocols/main.bro index 8924c4c259..43ea3b49f8 100644 --- a/scripts/base/frameworks/protocols/main.bro +++ b/scripts/base/frameworks/protocols/main.bro @@ -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; } - - - - - \ No newline at end of file diff --git a/scripts/base/protocols/dns/main.bro b/scripts/base/protocols/dns/main.bro index 95259fb2e8..d6b44323d1 100644 --- a/scripts/base/protocols/dns/main.bro +++ b/scripts/base/protocols/dns/main.bro @@ -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 { diff --git a/scripts/base/protocols/ftp/main.bro b/scripts/base/protocols/ftp/main.bro index 52366d28e1..3b2f0cca61 100644 --- a/scripts/base/protocols/ftp/main.bro +++ b/scripts/base/protocols/ftp/main.bro @@ -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; diff --git a/scripts/base/protocols/http/main.bro b/scripts/base/protocols/http/main.bro index dbfbe4b6ff..86b59d1f10 100644 --- a/scripts/base/protocols/http/main.bro +++ b/scripts/base/protocols/http/main.bro @@ -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, diff --git a/scripts/base/protocols/irc/main.bro b/scripts/base/protocols/irc/main.bro index a59e5043f6..acb0250fc8 100644 --- a/scripts/base/protocols/irc/main.bro +++ b/scripts/base/protocols/irc/main.bro @@ -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 { diff --git a/scripts/base/protocols/smtp/main.bro b/scripts/base/protocols/smtp/main.bro index 5676878b18..544e40bf12 100644 --- a/scripts/base/protocols/smtp/main.bro +++ b/scripts/base/protocols/smtp/main.bro @@ -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 { diff --git a/scripts/base/protocols/ssh/main.bro b/scripts/base/protocols/ssh/main.bro index 7ca71ba9df..290b1a9c89 100644 --- a/scripts/base/protocols/ssh/main.bro +++ b/scripts/base/protocols/ssh/main.bro @@ -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; diff --git a/scripts/base/protocols/ssl/main.bro b/scripts/base/protocols/ssl/main.bro index 6a75e01735..5c16808532 100644 --- a/scripts/base/protocols/ssl/main.bro +++ b/scripts/base/protocols/ssl/main.bro @@ -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) diff --git a/scripts/base/protocols/syslog/main.bro b/scripts/base/protocols/syslog/main.bro index 786e3668a4..502021f851 100644 --- a/scripts/base/protocols/syslog/main.bro +++ b/scripts/base/protocols/syslog/main.bro @@ -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; diff --git a/scripts/base/frameworks/packet-filter/load-balance.bro b/scripts/policy/misc/load-balancing.bro similarity index 79% rename from scripts/base/frameworks/packet-filter/load-balance.bro rename to scripts/policy/misc/load-balancing.bro index 105a37b617..fedf075217 100644 --- a/scripts/base/frameworks/packet-filter/load-balance.bro +++ b/scripts/policy/misc/load-balancing.bro @@ -1,27 +1,39 @@ -##! 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). +##! This script implements the "Bro side" of several load balancing +##! approaches for Bro clusters. @load base/frameworks/cluster @load base/frameworks/packet-filter -module PacketFilter; +module LoadBalancing; export { + + type Method: enum { + ## Apply BPF filters to each worker in a way that causes them to + ## automatically flow balance traffic between them. + AUTO_BPF, + ## Load balance traffic across the workers by making each one apply + ## a restrict filter to only listen to a single MAC address. This + ## is a somewhat common deployment option for sites doing network + ## based load balancing with MAC address rewriting and passing the + ## traffic to a single interface. Multiple MAC addresses will show + ## up on the same interface and need filtered to a single address. + #MAC_ADDR_BPF, + }; + + ## Defines the method of load balancing to use. + const method = AUTO_BPF &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 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/; @@ -33,7 +45,7 @@ export { event bro_init() &priority=5 { - if ( ! enable_BPF_load_balancing ) + if ( method != AUTO_BPF ) return; local worker_ip_interface: table[addr, string] of count = table(); diff --git a/src/main.cc b/src/main.cc index ff33a3859d..d70832efcb 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1003,13 +1003,14 @@ int main(int argc, char** argv) vl->append(new Val(i->include_level, TYPE_COUNT)); mgr.QueueEvent(bro_script_loaded, vl); } - - dpm->PostScriptInit(); - + reporter->ReportViaEvents(true); + // Drain the event queue here to support the protocols framework configuring DPM mgr.Drain(); + dpm->PostScriptInit(); + have_pending_timers = ! reading_traces && timer_mgr->Size() > 0; io_sources.Register(thread_mgr, true); diff --git a/testing/btest/Baseline/core.print-bpf-filters/conn.log b/testing/btest/Baseline/core.print-bpf-filters/conn.log index 5ce968d5e6..c26fd152a4 100644 --- a/testing/btest/Baseline/core.print-bpf-filters/conn.log +++ b/testing/btest/Baseline/core.print-bpf-filters/conn.log @@ -5,4 +5,4 @@ #path conn #fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state local_orig missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes #types time string addr port addr port enum string interval count count string bool count string count count count count -1128727435.450898 UWkUyAuUGXf 141.42.64.125 56730 125.190.109.199 80 tcp http 1.733303 98 9417 SF - 0 ShADdFaf 12 730 10 9945 +1278600802.069419 UWkUyAuUGXf 10.20.80.1 50343 10.0.0.15 80 tcp - 0.004152 9 3429 SF - 0 ShADadfF 7 381 7 3801 diff --git a/testing/btest/Baseline/core.print-bpf-filters/output b/testing/btest/Baseline/core.print-bpf-filters/output index a2bf430fb4..5a345c9f4f 100644 --- a/testing/btest/Baseline/core.print-bpf-filters/output +++ b/testing/btest/Baseline/core.print-bpf-filters/output @@ -5,7 +5,7 @@ #path packet_filter #fields ts node filter init success #types time string string bool bool -1328294052.330721 - ip or not ip T T +1335502481.107322 - ip or not ip T T #separator \x09 #set_separator , #empty_field (empty) @@ -13,7 +13,7 @@ #path packet_filter #fields ts node filter init success #types time string string bool bool -1328294052.542418 - ((((((((((((((((((((((((port 53) or (tcp port 989)) or (tcp port 443)) or (port 6669)) or (udp and port 5353)) or (port 6668)) or (udp and port 5355)) or (tcp port 22)) or (tcp port 995)) or (port 21)) or (tcp port 25 or tcp port 587)) or (port 6667)) or (tcp port 614)) or (tcp port 990)) or (udp port 137)) or (tcp port 993)) or (tcp port 5223)) or (port 514)) or (tcp port 585)) or (tcp port 992)) or (tcp port 563)) or (tcp port 994)) or (tcp port 636)) or (tcp and port (80 or 81 or 631 or 1080 or 3138 or 8000 or 8080 or 8888))) or (port 6666) T T +1335502481.417564 - port 42 T T #separator \x09 #set_separator , #empty_field (empty) @@ -21,12 +21,4 @@ #path packet_filter #fields ts node filter init success #types time string string bool bool -1328294052.748480 - port 42 T T -#separator \x09 -#set_separator , -#empty_field (empty) -#unset_field - -#path packet_filter -#fields ts node filter init success -#types time string string bool bool -1328294052.952845 - port 56730 T T +1335502481.737329 - (vlan) and (ip or not ip) T T diff --git a/testing/btest/core/print-bpf-filters.bro b/testing/btest/core/print-bpf-filters.bro index 6d9cef0220..383982eddf 100644 --- a/testing/btest/core/print-bpf-filters.bro +++ b/testing/btest/core/print-bpf-filters.bro @@ -1,10 +1,8 @@ -# @TEST-EXEC: bro -r $TRACES/empty.trace -e '' >output +# @TEST-EXEC: bro -r $TRACES/empty.trace >output # @TEST-EXEC: cat packet_filter.log >>output -# @TEST-EXEC: bro -r $TRACES/empty.trace PacketFilter::all_packets=F >>output +# @TEST-EXEC: bro -r $TRACES/empty.trace -f "port 42" >>output # @TEST-EXEC: cat packet_filter.log >>output -# @TEST-EXEC: bro -r $TRACES/empty.trace -f "port 42" -e '' >>output -# @TEST-EXEC: cat packet_filter.log >>output -# @TEST-EXEC: bro -r $TRACES/empty.trace -C -f "port 56730" -r $TRACES/mixed-vlan-mpls.trace >>output +# @TEST-EXEC: bro -r $TRACES/mixed-vlan-mpls.trace PacketFilter::restricted_filter="vlan" >>output # @TEST-EXEC: cat packet_filter.log >>output # @TEST-EXEC: btest-diff output # @TEST-EXEC: btest-diff conn.log