Merge remote-tracking branch 'origin/topic/robin/plugins'

This commit is contained in:
Robin Sommer 2013-06-04 20:58:16 -07:00
commit da3eb2d3e2
464 changed files with 14585 additions and 12210 deletions

View file

@ -12,7 +12,7 @@
broPolicies=${BRO_SCRIPT_SOURCE_PATH}:${BRO_SCRIPT_SOURCE_PATH}/policy:${BRO_SCRIPT_SOURCE_PATH}/site
broGenPolicies=${CMAKE_BINARY_DIR}/src
broGenPolicies=${CMAKE_BINARY_DIR}/scripts
installedPolicies=${BRO_SCRIPT_INSTALL_PATH}:${BRO_SCRIPT_INSTALL_PATH}/site

View file

@ -45,12 +45,6 @@ macro(REST_TARGET srcDir broInput)
set(sumTextSrc ${absSrcPath})
set(ogSourceFile ${absSrcPath})
if (${extension} STREQUAL ".bif.bro")
set(ogSourceFile ${BIF_SRC_DIR}/${basename})
# the summary text is taken at configure time, but .bif.bro files
# may not have been generated yet, so read .bif file instead
set(sumTextSrc ${ogSourceFile})
endif ()
if (NOT relDstDir)
set(docName "${basename}")
@ -70,7 +64,7 @@ macro(REST_TARGET srcDir broInput)
if (NOT "${ARGN}" STREQUAL "")
set(group ${ARGN})
elseif (${extension} STREQUAL ".bif.bro")
elseif (${broInput} MATCHES "\\.bif\\.bro$")
set(group bifs)
elseif (relDstDir)
set(group ${relDstDir}/index)

View file

@ -16,15 +16,63 @@ rest_target(${CMAKE_CURRENT_SOURCE_DIR} example.bro internal)
rest_target(${psd} base/init-default.bro internal)
rest_target(${psd} base/init-bare.bro internal)
rest_target(${CMAKE_BINARY_DIR}/src base/bro.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/src base/const.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/src base/event.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/src base/file_analysis.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/src base/input.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/src base/logging.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/src base/reporter.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/src base/strings.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/src base/types.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/analyzer.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/bro.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/const.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/event.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/file_analysis.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/input.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/logging.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_ARP.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_AYIYA.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_BackDoor.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_BitTorrent.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_ConnSize.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_DCE_RPC.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_DHCP.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_DNS.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_FTP.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_FTP.functions.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_File.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_Finger.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_GTPv1.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_Gnutella.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_HTTP.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_HTTP.functions.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_ICMP.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_IRC.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_Ident.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_InterConn.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_Login.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_Login.functions.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_MIME.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_Modbus.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_NCP.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_NTP.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_NetBIOS.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_NetBIOS.functions.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_NetFlow.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_PIA.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_POP3.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_RPC.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_SMB.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_SMTP.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_SMTP.functions.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_SOCKS.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_SSH.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_SSL.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_SSL.functions.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_SteppingStone.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_Syslog.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_TCP.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_TCP.functions.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_Teredo.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_UDP.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/plugins/Bro_ZIP.events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/reporter.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/strings.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/scripts base/bif/types.bif.bro)
rest_target(${psd} base/frameworks/analyzer/main.bro)
rest_target(${psd} base/frameworks/cluster/main.bro)
rest_target(${psd} base/frameworks/cluster/nodes/manager.bro)
rest_target(${psd} base/frameworks/cluster/nodes/proxy.bro)
@ -146,7 +194,6 @@ rest_target(${psd} policy/frameworks/software/vulnerable.bro)
rest_target(${psd} policy/integration/barnyard2/main.bro)
rest_target(${psd} policy/integration/barnyard2/types.bro)
rest_target(${psd} policy/integration/collective-intel/main.bro)
rest_target(${psd} policy/misc/analysis-groups.bro)
rest_target(${psd} policy/misc/app-metrics.bro)
rest_target(${psd} policy/misc/capture-loss.bro)
rest_target(${psd} policy/misc/detect-traceroute/main.bro)

View file

@ -54,11 +54,11 @@ global example_ports = {
443/tcp, 562/tcp,
} &redef;
# redefinitions of "dpd_config" are self-documenting and
# go into the generated doc's "Port Analysis" section
redef dpd_config += {
[ANALYZER_SSL] = [$ports = example_ports]
};
event bro_init()
{
Analyzer::register_for_ports(Analyzer::ANALYZER_SSL, example_ports);
}
# redefinitions of "Notice::Type" are self-documenting, but
# more information can be supplied in two different ways

View file

@ -67,12 +67,12 @@ sourcedir=${thisdir}/../..
echo "$statictext" > $outfile
bifs=`( cd ${sourcedir}/src && find . -name \*\.bif | sort )`
bifs=`( cd ${sourcedir}/build/scripts/base && find . -name \*\.bif.bro | sort )`
for file in $bifs
do
f=${file:2}.bro
echo "rest_target(\${CMAKE_BINARY_DIR}/src base/$f)" >> $outfile
f=${file:2}
echo "rest_target(\${CMAKE_BINARY_DIR}/scripts base/$f)" >> $outfile
done
scriptfiles=`( cd ${sourcedir}/scripts && find . -name \*\.bro | sort )`

View file

@ -0,0 +1 @@
@load ./main

View file

@ -0,0 +1,181 @@
##! Framework for managing Bro's protocol analyzers.
##!
##! The analyzer framework allows to dynamically enable or disable analyzers, as
##! well as to manage the well-known ports which automatically activate a
##! particular analyzer for new connections.
##!
##! Protocol analyzers are identified by unique tags of type
##! :bro:type:`Analyzer::Tag`, such as :bro:enum:`Analyzer::ANALYZER_HTTP` and
##! :bro:enum:`Analyzer::ANALYZER_HTTP`. These tags are defined internally by
##! the analyzers themselves, and documented in their analyzer-specific
##! description along with the events that they generate.
##!
##! .. todo: ``The ANALYZER_*`` are in fact not yet documented, we need to
##! add that to Broxygen.
module Analyzer;
export {
## If true, all available analyzers are initially disabled at startup. One
## can then selectively enable them with
## :bro:id:`Analyzer::enable_analyzer`.
global disable_all = F &redef;
## Enables an analyzer. Once enabled, the analyzer may be used for analysis
## of future connections as decided by Bro's dynamic protocol detection.
##
## tag: The tag of the analyzer to enable.
##
## Returns: True if the analyzer was successfully enabled.
global enable_analyzer: function(tag: Analyzer::Tag) : bool;
## Disables an analyzer. Once disabled, the analyzer will not be used
## further for analysis of future connections.
##
## tag: The tag of the analyzer to disable.
##
## Returns: True if the analyzer was successfully disabled.
global disable_analyzer: function(tag: Analyzer::Tag) : bool;
## Registers a set of well-known ports for an analyzer. If a future
## connection on one of these ports is seen, the analyzer will be
## automatically assigned to parsing it. The function *adds* to all ports
## already registered, it doesn't replace them.
##
## tag: The tag of the analyzer.
##
## ports: The set of well-known ports to associate with the analyzer.
##
## Returns: True if the ports were sucessfully registered.
global register_for_ports: function(tag: Analyzer::Tag, ports: set[port]) : bool;
## Registers an individual well-known port for an analyzer. If a future
## connection on this port is seen, the analyzer will be automatically
## assigned to parsing it. The function *adds* to all ports already
## registered, it doesn't replace them.
##
## tag: The tag of the analyzer.
##
## p: The well-known port to associate with the analyzer.
##
## Returns: True if the port was sucessfully registered.
global register_for_port: function(tag: Analyzer::Tag, p: port) : bool;
## Returns a set of all well-known ports currently registered for a
## specific analyzer.
##
## tag: The tag of the analyzer.
##
## Returns: The set of ports.
global registered_ports: function(tag: Analyzer::Tag) : set[port];
## Returns a table of all ports-to-analyzer mappings currently registered.
##
## Returns: A table mapping each analyzer to the set of ports
## registered for it.
global all_registered_ports: function() : table[Analyzer::Tag] of set[port];
## Translates an analyzer type to a string with the analyzer's name.
##
## tag: The analyzer tag.
##
## Returns: The analyzer name corresponding to the tag.
global name: function(tag: Analyzer::Tag) : string;
## Schedules an analyzer for a future connection originating from a given IP
## address and port.
##
## orig: The IP address originating a connection in the future.
## 0.0.0.0 can be used as a wildcard to match any originator address.
##
## resp: The IP address responding to a connection from *orig*.
##
## resp_p: The destination port at *resp*.
##
## analyzer: The analyzer ID.
##
## tout: A timeout interval after which the scheduling request will be
## discarded if the connection has not yet been seen.
##
## Returns: True if succesful.
global schedule_analyzer: function(orig: addr, resp: addr, resp_p: port,
analyzer: Analyzer::Tag, tout: interval) : bool;
## A set of analyzers to disable by default at startup. The default set
## contains legacy analyzers that are no longer supported.
global disabled_analyzers: set[Analyzer::Tag] = {
ANALYZER_INTERCONN,
ANALYZER_STEPPINGSTONE,
ANALYZER_BACKDOOR,
ANALYZER_TCPSTATS,
} &redef;
}
@load base/bif/analyzer.bif
global ports: table[Analyzer::Tag] of set[port];
event bro_init() &priority=5
{
if ( disable_all )
__disable_all_analyzers();
for ( a in disabled_analyzers )
disable_analyzer(a);
}
function enable_analyzer(tag: Analyzer::Tag) : bool
{
return __enable_analyzer(tag);
}
function disable_analyzer(tag: Analyzer::Tag) : bool
{
return __disable_analyzer(tag);
}
function register_for_ports(tag: Analyzer::Tag, ports: set[port]) : bool
{
local rc = T;
for ( p in ports )
{
if ( ! register_for_port(tag, p) )
rc = F;
}
return rc;
}
function register_for_port(tag: Analyzer::Tag, p: port) : bool
{
if ( ! __register_for_port(tag, p) )
return F;
if ( tag !in ports )
ports[tag] = set();
add ports[tag][p];
return T;
}
function registered_ports(tag: Analyzer::Tag) : set[port]
{
return tag in ports ? ports[tag] : set();
}
function all_registered_ports(): table[Analyzer::Tag] of set[port]
{
return ports;
}
function name(atype: Analyzer::Tag) : string
{
return __name(atype);
}
function schedule_analyzer(orig: addr, resp: addr, resp_p: port,
analyzer: Analyzer::Tag, tout: interval) : bool
{
return __schedule_analyzer(orig, resp, resp_p, analyzer, tout);
}

View file

@ -23,12 +23,12 @@ export {
analyzer: string &log;
## The textual reason for the analysis failure.
failure_reason: string &log;
## Disabled analyzer IDs. This is only for internal tracking
## Disabled analyzer IDs. This is only for internal tracking
## so as to not attempt to disable analyzers multiple times.
disabled_aids: set[count];
};
## Ignore violations which go this many bytes into the connection.
## Set to 0 to never ignore protocol violations.
const ignore_violations_after = 10 * 1024 &redef;
@ -41,41 +41,30 @@ redef record connection += {
event bro_init() &priority=5
{
Log::create_stream(DPD::LOG, [$columns=Info]);
# Populate the internal DPD analysis variable.
for ( a in dpd_config )
{
for ( p in dpd_config[a]$ports )
{
if ( p !in dpd_analyzer_ports )
dpd_analyzer_ports[p] = set();
add dpd_analyzer_ports[p][a];
}
}
}
event protocol_confirmation(c: connection, atype: count, aid: count) &priority=10
event protocol_confirmation(c: connection, atype: Analyzer::Tag, aid: count) &priority=10
{
local analyzer = analyzer_name(atype);
local analyzer = Analyzer::name(atype);
if ( fmt("-%s",analyzer) in c$service )
delete c$service[fmt("-%s", analyzer)];
add c$service[analyzer];
}
event protocol_violation(c: connection, atype: count, aid: count,
event protocol_violation(c: connection, atype: Analyzer::Tag, aid: count,
reason: string) &priority=10
{
local analyzer = analyzer_name(atype);
local analyzer = Analyzer::name(atype);
# If the service hasn't been confirmed yet, don't generate a log message
# for the protocol violation.
if ( analyzer !in c$service )
return;
delete c$service[analyzer];
add c$service[fmt("-%s", analyzer)];
local info: Info;
info$ts=network_time();
info$uid=c$uid;
@ -86,7 +75,7 @@ event protocol_violation(c: connection, atype: count, aid: count,
c$dpd = info;
}
event protocol_violation(c: connection, atype: count, aid: count, reason: string) &priority=5
event protocol_violation(c: connection, atype: Analyzer::Tag, aid: count, reason: string) &priority=5
{
if ( !c?$dpd || aid in c$dpd$disabled_aids )
return;
@ -94,13 +83,13 @@ event protocol_violation(c: connection, atype: count, aid: count, reason: string
local size = c$orig$size + c$resp$size;
if ( ignore_violations_after > 0 && size > ignore_violations_after )
return;
# Disable the analyzer that raised the last core-generated event.
disable_analyzer(c$id, aid);
add c$dpd$disabled_aids[aid];
}
event protocol_violation(c: connection, atype: count, aid: count,
event protocol_violation(c: connection, atype: Analyzer::Tag, aid: count,
reason: string) &priority=-5
{
if ( c?$dpd )

View file

@ -1,7 +1,7 @@
##! An interface for driving the analysis of files, possibly independent of
##! any network protocol over which they're transported.
@load base/file_analysis.bif
@load base/bif/file_analysis.bif
@load base/frameworks/logging
module FileAnalysis;
@ -104,7 +104,7 @@ export {
## A table that can be used to disable file analysis completely for
## any files transferred over given network protocol analyzers.
const disable: table[AnalyzerTag] of bool = table() &redef;
const disable: table[Analyzer::Tag] of bool = table() &redef;
## Event that can be handled to access the Info record as it is sent on
## to the logging framework.

View file

@ -149,7 +149,7 @@ export {
global end_of_data: event(name: string, source:string);
}
@load base/input.bif
@load base/bif/input.bif
module Input;

View file

@ -366,7 +366,7 @@ export {
# We keep a script-level copy of all filters so that we can manipulate them.
global filters: table[ID, string] of Filter;
@load base/logging.bif # Needs Filter and Stream defined.
@load base/bif/logging.bif # Needs Filter and Stream defined.
module Log;

View file

@ -9,7 +9,7 @@
##! Note that this framework deals with the handling of internally generated
##! reporter messages, for the interface in to actually creating interface
##! into actually creating reporter messages from the scripting layer, use
##! the built-in functions in :doc:`/scripts/base/reporter.bif`.
##! the built-in functions in :doc:`/scripts/base/bif/reporter.bif`.
module Reporter;

View file

@ -83,19 +83,17 @@ export {
}
const ayiya_ports = { 5072/udp };
redef dpd_config += { [ANALYZER_AYIYA] = [$ports = ayiya_ports] };
const teredo_ports = { 3544/udp };
redef dpd_config += { [ANALYZER_TEREDO] = [$ports = teredo_ports] };
const gtpv1_ports = { 2152/udp, 2123/udp };
redef dpd_config += { [ANALYZER_GTPV1] = [$ports = gtpv1_ports] };
redef likely_server_ports += { ayiya_ports, teredo_ports, gtpv1_ports };
event bro_init() &priority=5
{
Log::create_stream(Tunnel::LOG, [$columns=Info]);
Analyzer::register_for_ports(Analyzer::ANALYZER_AYIYA, ayiya_ports);
Analyzer::register_for_ports(Analyzer::ANALYZER_TEREDO, teredo_ports);
Analyzer::register_for_ports(Analyzer::ANALYZER_GTPV1, gtpv1_ports);
}
function register_all(ecv: EncapsulatingConnVector)

View file

@ -1,5 +1,5 @@
@load base/const.bif
@load base/types.bif
@load base/bif/const.bif.bro
@load base/bif/types.bif
# Type declarations
@ -226,7 +226,7 @@ type endpoint_stats: record {
## for a connection, it assigns it a unique ID that can be used to reference
## that instance.
##
## .. bro:see:: analyzer_name disable_analyzer protocol_confirmation
## .. bro:see:: Analyzer::name Analyzer::disable_analyzer protocol_confirmation
## protocol_violation
##
## .. todo::While we declare an alias for the type here, the events/functions still
@ -713,9 +713,9 @@ type entropy_test_result: record {
};
# Prototypes of Bro built-in functions.
@load base/strings.bif
@load base/bro.bif
@load base/reporter.bif
@load base/bif/strings.bif
@load base/bif/bro.bif
@load base/bif/reporter.bif
## Deprecated. This is superseded by the new logging framework.
global log_file_name: function(tag: string): string &redef;
@ -2723,7 +2723,7 @@ export {
}
module GLOBAL;
@load base/event.bif
@load base/bif/event.bif
## BPF filter the user has set via the -f command line options. Empty if none.
const cmd_line_bpf_filter = "" &redef;
@ -2913,34 +2913,11 @@ const remote_trace_sync_peers = 0 &redef;
## consistency check.
const remote_check_sync_consistency = F &redef;
## Analyzer tags. The core automatically defines constants
## ``ANALYZER_<analyzer-name>*``, e.g., ``ANALYZER_HTTP``.
##
## .. bro:see:: dpd_config
##
## .. todo::We should autodoc these automaticallty generated constants.
type AnalyzerTag: count;
## Set of ports activating a particular protocol analysis.
##
## .. bro:see:: dpd_config
type dpd_protocol_config: record {
ports: set[port] &optional; ##< Set of ports.
};
## Port configuration for Bro's "dynamic protocol detection". Protocol
## analyzers can be activated via either well-known ports or content analysis.
## This table defines the ports.
##
## .. bro:see:: dpd_reassemble_first_packets dpd_buffer_size
## dpd_match_only_beginning dpd_ignore_ports
const dpd_config: table[AnalyzerTag] of dpd_protocol_config = {} &redef;
## Reassemble the beginning of all TCP connections before doing
## signature-matching. Enabling this provides more accurate matching at the
## expensive of CPU cycles.
##
## .. bro:see:: dpd_config dpd_buffer_size
## .. bro:see:: dpd_buffer_size
## dpd_match_only_beginning dpd_ignore_ports
##
## .. note:: Despite the name, this option affects *all* signature matching, not
@ -2955,24 +2932,24 @@ const dpd_reassemble_first_packets = T &redef;
## activated afterwards. Then only analyzers that can deal with partial
## connections will be able to analyze the session.
##
## .. bro:see:: dpd_reassemble_first_packets dpd_config dpd_match_only_beginning
## .. bro:see:: dpd_reassemble_first_packets dpd_match_only_beginning
## dpd_ignore_ports
const dpd_buffer_size = 1024 &redef;
## If true, stops signature matching if dpd_buffer_size has been reached.
##
## .. bro:see:: dpd_reassemble_first_packets dpd_buffer_size
## dpd_config dpd_ignore_ports
## dpd_ignore_ports
##
## .. note:: Despite the name, this option affects *all* signature matching, not
## only signatures used for dynamic protocol detection.
const dpd_match_only_beginning = T &redef;
## If true, don't consider any ports for deciding which protocol analyzer to
## use. If so, the value of :bro:see:`dpd_config` is ignored.
## use.
##
## .. bro:see:: dpd_reassemble_first_packets dpd_buffer_size
## dpd_match_only_beginning dpd_config
## dpd_match_only_beginning
const dpd_ignore_ports = F &redef;
## Ports which the core considers being likely used by servers. For ports in
@ -2980,13 +2957,6 @@ const dpd_ignore_ports = F &redef;
## connection if it misses the initial handshake.
const likely_server_ports: set[port] &redef;
## Deprated. Set of all ports for which we know an analyzer, built by
## :doc:`/scripts/base/frameworks/dpd/main`.
##
## .. todo::This should be defined by :doc:`/scripts/base/frameworks/dpd/main`
## itself we still need it.
global dpd_analyzer_ports: table[port] of set[AnalyzerTag];
## Per-incident timer managers are drained after this amount of inactivity.
const timer_mgr_inactivity_timeout = 1 min &redef;
@ -3095,10 +3065,12 @@ module GLOBAL;
## Number of bytes per packet to capture from live interfaces.
const snaplen = 8192 &redef;
# Load the logging framework here because it uses fairly deep integration with
# Load these frameworks here because they use fairly deep integration with
# BiFs and script-land defined types.
@load base/frameworks/logging
@load base/frameworks/input
@load base/frameworks/analyzer
@load base/frameworks/file-analysis
# Load BiFs defined by plugins.
@load base/bif/plugins

View file

@ -22,6 +22,7 @@
# loaded in base/init-bare.bro
#@load base/frameworks/logging
@load base/frameworks/notice
@load base/frameworks/analyzer
@load base/frameworks/dpd
@load base/frameworks/signatures
@load base/frameworks/packet-filter

View file

@ -6,9 +6,9 @@ module Conn;
export {
## Define inactivity timeouts by the service detected being used over
## the connection.
const analyzer_inactivity_timeouts: table[AnalyzerTag] of interval = {
const analyzer_inactivity_timeouts: table[Analyzer::Tag] of interval = {
# For interactive services, allow longer periods of inactivity.
[[ANALYZER_SSH, ANALYZER_FTP]] = 1 hrs,
[[Analyzer::ANALYZER_SSH, Analyzer::ANALYZER_FTP]] = 1 hrs,
} &redef;
## Define inactivity timeouts based on common protocol ports.
@ -18,7 +18,7 @@ export {
}
event protocol_confirmation(c: connection, atype: count, aid: count)
event protocol_confirmation(c: connection, atype: Analyzer::Tag, aid: count)
{
if ( atype in analyzer_inactivity_timeouts )
set_inactivity_timeout(c$id, analyzer_inactivity_timeouts[atype]);

View file

@ -130,19 +130,13 @@ redef capture_filters += {
["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 };
const ports = { 53/udp, 53/tcp, 137/udp, 5353/udp, 5355/udp };
redef likely_server_ports += { ports };
event bro_init() &priority=5
{
Log::create_stream(DNS::LOG, [$columns=Info, $ev=log_dns]);
Analyzer::register_for_ports(Analyzer::ANALYZER_DNS, ports);
}
function new_session(c: connection, trans_id: count): Info

View file

@ -11,7 +11,7 @@ export {
function get_handle_string(c: connection): string
{
return cat(ANALYZER_FTP_DATA, " ", c$start_time, " ", id_string(c$id));
return cat(Analyzer::ANALYZER_FTP_DATA, " ", c$start_time, " ", id_string(c$id));
}
function get_file_handle(c: connection, is_orig: bool): string
@ -40,8 +40,8 @@ function get_file_handle(c: connection, is_orig: bool): string
module GLOBAL;
event get_file_handle(tag: AnalyzerTag, c: connection, is_orig: bool)
event get_file_handle(tag: Analyzer::Tag, c: connection, is_orig: bool)
{
if ( tag != ANALYZER_FTP_DATA ) return;
if ( tag != Analyzer::ANALYZER_FTP_DATA ) return;
set_file_handle(FTP::get_file_handle(c, is_orig));
}

View file

@ -1,6 +1,6 @@
##! The logging this script does is primarily focused on logging FTP commands
##! along with metadata. For example, if files are transferred, the argument
##! 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.
@load ./utils-commands
@ -13,16 +13,16 @@ module FTP;
export {
## The FTP protocol logging stream identifier.
redef enum Log::ID += { LOG };
## List of commands that should have their command/response pairs logged.
const logged_commands = {
"APPE", "DELE", "RETR", "STOR", "STOU", "ACCT", "PORT", "PASV", "EPRT",
"EPSV"
} &redef;
## This setting changes if passwords used in FTP sessions are captured or not.
const default_capture_password = F &redef;
## User IDs that can be considered "anonymous".
const guest_ids = { "anonymous", "ftp", "ftpuser", "guest" } &redef;
@ -37,7 +37,7 @@ export {
## The port at which the acceptor is listening for the data connection.
resp_p: port &log;
};
type Info: record {
## Time when the command was sent.
ts: time &log;
@ -53,12 +53,12 @@ export {
command: string &log &optional;
## Argument for the command if one is given.
arg: string &log &optional;
## Libmagic "sniffed" file type if the command indicates a file transfer.
mime_type: string &log &optional;
## Size of the file if the command indicates a file transfer.
file_size: count &log &optional;
## Reply code from the server in response to the command.
reply_code: count &log &optional;
## Reply message from the server in response to the command.
@ -74,31 +74,31 @@ export {
## more concrete is discovered that the existing but unknown
## directory is ok to use.
cwd: string &default=".";
## Command that is currently waiting for a response.
cmdarg: CmdArg &optional;
## Queue for commands that have been sent but not yet responded to
## Queue for commands that have been sent but not yet responded to
## are tracked here.
pending_commands: PendingCmds;
## Indicates if the session is in active or passive mode.
passive: bool &default=F;
## Determines if the password will be captured for this request.
capture_password: bool &default=default_capture_password;
};
## This record is to hold a parsed FTP reply code. For example, for the
## This record is to hold a parsed FTP reply code. For example, for the
## 201 status code, the digits would be parsed as: x->2, y->0, z=>1.
type ReplyCode: record {
x: count;
y: count;
z: count;
};
## Parse FTP reply codes into the three constituent single digit values.
global parse_ftp_reply_code: function(code: count): ReplyCode;
## Event that can be handled to access the :bro:type:`FTP::Info`
## record as it is sent on to the logging framework.
global log_ftp: event(rec: Info);
@ -111,11 +111,10 @@ redef record connection += {
};
# Configure DPD
const ports = { 21/tcp, 2811/tcp } &redef; # 2811/tcp is GridFTP.
redef capture_filters += { ["ftp"] = "port 21 and port 2811" };
redef dpd_config += { [ANALYZER_FTP] = [$ports = ports] };
redef likely_server_ports += { 21/tcp, 2811/tcp };
const ports = { 21/tcp, 2811/tcp };
redef likely_server_ports += { ports };
# Establish the variable for tracking expected connections.
global ftp_data_expected: table[addr, port] of Info &read_expire=5mins;
@ -123,6 +122,7 @@ global ftp_data_expected: table[addr, port] of Info &read_expire=5mins;
event bro_init() &priority=5
{
Log::create_stream(FTP::LOG, [$columns=Info, $ev=log_ftp]);
Analyzer::register_for_ports(Analyzer::ANALYZER_FTP, ports);
}
## A set of commands where the argument can be expected to refer
@ -166,7 +166,7 @@ function set_ftp_session(c: connection)
s$uid=c$uid;
s$id=c$id;
c$ftp=s;
# Add a shim command so the server can respond with some init response.
add_pending_cmd(c$ftp$pending_commands, "<init>", "");
}
@ -178,13 +178,13 @@ function ftp_message(s: Info)
# or it's a deliberately logged command.
if ( |s$tags| > 0 || (s?$cmdarg && s$cmdarg$cmd in logged_commands) )
{
if ( s?$password &&
! s$capture_password &&
if ( s?$password &&
! s$capture_password &&
to_lower(s$user) !in guest_ids )
{
s$password = "<hidden>";
}
local arg = s$cmdarg$arg;
if ( s$cmdarg$cmd in file_cmds )
{
@ -194,7 +194,7 @@ function ftp_message(s: Info)
arg = fmt("ftp://%s%s", addr_to_uri(s$id$resp_h), comp_path);
}
s$ts=s$cmdarg$ts;
s$command=s$cmdarg$cmd;
if ( arg == "" )
@ -204,9 +204,9 @@ function ftp_message(s: Info)
Log::write(FTP::LOG, s);
}
# The MIME and file_size fields are specific to file transfer commands
# and may not be used in all commands so they need reset to "blank"
# The MIME and file_size fields are specific to file transfer commands
# and may not be used in all commands so they need reset to "blank"
# values after logging.
delete s$mime_type;
delete s$file_size;
@ -221,8 +221,8 @@ function add_expected_data_channel(s: Info, chan: ExpectedDataChannel)
s$passive = chan$passive;
s$data_channel = chan;
ftp_data_expected[chan$resp_h, chan$resp_p] = s;
expect_connection(chan$orig_h, chan$resp_h, chan$resp_p, ANALYZER_FTP_DATA,
5mins);
Analyzer::schedule_analyzer(chan$orig_h, chan$resp_h, chan$resp_p, Analyzer::ANALYZER_FTP_DATA,
5mins);
}
event ftp_request(c: connection, command: string, arg: string) &priority=5
@ -237,19 +237,19 @@ event ftp_request(c: connection, command: string, arg: string) &priority=5
remove_pending_cmd(c$ftp$pending_commands, c$ftp$cmdarg);
ftp_message(c$ftp);
}
local id = c$id;
set_ftp_session(c);
# Queue up the new command and argument
add_pending_cmd(c$ftp$pending_commands, command, arg);
if ( command == "USER" )
c$ftp$user = arg;
else if ( command == "PASS" )
c$ftp$password = arg;
else if ( command == "PORT" || command == "EPRT" )
{
local data = (command == "PORT") ?
@ -277,7 +277,7 @@ event ftp_reply(c: connection, code: count, msg: string, cont_resp: bool) &prior
# TODO: figure out what to do with continued FTP response (not used much)
if ( cont_resp ) return;
# TODO: do some sort of generic clear text login processing here.
local response_xyz = parse_ftp_reply_code(code);
#if ( response_xyz$x == 2 && # successful
@ -293,17 +293,17 @@ event ftp_reply(c: connection, code: count, msg: string, cont_resp: bool) &prior
# if that's given as well which would be more correct.
c$ftp$file_size = extract_count(msg);
}
# PASV and EPSV processing
else if ( (code == 227 || code == 229) &&
(c$ftp$cmdarg$cmd == "PASV" || c$ftp$cmdarg$cmd == "EPSV") )
{
local data = (code == 227) ? parse_ftp_pasv(msg) : parse_ftp_epsv(msg);
if ( data$valid )
{
c$ftp$passive=T;
if ( code == 229 && data$h == [::] )
data$h = c$id$resp_h;
@ -327,9 +327,9 @@ event ftp_reply(c: connection, code: count, msg: string, cont_resp: bool) &prior
else if ( c$ftp$cmdarg$cmd == "PWD" || c$ftp$cmdarg$cmd == "XPWD" )
c$ftp$cwd = extract_path(msg);
}
# In case there are multiple commands queued, go ahead and remove the
# command here and log because we can't do the normal processing pipeline
# command here and log because we can't do the normal processing pipeline
# to wait for a new command before logging the command/response pair.
if ( |c$ftp$pending_commands| > 1 )
{
@ -338,7 +338,7 @@ event ftp_reply(c: connection, code: count, msg: string, cont_resp: bool) &prior
}
}
event expected_connection_seen(c: connection, a: count) &priority=10
event scheduled_analyzer_applied(c: connection, a: Analyzer::Tag) &priority=10
{
local id = c$id;
if ( [id$resp_h, id$resp_p] in ftp_data_expected )
@ -361,7 +361,7 @@ event connection_reused(c: connection) &priority=5
if ( "ftp-data" in c$service )
c$ftp_data_reuse = T;
}
event connection_state_remove(c: connection) &priority=-5
{
if ( c$ftp_data_reuse ) return;

View file

@ -15,17 +15,17 @@ function get_file_handle(c: connection, is_orig: bool): string
if ( ! c?$http ) return "";
if ( c$http$range_request )
return cat(ANALYZER_HTTP, " ", is_orig, " ", c$id$orig_h, " ",
return cat(Analyzer::ANALYZER_HTTP, " ", is_orig, " ", c$id$orig_h, " ",
build_url(c$http));
return cat(ANALYZER_HTTP, " ", c$start_time, " ", is_orig, " ",
return cat(Analyzer::ANALYZER_HTTP, " ", c$start_time, " ", is_orig, " ",
c$http$trans_depth, " ", id_string(c$id));
}
module GLOBAL;
event get_file_handle(tag: AnalyzerTag, c: connection, is_orig: bool)
event get_file_handle(tag: Analyzer::Tag, c: connection, is_orig: bool)
{
if ( tag != ANALYZER_HTTP ) return;
if ( tag != Analyzer::ANALYZER_HTTP ) return;
set_file_handle(HTTP::get_file_handle(c, is_orig));
}

View file

@ -123,29 +123,26 @@ redef record connection += {
http_state: State &optional;
};
# Initialize the HTTP logging stream.
event bro_init() &priority=5
{
Log::create_stream(HTTP::LOG, [$columns=Info, $ev=log_http]);
}
# DPD configuration.
const ports = {
80/tcp, 81/tcp, 631/tcp, 1080/tcp, 3128/tcp,
8000/tcp, 8080/tcp, 8888/tcp,
};
redef dpd_config += {
[[ANALYZER_HTTP, ANALYZER_HTTP_BINPAC]] = [$ports = ports],
};
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 += {
80/tcp, 81/tcp, 631/tcp, 1080/tcp, 3138/tcp,
const ports = {
80/tcp, 81/tcp, 631/tcp, 1080/tcp, 3128/tcp,
8000/tcp, 8080/tcp, 8888/tcp,
};
redef likely_server_ports += { ports };
# Initialize the HTTP logging stream and ports.
event bro_init() &priority=5
{
Log::create_stream(HTTP::LOG, [$columns=Info, $ev=log_http]);
Analyzer::register_for_ports(Analyzer::ANALYZER_HTTP, ports);
}
function code_in_range(c: count, min: count, max: count) : bool
{
return c >= min && c <= max;

View file

@ -175,11 +175,11 @@ event irc_dcc_message(c: connection, is_orig: bool,
c$irc$dcc_file_name = argument;
c$irc$dcc_file_size = size;
local p = count_to_port(dest_port, tcp);
expect_connection(to_addr("0.0.0.0"), address, p, ANALYZER_IRC_DATA, 5 min);
Analyzer::schedule_analyzer(0.0.0.0, address, p, Analyzer::ANALYZER_IRC_DATA, 5 min);
dcc_expected_transfers[address, p] = c$irc;
}
event expected_connection_seen(c: connection, a: count) &priority=10
event expected_connection_seen(c: connection, a: Analyzer::Tag) &priority=10
{
local id = c$id;
if ( [id$resp_h, id$resp_p] in dcc_expected_transfers )

View file

@ -12,13 +12,13 @@ export {
function get_file_handle(c: connection, is_orig: bool): string
{
if ( is_orig ) return "";
return cat(ANALYZER_IRC_DATA, " ", c$start_time, " ", id_string(c$id));
return cat(Analyzer::ANALYZER_IRC_DATA, " ", c$start_time, " ", id_string(c$id));
}
module GLOBAL;
event get_file_handle(tag: AnalyzerTag, c: connection, is_orig: bool)
event get_file_handle(tag: Analyzer::Tag, c: connection, is_orig: bool)
{
if ( tag != ANALYZER_IRC_DATA ) return;
if ( tag != Analyzer::ANALYZER_IRC_DATA ) return;
set_file_handle(IRC::get_file_handle(c, is_orig));
}

View file

@ -45,14 +45,13 @@ redef capture_filters += { ["irc-6668"] = "port 6668" };
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 };
const ports = { 6666/tcp, 6667/tcp, 6668/tcp, 6669/tcp };
redef likely_server_ports += { ports };
event bro_init() &priority=5
{
Log::create_stream(IRC::LOG, [$columns=Info, $ev=irc_log]);
Analyzer::register_for_ports(Analyzer::ANALYZER_IRC, ports);
}
function new_session(c: connection): Info

View file

@ -31,12 +31,14 @@ redef record connection += {
# Configure DPD and the packet filter.
redef capture_filters += { ["modbus"] = "tcp port 502" };
redef dpd_config += { [ANALYZER_MODBUS] = [$ports = set(502/tcp)] };
redef likely_server_ports += { 502/tcp };
const ports = { 502/tcp };
redef likely_server_ports += { ports };
event bro_init() &priority=5
{
Log::create_stream(Modbus::LOG, [$columns=Info, $ev=log_modbus]);
Analyzer::register_for_ports(Analyzer::ANALYZER_MODBUS, ports);
}
event modbus_message(c: connection, headers: ModbusHeaders, is_orig: bool) &priority=5

View file

@ -13,14 +13,14 @@ export {
function get_file_handle(c: connection, is_orig: bool): string
{
if ( ! c?$smtp ) return "";
return cat(ANALYZER_SMTP, " ", c$start_time, " ", c$smtp$trans_depth, " ",
return cat(Analyzer::ANALYZER_SMTP, " ", c$start_time, " ", c$smtp$trans_depth, " ",
c$smtp_state$mime_level);
}
module GLOBAL;
event get_file_handle(tag: AnalyzerTag, c: connection, is_orig: bool)
event get_file_handle(tag: Analyzer::Tag, c: connection, is_orig: bool)
{
if ( tag != ANALYZER_SMTP ) return;
if ( tag != Analyzer::ANALYZER_SMTP ) return;
set_file_handle(SMTP::get_file_handle(c, is_orig));
}

View file

@ -74,9 +74,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 += {
@ -86,13 +83,14 @@ redef record connection += {
# Configure DPD
redef capture_filters += { ["smtp"] = "tcp port 25 or tcp port 587" };
redef dpd_config += { [ANALYZER_SMTP] = [$ports = ports] };
redef likely_server_ports += { 25/tcp, 587/tcp };
const ports = { 25/tcp, 587/tcp };
redef likely_server_ports += { ports };
event bro_init() &priority=5
{
Log::create_stream(SMTP::LOG, [$columns=SMTP::Info, $ev=log_smtp]);
Analyzer::register_for_ports(Analyzer::ANALYZER_SMTP, ports);
}
function find_address_in_smtp_header(header: string): string

View file

@ -34,9 +34,13 @@ export {
global log_socks: event(rec: Info);
}
const ports = { 1080/tcp };
redef likely_server_ports += { ports };
event bro_init() &priority=5
{
Log::create_stream(SOCKS::LOG, [$columns=Info, $ev=log_socks]);
Analyzer::register_for_ports(Analyzer::ANALYZER_SOCKS, ports);
}
redef record connection += {
@ -45,7 +49,6 @@ redef record connection += {
# Configure DPD
redef capture_filters += { ["socks"] = "tcp port 1080" };
redef dpd_config += { [ANALYZER_SOCKS] = [$ports = set(1080/tcp)] };
redef likely_server_ports += { 1080/tcp };
function set_session(c: connection, version: count)

View file

@ -71,10 +71,11 @@ export {
}
# Configure DPD and the packet filter
redef capture_filters += { ["ssh"] = "tcp port 22" };
redef dpd_config += { [ANALYZER_SSH] = [$ports = set(22/tcp)] };
redef likely_server_ports += { 22/tcp };
const ports = { 22/tcp };
redef capture_filters += { ["ssh"] = "tcp port 22" };
redef likely_server_ports += { ports };
redef record connection += {
ssh: Info &optional;
@ -83,6 +84,7 @@ redef record connection += {
event bro_init() &priority=5
{
Log::create_stream(SSH::LOG, [$columns=Info, $ev=log_ssh]);
Analyzer::register_for_ports(Analyzer::ANALYZER_SSH, ports);
}
function set_session(c: connection)

View file

@ -94,11 +94,6 @@ redef record Info += {
delay_tokens: set[string] &optional;
};
event bro_init() &priority=5
{
Log::create_stream(SSL::LOG, [$columns=Info, $ev=log_ssl]);
}
redef capture_filters += {
["ssl"] = "tcp port 443",
["nntps"] = "tcp port 563",
@ -117,16 +112,9 @@ redef capture_filters += {
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;
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
};
redef likely_server_ports += { ports };
# A queue that buffers log records.
global log_delay_queue: table[count] of Info;
@ -135,6 +123,12 @@ global log_delay_queue_head = 0;
# The bottom queue index that points to the next record to be flushed.
global log_delay_queue_tail = 0;
event bro_init() &priority=5
{
Log::create_stream(SSL::LOG, [$columns=Info, $ev=log_ssl]);
Analyzer::register_for_ports(Analyzer::ANALYZER_SSL, ports);
}
function set_session(c: connection)
{
if ( ! c?$ssl )
@ -288,14 +282,14 @@ event ssl_established(c: connection) &priority=-5
finish(c);
}
event protocol_confirmation(c: connection, atype: count, aid: count) &priority=5
event protocol_confirmation(c: connection, atype: Analyzer::Tag, aid: count) &priority=5
{
# Check by checking for existence of c$ssl record.
if ( c?$ssl && analyzer_name(atype) == "SSL" )
if ( c?$ssl && atype == Analyzer::ANALYZER_SSL )
c$ssl$analyzer_id = aid;
}
event protocol_violation(c: connection, atype: count, aid: count,
event protocol_violation(c: connection, atype: Analyzer::Tag, aid: count,
reason: string) &priority=5
{
if ( c?$ssl )

View file

@ -27,10 +27,9 @@ export {
}
redef capture_filters += { ["syslog"] = "port 514" };
const ports = { 514/udp } &redef;
redef dpd_config += { [ANALYZER_SYSLOG_BINPAC] = [$ports = ports] };
redef likely_server_ports += { 514/udp };
const ports = { 514/udp };
redef likely_server_ports += { ports };
redef record connection += {
syslog: Info &optional;
@ -39,6 +38,7 @@ redef record connection += {
event bro_init() &priority=5
{
Log::create_stream(Syslog::LOG, [$columns=Info]);
Analyzer::register_for_ports(Analyzer::ANALYZER_SYSLOG, ports);
}
event syslog_message(c: connection, facility: count, severity: count, msg: string) &priority=5

View file

@ -21,22 +21,22 @@ export {
type dir: enum { NONE, INCOMING, OUTGOING, BOTH };
const valids: table[count, addr, port] of dir = {
const valids: table[Analyzer::Tag, addr, port] of dir = {
# A couple of ports commonly used for benign HTTP servers.
# For now we want to see everything.
# [ANALYZER_HTTP, 0.0.0.0, 81/tcp] = OUTGOING,
# [ANALYZER_HTTP, 0.0.0.0, 82/tcp] = OUTGOING,
# [ANALYZER_HTTP, 0.0.0.0, 83/tcp] = OUTGOING,
# [ANALYZER_HTTP, 0.0.0.0, 88/tcp] = OUTGOING,
# [ANALYZER_HTTP, 0.0.0.0, 8001/tcp] = OUTGOING,
# [ANALYZER_HTTP, 0.0.0.0, 8090/tcp] = OUTGOING,
# [ANALYZER_HTTP, 0.0.0.0, 8081/tcp] = OUTGOING,
# [Analyzer::ANALYZER_HTTP, 0.0.0.0, 81/tcp] = OUTGOING,
# [Analyzer::ANALYZER_HTTP, 0.0.0.0, 82/tcp] = OUTGOING,
# [Analyzer::ANALYZER_HTTP, 0.0.0.0, 83/tcp] = OUTGOING,
# [Analyzer::ANALYZER_HTTP, 0.0.0.0, 88/tcp] = OUTGOING,
# [Analyzer::ANALYZER_HTTP, 0.0.0.0, 8001/tcp] = OUTGOING,
# [Analyzer::ANALYZER_HTTP, 0.0.0.0, 8090/tcp] = OUTGOING,
# [Analyzer::ANALYZER_HTTP, 0.0.0.0, 8081/tcp] = OUTGOING,
#
# [ANALYZER_HTTP, 0.0.0.0, 6346/tcp] = BOTH, # Gnutella
# [ANALYZER_HTTP, 0.0.0.0, 6347/tcp] = BOTH, # Gnutella
# [ANALYZER_HTTP, 0.0.0.0, 6348/tcp] = BOTH, # Gnutella
# [Analyzer::ANALYZER_HTTP, 0.0.0.0, 6346/tcp] = BOTH, # Gnutella
# [Analyzer::ANALYZER_HTTP, 0.0.0.0, 6347/tcp] = BOTH, # Gnutella
# [Analyzer::ANALYZER_HTTP, 0.0.0.0, 6348/tcp] = BOTH, # Gnutella
} &redef;
# Set of analyzers for which we suppress Server_Found notices
@ -44,8 +44,8 @@ export {
# log files, this also saves memory because for these we don't
# need to remember which servers we already have reported, which
# for some can be a lot.
const suppress_servers: set [count] = {
# ANALYZER_HTTP
const suppress_servers: set [Analyzer::Tag] = {
# Analyzer::ANALYZER_HTTP
} &redef;
# We consider a connection to use a protocol X if the analyzer for X
@ -60,7 +60,7 @@ export {
# Entry point for other analyzers to report that they recognized
# a certain (sub-)protocol.
global found_protocol: function(c: connection, analyzer: count,
global found_protocol: function(c: connection, analyzer: Analyzer::Tag,
protocol: string);
# Table keeping reported (server, port, analyzer) tuples (and their
@ -70,7 +70,7 @@ export {
}
# Table that tracks currently active dynamic analyzers per connection.
global conns: table[conn_id] of set[count];
global conns: table[conn_id] of set[Analyzer::Tag];
# Table of reports by other analyzers about the protocol used in a connection.
global protocols: table[conn_id] of set[string];
@ -80,7 +80,7 @@ type protocol : record {
sub: string; # "sub-protocols" reported by other sources
};
function get_protocol(c: connection, a: count) : protocol
function get_protocol(c: connection, a: Analyzer::Tag) : protocol
{
local str = "";
if ( c$id in protocols )
@ -89,7 +89,7 @@ function get_protocol(c: connection, a: count) : protocol
str = |str| > 0 ? fmt("%s/%s", str, p) : p;
}
return [$a=analyzer_name(a), $sub=str];
return [$a=Analyzer::name(a), $sub=str];
}
function fmt_protocol(p: protocol) : string
@ -97,7 +97,7 @@ function fmt_protocol(p: protocol) : string
return p$sub != "" ? fmt("%s (via %s)", p$sub, p$a) : p$a;
}
function do_notice(c: connection, a: count, d: dir)
function do_notice(c: connection, a: Analyzer::Tag, d: dir)
{
if ( d == BOTH )
return;
@ -113,7 +113,7 @@ function do_notice(c: connection, a: count, d: dir)
NOTICE([$note=Protocol_Found,
$msg=fmt("%s %s on port %s", id_string(c$id), s, c$id$resp_p),
$sub=s, $conn=c, $n=a]);
$sub=s, $conn=c]);
# We report multiple Server_Found's per host if we find a new
# sub-protocol.
@ -129,7 +129,7 @@ function do_notice(c: connection, a: count, d: dir)
NOTICE([$note=Server_Found,
$msg=fmt("%s: %s server on port %s%s", c$id$resp_h, s,
c$id$resp_p, (known ? " (update)" : "")),
$p=c$id$resp_p, $sub=s, $conn=c, $src=c$id$resp_h, $n=a]);
$p=c$id$resp_p, $sub=s, $conn=c, $src=c$id$resp_h]);
if ( ! known )
servers[c$id$resp_h, c$id$resp_p, p$a] = set();
@ -194,10 +194,10 @@ event connection_state_remove(c: connection)
report_protocols(c);
}
event protocol_confirmation(c: connection, atype: count, aid: count)
event protocol_confirmation(c: connection, atype: Analyzer::Tag, aid: count)
{
# Don't report anything running on a well-known port.
if ( atype in dpd_config && c$id$resp_p in dpd_config[atype]$ports )
if ( c$id$resp_p in Analyzer::registered_ports(atype) )
return;
if ( c$id in conns )
@ -214,11 +214,10 @@ event protocol_confirmation(c: connection, atype: count, aid: count)
}
}
function found_protocol(c: connection, analyzer: count, protocol: string)
function found_protocol(c: connection, atype: Analyzer::Tag, protocol: string)
{
# Don't report anything running on a well-known port.
if ( analyzer in dpd_config &&
c$id$resp_p in dpd_config[analyzer]$ports )
if ( c$id$resp_p in Analyzer::registered_ports(atype) )
return;
if ( c$id !in protocols )

View file

@ -20,7 +20,7 @@ export {
}
event protocol_violation(c: connection, atype: count, aid: count,
event protocol_violation(c: connection, atype: Analyzer::Tag, aid: count,
reason: string) &priority=4
{
if ( ! c?$dpd ) return;

View file

@ -1,31 +0,0 @@
##! This script gives the capability to selectively enable and disable event
##! groups at runtime. No events will be raised for all members of a disabled
##! event group.
module AnalysisGroups;
export {
## By default, all event groups are enabled.
## We disable all groups in this table.
const disabled: set[string] &redef;
}
# Set to remember all groups which were disabled by the last update.
global currently_disabled: set[string];
# This is the event that the control framework uses when it needs to indicate
# that an update control action happened.
event Control::configuration_update()
{
# Reenable those which are not to be disabled anymore.
for ( g in currently_disabled )
if ( g !in disabled )
enable_event_group(g);
# Disable those which are not already disabled.
for ( g in disabled )
if ( g !in currently_disabled )
disable_event_group(g);
currently_disabled = copy(disabled);
}

View file

@ -87,7 +87,7 @@ function known_services_done(c: connection)
event log_it(network_time(), id$resp_h, id$resp_p, c$service);
}
event protocol_confirmation(c: connection, atype: count, aid: count) &priority=-5
event protocol_confirmation(c: connection, atype: Analyzer::Tag, aid: count) &priority=-5
{
known_services_done(c);
}

View file

@ -31,7 +31,6 @@
@load integration/barnyard2/types.bro
@load integration/collective-intel/__load__.bro
@load integration/collective-intel/main.bro
@load misc/analysis-groups.bro
@load misc/app-metrics.bro
@load misc/capture-loss.bro
@load misc/detect-traceroute/__load__.bro

View file

@ -1,403 +0,0 @@
// Main analyzer interface.
#ifndef ANALYZER_H
#define ANALYZER_H
#include <list>
#include "AnalyzerTags.h"
#include "Conn.h"
#include "Obj.h"
class DPM;
class PIA;
class Analyzer;
typedef list<Analyzer*> analyzer_list;
typedef void (Analyzer::*analyzer_timer_func)(double t);
// FIXME: This is a copy of ConnectionTimer, which we may eventually be
// able to get rid of.
class AnalyzerTimer : public Timer {
public:
AnalyzerTimer(Analyzer* arg_analyzer, analyzer_timer_func arg_timer,
double arg_t, int arg_do_expire, TimerType arg_type)
: Timer(arg_t, arg_type)
{ Init(arg_analyzer, arg_timer, arg_do_expire); }
virtual ~AnalyzerTimer();
void Dispatch(double t, int is_expire);
protected:
AnalyzerTimer() {}
void Init(Analyzer* analyzer, analyzer_timer_func timer, int do_expire);
Analyzer* analyzer;
analyzer_timer_func timer;
int do_expire;
};
// Main analyzer interface.
//
// Each analyzer is part of a tree, having a parent analyzer and an
// arbitrary number of child analyzers. Each analyzer also has a list of
// *suppport analyzers*. All its input first passes through this list of
// support analyzers, which can perform arbitrary preprocessing. Support
// analyzers share the same interface as regular analyzers, except that
// they are unidirectional, i.e., they see only one side of a connection.
//
// When overiding any of these methods, always make sure to call the
// base-class version first.
class SupportAnalyzer;
class OutputHandler;
class Analyzer {
public:
Analyzer(AnalyzerTag::Tag tag, Connection* conn);
virtual ~Analyzer();
virtual void Init();
virtual void Done();
// Pass data to the analyzer (it's automatically passed through its
// support analyzers first). We have packet-wise and stream-wise
// interfaces. For the packet-interface, some analyzers may require
// more information than others, so IP/caplen and seq may or may
// not be set.
void NextPacket(int len, const u_char* data, bool orig,
int seq = -1, const IP_Hdr* ip = 0, int caplen = 0);
void NextStream(int len, const u_char* data, bool is_orig);
// Used for data that can't be delivered (e.g., due to a previous
// sequence hole/gap).
void NextUndelivered(int seq, int len, bool is_orig);
// Report message boundary. (See EndOfData() below.)
void NextEndOfData(bool orig);
// Pass data on to all child analyzer(s). For SupportAnalyzers (see
// below), this is overridden to pass it on to the next sibling (or
// finally to the parent, if it's the last support analyzer).
//
// If we have an associated OutputHandler (see below), the data is
// additionally passed to that, too. For SupportAnalyzers, it is *only*
// delivered to the OutputHandler.
virtual void ForwardPacket(int len, const u_char* data,
bool orig, int seq,
const IP_Hdr* ip, int caplen);
virtual void ForwardStream(int len, const u_char* data, bool orig);
virtual void ForwardUndelivered(int seq, int len, bool orig);
// Report a message boundary to all child analyzers
virtual void ForwardEndOfData(bool orig);
AnalyzerID GetID() const { return id; }
Connection* Conn() const { return conn; }
// An OutputHandler can be used to get access to data extracted by this
// analyzer (i.e., all data which is passed to
// Forward{Packet,Stream,Undelivered}). We take the ownership of
// the handler.
class OutputHandler {
public:
virtual ~OutputHandler() { }
virtual void DeliverPacket(int len, const u_char* data,
bool orig, int seq,
const IP_Hdr* ip, int caplen)
{ }
virtual void DeliverStream(int len, const u_char* data,
bool orig) { }
virtual void Undelivered(int seq, int len, bool orig) { }
};
OutputHandler* GetOutputHandler() const { return output_handler; }
void SetOutputHandler(OutputHandler* handler)
{ output_handler = handler; }
// If an analyzer was triggered by a signature match, this returns the
// name of the signature; nil if not.
const Rule* Signature() const { return signature; }
void SetSignature(const Rule* sig) { signature = sig; }
void SetSkip(bool do_skip) { skip = do_skip; }
bool Skipping() const { return skip; }
bool IsFinished() const { return finished; }
AnalyzerTag::Tag GetTag() const { return tag; }
const char* GetTagName() const;
static AnalyzerTag::Tag GetTag(const char* tag);
static const char* GetTagName(AnalyzerTag::Tag tag);
static bool IsAvailable(AnalyzerTag::Tag tag)
{ return analyzer_configs[tag].available(); }
// Management of the tree.
//
// We immediately discard an added analyzer if there's already a child
// of the same type.
void AddChildAnalyzer(Analyzer* analyzer)
{ AddChildAnalyzer(analyzer, true); }
Analyzer* AddChildAnalyzer(AnalyzerTag::Tag tag);
void RemoveChildAnalyzer(Analyzer* analyzer);
void RemoveChildAnalyzer(AnalyzerID id);
bool HasChildAnalyzer(AnalyzerTag::Tag tag);
// Recursive; returns nil if not found.
Analyzer* FindChild(AnalyzerID id);
// Recursive; returns first found, or nil.
Analyzer* FindChild(AnalyzerTag::Tag tag);
const analyzer_list& GetChildren() { return children; }
Analyzer* Parent() const { return parent; }
void SetParent(Analyzer* p) { parent = p; }
// Remove this child analyzer from the parent's list.
void Remove() { assert(parent); parent->RemoveChildAnalyzer(this); }
// Management of support analyzers. Support analyzers are associated
// with a direction, and will only see data in the corresponding flow.
//
// We immediately discard an added analyzer if there's already a child
// of the same type for the same direction.
// Adds to tail of list.
void AddSupportAnalyzer(SupportAnalyzer* analyzer);
void RemoveSupportAnalyzer(SupportAnalyzer* analyzer);
// These are the methods where the analyzer actually gets its input.
// Each analyzer has only to implement the schemes it supports.
// Packet-wise (or more generally chunk-wise) input. "data" points
// to the payload that the analyzer is supposed to examine. If it's
// part of a full packet, "ip" points to its IP header. An analyzer
// may or may not require to be given the full packet (and its caplen)
// as well.
virtual void DeliverPacket(int len, const u_char* data, bool orig,
int seq, const IP_Hdr* ip, int caplen);
// Stream-wise payload input.
virtual void DeliverStream(int len, const u_char* data, bool orig);
// If a parent analyzer can't turn a sequence of packets into a stream
// (e.g., due to holes), it can pass the remaining data through this
// method to the child.
virtual void Undelivered(int seq, int len, bool orig);
// Report a message boundary. This is a generic method that can be used
// by specific Analyzers if all data of a message has been delivered,
// e.g., to report that HTTP body has been delivered completely by the
// HTTP analyzer before it starts with the next body. EndOfData() is
// automatically generated by the analyzer's Done() method.
virtual void EndOfData(bool is_orig);
// Occasionally we may find during analysis that we got the direction
// of the connection wrong. In these cases, this method is called
// to swap state if necessary. This will not happen after payload
// has already been passed on, so most analyzers don't need to care.
virtual void FlipRoles();
// Feedback about protocol conformance, to be called by the
// analyzer's processing. The methods raise the correspondiong
// protocol_confirmation and protocol_violation events.
// Report that we believe we're parsing the right protocol. This
// should be called as early as possible during a connection's
// life-time. The protocol_confirmed event is only raised once per
// analyzer, even if the method is called multiple times.
virtual void ProtocolConfirmation();
// Return whether the analyzer previously called ProtocolConfirmation()
// at least once before.
bool ProtocolConfirmed() const
{ return protocol_confirmed; }
// Report that we found a significant protocol violation which might
// indicate that the analyzed data is in fact not the expected
// protocol. The protocol_violation event is raised once per call to
// this method so that the script-level may build up some notion of
// how "severely" protocol semantics are violated.
virtual void ProtocolViolation(const char* reason,
const char* data = 0, int len = 0);
virtual unsigned int MemoryAllocation() const;
// Called whenever the connection value needs to be updated. Per
// default, this method will be called for each analyzer in the tree.
// Analyzers can use this method to attach additional data to the
// connections. A call to BuildConnVal will in turn trigger a call to
// UpdateConnVal.
virtual void UpdateConnVal(RecordVal *conn_val);
// The following methods are proxies: calls are directly forwarded
// to the connection instance. These are for convenience only,
// allowing us to reuse more of the old analyzer code unchanged.
RecordVal* BuildConnVal()
{ return conn->BuildConnVal(); }
void Event(EventHandlerPtr f, const char* name = 0)
{ conn->Event(f, this, name); }
void Event(EventHandlerPtr f, Val* v1, Val* v2 = 0)
{ conn->Event(f, this, v1, v2); }
void ConnectionEvent(EventHandlerPtr f, val_list* vl)
{ conn->ConnectionEvent(f, this, vl); }
void Weird(const char* name, const char* addl = "")
{ conn->Weird(name, addl); }
// Factory function to instantiate new analyzers.
static Analyzer* InstantiateAnalyzer(AnalyzerTag::Tag tag, Connection* c);
protected:
friend class DPM;
friend class Connection;
friend class AnalyzerTimer;
friend class TCP_ApplicationAnalyzer;
Analyzer() { }
// Associates a connection with this analyzer. Must be called if
// we're using the default ctor.
void SetConnection(Connection* c) { conn = c; }
// Creates the given timer to expire at time t. If do_expire
// is true, then the timer is also evaluated when Bro terminates,
// otherwise not.
void AddTimer(analyzer_timer_func timer, double t, int do_expire,
TimerType type);
void RemoveTimer(Timer* t);
void CancelTimers();
bool HasSupportAnalyzer(AnalyzerTag::Tag tag, bool orig);
void AddChildAnalyzer(Analyzer* analyzer, bool init);
void InitChildren();
void AppendNewChildren();
private:
// Internal method to eventually delete a child analyzer that's
// already Done().
void DeleteChild(analyzer_list::iterator i);
AnalyzerTag::Tag tag;
AnalyzerID id;
Connection* conn;
Analyzer* parent;
const Rule* signature;
OutputHandler* output_handler;
analyzer_list children;
SupportAnalyzer* orig_supporters;
SupportAnalyzer* resp_supporters;
analyzer_list new_children;
bool protocol_confirmed;
timer_list timers;
bool timers_canceled;
bool skip;
bool finished;
bool removing;
static AnalyzerID id_counter;
typedef bool (*available_callback)();
typedef Analyzer* (*factory_callback)(Connection* conn);
typedef bool (*match_callback)(Connection*);
struct Config {
AnalyzerTag::Tag tag;
const char* name;
factory_callback factory;
available_callback available;
match_callback match;
bool partial;
};
// Table of analyzers.
static const Config analyzer_configs[];
};
#define ADD_ANALYZER_TIMER(timer, t, do_expire, type) \
AddTimer(analyzer_timer_func(timer), (t), (do_expire), (type))
#define LOOP_OVER_CHILDREN(var) \
for ( analyzer_list::iterator var = children.begin(); \
var != children.end(); var++ )
#define LOOP_OVER_CONST_CHILDREN(var) \
for ( analyzer_list::const_iterator var = children.begin(); \
var != children.end(); var++ )
#define LOOP_OVER_GIVEN_CHILDREN(var, the_kids) \
for ( analyzer_list::iterator var = the_kids.begin(); \
var != the_kids.end(); var++ )
#define LOOP_OVER_GIVEN_CONST_CHILDREN(var, the_kids) \
for ( analyzer_list::const_iterator var = the_kids.begin(); \
var != the_kids.end(); var++ )
class SupportAnalyzer : public Analyzer {
public:
SupportAnalyzer(AnalyzerTag::Tag tag, Connection* conn, bool arg_orig)
: Analyzer(tag, conn) { orig = arg_orig; sibling = 0; }
virtual ~SupportAnalyzer() {}
bool IsOrig() const { return orig; }
virtual void ForwardPacket(int len, const u_char* data, bool orig,
int seq, const IP_Hdr* ip, int caplen);
virtual void ForwardStream(int len, const u_char* data, bool orig);
virtual void ForwardUndelivered(int seq, int len, bool orig);
SupportAnalyzer* Sibling() const { return sibling; }
protected:
friend class Analyzer;
SupportAnalyzer() { }
private:
bool orig;
// Points to next support analyzer in chain. The list is managed by
// parent analyzer.
SupportAnalyzer* sibling;
};
class TransportLayerAnalyzer : public Analyzer {
public:
TransportLayerAnalyzer(AnalyzerTag::Tag tag, Connection* conn)
: Analyzer(tag, conn) { pia = 0; }
virtual void Done();
virtual bool IsReuse(double t, const u_char* pkt) = 0;
virtual void SetContentsFile(unsigned int direction, BroFile* f);
virtual BroFile* GetContentsFile(unsigned int direction) const;
void SetPIA(PIA* arg_PIA) { pia = arg_PIA; }
PIA* GetPIA() const { return pia; }
// Raises packet_contents event.
void PacketContents(const u_char* data, int len);
protected:
TransportLayerAnalyzer() { }
private:
PIA* pia;
};
#endif

View file

@ -1,57 +0,0 @@
#ifndef ANALYZERTAGS_H
#define ANALYZERTAGS_H
// Each kind of analyzer gets a tag. When adding an analyzer here, also adapt
// the table of analyzers in Analyzer.cc.
//
// Using a namespace here is kind of a hack: ideally this would be in "class
// Analyzer {...}". But then we'd have circular dependencies across the header
// files.
#include "util.h"
typedef uint32 AnalyzerID;
namespace AnalyzerTag {
enum Tag {
Error = 0, // used as error code
// Analyzer in charge of protocol detection.
PIA_TCP, PIA_UDP,
// Transport-layer analyzers.
ICMP, TCP, UDP,
// Application-layer analyzers (hand-written).
BitTorrent, BitTorrentTracker,
DCE_RPC, DNS, Finger, FTP, Gnutella, HTTP, Ident, IRC,
Login, NCP, NetbiosSSN, NFS, NTP, POP3, Portmapper, Rlogin,
RPC, Rsh, SMB, SMTP, SSH,
Telnet,
// Application-layer analyzers, binpac-generated.
DHCP_BINPAC, DNS_TCP_BINPAC, DNS_UDP_BINPAC,
HTTP_BINPAC, SSL, SYSLOG_BINPAC,
Modbus,
// Decapsulation analyzers.
AYIYA,
SOCKS,
Teredo,
GTPv1,
// Other
File, IRC_Data, FTP_Data, Backdoor, InterConn, SteppingStone, TCPStats,
ConnSize,
// Support-analyzers
Contents, ContentLine, NVT, Zip, Contents_DNS, Contents_NCP,
Contents_NetbiosSSN, Contents_Rlogin, Contents_Rsh,
Contents_DCE_RPC, Contents_SMB, Contents_RPC, Contents_NFS,
FTP_ADAT,
// End-marker.
LastAnalyzer
};
};
#endif

View file

@ -82,9 +82,7 @@ int* Base64Converter::InitBase64Table(const string& alphabet)
return base64_table;
}
Base64Converter::Base64Converter(Analyzer* arg_analyzer, const string& arg_alphabet)
Base64Converter::Base64Converter(analyzer::Analyzer* arg_analyzer, const string& arg_alphabet)
{
if ( arg_alphabet.size() > 0 )
{

View file

@ -7,7 +7,8 @@
#include "util.h"
#include "BroString.h"
#include "Analyzer.h"
#include "Reporter.h"
#include "analyzer/Analyzer.h"
// Maybe we should have a base class for generic decoders?
class Base64Converter {
@ -15,7 +16,7 @@ public:
// <analyzer> is used for error reporting, and it should be zero when
// the decoder is called by the built-in function decode_base64() or encode_base64().
// Empty alphabet indicates the default base64 alphabet.
Base64Converter(Analyzer* analyzer, const string& alphabet = "");
Base64Converter(analyzer::Analyzer* analyzer, const string& alphabet = "");
~Base64Converter();
// A note on Decode():
@ -62,7 +63,7 @@ protected:
int base64_after_padding;
int* base64_table;
int errored; // if true, we encountered an error - skip further processing
Analyzer* analyzer;
analyzer::Analyzer* analyzer;
};

View file

@ -35,12 +35,14 @@ BroDoc::BroDoc(const std::string& rel, const std::string& abs)
downloadable_filename = source_filename;
#if 0
size_t ext_pos = downloadable_filename.find(".bif.bro");
if ( std::string::npos != ext_pos )
downloadable_filename.erase(ext_pos + 4);
#endif
reST_filename = doc_title;
ext_pos = reST_filename.find(".bro");
size_t ext_pos = reST_filename.find(".bro");
if ( std::string::npos == ext_pos )
reST_filename += ".rst";

View file

@ -3,6 +3,13 @@ include_directories(BEFORE
${CMAKE_CURRENT_BINARY_DIR}
)
# This collects generated bif and pac files from subdirectories.
set(bro_ALL_GENERATED_OUTPUTS CACHE INTERNAL "automatically generated files" FORCE)
# If TRUE, use CMake's object libraries for sub-directories instead of
# static libraries. This requires CMake >= 2.8.8.
set(bro_HAVE_OBJECT_LIBRARIES FALSE)
configure_file(version.c.in ${CMAKE_CURRENT_BINARY_DIR}/version.c)
configure_file(util-config.h.in ${CMAKE_CURRENT_BINARY_DIR}/util-config.h)
@ -100,45 +107,7 @@ target_link_libraries(bifcl)
########################################################################
## bifcl-dependent targets
# A macro to define a command that uses the BIF compiler to produce
# C++ segments and Bro language declarations from .bif file
# The outputs are appended to list ALL_BIF_OUTPUTS
# Outputs that should be installed are appended to INSTALL_BIF_OUTPUTS
macro(BIF_TARGET bifInput)
get_bif_output_files(${bifInput} bifOutputs)
add_custom_command(OUTPUT ${bifOutputs}
COMMAND bifcl
ARGS ${CMAKE_CURRENT_SOURCE_DIR}/${bifInput} || (rm -f ${bifOutputs} && exit 1)
# In order be able to run bro from the build directory,
# the generated bro script needs to be inside a
# a directory tree named the same way it will be
# referenced from an @load.
COMMAND "${CMAKE_COMMAND}"
ARGS -E copy ${bifInput}.bro base/${bifInput}.bro
COMMAND "${CMAKE_COMMAND}"
ARGS -E remove -f ${bifInput}.bro
DEPENDS ${bifInput}
DEPENDS bifcl
COMMENT "[BIFCL] Processing ${bifInput}"
)
list(APPEND ALL_BIF_OUTPUTS ${bifOutputs})
list(APPEND INSTALL_BIF_OUTPUTS
${CMAKE_CURRENT_BINARY_DIR}/base/${bifInput}.bro)
endmacro(BIF_TARGET)
# returns a list of output files that bifcl will produce
# for given input file in ${outputFileVar}
macro(GET_BIF_OUTPUT_FILES inputFile outputFileVar)
set(${outputFileVar}
base/${inputFile}.bro
${inputFile}.func_def
${inputFile}.func_h
${inputFile}.func_init
${inputFile}.netvar_def
${inputFile}.netvar_h
${inputFile}.netvar_init
)
endmacro(GET_BIF_OUTPUT_FILES)
include(BifCl)
set(BIF_SRCS
bro.bif
@ -153,74 +122,53 @@ set(BIF_SRCS
)
foreach (bift ${BIF_SRCS})
bif_target(${bift})
bif_target(${bift} "standard")
endforeach ()
########################################################################
## BinPAC-dependent targets
include(BinPAC)
set(BINPAC_AUXSRC
binpac.pac
bro.pac
binpac_bro.h
${CMAKE_SOURCE_DIR}/src/binpac.pac
${CMAKE_SOURCE_DIR}/src/bro.pac
${CMAKE_SOURCE_DIR}/src/binpac_bro.h
)
# A macro to define a command that uses the BinPac compiler to
# produce C++ code that implements a protocol parser/analyzer
# The outputs of the command are appended to list ALL_BINPAC_OUTPUTS
# All arguments to this macro are appended to list ALL_BINPAC_INPUTS
macro(BINPAC_TARGET pacFile)
get_filename_component(basename ${pacFile} NAME_WE)
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${basename}_pac.h
${CMAKE_CURRENT_BINARY_DIR}/${basename}_pac.cc
COMMAND ${BinPAC_EXE}
ARGS -q -d ${CMAKE_CURRENT_BINARY_DIR}
-I ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/${pacFile}
DEPENDS ${BinPAC_EXE} ${pacFile}
${BINPAC_AUXSRC} ${ARGN}
COMMENT "[BINPAC] Processing ${pacFile}"
)
list(APPEND ALL_BINPAC_INPUTS ${ARGV})
list(APPEND ALL_BINPAC_OUTPUTS
${CMAKE_CURRENT_BINARY_DIR}/${basename}_pac.h
${CMAKE_CURRENT_BINARY_DIR}/${basename}_pac.cc)
endmacro(BINPAC_TARGET)
binpac_target(binpac-lib.pac)
binpac_target(binpac_bro-lib.pac)
list(APPEND BINPAC_OUTPUTS "${BINPAC_OUTPUT_CC}")
binpac_target(ayiya.pac
ayiya-protocol.pac ayiya-analyzer.pac)
binpac_target(bittorrent.pac
bittorrent-protocol.pac bittorrent-analyzer.pac)
binpac_target(dce_rpc.pac
dce_rpc-protocol.pac dce_rpc-analyzer.pac epmapper.pac)
binpac_target(dce_rpc_simple.pac
dce_rpc-protocol.pac epmapper.pac)
binpac_target(dhcp.pac
dhcp-protocol.pac dhcp-analyzer.pac)
binpac_target(dns.pac
dns-protocol.pac dns-analyzer.pac)
binpac_target(dns_tcp.pac
dns.pac)
binpac_target(gtpv1.pac
gtpv1-protocol.pac gtpv1-analyzer.pac)
binpac_target(http.pac
http-protocol.pac http-analyzer.pac)
binpac_target(ncp.pac)
binpac_target(netflow.pac
netflow-protocol.pac netflow-analyzer.pac)
binpac_target(smb.pac
smb-protocol.pac smb-pipe.pac smb-mailslot.pac)
binpac_target(socks.pac
socks-protocol.pac socks-analyzer.pac)
binpac_target(ssl.pac
ssl-defs.pac ssl-protocol.pac ssl-analyzer.pac)
binpac_target(syslog.pac
syslog-protocol.pac syslog-analyzer.pac)
binpac_target(modbus.pac
modbus-protocol.pac modbus-analyzer.pac)
binpac_target(binpac_bro-lib.pac)
list(APPEND BINPAC_OUTPUTS "${BINPAC_OUTPUT_CC}")
########################################################################
## Including subdirectories.
########################################################################
set(bro_SUBDIR_LIBS CACHE INTERNAL "subdir libraries" FORCE)
set(bro_PLUGIN_LIBS CACHE INTERNAL "plugin libraries" FORCE)
add_subdirectory(analyzer)
set(bro_SUBDIRS
${bro_SUBDIR_LIBS}
${bro_PLUGIN_LIBS}
)
if ( NOT bro_HAVE_OBJECT_LIBRARIES )
foreach (_plugin ${bro_PLUGIN_LIBS})
string(REGEX REPLACE "plugin-" "" _plugin "${_plugin}")
string(REGEX REPLACE "-" "_" _plugin "${_plugin}")
set(_decl "namespace plugin { namespace ${_plugin} { class Plugin; extern Plugin __plugin; } };")
set(_use "i += (size_t)(&(plugin::${_plugin}::__plugin));")
set(__BRO_DECL_PLUGINS "${__BRO_DECL_PLUGINS}${_decl}\n")
set(__BRO_USE_PLUGINS "${__BRO_USE_PLUGINS}${_use}\n")
endforeach()
configure_file(plugins.cc.in ${CMAKE_CURRENT_BINARY_DIR}/plugins.cc)
set(PLUGIN_INIT ${CMAKE_CURRENT_BINARY_DIR}/plugins.cc)
endif()
########################################################################
## bro target
@ -240,7 +188,7 @@ endif ()
macro(COLLECT_HEADERS _var)
foreach (src ${ARGN})
get_filename_component(ext ${src} EXT)
if (${ext} STREQUAL ".cc" OR ${ext} STREQUAL ".c")
if ("${ext}" STREQUAL ".cc" OR "${ext}" STREQUAL ".c")
get_filename_component(base ${src} NAME_WE)
get_filename_component(dir ${src} PATH)
if (NOT "${dir}")
@ -275,10 +223,8 @@ set_source_files_properties(nb_dns.c PROPERTIES COMPILE_FLAGS
set(bro_SRCS
${CMAKE_CURRENT_BINARY_DIR}/version.c
${BIF_SRCS}
${ALL_BIF_OUTPUTS}
${BINPAC_AUXSRC}
${ALL_BINPAC_INPUTS}
${ALL_BINPAC_OUTPUTS}
${BINPAC_OUTPUTS}
${TRANSFORMED_BISON_OUTPUTS}
${FLEX_RuleScanner_OUTPUTS}
${FLEX_RuleScanner_INPUT}
@ -290,19 +236,14 @@ set(bro_SRCS
${FLEX_Scanner_INPUT}
${BISON_Parser_INPUT}
${CMAKE_CURRENT_BINARY_DIR}/DebugCmdConstants.h
${PLUGIN_INIT}
main.cc
net_util.cc
util.cc
module_util.cc
Analyzer.cc
Anon.cc
ARP.cc
Attr.cc
AYIYA.cc
BackDoor.cc
Base64.cc
BitTorrent.cc
BitTorrentTracker.cc
BPF_Program.cc
BroDoc.cc
BroDocObj.cc
@ -312,14 +253,7 @@ set(bro_SRCS
ChunkedIO.cc
CompHash.cc
Conn.cc
ConnSizeAnalyzer.cc
ContentLine.cc
DCE_RPC.cc
DFA.cc
DHCP-binpac.cc
DNS.cc
DNS-binpac.cc
DNS_Mgr.cc
DbgBreakpoint.cc
DbgHelp.cc
DbgWatch.cc
@ -329,48 +263,29 @@ set(bro_SRCS
Desc.cc
Dict.cc
Discard.cc
DPM.cc
DNS_Mgr.cc
EquivClass.cc
Event.cc
EventHandler.cc
EventLauncher.cc
EventRegistry.cc
Expr.cc
FTP.cc
File.cc
FileAnalyzer.cc
Finger.cc
FlowSrc.cc
Frag.cc
Frame.cc
Func.cc
Gnutella.cc
GTPv1.cc
HTTP.cc
HTTP-binpac.cc
Hash.cc
ICMP.cc
ID.cc
Ident.cc
IntSet.cc
InterConn.cc
IOSource.cc
IP.cc
IPAddr.cc
IRC.cc
List.cc
Reporter.cc
Login.cc
MIME.cc
Modbus.cc
NCP.cc
NFA.cc
NFS.cc
NTP.cc
NVT.cc
Net.cc
NetVar.cc
NetbiosSSN.cc
Obj.cc
OpaqueVal.cc
OSFinger.cc
@ -378,31 +293,20 @@ set(bro_SRCS
PacketSort.cc
PersistenceSerializer.cc
PktSrc.cc
PIA.cc
PolicyFile.cc
POP3.cc
Portmap.cc
PrefixTable.cc
PriorityQueue.cc
Queue.cc
RandTest.cc
RE.cc
RPC.cc
Reassem.cc
RemoteSerializer.cc
Rlogin.cc
RSH.cc
Rule.cc
RuleAction.cc
RuleCondition.cc
RuleMatcher.cc
ScriptAnaly.cc
SmithWaterman.cc
SMB.cc
SMTP.cc
SOCKS.cc
SSH.cc
SSL.cc
Scope.cc
SerializationFormat.cc
SerialObj.cc
@ -410,24 +314,14 @@ set(bro_SRCS
Sessions.cc
StateAccess.cc
Stats.cc
SteppingStone.cc
Stmt.cc
Syslog-binpac.cc
TCP.cc
TCP_Endpoint.cc
TCP_Reassembler.cc
Telnet.cc
Teredo.cc
Timer.cc
Traverse.cc
Trigger.cc
TunnelEncapsulation.cc
Type.cc
UDP.cc
Val.cc
Var.cc
XDR.cc
ZIP.cc
bsd-getopt-long.c
bro_inet_ntop.c
cq.c
@ -473,18 +367,40 @@ set(bro_SRCS
3rdparty/sqlite3.c
plugin/Component.cc
plugin/Manager.cc
plugin/Plugin.cc
nb_dns.c
digest.h
)
collect_headers(bro_HEADERS ${bro_SRCS})
add_executable(bro ${bro_SRCS} ${bro_HEADERS})
target_link_libraries(bro ${brodeps} ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS})
if ( bro_HAVE_OBJECT_LIBRARIES )
add_executable(bro ${bro_SRCS} ${bro_HEADERS} ${bro_SUBDIRS})
target_link_libraries(bro ${brodeps} ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS})
else ()
add_executable(bro ${bro_SRCS} ${bro_HEADERS})
target_link_libraries(bro ${bro_SUBDIRS} ${brodeps} ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS})
endif ()
install(TARGETS bro DESTINATION bin)
install(FILES ${INSTALL_BIF_OUTPUTS} DESTINATION ${BRO_SCRIPT_INSTALL_PATH}/base)
set(BRO_EXE bro
CACHE STRING "Bro executable binary" FORCE)
# Target to create all the autogenerated files.
add_custom_target(generate_outputs DEPENDS ${bro_ALL_GENERATED_OUTPUTS})
# Build __load__.bro files for plugins/*.bif.bro.
bro_bif_create_loader(bif_loader_plugins ${CMAKE_BINARY_DIR}/scripts/base/bif/plugins)
add_dependencies(bif_loader_plugins ${bro_SUBDIRS})
add_dependencies(bro bif_loader_plugins)
# Install *.bif.bro.
install(DIRECTORY ${CMAKE_BINARY_DIR}/scripts/base/bif DESTINATION ${BRO_SCRIPT_INSTALL_PATH}/base)
# Make clean removes the bif directory.
set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES ${CMAKE_BINARY_DIR}/scripts/base/bif)

View file

@ -11,9 +11,10 @@
#include "Sessions.h"
#include "Reporter.h"
#include "Timer.h"
#include "PIA.h"
#include "analyzer/protocol/pia/PIA.h"
#include "binpac.h"
#include "TunnelEncapsulation.h"
#include "analyzer/Analyzer.h"
void ConnectionTimer::Init(Connection* arg_conn, timer_func arg_timer,
int arg_do_expire)
@ -402,16 +403,21 @@ RecordVal* Connection::BuildConnVal()
return conn_val;
}
Analyzer* Connection::FindAnalyzer(AnalyzerID id)
analyzer::Analyzer* Connection::FindAnalyzer(analyzer::ID id)
{
return root_analyzer ? root_analyzer->FindChild(id) : 0;
}
Analyzer* Connection::FindAnalyzer(AnalyzerTag::Tag tag)
analyzer::Analyzer* Connection::FindAnalyzer(analyzer::Tag tag)
{
return root_analyzer ? root_analyzer->FindChild(tag) : 0;
}
analyzer::Analyzer* Connection::FindAnalyzer(const char* name)
{
return root_analyzer->FindChild(name);
}
void Connection::AppendAddl(const char* str)
{
Unref(BuildConnVal());
@ -540,7 +546,7 @@ Val* Connection::BuildVersionVal(const char* s, int len)
}
int Connection::VersionFoundEvent(const IPAddr& addr, const char* s, int len,
Analyzer* analyzer)
analyzer::Analyzer* analyzer)
{
if ( ! software_version_found && ! software_parse_error )
return 1;
@ -578,7 +584,7 @@ int Connection::VersionFoundEvent(const IPAddr& addr, const char* s, int len,
}
int Connection::UnparsedVersionFoundEvent(const IPAddr& addr,
const char* full, int len, Analyzer* analyzer)
const char* full, int len, analyzer::Analyzer* analyzer)
{
// Skip leading white space.
while ( len && isspace(*full) )
@ -602,7 +608,7 @@ int Connection::UnparsedVersionFoundEvent(const IPAddr& addr,
return 1;
}
void Connection::Event(EventHandlerPtr f, Analyzer* analyzer, const char* name)
void Connection::Event(EventHandlerPtr f, analyzer::Analyzer* analyzer, const char* name)
{
if ( ! f )
return;
@ -615,7 +621,7 @@ void Connection::Event(EventHandlerPtr f, Analyzer* analyzer, const char* name)
ConnectionEvent(f, analyzer, vl);
}
void Connection::Event(EventHandlerPtr f, Analyzer* analyzer, Val* v1, Val* v2)
void Connection::Event(EventHandlerPtr f, analyzer::Analyzer* analyzer, Val* v1, Val* v2)
{
if ( ! f )
{
@ -634,7 +640,7 @@ void Connection::Event(EventHandlerPtr f, Analyzer* analyzer, Val* v1, Val* v2)
ConnectionEvent(f, analyzer, vl);
}
void Connection::ConnectionEvent(EventHandlerPtr f, Analyzer* a, val_list* vl)
void Connection::ConnectionEvent(EventHandlerPtr f, analyzer::Analyzer* a, val_list* vl)
{
if ( ! f )
{
@ -929,7 +935,7 @@ error:
return false;
}
void Connection::SetRootAnalyzer(TransportLayerAnalyzer* analyzer, PIA* pia)
void Connection::SetRootAnalyzer(analyzer::TransportLayerAnalyzer* analyzer, analyzer::pia::PIA* pia)
{
root_analyzer = analyzer;
primary_PIA = pia;

View file

@ -11,19 +11,22 @@
#include "Serializer.h"
#include "PersistenceSerializer.h"
#include "RuleMatcher.h"
#include "AnalyzerTags.h"
#include "IPAddr.h"
#include "TunnelEncapsulation.h"
#include "analyzer/Tag.h"
#include "analyzer/Analyzer.h"
class Connection;
class ConnectionTimer;
class NetSessions;
class LoginConn;
class RuleHdrTest;
class Specific_RE_Matcher;
class TransportLayerAnalyzer;
class RuleEndpointState;
namespace analyzer { class TransportLayerAnalyzer; }
typedef enum {
NUL_IN_LINE,
SINGULAR_CR,
@ -47,7 +50,7 @@ static inline int addr_port_canon_lt(const IPAddr& addr1, uint32 p1,
return addr1 < addr2 || (addr1 == addr2 && p1 < p2);
}
class Analyzer;
namespace analyzer { class Analyzer; }
class Connection : public BroObj {
public:
@ -102,8 +105,9 @@ public:
void FlipRoles();
Analyzer* FindAnalyzer(AnalyzerID id);
Analyzer* FindAnalyzer(AnalyzerTag::Tag tag); // find first in tree.
analyzer::Analyzer* FindAnalyzer(analyzer::ID id);
analyzer::Analyzer* FindAnalyzer(analyzer::Tag tag); // find first in tree.
analyzer::Analyzer* FindAnalyzer(const char* name); // find first in tree.
TransportProto ConnTransport() const { return proto; }
@ -161,15 +165,15 @@ public:
// Raises a software_version_found event based on the
// given string (returns false if it's not parseable).
int VersionFoundEvent(const IPAddr& addr, const char* s, int len,
Analyzer* analyzer = 0);
analyzer::Analyzer* analyzer = 0);
// Raises a software_unparsed_version_found event.
int UnparsedVersionFoundEvent(const IPAddr& addr,
const char* full_descr, int len, Analyzer* analyzer);
const char* full_descr, int len, analyzer::Analyzer* analyzer);
void Event(EventHandlerPtr f, Analyzer* analyzer, const char* name = 0);
void Event(EventHandlerPtr f, Analyzer* analyzer, Val* v1, Val* v2 = 0);
void ConnectionEvent(EventHandlerPtr f, Analyzer* analyzer,
void Event(EventHandlerPtr f, analyzer::Analyzer* analyzer, const char* name = 0);
void Event(EventHandlerPtr f, analyzer::Analyzer* analyzer, Val* v1, Val* v2 = 0);
void ConnectionEvent(EventHandlerPtr f, analyzer::Analyzer* analyzer,
val_list* vl);
void Weird(const char* name, const char* addl = "");
@ -241,9 +245,9 @@ public:
void DeleteTimer(double t);
// Sets the root of the analyzer tree as well as the primary PIA.
void SetRootAnalyzer(TransportLayerAnalyzer* analyzer, PIA* pia);
TransportLayerAnalyzer* GetRootAnalyzer() { return root_analyzer; }
PIA* GetPrimaryPIA() { return primary_PIA; }
void SetRootAnalyzer(analyzer::TransportLayerAnalyzer* analyzer, analyzer::pia::PIA* pia);
analyzer::TransportLayerAnalyzer* GetRootAnalyzer() { return root_analyzer; }
analyzer::pia::PIA* GetPrimaryPIA() { return primary_PIA; }
// Sets the transport protocol in use.
void SetTransport(TransportProto arg_proto) { proto = arg_proto; }
@ -314,8 +318,8 @@ protected:
string history;
uint32 hist_seen;
TransportLayerAnalyzer* root_analyzer;
PIA* primary_PIA;
analyzer::TransportLayerAnalyzer* root_analyzer;
analyzer::pia::PIA* primary_PIA;
uint64 uid; // Globally unique connection ID.
};

View file

@ -1,24 +0,0 @@
#include "DHCP-binpac.h"
DHCP_Analyzer_binpac::DHCP_Analyzer_binpac(Connection* conn)
: Analyzer(AnalyzerTag::DHCP_BINPAC, conn)
{
interp = new binpac::DHCP::DHCP_Conn(this);
}
DHCP_Analyzer_binpac::~DHCP_Analyzer_binpac()
{
delete interp;
}
void DHCP_Analyzer_binpac::Done()
{
Analyzer::Done();
}
void DHCP_Analyzer_binpac::DeliverPacket(int len, const u_char* data,
bool orig, int seq, const IP_Hdr* ip, int caplen)
{
Analyzer::DeliverPacket(len, data, orig, seq, ip, caplen);
interp->NewData(orig, data, data + len);
}

View file

@ -1,28 +0,0 @@
#ifndef dhcp_binpac_h
#define dhcp_binpac_h
#include "UDP.h"
#include "dhcp_pac.h"
class DHCP_Analyzer_binpac : public Analyzer {
public:
DHCP_Analyzer_binpac(Connection* conn);
virtual ~DHCP_Analyzer_binpac();
virtual void Done();
virtual void DeliverPacket(int len, const u_char* data, bool orig,
int seq, const IP_Hdr* ip, int caplen);
static Analyzer* InstantiateAnalyzer(Connection* conn)
{ return new DHCP_Analyzer_binpac(conn); }
static bool Available()
{ return dhcp_request && FLAGS_use_binpac; }
protected:
binpac::DHCP::DHCP_Conn* interp;
};
#endif

View file

@ -1,90 +0,0 @@
#include "DNS-binpac.h"
#include "TCP_Reassembler.h"
DNS_UDP_Analyzer_binpac::DNS_UDP_Analyzer_binpac(Connection* conn)
: Analyzer(AnalyzerTag::DNS_UDP_BINPAC, conn)
{
interp = new binpac::DNS::DNS_Conn(this);
did_session_done = 0;
ADD_ANALYZER_TIMER(&DNS_UDP_Analyzer_binpac::ExpireTimer,
network_time + dns_session_timeout, 1, TIMER_DNS_EXPIRE);
}
DNS_UDP_Analyzer_binpac::~DNS_UDP_Analyzer_binpac()
{
delete interp;
}
void DNS_UDP_Analyzer_binpac::Done()
{
Analyzer::Done();
if ( ! did_session_done )
Event(udp_session_done);
}
void DNS_UDP_Analyzer_binpac::DeliverPacket(int len, const u_char* data, bool orig, int seq, const IP_Hdr* ip, int caplen)
{
Analyzer::DeliverPacket(len, data, orig, seq, ip, caplen);
interp->NewData(orig, data, data + len);
}
void DNS_UDP_Analyzer_binpac::ExpireTimer(double t)
{
// The - 1.0 in the following is to allow 1 second for the
// common case of a single request followed by a single reply,
// so we don't needlessly set the timer twice in that case.
if ( t - Conn()->LastTime() >= dns_session_timeout - 1.0 || terminating )
{
Event(connection_timeout);
sessions->Remove(Conn());
}
else
ADD_ANALYZER_TIMER(&DNS_UDP_Analyzer_binpac::ExpireTimer,
t + dns_session_timeout, 1, TIMER_DNS_EXPIRE);
}
DNS_TCP_Analyzer_binpac::DNS_TCP_Analyzer_binpac(Connection* conn)
: TCP_ApplicationAnalyzer(AnalyzerTag::DNS_TCP_BINPAC, conn)
{
interp = new binpac::DNS_on_TCP::DNS_TCP_Conn(this);
}
DNS_TCP_Analyzer_binpac::~DNS_TCP_Analyzer_binpac()
{
delete interp;
}
void DNS_TCP_Analyzer_binpac::Done()
{
TCP_ApplicationAnalyzer::Done();
interp->FlowEOF(true);
interp->FlowEOF(false);
}
void DNS_TCP_Analyzer_binpac::EndpointEOF(bool is_orig)
{
TCP_ApplicationAnalyzer::EndpointEOF(is_orig);
interp->FlowEOF(is_orig);
}
void DNS_TCP_Analyzer_binpac::DeliverStream(int len, const u_char* data,
bool orig)
{
TCP_ApplicationAnalyzer::DeliverStream(len, data, orig);
assert(TCP());
if ( TCP()->IsPartial() || TCP()->HadGap(orig) )
// punt-on-partial or stop-on-gap.
return;
interp->NewData(orig, data, data + len);
}
void DNS_TCP_Analyzer_binpac::Undelivered(int seq, int len, bool orig)
{
TCP_ApplicationAnalyzer::Undelivered(seq, len, orig);
interp->NewGap(orig, len);
}

View file

@ -1,60 +0,0 @@
#ifndef dns_binpac_h
#define dns_binpac_h
#include "UDP.h"
#include "TCP.h"
#include "dns_pac.h"
// FIXME: As the binpac analyer for DNS-TCP and DNS-UDP are currently
// structured, we cannot directly combine them into one analyzer. Can we
// change that easily? (Ideally, the TCP preprocessing would become a
// support-analyzer as it is done for the traditional DNS analyzer.)
class DNS_UDP_Analyzer_binpac : public Analyzer {
public:
DNS_UDP_Analyzer_binpac(Connection* conn);
virtual ~DNS_UDP_Analyzer_binpac();
virtual void Done();
virtual void DeliverPacket(int len, const u_char* data, bool orig,
int seq, const IP_Hdr* ip, int caplen);
static Analyzer* InstantiateAnalyzer(Connection* conn)
{ return new DNS_UDP_Analyzer_binpac(conn); }
static bool Available()
{ return (dns_request || dns_full_request) && FLAGS_use_binpac; }
protected:
friend class AnalyzerTimer;
void ExpireTimer(double t);
int did_session_done;
binpac::DNS::DNS_Conn* interp;
};
#include "dns_tcp_pac.h"
class DNS_TCP_Analyzer_binpac : public TCP_ApplicationAnalyzer {
public:
DNS_TCP_Analyzer_binpac(Connection* conn);
virtual ~DNS_TCP_Analyzer_binpac();
virtual void Done();
virtual void DeliverStream(int len, const u_char* data, bool orig);
virtual void Undelivered(int seq, int len, bool orig);
virtual void EndpointEOF(bool is_orig);
static Analyzer* InstantiateAnalyzer(Connection* conn)
{ return new DNS_TCP_Analyzer_binpac(conn); }
static bool Available()
{ return (dns_request || dns_full_request) && FLAGS_use_binpac; }
protected:
binpac::DNS_on_TCP::DNS_TCP_Conn* interp;
};
#endif

View file

@ -1,407 +0,0 @@
#include "DPM.h"
#include "PIA.h"
#include "Hash.h"
#include "ICMP.h"
#include "UDP.h"
#include "TCP.h"
#include "Val.h"
#include "BackDoor.h"
#include "InterConn.h"
#include "SteppingStone.h"
#include "ConnSizeAnalyzer.h"
ExpectedConn::ExpectedConn(const IPAddr& _orig, const IPAddr& _resp,
uint16 _resp_p, uint16 _proto)
{
if ( _orig == IPAddr(string("0.0.0.0")) )
// don't use the IPv4 mapping, use the literal unspecified address
// to indicate a wildcard
orig = IPAddr(string("::"));
else
orig = _orig;
resp = _resp;
resp_p = _resp_p;
proto = _proto;
}
ExpectedConn::ExpectedConn(const ExpectedConn& c)
{
orig = c.orig;
resp = c.resp;
resp_p = c.resp_p;
proto = c.proto;
}
DPM::DPM()
: active_analyzers(0), expected_conns_queue(AssignedAnalyzer::compare)
{
}
DPM::~DPM()
{
delete [] active_analyzers;
}
void DPM::PreScriptInit()
{
for ( int i = 1; i < int(AnalyzerTag::LastAnalyzer); i++ )
{
// Create IDs ANALYZER_*.
ID* id = install_ID(fmt("ANALYZER_%s",
Analyzer::analyzer_configs[i].name),
GLOBAL_MODULE_NAME, true, false);
assert(id);
id->SetVal(new Val(i, TYPE_COUNT));
id->SetType(id->ID_Val()->Type()->Ref());
}
}
void DPM::PostScriptInit()
{
active_analyzers = new bool[int(AnalyzerTag::LastAnalyzer)];
for ( int i = 1; i < int(AnalyzerTag::LastAnalyzer); i++ )
{
if ( ! Analyzer::analyzer_configs[i].available )
continue;
active_analyzers[i] = Analyzer::analyzer_configs[i].available();
if ( active_analyzers[i] )
AddConfig(Analyzer::analyzer_configs[i]);
}
}
void DPM::AddConfig(const Analyzer::Config& cfg)
{
#ifdef USE_PERFTOOLS_DEBUG
HeapLeakChecker::Disabler disabler;
#endif
Val* index = new Val(cfg.tag, TYPE_COUNT);
Val* v = dpd_config->Lookup(index);
#ifdef DEBUG
ODesc desc;
#endif
if ( v )
{
RecordVal* cfg_record = v->AsRecordVal();
Val* ports = cfg_record->Lookup(0);
if ( ports )
{
ListVal* plist = ports->AsTableVal()->ConvertToPureList();
for ( int i = 0; i< plist->Length(); ++i )
{
PortVal* port = plist->Index(i)->AsPortVal();
analyzer_map* ports =
port->IsTCP() ? &tcp_ports : &udp_ports;
analyzer_map::iterator j =
ports->find(port->Port());
if ( j == ports->end() )
{
tag_list* analyzers = new tag_list;
analyzers->push_back(cfg.tag);
ports->insert(analyzer_map::value_type(port->Port(), analyzers));
}
else
j->second->push_back(cfg.tag);
#ifdef DEBUG
port->Describe(&desc);
desc.SP();
#endif
}
}
}
DBG_LOG(DBG_DPD, "%s analyzer active on port(s) %s", cfg.name, desc.Description());
Unref(index);
}
AnalyzerTag::Tag DPM::GetExpected(int proto, const Connection* conn)
{
if ( ! expected_conns.Length() )
return AnalyzerTag::Error;
ExpectedConn c(conn->OrigAddr(), conn->RespAddr(),
ntohs(conn->RespPort()), proto);
HashKey* key = BuildExpectedConnHashKey(c);
AssignedAnalyzer* a = expected_conns.Lookup(key);
delete key;
if ( ! a )
{
// Wildcard for originator.
c.orig = IPAddr(string("::"));
HashKey* key = BuildExpectedConnHashKey(c);
a = expected_conns.Lookup(key);
delete key;
}
if ( ! a )
return AnalyzerTag::Error;
// We don't delete it here. It will be expired eventually.
return a->analyzer;
}
bool DPM::BuildInitialAnalyzerTree(TransportProto proto, Connection* conn,
const u_char* data)
{
TCP_Analyzer* tcp = 0;
UDP_Analyzer* udp = 0;
ICMP_Analyzer* icmp = 0;
TransportLayerAnalyzer* root = 0;
AnalyzerTag::Tag expected = AnalyzerTag::Error;
analyzer_map* ports = 0;
PIA* pia = 0;
bool analyzed = false;
switch ( proto ) {
case TRANSPORT_TCP:
root = tcp = new TCP_Analyzer(conn);
pia = new PIA_TCP(conn);
expected = GetExpected(proto, conn);
ports = &tcp_ports;
DBG_DPD(conn, "activated TCP analyzer");
break;
case TRANSPORT_UDP:
root = udp = new UDP_Analyzer(conn);
pia = new PIA_UDP(conn);
expected = GetExpected(proto, conn);
ports = &udp_ports;
DBG_DPD(conn, "activated UDP analyzer");
break;
case TRANSPORT_ICMP: {
root = icmp = new ICMP_Analyzer(conn);
DBG_DPD(conn, "activated ICMP analyzer");
analyzed = true;
break;
}
default:
reporter->InternalError("unknown protocol");
}
if ( ! root )
{
DBG_DPD(conn, "cannot build analyzer tree");
return false;
}
// Any scheduled analyzer?
if ( expected != AnalyzerTag::Error )
{
Analyzer* analyzer =
Analyzer::InstantiateAnalyzer(expected, conn);
root->AddChildAnalyzer(analyzer, false);
DBG_DPD_ARGS(conn, "activated %s analyzer as scheduled",
Analyzer::GetTagName(expected));
// Hmm... Do we want *just* the expected analyzer, or all
// other potential analyzers as well? For now we only take
// the scheduled one.
}
else
{ // Let's see if it's a port we know.
if ( ports && ! dpd_ignore_ports )
{
analyzer_map::const_iterator i =
ports->find(ntohs(conn->RespPort()));
if ( i != ports->end() )
{
tag_list* analyzers = i->second;
for ( tag_list::const_iterator j = analyzers->begin();
j != analyzers->end(); j++ )
{
Analyzer* analyzer =
Analyzer::InstantiateAnalyzer(*j, conn);
root->AddChildAnalyzer(analyzer, false);
DBG_DPD_ARGS(conn, "activated %s analyzer due to port %d", Analyzer::GetTagName(*j), conn->RespPort());
}
}
}
}
if ( tcp )
{
// We have to decide whether to reassamble the stream.
// We turn it on right away if we already have an app-layer
// analyzer, reassemble_first_packets is true, or the user
// asks us to do so. In all other cases, reassembly may
// be turned on later by the TCP PIA.
bool reass = root->GetChildren().size() ||
dpd_reassemble_first_packets ||
tcp_content_deliver_all_orig ||
tcp_content_deliver_all_resp;
if ( tcp_contents && ! reass )
{
PortVal dport(ntohs(conn->RespPort()), TRANSPORT_TCP);
Val* result;
if ( ! reass )
reass = tcp_content_delivery_ports_orig->Lookup(&dport);
if ( ! reass )
reass = tcp_content_delivery_ports_resp->Lookup(&dport);
}
if ( reass )
tcp->EnableReassembly();
// Add a BackDoor analyzer if requested. This analyzer
// can handle both reassembled and non-reassembled input.
if ( BackDoor_Analyzer::Available() )
{
BackDoor_Analyzer* bd = new BackDoor_Analyzer(conn);
tcp->AddChildAnalyzer(bd, false);
}
// Add a InterConn analyzer if requested. This analyzer
// can handle both reassembled and non-reassembled input.
if ( InterConn_Analyzer::Available() )
{
InterConn_Analyzer* bd = new InterConn_Analyzer(conn);
tcp->AddChildAnalyzer(bd, false);
}
// Add a SteppingStone analyzer if requested. The port
// should really not be hardcoded here, but as it can
// handle non-reassembled data, it doesn't really fit into
// our general framing ... Better would be to turn it
// on *after* we discover we have interactive traffic.
uint16 resp_port = ntohs(conn->RespPort());
if ( SteppingStone_Analyzer::Available() &&
(resp_port == 22 || resp_port == 23 || resp_port == 513) )
{
AddrVal src(conn->OrigAddr());
if ( ! stp_skip_src->Lookup(&src) )
{
SteppingStone_Analyzer* bd =
new SteppingStone_Analyzer(conn);
tcp->AddChildAnalyzer(bd, false);
}
}
// Add TCPStats analyzer. This needs to see packets so
// we cannot add it as a normal child.
if ( TCPStats_Analyzer::Available() )
tcp->AddChildPacketAnalyzer(new TCPStats_Analyzer(conn));
// Add ConnSize analyzer. Needs to see packets, not stream.
if ( ConnSize_Analyzer::Available() )
tcp->AddChildPacketAnalyzer(new ConnSize_Analyzer(conn));
}
else
{
if ( ConnSize_Analyzer::Available() )
root->AddChildAnalyzer(new ConnSize_Analyzer(conn), false);
}
if ( pia )
root->AddChildAnalyzer(pia->AsAnalyzer(), false);
if ( root->GetChildren().size() )
analyzed = true;
conn->SetRootAnalyzer(root, pia);
root->Init();
root->InitChildren();
if ( ! analyzed )
conn->SetLifetime(non_analyzed_lifetime);
if ( expected != AnalyzerTag::Error )
conn->Event(expected_connection_seen, 0,
new Val(expected, TYPE_COUNT));
return true;
}
void DPM::ExpectConnection(const IPAddr& orig, const IPAddr& resp,
uint16 resp_p,
TransportProto proto, AnalyzerTag::Tag analyzer,
double timeout, void* cookie)
{
// Use the chance to see if the oldest entry is already expired.
if ( expected_conns_queue.size() )
{
AssignedAnalyzer* a = expected_conns_queue.top();
if ( a->timeout < network_time )
{
if ( ! a->deleted )
{
HashKey* key = BuildExpectedConnHashKey(a->conn);
expected_conns.Remove(key);
delete key;
}
expected_conns_queue.pop();
DBG_LOG(DBG_DPD, "Expired expected %s analyzer for %s",
Analyzer::GetTagName(analyzer),
fmt_conn_id(a->conn.orig, 0,
a->conn.resp,
a->conn.resp_p));
delete a;
}
}
ExpectedConn c(orig, resp, resp_p, proto);
HashKey* key = BuildExpectedConnHashKey(c);
AssignedAnalyzer* a = expected_conns.Lookup(key);
if ( a )
a->deleted = true;
a = new AssignedAnalyzer(c);
a->analyzer = analyzer;
a->cookie = cookie;
a->timeout = network_time + timeout;
a->deleted = false;
expected_conns.Insert(key, a);
expected_conns_queue.push(a);
delete key;
}
void DPM::Done()
{
// Clean up expected-connection table.
while ( expected_conns_queue.size() )
{
AssignedAnalyzer* a = expected_conns_queue.top();
if ( ! a->deleted )
{
HashKey* key = BuildExpectedConnHashKey(a->conn);
expected_conns.Remove(key);
delete key;
}
expected_conns_queue.pop();
delete a;
}
}

131
src/DPM.h
View file

@ -1,131 +0,0 @@
// The central management unit for dynamic analyzer selection.
#ifndef DPM_H
#define DPM_H
#include <queue>
#include "Analyzer.h"
#include "Dict.h"
#include "net_util.h"
// DPM debug logging, which includes the connection id into the message.
#ifdef DEBUG
# define DBG_DPD(conn, txt) \
DBG_LOG(DBG_DPD, "%s " txt, \
fmt_conn_id(conn->OrigAddr(), ntohs(conn->OrigPort()), \
conn->RespAddr(), ntohs(conn->RespPort())));
# define DBG_DPD_ARGS(conn, fmt, args...) \
DBG_LOG(DBG_DPD, "%s " fmt, \
fmt_conn_id(conn->OrigAddr(), ntohs(conn->OrigPort()), \
conn->RespAddr(), ntohs(conn->RespPort())), ##args);
#else
# define DBG_DPD(conn, txt)
# define DBG_DPD_ARGS(conn, fmt, args...)
#endif
// Map to assign expected connections to analyzers.
class ExpectedConn {
public:
ExpectedConn(const IPAddr& _orig, const IPAddr& _resp,
uint16 _resp_p, uint16 _proto);
ExpectedConn(const ExpectedConn& c);
IPAddr orig;
IPAddr resp;
uint16 resp_p;
uint16 proto;
};
// Associates an analyzer for an expected future connection.
class AssignedAnalyzer {
public:
AssignedAnalyzer(const ExpectedConn& c)
: conn(c)
{
}
ExpectedConn conn;
AnalyzerTag::Tag analyzer;
double timeout;
void* cookie;
bool deleted;
static bool compare(const AssignedAnalyzer* a1, const AssignedAnalyzer* a2)
{ return a1->timeout > a2->timeout; }
};
declare(PDict, AssignedAnalyzer);
class DPM {
public:
DPM();
~DPM();
// Setup analyzer config.
void PreScriptInit(); // To be called before scripts are parsed ...
void PostScriptInit(); // ... and after.
// Given info about the first packet, build initial analyzer tree.
//
// It would be more flexible if we simply pass in the IP header
// and then extract the information we need. However, when this
// method is called from the session management, protocol and ports
// have already been extracted there and it would be a waste to do
// it again.
//
// Returns 0 if we can't build a tree (e.g., because the necessary
// analyzers have not been converted to the DPM framework yet...)
bool BuildInitialAnalyzerTree(TransportProto proto, Connection* conn,
const u_char* data);
// Schedules a particular analyzer for an upcoming connection.
// 0 acts as a wildcard for orig. (Cookie is currently unused.
// Eventually, we may pass it on to the analyzer).
void ExpectConnection(const IPAddr& orig, const IPAddr& resp, uint16 resp_p,
TransportProto proto, AnalyzerTag::Tag analyzer,
double timeout, void* cookie);
// Activates signature matching for protocol detection. (Called when an
// DPM signatures is found.)
void ActivateSigs() { sigs_activated = true; }
bool SigsActivated() const { return sigs_activated; }
void Done();
private:
// Convert script-level config into internal data structures.
void AddConfig(const Analyzer::Config& tag);
// Return analyzer if any has been scheduled with ExpectConnection()
// AnalyzerTag::::Error if none.
AnalyzerTag::Tag GetExpected(int proto, const Connection* conn);
// Mappings of destination port to analyzer.
typedef list<AnalyzerTag::Tag> tag_list;
typedef map<uint32, tag_list*> analyzer_map;
analyzer_map tcp_ports;
analyzer_map udp_ports;
// Array of bools indicating whether an analyzer is activated,
// indexed by AnalyzerTag::Tag.
bool* active_analyzers;
// True if signature-matching has been activated.
bool sigs_activated;
PDict(AssignedAnalyzer) expected_conns;
typedef priority_queue<
AssignedAnalyzer*,
vector<AssignedAnalyzer*>,
bool (*)(const AssignedAnalyzer*,
const AssignedAnalyzer*)> conn_queue;
conn_queue expected_conns_queue;
};
extern DPM* dpm;
#endif

View file

@ -21,7 +21,7 @@ enum DebugStream {
DBG_STRING, // String code
DBG_NOTIFIERS, // Notifiers (see StateAccess.h)
DBG_MAINLOOP, // Main IOSource loop
DBG_DPD, // Dynamic application detection framework
DBG_ANALYZER, // Analyzer framework
DBG_TM, // Time-machine packet input via Brocolli
DBG_LOGGING, // Logging streams
DBG_INPUT, // Input streams

View file

@ -13,7 +13,7 @@ int num_events_queued = 0;
int num_events_dispatched = 0;
Event::Event(EventHandlerPtr arg_handler, val_list* arg_args,
SourceID arg_src, AnalyzerID arg_aid, TimerMgr* arg_mgr,
SourceID arg_src, analyzer::ID arg_aid, TimerMgr* arg_mgr,
BroObj* arg_obj)
{
handler = arg_handler;

View file

@ -5,14 +5,16 @@
#include "EventRegistry.h"
#include "Serializer.h"
#include "AnalyzerTags.h"
#include "analyzer/Tag.h"
#include "analyzer/Analyzer.h"
class EventMgr;
class Event : public BroObj {
public:
Event(EventHandlerPtr handler, val_list* args,
SourceID src = SOURCE_LOCAL, AnalyzerID aid = 0,
SourceID src = SOURCE_LOCAL, analyzer::ID aid = 0,
TimerMgr* mgr = 0, BroObj* obj = 0);
~Event();
@ -20,7 +22,7 @@ public:
Event* NextEvent() const { return next_event; }
SourceID Source() const { return src; }
AnalyzerID Analyzer() const { return aid; }
analyzer::ID Analyzer() const { return aid; }
TimerMgr* Mgr() const { return mgr; }
void Describe(ODesc* d) const;
@ -62,7 +64,7 @@ protected:
EventHandlerPtr handler;
val_list* args;
SourceID src;
AnalyzerID aid;
analyzer::ID aid;
TimerMgr* mgr;
BroObj* obj;
Event* next_event;
@ -77,7 +79,7 @@ public:
~EventMgr();
void QueueEvent(EventHandlerPtr h, val_list* vl,
SourceID src = SOURCE_LOCAL, AnalyzerID aid = 0,
SourceID src = SOURCE_LOCAL, analyzer::ID aid = 0,
TimerMgr* mgr = 0, BroObj* obj = 0)
{
if ( h )
@ -105,7 +107,7 @@ public:
// Returns the ID of the analyzer which raised the last event, or 0 if
// non-analyzer event.
AnalyzerID CurrentAnalyzer() const { return current_aid; }
analyzer::ID CurrentAnalyzer() const { return current_aid; }
// Returns the timer mgr associated with the last raised event.
TimerMgr* CurrentTimerMgr() const { return current_mgr; }
@ -124,7 +126,7 @@ protected:
Event* head;
Event* tail;
SourceID current_src;
AnalyzerID current_aid;
analyzer::ID current_aid;
TimerMgr* current_mgr;
RecordVal* src_val;
bool draining;

View file

@ -10,7 +10,6 @@ EventHandler::EventHandler(const char* arg_name)
used = false;
local = 0;
type = 0;
group = 0;
error_handler = false;
enabled = true;
}
@ -19,7 +18,6 @@ EventHandler::~EventHandler()
{
Unref(local);
delete [] name;
delete [] group;
}
EventHandler::operator bool() const

View file

@ -41,10 +41,6 @@ public:
void SetErrorHandler() { error_handler = true; }
bool ErrorHandler() { return error_handler; }
const char* Group() { return group; }
void SetGroup(const char* arg_group)
{ group = copy_string(arg_group); }
void SetEnable(bool arg_enable) { enabled = arg_enable; }
// We don't serialize the handler(s) itself here, but
@ -54,7 +50,6 @@ public:
private:
const char* name;
const char* group;
Func* local;
FuncType* type;
bool used; // this handler is indeed used somewhere

View file

@ -1,6 +1,8 @@
#include "Val.h"
#include "Analyzer.h"
#include "analyzer/Analyzer.h"
#include "EventLauncher.h"
#include "Event.h"
#include "NetVar.h"
#include "Conn.h"
#include "event.bif.func_def"

View file

@ -80,20 +80,13 @@ void EventRegistry::PrintDebug()
while ( (v = handlers.NextEntry(k, c)) )
{
delete k;
fprintf(stderr, "Registered event %s (%s handler)\n", v->Name(),
v->LocalHandler()? "local" : "no");
fprintf(stderr, "Registered event %s (%s handler / %s)\n", v->Name(),
v->LocalHandler()? "local" : "no",
*v ? "active" : "not active"
);
}
}
void EventRegistry::SetGroup(const char* name, const char* group)
{
EventHandler* eh = Lookup(name);
if ( ! eh )
reporter->InternalError("unknown event handler in SetGroup()");
eh->SetGroup(group);
}
void EventRegistry::SetErrorHandler(const char* name)
{
EventHandler* eh = Lookup(name);
@ -103,18 +96,3 @@ void EventRegistry::SetErrorHandler(const char* name)
eh->SetErrorHandler();
}
void EventRegistry::EnableGroup(const char* group, bool enable)
{
IterCookie* c = handlers.InitForIteration();
HashKey* k;
EventHandler* v;
while ( (v = handlers.NextEntry(k, c)) )
{
delete k;
if ( v->Group() && strcmp(v->Group(), group) == 0 )
v->SetEnable(enable);
}
}

View file

@ -26,17 +26,11 @@ public:
typedef PList(constchar) string_list;
string_list* Match(RE_Matcher* pattern);
// Associates a group with the given event.
void SetGroup(const char* name, const char* group);
// Marks a handler as handling errors. Error handler will not be called
// recursively to avoid infinite loops in case they trigger an error
// themselves.
void SetErrorHandler(const char* name);
// Enable/disable all members of the group.
void EnableGroup(const char* group, bool enable);
string_list* UnusedHandlers();
string_list* UsedHandlers();
void PrintDebug();

View file

@ -1,30 +0,0 @@
// See the file "COPYING" in the main distribution directory for copyright.
#ifndef finger_h
#define finger_h
#include "TCP.h"
class ContentLine_Analyzer;
class Finger_Analyzer : public TCP_ApplicationAnalyzer {
public:
Finger_Analyzer(Connection* conn);
virtual ~Finger_Analyzer() {}
virtual void Done();
// Line-based input.
virtual void DeliverStream(int len, const u_char* data, bool orig);
static Analyzer* InstantiateAnalyzer(Connection* conn)
{ return new Finger_Analyzer(conn); }
static bool Available() { return finger_request || finger_reply; }
protected:
ContentLine_Analyzer* content_line_orig;
ContentLine_Analyzer* content_line_resp;
int did_deliver;
};
#endif

View file

@ -9,7 +9,7 @@
#include "FlowSrc.h"
#include "Net.h"
#include "netflow_pac.h"
#include "analyzer/protocol/netflow/netflow_pac.h"
#include <errno.h>
FlowSrc::FlowSrc()

View file

@ -38,7 +38,7 @@
#include "Func.h"
#include "Frame.h"
#include "Var.h"
#include "Login.h"
#include "analyzer/protocol/login/Login.h"
#include "Sessions.h"
#include "RE.h"
#include "Serializer.h"
@ -564,7 +564,6 @@ void builtin_error(const char* msg, BroObj* arg)
void init_builtin_funcs()
{
ftp_port = internal_type("ftp_port")->AsRecordType();
bro_resources = internal_type("bro_resources")->AsRecordType();
net_stats = internal_type("NetStats")->AsRecordType();
matcher_stats = internal_type("matcher_stats")->AsRecordType();

View file

@ -1,46 +0,0 @@
#include "HTTP-binpac.h"
#include "TCP_Reassembler.h"
HTTP_Analyzer_binpac::HTTP_Analyzer_binpac(Connection *c)
: TCP_ApplicationAnalyzer(AnalyzerTag::HTTP_BINPAC, c)
{
interp = new binpac::HTTP::HTTP_Conn(this);
}
HTTP_Analyzer_binpac::~HTTP_Analyzer_binpac()
{
delete interp;
}
void HTTP_Analyzer_binpac::Done()
{
TCP_ApplicationAnalyzer::Done();
interp->FlowEOF(true);
interp->FlowEOF(false);
}
void HTTP_Analyzer_binpac::EndpointEOF(bool is_orig)
{
TCP_ApplicationAnalyzer::EndpointEOF(is_orig);
interp->FlowEOF(is_orig);
}
void HTTP_Analyzer_binpac::DeliverStream(int len, const u_char* data, bool orig)
{
TCP_ApplicationAnalyzer::DeliverStream(len, data, orig);
assert(TCP());
if ( TCP()->IsPartial() )
// punt on partial.
return;
interp->NewData(orig, data, data + len);
}
void HTTP_Analyzer_binpac::Undelivered(int seq, int len, bool orig)
{
TCP_ApplicationAnalyzer::Undelivered(seq, len, orig);
interp->NewGap(orig, len);
}

View file

@ -1,28 +0,0 @@
#ifndef http_binpac_h
#define http_binpac_h
#include "TCP.h"
#include "http_pac.h"
class HTTP_Analyzer_binpac : public TCP_ApplicationAnalyzer {
public:
HTTP_Analyzer_binpac(Connection* conn);
virtual ~HTTP_Analyzer_binpac();
virtual void Done();
virtual void DeliverStream(int len, const u_char* data, bool orig);
virtual void Undelivered(int seq, int len, bool orig);
virtual void EndpointEOF(bool is_orig);
static Analyzer* InstantiateAnalyzer(Connection* conn)
{ return new HTTP_Analyzer_binpac(conn); }
static bool Available()
{ return (http_request || http_reply) && FLAGS_use_binpac; }
protected:
binpac::HTTP::HTTP_Conn* interp;
};
#endif

View file

@ -221,21 +221,7 @@ void ID::UpdateValAttrs()
if ( Type()->Tag() == TYPE_FUNC )
{
Attr* attr = attrs->FindAttr(ATTR_GROUP);
if ( attr )
{
Val* group = attr->AttrExpr()->ExprVal();
if ( group )
{
if ( group->Type()->Tag() == TYPE_STRING )
event_registry->SetGroup(Name(), group->AsString()->CheckString());
else
Error("&group attribute takes string");
}
}
attr = attrs->FindAttr(ATTR_ERROR_HANDLER);
Attr* attr = attrs->FindAttr(ATTR_ERROR_HANDLER);
if ( attr )
event_registry->SetErrorHandler(Name());

View file

@ -26,6 +26,7 @@ public:
bool IsGlobal() const { return scope != SCOPE_FUNCTION; }
bool IsExport() const { return is_export; }
void SetExport() { is_export = true; }
string ModuleName() const;

View file

@ -5,9 +5,10 @@
#include "IPAddr.h"
#include "Reporter.h"
#include "Conn.h"
#include "DPM.h"
#include "bro_inet_ntop.h"
#include "analyzer/Manager.h"
const uint8_t IPAddr::v4_mapped_prefix[12] = { 0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0xff, 0xff };
@ -44,23 +45,6 @@ HashKey* BuildConnIDHashKey(const ConnID& id)
return new HashKey(&key, sizeof(key));
}
HashKey* BuildExpectedConnHashKey(const ExpectedConn& c)
{
struct {
in6_addr orig;
in6_addr resp;
uint16 resp_p;
uint16 proto;
} key;
key.orig = c.orig.in6;
key.resp = c.resp.in6;
key.resp_p = c.resp_p;
key.proto = c.proto;
return new HashKey(&key, sizeof(key));
}
void IPAddr::Mask(int top_bits_to_keep)
{
if ( top_bits_to_keep < 0 || top_bits_to_keep > 128 )

View file

@ -14,7 +14,7 @@
#include "threading/SerialTypes.h"
struct ConnID;
class ExpectedConn;
namespace analyzer { class ExpectedConn; }
typedef in_addr in4_addr;
@ -363,7 +363,6 @@ public:
void ConvertToThreadingValue(threading::Value::addr_t* v) const;
friend HashKey* BuildConnIDHashKey(const ConnID& id);
friend HashKey* BuildExpectedConnHashKey(const ExpectedConn& c);
unsigned int MemoryAllocation() const { return padded_sizeof(*this); }
@ -452,11 +451,6 @@ inline void IPAddr::ConvertToThreadingValue(threading::Value::addr_t* v) const
*/
HashKey* BuildConnIDHashKey(const ConnID& id);
/**
* Returns a hash key for a given ExpectedConn instance. Passes ownership to caller.
*/
HashKey* BuildExpectedConnHashKey(const ExpectedConn& c);
/**
* Class storing both IPv4 and IPv6 prefixes
* (i.e., \c 192.168.1.1/16 and \c FD00::/8.

View file

@ -1,58 +0,0 @@
#ifndef MODBUS_H
#define MODBUS_H
#include "TCP.h"
#include "modbus_pac.h"
class ModbusTCP_Analyzer : public TCP_ApplicationAnalyzer {
public:
ModbusTCP_Analyzer(Connection* conn);
virtual ~ModbusTCP_Analyzer();
virtual void Done();
virtual void DeliverStream(int len, const u_char* data, bool orig);
virtual void Undelivered(int seq, int len, bool orig);
virtual void EndpointEOF(bool is_orig);
static Analyzer* InstantiateAnalyzer(Connection* conn)
{ return new ModbusTCP_Analyzer(conn); }
// Put event names in this function
static bool Available()
{
return modbus_message
| modbus_exception
| modbus_read_coils_request
| modbus_read_coils_response
| modbus_read_discrete_inputs_request
| modbus_read_discrete_inputs_response
| modbus_read_holding_registers_request
| modbus_read_holding_registers_response
| modbus_read_input_registers_request
| modbus_read_input_registers_response
| modbus_write_single_coil_request
| modbus_write_single_coil_response
| modbus_write_single_register_request
| modbus_write_single_register_response
| modbus_write_multiple_coils_request
| modbus_write_multiple_coils_response
| modbus_write_multiple_registers_request
| modbus_write_multiple_registers_response
| modbus_read_file_record_request
| modbus_read_file_record_response
| modbus_write_file_record_request
| modbus_write_file_record_response
| modbus_mask_write_register_request
| modbus_mask_write_register_response
| modbus_read_write_multiple_registers_request
| modbus_read_write_multiple_registers_response
| modbus_read_fifo_queue_request
| modbus_read_fifo_queue_response;
}
protected:
binpac::ModbusTCP::ModbusTCP_Conn* interp;
};
#endif

View file

@ -94,7 +94,6 @@ RecordType* http_stats_rec;
RecordType* http_message_stat;
int truncate_http_URI;
int pm_request;
RecordType* pm_mapping;
TableType* pm_mappings;
RecordType* pm_port_request;
@ -209,7 +208,6 @@ TableType* irc_join_list;
RecordType* irc_join_info;
TableVal* irc_servers;
TableVal* dpd_config;
int dpd_reassemble_first_packets;
int dpd_buffer_size;
int dpd_match_only_beginning;
@ -423,14 +421,6 @@ void init_net_var()
http_message_stat = internal_type("http_message_stat")->AsRecordType();
truncate_http_URI = opt_internal_int("truncate_http_URI");
pm_request = pm_request_null || pm_request_set ||
pm_request_unset || pm_request_getport ||
pm_request_dump || pm_request_callit ||
pm_attempt_null || pm_attempt_set ||
pm_attempt_unset || pm_attempt_getport ||
pm_attempt_dump || pm_attempt_callit ||
pm_bad_port;
pm_mapping = internal_type("pm_mapping")->AsRecordType();
pm_mappings = internal_type("pm_mappings")->AsTableType();
pm_port_request = internal_type("pm_port_request")->AsRecordType();
@ -526,7 +516,6 @@ void init_net_var()
opt_internal_double("remote_trace_sync_interval");
remote_trace_sync_peers = opt_internal_int("remote_trace_sync_peers");
dpd_config = internal_val("dpd_config")->AsTableVal();
dpd_reassemble_first_packets =
opt_internal_int("dpd_reassemble_first_packets");
dpd_buffer_size = opt_internal_int("dpd_buffer_size");

View file

@ -97,7 +97,6 @@ extern RecordType* http_stats_rec;
extern RecordType* http_message_stat;
extern int truncate_http_URI;
extern int pm_request;
extern RecordType* pm_mapping;
extern TableType* pm_mappings;
extern RecordType* pm_port_request;
@ -213,7 +212,6 @@ extern TableType* irc_join_list;
extern RecordType* irc_join_info;
extern TableVal* irc_servers;
extern TableVal* dpd_config;
extern int dpd_reassemble_first_packets;
extern int dpd_buffer_size;
extern int dpd_match_only_beginning;

View file

@ -8,8 +8,9 @@ using std::string;
#include "Conn.h"
#include "Event.h"
#include "NetVar.h"
#include "DPM.h"
#include "PIA.h"
#include "analyzer/protocol/pia/PIA.h"
#include "analyzer/Manager.h"
void RuleActionEvent::DoAction(const Rule* parent, RuleEndpointState* state,
const u_char* data, int len)
@ -34,42 +35,45 @@ void RuleActionEvent::PrintDebug()
fprintf(stderr, " RuleActionEvent: |%s|\n", msg);
}
RuleActionDPM::RuleActionDPM(const char* arg_analyzer)
RuleActionAnalyzer::RuleActionAnalyzer(const char* arg_analyzer)
{
string str(arg_analyzer);
string::size_type pos = str.find(':');
string arg = str.substr(0, pos);
analyzer = Analyzer::GetTag(arg.c_str());
analyzer = analyzer_mgr->GetAnalyzerTag(arg.c_str());
if ( ! analyzer )
reporter->Warning("unknown analyzer '%s' specified in rule", arg.c_str());
if ( pos != string::npos )
{
arg = str.substr(pos + 1);
child_analyzer = Analyzer::GetTag(arg.c_str());
child_analyzer = analyzer_mgr->GetAnalyzerTag(arg.c_str());
if ( ! child_analyzer )
reporter->Warning("unknown analyzer '%s' specified in rule", arg.c_str());
}
else
child_analyzer = AnalyzerTag::Error;
if ( analyzer != AnalyzerTag::Error )
dpm->ActivateSigs();
child_analyzer = analyzer::Tag();
}
void RuleActionDPM::PrintDebug()
void RuleActionAnalyzer::PrintDebug()
{
if ( child_analyzer == AnalyzerTag::Error )
fprintf(stderr, "|%s|\n", Analyzer::GetTagName(analyzer));
if ( ! child_analyzer )
fprintf(stderr, "|%s|\n", analyzer_mgr->GetAnalyzerName(analyzer));
else
fprintf(stderr, "|%s:%s|\n",
Analyzer::GetTagName(analyzer),
Analyzer::GetTagName(child_analyzer));
analyzer_mgr->GetAnalyzerName(analyzer),
analyzer_mgr->GetAnalyzerName(child_analyzer));
}
void RuleActionEnable::DoAction(const Rule* parent, RuleEndpointState* state,
const u_char* data, int len)
{
if ( ChildAnalyzer() == AnalyzerTag::Error )
if ( ! ChildAnalyzer() )
{
if ( ! Analyzer::IsAvailable(Analyzer()) )
if ( ! analyzer_mgr->IsEnabled(Analyzer()) )
return;
if ( state->PIA() )
@ -77,7 +81,7 @@ void RuleActionEnable::DoAction(const Rule* parent, RuleEndpointState* state,
}
else
{
if ( ! Analyzer::IsAvailable(ChildAnalyzer()) )
if ( ! analyzer_mgr->IsEnabled(ChildAnalyzer()) )
return;
// This is ugly and works only if there exists only one
@ -90,13 +94,13 @@ void RuleActionEnable::DoAction(const Rule* parent, RuleEndpointState* state,
void RuleActionEnable::PrintDebug()
{
fprintf(stderr, " RuleActionEnable: ");
RuleActionDPM::PrintDebug();
RuleActionAnalyzer::PrintDebug();
}
void RuleActionDisable::DoAction(const Rule* parent, RuleEndpointState* state,
const u_char* data, int len)
{
if ( ChildAnalyzer() == AnalyzerTag::Error )
if ( ! ChildAnalyzer() )
{
if ( state->PIA() )
state->PIA()->DeactivateAnalyzer(Analyzer());
@ -109,5 +113,5 @@ void RuleActionDisable::DoAction(const Rule* parent, RuleEndpointState* state,
void RuleActionDisable::PrintDebug()
{
fprintf(stderr, " RuleActionDisable: ");
RuleActionDPM::PrintDebug();
RuleActionAnalyzer::PrintDebug();
}

View file

@ -1,11 +1,12 @@
#ifndef ruleaction_h
#define ruleaction_h
#include "AnalyzerTags.h"
#include "BroString.h"
#include "List.h"
#include "util.h"
#include "analyzer/Tag.h"
class Rule;
class RuleEndpointState;
@ -35,29 +36,27 @@ private:
const char* msg;
};
// Base class for DPM enable/disable actions.
class RuleActionDPM : public RuleAction {
// Base class for enable/disable actions.
class RuleActionAnalyzer : public RuleAction {
public:
RuleActionDPM(const char* analyzer);
RuleActionAnalyzer(const char* analyzer);
virtual void DoAction(const Rule* parent, RuleEndpointState* state,
const u_char* data, int len) = 0;
virtual void PrintDebug();
AnalyzerTag::Tag Analyzer() const { return analyzer; }
AnalyzerTag::Tag ChildAnalyzer() const { return child_analyzer; }
analyzer::Tag Analyzer() const { return analyzer; }
analyzer::Tag ChildAnalyzer() const { return child_analyzer; }
private:
// FIXME: This is in fact an AnalyzerID but we can't include "Analyzer.h"
// at this point due to circular dependenides. Fix that!
AnalyzerTag::Tag analyzer;
AnalyzerTag::Tag child_analyzer;
analyzer::Tag analyzer;
analyzer::Tag child_analyzer;
};
class RuleActionEnable : public RuleActionDPM {
class RuleActionEnable : public RuleActionAnalyzer {
public:
RuleActionEnable(const char* analyzer) : RuleActionDPM(analyzer) {}
RuleActionEnable(const char* analyzer) : RuleActionAnalyzer(analyzer) {}
virtual void DoAction(const Rule* parent, RuleEndpointState* state,
const u_char* data, int len);
@ -65,9 +64,9 @@ public:
virtual void PrintDebug();
};
class RuleActionDisable : public RuleActionDPM {
class RuleActionDisable : public RuleActionAnalyzer {
public:
RuleActionDisable(const char* analyzer) : RuleActionDPM(analyzer) {}
RuleActionDisable(const char* analyzer) : RuleActionAnalyzer(analyzer) {}
virtual void DoAction(const Rule* parent, RuleEndpointState* state,
const u_char* data, int len);

View file

@ -1,29 +1,29 @@
#include "config.h"
#include "RuleCondition.h"
#include "TCP.h"
#include "analyzer/protocol/tcp/TCP.h"
#include "Scope.h"
static inline bool is_established(const TCP_Endpoint* e)
static inline bool is_established(const analyzer::tcp::TCP_Endpoint* e)
{
// We more or less follow Snort here: an established session
// is one for which the initial handshake has succeded (but we
// add partial connections). The connection tear-down is part
// of the connection.
return e->state != TCP_ENDPOINT_INACTIVE &&
e->state != TCP_ENDPOINT_SYN_SENT &&
e->state != TCP_ENDPOINT_SYN_ACK_SENT;
return e->state != analyzer::tcp::TCP_ENDPOINT_INACTIVE &&
e->state != analyzer::tcp::TCP_ENDPOINT_SYN_SENT &&
e->state != analyzer::tcp::TCP_ENDPOINT_SYN_ACK_SENT;
}
bool RuleConditionTCPState::DoMatch(Rule* rule, RuleEndpointState* state,
const u_char* data, int len)
{
Analyzer* root = state->GetAnalyzer()->Conn()->GetRootAnalyzer();
analyzer::Analyzer* root = state->GetAnalyzer()->Conn()->GetRootAnalyzer();
if ( ! root || root->GetTag() != AnalyzerTag::TCP )
if ( ! root || ! root->IsAnalyzer("TCP") )
return false;
TCP_Analyzer* ta = static_cast<TCP_Analyzer*>(root);
analyzer::tcp::TCP_Analyzer* ta = static_cast<analyzer::tcp::TCP_Analyzer*>(root);
if ( tcpstates & STATE_STATELESS )
return true;

View file

@ -3,7 +3,7 @@
#include "config.h"
#include "Analyzer.h"
#include "analyzer/Analyzer.h"
#include "RuleMatcher.h"
#include "DFA.h"
#include "NetVar.h"
@ -159,9 +159,9 @@ void RuleHdrTest::PrintDebug()
fprintf(stderr, "\n");
}
RuleEndpointState::RuleEndpointState(Analyzer* arg_analyzer, bool arg_is_orig,
RuleEndpointState::RuleEndpointState(analyzer::Analyzer* arg_analyzer, bool arg_is_orig,
RuleEndpointState* arg_opposite,
::PIA* arg_PIA)
analyzer::pia::PIA* arg_PIA)
{
payload_size = -1;
analyzer = arg_analyzer;
@ -562,10 +562,10 @@ static inline bool compare(const vector<IPPrefix>& prefixes, const IPAddr& a,
return false;
}
RuleEndpointState* RuleMatcher::InitEndpoint(Analyzer* analyzer,
RuleEndpointState* RuleMatcher::InitEndpoint(analyzer::Analyzer* analyzer,
const IP_Hdr* ip, int caplen,
RuleEndpointState* opposite,
bool from_orig, PIA* pia)
bool from_orig, analyzer::pia::PIA* pia)
{
RuleEndpointState* state =
new RuleEndpointState(analyzer, from_orig, opposite, pia);
@ -1300,8 +1300,8 @@ uint32 id_to_uint(const char* id)
return 0;
}
void RuleMatcherState::InitEndpointMatcher(Analyzer* analyzer, const IP_Hdr* ip,
int caplen, bool from_orig, PIA* pia)
void RuleMatcherState::InitEndpointMatcher(analyzer::Analyzer* analyzer, const IP_Hdr* ip,
int caplen, bool from_orig, analyzer::pia::PIA* pia)
{
if ( ! rule_matcher )
return;

View file

@ -35,8 +35,10 @@ extern const char* current_rule_file;
class RuleMatcher;
extern RuleMatcher* rule_matcher;
class Analyzer;
class PIA;
namespace analyzer {
namespace pia { class PIA; }
class Analyzer;
}
// RuleHdrTest and associated things:
@ -140,7 +142,7 @@ class RuleEndpointState {
public:
~RuleEndpointState();
Analyzer* GetAnalyzer() const { return analyzer; }
analyzer::Analyzer* GetAnalyzer() const { return analyzer; }
bool IsOrig() { return is_orig; }
// For flipping roles.
@ -152,15 +154,15 @@ public:
// Returns -1 if no chunk has been fed yet at all.
int PayloadSize() { return payload_size; }
::PIA* PIA() const { return pia; }
analyzer::pia::PIA* PIA() const { return pia; }
private:
friend class RuleMatcher;
// Constructor is private; use RuleMatcher::InitEndpoint()
// for creating an instance.
RuleEndpointState(Analyzer* arg_analyzer, bool arg_is_orig,
RuleEndpointState* arg_opposite, ::PIA* arg_PIA);
RuleEndpointState(analyzer::Analyzer* arg_analyzer, bool arg_is_orig,
RuleEndpointState* arg_opposite, analyzer::pia::PIA* arg_PIA);
struct Matcher {
RE_Match_State* state;
@ -171,9 +173,9 @@ private:
typedef PList(Matcher) matcher_list;
bool is_orig;
Analyzer* analyzer;
analyzer::Analyzer* analyzer;
RuleEndpointState* opposite;
::PIA* pia;
analyzer::pia::PIA* pia;
matcher_list matchers;
rule_hdr_test_list hdr_tests;
@ -207,8 +209,8 @@ public:
// the given packet (which should be the first packet encountered for
// this endpoint). If the matching is triggered by an PIA, a pointer to
// it needs to be given.
RuleEndpointState* InitEndpoint(Analyzer* analyzer, const IP_Hdr* ip,
int caplen, RuleEndpointState* opposite, bool is_orig, PIA* pia);
RuleEndpointState* InitEndpoint(analyzer::Analyzer* analyzer, const IP_Hdr* ip,
int caplen, RuleEndpointState* opposite, bool is_orig, analyzer::pia::PIA* pia);
// Finish matching for this stream.
void FinishEndpoint(RuleEndpointState* state);
@ -310,8 +312,8 @@ public:
{ delete orig_match_state; delete resp_match_state; }
// ip may be nil.
void InitEndpointMatcher(Analyzer* analyzer, const IP_Hdr* ip,
int caplen, bool from_orig, PIA* pia = 0);
void InitEndpointMatcher(analyzer::Analyzer* analyzer, const IP_Hdr* ip,
int caplen, bool from_orig, analyzer::pia::PIA* pia = 0);
// bol/eol should be set to false for type Rule::PAYLOAD; they're
// deduced automatically.

View file

@ -1,26 +0,0 @@
// See the file "COPYING" in the main distribution directory for copyright.
#ifndef ssh_h
#define ssh_h
#include "TCP.h"
#include "ContentLine.h"
class SSH_Analyzer : public TCP_ApplicationAnalyzer {
public:
SSH_Analyzer(Connection* conn);
virtual void DeliverStream(int len, const u_char* data, bool orig);
static Analyzer* InstantiateAnalyzer(Connection* conn)
{ return new SSH_Analyzer(conn); }
static bool Available()
{ return ssh_client_version || ssh_server_version; }
private:
ContentLine_Analyzer* orig;
ContentLine_Analyzer* resp;
};
#endif

View file

@ -16,22 +16,25 @@
#include "Reporter.h"
#include "OSFinger.h"
#include "ICMP.h"
#include "UDP.h"
#include "analyzer/protocol/icmp/ICMP.h"
#include "analyzer/protocol/udp/UDP.h"
#include "DNS-binpac.h"
#include "HTTP-binpac.h"
#include "SteppingStone.h"
#include "BackDoor.h"
#include "InterConn.h"
#include "analyzer/protocol/stepping-stone/SteppingStone.h"
#include "analyzer/protocol/stepping-stone/events.bif.h"
#include "analyzer/protocol/backdoor/BackDoor.h"
#include "analyzer/protocol/backdoor/events.bif.h"
#include "analyzer/protocol/interconn/InterConn.h"
#include "analyzer/protocol/interconn/events.bif.h"
#include "analyzer/protocol/arp/ARP.h"
#include "analyzer/protocol/arp/events.bif.h"
#include "Discard.h"
#include "RuleMatcher.h"
#include "DPM.h"
#include "PacketSort.h"
#include "TunnelEncapsulation.h"
#include "analyzer/Manager.h"
// These represent NetBIOS services on ephemeral ports. They're numbered
// so that we can use a single int to hold either an actual TCP/UDP server
// port or one of these.
@ -104,7 +107,7 @@ NetSessions::NetSessions()
fragments.SetDeleteFunc(bro_obj_delete_func);
if ( stp_correlate_pair )
stp_manager = new SteppingStoneManager();
stp_manager = new analyzer::stepping_stone::SteppingStoneManager();
else
stp_manager = 0;
@ -143,7 +146,7 @@ NetSessions::NetSessions()
pkt_profiler = 0;
if ( arp_request || arp_reply || bad_arp )
arp_analyzer = new ARP_Analyzer();
arp_analyzer = new analyzer::arp::ARP_Analyzer();
else
arp_analyzer = 0;
}
@ -256,7 +259,7 @@ void NetSessions::NextPacket(double t, const struct pcap_pkthdr* hdr,
DoNextPacket(t, hdr, &ip_hdr, pkt, hdr_size, 0);
}
else if ( ARP_Analyzer::IsARP(pkt, hdr_size) )
else if ( analyzer::arp::ARP_Analyzer::IsARP(pkt, hdr_size) )
{
if ( arp_analyzer )
arp_analyzer->NextPacket(t, hdr, pkt, hdr_size);
@ -523,9 +526,9 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
const struct icmp* icmpp = (const struct icmp *) data;
id.src_port = icmpp->icmp_type;
id.dst_port = ICMP4_counterpart(icmpp->icmp_type,
icmpp->icmp_code,
id.is_one_way);
id.dst_port = analyzer::icmp::ICMP4_counterpart(icmpp->icmp_type,
icmpp->icmp_code,
id.is_one_way);
id.src_port = htons(id.src_port);
id.dst_port = htons(id.dst_port);
@ -539,9 +542,9 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
const struct icmp* icmpp = (const struct icmp *) data;
id.src_port = icmpp->icmp_type;
id.dst_port = ICMP6_counterpart(icmpp->icmp_type,
icmpp->icmp_code,
id.is_one_way);
id.dst_port = analyzer::icmp::ICMP6_counterpart(icmpp->icmp_type,
icmpp->icmp_code,
id.is_one_way);
id.src_port = htons(id.src_port);
id.dst_port = htons(id.dst_port);
@ -964,12 +967,12 @@ void NetSessions::Remove(Connection* c)
{
c->CancelTimers();
TCP_Analyzer* ta = (TCP_Analyzer*) c->GetRootAnalyzer();
analyzer::tcp::TCP_Analyzer* ta = (analyzer::tcp::TCP_Analyzer*) c->GetRootAnalyzer();
if ( ta && c->ConnTransport() == TRANSPORT_TCP )
{
assert(ta->GetTag() == AnalyzerTag::TCP);
TCP_Endpoint* to = ta->Orig();
TCP_Endpoint* tr = ta->Resp();
assert(ta->IsAnalyzer("TCP"));
analyzer::tcp::TCP_Endpoint* to = ta->Orig();
analyzer::tcp::TCP_Endpoint* tr = ta->Resp();
tcp_stats.StateLeft(to->state, tr->state);
}
@ -1178,7 +1181,7 @@ Connection* NetSessions::NewConn(HashKey* k, double t, const ConnID* id,
Connection* conn = new Connection(this, k, t, id, flow_label, encapsulation);
conn->SetTransport(tproto);
dpm->BuildInitialAnalyzerTree(tproto, conn, data);
analyzer_mgr->BuildInitialAnalyzerTree(conn);
bool external = conn->IsExternal();

View file

@ -6,12 +6,13 @@
#include "Dict.h"
#include "CompHash.h"
#include "IP.h"
#include "ARP.h"
#include "Frag.h"
#include "PacketFilter.h"
#include "Stats.h"
#include "NetVar.h"
#include "TunnelEncapsulation.h"
#include "analyzer/protocol/tcp/Stats.h"
#include <utility>
struct pcap_pkthdr;
@ -26,11 +27,12 @@ declare(PDict,Connection);
declare(PDict,FragReassembler);
class Discarder;
class SteppingStoneManager;
class PacketFilter;
class PacketSortElement;
namespace analyzer { namespace stepping_stone { class SteppingStoneManager; } }
namespace analyzer { namespace arp { class ARP_Analyzer; } }
struct SessionStats {
int num_TCP_conns;
int num_UDP_conns;
@ -127,7 +129,7 @@ public:
void ExpireTimerMgrs();
SteppingStoneManager* GetSTPManager() { return stp_manager; }
analyzer::stepping_stone::SteppingStoneManager* GetSTPManager() { return stp_manager; }
unsigned int CurrentConnections()
{
@ -183,7 +185,7 @@ public:
unsigned int ConnectionMemoryUsage();
unsigned int ConnectionMemoryUsageConnVals();
unsigned int MemoryAllocation();
TCPStateStats tcp_stats; // keeps statistics on TCP states
analyzer::tcp::TCPStateStats tcp_stats; // keeps statistics on TCP states
protected:
friend class RemoteSerializer;
@ -255,9 +257,9 @@ protected:
typedef std::map<IPPair, TunnelActivity> IPTunnelMap;
IPTunnelMap ip_tunnels;
ARP_Analyzer* arp_analyzer;
analyzer::arp::ARP_Analyzer* arp_analyzer;
SteppingStoneManager* stp_manager;
analyzer::stepping_stone::SteppingStoneManager* stp_manager;
Discarder* discarder;
PacketFilter* packet_filter;
OSFingerprint* SYN_OS_Fingerprinter;

View file

@ -389,84 +389,6 @@ void SegmentProfiler::Report()
reporter->SegmentProfile(name, loc, dtime, dmem);
}
TCPStateStats::TCPStateStats()
{
for ( int i = 0; i < TCP_ENDPOINT_RESET + 1; ++i )
for ( int j = 0; j < TCP_ENDPOINT_RESET + 1; ++j )
state_cnt[i][j] = 0;
}
void TCPStateStats::ChangeState(EndpointState o_prev, EndpointState o_now,
EndpointState r_prev, EndpointState r_now)
{
--state_cnt[o_prev][r_prev];
++state_cnt[o_now][r_now];
}
void TCPStateStats::FlipState(EndpointState orig, EndpointState resp)
{
--state_cnt[orig][resp];
++state_cnt[resp][orig];
}
unsigned int TCPStateStats::NumStatePartial() const
{
unsigned int sum = 0;
for ( int i = 0; i < TCP_ENDPOINT_RESET + 1; ++i )
{
sum += state_cnt[TCP_ENDPOINT_PARTIAL][i];
sum += state_cnt[i][TCP_ENDPOINT_PARTIAL];
}
return sum;
}
void TCPStateStats::PrintStats(BroFile* file, const char* prefix)
{
file->Write(prefix);
file->Write(" Inact. Syn. SA Part. Est. Fin. Rst.\n");
for ( int i = 0; i < TCP_ENDPOINT_RESET + 1; ++i )
{
file->Write(prefix);
switch ( i ) {
#define STATE_STRING(state, str) \
case state: \
file->Write(str); \
break;
STATE_STRING(TCP_ENDPOINT_INACTIVE, "Inact.");
STATE_STRING(TCP_ENDPOINT_SYN_SENT, "Syn. ");
STATE_STRING(TCP_ENDPOINT_SYN_ACK_SENT, "SA ");
STATE_STRING(TCP_ENDPOINT_PARTIAL, "Part. ");
STATE_STRING(TCP_ENDPOINT_ESTABLISHED, "Est. ");
STATE_STRING(TCP_ENDPOINT_CLOSED, "Fin. ");
STATE_STRING(TCP_ENDPOINT_RESET, "Rst. ");
}
file->Write(" ");
for ( int j = 0; j < TCP_ENDPOINT_RESET + 1; ++j )
{
unsigned int n = state_cnt[i][j];
if ( n > 0 )
{
char buf[32];
safe_snprintf(buf, sizeof(buf), "%-8d", state_cnt[i][j]);
file->Write(buf);
}
else
file->Write(" ");
}
file->Write("\n");
}
}
PacketProfiler::PacketProfiler(unsigned int mode, double freq,
BroFile* arg_file)
{

View file

@ -7,9 +7,6 @@
#include <sys/time.h>
#include <sys/resource.h>
#include "TCP_Endpoint.h"
// Object called by SegmentProfiler when it is done and reports its
// cumulative CPU/memory statistics.
class SegmentStatsReporter {
@ -121,67 +118,6 @@ extern uint64 tot_ack_bytes;
extern uint64 tot_gap_events;
extern uint64 tot_gap_bytes;
// A TCPStateStats object tracks the distribution of TCP states for
// the currently active connections.
class TCPStateStats {
public:
TCPStateStats();
~TCPStateStats() { }
void ChangeState(EndpointState o_prev, EndpointState o_now,
EndpointState r_prev, EndpointState r_now);
void FlipState(EndpointState orig, EndpointState resp);
void StateEntered (EndpointState o_state, EndpointState r_state)
{ ++state_cnt[o_state][r_state]; }
void StateLeft (EndpointState o_state, EndpointState r_state)
{ --state_cnt[o_state][r_state]; }
unsigned int Cnt(EndpointState state) const
{ return Cnt(state, state); }
unsigned int Cnt(EndpointState state1, EndpointState state2) const
{ return state_cnt[state1][state2]; }
unsigned int NumStateEstablished() const
{ return Cnt(TCP_ENDPOINT_ESTABLISHED); }
unsigned int NumStateHalfClose() const
{ // corresponds to S2,S3
return Cnt(TCP_ENDPOINT_ESTABLISHED, TCP_ENDPOINT_CLOSED) +
Cnt(TCP_ENDPOINT_CLOSED, TCP_ENDPOINT_ESTABLISHED);
}
unsigned int NumStateHalfRst() const
{
return Cnt(TCP_ENDPOINT_ESTABLISHED, TCP_ENDPOINT_RESET) +
Cnt(TCP_ENDPOINT_RESET, TCP_ENDPOINT_ESTABLISHED);
}
unsigned int NumStateClosed() const
{ return Cnt(TCP_ENDPOINT_CLOSED); }
unsigned int NumStateRequest() const
{
assert(Cnt(TCP_ENDPOINT_INACTIVE, TCP_ENDPOINT_SYN_SENT)==0);
return Cnt(TCP_ENDPOINT_SYN_SENT, TCP_ENDPOINT_INACTIVE);
}
unsigned int NumStateSuccRequest() const
{
return Cnt(TCP_ENDPOINT_SYN_SENT, TCP_ENDPOINT_SYN_ACK_SENT) +
Cnt(TCP_ENDPOINT_SYN_ACK_SENT, TCP_ENDPOINT_SYN_SENT);
}
unsigned int NumStateRstRequest() const
{
return Cnt(TCP_ENDPOINT_SYN_SENT, TCP_ENDPOINT_RESET) +
Cnt(TCP_ENDPOINT_RESET, TCP_ENDPOINT_SYN_SENT);
}
unsigned int NumStateInactive() const
{ return Cnt(TCP_ENDPOINT_INACTIVE); }
unsigned int NumStatePartial() const;
void PrintStats(BroFile* file, const char* prefix);
private:
unsigned int state_cnt[TCP_ENDPOINT_RESET+1][TCP_ENDPOINT_RESET+1];
};
class PacketProfiler {
public:
PacketProfiler(unsigned int mode, double freq, BroFile* arg_file);

View file

@ -1,55 +0,0 @@
#ifndef Syslog_binpac_h
#define Syslog_binpac_h
#include "UDP.h"
#include "TCP.h"
#include "syslog_pac.h"
class Syslog_Analyzer_binpac : public Analyzer {
public:
Syslog_Analyzer_binpac(Connection* conn);
virtual ~Syslog_Analyzer_binpac();
virtual void Done();
virtual void DeliverPacket(int len, const u_char* data, bool orig,
int seq, const IP_Hdr* ip, int caplen);
static Analyzer* InstantiateAnalyzer(Connection* conn)
{ return new Syslog_Analyzer_binpac(conn); }
static bool Available()
{ return syslog_message; }
protected:
friend class AnalyzerTimer;
void ExpireTimer(double t);
int did_session_done;
binpac::Syslog::Syslog_Conn* interp;
};
// #include "Syslog_tcp_pac.h"
//
//class Syslog_TCP_Analyzer_binpac : public TCP_ApplicationAnalyzer {
//public:
// Syslog_TCP_Analyzer_binpac(Connection* conn);
// virtual ~Syslog_TCP_Analyzer_binpac();
//
// virtual void Done();
// virtual void DeliverStream(int len, const u_char* data, bool orig);
// virtual void Undelivered(int seq, int len, bool orig);
// virtual void EndpointEOF(TCP_Reassembler* endp);
//
// static Analyzer* InstantiateAnalyzer(Connection* conn)
// { return new Syslog_TCP_Analyzer_binpac(conn); }
//
// static bool Available()
// { return (Syslog_request || Syslog_full_request) && FLAGS_use_binpac; }
//
//protected:
// binpac::Syslog_on_TCP::Syslog_TCP_Conn* interp;
//};
//
#endif

View file

@ -1049,6 +1049,11 @@ StringVal::StringVal(const char* s) : Val(TYPE_STRING)
val.string_val = new BroString(s);
}
StringVal::StringVal(const string& s) : Val(TYPE_STRING)
{
val.string_val = new BroString(s.c_str());
}
StringVal* StringVal::ToUpper()
{
val.string_val->ToUpper();

View file

@ -608,6 +608,7 @@ class StringVal : public Val {
public:
StringVal(BroString* s);
StringVal(const char* s);
StringVal(const string& s);
StringVal(int length, const char* s);
Val* SizeVal() const

View file

@ -1,191 +1,45 @@
// See the file "COPYING" in the main distribution directory for copyright.
#include <algorithm>
#include "Analyzer.h"
#include "PIA.h"
#include "Event.h"
#include "Manager.h"
#include "AYIYA.h"
#include "BackDoor.h"
#include "BitTorrent.h"
#include "BitTorrentTracker.h"
#include "Finger.h"
#include "InterConn.h"
#include "NTP.h"
#include "HTTP.h"
#include "HTTP-binpac.h"
#include "ICMP.h"
#include "SteppingStone.h"
#include "IRC.h"
#include "SMTP.h"
#include "FTP.h"
#include "FileAnalyzer.h"
#include "DNS.h"
#include "DNS-binpac.h"
#include "DHCP-binpac.h"
#include "Telnet.h"
#include "Rlogin.h"
#include "RSH.h"
#include "DCE_RPC.h"
#include "Gnutella.h"
#include "Ident.h"
#include "Modbus.h"
#include "NCP.h"
#include "NetbiosSSN.h"
#include "SMB.h"
#include "NFS.h"
#include "Portmap.h"
#include "POP3.h"
#include "SOCKS.h"
#include "SSH.h"
#include "SSL.h"
#include "Syslog-binpac.h"
#include "Teredo.h"
#include "ConnSizeAnalyzer.h"
#include "GTPv1.h"
#include "analyzer/protocol/pia/PIA.h"
#include "../Event.h"
// Keep same order here as in AnalyzerTag definition!
const Analyzer::Config Analyzer::analyzer_configs[] = {
{ AnalyzerTag::Error, "<ERROR>", 0, 0, 0, false },
namespace analyzer {
{ AnalyzerTag::PIA_TCP, "PIA_TCP", PIA_TCP::InstantiateAnalyzer,
PIA_TCP::Available, 0, false },
{ AnalyzerTag::PIA_UDP, "PIA_UDP", PIA_UDP::InstantiateAnalyzer,
PIA_UDP::Available, 0, false },
class AnalyzerTimer : public Timer {
public:
AnalyzerTimer(Analyzer* arg_analyzer, analyzer_timer_func arg_timer,
double arg_t, int arg_do_expire, TimerType arg_type);
{ AnalyzerTag::ICMP, "ICMP", ICMP_Analyzer::InstantiateAnalyzer,
ICMP_Analyzer::Available, 0, false },
virtual ~AnalyzerTimer();
{ AnalyzerTag::TCP, "TCP", TCP_Analyzer::InstantiateAnalyzer,
TCP_Analyzer::Available, 0, false },
{ AnalyzerTag::UDP, "UDP", UDP_Analyzer::InstantiateAnalyzer,
UDP_Analyzer::Available, 0, false },
void Dispatch(double t, int is_expire);
{ AnalyzerTag::BitTorrent, "BITTORRENT",
BitTorrent_Analyzer::InstantiateAnalyzer,
BitTorrent_Analyzer::Available, 0, false },
{ AnalyzerTag::BitTorrentTracker, "BITTORRENTTRACKER",
BitTorrentTracker_Analyzer::InstantiateAnalyzer,
BitTorrentTracker_Analyzer::Available, 0, false },
{ AnalyzerTag::DCE_RPC, "DCE_RPC",
DCE_RPC_Analyzer::InstantiateAnalyzer,
DCE_RPC_Analyzer::Available, 0, false },
{ AnalyzerTag::DNS, "DNS", DNS_Analyzer::InstantiateAnalyzer,
DNS_Analyzer::Available, 0, false },
{ AnalyzerTag::Finger, "FINGER", Finger_Analyzer::InstantiateAnalyzer,
Finger_Analyzer::Available, 0, false },
{ AnalyzerTag::FTP, "FTP", FTP_Analyzer::InstantiateAnalyzer,
FTP_Analyzer::Available, 0, false },
{ AnalyzerTag::Gnutella, "GNUTELLA",
Gnutella_Analyzer::InstantiateAnalyzer,
Gnutella_Analyzer::Available, 0, false },
{ AnalyzerTag::HTTP, "HTTP", HTTP_Analyzer::InstantiateAnalyzer,
HTTP_Analyzer::Available, 0, false },
{ AnalyzerTag::Ident, "IDENT", Ident_Analyzer::InstantiateAnalyzer,
Ident_Analyzer::Available, 0, false },
{ AnalyzerTag::IRC, "IRC", IRC_Analyzer::InstantiateAnalyzer,
IRC_Analyzer::Available, 0, false },
{ AnalyzerTag::Login, "LOGIN", 0, 0, 0, false }, // just a base class
{ AnalyzerTag::NCP, "NCP", NCP_Analyzer::InstantiateAnalyzer,
NCP_Analyzer::Available, 0, false },
{ AnalyzerTag::NetbiosSSN, "NetbiosSSN",
NetbiosSSN_Analyzer::InstantiateAnalyzer,
NetbiosSSN_Analyzer::Available, 0, false },
{ AnalyzerTag::NFS, "NFS", NFS_Analyzer::InstantiateAnalyzer,
NFS_Analyzer::Available, 0, false },
{ AnalyzerTag::NTP, "NTP", NTP_Analyzer::InstantiateAnalyzer,
NTP_Analyzer::Available, 0, false },
{ AnalyzerTag::POP3, "POP3", POP3_Analyzer::InstantiateAnalyzer,
POP3_Analyzer::Available, 0, false },
{ AnalyzerTag::Portmapper, "PORTMAPPER",
Portmapper_Analyzer::InstantiateAnalyzer,
Portmapper_Analyzer::Available, 0, false },
{ AnalyzerTag::Rlogin, "RLOGIN", Rlogin_Analyzer::InstantiateAnalyzer,
Rlogin_Analyzer::Available, 0, false },
{ AnalyzerTag::RPC, "RPC", 0, 0, 0, false },
{ AnalyzerTag::Rsh, "RSH", Rsh_Analyzer::InstantiateAnalyzer,
Rsh_Analyzer::Available, 0, false },
{ AnalyzerTag::SMB, "SMB", SMB_Analyzer::InstantiateAnalyzer,
SMB_Analyzer::Available, 0, false },
{ AnalyzerTag::SMTP, "SMTP", SMTP_Analyzer::InstantiateAnalyzer,
SMTP_Analyzer::Available, 0, false },
{ AnalyzerTag::SSH, "SSH", SSH_Analyzer::InstantiateAnalyzer,
SSH_Analyzer::Available, 0, false },
{ AnalyzerTag::Telnet, "TELNET", Telnet_Analyzer::InstantiateAnalyzer,
Telnet_Analyzer::Available, 0, false },
protected:
AnalyzerTimer() {}
{ AnalyzerTag::DHCP_BINPAC, "DHCP_BINPAC",
DHCP_Analyzer_binpac::InstantiateAnalyzer,
DHCP_Analyzer_binpac::Available, 0, false },
{ AnalyzerTag::DNS_TCP_BINPAC, "DNS_TCP_BINPAC",
DNS_TCP_Analyzer_binpac::InstantiateAnalyzer,
DNS_TCP_Analyzer_binpac::Available, 0, false },
{ AnalyzerTag::DNS_UDP_BINPAC, "DNS_UDP_BINPAC",
DNS_UDP_Analyzer_binpac::InstantiateAnalyzer,
DNS_UDP_Analyzer_binpac::Available, 0, false },
{ AnalyzerTag::HTTP_BINPAC, "HTTP_BINPAC",
HTTP_Analyzer_binpac::InstantiateAnalyzer,
HTTP_Analyzer_binpac::Available, 0, false },
{ AnalyzerTag::SSL, "SSL",
SSL_Analyzer::InstantiateAnalyzer,
SSL_Analyzer::Available, 0, false },
{ AnalyzerTag::SYSLOG_BINPAC, "SYSLOG_BINPAC",
Syslog_Analyzer_binpac::InstantiateAnalyzer,
Syslog_Analyzer_binpac::Available, 0, false },
{ AnalyzerTag::Modbus, "MODBUS",
ModbusTCP_Analyzer::InstantiateAnalyzer,
ModbusTCP_Analyzer::Available, 0, false },
void Init(Analyzer* analyzer, analyzer_timer_func timer, int do_expire);
{ AnalyzerTag::AYIYA, "AYIYA",
AYIYA_Analyzer::InstantiateAnalyzer,
AYIYA_Analyzer::Available, 0, false },
{ AnalyzerTag::SOCKS, "SOCKS",
SOCKS_Analyzer::InstantiateAnalyzer,
SOCKS_Analyzer::Available, 0, false },
{ AnalyzerTag::Teredo, "TEREDO",
Teredo_Analyzer::InstantiateAnalyzer,
Teredo_Analyzer::Available, 0, false },
{ AnalyzerTag::GTPv1, "GTPV1",
GTPv1_Analyzer::InstantiateAnalyzer,
GTPv1_Analyzer::Available, 0, false },
{ AnalyzerTag::File, "FILE", File_Analyzer::InstantiateAnalyzer,
File_Analyzer::Available, 0, false },
{ AnalyzerTag::IRC_Data, "IRC_DATA", IRC_Data::InstantiateAnalyzer,
IRC_Data::Available, 0, false },
{ AnalyzerTag::FTP_Data, "FTP_DATA", FTP_Data::InstantiateAnalyzer,
FTP_Data::Available, 0, false },
{ AnalyzerTag::Backdoor, "BACKDOOR",
BackDoor_Analyzer::InstantiateAnalyzer,
BackDoor_Analyzer::Available, 0, false },
{ AnalyzerTag::InterConn, "INTERCONN",
InterConn_Analyzer::InstantiateAnalyzer,
InterConn_Analyzer::Available, 0, false },
{ AnalyzerTag::SteppingStone, "STEPPINGSTONE",
SteppingStone_Analyzer::InstantiateAnalyzer,
SteppingStone_Analyzer::Available, 0, false },
{ AnalyzerTag::TCPStats, "TCPSTATS",
TCPStats_Analyzer::InstantiateAnalyzer,
TCPStats_Analyzer::Available, 0, false },
{ AnalyzerTag::ConnSize, "CONNSIZE",
ConnSize_Analyzer::InstantiateAnalyzer,
ConnSize_Analyzer::Available, 0, false },
{ AnalyzerTag::Contents, "CONTENTS", 0, 0, 0, false },
{ AnalyzerTag::ContentLine, "CONTENTLINE", 0, 0, 0, false },
{ AnalyzerTag::NVT, "NVT", 0, 0, 0, false },
{ AnalyzerTag::Zip, "ZIP", 0, 0, 0, false },
{ AnalyzerTag::Contents_DNS, "CONTENTS_DNS", 0, 0, 0, false },
{ AnalyzerTag::Contents_NetbiosSSN, "CONTENTS_NETBIOSSSN", 0, 0, 0, false },
{ AnalyzerTag::Contents_NCP, "CONTENTS_NCP", 0, 0, 0, false },
{ AnalyzerTag::Contents_Rlogin, "CONTENTS_Rlogin", 0, 0, 0, false },
{ AnalyzerTag::Contents_Rsh, "CONTENTS_RSH", 0, 0, 0, false },
{ AnalyzerTag::Contents_DCE_RPC, "CONTENTS_DCE_RPC", 0, 0, 0, false },
{ AnalyzerTag::Contents_SMB, "CONTENTS_SMB", 0, 0, 0, false },
{ AnalyzerTag::Contents_RPC, "CONTENTS_RPC", 0, 0, 0, false },
{ AnalyzerTag::Contents_NFS, "CONTENTS_NFS", 0, 0, 0, false },
{ AnalyzerTag::FTP_ADAT, "FTP_ADAT", 0, 0, 0, false },
Analyzer* analyzer;
analyzer_timer_func timer;
int do_expire;
};
}
using namespace analyzer;
AnalyzerTimer::AnalyzerTimer(Analyzer* arg_analyzer, analyzer_timer_func arg_timer,
double arg_t, int arg_do_expire, TimerType arg_type)
: Timer(arg_t, arg_type)
{
Init(arg_analyzer, arg_timer, arg_do_expire);
}
AnalyzerTimer::~AnalyzerTimer()
{
analyzer->RemoveTimer(this);
@ -216,36 +70,53 @@ void AnalyzerTimer::Init(Analyzer* arg_analyzer, analyzer_timer_func arg_timer,
Ref(analyzer->Conn());
}
AnalyzerID Analyzer::id_counter = 0;;
analyzer::ID Analyzer::id_counter = 0;;
Analyzer* Analyzer::InstantiateAnalyzer(AnalyzerTag::Tag tag, Connection* c)
const char* Analyzer::GetAnalyzerName() const
{
Analyzer* a = analyzer_configs[tag].factory(c);
assert(a);
return a;
assert(tag);
return analyzer_mgr->GetAnalyzerName(tag);
}
const char* Analyzer::GetTagName(AnalyzerTag::Tag tag)
void Analyzer::SetAnalyzerTag(const Tag& arg_tag)
{
return analyzer_configs[tag].name;
assert(! tag || tag == arg_tag);
tag = arg_tag;
}
AnalyzerTag::Tag Analyzer::GetTag(const char* name)
bool Analyzer::IsAnalyzer(const char* name)
{
for ( int i = 1; i < int(AnalyzerTag::LastAnalyzer); i++ )
if ( strcasecmp(analyzer_configs[i].name, name) == 0 )
return analyzer_configs[i].tag;
return AnalyzerTag::Error;
assert(tag);
return strcmp(analyzer_mgr->GetAnalyzerName(tag), name) == 0;
}
// Used in debugging output.
static string fmt_analyzer(Analyzer* a)
{
return string(a->GetTagName()) + fmt("[%d]", a->GetID());
return string(a->GetAnalyzerName()) + fmt("[%d]", a->GetID());
}
Analyzer::Analyzer(AnalyzerTag::Tag arg_tag, Connection* arg_conn)
Analyzer::Analyzer(const char* name, Connection* conn)
{
Tag tag = analyzer_mgr->GetAnalyzerTag(name);
if ( ! tag )
reporter->InternalError("unknown analyzer name %s; mismatch with tag analyzer::Component?", name);
CtorInit(tag, conn);
}
Analyzer::Analyzer(const Tag& tag, Connection* conn)
{
CtorInit(tag, conn);
}
Analyzer::Analyzer(Connection* conn)
{
CtorInit(Tag(), conn);
}
void Analyzer::CtorInit(const Tag& arg_tag, Connection* arg_conn)
{
// Don't Ref conn here to avoid circular ref'ing. It can't be deleted
// before us.
@ -355,11 +226,6 @@ void Analyzer::NextPacket(int len, const u_char* data, bool is_orig, int seq,
}
}
const char* Analyzer::GetTagName() const
{
return GetTagName(tag);
}
void Analyzer::NextStream(int len, const u_char* data, bool is_orig)
{
if ( skip )
@ -514,7 +380,7 @@ void Analyzer::ForwardEndOfData(bool orig)
void Analyzer::AddChildAnalyzer(Analyzer* analyzer, bool init)
{
if ( HasChildAnalyzer(analyzer->GetTag()) )
if ( HasChildAnalyzer(analyzer->GetAnalyzerTag()) )
{
analyzer->Done();
delete analyzer;
@ -533,16 +399,19 @@ void Analyzer::AddChildAnalyzer(Analyzer* analyzer, bool init)
if ( init )
analyzer->Init();
DBG_LOG(DBG_DPD, "%s added child %s",
DBG_LOG(DBG_ANALYZER, "%s added child %s",
fmt_analyzer(this).c_str(), fmt_analyzer(analyzer).c_str());
}
Analyzer* Analyzer::AddChildAnalyzer(AnalyzerTag::Tag analyzer)
Analyzer* Analyzer::AddChildAnalyzer(Tag analyzer)
{
if ( ! HasChildAnalyzer(analyzer) )
{
Analyzer* a = InstantiateAnalyzer(analyzer, conn);
AddChildAnalyzer(a);
Analyzer* a = analyzer_mgr->InstantiateAnalyzer(analyzer, conn);
if ( a )
AddChildAnalyzer(a);
return a;
}
@ -554,7 +423,7 @@ void Analyzer::RemoveChildAnalyzer(Analyzer* analyzer)
LOOP_OVER_CHILDREN(i)
if ( *i == analyzer && ! (analyzer->finished || analyzer->removing) )
{
DBG_LOG(DBG_DPD, "%s disabling child %s",
DBG_LOG(DBG_ANALYZER, "%s disabling child %s",
fmt_analyzer(this).c_str(), fmt_analyzer(*i).c_str());
// We just flag it as being removed here but postpone
// actually doing that to later. Otherwise, we'd need
@ -567,12 +436,12 @@ void Analyzer::RemoveChildAnalyzer(Analyzer* analyzer)
}
}
void Analyzer::RemoveChildAnalyzer(AnalyzerID id)
void Analyzer::RemoveChildAnalyzer(ID id)
{
LOOP_OVER_CHILDREN(i)
if ( (*i)->id == id && ! ((*i)->finished || (*i)->removing) )
{
DBG_LOG(DBG_DPD, "%s disabling child %s", GetTagName(), id,
DBG_LOG(DBG_ANALYZER, "%s disabling child %s", GetAnalyzerName(), id,
fmt_analyzer(this).c_str(), fmt_analyzer(*i).c_str());
// See comment above.
(*i)->removing = true;
@ -580,7 +449,7 @@ void Analyzer::RemoveChildAnalyzer(AnalyzerID id)
}
}
bool Analyzer::HasChildAnalyzer(AnalyzerTag::Tag tag)
bool Analyzer::HasChildAnalyzer(Tag tag)
{
LOOP_OVER_CHILDREN(i)
if ( (*i)->tag == tag )
@ -593,7 +462,7 @@ bool Analyzer::HasChildAnalyzer(AnalyzerTag::Tag tag)
return false;
}
Analyzer* Analyzer::FindChild(AnalyzerID arg_id)
Analyzer* Analyzer::FindChild(ID arg_id)
{
if ( id == arg_id )
return this;
@ -608,7 +477,7 @@ Analyzer* Analyzer::FindChild(AnalyzerID arg_id)
return 0;
}
Analyzer* Analyzer::FindChild(AnalyzerTag::Tag arg_tag)
Analyzer* Analyzer::FindChild(Tag arg_tag)
{
if ( tag == arg_tag )
return this;
@ -623,6 +492,12 @@ Analyzer* Analyzer::FindChild(AnalyzerTag::Tag arg_tag)
return 0;
}
Analyzer* Analyzer::FindChild(const char* name)
{
Tag tag = analyzer_mgr->GetAnalyzerTag(name);
return tag ? FindChild(tag) : 0;
}
void Analyzer::DeleteChild(analyzer_list::iterator i)
{
Analyzer* child = *i;
@ -636,7 +511,7 @@ void Analyzer::DeleteChild(analyzer_list::iterator i)
child->removing = false;
}
DBG_LOG(DBG_DPD, "%s deleted child %s 3",
DBG_LOG(DBG_ANALYZER, "%s deleted child %s 3",
fmt_analyzer(this).c_str(), fmt_analyzer(child).c_str());
children.erase(i);
@ -645,9 +520,9 @@ void Analyzer::DeleteChild(analyzer_list::iterator i)
void Analyzer::AddSupportAnalyzer(SupportAnalyzer* analyzer)
{
if ( HasSupportAnalyzer(analyzer->GetTag(), analyzer->IsOrig()) )
if ( HasSupportAnalyzer(analyzer->GetAnalyzerTag(), analyzer->IsOrig()) )
{
DBG_LOG(DBG_DPD, "%s already has %s %s",
DBG_LOG(DBG_ANALYZER, "%s already has %s %s",
fmt_analyzer(this).c_str(),
analyzer->IsOrig() ? "originator" : "responder",
fmt_analyzer(analyzer).c_str());
@ -675,7 +550,7 @@ void Analyzer::AddSupportAnalyzer(SupportAnalyzer* analyzer)
analyzer->Init();
DBG_LOG(DBG_DPD, "%s added %s support %s",
DBG_LOG(DBG_ANALYZER, "%s added %s support %s",
fmt_analyzer(this).c_str(),
analyzer->IsOrig() ? "originator" : "responder",
fmt_analyzer(analyzer).c_str());
@ -699,7 +574,7 @@ void Analyzer::RemoveSupportAnalyzer(SupportAnalyzer* analyzer)
else
*head = s->sibling;
DBG_LOG(DBG_DPD, "%s removed support %s",
DBG_LOG(DBG_ANALYZER, "%s removed support %s",
fmt_analyzer(this).c_str(),
analyzer->IsOrig() ? "originator" : "responder",
fmt_analyzer(analyzer).c_str());
@ -711,7 +586,7 @@ void Analyzer::RemoveSupportAnalyzer(SupportAnalyzer* analyzer)
return;
}
bool Analyzer::HasSupportAnalyzer(AnalyzerTag::Tag tag, bool orig)
bool Analyzer::HasSupportAnalyzer(Tag tag, bool orig)
{
SupportAnalyzer* s = orig ? orig_supporters : resp_supporters;
for ( ; s; s = s->sibling )
@ -724,33 +599,33 @@ bool Analyzer::HasSupportAnalyzer(AnalyzerTag::Tag tag, bool orig)
void Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig,
int seq, const IP_Hdr* ip, int caplen)
{
DBG_LOG(DBG_DPD, "%s DeliverPacket(%d, %s, %d, %p, %d) [%s%s]",
DBG_LOG(DBG_ANALYZER, "%s DeliverPacket(%d, %s, %d, %p, %d) [%s%s]",
fmt_analyzer(this).c_str(), len, is_orig ? "T" : "F", seq, ip, caplen,
fmt_bytes((const char*) data, min(40, len)), len > 40 ? "..." : "");
}
void Analyzer::DeliverStream(int len, const u_char* data, bool is_orig)
{
DBG_LOG(DBG_DPD, "%s DeliverStream(%d, %s) [%s%s]",
DBG_LOG(DBG_ANALYZER, "%s DeliverStream(%d, %s) [%s%s]",
fmt_analyzer(this).c_str(), len, is_orig ? "T" : "F",
fmt_bytes((const char*) data, min(40, len)), len > 40 ? "..." : "");
}
void Analyzer::Undelivered(int seq, int len, bool is_orig)
{
DBG_LOG(DBG_DPD, "%s Undelivered(%d, %d, %s)",
DBG_LOG(DBG_ANALYZER, "%s Undelivered(%d, %d, %s)",
fmt_analyzer(this).c_str(), seq, len, is_orig ? "T" : "F");
}
void Analyzer::EndOfData(bool is_orig)
{
DBG_LOG(DBG_DPD, "%s EndOfData(%s)",
DBG_LOG(DBG_ANALYZER, "%s EndOfData(%s)",
fmt_analyzer(this).c_str(), is_orig ? "T" : "F");
}
void Analyzer::FlipRoles()
{
DBG_LOG(DBG_DPD, "%s FlipRoles()");
DBG_LOG(DBG_ANALYZER, "%s FlipRoles()");
LOOP_OVER_CHILDREN(i)
(*i)->FlipRoles();
@ -774,9 +649,12 @@ void Analyzer::ProtocolConfirmation()
if ( protocol_confirmed )
return;
EnumVal* tval = tag.AsEnumVal();
Ref(tval);
val_list* vl = new val_list;
vl->append(BuildConnVal());
vl->append(new Val(tag, TYPE_COUNT));
vl->append(tval);
vl->append(new Val(id, TYPE_COUNT));
// We immediately raise the event so that the analyzer can quickly
@ -802,9 +680,12 @@ void Analyzer::ProtocolViolation(const char* reason, const char* data, int len)
else
r = new StringVal(reason);
EnumVal* tval = tag.AsEnumVal();
Ref(tval);
val_list* vl = new val_list;
vl->append(BuildConnVal());
vl->append(new Val(tag, TYPE_COUNT));
vl->append(tval);
vl->append(new Val(id, TYPE_COUNT));
vl->append(r);
@ -876,6 +757,31 @@ void Analyzer::UpdateConnVal(RecordVal *conn_val)
(*i)->UpdateConnVal(conn_val);
}
RecordVal* Analyzer::BuildConnVal()
{
return conn->BuildConnVal();
}
void Analyzer::Event(EventHandlerPtr f, const char* name)
{
conn->Event(f, this, name);
}
void Analyzer::Event(EventHandlerPtr f, Val* v1, Val* v2)
{
conn->Event(f, this, v1, v2);
}
void Analyzer::ConnectionEvent(EventHandlerPtr f, val_list* vl)
{
conn->ConnectionEvent(f, this, vl);
}
void Analyzer::Weird(const char* name, const char* addl)
{
conn->Weird(name, addl);
}
void SupportAnalyzer::ForwardPacket(int len, const u_char* data, bool is_orig,
int seq, const IP_Hdr* ip, int caplen)
{

852
src/analyzer/Analyzer.h Normal file
View file

@ -0,0 +1,852 @@
// See the file "COPYING" in the main distribution directory for copyright.
#ifndef ANALYZER_ANALYZER_H
#define ANALYZER_ANALYZER_H
#include <list>
#include "Tag.h"
#include "../Obj.h"
#include "../EventHandler.h"
#include "../Timer.h"
class Rule;
class Connection;
class IP_Hdr;
namespace analyzer {
namespace tcp { class TCP_ApplicationAnalyzer; }
namespace pia { class PIA; }
class Analyzer;
class AnalyzerTimer;
class SupportAnalyzer;
class OutputHandler;
typedef list<Analyzer*> analyzer_list;
typedef uint32 ID;
typedef void (Analyzer::*analyzer_timer_func)(double t);
/**
* Class to receive processed output from an anlyzer.
*/
class OutputHandler {
public:
/**
* Destructor.
*/
virtual ~OutputHandler() { }
/**
* Hook for receiving packet data. Parameters are the same as for
* Analyzer::DeliverPacket().
*/
virtual void DeliverPacket(int len, const u_char* data,
bool orig, int seq,
const IP_Hdr* ip, int caplen)
{ }
/**
* Hook for receiving stream data. Parameters are the same as for
* Analyzer::DeliverStream().
*/
virtual void DeliverStream(int len, const u_char* data,
bool orig) { }
/**
* Hook for receiving notification of stream gaps. Parameters are the
* same as for Analyzer::Undelivered().
*/
virtual void Undelivered(int seq, int len, bool orig) { }
};
/**
* Main analyzer interface.
*
* Each analyzer is part of a tree, having a parent analyzer and an arbitrary
* number of child analyzers. Each analyzer also has a list of
* SupportAnalyzer. All analyzer input first passes through this list of
* support analyzers, which can perform arbitrary preprocessing.
*
* When overiding any of the class' methods, always make sure to call the
* base-class version first.
*/
class Analyzer {
public:
/**
* Constructor.
*
* @param name The name for the type of analyzer. The name must match
* the one the corresponding Component registers.
*
* @param conn The connection the analyzer is associated with.
*/
Analyzer(const char* name, Connection* conn);
/**
* Constructor.
*
* @param tag The tag for the type of analyzer. The tag must map to
* the name the corresponding Component registers.
*
* @param conn The connection the analyzer is associated with.
*/
Analyzer(const Tag& tag, Connection* conn);
/**
* Constructor. As this version of the constructor does not receive a
* name or tag, setTag() must be called before the instance can be
* used.
*
* @param conn The connection the analyzer is associated with.
*/
Analyzer(Connection* conn);
/**
* Destructor.
*/
virtual ~Analyzer();
/**
* Initializes the analyzer before input processing starts.
*/
virtual void Init();
/**
* Finishes the analyzer's operation after all input has been parsed.
*/
virtual void Done();
/**
* Passes packet input to the analyzer for processing. The analyzer
* will process the input with any support analyzers first and then
* forward the data to DeliverStream(), which derived classes can
* override.
*
* Note that there is a separate method for stream input,
* NextStream().
*
* @param len The number of bytes passed in.
*
* @param data Pointer the input to process.
*
* @param is_orig True if this is originator-side input.
*
* @param seq Current sequence number, if available (only supported
* if the data is coming from the TCP analyzer.
*
* @param ip An IP packet header associated with the data, if
* available.
*
* @param caplen The packet's capture length, if available.
*/
void NextPacket(int len, const u_char* data, bool is_orig,
int seq = -1, const IP_Hdr* ip = 0, int caplen = 0);
/**
* Passes stream input to the analyzer for processing. The analyzer
* will process the input with any support analyzers first and then
* forward the data to DeliverStream(), which derived classes can
* override.
*
* Note that there is a separate method for packet input,
* NextPacket().
*
* @param len The number of bytes passed in.
*
* @param data Pointer the input to process.
*
* @param is_orig True if this is originator-side input.
*/
void NextStream(int len, const u_char* data, bool is_orig);
/**
* Informs the analyzer about a gap in the TCP stream, i.e., data
* that can't be delivered. This method triggers Undelivered(), which
* derived classes can override.
*
* @param seq The sequence number of the first byte of gap.
*
* @param len The length of the gap.
*
* @param is_orig True if this is about originator-side input.
*/
void NextUndelivered(int seq, int len, bool is_orig);
/**
* Reports a message boundary. This is a generic method that can be
* used by an Analyzer if all data of a PDU has been delivered, e.g.,
* to report that HTTP body has been delivered completely by the HTTP
* analyzer before it starts with the next body. A final EndOfData()
* is automatically generated by the analyzer's Done() method. This
* method triggers EndOfData(), which derived classes can override.
*
* @param is_orig True if this is about originator-side input.
*/
void NextEndOfData(bool is_orig);
/**
* Forwards packet input on to all child analyzers. If the analyzer
* has an associated OutputHandlers, that one receives the input as
* well.
*
* Parameters are the same as for NextPacket().
*/
virtual void ForwardPacket(int len, const u_char* data,
bool orig, int seq,
const IP_Hdr* ip, int caplen);
/**
* Forwards stream input on to all child analyzers. If the analyzer
* has an associated OutputHandlers, that one receives the input as
* well.
*
* Parameters are the same as for NextStream().
*/
virtual void ForwardStream(int len, const u_char* data, bool orig);
/**
* Forwards a sequence gap on to all child analyzers.
*
* Parameters are the same as for NextUndelivered().
*/
virtual void ForwardUndelivered(int seq, int len, bool orig);
/**
* Forwards an end-of-data notification on to all child analyzers.
*
* Parameters are the same as for NextPacket().
*/
virtual void ForwardEndOfData(bool orig);
/**
* Hook for accessing packet input for parsing. This is called by
* NextDeliverPacket() and can be overridden by derived classes.
* Parameters are the same.
*/
virtual void DeliverPacket(int len, const u_char* data, bool orig,
int seq, const IP_Hdr* ip, int caplen);
/**
* Hook for accessing stream input for parsing. This is called by
* NextDeliverStream() and can be overridden by derived classes.
* Parameters are the same.
*/
virtual void DeliverStream(int len, const u_char* data, bool orig);
/**
* Hook for accessing input gap during parsing. This is called by
* NextUndelivered() and can be overridden by derived classes.
* Parameters are the same.
*/
virtual void Undelivered(int seq, int len, bool orig);
/**
* Hook for accessing end-of-data notifications. This is called by
* NextEndOfData() and can be overridden by derived classes.
* Parameters are the same.
*/
virtual void EndOfData(bool is_orig);
/**
* Signals the analyzer that its associated connection had its
* endpoint flipped. This can happen if during analysis it turns out
* that we got the direction of the connection wrong. In these
* cases, this method is called to swap state if necessary. This
* will not happen after payload has already been passed on, so most
* analyzers don't need to care.
*/
virtual void FlipRoles();
/**
* Returns the analyzer instance's internal ID. These IDs are unique
* across all analyzer instantiated and can thus be used to indentify
* a specific instance.
*/
ID GetID() const { return id; }
/**
* Returns the connection that the analyzer is associated with.
*/
Connection* Conn() const { return conn; }
/**
* Returns the OutputHandler associated with the connection, or null
* if none.
*/
OutputHandler* GetOutputHandler() const { return output_handler; }
/**
* Associates an OutputHandler with the connnection.
*
* @param handler The handler.
*/
void SetOutputHandler(OutputHandler* handler)
{ output_handler = handler; }
/**
* If this analyzer was activated by a signature match, this returns
* the signature that did so. Returns null otherwise.
*/
const Rule* Signature() const { return signature; }
/**
* Sets the signature that activated this analyzer, if any.
*
* @param sig The signature.
*/
void SetSignature(const Rule* sig) { signature = sig; }
/**
* Signals the analyzer to skip all further input processsing. The \a
* Next*() methods check this flag and discard the input if its set.
*
* @param do_skipe If true, further processing will be skipped.
*/
void SetSkip(bool do_skip) { skip = do_skip; }
/**
* Returns true if the analyzer has been told to skip processing all
* further input.
*/
bool Skipping() const { return skip; }
/**
* Returns true if Done() has been called.
*/
bool IsFinished() const { return finished; }
/**
* Returns the tag associated with the analyzer's type.
*/
Tag GetAnalyzerTag() const { assert(tag); return tag; }
/**
* Sets the tag associated with the analyzer's type. Note that this
* can be called only right after construction, if the constructor
* did not receive a name or tag. The method cannot be used to change
* an existing tag.
*/
void SetAnalyzerTag(const Tag& tag);
/**
* Returns a textual description of the analyzer's type. This is
* what's passed to the constructor and usally corresponds to the
* protocol name, e.g., "HTTP".
*/
const char* GetAnalyzerName() const;
/**
* Returns true if this analyzer's type matches the name passes in.
* This is shortcut for comparing GetAnalyzerName() with the given
* name.
*
* @param name The name to check.
*/
bool IsAnalyzer(const char* name);
/**
* Adds a new child analyzer to the analyzer tree. If an analyzer of
* the same type already exists, the one passes in is silenty
* discarded.
*
* @param analyzer The ananlyzer to add. Takes ownership.
*/
void AddChildAnalyzer(Analyzer* analyzer)
{ AddChildAnalyzer(analyzer, true); }
/**
* Adds a new child analyzer to the analyzer tree. If an analyzer of
* the same type already exists, the one passes in is silenty
* discarded.
*
* @param tag The type of analyzer to add.
*/
Analyzer* AddChildAnalyzer(Tag tag);
/**
* Removes a child analyzer. It's ok for the analyzer to not to be a
* child, in which case the method does nothing.
*
* @param analyzer The analyzer to remove.
*/
void RemoveChildAnalyzer(Analyzer* analyzer);
/**
* Removes a child analyzer. It's ok for the analyzer to not to be a
* child, in which case the method does nothing.
*
* @param tag The type of analyzer to remove.
*/
void RemoveChildAnalyzer(ID id);
/**
* Returns true if analyzer has a direct child of a given type.
*
* @param tag The type of analyzer to check for.
*/
bool HasChildAnalyzer(Tag tag);
/**
* Recursively searches all (direct or indirect) childs of the
* analyzer for an analyzer with a specific ID.
*
* @param id The analyzer id to search. This is the ID that GetID()
* returns.
*
* @return The analyzer, or null if not found.
*/
Analyzer* FindChild(ID id);
/**
* Recursively searches all (direct or indirect) childs of the
* analyzer for an analyzer of a given type.
*
* @param tag The analyzer type to search.
*
* @return The first analyzer of the given type found, or null if
* none.
*/
Analyzer* FindChild(Tag tag);
/**
* Recursively searches all (direct or indirect) childs of the
* analyzer for an analyzer of a given type.
*
* @param name The naem of the analyzer type to search (e.g.,
* "HTTP").
*
* @return The first analyzer of the given type found, or null if
* none.
*/
Analyzer* FindChild(const char* name);
/**
* Returns a list of all direct child analyzers.
*/
const analyzer_list& GetChildren() { return children; }
/**
* Returns a pointer to the parent analyzer, or null if this instance
* has not yet been added to an analyzer tree.
*/
Analyzer* Parent() const { return parent; }
/**
* Sets the parent analyzer.
*
* @param p The new parent.
*/
void SetParent(Analyzer* p) { parent = p; }
/**
* Remove the analyzer form its parent. The analyzer must have a
* parent associated with it.
*/
void Remove() { assert(parent); parent->RemoveChildAnalyzer(this); }
/**
* Appends a support analyzer to the current list.
*
* @param analyzer The support analyzer to add.
*/
void AddSupportAnalyzer(SupportAnalyzer* analyzer);
/**
* Remove a support analyzer.
*
* @param analyzer The analyzer to remove. The function is a no-op if
* that analyzer is not part of the list of support analyzer.
*/
void RemoveSupportAnalyzer(SupportAnalyzer* analyzer);
/**
* Signals Bro's protocol detection that the analyzer has recognized
* the input to indeed conform to the expected protocol. This should
* be called as early as possible during a connection's life-time. It
* may turn into \c protocol_confirmed event at the script-layer (but
* only once per analyzer for each connection, even if the method is
* called multiple times).
*/
virtual void ProtocolConfirmation();
/**
* Signals Bro's protocol detection that the analyzer has found a
* severe protocol violation that could indicate that it's not
* parsing the expected protocol. This turns into \c
* protocol_violation events at the script-layer (one such event is
* raised for each call to this method so that the script-layer can
* built up a notion of how prevalent protocol violations are; the
* more, the less likely it's the right protocol).
*
* @param reason A textual description of the error encountered.
*
* @param data An optional pointer to the malformed data.
*
* @param len If \a data is given, the length of it.
*/
virtual void ProtocolViolation(const char* reason,
const char* data = 0, int len = 0);
/**
* Returns true if ProtocolConfirmation() has been called at least
* once.
*/
bool ProtocolConfirmed() const
{ return protocol_confirmed; }
/**
* Called whenever the connection value is updated. Per default, this
* method will be called for each analyzer in the tree. Analyzers can
* use this method to attach additional data to the connections. A
* call to BuildConnVal() will in turn trigger a call to
* UpdateConnVal().
*
* @param conn_val The connenction value being updated.
*/
virtual void UpdateConnVal(RecordVal *conn_val);
/**
* Convenience function that forwards directly to
* Connection::BuildConnVal().
*/
RecordVal* BuildConnVal();
/**
* Convenience function that forwards directly to the corresponding
* Connection::Event().
*/
void Event(EventHandlerPtr f, const char* name = 0);
/**
* Convenience function that forwards directly to the corresponding
* Connection::Event().
*/
void Event(EventHandlerPtr f, Val* v1, Val* v2 = 0);
/**
* Convenience function that forwards directly to
* Connection::ConnectionEvent().
*/
void ConnectionEvent(EventHandlerPtr f, val_list* vl);
/**
* Convenience function that forwards directly to the corresponding
* Connection::Weird().
*/
void Weird(const char* name, const char* addl = "");
/**
* Internal method.
*/
virtual unsigned int MemoryAllocation() const;
protected:
friend class AnalyzerTimer;
friend class Manager;
friend class ::Connection;
friend class tcp::TCP_ApplicationAnalyzer;
/**
* Associates a connection with this analyzer. Must be called if
* using the default ctor.
*
* @param c The connection.
*/
void SetConnection(Connection* c) { conn = c; }
/**
* Instantiates a new timer associated with the analyzer.
*
* @param timer The callback function to execute when the timer
* fires.
*
* @param t The absolute time when the timer will fire.
*
* @param do_expire If true, the timer will also fire when Bro
* terminates even if \a t has not been reache yet.
*
* @param type The timer's type.
*/
void AddTimer(analyzer_timer_func timer, double t, int do_expire,
TimerType type);
/**
* Cancels all timers added previously via AddTimer().
*/
void CancelTimers();
/**
* Removes a given timer. This is an internal method and shouldn't be
* used by derived class. It does not cancel the timer.
*/
void RemoveTimer(Timer* t);
/**
* Returnsn true if the analyzer has associated an SupportAnalyzer of a given type.
*
* @param tag The type to check for.
*
* @param orig True if asking about the originator side.
*/
bool HasSupportAnalyzer(Tag tag, bool orig);
/**
* Adds a a new child analyzer with the option whether to intialize
* it. This is an internal method.
*
* @param analyzer The analyzer to add. Takes ownership.
*
* @param init If true, Init() will be calle.d
*/
void AddChildAnalyzer(Analyzer* analyzer, bool init);
/**
* Inits all child analyzers. This is an internal method.
*/
void InitChildren();
/**
* Reorganizes the child data structure. This is an internal method.
*/
void AppendNewChildren();
private:
// Internal method to eventually delete a child analyzer that's
// already Done().
void DeleteChild(analyzer_list::iterator i);
// Helper for the ctors.
void CtorInit(const Tag& tag, Connection* conn);
Tag tag;
ID id;
Connection* conn;
Analyzer* parent;
const Rule* signature;
OutputHandler* output_handler;
analyzer_list children;
SupportAnalyzer* orig_supporters;
SupportAnalyzer* resp_supporters;
analyzer_list new_children;
bool protocol_confirmed;
timer_list timers;
bool timers_canceled;
bool skip;
bool finished;
bool removing;
static ID id_counter;
};
/**
* Convenience macro to add a new timer.
*/
#define ADD_ANALYZER_TIMER(timer, t, do_expire, type) \
AddTimer(analyzer::analyzer_timer_func(timer), (t), (do_expire), (type))
/**
* Internal convenience macro to iterate over the list of child analyzers.
*/
#define LOOP_OVER_CHILDREN(var) \
for ( analyzer::analyzer_list::iterator var = children.begin(); \
var != children.end(); var++ )
/**
* Internal convenience macro to iterate over the constant list of child
* analyzers.
*/
#define LOOP_OVER_CONST_CHILDREN(var) \
for ( analyzer::analyzer_list::const_iterator var = children.begin(); \
var != children.end(); var++ )
/**
* Convenience macro to iterate over a given list of child analyzers.
*/
#define LOOP_OVER_GIVEN_CHILDREN(var, the_kids) \
for ( analyzer::analyzer_list::iterator var = the_kids.begin(); \
var != the_kids.end(); var++ )
/**
* Convenience macro to iterate over a given constant list of child
* analyzers.
*/
#define LOOP_OVER_GIVEN_CONST_CHILDREN(var, the_kids) \
for ( analyzer::analyzer_list::const_iterator var = the_kids.begin(); \
var != the_kids.end(); var++ )
/**
* Support analyzer preprocess input before it reaches an analyzer's main
* processing. They share the input interface with of an Analyzer but they
* are uni-directional: they receive data only from one side of a connection.
*
*/
class SupportAnalyzer : public Analyzer {
public:
/**
* Constructor.
*
* @param name A name for the protocol the analyzer is parsing. The
* name must match the one the corresponding Component registers.
*
* @param conn The connection the analyzer is associated with.
*
* @param arg_orig: If true, this is a support analyzer for the
* connection originator side, and otherwise for the responder side.
*/
SupportAnalyzer(const char* name, Connection* conn, bool arg_orig)
: Analyzer(name, conn) { orig = arg_orig; sibling = 0; }
/**
* Destructor.
*/
virtual ~SupportAnalyzer() {}
/**
* Returns true if this is a support analyzer for the connection's
* originator side.
*/
bool IsOrig() const { return orig; }
/**
* Passes packet input to the next sibling SupportAnalyzer if any, or
* on to the associated main analyzer if none. If however there's an
* output handler associated with this support analyzer, the data is
* passed only to there.
*
* Parameters same as for Analyzer::ForwardPacket.
*/
virtual void ForwardPacket(int len, const u_char* data, bool orig,
int seq, const IP_Hdr* ip, int caplen);
/**
* Passes stream input to the next sibling SupportAnalyzer if any, or
* on to the associated main analyzer if none. If however there's an
* output handler associated with this support analyzer, the data is
* passed only to there.
*
* Parameters same as for Analyzer::ForwardStream.
*/
virtual void ForwardStream(int len, const u_char* data, bool orig);
/**
* Passes gap information to the next sibling SupportAnalyzer if any,
* or on to the associated main analyzer if none. If however there's
* an output handler associated with this support analyzer, the gap is
* passed only to there.
*
* Parameters same as for Analyzer::ForwardPacket.
*/
virtual void ForwardUndelivered(int seq, int len, bool orig);
/**
* Returns the analyzer next sibling, or null if none.
*/
SupportAnalyzer* Sibling() const { return sibling; }
protected:
friend class Analyzer;
private:
bool orig;
// Points to next support analyzer in chain. The list is managed by
// parent analyzer.
SupportAnalyzer* sibling;
};
// The following need to be consistent with bro.init.
#define CONTENTS_NONE 0
#define CONTENTS_ORIG 1
#define CONTENTS_RESP 2
#define CONTENTS_BOTH 3
/**
* Base class for analyzers parsing transport-layer protocols.
*/
class TransportLayerAnalyzer : public Analyzer {
public:
/**
* Constructor.
*
* @param name A name for the protocol the analyzer is parsing. The
* name must match the one the corresponding Component registers.
*
* @param conn The connection the analyzer is associated with.
*/
TransportLayerAnalyzer(const char* name, Connection* conn)
: Analyzer(name, conn) { pia = 0; }
/**
* Overridden from parent class.
*/
virtual void Done();
/**
* Returns true if the analyzer determines that in fact a new
* connection has started without the connection statement having
* terminated the previous one, i.e., the new data is arriving at
* what's the analyzer for the previous instance. This is used only
* for TCP.
*/
virtual bool IsReuse(double t, const u_char* pkt) = 0;
/**
* Associates a file with the analyzer in which to record all
* analyzed input. This must only be called with derived classes that
* overide the method; the default implementation will abort.
*
* @param direction One of the CONTENTS_* constants indicating which
* direction of the input stream is to be recorded.
*
* @param f The file to record to.
*
*/
virtual void SetContentsFile(unsigned int direction, BroFile* f);
/**
* Returns an associated contents file, if any. This must only be
* called with derived classes that overide the method; the default
* implementation will abort.
*
* @param direction One of the CONTENTS_* constants indicating which
* direction the query is for.
*/
virtual BroFile* GetContentsFile(unsigned int direction) const;
/**
* Associates a PIA with this analyzer. A PIA takes the
* transport-layer input and determine which protocol analyzer(s) to
* use for parsing it.
*/
void SetPIA(pia::PIA* arg_PIA) { pia = arg_PIA; }
/**
* Returns the associated PIA, or null of none. Does not take
* ownership.
*/
pia::PIA* GetPIA() const { return pia; }
/**
* Helper to raise a \c packet_contents event.
*
* @param data The dass to pass to the event.
*
* @param len The length of \a data.
*/
void PacketContents(const u_char* data, int len);
private:
pia::PIA* pia;
};
}
#endif

View file

@ -0,0 +1,22 @@
include(BroSubdir)
include_directories(BEFORE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
)
add_subdirectory(protocol)
set(analyzer_SRCS
Analyzer.cc
Manager.cc
Component.cc
Tag.cc
)
bif_target(analyzer.bif)
bro_add_subdir_library(analyzer ${analyzer_SRCS} ${BIF_OUTPUT_CC})
add_dependencies(bro_analyzer generate_outputs)

90
src/analyzer/Component.cc Normal file
View file

@ -0,0 +1,90 @@
// See the file "COPYING" in the main distribution directory for copyright.
#include "Component.h"
#include "Manager.h"
#include "../Desc.h"
using namespace analyzer;
Tag::type_t Component::type_counter = 0;
static const char* canonify_name(const char* name)
{
unsigned int len = strlen(name);
char* nname = new char[len + 1];
for ( unsigned int i = 0; i < len; i++ )
{
char c = isalnum(name[i]) ? name[i] : '_';
nname[i] = toupper(c);
}
nname[len] = '\0';
return nname;
}
Component::Component(const char* arg_name, factory_callback arg_factory, Tag::subtype_t arg_subtype, bool arg_enabled, bool arg_partial)
: plugin::Component(plugin::component::ANALYZER)
{
name = copy_string(arg_name);
canon_name = canonify_name(arg_name);
factory = arg_factory;
enabled = arg_enabled;
partial = arg_partial;
tag = analyzer::Tag(++type_counter, arg_subtype);
}
Component::Component(const Component& other)
: plugin::Component(Type())
{
name = copy_string(other.name);
canon_name = copy_string(other.canon_name);
factory = other.factory;
enabled = other.enabled;
partial = other.partial;
tag = other.tag;
}
Component::~Component()
{
delete [] name;
delete [] canon_name;
}
analyzer::Tag Component::Tag() const
{
return tag;
}
void Component::Describe(ODesc* d)
{
plugin::Component::Describe(d);
d->Add(name);
d->Add(" (");
if ( factory )
{
d->Add("ANALYZER_");
d->Add(canon_name);
d->Add(", ");
}
d->Add(enabled ? "enabled" : "disabled");
d->Add(")");
}
Component& Component::operator=(const Component& other)
{
if ( &other != this )
{
name = copy_string(other.name);
factory = other.factory;
enabled = other.enabled;
partial = other.partial;
tag = other.tag;
}
return *this;
}

141
src/analyzer/Component.h Normal file
View file

@ -0,0 +1,141 @@
// See the file "COPYING" in the main distribution directory for copyright.
#ifndef ANALYZER_PLUGIN_COMPONENT_H
#define ANALYZER_PLUGIN_COMPONENT_H
#include "Tag.h"
#include "plugin/Component.h"
#include "../config.h"
#include "../util.h"
class Connection;
namespace analyzer {
class Analyzer;
/**
* Component description for plugins providing analyzers.
*
* A plugin can provide a specific protocol analyzer by registering this
* analyzer component, describing the analyzer.
*/
class Component : public plugin::Component {
public:
typedef bool (*available_callback)();
typedef Analyzer* (*factory_callback)(Connection* conn);
/**
* Constructor.
*
* @param name The name of the provided analyzer. This name is used
* across the system to identify the analyzer, e.g., when calling
* analyzer::Manager::InstantiateAnalyzer with a name.
*
* @param factory A factory function to instantiate instances of the
* analyzer's class, which must be derived directly or indirectly
* from analyzer::Analyzer. This is typically a static \c
* Instatiate() method inside the class that just allocates and
* returns a new instance.
*
* @param subtype A subtype associated with this component that
* further distinguishes it. The subtype will be integrated into
* the analyzer::Tag that the manager associates with this analyzer,
* and analyzer instances can accordingly access it via analyzer::Tag().
* If not used, leave at zero.
*
* @param enabled If false the analyzer starts out as disabled and
* hence won't be used. It can still be enabled later via the
* manager, including from script-land.
*
* @param partial If true, the analyzer can deal with payload from
* partial connections, i.e., when Bro enters the stream mid-way
* after not seeing the beginning. Note that handling of partial
* connections has generally not seen much testing yet as virtually
* no existing analyzer supports it.
*/
Component(const char* name, factory_callback factory, Tag::subtype_t subtype = 0, bool enabled = true, bool partial = false);
/**
* Copy constructor.
*/
Component(const Component& other);
/**
* Destructor.
*/
~Component();
/**
* Returns the name of the analyzer. This name is unique across all
* analyzers and used to identify it. The returned name is derived
* from what's passed to the constructor but upper-cased and
* canonified to allow being part of a script-level ID.
*/
const char* Name() const { return name; }
/**
* Returns a canonocalized version of the analyzer's name. The
* returned name is derived from what's passed to the constructor but
* upper-cased and transformed to allow being part of a script-level
* ID.
*/
const char* CanonicalName() const { return canon_name; }
/**
* Returns the analyzer's factory function.
*/
factory_callback Factory() const { return factory; }
/**
* Returns whether the analyzer supports partial connections. Partial
* connections are those where Bro starts processing payload
* mid-stream, after missing the beginning.
*/
bool Partial() const { return partial; }
/**
* Returns true if the analyzer is currently enabled and hence
* available for use.
*/
bool Enabled() const { return enabled; }
/**
* Returns the analyzer's tag. Note that this is automatically
* generated for each new Components, and hence unique across all of
* them.
*/
analyzer::Tag Tag() const;
/**
* Enables or disables this analyzer.
*
* @param arg_enabled True to enabled, false to disable.
*
*/
void SetEnabled(bool arg_enabled) { enabled = arg_enabled; }
/**
* Generates a human-readable description of the component's main
* parameters. This goes into the output of \c "bro -NN".
*/
virtual void Describe(ODesc* d);
Component& operator=(const Component& other);
private:
const char* name; // The analyzer's name.
const char* canon_name; // The analyzer's canonical name.
factory_callback factory; // The analyzer's factory callback.
bool partial; // True if the analyzer supports partial connections.
analyzer::Tag tag; // The automatically assigned analyzer tag.
bool enabled; // True if the analyzer is enabled.
// Global counter used to generate unique tags.
static analyzer::Tag::type_t type_counter;
};
}
#endif

697
src/analyzer/Manager.cc Normal file
View file

@ -0,0 +1,697 @@
// See the file "COPYING" in the main distribution directory for copyright.
#include "Manager.h"
#include "Hash.h"
#include "Val.h"
#include "protocol/backdoor/BackDoor.h"
#include "protocol/conn-size/ConnSize.h"
#include "protocol/icmp/ICMP.h"
#include "protocol/interconn/InterConn.h"
#include "protocol/pia/PIA.h"
#include "protocol/stepping-stone/SteppingStone.h"
#include "protocol/tcp/TCP.h"
#include "protocol/udp/UDP.h"
#include "plugin/Manager.h"
#include "protocol/tcp/events.bif.h"
using namespace analyzer;
Manager::ConnIndex::ConnIndex(const IPAddr& _orig, const IPAddr& _resp,
uint16 _resp_p, uint16 _proto)
{
if ( _orig == IPAddr(string("0.0.0.0")) )
// don't use the IPv4 mapping, use the literal unspecified address
// to indicate a wildcard
orig = IPAddr(string("::"));
else
orig = _orig;
resp = _resp;
resp_p = _resp_p;
proto = _proto;
}
Manager::ConnIndex::ConnIndex()
{
orig = resp = IPAddr("0.0.0.0");
resp_p = 0;
proto = 0;
}
bool Manager::ConnIndex::operator<(const ConnIndex& other) const
{
if ( orig != other.orig )
return orig < other.orig;
if ( resp != other.resp )
return resp < other.resp;
if ( proto != other.proto )
return proto < other.proto;
if ( resp_p != other.resp_p )
return resp_p < other.resp_p;
return false;
}
Manager::Manager()
{
tag_enum_type = new EnumType("Analyzer::Tag");
::ID* id = install_ID("Tag", "Analyzer", true, true);
add_type(id, tag_enum_type, 0, 0);
}
Manager::~Manager()
{
for ( analyzer_map_by_port::const_iterator i = analyzers_by_port_tcp.begin(); i != analyzers_by_port_tcp.end(); i++ )
delete i->second;
for ( analyzer_map_by_port::const_iterator i = analyzers_by_port_udp.begin(); i != analyzers_by_port_udp.end(); i++ )
delete i->second;
analyzers_by_port_udp.clear();
analyzers_by_port_tcp.clear();
// Clean up expected-connection table.
while ( conns_by_timeout.size() )
{
ScheduledAnalyzer* a = conns_by_timeout.top();
conns_by_timeout.pop();
delete a;
}
}
void Manager::InitPreScript()
{
std::list<Component*> analyzers = plugin_mgr->Components<Component>();
for ( std::list<Component*>::const_iterator i = analyzers.begin(); i != analyzers.end(); i++ )
RegisterAnalyzerComponent(*i);
// Cache these tags.
analyzer_backdoor = GetAnalyzerTag("BACKDOOR");
analyzer_connsize = GetAnalyzerTag("CONNSIZE");
analyzer_interconn = GetAnalyzerTag("INTERCONN");
analyzer_stepping = GetAnalyzerTag("STEPPINGSTONE");
analyzer_tcpstats = GetAnalyzerTag("TCPSTATS");
}
void Manager::InitPostScript()
{
#include "analyzer.bif.init.cc"
}
void Manager::DumpDebug()
{
#ifdef DEBUG
DBG_LOG(DBG_ANALYZER, "Available analyzers after bro_init():");
for ( analyzer_map_by_name::const_iterator i = analyzers_by_name.begin(); i != analyzers_by_name.end(); i++ )
DBG_LOG(DBG_ANALYZER, " %s (%s)", i->second->Name(), IsEnabled(i->second->Tag()) ? "enabled" : "disabled");
DBG_LOG(DBG_ANALYZER, "");
DBG_LOG(DBG_ANALYZER, "Analyzers by port:");
for ( analyzer_map_by_port::const_iterator i = analyzers_by_port_tcp.begin(); i != analyzers_by_port_tcp.end(); i++ )
{
string s;
for ( tag_set::const_iterator j = i->second->begin(); j != i->second->end(); j++ )
s += string(GetAnalyzerName(*j)) + " ";
DBG_LOG(DBG_ANALYZER, " %d/tcp: %s", i->first, s.c_str());
}
for ( analyzer_map_by_port::const_iterator i = analyzers_by_port_udp.begin(); i != analyzers_by_port_udp.end(); i++ )
{
string s;
for ( tag_set::const_iterator j = i->second->begin(); j != i->second->end(); j++ )
s += string(GetAnalyzerName(*j)) + " ";
DBG_LOG(DBG_ANALYZER, " %d/udp: %s", i->first, s.c_str());
}
#endif
}
void Manager::Done()
{
}
void Manager::RegisterAnalyzerComponent(Component* component)
{
const char* cname = component->CanonicalName();
if ( Lookup(cname) )
reporter->FatalError("Analyzer %s defined more than once", cname);
DBG_LOG(DBG_ANALYZER, "Registering analyzer %s (tag %s)",
component->Name(), component->Tag().AsString().c_str());
analyzers_by_name.insert(std::make_pair(cname, component));
analyzers_by_tag.insert(std::make_pair(component->Tag(), component));
analyzers_by_val.insert(std::make_pair(component->Tag().AsEnumVal()->InternalInt(), component));
// Install enum "Analyzer::ANALYZER_*"
string id = fmt("ANALYZER_%s", cname);
tag_enum_type->AddName("Analyzer", id.c_str(), component->Tag().AsEnumVal()->InternalInt(), true);
}
bool Manager::EnableAnalyzer(Tag tag)
{
Component* p = Lookup(tag);
if ( ! p )
return false;
DBG_LOG(DBG_ANALYZER, "Enabling analyzer %s", p->Name());
p->SetEnabled(true);
return true;
}
bool Manager::EnableAnalyzer(EnumVal* val)
{
Component* p = Lookup(val);
if ( ! p )
return false;
DBG_LOG(DBG_ANALYZER, "Enabling analyzer %s", p->Name());
p->SetEnabled(true);
return true;
}
bool Manager::DisableAnalyzer(Tag tag)
{
Component* p = Lookup(tag);
if ( ! p )
return false;
DBG_LOG(DBG_ANALYZER, "Disabling analyzer %s", p->Name());
p->SetEnabled(false);
return true;
}
bool Manager::DisableAnalyzer(EnumVal* val)
{
Component* p = Lookup(val);
if ( ! p )
return false;
DBG_LOG(DBG_ANALYZER, "Disabling analyzer %s", p->Name());
p->SetEnabled(false);
return true;
}
void Manager::DisableAllAnalyzers()
{
DBG_LOG(DBG_ANALYZER, "Disabling all analyzers");
for ( analyzer_map_by_tag::const_iterator i = analyzers_by_tag.begin(); i != analyzers_by_tag.end(); i++ )
i->second->SetEnabled(false);
}
bool Manager::IsEnabled(Tag tag)
{
if ( ! tag )
return false;
Component* p = Lookup(tag);
if ( ! p )
return false;
return p->Enabled();
}
bool Manager::IsEnabled(EnumVal* val)
{
Component* p = Lookup(val);
if ( ! p )
return false;
return p->Enabled();
}
bool Manager::RegisterAnalyzerForPort(EnumVal* val, PortVal* port)
{
Component* p = Lookup(val);
if ( ! p )
return false;
return RegisterAnalyzerForPort(p->Tag(), port->PortType(), port->Port());
}
bool Manager::UnregisterAnalyzerForPort(EnumVal* val, PortVal* port)
{
Component* p = Lookup(val);
if ( ! p )
return false;
return UnregisterAnalyzerForPort(p->Tag(), port->PortType(), port->Port());
}
bool Manager::RegisterAnalyzerForPort(Tag tag, TransportProto proto, uint32 port)
{
tag_set* l = LookupPort(proto, port, true);
#ifdef DEBUG
const char* name = GetAnalyzerName(tag);
DBG_LOG(DBG_ANALYZER, "Registering analyzer %s for port %" PRIu32 "/%d", name, port, proto);
#endif
l->insert(tag);
return true;
}
bool Manager::UnregisterAnalyzerForPort(Tag tag, TransportProto proto, uint32 port)
{
tag_set* l = LookupPort(proto, port, true);
#ifdef DEBUG
const char* name = GetAnalyzerName(tag);
DBG_LOG(DBG_ANALYZER, "Unregistering analyzer %s for port %" PRIu32 "/%d", name, port, proto);
#endif
l->erase(tag);
return true;
}
Analyzer* Manager::InstantiateAnalyzer(Tag tag, Connection* conn)
{
Component* c = Lookup(tag);
if ( ! c )
reporter->InternalError("request to instantiate unknown analyzer");
if ( ! c->Enabled() )
return 0;
if ( ! c->Factory() )
reporter->InternalError("analyzer %s cannot be instantiated dynamically", GetAnalyzerName(tag));
Analyzer* a = c->Factory()(conn);
if ( ! a )
reporter->InternalError("analyzer instantiation failed");
a->SetAnalyzerTag(tag);
return a;
}
Analyzer* Manager::InstantiateAnalyzer(const char* name, Connection* conn)
{
Tag tag = GetAnalyzerTag(name);
return tag ? InstantiateAnalyzer(tag, conn) : 0;
}
const char* Manager::GetAnalyzerName(Tag tag)
{
static const char* error = "<error>";
if ( ! tag )
return error;
Component* c = Lookup(tag);
if ( ! c )
reporter->InternalError("request for name of unknown analyzer tag %s", tag.AsString().c_str());
return c->CanonicalName();
}
const char* Manager::GetAnalyzerName(Val* val)
{
return GetAnalyzerName(Tag(val->AsEnumVal()));
}
Tag Manager::GetAnalyzerTag(const char* name)
{
Component* c = Lookup(name);
return c ? c->Tag() : Tag();
}
EnumType* Manager::GetTagEnumType()
{
return tag_enum_type;
}
Component* Manager::Lookup(const char* name)
{
analyzer_map_by_name::const_iterator i = analyzers_by_name.find(to_upper(name));
return i != analyzers_by_name.end() ? i->second : 0;
}
Component* Manager::Lookup(const Tag& tag)
{
analyzer_map_by_tag::const_iterator i = analyzers_by_tag.find(tag);
return i != analyzers_by_tag.end() ? i->second : 0;
}
Component* Manager::Lookup(EnumVal* val)
{
analyzer_map_by_val::const_iterator i = analyzers_by_val.find(val->InternalInt());
return i != analyzers_by_val.end() ? i->second : 0;
}
Manager::tag_set* Manager::LookupPort(TransportProto proto, uint32 port, bool add_if_not_found)
{
analyzer_map_by_port* m = 0;
switch ( proto ) {
case TRANSPORT_TCP:
m = &analyzers_by_port_tcp;
break;
case TRANSPORT_UDP:
m = &analyzers_by_port_udp;
break;
default:
reporter->InternalError("unsupport transport protocol in analyzer::Manager::LookupPort");
}
analyzer_map_by_port::const_iterator i = m->find(port);
if ( i != m->end() )
return i->second;
if ( ! add_if_not_found )
return 0;
tag_set* l = new tag_set;
m->insert(std::make_pair(port, l));
return l;
}
Manager::tag_set* Manager::LookupPort(PortVal* val, bool add_if_not_found)
{
return LookupPort(val->PortType(), val->Port(), add_if_not_found);
}
bool Manager::BuildInitialAnalyzerTree(Connection* conn)
{
Analyzer* analyzer = 0;
tcp::TCP_Analyzer* tcp = 0;
udp::UDP_Analyzer* udp = 0;
icmp::ICMP_Analyzer* icmp = 0;
TransportLayerAnalyzer* root = 0;
tag_set expected;
pia::PIA* pia = 0;
bool analyzed = false;
bool check_port = false;
switch ( conn->ConnTransport() ) {
case TRANSPORT_TCP:
root = tcp = new tcp::TCP_Analyzer(conn);
pia = new pia::PIA_TCP(conn);
expected = GetScheduled(conn);
check_port = true;
DBG_ANALYZER(conn, "activated TCP analyzer");
break;
case TRANSPORT_UDP:
root = udp = new udp::UDP_Analyzer(conn);
pia = new pia::PIA_UDP(conn);
expected = GetScheduled(conn);
check_port = true;
DBG_ANALYZER(conn, "activated UDP analyzer");
break;
case TRANSPORT_ICMP: {
root = icmp = new icmp::ICMP_Analyzer(conn);
DBG_ANALYZER(conn, "activated ICMP analyzer");
analyzed = true;
break;
}
default:
reporter->InternalError("unknown protocol");
}
if ( ! root )
{
DBG_ANALYZER(conn, "cannot build analyzer tree");
return false;
}
// Any scheduled analyzer?
for ( tag_set::iterator i = expected.begin(); i != expected.end(); i++ )
{
Analyzer* analyzer = analyzer_mgr->InstantiateAnalyzer(*i, conn);
if ( analyzer )
{
root->AddChildAnalyzer(analyzer, false);
DBG_ANALYZER_ARGS(conn, "activated %s analyzer as scheduled",
analyzer_mgr->GetAnalyzerName(*i));
}
}
// Hmm... Do we want *just* the expected analyzer, or all
// other potential analyzers as well? For now we only take
// the scheduled ones.
if ( expected.size() == 0 )
{ // Let's see if it's a port we know.
if ( check_port && ! dpd_ignore_ports )
{
int resp_port = ntohs(conn->RespPort());
tag_set* ports = LookupPort(conn->ConnTransport(), resp_port, false);
if ( ports )
{
for ( tag_set::const_iterator j = ports->begin(); j != ports->end(); ++j )
{
Analyzer* analyzer = analyzer_mgr->InstantiateAnalyzer(*j, conn);
if ( ! analyzer )
continue;
root->AddChildAnalyzer(analyzer, false);
DBG_ANALYZER_ARGS(conn, "activated %s analyzer due to port %d",
analyzer_mgr->GetAnalyzerName(*j), resp_port);
}
}
}
}
if ( tcp )
{
// We have to decide whether to reassamble the stream.
// We turn it on right away if we already have an app-layer
// analyzer, reassemble_first_packets is true, or the user
// asks us to do so. In all other cases, reassembly may
// be turned on later by the TCP PIA.
bool reass = root->GetChildren().size() ||
dpd_reassemble_first_packets ||
tcp_content_deliver_all_orig ||
tcp_content_deliver_all_resp;
if ( tcp_contents && ! reass )
{
PortVal dport(ntohs(conn->RespPort()), TRANSPORT_TCP);
Val* result;
if ( ! reass )
reass = tcp_content_delivery_ports_orig->Lookup(&dport);
if ( ! reass )
reass = tcp_content_delivery_ports_resp->Lookup(&dport);
}
if ( reass )
tcp->EnableReassembly();
if ( IsEnabled(analyzer_backdoor) )
// Add a BackDoor analyzer if requested. This analyzer
// can handle both reassembled and non-reassembled input.
tcp->AddChildAnalyzer(new backdoor::BackDoor_Analyzer(conn), false);
if ( IsEnabled(analyzer_interconn) )
// Add a InterConn analyzer if requested. This analyzer
// can handle both reassembled and non-reassembled input.
tcp->AddChildAnalyzer(new interconn::InterConn_Analyzer(conn), false);
if ( IsEnabled(analyzer_stepping) )
{
// Add a SteppingStone analyzer if requested. The port
// should really not be hardcoded here, but as it can
// handle non-reassembled data, it doesn't really fit into
// our general framing ... Better would be to turn it
// on *after* we discover we have interactive traffic.
uint16 resp_port = ntohs(conn->RespPort());
if ( resp_port == 22 || resp_port == 23 || resp_port == 513 )
{
AddrVal src(conn->OrigAddr());
if ( ! stp_skip_src->Lookup(&src) )
tcp->AddChildAnalyzer(new stepping_stone::SteppingStone_Analyzer(conn), false);
}
}
if ( IsEnabled(analyzer_tcpstats) )
// Add TCPStats analyzer. This needs to see packets so
// we cannot add it as a normal child.
tcp->AddChildPacketAnalyzer(new tcp::TCPStats_Analyzer(conn));
if ( IsEnabled(analyzer_connsize) )
// Add ConnSize analyzer. Needs to see packets, not stream.
tcp->AddChildPacketAnalyzer(new conn_size::ConnSize_Analyzer(conn));
}
else
{
if ( IsEnabled(analyzer_connsize) )
// Add ConnSize analyzer. Needs to see packets, not stream.
root->AddChildAnalyzer(new conn_size::ConnSize_Analyzer(conn));
}
if ( pia )
root->AddChildAnalyzer(pia->AsAnalyzer());
if ( root->GetChildren().size() )
analyzed = true;
conn->SetRootAnalyzer(root, pia);
root->Init();
root->InitChildren();
if ( ! analyzed )
conn->SetLifetime(non_analyzed_lifetime);
for ( tag_set::iterator i = expected.begin(); i != expected.end(); i++ )
{
EnumVal* tag = i->AsEnumVal();
Ref(tag);
conn->Event(scheduled_analyzer_applied, 0, tag);
}
return true;
}
void Manager::ExpireScheduledAnalyzers()
{
if ( ! network_time )
return;
while ( conns_by_timeout.size() )
{
ScheduledAnalyzer* a = conns_by_timeout.top();
if ( a->timeout > network_time )
return;
conns_by_timeout.pop();
std::pair<conns_map::iterator, conns_map::iterator> all = conns.equal_range(a->conn);
bool found = false;
for ( conns_map::iterator i = all.first; i != all.second; i++ )
{
if ( i->second != a )
continue;
conns.erase(i);
DBG_LOG(DBG_ANALYZER, "Expiring expected analyzer %s for connection %s",
analyzer_mgr->GetAnalyzerName(a->analyzer),
fmt_conn_id(a->conn.orig, 0, a->conn.resp, a->conn.resp_p));
delete a;
found = true;
break;
}
assert(found);
}
}
void Manager::ScheduleAnalyzer(const IPAddr& orig, const IPAddr& resp,
uint16 resp_p,
TransportProto proto, Tag analyzer,
double timeout)
{
if ( ! network_time )
{
reporter->Warning("cannot schedule analyzers before processing begins; ignored");
return;
}
assert(timeout);
// Use the chance to see if the oldest entry is already expired.
ExpireScheduledAnalyzers();
ScheduledAnalyzer* a = new ScheduledAnalyzer;
a->conn = ConnIndex(orig, resp, resp_p, proto);
a->analyzer = analyzer;
a->timeout = network_time + timeout;
conns.insert(std::make_pair(a->conn, a));
conns_by_timeout.push(a);
}
void Manager::ScheduleAnalyzer(const IPAddr& orig, const IPAddr& resp,
uint16 resp_p,
TransportProto proto, const char* analyzer,
double timeout)
{
Tag tag = GetAnalyzerTag(analyzer);
if ( tag != Tag() )
ScheduleAnalyzer(orig, resp, resp_p, proto, tag, timeout);
}
void Manager::ScheduleAnalyzer(const IPAddr& orig, const IPAddr& resp, PortVal* resp_p,
Val* analyzer, double timeout)
{
EnumVal* ev = analyzer->AsEnumVal();
return ScheduleAnalyzer(orig, resp, resp_p->Port(), resp_p->PortType(), Tag(ev), timeout);
}
Manager::tag_set Manager::GetScheduled(const Connection* conn)
{
ConnIndex c(conn->OrigAddr(), conn->RespAddr(),
ntohs(conn->RespPort()), conn->ConnTransport());
std::pair<conns_map::iterator, conns_map::iterator> all = conns.equal_range(c);
tag_set result;
for ( conns_map::iterator i = all.first; i != all.second; i++ )
result.insert(i->second->analyzer);
// Try wildcard for originator.
c.orig = IPAddr(string("::"));
all = conns.equal_range(c);
for ( conns_map::iterator i = all.first; i != all.second; i++ )
{
if ( i->second->timeout > network_time )
result.insert(i->second->analyzer);
}
// We don't delete scheduled analyzers here. They will be expired
// eventually.
return result;
}

443
src/analyzer/Manager.h Normal file
View file

@ -0,0 +1,443 @@
// See the file "COPYING" in the main distribution directory for copyright.
/**
* The central management unit for registering and instantiating analyzers.
*
* For each protocol that Bro supports, there's one class derived from
* analyzer::Analyzer. Once we have decided that a connection's payload is to
* be parsed as a given protocol, we instantiate the corresponding
* analyzer-derived class and add the new instance as a child node into the
* connection's analyzer tree.
*
* In addition to the analyzer-derived class itself, for each protocol
* there's also "meta-class" derived from analyzer::Component that describes
* the analyzer, including status information on if that particular protocol
* analysis is currently enabled.
*
* To identify an analyzer (or to be precise: a component), the manager
* maintains mappings of (1) analyzer::Tag to component, and (2)
* human-readable analyzer name to component.
*/
#ifndef ANALYZER_MANAGER_H
#define ANALYZER_MANAGER_H
#include <queue>
#include "Analyzer.h"
#include "Component.h"
#include "Tag.h"
#include "../Dict.h"
#include "../net_util.h"
#include "../IP.h"
#include "analyzer/analyzer.bif.h"
namespace analyzer {
/**
* Class maintaining and scheduling available protocol analyzers.
*
* The manager maintains a registry of all available protocol analyzers,
* including a mapping between their textual names and analyzer::Tag. It
* instantantiates new analyzers on demand. For new connections, the manager
* sets up their initial analyzer tree, including adding the right \c PIA,
* respecting well-known ports, and tracking any analyzers specifically
* scheduled for individidual connections.
*
* Note that we keep the public interface of this class free of std::*
* classes. This allows to external analyzer code to potentially use a
* different C++ standard library.
*/
class Manager {
public:
/**
* Constructor.
*/
Manager();
/**
* Destructor.
*/
~Manager();
/**
* First-stage initializion of the manager. This is called early on
* during Bro's initialization, before any scripts are processed.
*/
void InitPreScript();
/**
* Second-stage initialization of the manager. This is called late
* during Bro's initialization after any scripts are processed.
*/
void InitPostScript();
/**
* Finished the manager's operations.
*/
void Done();
/**
* Dumps out the state of all registered analyzers to the \c analyzer
* debug stream. Should be called only after any \c bro_init events
* have executed to ensure that any of their changes are applied.
*/
void DumpDebug(); // Called after bro_init() events.
/**
* Enables an analyzer type. Only enabled analyzers will be
* instantiated for new connections.
*
* @param tag The analyzer's tag.
*
* @return True if successful.
*/
bool EnableAnalyzer(Tag tag);
/**
* Enables an analyzer type. Only enabled analyzers will be
* instantiated for new connections.
*
* @param tag The analyzer's tag as an enum of script type \c
* Analyzer::Tag.
*
* @return True if successful.
*/
bool EnableAnalyzer(EnumVal* tag);
/**
* Enables an analyzer type. Disabled analyzers will not be
* instantiated for new connections.
*
* @param tag The analyzer's tag.
*
* @return True if successful.
*/
bool DisableAnalyzer(Tag tag);
/**
* Enables an analyzer type. Disabled analyzers will not be
* instantiated for new connections.
*
* @param tag The analyzer's tag as an enum of script type \c
* Analyzer::Tag.
*
* @return True if successful.
*/
bool DisableAnalyzer(EnumVal* tag);
/**
* Disables all currently registered analyzers.
*/
void DisableAllAnalyzers();
/**
* Returns true if an analyzer is enabled.
*
* @param tag The analyzer's tag.
*/
bool IsEnabled(Tag tag);
/**
* Returns true if an analyzer is enabled.
*
* @param tag The analyzer's tag as an enum of script type \c
* Analyzer::Tag.
*/
bool IsEnabled(EnumVal* tag);
/**
* Registers a well-known port for an analyzer. Once registered,
* connection on that port will start with a corresponding analyzer
* assigned.
*
* @param tag The analyzer's tag as an enum of script type \c
* Analyzer::Tag.
*
* @param port The well-known port.
*
* @return True if successful.
*/
bool RegisterAnalyzerForPort(EnumVal* tag, PortVal* port);
/**
* Registers a well-known port for an analyzer. Once registered,
* connection on that port will start with a corresponding analyzer
* assigned.
*
* @param tag The analyzer's tag.
*
* @param proto The port's protocol.
*
* @param port The port's number.
*
* @return True if successful.
*/
bool RegisterAnalyzerForPort(Tag tag, TransportProto proto, uint32 port);
/**
* Unregisters a well-known port for an anlyzers.
*
* @param tag The analyzer's tag as an enum of script type \c
* Analyzer::Tag.
*
* @param port The well-known port.
*
* @return True if successful (incl. when the port wasn't actually
* registered for the analyzer).
*
*/
bool UnregisterAnalyzerForPort(EnumVal* tag, PortVal* port);
/**
* Unregisters a well-known port for an anlyzers.
*
* @param tag The analyzer's tag.
*
* @param proto The port's protocol.
*
* @param port The port's number.
*
* @param tag The analyzer's tag as an enum of script type \c
* Analyzer::Tag.
*/
bool UnregisterAnalyzerForPort(Tag tag, TransportProto proto, uint32 port);
/**
* Instantiates a new analyzer instance for a connection.
*
* @param tag The analyzer's tag.
*
* @param conn The connection the analyzer is to be associated with.
*
* @return The new analyzer instance. Note that the analyzer will not
* have been added to the connection's analyzer tree yet. Returns
* null if tag is invalid or the requested analyzer is disabled.
*/
Analyzer* InstantiateAnalyzer(Tag tag, Connection* c);
/**
* Instantiates a new analyzer instance for a connection.
*
* @param name The name of the analyzer.
*
* @param conn The connection the analyzer is to be associated with.
*
* @return The new analyzer instance. Note that the analyzer will not
* have been added to the connection's analyzer tree yet. Returns
* null if the name is not known or if the requested analyzer that is
* disabled.
*/
Analyzer* InstantiateAnalyzer(const char* name, Connection* c);
/**
* Translates an analyzer tag into corresponding analyzer name.
*
* @param tag The analyzer tag.
*
* @return The name, or an empty string if the tag is invalid.
*/
const char* GetAnalyzerName(Tag tag);
/**
* Translates an script-level analyzer tag into corresponding
* analyzer name.
*
* @param val The analyzer tag as an script-level enum value of type
* \c Analyzer::Tag.
*
* @return The name, or an empty string if the tag is invalid.
*/
const char* GetAnalyzerName(Val* val);
/**
* Translates an analyzer name into the corresponding tag.
*
* @param name The name.
*
* @return The tag. If the name does not correspond to a valid
* analyzer, the returned tag will evaluate to false.
*/
Tag GetAnalyzerTag(const char* name);
/**
* Returns the enum type that corresponds to the script-level type \c
* Analyzer::Tag.
*/
EnumType* GetTagEnumType();
/**
* Given the first packet of a connection, builds its initial
* analyzer tree.
*
* @param conn The connection to add the initial set of analyzers to.
*
* @return False if the tree cannot be build; that's usually an
* internally error.
*/
bool BuildInitialAnalyzerTree(Connection* conn);
/**
* Schedules a particular analyzer for an upcoming connection. Once
* the connection is seen, BuildInitAnalyzerTree() will add the
* specified analyzer to its tree.
*
* @param orig The connection's anticipated originator address.
* 0.0.0.0 can be used as a wildcard matching any originator.
*
* @param resp The connection's anticipated responder address (no
* wilcard).
*
* @param resp_p The connection's anticipated responder port.
*
* @param proto The connection's anticipated transport protocol.
*
* @param analyzer The analyzer to use once the connection is seen.
*
* @param timeout An interval after which to timeout the request to
* schedule this analyzer. Must be non-zero.
*/
void ScheduleAnalyzer(const IPAddr& orig, const IPAddr& resp, uint16 resp_p,
TransportProto proto, Tag analyzer, double timeout);
/**
* Schedules a particular analyzer for an upcoming connection. Once
* the connection is seen, BuildInitAnalyzerTree() will add the
* specified analyzer to its tree.
*
* @param orig The connection's anticipated originator address. 0 can
* be used as a wildcard matching any originator.
*
* @param resp The The connection's anticipated responder address (no
* wilcard).
*
* @param resp_p The connection's anticipated responder port.
*
* @param proto The connection's anticipated transport protocol.
*
* @param analyzer The name of the analyzer to use once the
* connection is seen.
*
* @param timeout An interval after which to timeout the request to
* schedule this analyzer. Must be non-zero.
*/
void ScheduleAnalyzer(const IPAddr& orig, const IPAddr& resp, uint16 resp_p,
TransportProto proto, const char* analyzer,
double timeout);
/**
* Schedules a particular analyzer for an upcoming connection. Once
* the connection is seen, BuildInitAnalyzerTree() will add the
* specified analyzer to its tree.
*
* @param orig The connection's anticipated originator address. 0 can
* be used as a wildcard matching any originator.
*
* @param resp The connection's anticipated responder address (no
* wilcard).
*
* @param resp_p The connection's anticipated responder port.
*
* @param analyzer The analyzer to use once the connection is seen as
* an enum value of script-type \c Analyzer::Tag.
*
* @param timeout An interval after which to timeout the request to
* schedule this analyzer. Must be non-zero.
*/
void ScheduleAnalyzer(const IPAddr& orig, const IPAddr& resp, PortVal* resp_p,
Val* analyzer, double timeout);
private:
typedef set<Tag> tag_set;
typedef map<string, Component*> analyzer_map_by_name;
typedef map<Tag, Component*> analyzer_map_by_tag;
typedef map<int, Component*> analyzer_map_by_val;
typedef map<uint32, tag_set*> analyzer_map_by_port;
void RegisterAnalyzerComponent(Component* component); // Takes ownership.
Component* Lookup(const string& name);
Component* Lookup(const char* name);
Component* Lookup(const Tag& tag);
Component* Lookup(EnumVal* val);
tag_set* LookupPort(PortVal* val, bool add_if_not_found);
tag_set* LookupPort(TransportProto proto, uint32 port, bool add_if_not_found);
tag_set GetScheduled(const Connection* conn);
void ExpireScheduledAnalyzers();
analyzer_map_by_port analyzers_by_port_tcp;
analyzer_map_by_port analyzers_by_port_udp;
analyzer_map_by_name analyzers_by_name;
analyzer_map_by_tag analyzers_by_tag;
analyzer_map_by_val analyzers_by_val;
Tag analyzer_backdoor;
Tag analyzer_connsize;
Tag analyzer_interconn;
Tag analyzer_stepping;
Tag analyzer_tcpstats;
EnumType* tag_enum_type;
//// Data structures to track analyzed scheduled for future connections.
// The index for a scheduled connection.
struct ConnIndex {
IPAddr orig;
IPAddr resp;
uint16 resp_p;
uint16 proto;
ConnIndex(const IPAddr& _orig, const IPAddr& _resp,
uint16 _resp_p, uint16 _proto);
ConnIndex();
bool operator<(const ConnIndex& other) const;
};
// Information associated with a scheduled connection.
struct ScheduledAnalyzer {
ConnIndex conn;
Tag analyzer;
double timeout;
struct Comparator {
bool operator() (ScheduledAnalyzer* a, ScheduledAnalyzer* b) {
return a->timeout > b->timeout;
}
};
};
typedef std::multimap<ConnIndex, ScheduledAnalyzer*> conns_map;
typedef std::priority_queue<ScheduledAnalyzer*,
vector<ScheduledAnalyzer*>,
ScheduledAnalyzer::Comparator> conns_queue;
conns_map conns;
conns_queue conns_by_timeout;
};
}
extern analyzer::Manager* analyzer_mgr;
// Macros for anayzer debug logging which include the connection id into the
// message.
#ifdef DEBUG
# define DBG_ANALYZER(conn, txt) \
DBG_LOG(DBG_ANALYZER, "%s " txt, \
fmt_conn_id(conn->OrigAddr(), ntohs(conn->OrigPort()), \
conn->RespAddr(), ntohs(conn->RespPort())));
# define DBG_ANALYZER_ARGS(conn, fmt, args...) \
DBG_LOG(DBG_ANALYZER, "%s " fmt, \
fmt_conn_id(conn->OrigAddr(), ntohs(conn->OrigPort()), \
conn->RespAddr(), ntohs(conn->RespPort())), ##args);
#else
# define DBG_ANALYZER(conn, txt)
# define DBG_ANALYZER_ARGS(conn, fmt, args...)
#endif
#endif

92
src/analyzer/Tag.cc Normal file
View file

@ -0,0 +1,92 @@
// See the file "COPYING" in the main distribution directory for copyright.
#include "Tag.h"
#include "Manager.h"
#include "../NetVar.h"
using namespace analyzer;
Tag Tag::Error;
Tag::Tag(type_t arg_type, subtype_t arg_subtype)
{
assert(arg_type > 0);
type = arg_type;
subtype = arg_subtype;
int64_t i = (int64)(type) | ((int64)subtype << 31);
EnumType* etype = analyzer_mgr->GetTagEnumType();
Ref(etype);
val = new EnumVal(i, etype);
}
Tag::Tag(EnumVal* arg_val)
{
assert(val);
val = arg_val;
Ref(val);
int64 i = val->InternalInt();
type = i & 0xffffffff;
subtype = (i >> 31) & 0xffffffff;
}
Tag::Tag(const Tag& other)
{
type = other.type;
subtype = other.subtype;
val = other.val;
if ( val )
Ref(val);
}
Tag::Tag()
{
type = 0;
subtype = 0;
val = 0;
}
Tag::~Tag()
{
Unref(val);
val = 0;
}
Tag& Tag::operator=(const Tag& other)
{
if ( this != &other )
{
type = other.type;
subtype = other.subtype;
val = other.val;
if ( val )
Ref(val);
}
return *this;
}
EnumVal* Tag::AsEnumVal() const
{
if ( ! val )
{
assert(analyzer_mgr);
assert(type == 0 && subtype == 0);
EnumType* etype = analyzer_mgr->GetTagEnumType();
Ref(etype);
val = new EnumVal(0, etype);
}
return val;
}
std::string Tag::AsString() const
{
return fmt("%" PRIu32 "/%" PRIu32, type, subtype);
}

152
src/analyzer/Tag.h Normal file
View file

@ -0,0 +1,152 @@
// See the file "COPYING" in the main distribution directory for copyright.
#ifndef ANALYZER_TAG_H
#define ANALYZER_TAG_H
#include "config.h"
#include "util.h"
class EnumVal;
namespace analyzer {
class Manager;
class Component;
/**
* Class to identify an analyzer type.
*
* Each analyzer type gets a tag consisting of a main type and subtype. The
* former is an identifier that's unique all analyzer classes. The latter is
* passed through to the analyzer instances for their use, yet not further
* interpreted by the analyzer infrastructure; it allows an analyzer to
* branch out into a set of sub-analyzers internally. Jointly, main type and
* subtype form an analyzer "tag". Each unique tag corresponds to a single
* "analyzer" from the user's perspective. At the script layer, these tags
* are mapped into enums of type \c Analyzer::Tag. Internally, the
* analyzer::Mangager maintains the mapping of tag to analyzer (and it also
* assigns them their main types), and analyzer::Component creates new
* tags.
*
* The Tag class supports all operations necessary to act as an index in a
* \c std::map.
*/
class Tag {
public:
/**
* Type for the analyzer's main type.
*/
typedef uint32 type_t;
/**
* Type for the analyzer's subtype.
*/
typedef uint32 subtype_t;
/*
* Copy constructor.
*/
Tag(const Tag& other);
/**
* Default constructor. This initializes the tag with an error value
* that will make \c operator \c bool return false.
*/
Tag();
/**
* Destructor.
*/
~Tag();
/**
* Returns the tag's main type.
*/
type_t Type() const { return type; }
/**
* Returns the tag's subtype.
*/
subtype_t Subtype() const { return subtype; }
/**
* Returns the \c Analyzer::Tag enum that corresponds to this tag.
* The returned value is \a does not have its ref-count increased.
*/
EnumVal* AsEnumVal() const;
/**
* Returns the numerical values for main and subtype inside a string
* suitable for printing. This is primarily for debugging.
*/
std::string AsString() const;
/**
* Returns false if the tag represents an error value rather than a
* legal analyzer type.
*/
operator bool() const { return *this != Tag(); }
/**
* Assignment operator.
*/
Tag& operator=(const Tag& other);
/**
* Compares two tags for equality.
*/
bool operator==(const Tag& other) const
{
return type == other.type && subtype == other.subtype;
}
/**
* Compares two tags for inequality.
*/
bool operator!=(const Tag& other) const
{
return type != other.type || subtype != other.subtype;
}
/**
* Compares two tags for less-than relationship.
*/
bool operator<(const Tag& other) const
{
return type != other.type ? type < other.type : (subtype < other.subtype);
}
static Tag Error;
protected:
friend class analyzer::Manager;
friend class analyzer::Component;
/**
* Constructor. Note
*
* @param type The main type. Note that the \a analyzer::Manager
* manages the value space internally, so noone else should assign
* any main tyoes.
*
* @param subtype The sub type, which is left to an analyzer for
* interpretation. By default it's set to zero.
*/
Tag(type_t type, subtype_t subtype = 0);
/**
* Constructor.
*
* @param val An enuam value of script type \c Analyzer::Tag.
*/
Tag(EnumVal* val);
private:
type_t type; // Main type.
subtype_t subtype; // Subtype.
mutable EnumVal* val; // Analyzer::Tag value.
};
}
#endif

45
src/analyzer/analyzer.bif Normal file
View file

@ -0,0 +1,45 @@
##! Internal functions and types used by the analyzer framework.
module Analyzer;
%%{
#include "NetVar.h"
#include "analyzer/Manager.h"
%%}
function Analyzer::__enable_analyzer%(id: Analyzer::Tag%) : bool
%{
bool result = analyzer_mgr->EnableAnalyzer(id->AsEnumVal());
return new Val(result, TYPE_BOOL);
%}
function Analyzer::__disable_analyzer%(id: Analyzer::Tag%) : bool
%{
bool result = analyzer_mgr->DisableAnalyzer(id->AsEnumVal());
return new Val(result, TYPE_BOOL);
%}
function Analyzer::__disable_all_analyzers%(%) : any
%{
analyzer_mgr->DisableAllAnalyzers();
return 0;
%}
function Analyzer::__register_for_port%(id: Analyzer::Tag, p: port%) : bool
%{
bool result = analyzer_mgr->RegisterAnalyzerForPort(id->AsEnumVal(), p);
return new Val(result, TYPE_BOOL);
%}
function Analyzer::__schedule_analyzer%(orig: addr, resp: addr, resp_p: port,
analyzer: Analyzer::Tag, tout: interval%) : bool
%{
analyzer_mgr->ScheduleAnalyzer(orig->AsAddr(), resp->AsAddr(), resp_p, analyzer->AsEnumVal(), tout);
return new Val(true, TYPE_BOOL);
%}
function __name%(atype: Analyzer::Tag%) : string
%{
return new StringVal(analyzer_mgr->GetAnalyzerName(atype));
%}

View file

@ -0,0 +1,40 @@
add_subdirectory(arp)
add_subdirectory(ayiya)
add_subdirectory(backdoor)
add_subdirectory(bittorrent)
add_subdirectory(conn-size)
add_subdirectory(dce-rpc)
add_subdirectory(dhcp)
add_subdirectory(dns)
add_subdirectory(file)
add_subdirectory(finger)
add_subdirectory(ftp)
add_subdirectory(gnutella)
add_subdirectory(gtpv1)
add_subdirectory(http)
add_subdirectory(icmp)
add_subdirectory(ident)
add_subdirectory(interconn)
add_subdirectory(irc)
add_subdirectory(login)
add_subdirectory(modbus)
add_subdirectory(mime)
add_subdirectory(ncp)
add_subdirectory(netflow)
add_subdirectory(netbios)
add_subdirectory(ntp)
add_subdirectory(pia)
add_subdirectory(pop3)
add_subdirectory(rpc)
add_subdirectory(smb)
add_subdirectory(smtp)
add_subdirectory(socks)
add_subdirectory(ssh)
add_subdirectory(ssl)
add_subdirectory(stepping-stone)
add_subdirectory(syslog)
add_subdirectory(tcp)
add_subdirectory(teredo)
add_subdirectory(udp)
add_subdirectory(zip)

View file

@ -1,10 +1,12 @@
// See the file "COPYING" in the main distribution directory for copyright.
#include "ARP.h"
#include "Event.h"
#include "Reporter.h"
#include "events.bif.h"
using namespace analyzer::arp;
ARP_Analyzer::ARP_Analyzer()
{

View file

@ -1,7 +1,7 @@
// See the file "COPYING" in the main distribution directory for copyright.
#ifndef arp_h
#define arp_h
#ifndef ANALYZER_PROTOCOL_ARP_ARP_H
#define ANALYZER_PROTOCOL_ARP_ARP_H
#include "config.h"
#include <sys/types.h>
@ -24,7 +24,9 @@
#endif
#include "NetVar.h"
#include "PacketSort.h"
namespace analyzer { namespace arp {
class ARP_Analyzer : public BroObj {
public:
@ -53,4 +55,6 @@ protected:
EventHandlerPtr arp_reply;
};
} } // namespace analyzer::*
#endif

View file

@ -0,0 +1,15 @@
# This is not an actual analyzer, but used by the core. We still
# maintain it here along with the other analyzers because conceptually
# it's also parsing a protocol just like them. The current structure
# is merely a left-over from when this code was written.
include(BroPlugin)
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
bro_plugin_begin(Bro ARP)
bro_plugin_cc(ARP.cc Plugin.cc)
bro_plugin_bif(events.bif)
bro_plugin_end()

View file

@ -0,0 +1,7 @@
#include "plugin/Plugin.h"
BRO_PLUGIN_BEGIN(Bro, ARP)
BRO_PLUGIN_DESCRIPTION("ARP Parsing Code");
BRO_PLUGIN_BIF_FILE(events);
BRO_PLUGIN_END

View file

@ -0,0 +1,63 @@
## Generated for ARP requests.
##
## See `Wikipedia <http://en.wikipedia.org/wiki/Address_Resolution_Protocol>`__
## for more information about the ARP protocol.
##
## mac_src: The request's source MAC address.
##
## mac_dst: The request's destination MAC address.
##
## SPA: The sender protocol address.
##
## SHA: The sender hardware address.
##
## TPA: The target protocol address.
##
## THA: The target hardware address.
##
## .. bro:see:: arp_reply bad_arp
event arp_request%(mac_src: string, mac_dst: string, SPA: addr, SHA: string,
TPA: addr, THA: string%);
## Generated for ARP replies.
##
## See `Wikipedia <http://en.wikipedia.org/wiki/Address_Resolution_Protocol>`__
## for more information about the ARP protocol.
##
## mac_src: The reply's source MAC address.
##
## mac_dst: The reply's destination MAC address.
##
## SPA: The sender protocol address.
##
## SHA: The sender hardware address.
##
## TPA: The target protocol address.
##
## THA: The target hardware address.
##
## .. bro:see:: arp_request bad_arp
event arp_reply%(mac_src: string, mac_dst: string, SPA: addr, SHA: string,
TPA: addr, THA: string%);
## Generated for ARP packets that Bro cannot interpret. Examples are packets
## with non-standard hardware address formats or hardware addresses that do not
## match the originator of the packet.
##
## SPA: The sender protocol address.
##
## SHA: The sender hardware address.
##
## TPA: The target protocol address.
##
## THA: The target hardware address.
##
## explanation: A short description of why the ARP packet is considered "bad".
##
## .. bro:see:: arp_reply arp_request
##
## .. todo:: Bro's current default configuration does not activate the protocol
## analyzer that generates this event; the corresponding script has not yet
## been ported to Bro 2.x. To still enable this event, one needs to
## register a port for it or add a DPD payload signature.
event bad_arp%(SPA: addr, SHA: string, TPA: addr, THA: string, explanation: string%);

View file

@ -1,7 +1,12 @@
#include "AYIYA.h"
#include "Func.h"
#include "events.bif.h"
using namespace analyzer::ayiya;
AYIYA_Analyzer::AYIYA_Analyzer(Connection* conn)
: Analyzer(AnalyzerTag::AYIYA, conn)
: Analyzer("AYIYA", conn)
{
interp = new binpac::AYIYA::AYIYA_Conn(this);
}

Some files were not shown because too many files have changed in this diff Show more