mirror of
https://github.com/zeek/zeek.git
synced 2025-10-05 08:08:19 +00:00
Initial rework of packet filter framework.
- Large rework on packet filter framework to make many things easier. - Removed the PacketFilter::all_packets variable because it was confusing. - New variable (PacketFilter::enable_auto_protocol_capture_filters) to re-enable the old filtering model of only sniffing ports for analyzed protocols. - In progress plugin model for adding filtering mechanisms. - New default single item for capture_filters = { ["default"] = PacketFilter::default_capture_filter }; - Mechanism and helper functions to "shunt" traffic with filters. - Created the Protocols framework to assist with reworking how base protocol scripts are registered with DPD and other things. - Protocols framework creates BPF filters for registered analyzers. (if using PacketFilter framework in that mode).
This commit is contained in:
parent
600d015dab
commit
430cd9b146
18 changed files with 403 additions and 161 deletions
|
@ -196,12 +196,9 @@ function setup_peer(p: event_peer, node: Node)
|
||||||
request_remote_events(p, node$events);
|
request_remote_events(p, node$events);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( node?$capture_filter )
|
if ( node?$capture_filter && node$capture_filter != "" )
|
||||||
{
|
{
|
||||||
local filter = node$capture_filter;
|
local filter = node$capture_filter;
|
||||||
if ( filter == "" )
|
|
||||||
filter = PacketFilter::default_filter;
|
|
||||||
|
|
||||||
do_script_log(p, fmt("sending capture_filter: %s", filter));
|
do_script_log(p, fmt("sending capture_filter: %s", filter));
|
||||||
send_capture_filter(p, filter);
|
send_capture_filter(p, filter);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +1,4 @@
|
||||||
|
@load ./utils
|
||||||
@load ./main
|
@load ./main
|
||||||
|
@load ./shunt
|
||||||
@load ./netstats
|
@load ./netstats
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
##! This script supports how Bro sets it's BPF capture filter. By default
|
##! This script supports how Bro sets it's BPF capture filter. By default
|
||||||
##! Bro sets an unrestricted filter that allows all traffic. If a filter
|
##! Bro sets a capture filter that allows all traffic. If a filter
|
||||||
##! is set on the command line, that filter takes precedence over the default
|
##! is set on the command line, that filter takes precedence over the default
|
||||||
##! open filter and all filters defined in Bro scripts with the
|
##! open filter and all filters defined in Bro scripts with the
|
||||||
##! :bro:id:`capture_filters` and :bro:id:`restrict_filters` variables.
|
##! :bro:id:`capture_filters` and :bro:id:`restrict_filters` variables.
|
||||||
|
|
||||||
@load base/frameworks/notice
|
@load base/frameworks/notice
|
||||||
|
@load base/frameworks/protocols
|
||||||
|
|
||||||
module PacketFilter;
|
module PacketFilter;
|
||||||
|
|
||||||
|
@ -19,6 +20,9 @@ export {
|
||||||
|
|
||||||
## This notice is generated if a packet filter is fails to install.
|
## This notice is generated if a packet filter is fails to install.
|
||||||
Install_Failure,
|
Install_Failure,
|
||||||
|
|
||||||
|
## Generated when a notice takes too long to compile.
|
||||||
|
Too_Long_To_Compile_Filter
|
||||||
};
|
};
|
||||||
|
|
||||||
## The record type defining columns to be logged in the packet filter
|
## The record type defining columns to be logged in the packet filter
|
||||||
|
@ -41,94 +45,220 @@ export {
|
||||||
## Indicate if the filter was applied successfully.
|
## Indicate if the filter was applied successfully.
|
||||||
success: bool &log &default=T;
|
success: bool &log &default=T;
|
||||||
};
|
};
|
||||||
|
|
||||||
## By default, Bro will examine all packets. If this is set to false,
|
## The BPF filter that is used by default to define what traffic should
|
||||||
## it will dynamically build a BPF filter that only select protocols
|
## be captured. Filters defined in :bro:id:`restrict_filters` will still
|
||||||
## for which the user has loaded a corresponding analysis script.
|
## be applied to reduce the captured traffic.
|
||||||
## The latter used to be default for Bro versions < 2.0. That has now
|
const default_capture_filter = "ip or not ip" &redef;
|
||||||
## changed however to enable port-independent protocol analysis.
|
|
||||||
const all_packets = T &redef;
|
|
||||||
|
|
||||||
## Filter string which is unconditionally or'ed to the beginning of every
|
## Filter string which is unconditionally or'ed to the beginning of every
|
||||||
## dynamically built filter.
|
## dynamically built filter.
|
||||||
const unrestricted_filter = "" &redef;
|
const unrestricted_filter = "" &redef;
|
||||||
|
|
||||||
|
## The maximum amount of time that you'd like to allow for 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.
|
||||||
|
const max_filter_compile_time = 100msec &redef;
|
||||||
|
|
||||||
|
## Install a BPF filter to exclude some traffic. The filter should positively
|
||||||
|
## match what is to be excluded, it will be wrapped in a "not".
|
||||||
|
##
|
||||||
|
## filter_id: A somewhat arbitrary string that can be used to identify
|
||||||
|
## the filter.
|
||||||
|
##
|
||||||
|
## filter: A BPF expression of traffic that should be excluded.
|
||||||
|
##
|
||||||
|
## Returns: A boolean value to indicate if the fitler was successfully
|
||||||
|
## installed or not.
|
||||||
|
global exclude: function(filter_id: string, filter: string): bool;
|
||||||
|
|
||||||
|
## Install a temporary filter to traffic which should not be passed through
|
||||||
|
## the BPF filter. The filter should match the traffic you don't want
|
||||||
|
## to see (it will be wrapped in a "not" condition).
|
||||||
|
##
|
||||||
|
## filter_id: A somewhat arbitrary string that can be used to identify
|
||||||
|
## the filter.
|
||||||
|
##
|
||||||
|
## filter: A BPF expression of traffic that should be excluded.
|
||||||
|
##
|
||||||
|
## length: The duration for which this filter should be put in place.
|
||||||
|
##
|
||||||
|
## Returns: A boolean value to indicate if the filter was successfully
|
||||||
|
## installed or not.
|
||||||
|
global exclude_for: function(filter_id: string, filter: string, span: interval): bool;
|
||||||
|
|
||||||
## Call this function to build and install a new dynamically built
|
## Call this function to build and install a new dynamically built
|
||||||
## packet filter.
|
## packet filter.
|
||||||
global install: function();
|
global install: function();
|
||||||
|
|
||||||
|
## A data structure to represent filter generating factories.
|
||||||
|
type FilterFactory: record {
|
||||||
|
## A function that is directly called when generating the complete filter.
|
||||||
|
func : function();
|
||||||
|
};
|
||||||
|
|
||||||
|
## API function to register a new factory for dynamic restriction filters.
|
||||||
|
global register_filter_factory: function(ff: FilterFactory);
|
||||||
|
|
||||||
|
## Enables the old filtering approach of "only watch common ports for
|
||||||
|
## analyzed protocols".
|
||||||
|
## Unless you know what you are doing, leave this set to F.
|
||||||
|
const enable_auto_protocol_capture_filters = F &redef;
|
||||||
|
|
||||||
## This is where the default packet filter is stored and it should not
|
## This is where the default packet filter is stored and it should not
|
||||||
## normally be modified by users.
|
## normally be modified by users.
|
||||||
global default_filter = "<not set yet>";
|
global current_filter = "<not set yet>";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
global dynamic_restrict_filters: table[string] of string = {};
|
||||||
|
|
||||||
|
# Set the default capture filter.
|
||||||
|
redef capture_filters += { ["default"] = default_capture_filter };
|
||||||
|
|
||||||
|
# Track if a filter is currenlty building so functions that would ultimately
|
||||||
|
# install a filter immediately can still be used buy they won't try to build or
|
||||||
|
# install the filter.
|
||||||
|
global currently_building = F;
|
||||||
|
|
||||||
|
global filter_factories: set[FilterFactory] = {};
|
||||||
|
|
||||||
redef enum PcapFilterID += {
|
redef enum PcapFilterID += {
|
||||||
DefaultPcapFilter,
|
DefaultPcapFilter,
|
||||||
|
FilterTester,
|
||||||
};
|
};
|
||||||
|
|
||||||
function combine_filters(lfilter: string, rfilter: string, op: string): string
|
function test_filter(filter: string): bool
|
||||||
{
|
{
|
||||||
if ( lfilter == "" && rfilter == "" )
|
if ( ! precompile_pcap_filter(FilterTester, filter) )
|
||||||
return "";
|
{
|
||||||
else if ( lfilter == "" )
|
# The given filter was invalid
|
||||||
return rfilter;
|
# TODO: generate a notice.
|
||||||
else if ( rfilter == "" )
|
return F;
|
||||||
return lfilter;
|
}
|
||||||
else
|
return T;
|
||||||
return fmt("(%s) %s (%s)", lfilter, op, rfilter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function build_default_filter(): string
|
event bro_init() &priority=6
|
||||||
|
{
|
||||||
|
Log::create_stream(PacketFilter::LOG, [$columns=Info]);
|
||||||
|
|
||||||
|
# Preverify the capture and restrict filters to give more granular failure messages.
|
||||||
|
for ( id in capture_filters )
|
||||||
|
{
|
||||||
|
if ( ! test_filter(capture_filters[id]) )
|
||||||
|
Reporter::fatal(fmt("Invalid capture_filter named '%s' - '%s'", id, capture_filters[id]));
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( id in restrict_filters )
|
||||||
|
{
|
||||||
|
if ( ! test_filter(restrict_filters[id]) )
|
||||||
|
Reporter::fatal(fmt("Invalid restrict filter named '%s' - '%s'", id, restrict_filters[id]));
|
||||||
|
}
|
||||||
|
|
||||||
|
install();
|
||||||
|
}
|
||||||
|
|
||||||
|
function register_filter_factory(ff: FilterFactory)
|
||||||
|
{
|
||||||
|
add filter_factories[ff];
|
||||||
|
}
|
||||||
|
|
||||||
|
event remove_dynamic_filter(filter_id: string)
|
||||||
|
{
|
||||||
|
if ( filter_id in dynamic_restrict_filters )
|
||||||
|
{
|
||||||
|
delete dynamic_restrict_filters[filter_id];
|
||||||
|
install();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function exclude(filter_id: string, filter: string): bool
|
||||||
|
{
|
||||||
|
if ( ! test_filter(filter) )
|
||||||
|
return F;
|
||||||
|
|
||||||
|
dynamic_restrict_filters[filter_id] = filter;
|
||||||
|
install();
|
||||||
|
return T;
|
||||||
|
}
|
||||||
|
|
||||||
|
function exclude_for(filter_id: string, filter: string, span: interval): bool
|
||||||
|
{
|
||||||
|
if ( exclude(filter_id, filter) )
|
||||||
|
{
|
||||||
|
schedule span { remove_dynamic_filter(filter_id) };
|
||||||
|
return T;
|
||||||
|
}
|
||||||
|
return F;
|
||||||
|
}
|
||||||
|
|
||||||
|
function build(): string
|
||||||
{
|
{
|
||||||
if ( cmd_line_bpf_filter != "" )
|
if ( cmd_line_bpf_filter != "" )
|
||||||
# Return what the user specified on the command line;
|
# Return what the user specified on the command line;
|
||||||
return cmd_line_bpf_filter;
|
return cmd_line_bpf_filter;
|
||||||
|
|
||||||
if ( all_packets )
|
|
||||||
{
|
|
||||||
# Return an "always true" filter.
|
|
||||||
if ( bro_has_ipv6() )
|
|
||||||
return "ip or not ip";
|
|
||||||
else
|
|
||||||
return "not ip6";
|
|
||||||
}
|
|
||||||
|
|
||||||
# Build filter dynamically.
|
|
||||||
|
|
||||||
# First the capture_filter.
|
currently_building = T;
|
||||||
|
|
||||||
|
# Install the default capture filter.
|
||||||
local cfilter = "";
|
local cfilter = "";
|
||||||
for ( id in capture_filters )
|
|
||||||
cfilter = combine_filters(cfilter, capture_filters[id], "or");
|
if ( |capture_filters| == 0 && ! enable_auto_protocol_capture_filters )
|
||||||
|
cfilter = default_capture_filter;
|
||||||
|
|
||||||
# Then the restrict_filter.
|
for ( id in capture_filters )
|
||||||
|
cfilter = combine_filters(cfilter, "or", capture_filters[id]);
|
||||||
|
|
||||||
|
if ( enable_auto_protocol_capture_filters )
|
||||||
|
cfilter = combine_filters(cfilter, "or", Protocols::to_bpf());
|
||||||
|
|
||||||
|
# Apply the restriction filters.
|
||||||
local rfilter = "";
|
local rfilter = "";
|
||||||
for ( id in restrict_filters )
|
for ( id in restrict_filters )
|
||||||
rfilter = combine_filters(rfilter, restrict_filters[id], "and");
|
rfilter = combine_filters(rfilter, "and", restrict_filters[id]);
|
||||||
|
|
||||||
|
# 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 factory based filters.
|
||||||
|
for ( factory in filter_factories )
|
||||||
|
{
|
||||||
|
factory$func();
|
||||||
|
}
|
||||||
|
|
||||||
# Finally, join them into one filter.
|
# Finally, join them into one filter.
|
||||||
local filter = combine_filters(rfilter, cfilter, "and");
|
local filter = combine_filters(cfilter, "and", rfilter);
|
||||||
|
|
||||||
if ( unrestricted_filter != "" )
|
if ( unrestricted_filter != "" )
|
||||||
filter = combine_filters(unrestricted_filter, filter, "or");
|
filter = combine_filters(unrestricted_filter, "or", filter);
|
||||||
|
|
||||||
# Exclude IPv6 if we don't support it.
|
|
||||||
if ( ! bro_has_ipv6() )
|
|
||||||
filter = combine_filters(filter, "not ip6", "and");
|
|
||||||
|
|
||||||
|
currently_building = F;
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
function install()
|
function install()
|
||||||
{
|
{
|
||||||
default_filter = build_default_filter();
|
if ( currently_building )
|
||||||
|
return;
|
||||||
if ( ! precompile_pcap_filter(DefaultPcapFilter, default_filter) )
|
|
||||||
|
current_filter = build();
|
||||||
|
|
||||||
|
#local ts = current_time();
|
||||||
|
if ( ! precompile_pcap_filter(DefaultPcapFilter, current_filter) )
|
||||||
{
|
{
|
||||||
NOTICE([$note=Compile_Failure,
|
NOTICE([$note=Compile_Failure,
|
||||||
$msg=fmt("Compiling packet filter failed"),
|
$msg=fmt("Compiling packet filter failed"),
|
||||||
$sub=default_filter]);
|
$sub=current_filter]);
|
||||||
Reporter::fatal(fmt("Bad pcap filter '%s'", default_filter));
|
Reporter::fatal(fmt("Bad pcap filter '%s'", current_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.
|
# Do an audit log for the packet filter.
|
||||||
local info: Info;
|
local info: Info;
|
||||||
info$ts = network_time();
|
info$ts = network_time();
|
||||||
|
@ -138,7 +268,7 @@ function install()
|
||||||
info$ts = current_time();
|
info$ts = current_time();
|
||||||
info$init = T;
|
info$init = T;
|
||||||
}
|
}
|
||||||
info$filter = default_filter;
|
info$filter = current_filter;
|
||||||
|
|
||||||
if ( ! install_pcap_filter(DefaultPcapFilter) )
|
if ( ! install_pcap_filter(DefaultPcapFilter) )
|
||||||
{
|
{
|
||||||
|
@ -146,15 +276,10 @@ function install()
|
||||||
info$success = F;
|
info$success = F;
|
||||||
NOTICE([$note=Install_Failure,
|
NOTICE([$note=Install_Failure,
|
||||||
$msg=fmt("Installing packet filter failed"),
|
$msg=fmt("Installing packet filter failed"),
|
||||||
$sub=default_filter]);
|
$sub=current_filter]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if ( reading_live_traffic() || reading_traces() )
|
if ( reading_live_traffic() || reading_traces() )
|
||||||
Log::write(PacketFilter::LOG, info);
|
Log::write(PacketFilter::LOG, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
event bro_init() &priority=10
|
|
||||||
{
|
|
||||||
Log::create_stream(PacketFilter::LOG, [$columns=Info]);
|
|
||||||
PacketFilter::install();
|
|
||||||
}
|
|
||||||
|
|
74
scripts/base/frameworks/packet-filter/shunt.bro
Normal file
74
scripts/base/frameworks/packet-filter/shunt.bro
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
@load base/frameworks/notice
|
||||||
|
|
||||||
|
module PacketFilter;
|
||||||
|
|
||||||
|
export {
|
||||||
|
const max_bpf_shunts = 100 &redef;
|
||||||
|
|
||||||
|
global shunt_conn: function(id: conn_id): bool;
|
||||||
|
|
||||||
|
redef enum Notice::Type += {
|
||||||
|
## Indicative that :bro:id:`max_bpf_shunts` connections are already
|
||||||
|
## being shunted with BPF filters and no more are allowed.
|
||||||
|
No_More_Conn_Shunts_Available,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
global shunted_conns: set[conn_id];
|
||||||
|
global shunted_conns_non_flag_tracking: set[conn_id];
|
||||||
|
|
||||||
|
function conn_shunt_filters()
|
||||||
|
{
|
||||||
|
# TODO: this could wrongly match if a connection happens with the ports reversed.
|
||||||
|
local filter = "";
|
||||||
|
local ipv4_tcp_filter = "";
|
||||||
|
for ( id in shunted_conns )
|
||||||
|
{
|
||||||
|
local prot = get_port_transport_proto(id$resp_p);
|
||||||
|
|
||||||
|
# TODO: add ipv6
|
||||||
|
#if ( prot == udp ) #|| is_ipv6_addr(id$orig_h) )
|
||||||
|
# {
|
||||||
|
# next;
|
||||||
|
# shunt_for()
|
||||||
|
# }
|
||||||
|
|
||||||
|
if ( prot == tcp )
|
||||||
|
ipv4_tcp_filter = combine_filters(ipv4_tcp_filter, "and", fmt("host %s and port %d and host %s and port %d and %s", id$orig_h, id$orig_p, id$resp_h, id$resp_p, prot));
|
||||||
|
}
|
||||||
|
|
||||||
|
ipv4_tcp_filter = combine_filters(ipv4_tcp_filter, "and", "tcp[tcpflags] & (tcp-syn|tcp-fin|tcp-rst) == 0");
|
||||||
|
|
||||||
|
if ( ipv4_tcp_filter == "" )
|
||||||
|
return;
|
||||||
|
PacketFilter::exclude("conn_shunt_filters", ipv4_tcp_filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
event bro_init() &priority=5
|
||||||
|
{
|
||||||
|
register_filter_factory([
|
||||||
|
$func()={ return conn_shunt_filters(); }
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function shunt_conn(id: conn_id): bool
|
||||||
|
{
|
||||||
|
if ( |shunted_conns| + |shunted_conns_non_flag_tracking| > max_bpf_shunts )
|
||||||
|
{
|
||||||
|
NOTICE([$note=No_More_Conn_Shunts_Available,
|
||||||
|
$msg=fmt("%d BPF shunts are in place and no more will be added until space clears.", max_bpf_shunts)]);
|
||||||
|
return F;
|
||||||
|
}
|
||||||
|
|
||||||
|
add shunted_conns[id];
|
||||||
|
install();
|
||||||
|
return T;
|
||||||
|
}
|
||||||
|
|
||||||
|
event connection_state_remove(c: connection) &priority=-5
|
||||||
|
{
|
||||||
|
# Don't rebuild the filter right away because the packet filter framework will check every few minutes
|
||||||
|
# and update the filter if things have changed.
|
||||||
|
if ( c$id in shunted_conns )
|
||||||
|
delete shunted_conns[c$id];
|
||||||
|
}
|
43
scripts/base/frameworks/packet-filter/utils.bro
Normal file
43
scripts/base/frameworks/packet-filter/utils.bro
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
module PacketFilter;
|
||||||
|
|
||||||
|
export {
|
||||||
|
## Takes a :bro:type:`port` and returns a BPF expression which will
|
||||||
|
## match the port.
|
||||||
|
##
|
||||||
|
## p: The port.
|
||||||
|
##
|
||||||
|
## Returns: A valid BPF filter string for matching the port.
|
||||||
|
global port_to_bpf: function(p: port): string;
|
||||||
|
|
||||||
|
## Combines two valid BPF filter strings with a string based operator
|
||||||
|
## to form a new filter.
|
||||||
|
##
|
||||||
|
## lfilter: Filter which will go on the left side.
|
||||||
|
##
|
||||||
|
## op: Operation being applied (typically "or" or "and").
|
||||||
|
##
|
||||||
|
## rfilter: Filter which will go on the right side.
|
||||||
|
##
|
||||||
|
## Returns: A new string representing the two filters combined with
|
||||||
|
## the operator. Either filter being an empty string will
|
||||||
|
## still result in a valid filter.
|
||||||
|
global combine_filters: function(lfilter: string, op: string, rfilter: string): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function port_to_bpf(p: port): string
|
||||||
|
{
|
||||||
|
local tp = get_port_transport_proto(p);
|
||||||
|
return cat(tp, " and ", fmt("port %d", p));
|
||||||
|
}
|
||||||
|
|
||||||
|
function combine_filters(lfilter: string, op: string, rfilter: string): string
|
||||||
|
{
|
||||||
|
if ( lfilter == "" && rfilter == "" )
|
||||||
|
return "";
|
||||||
|
else if ( lfilter == "" )
|
||||||
|
return rfilter;
|
||||||
|
else if ( rfilter == "" )
|
||||||
|
return lfilter;
|
||||||
|
else
|
||||||
|
return fmt("(%s) %s (%s)", lfilter, op, rfilter);
|
||||||
|
}
|
1
scripts/base/frameworks/protocols/__load__.bro
Normal file
1
scripts/base/frameworks/protocols/__load__.bro
Normal file
|
@ -0,0 +1 @@
|
||||||
|
@load ./main
|
49
scripts/base/frameworks/protocols/main.bro
Normal file
49
scripts/base/frameworks/protocols/main.bro
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
|
||||||
|
@load base/frameworks/packet-filter
|
||||||
|
|
||||||
|
module Protocols;
|
||||||
|
|
||||||
|
export {
|
||||||
|
const common_ports: table[string] of set[port] = {} &redef;
|
||||||
|
|
||||||
|
## Automatically creates a BPF filter for the specified protocol based
|
||||||
|
## on the data supplied for the protocol in the :bro:id:`common_ports`
|
||||||
|
## variable.
|
||||||
|
##
|
||||||
|
## protocol: A string representation for a protocol, e.g. "HTTP"
|
||||||
|
##
|
||||||
|
## Returns: BPF filter string.
|
||||||
|
global protocol_to_bpf: function(protocol: string): string;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
function protocol_to_bpf(protocol: string): string
|
||||||
|
{
|
||||||
|
# Return an empty string if an undefined protocol was given.
|
||||||
|
if ( protocol !in common_ports )
|
||||||
|
return "";
|
||||||
|
|
||||||
|
local output = "";
|
||||||
|
for ( one_port in common_ports[protocol] )
|
||||||
|
output = PacketFilter::combine_filters(output, "or", PacketFilter::port_to_bpf(one_port));
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
function to_bpf(): string
|
||||||
|
{
|
||||||
|
local output = "";
|
||||||
|
for ( p in common_ports )
|
||||||
|
output = PacketFilter::combine_filters(output, "or", protocol_to_bpf(p));
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -607,19 +607,6 @@ global signature_files = "" &add_func = add_signature_file;
|
||||||
## ``p0f`` fingerprint file to use. Will be searched relative to ``BRO_PATH``.
|
## ``p0f`` fingerprint file to use. Will be searched relative to ``BRO_PATH``.
|
||||||
const passive_fingerprint_file = "base/misc/p0f.fp" &redef;
|
const passive_fingerprint_file = "base/misc/p0f.fp" &redef;
|
||||||
|
|
||||||
# todo::testing to see if I can remove these without causing problems.
|
|
||||||
#const ftp = 21/tcp;
|
|
||||||
#const ssh = 22/tcp;
|
|
||||||
#const telnet = 23/tcp;
|
|
||||||
#const smtp = 25/tcp;
|
|
||||||
#const domain = 53/tcp; # note, doesn't include UDP version
|
|
||||||
#const gopher = 70/tcp;
|
|
||||||
#const finger = 79/tcp;
|
|
||||||
#const http = 80/tcp;
|
|
||||||
#const ident = 113/tcp;
|
|
||||||
#const bgp = 179/tcp;
|
|
||||||
#const rlogin = 513/tcp;
|
|
||||||
|
|
||||||
# TCP values for :bro:see:`endpoint` *state* field.
|
# TCP values for :bro:see:`endpoint` *state* field.
|
||||||
# todo::these should go into an enum to make them autodoc'able.
|
# todo::these should go into an enum to make them autodoc'able.
|
||||||
const TCP_INACTIVE = 0; ##< Endpoint is still inactive.
|
const TCP_INACTIVE = 0; ##< Endpoint is still inactive.
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
@load base/frameworks/metrics
|
@load base/frameworks/metrics
|
||||||
@load base/frameworks/intel
|
@load base/frameworks/intel
|
||||||
@load base/frameworks/reporter
|
@load base/frameworks/reporter
|
||||||
|
@load base/frameworks/protocols
|
||||||
|
|
||||||
@load base/protocols/conn
|
@load base/protocols/conn
|
||||||
@load base/protocols/dns
|
@load base/protocols/dns
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##! Base DNS analysis script which tracks and logs DNS queries along with
|
##! Base DNS analysis script which tracks and logs DNS queries along with
|
||||||
##! their responses.
|
##! their responses.
|
||||||
|
|
||||||
|
@load base/frameworks/protocols
|
||||||
@load ./consts
|
@load ./consts
|
||||||
|
|
||||||
module DNS;
|
module DNS;
|
||||||
|
@ -109,23 +110,11 @@ redef record connection += {
|
||||||
dns_state: State &optional;
|
dns_state: State &optional;
|
||||||
};
|
};
|
||||||
|
|
||||||
# DPD configuration.
|
# Not attaching ANALYZER_DNS_UDP_BINPAC and ANALYZER_DNS_TCP_BINPAC right now.
|
||||||
redef capture_filters += {
|
global analyzers = { ANALYZER_DNS };
|
||||||
["dns"] = "port 53",
|
redef Protocols::analyzer_map["DNS"] = analyzers;
|
||||||
["mdns"] = "udp and port 5353",
|
global ports = { 53/udp, 53/tcp, 137/udp, 5353/udp, 5355/udp };
|
||||||
["llmns"] = "udp and port 5355",
|
redef Protocols::common_ports["DNS"] = ports;
|
||||||
["netbios-ns"] = "udp port 137",
|
|
||||||
};
|
|
||||||
|
|
||||||
const dns_ports = { 53/udp, 53/tcp, 137/udp, 5353/udp, 5355/udp };
|
|
||||||
redef dpd_config += { [ANALYZER_DNS] = [$ports = dns_ports] };
|
|
||||||
|
|
||||||
const dns_udp_ports = { 53/udp, 137/udp, 5353/udp, 5355/udp };
|
|
||||||
const dns_tcp_ports = { 53/tcp };
|
|
||||||
redef dpd_config += { [ANALYZER_DNS_UDP_BINPAC] = [$ports = dns_udp_ports] };
|
|
||||||
redef dpd_config += { [ANALYZER_DNS_TCP_BINPAC] = [$ports = dns_tcp_ports] };
|
|
||||||
|
|
||||||
redef likely_server_ports += { 53/udp, 53/tcp, 137/udp, 5353/udp, 5355/udp };
|
|
||||||
|
|
||||||
event bro_init() &priority=5
|
event bro_init() &priority=5
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,10 +3,12 @@
|
||||||
##! will take on the full path that the client is at along with the requested
|
##! will take on the full path that the client is at along with the requested
|
||||||
##! file name.
|
##! file name.
|
||||||
|
|
||||||
|
@load base/frameworks/protocols
|
||||||
@load ./utils-commands
|
@load ./utils-commands
|
||||||
@load base/utils/paths
|
@load base/utils/paths
|
||||||
@load base/utils/numbers
|
@load base/utils/numbers
|
||||||
|
|
||||||
|
|
||||||
module FTP;
|
module FTP;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
@ -92,12 +94,10 @@ redef record connection += {
|
||||||
ftp: Info &optional;
|
ftp: Info &optional;
|
||||||
};
|
};
|
||||||
|
|
||||||
# Configure DPD
|
global analyzers = { ANALYZER_FTP };
|
||||||
const ports = { 21/tcp } &redef;
|
redef Protocols::analyzer_map["FTP"] = analyzers;
|
||||||
redef capture_filters += { ["ftp"] = "port 21" };
|
global ports = { 21/tcp };
|
||||||
redef dpd_config += { [ANALYZER_FTP] = [$ports = ports] };
|
redef Protocols::common_ports["FTP"] = ports;
|
||||||
|
|
||||||
redef likely_server_ports += { 21/tcp };
|
|
||||||
|
|
||||||
# Establish the variable for tracking expected connections.
|
# Establish the variable for tracking expected connections.
|
||||||
global ftp_data_expected: table[addr, port] of Info &create_expire=5mins;
|
global ftp_data_expected: table[addr, port] of Info &create_expire=5mins;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
##! to log request/response pairs and all relevant metadata together in
|
##! to log request/response pairs and all relevant metadata together in
|
||||||
##! a single record.
|
##! a single record.
|
||||||
|
|
||||||
|
@load base/frameworks/protocols
|
||||||
@load base/utils/numbers
|
@load base/utils/numbers
|
||||||
@load base/utils/files
|
@load base/utils/files
|
||||||
|
|
||||||
|
@ -110,17 +111,15 @@ event bro_init() &priority=5
|
||||||
Log::create_stream(HTTP::LOG, [$columns=Info, $ev=log_http]);
|
Log::create_stream(HTTP::LOG, [$columns=Info, $ev=log_http]);
|
||||||
}
|
}
|
||||||
|
|
||||||
# DPD configuration.
|
|
||||||
const ports = {
|
global analyzers = { ANALYZER_HTTP, ANALYZER_HTTP_BINPAC };
|
||||||
80/tcp, 81/tcp, 631/tcp, 1080/tcp, 3138/tcp,
|
redef Protocols::analyzer_map["HTTP"] = analyzers;
|
||||||
8000/tcp, 8080/tcp, 8888/tcp,
|
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 = ports],
|
#redef dpd_config += {
|
||||||
};
|
# [[ANALYZER_HTTP, ANALYZER_HTTP_BINPAC]] = [$ports = Protocols::common_ports["HTTP"]],
|
||||||
redef capture_filters += {
|
#};
|
||||||
["http"] = "tcp and port (80 or 81 or 631 or 1080 or 3138 or 8000 or 8080 or 8888)"
|
|
||||||
};
|
|
||||||
|
|
||||||
redef likely_server_ports += {
|
redef likely_server_ports += {
|
||||||
80/tcp, 81/tcp, 631/tcp, 1080/tcp, 3138/tcp,
|
80/tcp, 81/tcp, 631/tcp, 1080/tcp, 3138/tcp,
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
##! IRC commands along with the associated response and some additional
|
##! IRC commands along with the associated response and some additional
|
||||||
##! metadata about the connection if it's available.
|
##! metadata about the connection if it's available.
|
||||||
|
|
||||||
|
@load base/frameworks/protocols
|
||||||
|
|
||||||
module IRC;
|
module IRC;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
@ -36,17 +38,10 @@ redef record connection += {
|
||||||
irc: Info &optional;
|
irc: Info &optional;
|
||||||
};
|
};
|
||||||
|
|
||||||
# Some common IRC ports.
|
global analyzers = { ANALYZER_IRC };
|
||||||
redef capture_filters += { ["irc-6666"] = "port 6666" };
|
redef Protocols::analyzer_map["IRC"] = analyzers;
|
||||||
redef capture_filters += { ["irc-6667"] = "port 6667" };
|
global ports = { 6666/tcp, 6667/tcp, 6668/tcp, 6669/tcp, 7000/tcp };
|
||||||
redef capture_filters += { ["irc-6668"] = "port 6668" };
|
redef Protocols::common_ports["IRC"] = ports;
|
||||||
redef capture_filters += { ["irc-6669"] = "port 6669" };
|
|
||||||
|
|
||||||
# DPD configuration.
|
|
||||||
const irc_ports = { 6666/tcp, 6667/tcp, 6668/tcp, 6669/tcp };
|
|
||||||
redef dpd_config += { [ANALYZER_IRC] = [$ports = irc_ports] };
|
|
||||||
|
|
||||||
redef likely_server_ports += { 6666/tcp, 6667/tcp, 6668/tcp, 6669/tcp };
|
|
||||||
|
|
||||||
event bro_init() &priority=5
|
event bro_init() &priority=5
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
@load base/frameworks/notice
|
@load base/frameworks/notice
|
||||||
|
@load base/frameworks/protocols
|
||||||
@load base/utils/addrs
|
@load base/utils/addrs
|
||||||
@load base/utils/directions-and-hosts
|
@load base/utils/directions-and-hosts
|
||||||
|
|
||||||
|
@ -66,11 +67,9 @@ redef record connection += {
|
||||||
smtp_state: State &optional;
|
smtp_state: State &optional;
|
||||||
};
|
};
|
||||||
|
|
||||||
# Configure DPD
|
global analyzers = { ANALYZER_SMTP };
|
||||||
redef capture_filters += { ["smtp"] = "tcp port 25 or tcp port 587" };
|
redef Protocols::analyzer_map["SMTP"] = analyzers;
|
||||||
redef dpd_config += { [ANALYZER_SMTP] = [$ports = ports] };
|
redef Protocols::common_ports["SMTP"] = ports;
|
||||||
|
|
||||||
redef likely_server_ports += { 25/tcp, 587/tcp };
|
|
||||||
|
|
||||||
event bro_init() &priority=5
|
event bro_init() &priority=5
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
##! is not attempted if the connection size analyzer isn't enabled.
|
##! is not attempted if the connection size analyzer isn't enabled.
|
||||||
|
|
||||||
@load base/frameworks/notice
|
@load base/frameworks/notice
|
||||||
|
@load base/frameworks/protocols
|
||||||
@load base/utils/site
|
@load base/utils/site
|
||||||
@load base/utils/thresholds
|
@load base/utils/thresholds
|
||||||
@load base/utils/conn-ids
|
@load base/utils/conn-ids
|
||||||
|
@ -73,11 +74,10 @@ export {
|
||||||
global log_ssh: event(rec: Info);
|
global log_ssh: event(rec: Info);
|
||||||
}
|
}
|
||||||
|
|
||||||
# Configure DPD and the packet filter
|
global analyzers = { ANALYZER_SSH };
|
||||||
redef capture_filters += { ["ssh"] = "tcp port 22" };
|
redef Protocols::analyzer_map["SSH"] = analyzers;
|
||||||
redef dpd_config += { [ANALYZER_SSH] = [$ports = set(22/tcp)] };
|
global ports = { 22/tcp };
|
||||||
|
redef Protocols::common_ports["SSH"] = ports;
|
||||||
redef likely_server_ports += { 22/tcp };
|
|
||||||
|
|
||||||
redef record connection += {
|
redef record connection += {
|
||||||
ssh: Info &optional;
|
ssh: Info &optional;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##! Base SSL analysis script. This script logs information about the SSL/TLS
|
##! Base SSL analysis script. This script logs information about the SSL/TLS
|
||||||
##! handshaking and encryption establishment process.
|
##! handshaking and encryption establishment process.
|
||||||
|
|
||||||
|
@load base/frameworks/protocols
|
||||||
@load ./consts
|
@load ./consts
|
||||||
|
|
||||||
module SSL;
|
module SSL;
|
||||||
|
@ -70,35 +71,13 @@ event bro_init() &priority=5
|
||||||
{
|
{
|
||||||
Log::create_stream(SSL::LOG, [$columns=Info, $ev=log_ssl]);
|
Log::create_stream(SSL::LOG, [$columns=Info, $ev=log_ssl]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
global analyzers = { ANALYZER_SSL };
|
||||||
|
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 capture_filters += {
|
|
||||||
["ssl"] = "tcp port 443",
|
|
||||||
["nntps"] = "tcp port 563",
|
|
||||||
["imap4-ssl"] = "tcp port 585",
|
|
||||||
["sshell"] = "tcp port 614",
|
|
||||||
["ldaps"] = "tcp port 636",
|
|
||||||
["ftps-data"] = "tcp port 989",
|
|
||||||
["ftps"] = "tcp port 990",
|
|
||||||
["telnets"] = "tcp port 992",
|
|
||||||
["imaps"] = "tcp port 993",
|
|
||||||
["ircs"] = "tcp port 994",
|
|
||||||
["pop3s"] = "tcp port 995",
|
|
||||||
["xmpps"] = "tcp port 5223",
|
|
||||||
};
|
|
||||||
|
|
||||||
const ports = {
|
|
||||||
443/tcp, 563/tcp, 585/tcp, 614/tcp, 636/tcp,
|
|
||||||
989/tcp, 990/tcp, 992/tcp, 993/tcp, 995/tcp, 5223/tcp
|
|
||||||
};
|
|
||||||
|
|
||||||
redef dpd_config += {
|
|
||||||
[[ANALYZER_SSL]] = [$ports = ports]
|
|
||||||
};
|
|
||||||
|
|
||||||
redef likely_server_ports += {
|
|
||||||
443/tcp, 563/tcp, 585/tcp, 614/tcp, 636/tcp,
|
|
||||||
989/tcp, 990/tcp, 992/tcp, 993/tcp, 995/tcp, 5223/tcp
|
|
||||||
};
|
|
||||||
|
|
||||||
function set_session(c: connection)
|
function set_session(c: connection)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
##! Core script support for logging syslog messages. This script represents
|
##! Core script support for logging syslog messages. This script represents
|
||||||
##! one syslog message as one logged record.
|
##! one syslog message as one logged record.
|
||||||
|
|
||||||
|
@load base/frameworks/protocols
|
||||||
@load ./consts
|
@load ./consts
|
||||||
|
|
||||||
module Syslog;
|
module Syslog;
|
||||||
|
@ -24,11 +25,10 @@ export {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
redef capture_filters += { ["syslog"] = "port 514" };
|
global analyzers = { ANALYZER_SYSLOG_BINPAC };
|
||||||
const ports = { 514/udp } &redef;
|
redef Protocols::analyzer_map["SYSLOG"] = analyzers;
|
||||||
redef dpd_config += { [ANALYZER_SYSLOG_BINPAC] = [$ports = ports] };
|
global ports = { 514/udp };
|
||||||
|
redef Protocols::common_ports["SYSLOG"] = ports;
|
||||||
redef likely_server_ports += { 514/udp };
|
|
||||||
|
|
||||||
redef record connection += {
|
redef record connection += {
|
||||||
syslog: Info &optional;
|
syslog: Info &optional;
|
||||||
|
|
|
@ -3,7 +3,9 @@
|
||||||
|
|
||||||
## This normally isn't used because of the default open packet filter
|
## This normally isn't used because of the default open packet filter
|
||||||
## but we set it anyway in case the user is using a packet filter.
|
## but we set it anyway in case the user is using a packet filter.
|
||||||
redef capture_filters += { ["frag"] = "(ip[6:2] & 0x3fff != 0) and tcp" };
|
## Note: This was removed because the default model now is to have a wide
|
||||||
|
## open packet filter.
|
||||||
|
#redef capture_filters += { ["frag"] = "(ip[6:2] & 0x3fff != 0) and tcp" };
|
||||||
|
|
||||||
## Shorten the fragment timeout from never expiring to expiring fragments after
|
## Shorten the fragment timeout from never expiring to expiring fragments after
|
||||||
## five minutes.
|
## five minutes.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue