Merge remote-tracking branch 'origin/master' into topic/bernhard/input-update

This commit is contained in:
Bernhard Amann 2013-06-08 05:43:21 -07:00
commit b39bffd9aa
494 changed files with 15196 additions and 12261 deletions

45
CHANGES
View file

@ -1,4 +1,49 @@
2.1-741 | 2013-06-07 17:28:50 -0700
* Fixing typo that could cause an assertion to falsely trigger.
(Robin Sommer)
2.1-740 | 2013-06-07 16:37:32 -0700
* Fix for CMake 2.6.x. (Robin Sommer)
2.1-738 | 2013-06-07 08:38:13 -0700
* Remove invalid free on non-allocated pointer in hash function
object. Addresses #1018. (Matthias Vallentin)
2.1-736 | 2013-06-06 10:05:20 -0700
* New "magic constants" @DIR and @FILENAME that expand to the
directory path of the current script and just the script file name
without path, respectively. (Jon Siwek)
2.1-731 | 2013-06-04 21:19:08 -0700
* Reorginization of internal protocol analyzer code. We're moving
them to a modularized structure, based on a plugin model. Along
with this change comes generic plugin infrastructure that we'll
later extend to other Bro component as well. For now all plugins
are compiled in statically, but in the future we plan to also
enable dynamic loading at run time. (Robin Sommer)
* Ignoring file ids in external tests. (Robin Sommer)
2.1-675 | 2013-06-02 20:03:19 -0700
* Fix a compiler warning. (Robin Sommer)
* Allow named vector/set/table/record constructors. Addresses #983.
(Jon Siwek)
* Adding Makefile target test-all that also runs the BroControl test
suite. (Robin Sommer)
2.1-664 | 2013-05-28 21:37:46 -0700
* Dangling pointer fix. Addresses #1004. (Jon Siwek)
2.1-659 | 2013-05-24 17:24:18 -0700
* Fix broken/missing documentation. (Jon Siwek)

View file

@ -61,7 +61,10 @@ distclean:
rm -rf $(BUILD)
test:
@(cd testing && make )
@( cd testing && make )
test-all: test
test -d aux/broctl && ( cd aux/broctl && make test )
configured:
@test -d $(BUILD) || ( echo "Error: No build/ directory found. Did you run configure?" && exit 1 )

17
NEWS
View file

@ -46,6 +46,19 @@ New Functionality
have changed their signatures to work with opaques types rather
than global state as it was before.
- The scripting language now supports a constructing sets, tables,
vectors, and records by name:
type MyRecordType: record {
c: count;
s: string &optional;
};
global r: MyRecordType = record($c = 7);
type MySet: set[MyRec];
global s = MySet([$c=1], [$c=2]);
- Strings now support the subscript operator to extract individual
characters and substrings (e.g., s[4], s[1,5]). The index expression
can take up to two indices for the start and end index of the
@ -55,6 +68,10 @@ New Functionality
global foo: function(s: string, t: string &default="abc", u: count &default=0);
- Scripts can now use two new "magic constants" @DIR and @FILENAME
that expand to the directory path of the current script and just the
script file name without path, respectively. (Jon Siwek)
- The new file analysis framework moves most of the processing of file
content from script-land into the core, where it belongs. Much of
this is an internal change, the framework comes with the following

View file

@ -1 +1 @@
2.1-659
2.1-741

@ -1 +1 @@
Subproject commit f86a3169b8d49189d264cbc1a7507260cd9ff51d
Subproject commit c39bd478b9d0ecd05b1b83aa9d09a7887893977c

@ -1 +1 @@
Subproject commit cfaf4eea788bdac4ebfe9e46e3de2cd74b0bc068
Subproject commit a9942558c7d3dfd80148b8aaded64c82ade3d117

@ -1 +1 @@
Subproject commit 8955807b0f4151f5f6aca2e68d353b9b341d9f86
Subproject commit 889f9c65944ceac20ad9230efc39d33e6e1221c3

@ -1 +1 @@
Subproject commit 4d0b75afadd6a3c6507e8ca18cb1913faa93a3b0
Subproject commit cf7a1ca56f2b20f777542d912de0a9c8fdb0655d

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

2
cmake

@ -1 +1 @@
Subproject commit e1a7fd00a0a66d6831a239fe84f5fcfaa54e2c35
Subproject commit 0187b33a29d5ec824f940feff60dc5d8c2fe314f

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

@ -246,6 +246,31 @@ The Bro scripting language supports the following built-in types.
[5] = "five",
};
A table constructor (equivalent to above example) can also be used
to create a table:
.. code:: bro
global t2: table[count] of string = table(
[11] = "eleven",
[5] = "five"
);
Table constructors can also be explicitly named by a type, which is
useful for when a more complex index type could otherwise be
ambiguous:
.. code:: bro
type MyRec: record {
a: count &optional;
b: count;
};
type MyTable: table[MyRec] of string;
global t3 = MyTable([[$b=5]] = "b5", [[$b=7]] = "b7");
Accessing table elements if provided by enclosing values within square
brackets (``[]``), for example:
@ -308,6 +333,28 @@ The Bro scripting language supports the following built-in types.
The types are explicitly shown in the example above, but they could
have been left to type inference.
A set constructor (equivalent to above example) can also be used to
create a set:
.. code:: bro
global s3: set[port] = set(21/tcp, 23/tcp, 80/tcp, 443/tcp);
Set constructors can also be explicitly named by a type, which is
useful for when a more complex index type could otherwise be
ambiguous:
.. code:: bro
type MyRec: record {
a: count &optional;
b: count;
};
type MySet: set[MyRec];
global s4 = MySet([$b=1], [$b=2]);
Set membership is tested with ``in``:
.. code:: bro
@ -349,6 +396,21 @@ The Bro scripting language supports the following built-in types.
global v: vector of string = vector("one", "two", "three");
Vector constructors can also be explicitly named by a type, which
is useful for when a more complex yield type could otherwise be
ambiguous.
.. code:: bro
type MyRec: record {
a: count &optional;
b: count;
};
type MyVec: vector of MyRec;
global v2 = MyVec([$b=1], [$b=2], [$b=3]);
Adding an element to a vector involves accessing/assigning it:
.. code:: bro
@ -402,6 +464,19 @@ The Bro scripting language supports the following built-in types.
if ( r?$s )
...
Records can also be created using a constructor syntax:
.. code:: bro
global r2: MyRecordType = record($c = 7);
And the constructor can be explicitly named by type, too, which
is arguably more readable code:
.. code:: bro
global r3 = MyRecordType($c = 42);
.. bro:type:: opaque
A data type whose actual representation/implementation is

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,41 @@ 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)
add_dependencies(generate_outputs ${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

@ -3320,12 +3320,20 @@ bool HasFieldExpr::DoUnserialize(UnserialInfo* info)
return UNSERIALIZE(&not_used) && UNSERIALIZE_STR(&field_name, 0) && UNSERIALIZE(&field);
}
RecordConstructorExpr::RecordConstructorExpr(ListExpr* constructor_list)
RecordConstructorExpr::RecordConstructorExpr(ListExpr* constructor_list,
BroType* arg_type)
: UnaryExpr(EXPR_RECORD_CONSTRUCTOR, constructor_list)
{
if ( IsError() )
return;
if ( arg_type && arg_type->Tag() != TYPE_RECORD )
{
Error("bad record constructor type", arg_type);
SetError();
return;
}
// Spin through the list, which should be comprised of
// either record's or record-field-assign, and build up a
// record type to associate with this constructor.
@ -3365,7 +3373,17 @@ RecordConstructorExpr::RecordConstructorExpr(ListExpr* constructor_list)
}
}
SetType(new RecordType(record_types));
ctor_type = new RecordType(record_types);
if ( arg_type )
SetType(arg_type->Ref());
else
SetType(ctor_type->Ref());
}
RecordConstructorExpr::~RecordConstructorExpr()
{
Unref(ctor_type);
}
Val* RecordConstructorExpr::InitVal(const BroType* t, Val* aggr) const
@ -3391,7 +3409,7 @@ Val* RecordConstructorExpr::InitVal(const BroType* t, Val* aggr) const
Val* RecordConstructorExpr::Fold(Val* v) const
{
ListVal* lv = v->AsListVal();
RecordType* rt = type->AsRecordType();
RecordType* rt = ctor_type->AsRecordType();
if ( lv->Length() != rt->NumFields() )
Internal("inconsistency evaluating record constructor");
@ -3401,6 +3419,19 @@ Val* RecordConstructorExpr::Fold(Val* v) const
for ( int i = 0; i < lv->Length(); ++i )
rv->Assign(i, lv->Index(i)->Ref());
if ( ! same_type(rt, type) )
{
RecordVal* new_val = rv->CoerceTo(type->AsRecordType());
if ( new_val )
{
Unref(rv);
rv = new_val;
}
else
Internal("record constructor coercion failed");
}
return rv;
}
@ -3416,37 +3447,89 @@ IMPLEMENT_SERIAL(RecordConstructorExpr, SER_RECORD_CONSTRUCTOR_EXPR);
bool RecordConstructorExpr::DoSerialize(SerialInfo* info) const
{
DO_SERIALIZE(SER_RECORD_CONSTRUCTOR_EXPR, UnaryExpr);
SERIALIZE_OPTIONAL(ctor_type);
return true;
}
bool RecordConstructorExpr::DoUnserialize(UnserialInfo* info)
{
DO_UNSERIALIZE(UnaryExpr);
BroType* t = 0;
UNSERIALIZE_OPTIONAL(t, RecordType::Unserialize(info));
ctor_type = t->AsRecordType();
return true;
}
TableConstructorExpr::TableConstructorExpr(ListExpr* constructor_list,
attr_list* arg_attrs)
attr_list* arg_attrs, BroType* arg_type)
: UnaryExpr(EXPR_TABLE_CONSTRUCTOR, constructor_list)
{
if ( IsError() )
return;
if ( constructor_list->Exprs().length() == 0 )
SetType(new TableType(new TypeList(base_type(TYPE_ANY)), 0));
if ( arg_type )
{
if ( ! arg_type->IsTable() )
{
Error("bad table constructor type", arg_type);
SetError();
return;
}
SetType(arg_type->Ref());
}
else
{
SetType(init_type(constructor_list));
if ( constructor_list->Exprs().length() == 0 )
SetType(new TableType(new TypeList(base_type(TYPE_ANY)), 0));
else
{
SetType(init_type(constructor_list));
if ( ! type )
SetError();
if ( ! type )
SetError();
else if ( type->Tag() != TYPE_TABLE ||
type->AsTableType()->IsSet() )
SetError("values in table(...) constructor do not specify a table");
else if ( type->Tag() != TYPE_TABLE ||
type->AsTableType()->IsSet() )
SetError("values in table(...) constructor do not specify a table");
}
}
attrs = arg_attrs ? new Attributes(arg_attrs, type, false) : 0;
type_list* indices = type->AsTableType()->Indices()->Types();
const expr_list& cle = constructor_list->Exprs();
// check and promote all index expressions in ctor list
loop_over_list(cle, i)
{
if ( cle[i]->Tag() != EXPR_ASSIGN )
continue;
Expr* idx_expr = cle[i]->AsAssignExpr()->Op1();
if ( idx_expr->Tag() != EXPR_LIST )
continue;
expr_list& idx_exprs = idx_expr->AsListExpr()->Exprs();
if ( idx_exprs.length() != indices->length() )
continue;
loop_over_list(idx_exprs, j)
{
Expr* idx = idx_exprs[j];
if ( check_and_promote_expr(idx, (*indices)[j]) )
{
if ( idx != idx_exprs[j] )
idx_exprs.replace(j, idx);
continue;
}
ExprError("inconsistent types in table constructor");
}
}
}
Val* TableConstructorExpr::Eval(Frame* f) const
@ -3502,16 +3585,30 @@ bool TableConstructorExpr::DoUnserialize(UnserialInfo* info)
}
SetConstructorExpr::SetConstructorExpr(ListExpr* constructor_list,
attr_list* arg_attrs)
attr_list* arg_attrs, BroType* arg_type)
: UnaryExpr(EXPR_SET_CONSTRUCTOR, constructor_list)
{
if ( IsError() )
return;
if ( constructor_list->Exprs().length() == 0 )
SetType(new ::SetType(new TypeList(base_type(TYPE_ANY)), 0));
if ( arg_type )
{
if ( ! arg_type->IsSet() )
{
Error("bad set constructor type", arg_type);
SetError();
return;
}
SetType(arg_type->Ref());
}
else
SetType(init_type(constructor_list));
{
if ( constructor_list->Exprs().length() == 0 )
SetType(new ::SetType(new TypeList(base_type(TYPE_ANY)), 0));
else
SetType(init_type(constructor_list));
}
if ( ! type )
SetError();
@ -3520,6 +3617,37 @@ SetConstructorExpr::SetConstructorExpr(ListExpr* constructor_list,
SetError("values in set(...) constructor do not specify a set");
attrs = arg_attrs ? new Attributes(arg_attrs, type, false) : 0;
type_list* indices = type->AsTableType()->Indices()->Types();
expr_list& cle = constructor_list->Exprs();
if ( indices->length() == 1 )
{
if ( ! check_and_promote_exprs_to_type(constructor_list,
(*indices)[0]) )
ExprError("inconsistent type in set constructor");
}
else if ( indices->length() > 1 )
{
// Check/promote each expression in composite index.
loop_over_list(cle, i)
{
Expr* ce = cle[i];
ListExpr* le = ce->AsListExpr();
if ( ce->Tag() == EXPR_LIST &&
check_and_promote_exprs(le, type->AsTableType()->Indices()) )
{
if ( le != cle[i] )
cle.replace(i, le);
continue;
}
ExprError("inconsistent types in set constructor");
}
}
}
Val* SetConstructorExpr::Eval(Frame* f) const
@ -3590,31 +3718,50 @@ bool SetConstructorExpr::DoUnserialize(UnserialInfo* info)
return true;
}
VectorConstructorExpr::VectorConstructorExpr(ListExpr* constructor_list)
VectorConstructorExpr::VectorConstructorExpr(ListExpr* constructor_list,
BroType* arg_type)
: UnaryExpr(EXPR_VECTOR_CONSTRUCTOR, constructor_list)
{
if ( IsError() )
return;
if ( constructor_list->Exprs().length() == 0 )
if ( arg_type )
{
// vector().
SetType(new ::VectorType(base_type(TYPE_ANY)));
return;
}
if ( arg_type->Tag() != TYPE_VECTOR )
{
Error("bad vector constructor type", arg_type);
SetError();
return;
}
BroType* t = merge_type_list(constructor_list);
if ( t )
{
SetType(new VectorType(t->Ref()));
if ( ! check_and_promote_exprs_to_type(constructor_list, t) )
ExprError("inconsistent types in vector constructor");
Unref(t);
SetType(arg_type->Ref());
}
else
SetError();
{
if ( constructor_list->Exprs().length() == 0 )
{
// vector().
SetType(new ::VectorType(base_type(TYPE_ANY)));
return;
}
BroType* t = merge_type_list(constructor_list);
if ( t )
{
SetType(new VectorType(t->Ref()));
Unref(t);
}
else
{
SetError();
return;
}
}
if ( ! check_and_promote_exprs_to_type(constructor_list,
type->AsVectorType()->YieldType()) )
ExprError("inconsistent types in vector constructor");
}
Val* VectorConstructorExpr::Eval(Frame* f) const

View file

@ -57,6 +57,8 @@ extern const char* expr_name(BroExprTag t);
class Stmt;
class Frame;
class ListExpr;
class NameExpr;
class AssignExpr;
class CallExpr;
class EventExpr;
@ -159,12 +161,37 @@ public:
CHECK_TAG(tag, EXPR_LIST, "ExprVal::AsListExpr", expr_name)
return (const ListExpr*) this;
}
ListExpr* AsListExpr()
{
CHECK_TAG(tag, EXPR_LIST, "ExprVal::AsListExpr", expr_name)
return (ListExpr*) this;
}
const NameExpr* AsNameExpr() const
{
CHECK_TAG(tag, EXPR_NAME, "ExprVal::AsNameExpr", expr_name)
return (const NameExpr*) this;
}
NameExpr* AsNameExpr()
{
CHECK_TAG(tag, EXPR_NAME, "ExprVal::AsNameExpr", expr_name)
return (NameExpr*) this;
}
const AssignExpr* AsAssignExpr() const
{
CHECK_TAG(tag, EXPR_ASSIGN, "ExprVal::AsAssignExpr", expr_name)
return (const AssignExpr*) this;
}
AssignExpr* AsAssignExpr()
{
CHECK_TAG(tag, EXPR_ASSIGN, "ExprVal::AsAssignExpr", expr_name)
return (AssignExpr*) this;
}
void Describe(ODesc* d) const;
bool Serialize(SerialInfo* info) const;
@ -729,7 +756,8 @@ protected:
class RecordConstructorExpr : public UnaryExpr {
public:
RecordConstructorExpr(ListExpr* constructor_list);
RecordConstructorExpr(ListExpr* constructor_list, BroType* arg_type = 0);
~RecordConstructorExpr();
protected:
friend class Expr;
@ -741,11 +769,14 @@ protected:
void ExprDescribe(ODesc* d) const;
DECLARE_SERIAL(RecordConstructorExpr);
RecordType* ctor_type; // type inferred from the ctor expression list args
};
class TableConstructorExpr : public UnaryExpr {
public:
TableConstructorExpr(ListExpr* constructor_list, attr_list* attrs);
TableConstructorExpr(ListExpr* constructor_list, attr_list* attrs,
BroType* arg_type = 0);
~TableConstructorExpr() { Unref(attrs); }
Attributes* Attrs() { return attrs; }
@ -767,7 +798,8 @@ protected:
class SetConstructorExpr : public UnaryExpr {
public:
SetConstructorExpr(ListExpr* constructor_list, attr_list* attrs);
SetConstructorExpr(ListExpr* constructor_list, attr_list* attrs,
BroType* arg_type = 0);
~SetConstructorExpr() { Unref(attrs); }
Attributes* Attrs() { return attrs; }
@ -789,7 +821,7 @@ protected:
class VectorConstructorExpr : public UnaryExpr {
public:
VectorConstructorExpr(ListExpr* constructor_list);
VectorConstructorExpr(ListExpr* constructor_list, BroType* arg_type = 0);
Val* Eval(Frame* f) const;

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

@ -66,7 +66,6 @@ template<class T, int N> class H3 {
T byte_lookup[N][H3_BYTE_RANGE];
public:
H3();
~H3() { free(byte_lookup); }
T operator()(const void* data, size_t size, size_t offset = 0) const
{
const unsigned char *p = static_cast<const unsigned char*>(data);

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

@ -351,10 +351,12 @@ public:
}
char Type() { return buffer[0]; }
RemoteSerializer::PeerID Peer()
{
// Wow, is this ugly...
return ntohl(*(uint32*)(buffer + 4));
uint32 tmp;
memcpy(&tmp, buffer + 4, sizeof(tmp));
return ntohl(tmp);
}
const char* Raw() { return buffer; }

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);
}
@ -1159,12 +1162,12 @@ Connection* NetSessions::NewConn(HashKey* k, double t, const ConnID* id,
if ( ! WantConnection(src_h, dst_h, tproto, flags, flip) )
return 0;
ConnID flip_id = *id;
if ( flip )
{
// Make a guess that we're seeing the tail half of
// an analyzable connection.
ConnID flip_id = *id;
const IPAddr ta = flip_id.src_addr;
flip_id.src_addr = flip_id.dst_addr;
flip_id.dst_addr = ta;
@ -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

@ -217,6 +217,11 @@ public:
return tag == TYPE_TABLE && (YieldType() == 0);
}
int IsTable() const
{
return tag == TYPE_TABLE && (YieldType() != 0);
}
BroType* Ref() { ::Ref(this); return this; }
virtual void Describe(ODesc* d) const;

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

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