Merge remote-tracking branch 'origin/master' into topic/vladg/file-analysis-exe-analyzer

Conflicts:
	src/types.bif
This commit is contained in:
Vlad Grigorescu 2015-02-19 16:59:52 -06:00
commit b90c8cb8ec
709 changed files with 119094 additions and 88762 deletions

3
.gitmodules vendored
View file

@ -19,3 +19,6 @@
[submodule "src/3rdparty"]
path = src/3rdparty
url = git://git.bro.org/bro-3rdparty
[submodule "aux/plugins"]
path = aux/plugins
url = git://git.bro.org/bro-plugins

674
CHANGES
View file

@ -1,4 +1,678 @@
2.3-397 | 2015-01-27 10:13:10 -0600
* Handle guess_lexer exceptions in pygments reST directive (Jon Siwek)
2.3-396 | 2015-01-23 10:49:15 -0600
* DNP3: fix reachable assertion and buffer over-read/overflow.
CVE number pending. (Travis Emmert, Jon Siwek)
* Update binpac: Fix potential out-of-bounds memory reads in generated
code. CVE-2014-9586. (John Villamil and Chris Rohlf - Yahoo
Paranoids, Jon Siwek)
* Fixing (harmless) Coverity warning. (Robin Sommer)
2.3-392 | 2015-01-15 09:44:15 -0800
* Small changes to EC curve names in a newer draft. (Johanna Amann)
2.3-390 | 2015-01-14 13:27:34 -0800
* Updating MySQL analyses. (Vlad Grigorescu)
- Use a boolean success instead of a result string.
- Change the affected_rows response detail string to a "rows" count.
- Fix the state tracking to log incomplete command.
* Extend DNP3 to support communication over UDP. (Hui Lin)
* Fix a bug in DNP3 determining the length of an object in some
cases. (Hui Lin)
2.3-376 | 2015-01-12 09:38:10 -0600
* Improve documentation for connection_established event. (Jon Siwek)
2.3-375 | 2015-01-08 13:10:09 -0600
* Increase minimum required CMake version to 2.8. (Jon Siwek)
2.3-374 | 2015-01-07 10:03:17 -0600
* Improve documentation of the Intelligence Framework. (Daniel Thayer)
2.3-371 | 2015-01-06 09:58:09 -0600
* Update/improve file mime type identification. (Seth Hall)
- Change to the default BOF buffer size to 3000 (was 1024).
- Reorganized MS signatures into a separate file.
- Remove all of the x-c detections. Nearly all false positives.
- Improve TAR detections, removing old, back up TAR detections.
- Remove one of the x-elc detections that was too loose
and caused many false positives.
- Improved lots of the signatures and added new ones. (Seth Hall)
* Add support for file reassembly in the file analysis framework
(Seth Hall, Jon Siwek).
- The reassembly behavior can be modified per-file by enabling or
disabling the reassembler and/or modifying the size of the
reassembly buffer.
- Changed the file extraction analyzer to use stream-wise input to
avoid issues with the chunk-wise approach not immediately
triggering the file_new event due to mime-type detection delay.
Before, early chunks frequently ended up lost. Extraction also
will now explicitly NUL-fill gaps in the file instead of
implicitly relying on pwrite to do it.
2.3-349 | 2015-01-05 15:21:13 -0600
* Fix race condition in unified2 file analyzer startup. (Jon siwek)
2.3-348 | 2014-12-31 09:19:34 -0800
* Changing Makefile's test-all to run test-all for broctl, which now
executes trace-summary tests as well. (Robin Sommer)
2.3-345 | 2014-12-31 09:06:15 -0800
* Correct a typo in the Notice framework doc. (Daniel Thayer)
2.3-343 | 2014-12-12 12:43:46 -0800
* Fix PIA packet replay to deliver copy of IP header. This prevented
one from writing a packet-wise analyzer that needs access to IP
headers and can be attached to a connection via signature match.
Addresses BIT-1298 (Jon Siwek)
2.3-338 | 2014-12-08 13:56:19 -0800
* Add man page for Bro. (Raúl Benencia)
* Updating doc baselines. (Robin Sommer)
2.3-334 | 2014-12-03 14:22:07 -0800
* Fix compound assignment to require proper L-value. Addresses
BIT-1295. (Jon Siwek)
2.3-332 | 2014-12-03 14:14:11 -0800
* Make using local IDs in @if directives an error. Addresses
BIT-1296. (Jon Siwek)
2.3-330 | 2014-12-03 14:10:39 -0800
* Fix some "make doc" warnings and update some doc tests. (Daniel
Thayer)
2.3-328 | 2014-12-02 08:13:10 -0500
* Update windows-version-detection.bro to add support for
Windows 10. (Michal Purzynski)
2.3-326 | 2014-12-01 12:10:27 -0600
* BIFScanner: fix invalid characters in generated preprocessor macros.
(Hilko Bengen)
* BIT-1294: fix exec.bro from mutating Input::end_of_data event
parameters. (Johanna Amann)
* Add/invoke "distclean" for testing directories. (Raúl Benencia)
* Delete prebuilt python bytecode files from git. (Jon Siwek)
* Add Windows detection based on CryptoAPI HTTP traffic as a software
framework policy script. (Vlad Grigorescu)
2.3-316 | 2014-11-25 17:35:06 -0800
* Make the SSL analyzer skip further processing once encountering
situations which are very probably non-recoverable. (Johanna
Amann)
2.3-313 | 2014-11-25 14:27:07 -0800
* Make SSL v2 protocol tests more strict. In its former state they
triggered on http traffic over port 443 sometimes. Found by Michał
Purzyński. (Johanna Amann)
* Fix X509 analyzer to correctly return ECDSA as the key_type for
ECDSA certs. Bug found by Michał Purzyński. (Johanna Amann)
2.3-310 | 2014-11-19 10:56:59 -0600
* Disable verbose bison output. (Jon Siwek)
2.3-309 | 2014-11-18 12:17:53 -0800
* New decompose_uri() function in base/utils/urls that splits a URI
into its pieces. (Anthony Kasza).
2.3-305 | 2014-11-18 11:09:04 -0800
* Improve coercion of &default expressions. Addresses BIT-1288. (Jon
Siwek)
2.3-303 | 2014-11-18 10:53:04 -0800
* For DH key exchanges, use p as the parameter for weak key
exchanges. (Johanna Amann)
2.3-301 | 2014-11-11 13:47:27 -0800
* Add builtin function enum_to_int() that converts an enum into a
integer. (Christian Struck)
2.3-297 | 2014-11-11 11:50:47 -0800
* Removing method from SSL analyzer that's no longer used. (Robin
Sommer)
2.3-296 | 2014-11-11 11:42:38 -0800
* A new analyzer parsing the MySQL wire protocol. Activity gets
logged into mysql.log. Supports protocol versions 9 and 10. (Vlad
Grigorescu)
2.3-280 | 2014-11-05 09:46:33 -0500
* Add Windows detection based on CryptoAPI HTTP traffic as a
software framework policy script. (Vlad Grigorescu)
2.3-278 | 2014-11-03 18:55:18 -0800
* Add new curves from draft-ietf-tls-negotiated-ff-dhe to SSL
analysis. (Johanna Amann)
2.3-274 | 2014-10-31 17:45:25 -0700
* Adding call to new binpac::init() function. (Robin Sommer)
2.3-272 | 2014-10-31 16:29:42 -0700
* Fix segfault if when statement's RHS is unitialized. Addresses
BIT-1176. (Jon Siwek)
* Fix checking vector indices via "in". Addresses BIT-1280. (Jon
Siwek)
2.3-268 | 2014-10-31 12:12:22 -0500
* BIT-1283: Fix crash when using &encrypt. (Jon Siwek)
2.3-267 | 2014-10-31 10:35:02 -0500
* BIT-1284: Allow arbitrary when statement timeout expressions
(Jon Siwek)
2.3-266 | 2014-10-31 09:21:28 -0500
* BIT-1166: Add configure options to fine tune local state dirs used
by BroControl. (Jon Siwek)
2.3-264 | 2014-10-30 13:25:57 -0500
* Fix some minor Coverity Scan complaints. (Jon Siwek)
2.3-263 | 2014-10-28 15:09:10 -0500
* Fix checking of fwrite return values (Johanna Amann)
2.3-260 | 2014-10-27 12:54:17 -0500
* Fix errors/warnings when compiling with -std=c++11 (Jon Siwek)
2.3-259 | 2014-10-27 10:04:04 -0500
* Documentation fixes. (Vicente Jimenez Aguilar and Stefano Azzalini)
2.3-256 | 2014-10-24 15:33:45 -0700
* Adding missing test baseline. (Robin Sommer)
2.3-255 | 2014-10-24 13:39:44 -0700
* Fixing unstable active-http test. (Robin Sommer)
2.3-254 | 2014-10-24 11:40:51 -0700
* Fix active-http.bro to deal reliably with empty server responses,
which will now be passed back as empty files. (Christian Struck)
2.3-248 | 2014-10-23 14:20:59 -0700
* Change order in which a plugin's scripts are loaded at startup.
(Robin Sommer)
2.3-247 | 2014-10-21 13:42:38 -0700
* Updates to the SSL analyzer. (Johanna Amann)
* Mark everything below 2048 bit as a weak key.
* Fix notice suppression.
* Add information about server-chosen protocol to ssl.log, if
provided by application_layer_next_protocol.
* Add boolean flag to ssl.log signaling if a session was
resumed. Remove the (usually not really that useful) session
ID that the client sent.
2.3-240 | 2014-10-21 13:36:33 -0700
* Fix Coverity-reported issues in DNP3 analyzer. (Seth Hall)
2.3-238 | 2014-10-16 06:51:49 -0700
* Fix multipart HTTP/MIME entity file analysis so that (1) singular
CR or LF characters in multipart body content are no longer
converted to a full CRLF (thus corrupting the file) and (2) it
also no longer considers the CRLF before the multipart boundary as
part of the content. Addresses BIT-1235. (Jon Siwek)
2.3-235 | 2014-10-15 10:20:47 -0500
* BIT-1273: Add error message for bad enum declaration syntax.
(Jon Siwek)
2.3-234 | 2014-10-14 14:42:09 -0500
* Documentation fixes. (Steve Smoot)
2.3-233 | 2014-10-09 16:00:27 -0500
* Change find-bro-logs unit test to follow symlinks. (Jon Siwek)
* Add error checks and messages to a test script (Daniel Thayer)
2.3-230 | 2014-10-08 08:15:17 -0700
* Further baseline normalization for plugin test portability. (Robin
Sommer)
2.3-229 | 2014-10-07 20:18:11 -0700
* Fix for test portability. (Robin Sommer)
2.3-228 | 2014-10-07 15:32:37 -0700
* Include plugin unit tests into the top-level btest configuration. (Robin Sommer)
* Switching the prefix separator for packet source/dumper plugins
once more, now to "::". Addresses BIT-1267. (Robin Sommer)
* Fix for allowing a packet source/dumper plugin to support multiple
prefixes with a colon. (Robin Sommer)
2.3-225 | 2014-10-07 15:13:35 -0700
* Updating plugin documentation. (Robin Sommer)
2.3-224 | 2014-10-07 14:32:17 -0700
* Improved the log file reference documentation. (Jeannette Dopheide
and Daniel Thayer)
* Improves shockwave flash file signatures. (Seth Hall)
- This moves the signatures out of the libmagic imported signatures
and into our own general.sig.
- Expand the detection to LZMA compressed flash files.
* Add new script language reference documentation on operators,
statements, and directives. Also improved the documentation on
types and attributes by splitting them into two docs, and
providing more examples and adding a chart on the top of each page
with links to each type and attribute for easier access to the
information. (Daniel Thayer)
* Split the types and attributes reference doc into two docs.
(Daniel Thayer)
2.3-208 | 2014-10-03 09:38:52 -0500
* BIT-1268: Fix uninitialized router_list argument in
dhcp_offer/dhcp_ack. (Jon Siwek)
2.3-207 | 2014-10-02 16:39:17 -0700
* Updating plugin docs. (Robin Sommer)
* Fix packet sources being treated as idle when a packet is
available. Addresses BIT-1266. (Jon Siwek)
* Fix regression causing the main loop to spin more frequently.
Addresses BIT-1266. (Jon Siwek)
2.3-203 | 2014-09-29 20:06:54 -0700
* Fix to use length parameter in DNP3 time conversion correctly now.
(Robin Sommer)
2.3-202 | 2014-09-29 17:05:18 -0700
* New SSL extension type from IANA and a few other SSL const
changes. (Johanna Amann)
* Make unexpected pipe errors fatal as precaution. Addresses
BIT-1260. (Jon Siwek)
* Adding a function for DNP3 to translate the timestamp format. (Hui
Lin)
2.3-197 | 2014-09-29 10:42:01 -0500
* Fix possible seg fault in TCP reassembler. (Jon Siwek)
2.3-196 | 2014-09-25 17:53:27 -0700
* Changing prefix for packet sources/dumper from ':' to '%'.
Addresses BIT-1249. (Robin Sommer)
* Remove timeouts from remote communication loop. The select() now
blocks until there's work to do instead of relying on a small
timeout value which can cause unproductive use of cpu cycles. (Jon
Siwek)
* Improve error message when failing to activate a plugin. Also fix
a unit test helper script that checks plugin availability. (Jon
Siwek)
2.3-183 | 2014-09-24 10:08:04 -0500
* Add a "node" field to Intel::Seen struture and intel.log to
indicate which node discovered a hit on an intel item. (Seth Hall)
* BIT-1261: Fixes to plugin quick start doc. (Jon Siwek)
2.3-180 | 2014-09-22 12:52:41 -0500
* BIT-1259: Fix issue w/ duplicate TCP reassembly deliveries.
(Jon Siwek)
2.3-178 | 2014-09-18 14:29:46 -0500
* BIT-1256: Fix file analysis events from coming after bro_done().
(Jon Siwek)
2.3-177 | 2014-09-17 09:41:27 -0500
* Documentation fixes. (Chris Mavrakis)
2.3-174 | 2014-09-17 09:37:09 -0500
* Fixed some "make doc" warnings caused by reST formatting
(Daniel Thayer).
2.3-172 | 2014-09-15 13:38:52 -0500
* Remove unneeded allocations for HTTP messages. (Jon Siwek)
2.3-171 | 2014-09-15 11:14:57 -0500
* Fix a compile error on systems without pcap-int.h. (Jon Siwek)
2.3-170 | 2014-09-12 19:28:01 -0700
* Fix incorrect data delivery skips after gap in HTTP Content-Range.
Addresses BIT-1247. (Jon Siwek)
* Fix file analysis placement of data after gap in HTTP
Content-Range. Addresses BIT-1248. (Jon Siwek)
* Fix issue w/ TCP reassembler not delivering some segments.
Addresses BIT-1246. (Jon Siwek)
* Fix MIME entity file data/gap ordering and raise http_entity_data
in line with data arrival. Addresses BIT-1240. (Jon Siwek)
* Implement file ID caching for MIME_Mail. (Jon Siwek)
* Fix a compile error. (Jon Siwek)
2.3-161 | 2014-09-09 12:35:38 -0500
* Bugfixes and test updates/additions. (Robin Sommer)
* Interface tweaks and docs for PktSrc/PktDumper. (Robin Sommer)
* Moving PCAP-related bifs to iosource/pcap.bif. (Robin Sommer)
* Moving some of the BPF filtering code into base class.
This will allow packet sources that don't support BPF natively to
emulate the filtering via libpcap. (Robin Sommer)
* Removing FlowSrc. (Robin Sommer)
* Removing remaining pieces of the 2ndary path, and left-over
files of packet sorter. (Robin Sommer)
* A bunch of infrastructure work to move IOSource, IOSourceRegistry
(now iosource::Manager) and PktSrc/PktDumper code into iosource/,
and over to a plugin structure. (Robin Sommer)
2.3-137 | 2014-09-08 19:01:13 -0500
* Fix Broxygen's rendering of opaque types. (Jon Siwek)
2.3-136 | 2014-09-07 20:50:46 -0700
* Change more http links to https. (Johanna Amann)
2.3-134 | 2014-09-04 16:16:36 -0700
* Fixed a number of issues with OCSP reply validation. Addresses
BIT-1212. (Johanna Amann)
* Fix null pointer dereference in OCSP verification code in case no
certificate is sent as part as the ocsp reply. Addresses BIT-1212.
(Johanna Amann)
2.3-131 | 2014-09-04 16:10:32 -0700
* Make links in documentation templates protocol relative. (Johanna
Amann)
2.3-129 | 2014-09-02 17:21:21 -0700
* Simplify a conditional with equivalent branches. (Jon Siwek)
* Change EDNS parsing code to use rdlength more cautiously. (Jon
Siwek)
* Fix a memory leak when bind() fails due to EADDRINUSE. (Jon Siwek)
* Fix possible buffer over-read in DNS TSIG parsing. (Jon Siwek)
2.3-124 | 2014-08-26 09:24:19 -0500
* Better documentation for sub_bytes (Jimmy Jones)
* BIT-1234: Fix build on systems that already have ntohll/htonll
(Jon Siwek)
2.3-121 | 2014-08-22 15:22:15 -0700
* Detect functions that try to bind variables from an outer scope
and raise an error saying that's not supported. Addresses
BIT-1233. (Jon Siwek)
2.3-116 | 2014-08-21 16:04:13 -0500
* Adding plugin testing to Makefile's test-all. (Robin Sommer)
* Converting log writers and input readers to plugins.
DataSeries and ElasticSearch plugins have moved to the new
bro-plugins repository, which is now a git submodule in the
aux/plugins directory. (Robin Sommer)
2.3-98 | 2014-08-19 11:03:46 -0500
* Silence some doc-related warnings when using `bro -e`.
Closes BIT-1232. (Jon Siwek)
* Fix possible null ptr derefs reported by Coverity. (Jon Siwek)
2.3-96 | 2014-08-01 14:35:01 -0700
* Small change to DHCP documentation. In server->client messages the
host name may differ from the one requested by the client.
(Johanna Amann)
* Split DHCP log writing from record creation. This allows users to
customize dhcp.log by changing the record in their own dhcp_ack
event. (Johanna Amann)
* Update PATH so that documentation btests can find bro-cut. (Daniel
Thayer)
* Remove gawk from list of optional packages in documentation.
(Daniel Thayer)
* Fix for redefining built-in constants. (Robin Sommer)
2.3-86 | 2014-07-31 14:19:58 -0700
* Fix for redefining built-in constants. (Robin Sommer)
* Adding missing check that a plugin's API version matches what Bro
defines. (Robin Sommer)
* Adding NEWS entry for plugins. (Robin Sommer)
2.3-83 | 2014-07-30 16:26:11 -0500
* Minor adjustments to plugin code/docs. (Jon Siwek)
* Dynamic plugin support. (Rpbin Sommer)
Bro now supports extending core functionality, like protocol and
file analysis, dynamically with external plugins in the form of
shared libraries. See doc/devel/plugins.rst for an overview of the
main functionality. Changes coming with this:
- Replacing the old Plugin macro magic with a new API.
- The plugin API changed to generally use std::strings instead
of const char*.
- There are a number of invocations of PLUGIN_HOOK_
{VOID,WITH_RESULT} across the code base, which allow plugins
to hook into the processing at those locations.
- A few new accessor methods to various classes to allow
plugins to get to that information.
- network_time cannot be just assigned to anymore, there's now
function net_update_time() for that.
- Redoing how builtin variables are initialized, so that it
works for plugins as well. No more init_net_var(), but
instead bifcl-generated code that registers them.
- Various changes for adjusting to the now dynamic generation
of analyzer instances.
- same_type() gets an optional extra argument allowing record type
comparision to ignore if field names don't match. (Robin Sommer)
- Further unify file analysis API with the protocol analyzer API
(assigning IDs to analyzers; adding Init()/Done() methods;
adding subtypes). (Robin Sommer)
- A new command line option -Q that prints some basic execution
time stats. (Robin Sommer)
- Add support to the file analysis for activating analyzers by
MIME type. (Robin Sommer)
- File::register_for_mime_type(tag: Analyzer::Tag, mt:
string): Associates a file analyzer with a MIME type.
- File::add_analyzers_for_mime_type(f: fa_file, mtype:
string): Activates all analyzers registered for a MIME
type for the file.
- The default file_new() handler calls
File::add_analyzers_for_mime_type() with the file's MIME
type.
2.3-20 | 2014-07-22 17:41:02 -0700
* Updating submodule(s).
2.3-19 | 2014-07-22 17:29:19 -0700
* Implement bytestring_to_coils() in Modbus analyzer so that coils
gets passed to the corresponding events. (Hui Lin)
* Add length field to ModbusHeaders. (Hui Lin)
2.3-12 | 2014-07-10 19:17:37 -0500
* Include yield of vectors in Broxygen's type descriptions.
Addresses BIT-1217. (Jon Siwek)
2.3-11 | 2014-07-10 14:49:27 -0700
* Fixing DataSeries output. It was using a now illegal value as its
default compression level. (Robin Sommer)
2.3-7 | 2014-06-26 17:35:18 -0700
* Extending "make test-all" to include aux/bro-aux. (Robin Sommer)
2.3-6 | 2014-06-26 17:24:10 -0700
* DataSeries compilation issue fixed. (mlaterman)
* Fix a reference counting bug in ListVal ctor. (Jon Siwek)
2.3-3 | 2014-06-26 15:41:04 -0500
* Support tilde expansion when Bro tries to find its own path. (Jon
Siwek)
2.3-2 | 2014-06-23 16:54:15 -0500
* Remove references to line numbers in tutorial text. (Daniel Thayer)
2.3 | 2014-06-16 09:48:25 -0500
* Release 2.3.
2.3-beta-33 | 2014-06-12 11:59:28 -0500
* Documentation improvements/fixes. (Daniel Thayer)
2.3-beta-24 | 2014-06-11 15:35:31 -0500
* Fix SMTP state tracking when server response is missing.
(Robin Sommer)
2.3-beta-22 | 2014-06-11 12:31:38 -0500
* Fix doc/test that broke due to a Bro script change. (Jon Siwek)
* Remove unused --with-libmagic configure option. (Jon Siwek)
2.3-beta-20 | 2014-06-10 18:16:51 -0700
* Fix use-after-free in some cases of reassigning a table index.
Addresses BIT-1202. (Jon Siwek)
2.3-beta-18 | 2014-06-06 13:11:50 -0700
* Add two more SSL events, one triggered for each handshake message

View file

@ -1,5 +1,9 @@
project(Bro C CXX)
cmake_minimum_required(VERSION 2.6.3 FATAL_ERROR)
# When changing the minimum version here, also adapt
# aux/bro-aux/plugin-support/skeleton/CMakeLists.txt
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
include(cmake/CommonCMakeConfig.cmake)
########################################################################
@ -11,17 +15,28 @@ if (NOT BRO_SCRIPT_INSTALL_PATH)
set(BRO_SCRIPT_INSTALL_PATH ${BRO_ROOT_DIR}/share/bro)
endif ()
if (NOT BRO_MAN_INSTALL_PATH)
# set the default Bro man page installation path (user did not specify one)
set(BRO_MAN_INSTALL_PATH ${BRO_ROOT_DIR}/share/man)
endif ()
# sanitize the Bro script install directory into an absolute path
# (CMake is confused by ~ as a representation of home directory)
get_filename_component(BRO_SCRIPT_INSTALL_PATH ${BRO_SCRIPT_INSTALL_PATH}
ABSOLUTE)
set(BRO_PLUGIN_INSTALL_PATH ${BRO_ROOT_DIR}/lib/bro/plugins CACHE STRING "Installation path for plugins" FORCE)
configure_file(bro-path-dev.in ${CMAKE_CURRENT_BINARY_DIR}/bro-path-dev)
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/bro-path-dev.sh
"export BROPATH=`${CMAKE_CURRENT_BINARY_DIR}/bro-path-dev`\n"
"export BRO_PLUGIN_PATH=\"${CMAKE_CURRENT_BINARY_DIR}/src:${BRO_PLUGIN_INSTALL_PATH}\"\n"
"export PATH=\"${CMAKE_CURRENT_BINARY_DIR}/src\":$PATH\n")
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/bro-path-dev.csh
"setenv BROPATH `${CMAKE_CURRENT_BINARY_DIR}/bro-path-dev`\n"
"setenv BRO_PLUGIN_PATH \"${CMAKE_CURRENT_BINARY_DIR}/src:${BRO_PLUGIN_INSTALL_PATH}\"\n"
"setenv PATH \"${CMAKE_CURRENT_BINARY_DIR}/src\":$PATH\n")
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" VERSION LIMIT_COUNT 1)
@ -117,33 +132,6 @@ if (GOOGLEPERFTOOLS_FOUND)
endif ()
endif ()
set(USE_DATASERIES false)
find_package(Lintel)
find_package(DataSeries)
find_package(LibXML2)
if (NOT DISABLE_DATASERIES AND
LINTEL_FOUND AND DATASERIES_FOUND AND LIBXML2_FOUND)
set(USE_DATASERIES true)
include_directories(BEFORE ${Lintel_INCLUDE_DIR})
include_directories(BEFORE ${DataSeries_INCLUDE_DIR})
include_directories(BEFORE ${LibXML2_INCLUDE_DIR})
list(APPEND OPTLIBS ${Lintel_LIBRARIES})
list(APPEND OPTLIBS ${DataSeries_LIBRARIES})
list(APPEND OPTLIBS ${LibXML2_LIBRARIES})
endif()
set(USE_ELASTICSEARCH false)
set(USE_CURL false)
find_package(LibCURL)
if (NOT DISABLE_ELASTICSEARCH AND LIBCURL_FOUND)
set(USE_ELASTICSEARCH true)
set(USE_CURL true)
include_directories(BEFORE ${LibCURL_INCLUDE_DIR})
list(APPEND OPTLIBS ${LibCURL_LIBRARIES})
endif()
if (ENABLE_PERFTOOLS_DEBUG OR ENABLE_PERFTOOLS)
# Just a no op to prevent CMake from complaining about manually-specified
# ENABLE_PERFTOOLS_DEBUG or ENABLE_PERFTOOLS not being used if google
@ -165,6 +153,8 @@ set(brodeps
include(TestBigEndian)
test_big_endian(WORDS_BIGENDIAN)
include(CheckSymbolExists)
check_symbol_exists(htonll arpa/inet.h HAVE_BYTEORDER_64)
include(OSSpecific)
include(CheckTypes)
@ -174,6 +164,10 @@ include(MiscTests)
include(PCAPTests)
include(OpenSSLTests)
include(CheckNameserCompat)
include(GetArchitecture)
# Tell the plugin code that we're building as part of the main tree.
set(BRO_PLUGIN_INTERNAL_BUILD true CACHE INTERNAL "" FORCE)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in
${CMAKE_CURRENT_BINARY_DIR}/config.h)
@ -186,6 +180,7 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})
add_subdirectory(src)
add_subdirectory(scripts)
add_subdirectory(doc)
add_subdirectory(man)
include(CheckOptionalBuildSources)
@ -238,10 +233,6 @@ message(
"\n tcmalloc: ${USE_PERFTOOLS_TCMALLOC}"
"\n debugging: ${USE_PERFTOOLS_DEBUG}"
"\njemalloc: ${ENABLE_JEMALLOC}"
"\ncURL: ${USE_CURL}"
"\n"
"\nDataSeries: ${USE_DATASERIES}"
"\nElasticSearch: ${USE_ELASTICSEARCH}"
"\n"
"\n================================================================\n"
)

View file

@ -48,13 +48,16 @@ bindist:
distclean:
rm -rf $(BUILD)
$(MAKE) -C testing $@
test:
@( cd testing && make )
test-all: test
test -d aux/broctl && ( cd aux/broctl && make test )
test -d aux/broctl && ( cd aux/broctl && make test-all )
test -d aux/btest && ( cd aux/btest && make test )
test -d aux/bro-aux && ( cd aux/bro-aux && make test )
test -d aux/plugins && ( cd aux/plugins && make test-all )
configured:
@test -d $(BUILD) || ( echo "Error: No build/ directory found. Did you run configure?" && exit 1 )

49
NEWS
View file

@ -4,6 +4,55 @@ release. For an exhaustive list of changes, see the ``CHANGES`` file
(note that submodules, such as BroControl and Broccoli, come with
their own ``CHANGES``.)
Bro 2.4 (in progress)
=====================
Dependencies
------------
New Functionality
-----------------
- Bro now has support for external plugins that can extend its core
functionality, like protocol/file analysis, via shared libraries.
Plugins can be developed and distributed externally, and will be
pulled in dynamically at startup. Currently, a plugin can provide
custom protocol analyzers, file analyzers, log writers[TODO], input
readers[TODO], packet sources[TODO], and new built-in functions. A
plugin can furthermore hook into Bro's processing a number of places
to add custom logic.
See https://www.bro.org/sphinx-git/devel/plugins.html for more
information on writing plugins.
- Bro now has supoprt for the MySQL wire protocol. Activity gets
logged into mysql.log.
- Bro's file analysis now supports reassembly of files that are not
transferred/seen sequentially.
Changed Functionality
---------------------
- bro-cut has been rewritten in C, and is hence much faster.
- File analysis
* Removed ``fa_file`` record's ``mime_type`` and ``mime_types``
fields. The events ``file_mime_type`` and ``file_mime_types``
have been added which contain the same information. The
``mime_type`` field of ``Files::Info`` also still has this info.
* Removed ``Files::add_analyzers_for_mime_type`` function.
* Removed ``offset`` parameter of the ``file_extraction_limit``
event. Since file extraction now internally depends on file
reassembly for non-sequential files, "offset" can be obtained
with other information already available -- adding together
``seen_bytes`` and ``missed_bytes`` fields of the ``fa_file``
record gives the how many bytes have been written so far (i.e.
the "offset").
Bro 2.3
=======

View file

@ -1 +1 @@
2.3-beta-18
2.3-397

@ -1 +1 @@
Subproject commit ec1e052afd5a8cd3d1d2cbb28fcd688018e379a5
Subproject commit 8d56b507b8b804fa83f6637f3b1f198e696cd603

@ -1 +1 @@
Subproject commit 5721df4f5f6fa84de6257cca6582a28e45831786
Subproject commit 0b713c027d3efaaca50e5df995c02656175573cd

@ -1 +1 @@
Subproject commit c2f5dd2cb7876158fdf9721aebd22567db840db1
Subproject commit d43cc790e5b8709b5e032e52ad0e00936494739b

@ -1 +1 @@
Subproject commit 1e55bff2df49fe7dc3bd54e21050b39530eeb714
Subproject commit 8c9b87bc73e1ddaa304e3d89028c1e7b95d37a91

@ -1 +1 @@
Subproject commit 4da1bd24038d4977e655f2b210f34e37f0b73b78
Subproject commit 93d4989ed1537e4d143cf09d44077159f869a4b2

1
aux/plugins Submodule

@ -0,0 +1 @@
Subproject commit ad600b5bdcd56a2723e323c0f2c8e1708956ca4f

2
cmake

@ -1 +1 @@
Subproject commit 0f301aa08a970150195a2ea5b3ed43d2d98b35b3
Subproject commit 1316c07f7059647b6c4a496ea36e4b83bb5d8f0f

View file

@ -129,6 +129,9 @@
/* whether words are stored with the most significant byte first */
#cmakedefine WORDS_BIGENDIAN
/* whether htonll/ntohll is defined in <arpa/inet.h> */
#cmakedefine HAVE_BYTEORDER_64
/* ultrix can't hack const */
#cmakedefine NEED_ULTRIX_CONST_HACK
#ifdef NEED_ULTRIX_CONST_HACK
@ -209,3 +212,14 @@
/* Common IPv6 extension structure */
#cmakedefine HAVE_IP6_EXT
/* String with host architecture (e.g., "linux-x86_64") */
#define HOST_ARCHITECTURE "@HOST_ARCHITECTURE@"
/* String with extension of dynamic libraries (e.g., ".so") */
#define DYNAMIC_PLUGIN_SUFFIX "@CMAKE_SHARED_MODULE_SUFFIX@"
/* True if we're building outside of the main Bro source code tree. */
#ifndef BRO_PLUGIN_INTERNAL_BUILD
#define BRO_PLUGIN_INTERNAL_BUILD @BRO_PLUGIN_INTERNAL_BUILD@
#endif

41
configure vendored
View file

@ -24,6 +24,13 @@ Usage: $0 [OPTION]... [VAR=VALUE]...
--prefix=PREFIX installation directory [/usr/local/bro]
--scriptdir=PATH root installation directory for Bro scripts
[PREFIX/share/bro]
--localstatedir=PATH when using BroControl, path to store log files
and run-time data (within log/ and spool/ subdirs)
[PREFIX]
--spooldir=PATH when using BroControl, path to store run-time data
[PREFIX/spool]
--logdir=PATH when using BroControl, path to store log file
[PREFIX/logs]
--conf-files-dir=PATH config files installation directory [PREFIX/etc]
Optional Features:
@ -39,8 +46,6 @@ Usage: $0 [OPTION]... [VAR=VALUE]...
--disable-auxtools don't build or install auxiliary tools
--disable-perftools don't try to build with Google Perftools
--disable-python don't try to build python bindings for broccoli
--disable-dataseries don't use the optional DataSeries log writer
--disable-elasticsearch don't use the optional ElasticSearch log writer
Required Packages in Non-Standard Locations:
--with-openssl=PATH path to OpenSSL install root
@ -50,7 +55,6 @@ Usage: $0 [OPTION]... [VAR=VALUE]...
--with-flex=PATH path to flex executable
--with-bison=PATH path to bison executable
--with-perl=PATH path to perl executable
--with-libmagic=PATH path to libmagic install root
Optional Packages in Non-Standard Locations:
--with-geoip=PATH path to the libGeoIP install root
@ -63,9 +67,6 @@ Usage: $0 [OPTION]... [VAR=VALUE]...
--with-ruby-lib=PATH path to ruby library
--with-ruby-inc=PATH path to ruby headers
--with-swig=PATH path to SWIG executable
--with-dataseries=PATH path to DataSeries and Lintel libraries
--with-xml2=PATH path to libxml2 installation (for DataSeries)
--with-curl=PATH path to libcurl install root (for ElasticSearch)
Packaging Options (for developers):
--binary-package toggle special logic for binary packaging
@ -150,6 +151,15 @@ while [ $# -ne 0 ]; do
append_cache_entry BRO_ETC_INSTALL_DIR PATH $optarg
user_set_conffilesdir="true"
;;
--localstatedir=*)
append_cache_entry BRO_LOCAL_STATE_DIR PATH $optarg
;;
--spooldir=*)
append_cache_entry BRO_SPOOL_DIR PATH $optarg
;;
--logdir=*)
append_cache_entry BRO_LOG_DIR PATH $optarg
;;
--enable-debug)
append_cache_entry ENABLE_DEBUG BOOL true
;;
@ -184,12 +194,6 @@ while [ $# -ne 0 ]; do
--enable-ruby)
append_cache_entry DISABLE_RUBY_BINDINGS BOOL false
;;
--disable-dataseries)
append_cache_entry DISABLE_DATASERIES BOOL true
;;
--disable-elasticsearch)
append_cache_entry DISABLE_ELASTICSEARCH BOOL true
;;
--with-openssl=*)
append_cache_entry OpenSSL_ROOT_DIR PATH $optarg
;;
@ -211,9 +215,6 @@ while [ $# -ne 0 ]; do
--with-perl=*)
append_cache_entry PERL_EXECUTABLE PATH $optarg
;;
--with-libmagic=*)
append_cache_entry LibMagic_ROOT_DIR PATH $optarg
;;
--with-geoip=*)
append_cache_entry LibGeoIP_ROOT_DIR PATH $optarg
;;
@ -247,16 +248,6 @@ while [ $# -ne 0 ]; do
--with-swig=*)
append_cache_entry SWIG_EXECUTABLE PATH $optarg
;;
--with-dataseries=*)
append_cache_entry DataSeries_ROOT_DIR PATH $optarg
append_cache_entry Lintel_ROOT_DIR PATH $optarg
;;
--with-xml2=*)
append_cache_entry LibXML2_ROOT_DIR PATH $optarg
;;
--with-curl=*)
append_cache_entry LibCURL_ROOT_DIR PATH $optarg
;;
--binary-package)
append_cache_entry BINARY_PACKAGING_MODE BOOL true
;;

View file

@ -10,7 +10,7 @@
{% endblock %}
{% block header %}
<iframe src="http://www.bro.org/frames/header-no-logo.html" width="100%" height="100px" frameborder="0" marginheight="0" scrolling="no" marginwidth="0">
<iframe src="//www.bro.org/frames/header-no-logo.html" width="100%" height="100px" frameborder="0" marginheight="0" scrolling="no" marginwidth="0">
</iframe>
{% endblock %}
@ -108,6 +108,6 @@
{% endblock %}
{% block footer %}
<iframe src="http://www.bro.org/frames/footer.html" width="100%" height="420px" frameborder="0" marginheight="0" scrolling="no" marginwidth="0">
<iframe src="//www.bro.org/frames/footer.html" width="100%" height="420px" frameborder="0" marginheight="0" scrolling="no" marginwidth="0">
</iframe>
{% endblock %}

View file

@ -21,7 +21,7 @@ sys.path.insert(0, os.path.abspath('sphinx_input/ext'))
# ----- Begin of BTest configuration. -----
btest = os.path.abspath("@CMAKE_SOURCE_DIR@/aux/btest")
brocut = os.path.abspath("@CMAKE_SOURCE_DIR@/aux/bro-aux/bro-cut")
brocut = os.path.abspath("@CMAKE_SOURCE_DIR@/build/aux/bro-aux/bro-cut")
bro = os.path.abspath("@CMAKE_SOURCE_DIR@/build/src")
os.environ["PATH"] += (":%s:%s/sphinx:%s:%s" % (btest, btest, bro, brocut))

447
doc/devel/plugins.rst Normal file
View file

@ -0,0 +1,447 @@
===================
Writing Bro Plugins
===================
Bro is internally moving to a plugin structure that enables extending
the system dynamically, without modifying the core code base. That way
custom code remains self-contained and can be maintained, compiled,
and installed independently. Currently, plugins can add the following
functionality to Bro:
- Bro scripts.
- Builtin functions/events/types for the scripting language.
- Protocol analyzers.
- File analyzers.
- Packet sources and packet dumpers.
- Logging framework backends.
- Input framework readers.
A plugin's functionality is available to the user just as if Bro had
the corresponding code built-in. Indeed, internally many of Bro's
pieces are structured as plugins as well, they are just statically
compiled into the binary rather than loaded dynamically at runtime.
Quick Start
===========
Writing a basic plugin is quite straight-forward as long as one
follows a few conventions. In the following we walk a simple example
plugin that adds a new built-in function (bif) to Bro: we'll add
``rot13(s: string) : string``, a function that rotates every character
in a string by 13 places.
Generally, a plugin comes in the form of a directory following a
certain structure. To get started, Bro's distribution provides a
helper script ``aux/bro-aux/plugin-support/init-plugin`` that creates
a skeleton plugin that can then be customized. Let's use that::
# mkdir rot13-plugin
# cd rot13-plugin
# init-plugin Demo Rot13
As you can see the script takes two arguments. The first is a
namespace the plugin will live in, and the second a descriptive name
for the plugin itself. Bro uses the combination of the two to identify
a plugin. The namespace serves to avoid naming conflicts between
plugins written by independent developers; pick, e.g., the name of
your organisation. The namespace ``Bro`` is reserved for functionality
distributed by the Bro Project. In our example, the plugin will be
called ``Demo::Rot13``.
The ``init-plugin`` script puts a number of files in place. The full
layout is described later. For now, all we need is
``src/rot13.bif``. It's initially empty, but we'll add our new bif
there as follows::
# cat src/rot13.bif
module CaesarCipher;
function rot13%(s: string%) : string
%{
char* rot13 = copy_string(s->CheckString());
for ( char* p = rot13; *p; p++ )
{
char b = islower(*p) ? 'a' : 'A';
*p = (*p - b + 13) % 26 + b;
}
BroString* bs = new BroString(1, reinterpret_cast<byte_vec>(rot13),
strlen(rot13));
return new StringVal(bs);
%}
The syntax of this file is just like any other ``*.bif`` file; we
won't go into it here.
Now we can already compile our plugin, we just need to tell the
configure script put in place by ``init-plugin`` where the Bro source
tree is located (Bro needs to have been built there first)::
# ./configure --bro-dist=/path/to/bro/dist && make
[... cmake output ...]
Now our ``rot13-plugin`` directory has everything that it needs
for Bro to recognize it as a dynamic plugin. Once we point Bro to it,
it will pull it in automatically, as we can check with the ``-N``
option::
# export BRO_PLUGIN_PATH=/path/to/rot13-plugin
# bro -N
[...]
Plugin: Demo::Rot13 - <Insert brief description of plugin> (dynamic, version 1)
[...]
That looks quite good, except for the dummy description that we should
replace with something nicer so that users will know what our plugin
is about. We do this by editing the ``config.description`` line in
``src/Plugin.cc``, like this::
[...]
plugin::Configuration Configure()
{
plugin::Configuration config;
config.name = "Demo::Rot13";
config.description = "Caesar cipher rotating a string's characters by 13 places.";
config.version.major = 1;
config.version.minor = 0;
return config;
}
[...]
# make
[...]
# bro -N | grep Rot13
Plugin: Demo::Rot13 - Caesar cipher rotating a string's characters by 13 places. (dynamic, version 1)
Better. Bro can also show us what exactly the plugin provides with the
more verbose option ``-NN``::
# bro -NN
[...]
Plugin: Demo::Rot13 - Caesar cipher rotating a string's characters by 13 places. (dynamic, version 1)
[Function] CaesarCipher::rot13
[...]
There's our function. Now let's use it::
# bro -e 'print CaesarCipher::rot13("Hello")'
Uryyb
It works. We next install the plugin along with Bro itself, so that it
will find it directly without needing the ``BRO_PLUGIN_PATH``
environment variable. If we first unset the variable, the function
will no longer be available::
# unset BRO_PLUGIN_PATH
# bro -e 'print CaesarCipher::rot13("Hello")'
error in <command line>, line 1: unknown identifier CaesarCipher::rot13, at or near "CaesarCipher::rot13"
Once we install it, it works again::
# make install
# bro -e 'print CaesarCipher::rot13("Hello")'
Uryyb
The installed version went into
``<bro-install-prefix>/lib/bro/plugins/Demo_Rot13``.
We can distribute the plugin in either source or binary form by using
the Makefile's ``sdist`` and ``bdist`` target, respectively. Both
create corrsponding tarballs::
# make sdist
[...]
Source distribution in build/sdist/Demo_Rot13.tar.gz
# make bdist
[...]
Binary distribution in build/Demo_Rot13-darwin-x86_64.tar.gz
The source archive will contain everything in the plugin directory
except any generated files. The binary archive will contain anything
needed to install and run the plugin, i.e., just what ``make install``
puts into place as well. As the binary distribution is
platform-dependent, its name includes the OS and architecture the
plugin was built on.
Plugin Directory Layout
=======================
A plugin's directory needs to follow a set of conventions so that Bro
(1) recognizes it as a plugin, and (2) knows what to load. While
``init-plugin`` takes care of most of this, the following is the full
story. We'll use ``<base>`` to represent a plugin's top-level
directory.
``<base>/__bro_plugin__``
A file that marks a directory as containing a Bro plugin. The file
must exist, and its content must consist of a single line with the
qualified name of the plugin (e.g., "Demo::Rot13").
``<base>/lib/<plugin-name>-<os>-<arch>.so``
The shared library containing the plugin's compiled code. Bro will
load this in dynamically at run-time if OS and architecture match
the current platform.
``scripts/``
A directory with the plugin's custom Bro scripts. When the plugin
gets activated, this directory will be automatically added to
``BROPATH``, so that any scripts/modules inside can be
"@load"ed.
``scripts``/__load__.bro
A Bro script that will be loaded immediately when the plugin gets
activated. See below for more information on activating plugins.
``lib/bif/``
Directory with auto-generated Bro scripts that declare the plugin's
bif elements. The files here are produced by ``bifcl``.
By convention, a plugin should put its custom scripts into sub folders
of ``scripts/``, i.e., ``scripts/<script-namespace>/<script>.bro`` to
avoid conflicts. As usual, you can then put a ``__load__.bro`` in
there as well so that, e.g., ``@load Demo/Rot13`` could load a whole
module in the form of multiple individual scripts.
Note that in addition to the paths above, the ``init-plugin`` helper
puts some more files and directories in place that help with
development and installation (e.g., ``CMakeLists.txt``, ``Makefile``,
and source code in ``src/``). However, all these do not have a special
meaning for Bro at runtime and aren't necessary for a plugin to
function.
``init-plugin``
===============
``init-plugin`` puts a basic plugin structure in place that follows
the above layout and augments it with a CMake build and installation
system. Plugins with this structure can be used both directly out of
their source directory (after ``make`` and setting Bro's
``BRO_PLUGIN_PATH``), and when installed alongside Bro (after ``make
install``).
``make install`` copies over the ``lib`` and ``scripts`` directories,
as well as the ``__bro_plugin__`` magic file and the ``README`` (which
you should customize). One can add further CMake ``install`` rules to
install additional files if needed.
``init-plugin`` will never overwrite existing files, so it's safe to
rerun in an existing plugin directory; it only put files in place that
don't exist yet. That also provides a convenient way to revert a file
back to what ``init-plugin`` created originally: just delete it and
rerun.
Activating a Plugin
===================
A plugin needs to be *activated* to make it available to the user.
Activating a plugin will:
1. Load the dynamic module
2. Make any bif items available
3. Add the ``scripts/`` directory to ``BROPATH``
4. Load ``scripts/__load__.bro``
By default, Bro will automatically activate all dynamic plugins found
in its search path ``BRO_PLUGIN_PATH``. However, in bare mode (``bro
-b``), no dynamic plugins will be activated by default; instead the
user can selectively enable individual plugins in scriptland using the
``@load-plugin <qualified-plugin-name>`` directive (e.g.,
``@load-plugin Demo::Rot13``). Alternatively, one can activate a
plugin from the command-line by specifying its full name
(``Demo::Rot13``), or set the environment variable
``BRO_PLUGIN_ACTIVATE`` to a list of comma(!)-separated names of
plugins to unconditionally activate, even in bare mode.
``bro -N`` shows activated plugins separately from found but not yet
activated plugins. Note that plugins compiled statically into Bro are
always activated, and hence show up as such even in bare mode.
Plugin Components
=================
The following subsections detail providing individual types of
functionality via plugins. Note that a single plugin can provide more
than one component type. For example, a plugin could provide multiple
protocol analyzers at once; or both a logging backend and input reader
at the same time.
.. todo::
These subsections are mostly missing right now, as much of their
content isn't actually plugin-specific, but concerns generally
writing such functionality for Bro. The best way to get started
right now is to look at existing code implementing similar
functionality, either as a plugin or inside Bro proper. Also, for
each component type there's a unit test in
``testing/btest/plugins`` creating a basic plugin skeleton with a
corresponding component.
Bro Scripts
-----------
Scripts are easy: just put them into ``scripts/``, as described above.
The CMake infrastructure will automatically install them, as well
include them into the source and binary plugin distributions.
Builtin Language Elements
-------------------------
Functions
TODO
Events
TODO
Types
TODO
Protocol Analyzers
------------------
TODO.
File Analyzers
--------------
TODO.
Logging Writer
--------------
TODO.
Input Reader
------------
TODO.
Packet Sources
--------------
TODO.
Packet Dumpers
--------------
TODO.
Hooks
=====
TODO.
Testing Plugins
===============
A plugin should come with a test suite to exercise its functionality.
The ``init-plugin`` script puts in place a basic </btest/README> setup
to start with. Initially, it comes with a single test that just checks
that Bro loads the plugin correctly. It won't have a baseline yet, so
let's get that in place::
# cd tests
# btest -d
[ 0%] plugin.loading ... failed
% 'btest-diff output' failed unexpectedly (exit code 100)
% cat .diag
== File ===============================
Demo::Rot13 - Caesar cipher rotating a string's characters by 13 places. (dynamic, version 1.0)
[Function] CaesarCipher::rot13
== Error ===============================
test-diff: no baseline found.
=======================================
# btest -U
all 1 tests successful
# cd ..
# make test
make -C tests
make[1]: Entering directory `tests'
all 1 tests successful
make[1]: Leaving directory `tests'
Now let's add a custom test that ensures that our bif works
correctly::
# cd tests
# cat >plugin/rot13.bro
# @TEST-EXEC: bro %INPUT >output
# @TEST-EXEC: btest-diff output
event bro_init()
{
print CaesarCipher::rot13("Hello");
}
Check the output::
# btest -d plugin/rot13.bro
[ 0%] plugin.rot13 ... failed
% 'btest-diff output' failed unexpectedly (exit code 100)
% cat .diag
== File ===============================
Uryyb
== Error ===============================
test-diff: no baseline found.
=======================================
% cat .stderr
1 of 1 test failed
Install the baseline::
# btest -U plugin/rot13.bro
all 1 tests successful
Run the test-suite::
# btest
all 2 tests successful
Debugging Plugins
=================
If your plugin isn't loading as expected, Bro's debugging facilities
can help to illuminate what's going on. To enable, recompile Bro
with debugging support (``./configure --enable-debug``), and
afterwards rebuild your plugin as well. If you then run Bro with ``-B
plugins``, it will produce a file ``debug.log`` that records details
about the process for searching, loading, and activating plugins.
To generate your own debugging output from inside your plugin, you can
add a custom debug stream by using the ``PLUGIN_DBG_LOG(<plugin>,
<args>)`` macro (defined in ``DebugLogger.h``), where ``<plugin>`` is
the ``Plugin`` instance and ``<args>`` are printf-style arguments,
just as with Bro's standard debugging macros (grep for ``DBG_LOG`` in
Bro's ``src/`` to see examples). At runtime, you can then activate
your plugin's debugging output with ``-B plugin-<name>``, where
``<name>`` is the name of the plugin as returned by its
``Configure()`` method, yet with the namespace-separator ``::``
replaced with a simple dash. Example: If the plugin is called
``Bro::Demo``, use ``-B plugin-Bro-Demo``. As usual, the debugging
output will be recorded to ``debug.log`` if Bro's compiled in debug
mode.
Documenting Plugins
===================
.. todo::
Integrate all this with Broxygen.

View file

@ -176,6 +176,10 @@ class BroIdentifier(BroGeneric):
def get_index_text(self, objectname, name):
return name
class BroKeyword(BroGeneric):
def get_index_text(self, objectname, name):
return name
class BroAttribute(BroGeneric):
def get_index_text(self, objectname, name):
return _('%s (attribute)') % (name)
@ -213,6 +217,7 @@ class BroDomain(Domain):
'type': ObjType(l_('type'), 'type'),
'namespace': ObjType(l_('namespace'), 'namespace'),
'id': ObjType(l_('id'), 'id'),
'keyword': ObjType(l_('keyword'), 'keyword'),
'enum': ObjType(l_('enum'), 'enum'),
'attr': ObjType(l_('attr'), 'attr'),
}
@ -221,6 +226,7 @@ class BroDomain(Domain):
'type': BroGeneric,
'namespace': BroNamespace,
'id': BroIdentifier,
'keyword': BroKeyword,
'enum': BroEnum,
'attr': BroAttribute,
}
@ -229,6 +235,7 @@ class BroDomain(Domain):
'type': XRefRole(),
'namespace': XRefRole(),
'id': XRefRole(),
'keyword': XRefRole(),
'enum': XRefRole(),
'attr': XRefRole(),
'see': XRefRole(),

Binary file not shown.

Binary file not shown.

View file

@ -135,7 +135,10 @@ class Pygments(Directive):
# lexer not found, use default.
lexer = TextLexer()
else:
try:
lexer = guess_lexer(content)
except:
lexer = TextLexer()
# import sys
# print >>sys.stderr, self.arguments, lexer.__class__

View file

@ -1,7 +1,7 @@
event file_new(f: fa_file)
event file_mime_type(f: fa_file, mime_type: string)
{
print "new file", f$id;
if ( f?$mime_type && f$mime_type == "text/plain" )
if ( mime_type == "text/plain" )
Files::add_analyzer(f, Files::ANALYZER_MD5);
}

View file

@ -14,32 +14,35 @@ consume that data, make it available for matching, and provide
infrastructure around improving performance, memory utilization, and
generally making all of this easier.
Data in the Intelligence Framework is the atomic piece of intelligence
Data in the Intelligence Framework is an atomic piece of intelligence
such as an IP address or an e-mail address along with a suite of
metadata about it such as a freeform source field, a freeform
descriptive field and a URL which might lead to more information about
the specific item. The metadata in the default scripts has been
deliberately kept minimal so that the community can find the
appropriate fields that need added by writing scripts which extend the
appropriate fields that need to be added by writing scripts which extend the
base record using the normal record extension mechanism.
Quick Start
-----------
Load the package of scripts that sends data into the Intelligence
Framework to be checked by loading this script in local.bro::
@load policy/frameworks/intel/seen
Refer to the "Loading Intelligence" section below to see the format
for Intelligence Framework text files, then load those text files with
this line in local.bro::
redef Intel::read_files += { "/somewhere/yourdata.txt" };
The data itself only needs to reside on the manager if running in a
The text files need to reside only on the manager if running in a
cluster.
Add the following line to local.bro in order to load the scripts
that send "seen" data into the Intelligence Framework to be checked against
the loaded intelligence data::
@load policy/frameworks/intel/seen
Intelligence data matches will be logged to the intel.log file.
Architecture
------------
@ -58,8 +61,10 @@ manager is the only node that needs the intelligence data. The
intelligence framework has distribution mechanisms which will push
data out to all of the nodes that need it.
Here is an example of the intelligence data format. Note that all
whitespace field separators are literal tabs and fields containing only a
Here is an example of the intelligence data format (note that there will be
additional fields if you are using CIF intelligence data or if you are
using the policy/frameworks/intel/do_notice script). Note that all fields
must be separated by a single tab character and fields containing only a
hyphen are considered to be null values. ::
#fields indicator indicator_type meta.source meta.desc meta.url
@ -69,8 +74,21 @@ hyphen are considered to be null values. ::
For a list of all built-in `indicator_type` values, please refer to the
documentation of :bro:see:`Intel::Type`.
To load the data once files are created, use the following example
code to define files to load with your own file names of course::
Note that if you are using data from the Collective Intelligence Framework,
then you will need to add the following line to your local.bro in order
to support additional metadata fields used by CIF::
@load policy/integration/collective-intel
There is a simple mechanism to raise a Bro notice (of type Intel::Notice)
for user-specified intelligence matches. To use this feature, add the
following line to local.bro in order to support additional metadata fields
(documented in the :bro:see:`Intel::MetaData` record)::
@load policy/frameworks/intel/do_notice
To load the data once the files are created, use the following example
to specify which files to load (with your own file names of course)::
redef Intel::read_files += {
"/somewhere/feed1.txt",
@ -85,24 +103,23 @@ Seen Data
When some bit of data is extracted (such as an email address in the
"From" header in a message over SMTP), the Intelligence Framework
needs to be informed that this data was discovered and it's presence
should be checked within the intelligence data set. This is
accomplished through the :bro:see:`Intel::seen` function.
needs to be informed that this data was discovered so that its presence
will be checked within the loaded intelligence data. This is
accomplished through the :bro:see:`Intel::seen` function, however
typically users won't need to work with this function due to the
scripts included with Bro that will call this function.
Typically users won't need to work with this function due to built in
hook scripts that Bro ships with that will "see" data and send it into
the intelligence framework. A user may only need to load the entire
package of hook scripts as a module or pick and choose specific
scripts to load. Keep in mind that as more data is sent into the
To load all of the scripts included with Bro for sending "seen" data to
the intelligence framework, just add this line to local.bro::
@load policy/frameworks/intel/seen
Alternatively, specific scripts in that directory can be loaded.
Keep in mind that as more data is sent into the
intelligence framework, the CPU load consumed by Bro will increase
depending on how many times the :bro:see:`Intel::seen` function is
being called which is heavily traffic dependent.
The full package of hook scripts that Bro ships with for sending this
"seen" data into the intelligence framework can be loading by adding
this line to local.bro::
@load policy/frameworks/intel/seen
Intelligence Matches
********************
@ -111,6 +128,7 @@ Against all hopes, most networks will eventually have a hit on
intelligence data which could indicate a possible compromise or other
unwanted activity. The Intelligence Framework provides an event that
is generated whenever a match is discovered named :bro:see:`Intel::match`.
Due to design restrictions placed upon
the intelligence framework, there is no assurance as to where this
event will be generated. It could be generated on the worker where
@ -119,3 +137,7 @@ handled, only the data given as event arguments to the event can be
assured since the host where the data was seen may not be where
``Intel::match`` is handled.
Intelligence matches are logged to the intel.log file. For a description of
each field in that file, see the documentation for the :bro:see:`Intel::Info`
record.

View file

@ -1,186 +0,0 @@
=============================
Binary Output with DataSeries
=============================
.. rst-class:: opening
Bro's default ASCII log format is not exactly the most efficient
way for storing and searching large volumes of data. An an
alternative, Bro comes with experimental support for `DataSeries
<http://www.hpl.hp.com/techreports/2009/HPL-2009-323.html>`_
output, an efficient binary format for recording structured bulk
data. DataSeries is developed and maintained at HP Labs.
.. contents::
Installing DataSeries
---------------------
To use DataSeries, its libraries must be available at compile-time,
along with the supporting *Lintel* package. Generally, both are
distributed on `HP Labs' web site
<http://tesla.hpl.hp.com/opensource/>`_. Currently, however, you need
to use recent development versions for both packages, which you can
download from github like this::
git clone http://github.com/dataseries/Lintel
git clone http://github.com/dataseries/DataSeries
To build and install the two into ``<prefix>``, do::
( cd Lintel && mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX=<prefix> .. && make && make install )
( cd DataSeries && mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX=<prefix> .. && make && make install )
Please refer to the packages' documentation for more information about
the installation process. In particular, there's more information on
required and optional `dependencies for Lintel
<https://raw.github.com/dataseries/Lintel/master/doc/dependencies.txt>`_
and `dependencies for DataSeries
<https://raw.github.com/dataseries/DataSeries/master/doc/dependencies.txt>`_.
For users on RedHat-style systems, you'll need the following::
yum install libxml2-devel boost-devel
Compiling Bro with DataSeries Support
-------------------------------------
Once you have installed DataSeries, Bro's ``configure`` should pick it
up automatically as long as it finds it in a standard system location.
Alternatively, you can specify the DataSeries installation prefix
manually with ``--with-dataseries=<prefix>``. Keep an eye on
``configure``'s summary output, if it looks like the following, Bro
found DataSeries and will compile in the support::
# ./configure --with-dataseries=/usr/local
[...]
====================| Bro Build Summary |=====================
[...]
DataSeries: true
[...]
================================================================
Activating DataSeries
---------------------
The direct way to use DataSeries is to switch *all* log files over to
the binary format. To do that, just add ``redef
Log::default_writer=Log::WRITER_DATASERIES;`` to your ``local.bro``.
For testing, you can also just pass that on the command line::
bro -r trace.pcap Log::default_writer=Log::WRITER_DATASERIES
With that, Bro will now write all its output into DataSeries files
``*.ds``. You can inspect these using DataSeries's set of command line
tools, which its installation process installs into ``<prefix>/bin``.
For example, to convert a file back into an ASCII representation::
$ ds2txt conn.log
[... We skip a bunch of metadata here ...]
ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state local_orig missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes
1300475167.096535 CRCC5OdDlXe 141.142.220.202 5353 224.0.0.251 5353 udp dns 0.000000 0 0 S0 F 0 D 1 73 0 0
1300475167.097012 o7XBsfvo3U1 fe80::217:f2ff:fed7:cf65 5353 ff02::fb 5353 udp 0.000000 0 0 S0 F 0 D 1 199 0 0
1300475167.099816 pXPi1kPMgxb 141.142.220.50 5353 224.0.0.251 5353 udp 0.000000 0 0 S0 F 0 D 1 179 0 0
1300475168.853899 R7sOc16woCj 141.142.220.118 43927 141.142.2.2 53 udp dns 0.000435 38 89 SF F 0 Dd 1 66 1 117
1300475168.854378 Z6dfHVmt0X7 141.142.220.118 37676 141.142.2.2 53 udp dns 0.000420 52 99 SF F 0 Dd 1 80 1 127
1300475168.854837 k6T92WxgNAh 141.142.220.118 40526 141.142.2.2 53 udp dns 0.000392 38 183 SF F 0 Dd 1 66 1 211
[...]
(``--skip-all`` suppresses the metadata.)
Note that the ASCII conversion is *not* equivalent to Bro's default
output format.
You can also switch only individual files over to DataSeries by adding
code like this to your ``local.bro``:
.. code:: bro
event bro_init()
{
local f = Log::get_filter(Conn::LOG, "default"); # Get default filter for connection log.
f$writer = Log::WRITER_DATASERIES; # Change writer type.
Log::add_filter(Conn::LOG, f); # Replace filter with adapted version.
}
Bro's DataSeries writer comes with a few tuning options, see
:doc:`/scripts/base/frameworks/logging/writers/dataseries.bro`.
Working with DataSeries
=======================
Here are a few examples of using DataSeries command line tools to work
with the output files.
* Printing CSV::
$ ds2txt --csv conn.log
ts,uid,id.orig_h,id.orig_p,id.resp_h,id.resp_p,proto,service,duration,orig_bytes,resp_bytes,conn_state,local_orig,missed_bytes,history,orig_pkts,orig_ip_bytes,resp_pkts,resp_ip_bytes
1258790493.773208,ZTtgbHvf4s3,192.168.1.104,137,192.168.1.255,137,udp,dns,3.748891,350,0,S0,F,0,D,7,546,0,0
1258790451.402091,pOY6Rw7lhUd,192.168.1.106,138,192.168.1.255,138,udp,,0.000000,0,0,S0,F,0,D,1,229,0,0
1258790493.787448,pn5IiEslca9,192.168.1.104,138,192.168.1.255,138,udp,,2.243339,348,0,S0,F,0,D,2,404,0,0
1258790615.268111,D9slyIu3hFj,192.168.1.106,137,192.168.1.255,137,udp,dns,3.764626,350,0,S0,F,0,D,7,546,0,0
[...]
Add ``--separator=X`` to set a different separator.
* Extracting a subset of columns::
$ ds2txt --select '*' ts,id.resp_h,id.resp_p --skip-all conn.log
1258790493.773208 192.168.1.255 137
1258790451.402091 192.168.1.255 138
1258790493.787448 192.168.1.255 138
1258790615.268111 192.168.1.255 137
1258790615.289842 192.168.1.255 138
[...]
* Filtering rows::
$ ds2txt --where '*' 'duration > 5 && id.resp_p > 1024' --skip-all conn.ds
1258790631.532888 V8mV5WLITu5 192.168.1.105 55890 239.255.255.250 1900 udp 15.004568 798 0 S0 F 0 D 6 966 0 0
1258792413.439596 tMcWVWQptvd 192.168.1.105 55890 239.255.255.250 1900 udp 15.004581 798 0 S0 F 0 D 6 966 0 0
1258794195.346127 cQwQMRdBrKa 192.168.1.105 55890 239.255.255.250 1900 udp 15.005071 798 0 S0 F 0 D 6 966 0 0
1258795977.253200 i8TEjhWd2W8 192.168.1.105 55890 239.255.255.250 1900 udp 15.004824 798 0 S0 F 0 D 6 966 0 0
1258797759.160217 MsLsBA8Ia49 192.168.1.105 55890 239.255.255.250 1900 udp 15.005078 798 0 S0 F 0 D 6 966 0 0
1258799541.068452 TsOxRWJRGwf 192.168.1.105 55890 239.255.255.250 1900 udp 15.004082 798 0 S0 F 0 D 6 966 0 0
[...]
* Calculate some statistics:
Mean/stddev/min/max over a column::
$ dsstatgroupby '*' basic duration from conn.ds
# Begin DSStatGroupByModule
# processed 2159 rows, where clause eliminated 0 rows
# count(*), mean(duration), stddev, min, max
2159, 42.7938, 1858.34, 0, 86370
[...]
Quantiles of total connection volume::
$ dsstatgroupby '*' quantile 'orig_bytes + resp_bytes' from conn.ds
[...]
2159 data points, mean 24616 +- 343295 [0,1.26615e+07]
quantiles about every 216 data points:
10%: 0, 124, 317, 348, 350, 350, 601, 798, 1469
tails: 90%: 1469, 95%: 7302, 99%: 242629, 99.5%: 1226262
[...]
The ``man`` pages for these tools show further options, and their
``-h`` option gives some more information (either can be a bit cryptic
unfortunately though).
Deficiencies
------------
Due to limitations of the DataSeries format, one cannot inspect its
files before they have been fully written. In other words, when using
DataSeries, it's currently not possible to inspect the live log
files inside the spool directory before they are rotated to their
final location. It seems that this could be fixed with some effort,
and we will work with DataSeries development team on that if the
format gains traction among Bro users.
Likewise, we're considering writing custom command line tools for
interacting with DataSeries files, making that a bit more convenient
than what the standard utilities provide.

View file

@ -1,89 +0,0 @@
=========================================
Indexed Logging Output with ElasticSearch
=========================================
.. rst-class:: opening
Bro's default ASCII log format is not exactly the most efficient
way for searching large volumes of data. ElasticSearch
is a new data storage technology for dealing with tons of data.
It's also a search engine built on top of Apache's Lucene
project. It scales very well, both for distributed indexing and
distributed searching.
.. contents::
Warning
-------
This writer plugin is still in testing and is not yet recommended for
production use! The approach to how logs are handled in the plugin is "fire
and forget" at this time, there is no error handling if the server fails to
respond successfully to the insertion request.
Installing ElasticSearch
------------------------
Download the latest version from: http://www.elasticsearch.org/download/.
Once extracted, start ElasticSearch with::
# ./bin/elasticsearch
For more detailed information, refer to the ElasticSearch installation
documentation: http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/setup.html
Compiling Bro with ElasticSearch Support
----------------------------------------
First, ensure that you have libcurl installed then run configure::
# ./configure
[...]
====================| Bro Build Summary |=====================
[...]
cURL: true
[...]
ElasticSearch: true
[...]
================================================================
Activating ElasticSearch
------------------------
The easiest way to enable ElasticSearch output is to load the
tuning/logs-to-elasticsearch.bro script. If you are using BroControl,
the following line in local.bro will enable it:
.. console::
@load tuning/logs-to-elasticsearch
With that, Bro will now write most of its logs into ElasticSearch in addition
to maintaining the Ascii logs like it would do by default. That script has
some tunable options for choosing which logs to send to ElasticSearch, refer
to the autogenerated script documentation for those options.
There is an interface being written specifically to integrate with the data
that Bro outputs into ElasticSearch named Brownian. It can be found here::
https://github.com/grigorescu/Brownian
Tuning
------
A common problem encountered with ElasticSearch is too many files being held
open. The ElasticSearch website has some suggestions on how to increase the
open file limit.
- http://www.elasticsearch.org/tutorials/too-many-open-files/
TODO
----
Lots.
- Perform multicast discovery for server.
- Better error detection.
- Better defaults (don't index loaded-plugins, for instance).
-

View file

@ -380,11 +380,11 @@ uncommon to need to delete that data before the end of the connection.
Other Writers
-------------
Bro supports the following output formats other than ASCII:
Bro supports the following built-in output formats other than ASCII:
.. toctree::
:maxdepth: 1
logging-dataseries
logging-elasticsearch
logging-input-sqlite
Further formats are available as external plugins.

View file

@ -271,7 +271,7 @@ script that is generating the notice has indicated to the notice framework how
to identify notices that are intrinsically the same. Identification of these
"intrinsically duplicate" notices is implemented with an optional field in
:bro:see:`Notice::Info` records named ``$identifier`` which is a simple string.
If the ``$identifier`` and ``$type`` fields are the same for two notices, the
If the ``$identifier`` and ``$note`` fields are the same for two notices, the
notice framework actually considers them to be the same thing and can use that
information to suppress duplicates for a configurable period of time.

View file

@ -7,18 +7,15 @@ global mime_to_ext: table[string] of string = {
["text/html"] = "html",
};
event file_new(f: fa_file)
event file_mime_type(f: fa_file, mime_type: string)
{
if ( f$source != "HTTP" )
return;
if ( ! f?$mime_type )
if ( mime_type !in mime_to_ext )
return;
if ( f$mime_type !in mime_to_ext )
return;
local fname = fmt("%s-%s.%s", f$source, f$id, mime_to_ext[f$mime_type]);
local fname = fmt("%s-%s.%s", f$source, f$id, mime_to_ext[mime_type]);
print fmt("Extracting file %s", fname);
Files::add_analyzer(f, Files::ANALYZER_EXTRACT, [$extract_filename=fname]);
}

View file

@ -31,6 +31,7 @@ Using Bro Section
httpmonitor/index.rst
broids/index.rst
mimestats/index.rst
scripting/index.rst
..
@ -40,12 +41,17 @@ Reference Section
.. toctree::
:maxdepth: 2
scripting/index.rst
frameworks/index.rst
script-reference/index.rst
components/index.rst
..
Development
===========
.. toctree::
:maxdepth: 2
devel/plugins.rst
* :ref:`General Index <genindex>`
* :ref:`search`

View file

@ -35,7 +35,7 @@ before you begin:
To build Bro from source, the following additional dependencies are required:
* CMake 2.6.3 or greater (http://www.cmake.org)
* CMake 2.8 or greater (http://www.cmake.org)
* Make
* C/C++ compiler
* SWIG (http://www.swig.org)
@ -91,7 +91,6 @@ build time:
* LibGeoIP (for geolocating IP addresses)
* sendmail (enables Bro and BroControl to send mail)
* gawk (enables all features of bro-cut)
* curl (used by a Bro script that implements active HTTP)
* gperftools (tcmalloc is used to improve memory and CPU usage)
* ipsumdump (for trace-summary; http://www.cs.ucla.edu/~kohler/ipsumdump)
@ -181,7 +180,7 @@ automatically. Finally, use ``make install-aux`` to install some of
the other programs that are in the ``aux/bro-aux`` directory.
OpenBSD users, please see our `FAQ
<http://www.bro.org/documentation/faq.html>`_ if you are having
<//www.bro.org/documentation/faq.html>`_ if you are having
problems installing Bro.
Finally, if you want to build the Bro documentation (not required, because

View file

@ -112,6 +112,8 @@ default, including:
As you can see, some log files are specific to a particular protocol,
while others aggregate information across different types of activity.
For a complete list of log files and a description of its purpose,
see :doc:`Log Files <../script-reference/log-files>`.
.. _bro-cut:
@ -162,8 +164,8 @@ tools like ``awk`` allow you to indicate the log file as a command
line option, bro-cut only takes input through redirection such as
``|`` and ``<``. There are a couple of ways to direct log file data
into ``bro-cut``, each dependent upon the type of log file you're
processing. A caveat of its use, however, is that the 8 lines of
header data must be present.
processing. A caveat of its use, however, is that all of the
header lines must be present.
.. note::
@ -177,8 +179,8 @@ moving the current log file into a directory with format
``YYYY-MM-DD`` and gzip compressing the file with a file format that
includes the log file type and time range of the file. In the case of
processing a compressed log file you simply adjust your command line
tools to use the complementary ``z*`` versions of commands such as cat
(``zcat``), ``grep`` (``zgrep``), and ``head`` (``zhead``).
tools to use the complementary ``z*`` versions of commands such as ``cat``
(``zcat``) or ``grep`` (``zgrep``).
Working with Timestamps
-----------------------
@ -250,44 +252,3 @@ protocol, it can have multiple ``GET``/``POST``/etc requests in a
stream and Bro is able to extract and track that information for you,
giving you an in-depth and structured view into HTTP traffic on your
network.
-----------------------
Common Log Files
-----------------------
As a monitoring tool, Bro records a detailed view of the traffic inspected
and the events generated in a series of relevant log files. These files can
later be reviewed for monitoring, auditing and troubleshooting purposes.
In this section we present a brief explanation of the most commonly used log
files generated by Bro including links to descriptions of some of the fields
for each log type.
+-----------------+---------------------------------------+------------------------------+
| Log File | Description | Field Descriptions |
+=================+=======================================+==============================+
| http.log | Shows all HTTP requests and replies | :bro:type:`HTTP::Info` |
+-----------------+---------------------------------------+------------------------------+
| ftp.log | Records FTP activity | :bro:type:`FTP::Info` |
+-----------------+---------------------------------------+------------------------------+
| ssl.log | Records SSL sessions including | :bro:type:`SSL::Info` |
| | certificates used | |
+-----------------+---------------------------------------+------------------------------+
| known_certs.log | Includes SSL certificates used | :bro:type:`Known::CertsInfo` |
+-----------------+---------------------------------------+------------------------------+
| smtp.log | Summarizes SMTP traffic on a network | :bro:type:`SMTP::Info` |
+-----------------+---------------------------------------+------------------------------+
| dns.log | Shows all DNS activity on a network | :bro:type:`DNS::Info` |
+-----------------+---------------------------------------+------------------------------+
| conn.log | Records all connections seen by Bro | :bro:type:`Conn::Info` |
+-----------------+---------------------------------------+------------------------------+
| dpd.log | Shows network activity on | :bro:type:`DPD::Info` |
| | non-standard ports | |
+-----------------+---------------------------------------+------------------------------+
| files.log | Records information about all files | :bro:type:`Files::Info` |
| | transmitted over the network | |
+-----------------+---------------------------------------+------------------------------+
| weird.log | Records unexpected protocol-level | :bro:type:`Weird::Info` |
| | activity | |
+-----------------+---------------------------------------+------------------------------+

View file

@ -1,5 +1,5 @@
.. _FAQ: http://www.bro.org/documentation/faq.html
.. _FAQ: //www.bro.org/documentation/faq.html
.. _quickstart:
@ -234,7 +234,7 @@ is valid before installing it and then restarting the Bro instance:
.. console::
[BroControl] > check
bro is ok.
bro scripts are ok.
[BroControl] > install
removing old policies in /usr/local/bro/spool/policy/site ... done.
removing old policies in /usr/local/bro/spool/policy/auto ... done.
@ -250,15 +250,15 @@ is valid before installing it and then restarting the Bro instance:
Now that the SSL notice is ignored, let's look at how to send an email on
the SSH notice. The notice framework has a similar option called
``emailed_types``, but that can't differentiate between SSH servers and we
only want email for logins to certain ones. Then we come to the ``PolicyItem``
record and ``policy`` set and realize that those are actually what get used
to implement the simple functionality of ``ignored_types`` and
``emailed_types``, but using that would generate email for all SSH servers and
we only want email for logins to certain ones. There is a ``policy`` hook
that is actually what is used to implement the simple functionality of
``ignored_types`` and
``emailed_types``, but it's extensible such that the condition and action taken
on notices can be user-defined.
In ``local.bro``, let's add a new ``PolicyItem`` record to the ``policy`` set
that only takes the email action for SSH logins to a defined set of servers:
In ``local.bro``, let's define a new ``policy`` hook handler body
that takes the email action for SSH logins only for a defined set of servers:
.. code:: bro
@ -276,9 +276,9 @@ that only takes the email action for SSH logins to a defined set of servers:
You'll just have to trust the syntax for now, but what we've done is
first declare our own variable to hold a set of watched addresses,
``watched_servers``; then added a record to the policy that will generate
an email on the condition that the predicate function evaluates to true, which
is whenever the notice type is an SSH login and the responding host stored
``watched_servers``; then added a hook handler body to the policy that will
generate an email whenever the notice type is an SSH login and the responding
host stored
inside the ``Info`` record's connection field is in the set of watched servers.
.. note:: Record field member access is done with the '$' character

View file

@ -0,0 +1,232 @@
Attributes
==========
The Bro scripting language supports the following attributes.
+-----------------------------+-----------------------------------------------+
| Name | Description |
+=============================+===============================================+
| :bro:attr:`&redef` |Redefine a global constant or extend a type. |
+-----------------------------+-----------------------------------------------+
| :bro:attr:`&priority` |Specify priority for event handler or hook. |
+-----------------------------+-----------------------------------------------+
| :bro:attr:`&log` |Mark a record field as to be written to a log. |
+-----------------------------+-----------------------------------------------+
| :bro:attr:`&optional` |Allow a record field value to be missing. |
+-----------------------------+-----------------------------------------------+
| :bro:attr:`&default` |Specify a default value. |
+-----------------------------+-----------------------------------------------+
| :bro:attr:`&add_func` |Specify a function to call for each "redef +=".|
+-----------------------------+-----------------------------------------------+
| :bro:attr:`&delete_func` |Same as "&add_func", except for "redef -=". |
+-----------------------------+-----------------------------------------------+
| :bro:attr:`&expire_func` |Specify a function to call when container |
| |element expires. |
+-----------------------------+-----------------------------------------------+
| :bro:attr:`&read_expire` |Specify a read timeout interval. |
+-----------------------------+-----------------------------------------------+
| :bro:attr:`&write_expire` |Specify a write timeout interval. |
+-----------------------------+-----------------------------------------------+
| :bro:attr:`&create_expire` |Specify a creation timeout interval. |
+-----------------------------+-----------------------------------------------+
| :bro:attr:`&synchronized` |Synchronize a variable across nodes. |
+-----------------------------+-----------------------------------------------+
| :bro:attr:`&persistent` |Make a variable persistent (written to disk). |
+-----------------------------+-----------------------------------------------+
| :bro:attr:`&rotate_interval`|Rotate a file after specified interval. |
+-----------------------------+-----------------------------------------------+
| :bro:attr:`&rotate_size` |Rotate a file after specified file size. |
+-----------------------------+-----------------------------------------------+
| :bro:attr:`&encrypt` |Encrypt a file when writing to disk. |
+-----------------------------+-----------------------------------------------+
| :bro:attr:`&raw_output` |Open file in raw mode (chars. are not escaped).|
+-----------------------------+-----------------------------------------------+
| :bro:attr:`&mergeable` |Prefer set union for synchronized state. |
+-----------------------------+-----------------------------------------------+
| :bro:attr:`&group` |Group event handlers to activate/deactivate. |
+-----------------------------+-----------------------------------------------+
| :bro:attr:`&error_handler` |Used internally for reporter framework events. |
+-----------------------------+-----------------------------------------------+
| :bro:attr:`&type_column` |Used by input framework for "port" type. |
+-----------------------------+-----------------------------------------------+
Here is a more detailed explanation of each attribute:
.. bro:attr:: &redef
Allows for redefinition of initial values of global objects declared as
constant.
In this example, the constant (assuming it is global) can be redefined
with a :bro:keyword:`redef` at some later point::
const clever = T &redef;
.. bro:attr:: &priority
Specifies the execution priority (as a signed integer) of a hook or
event handler. Higher values are executed before lower ones. The
default value is 0. Example::
event bro_init() &priority=10
{
print "high priority";
}
.. bro:attr:: &log
Writes a :bro:type:`record` field to the associated log stream.
.. bro:attr:: &optional
Allows a record field value to be missing (i.e., neither initialized nor
ever assigned a value).
In this example, the record could be instantiated with either
"myrec($a=127.0.0.1)" or "myrec($a=127.0.0.1, $b=80/tcp)"::
type myrec: record { a: addr; b: port &optional; };
The ``?$`` operator can be used to check if a record field has a value or
not (it returns a ``bool`` value of ``T`` if the field has a value,
and ``F`` if not).
.. bro:attr:: &default
Specifies a default value for a record field, container element, or a
function/hook/event parameter.
In this example, the record could be instantiated with either
"myrec($a=5, $c=3.14)" or "myrec($a=5, $b=53/udp, $c=3.14)"::
type myrec: record { a: count; b: port &default=80/tcp; c: double; };
In this example, the table will return the string ``"foo"`` for any
attempted access to a non-existing index::
global mytable: table[count] of string &default="foo";
When used with function/hook/event parameters, all of the parameters
with the "&default" attribute must come after all other parameters.
For example, the following function could be called either as "myfunc(5)"
or as "myfunc(5, 53/udp)"::
function myfunc(a: count, b: port &default=80/tcp)
{
print a, b;
}
.. bro:attr:: &add_func
Can be applied to an identifier with &redef to specify a function to
be called any time a "redef <id> += ..." declaration is parsed. The
function takes two arguments of the same type as the identifier, the first
being the old value of the variable and the second being the new
value given after the "+=" operator in the "redef" declaration. The
return value of the function will be the actual new value of the
variable after the "redef" declaration is parsed.
.. bro:attr:: &delete_func
Same as :bro:attr:`&add_func`, except for :bro:keyword:`redef` declarations
that use the "-=" operator.
.. bro:attr:: &expire_func
Called right before a container element expires. The function's
first parameter is of the same type of the container and the second
parameter the same type of the container's index. The return
value is an :bro:type:`interval` indicating the amount of additional
time to wait before expiring the container element at the given
index (which will trigger another execution of this function).
.. bro:attr:: &read_expire
Specifies a read expiration timeout for container elements. That is,
the element expires after the given amount of time since the last
time it has been read. Note that a write also counts as a read.
.. bro:attr:: &write_expire
Specifies a write expiration timeout for container elements. That
is, the element expires after the given amount of time since the
last time it has been written.
.. bro:attr:: &create_expire
Specifies a creation expiration timeout for container elements. That
is, the element expires after the given amount of time since it has
been inserted into the container, regardless of any reads or writes.
.. bro:attr:: &synchronized
Synchronizes variable accesses across nodes. The value of a
``&synchronized`` variable is automatically propagated to all peers
when it changes.
.. bro:attr:: &persistent
Makes a variable persistent, i.e., its value is written to disk (per
default at shutdown time).
.. bro:attr:: &rotate_interval
Rotates a file after a specified interval.
.. bro:attr:: &rotate_size
Rotates a file after it has reached a given size in bytes.
.. bro:attr:: &encrypt
Encrypts files right before writing them to disk.
.. bro:attr:: &raw_output
Opens a file in raw mode, i.e., non-ASCII characters are not
escaped.
.. bro:attr:: &mergeable
Prefers merging sets on assignment for synchronized state. This
attribute is used in conjunction with :bro:attr:`&synchronized`
container types: when the same container is updated at two peers
with different values, the propagation of the state causes a race
condition, where the last update succeeds. This can cause
inconsistencies and can be avoided by unifying the two sets, rather
than merely overwriting the old value.
.. bro:attr:: &group
Groups event handlers such that those in the same group can be
jointly activated or deactivated.
.. bro:attr:: &error_handler
Internally set on the events that are associated with the reporter
framework: :bro:id:`reporter_info`, :bro:id:`reporter_warning`, and
:bro:id:`reporter_error`. It prevents any handlers of those events
from being able to generate reporter messages that go through any of
those events (i.e., it prevents an infinite event recursion). Instead,
such nested reporter messages are output to stderr.
.. bro:attr:: &type_column
Used by the input framework. It can be used on columns of type
:bro:type:`port` (such a column only contains the port number) and
specifies the name of an additional column in
the input file which specifies the protocol of the port (tcp/udp/icmp).
In the following example, the input file would contain four columns
named "ip", "srcp", "proto", and "msg"::
type Idx: record {
ip: addr;
};
type Val: record {
srcp: port &type_column = "proto";
msg: string;
};

View file

@ -0,0 +1,173 @@
Directives
==========
The Bro scripting language supports a number of directives that can
affect which scripts will be loaded or which lines in a script will be
executed. Directives are evaluated before script execution begins.
.. bro:keyword:: @DEBUG
TODO
.. bro:keyword:: @DIR
Expands to the directory pathname where the current script is located.
Example::
print "Directory:", @DIR;
.. bro:keyword:: @FILENAME
Expands to the filename of the current script.
Example::
print "File:", @FILENAME;
.. bro:keyword:: @load
Loads the specified Bro script, specified as the relative pathname
of the file (relative to one of the directories in Bro's file search path).
If the Bro script filename ends with ".bro", then you don't need to
specify the file extension. The filename cannot contain any whitespace.
In this example, Bro will try to load a script
"policy/misc/capture-loss.bro" by looking in each directory in the file
search path (the file search path can be changed by setting the BROPATH
environment variable)::
@load policy/misc/capture-loss
If you specify the name of a directory instead of a filename, then
Bro will try to load a file in that directory called "__load__.bro"
(presumably that file will contain additional "@load" directives).
In this example, Bro will try to load a file "tuning/defaults/__load__.bro"
by looking in each directory in the file search path::
@load tuning/defaults
The purpose of this directive is to ensure that all script dependencies
are satisfied, and to avoid having to list every needed Bro script
on the command-line. Bro keeps track of which scripts have been
loaded, so it is not an error to load a script more than once (once
a script has been loaded, any subsequent "@load" directives
for that script are ignored).
.. bro:keyword:: @load-sigs
This works similarly to "@load", except that in this case the filename
represents a signature file (not a Bro script). If the signature filename
ends with ".sig", then you don't need to specify the file extension
in the "@load-sigs" directive. The filename cannot contain any
whitespace.
In this example, Bro will try to load a signature file
"base/protocols/ssl/dpd.sig"::
@load-sigs base/protocols/ssl/dpd
The format for a signature file is explained in the documentation for the
`Signature Framework <../frameworks/signatures.html>`_.
.. bro:keyword:: @unload
This specifies a Bro script that we don't want to load (so a subsequent
attempt to load the specified script will be skipped). However,
if the specified script has already been loaded, then this directive
has no affect.
In the following example, if the "policy/misc/capture-loss.bro" script
has not been loaded yet, then Bro will not load it::
@unload policy/misc/capture-loss
.. bro:keyword:: @prefixes
Specifies a filename prefix to use when looking for script files
to load automatically. The prefix cannot contain any whitespace.
In the following example, the prefix "cluster" is used and all prefixes
that were previously specified are not used::
@prefixes = cluster
In the following example, the prefix "cluster-manager" is used in
addition to any previously-specified prefixes::
@prefixes += cluster-manager
The way this works is that after Bro parses all script files, then for each
loaded script Bro will take the absolute path of the script and then
it removes the portion of the directory path that is in Bro's file
search path. Then it replaces each "/" character with a period "."
and then prepends the prefix (specified in the "@prefixes" directive)
followed by a period. The resulting filename is searched for in each
directory in Bro's file search path. If a matching file is found, then
the file is automatically loaded.
For example, if a script called "local.bro" has been loaded, and a prefix
of "test" was specified, then Bro will look for a file named
"test.local.bro" in each directory of Bro's file search path.
An alternative way to specify prefixes is to use the "-p" Bro
command-line option.
.. bro:keyword:: @if
The specified expression must evaluate to type :bro:type:`bool`. If the
value is true, then the following script lines (up to the next "@else"
or "@endif") are available to be executed.
Example::
@if ( ver == 2 )
print "version 2 detected";
@endif
.. bro:keyword:: @ifdef
This works like "@if", except that the result is true if the specified
identifier is defined.
Example::
@ifdef ( pi )
print "pi is defined";
@endif
.. bro:keyword:: @ifndef
This works exactly like "@ifdef", except that the result is true if the
specified identifier is not defined.
Example::
@ifndef ( pi )
print "pi is not defined";
@endif
.. bro:keyword:: @else
This directive is optional after an "@if", "@ifdef", or
"@ifndef". If present, it provides an else clause.
Example::
@ifdef ( pi )
print "pi is defined";
@else
print "pi is not defined";
@endif
.. bro:keyword:: @endif
This directive is required to terminate each "@if", "@ifdef", or
"@ifndef".

View file

@ -5,10 +5,17 @@ Script Reference
.. toctree::
:maxdepth: 1
operators
types
attributes
statements
directives
log-files
notices
proto-analyzers
file-analyzers
builtins
packages
scripts
Broxygen Example Script </scripts/broxygen/example.bro>

View file

@ -0,0 +1,148 @@
=========
Log Files
=========
Listed below are the log files generated by Bro, including a brief description
of the log file and links to descriptions of the fields for each log
type.
Network Protocols
-----------------
+----------------------------+---------------------------------------+---------------------------------+
| Log File | Description | Field Descriptions |
+============================+=======================================+=================================+
| conn.log | TCP/UDP/ICMP connections | :bro:type:`Conn::Info` |
+----------------------------+---------------------------------------+---------------------------------+
| dhcp.log | DHCP leases | :bro:type:`DHCP::Info` |
+----------------------------+---------------------------------------+---------------------------------+
| dnp3.log | DNP3 requests and replies | :bro:type:`DNP3::Info` |
+----------------------------+---------------------------------------+---------------------------------+
| dns.log | DNS activity | :bro:type:`DNS::Info` |
+----------------------------+---------------------------------------+---------------------------------+
| ftp.log | FTP activity | :bro:type:`FTP::Info` |
+----------------------------+---------------------------------------+---------------------------------+
| http.log | HTTP requests and replies | :bro:type:`HTTP::Info` |
+----------------------------+---------------------------------------+---------------------------------+
| irc.log | IRC commands and responses | :bro:type:`IRC::Info` |
+----------------------------+---------------------------------------+---------------------------------+
| modbus.log | Modbus commands and responses | :bro:type:`Modbus::Info` |
+----------------------------+---------------------------------------+---------------------------------+
| modbus_register_change.log | Tracks changes to Modbus holding | :bro:type:`Modbus::MemmapInfo` |
| | registers | |
+----------------------------+---------------------------------------+---------------------------------+
| radius.log | RADIUS authentication attempts | :bro:type:`RADIUS::Info` |
+----------------------------+---------------------------------------+---------------------------------+
| smtp.log | SMTP transactions | :bro:type:`SMTP::Info` |
+----------------------------+---------------------------------------+---------------------------------+
| snmp.log | SNMP messages | :bro:type:`SNMP::Info` |
+----------------------------+---------------------------------------+---------------------------------+
| socks.log | SOCKS proxy requests | :bro:type:`SOCKS::Info` |
+----------------------------+---------------------------------------+---------------------------------+
| ssh.log | SSH connections | :bro:type:`SSH::Info` |
+----------------------------+---------------------------------------+---------------------------------+
| ssl.log | SSL/TLS handshake info | :bro:type:`SSL::Info` |
+----------------------------+---------------------------------------+---------------------------------+
| syslog.log | Syslog messages | :bro:type:`Syslog::Info` |
+----------------------------+---------------------------------------+---------------------------------+
| tunnel.log | Tunneling protocol events | :bro:type:`Tunnel::Info` |
+----------------------------+---------------------------------------+---------------------------------+
Files
-----
+----------------------------+---------------------------------------+---------------------------------+
| Log File | Description | Field Descriptions |
+============================+=======================================+=================================+
| files.log | File analysis results | :bro:type:`Files::Info` |
+----------------------------+---------------------------------------+---------------------------------+
| x509.log | X.509 certificate info | :bro:type:`X509::Info` |
+----------------------------+---------------------------------------+---------------------------------+
Detection
---------
+----------------------------+---------------------------------------+---------------------------------+
| Log File | Description | Field Descriptions |
+============================+=======================================+=================================+
| intel.log | Intelligence data matches | :bro:type:`Intel::Info` |
+----------------------------+---------------------------------------+---------------------------------+
| notice.log | Bro notices | :bro:type:`Notice::Info` |
+----------------------------+---------------------------------------+---------------------------------+
| notice_alarm.log | The alarm stream | :bro:enum:`Notice::ACTION_ALARM`|
+----------------------------+---------------------------------------+---------------------------------+
| signatures.log | Signature matches | :bro:type:`Signatures::Info` |
+----------------------------+---------------------------------------+---------------------------------+
| traceroute.log | Traceroute detection | :bro:type:`Traceroute::Info` |
+----------------------------+---------------------------------------+---------------------------------+
Network Observations
--------------------
+----------------------------+---------------------------------------+---------------------------------+
| Log File | Description | Field Descriptions |
+============================+=======================================+=================================+
| app_stats.log | Web app usage statistics | :bro:type:`AppStats::Info` |
+----------------------------+---------------------------------------+---------------------------------+
| known_certs.log | SSL certificates | :bro:type:`Known::CertsInfo` |
+----------------------------+---------------------------------------+---------------------------------+
| known_devices.log | MAC addresses of devices on the | :bro:type:`Known::DevicesInfo` |
| | network | |
+----------------------------+---------------------------------------+---------------------------------+
| known_hosts.log | Hosts that have completed TCP | :bro:type:`Known::HostsInfo` |
| | handshakes | |
+----------------------------+---------------------------------------+---------------------------------+
| known_modbus.log | Modbus masters and slaves | :bro:type:`Known::ModbusInfo` |
+----------------------------+---------------------------------------+---------------------------------+
| known_services.log | Services running on hosts | :bro:type:`Known::ServicesInfo` |
+----------------------------+---------------------------------------+---------------------------------+
| software.log | Software being used on the network | :bro:type:`Software::Info` |
+----------------------------+---------------------------------------+---------------------------------+
Miscellaneous
-------------
+----------------------------+---------------------------------------+---------------------------------+
| Log File | Description | Field Descriptions |
+============================+=======================================+=================================+
| barnyard2.log | Alerts received from Barnyard2 | :bro:type:`Barnyard2::Info` |
+----------------------------+---------------------------------------+---------------------------------+
| dpd.log | Dynamic protocol detection failures | :bro:type:`DPD::Info` |
+----------------------------+---------------------------------------+---------------------------------+
| unified2.log | Interprets Snort's unified output | :bro:type:`Unified2::Info` |
+----------------------------+---------------------------------------+---------------------------------+
| weird.log | Unexpected network-level activity | :bro:type:`Weird::Info` |
+----------------------------+---------------------------------------+---------------------------------+
Bro Diagnostics
---------------
+----------------------------+---------------------------------------+---------------------------------+
| Log File | Description | Field Descriptions |
+============================+=======================================+=================================+
| capture_loss.log | Packet loss rate | :bro:type:`CaptureLoss::Info` |
+----------------------------+---------------------------------------+---------------------------------+
| cluster.log | Bro cluster messages | :bro:type:`Cluster::Info` |
+----------------------------+---------------------------------------+---------------------------------+
| communication.log | Communication events between Bro or | :bro:type:`Communication::Info` |
| | Broccoli instances | |
+----------------------------+---------------------------------------+---------------------------------+
| loaded_scripts.log | Shows all scripts loaded by Bro | :bro:type:`LoadedScripts::Info` |
+----------------------------+---------------------------------------+---------------------------------+
| packet_filter.log | List packet filters that were applied | :bro:type:`PacketFilter::Info` |
+----------------------------+---------------------------------------+---------------------------------+
| prof.log | Profiling statistics (to create this | N/A |
| | log, load policy/misc/profiling.bro) | |
+----------------------------+---------------------------------------+---------------------------------+
| reporter.log | Internal error/warning/info messages | :bro:type:`Reporter::Info` |
+----------------------------+---------------------------------------+---------------------------------+
| stats.log | Memory/event/packet/lag statistics | :bro:type:`Stats::Info` |
+----------------------------+---------------------------------------+---------------------------------+
| stderr.log | Captures standard error when Bro is | N/A |
| | started from BroControl | |
+----------------------------+---------------------------------------+---------------------------------+
| stdout.log | Captures standard output when Bro is | N/A |
| | started from BroControl | |
+----------------------------+---------------------------------------+---------------------------------+

View file

@ -0,0 +1,191 @@
Operators
=========
The Bro scripting language supports the following operators. Note that
each data type only supports a subset of these operators. For more
details, see the documentation about the `data types <types.html>`_.
Relational operators
--------------------
The relational operators evaluate to type :bro:type:`bool`.
+------------------------------+--------------+
| Name | Syntax |
+==============================+==============+
| Equality | *a* == *b* |
+------------------------------+--------------+
| Inequality | *a* != *b* |
+------------------------------+--------------+
| Less than | *a* < *b* |
+------------------------------+--------------+
| Less than or equal | *a* <= *b* |
+------------------------------+--------------+
| Greater than | *a* > *b* |
+------------------------------+--------------+
| Greater than or equal | *a* >= *b* |
+------------------------------+--------------+
Logical operators
-----------------
The logical operators require operands of type :bro:type:`bool`, and
evaluate to type :bro:type:`bool`.
+------------------------------+--------------+
| Name | Syntax |
+==============================+==============+
| Logical AND | *a* && *b* |
+------------------------------+--------------+
| Logical OR | *a* \|\| *b* |
+------------------------------+--------------+
| Logical NOT | ! *a* |
+------------------------------+--------------+
Arithmetic operators
--------------------
+------------------------------+-------------+-------------------------------+
| Name | Syntax | Notes |
+==============================+=============+===============================+
| Addition | *a* + *b* | For :bro:type:`string` |
| | | operands, this performs |
| | | string concatenation. |
+------------------------------+-------------+-------------------------------+
| Subtraction | *a* - *b* | |
+------------------------------+-------------+-------------------------------+
| Multiplication | *a* \* *b* | |
+------------------------------+-------------+-------------------------------+
| Division | *a* / *b* | For :bro:type:`int` or |
| | | :bro:type:`count` operands, |
| | | the fractional part of the |
| | | result is dropped. |
+------------------------------+-------------+-------------------------------+
| Modulo | *a* % *b* | Operand types cannot be |
| | | "double". |
+------------------------------+-------------+-------------------------------+
| Unary plus | \+ *a* | |
+------------------------------+-------------+-------------------------------+
| Unary minus | \- *a* | |
+------------------------------+-------------+-------------------------------+
| Pre-increment | ++ *a* | Operand type cannot be |
| | | "double". |
+------------------------------+-------------+-------------------------------+
| Pre-decrement | ``--`` *a* | Operand type cannot be |
| | | "double". |
+------------------------------+-------------+-------------------------------+
| Absolute value | \| *a* \| | If operand is |
| | | :bro:type:`string`, |
| | | :bro:type:`set`, |
| | | :bro:type:`table`, or |
| | | :bro:type:`vector`, this |
| | | evaluates to number |
| | | of elements. |
+------------------------------+-------------+-------------------------------+
Assignment operators
--------------------
The assignment operators evaluate to the result of the assignment.
+------------------------------+-------------+
| Name | Syntax |
+==============================+=============+
| Assignment | *a* = *b* |
+------------------------------+-------------+
| Addition assignment | *a* += *b* |
+------------------------------+-------------+
| Subtraction assignment | *a* -= *b* |
+------------------------------+-------------+
Record field operators
----------------------
The record field operators take a :bro:type:`record` as the first operand,
and a field name as the second operand. For both operators, the specified
field name must be in the declaration of the record type.
+------------------------------+-------------+-------------------------------+
| Name | Syntax | Notes |
+==============================+=============+===============================+
| Field access | *a* $ *b* | |
+------------------------------+-------------+-------------------------------+
| Field value existence test | *a* ?$ *b* | Evaluates to type |
| | | :bro:type:`bool`. |
| | | True if the specified field |
| | | has been assigned a value, or |
| | | false if not. |
+------------------------------+-------------+-------------------------------+
Other operators
---------------
+--------------------------------+-------------------+------------------------+
| Name | Syntax | Notes |
+================================+===================+========================+
| Membership test | *a* in *b* |Evaluates to type |
| | |:bro:type:`bool`. Do not|
| | |confuse this use of "in"|
| | |with that used in a |
| | |:bro:keyword:`for` |
| | |statement. |
+--------------------------------+-------------------+------------------------+
| Non-membership test | *a* !in *b* |This is the logical NOT |
| | |of the "in" operator. |
| | |For example: "a !in b" |
| | |is equivalent to |
| | |"!(a in b)". |
+--------------------------------+-------------------+------------------------+
| Table or vector element access | *a* [ *b* ] |This operator can also |
| | |be used with a |
| | |:bro:type:`set`, but |
| | |only with the |
| | |:bro:keyword:`add` or |
| | |:bro:keyword:`delete` |
| | |statement. |
+--------------------------------+-------------------+------------------------+
| Substring extraction | *a* [ *b* : *c* ] |See the |
| | |:bro:type:`string` type |
| | |for more details. |
+--------------------------------+-------------------+------------------------+
| Create a deep copy | copy ( *a* ) |This is relevant only |
| | |for data types that are |
| | |assigned by reference, |
| | |such as |
| | |:bro:type:`vector`, |
| | |:bro:type:`set`, |
| | |:bro:type:`table`, |
| | |and :bro:type:`record`. |
+--------------------------------+-------------------+------------------------+
| Module namespace access | *a* \:\: *b* |The first operand is the|
| | |module name, and the |
| | |second operand is an |
| | |identifier that refers |
| | |to a global variable, |
| | |enumeration constant, or|
| | |user-defined type that |
| | |was exported from the |
| | |module. |
+--------------------------------+-------------------+------------------------+
| Conditional | *a* ? *b* : *c* |The first operand must |
| | |evaluate to type |
| | |:bro:type:`bool`. |
| | |If true, then the |
| | |second expression is |
| | |evaluated and is the |
| | |result of the entire |
| | |expression. Otherwise, |
| | |the third expression is |
| | |evaluated and is the |
| | |result of the entire |
| | |expression. The types of|
| | |the second and third |
| | |operands must be |
| | |compatible. |
+--------------------------------+-------------------+------------------------+

View file

@ -0,0 +1,602 @@
Declarations and Statements
===========================
The Bro scripting language supports the following declarations and
statements.
Declarations
~~~~~~~~~~~~
+----------------------------+-----------------------------+
| Name | Description |
+============================+=============================+
| :bro:keyword:`module` | Change the current module |
+----------------------------+-----------------------------+
| :bro:keyword:`export` | Export identifiers from the |
| | current module |
+----------------------------+-----------------------------+
| :bro:keyword:`global` | Declare a global variable |
+----------------------------+-----------------------------+
| :bro:keyword:`const` | Declare a constant |
+----------------------------+-----------------------------+
| :bro:keyword:`type` | Declare a user-defined type |
+----------------------------+-----------------------------+
| :bro:keyword:`redef` | Redefine a global value or |
| | extend a user-defined type |
+----------------------------+-----------------------------+
| `function/event/hook`_ | Declare a function, event |
| | handler, or hook |
+----------------------------+-----------------------------+
Statements
~~~~~~~~~~
+----------------------------+------------------------+
| Name | Description |
+============================+========================+
| :bro:keyword:`local` | Declare a local |
| | variable |
+----------------------------+------------------------+
| :bro:keyword:`add`, | Add or delete |
| :bro:keyword:`delete` | elements |
+----------------------------+------------------------+
| :bro:keyword:`print` | Print to stdout or a |
| | file |
+----------------------------+------------------------+
| :bro:keyword:`for`, | Loop over each |
| :bro:keyword:`next`, | element in a container |
| :bro:keyword:`break` | object |
+----------------------------+------------------------+
| :bro:keyword:`if` | Evaluate boolean |
| | expression and if true,|
| | execute a statement |
+----------------------------+------------------------+
| :bro:keyword:`switch`, | Evaluate expression |
| :bro:keyword:`break`, | and execute statement |
| :bro:keyword:`fallthrough` | with a matching value |
+----------------------------+------------------------+
| :bro:keyword:`when` | Asynchronous execution |
+----------------------------+------------------------+
| :bro:keyword:`event`, | Invoke or schedule |
| :bro:keyword:`schedule` | an event handler |
+----------------------------+------------------------+
| :bro:keyword:`return` | Return from function, |
| | hook, or event handler |
+----------------------------+------------------------+
Declarations
------------
The following global declarations cannot occur within a function, hook, or
event handler. Also, these declarations cannot appear after any statements
that are outside of a function, hook, or event handler.
.. bro:keyword:: module
The "module" keyword is used to change the current module. This
affects the scope of any subsequently declared global identifiers.
Example::
module mymodule;
If a global identifier is declared after a "module" declaration,
then its scope ends at the end of the current Bro script or at the
next "module" declaration, whichever comes first. However, if a
global identifier is declared after a "module" declaration, but inside
an :bro:keyword:`export` block, then its scope ends at the end of the
last loaded Bro script, but it must be referenced using the namespace
operator (``::``) in other modules.
There can be any number of "module" declarations in a Bro script.
The same "module" declaration can appear in any number of different
Bro scripts.
.. bro:keyword:: export
An "export" block contains one or more declarations
(no statements are allowed in an "export" block) that the current
module is exporting. This enables these global identifiers to be visible
in other modules (but not prior to their declaration) via the namespace
operator (``::``). See the :bro:keyword:`module` keyword for a more
detailed explanation.
Example::
export {
redef enum Log::ID += { LOG };
type Info: record {
ts: time &log;
uid: string &log;
};
const conntime = 30sec &redef;
}
Note that the braces in an "export" block are always required
(they do not indicate a compound statement). Also, no semicolon is
needed to terminate an "export" block.
.. bro:keyword:: global
Variables declared with the "global" keyword will be global.
If a type is not specified, then an initializer is required so that
the type can be inferred. Likewise, if an initializer is not supplied,
then the type must be specified. Example::
global pi = 3.14;
global hosts: set[addr];
global ciphers: table[string] of string = table();
Variable declarations outside of any function, hook, or event handler are
required to use this keyword (unless they are declared with the
:bro:keyword:`const` keyword). Definitions of functions, hooks, and
event handlers are not allowed to use the "global"
keyword (they already have global scope), except function declarations
where no function body is supplied use the "global" keyword.
The scope of a global variable begins where the declaration is located,
and extends through all remaining Bro scripts that are loaded (however,
see the :bro:keyword:`module` keyword for an explanation of how modules
change the visibility of global identifiers).
.. bro:keyword:: const
A variable declared with the "const" keyword will be constant.
Variables declared as constant are required to be initialized at the
time of declaration. Example::
const pi = 3.14;
const ssh_port: port = 22/tcp;
The value of a constant cannot be changed later (the only
exception is if the variable is global and has the :bro:attr:`&redef`
attribute, then its value can be changed only with a :bro:keyword:`redef`).
The scope of a constant is local if the declaration is in a
function, hook, or event handler, and global otherwise.
Note that the "const" keyword cannot be used with either the "local"
or "global" keywords (i.e., "const" replaces "local" and "global").
.. bro:keyword:: type
The "type" keyword is used to declare a user-defined type. The name
of this new type has global scope and can be used anywhere a built-in
type name can occur.
The "type" keyword is most commonly used when defining a
:bro:type:`record` or an :bro:type:`enum`, but is also useful when
dealing with more complex types.
Example::
type mytype: table[count] of table[addr, port] of string;
global myvar: mytype;
.. bro:keyword:: redef
There are three ways that "redef" can be used: to change the value of
a global variable, to extend a record type or enum type, or to specify
a new event handler body that replaces all those that were previously
defined.
If you're using "redef" to change a global variable (defined using either
:bro:keyword:`const` or :bro:keyword:`global`), then the variable that you
want to change must have the :bro:attr:`&redef` attribute. If the variable
you're changing is a table, set, or pattern, you can use ``+=`` to add
new elements, or you can use ``=`` to specify a new value (all previous
contents of the object are removed). If the variable you're changing is a
set or table, then you can use the ``-=`` operator to remove the
specified elements (nothing happens for specified elements that don't
exist). If the variable you are changing is not a table, set, or pattern,
then you must use the ``=`` operator.
Examples::
redef pi = 3.14;
If you're using "redef" to extend a record or enum, then you must
use the ``+=`` assignment operator.
For an enum, you can add more enumeration constants, and for a record
you can add more record fields (however, each record field in the "redef"
must have either the :bro:attr:`&optional` or :bro:attr:`&default`
attribute).
Examples::
redef enum color += { Blue, Red };
redef record MyRecord += { n2:int &optional; s2:string &optional; };
If you're using "redef" to specify a new event handler body that
replaces all those that were previously defined (i.e., any subsequently
defined event handler body will not be affected by this "redef"), then
the syntax is the same as a regular event handler definition except for
the presence of the "redef" keyword.
Example::
redef event myevent(s:string) { print "Redefined", s; }
.. _function/event/hook:
**function/event/hook**
For details on how to declare a :bro:type:`function`,
:bro:type:`event` handler, or :bro:type:`hook`,
see the documentation for those types.
Statements
----------
Each statement in a Bro script must be terminated with a semicolon (with a
few exceptions noted below). An individual statement can span multiple
lines.
All statements (except those contained within a function, hook, or event
handler) must appear after all global declarations.
Here are the statements that the Bro scripting language supports.
.. bro:keyword:: add
The "add" statement is used to add an element to a :bro:type:`set`.
Nothing happens if the specified element already exists in the set.
Example::
local myset: set[string];
add myset["test"];
.. bro:keyword:: break
The "break" statement is used to break out of a :bro:keyword:`switch` or
:bro:keyword:`for` statement.
.. bro:keyword:: delete
The "delete" statement is used to remove an element from a
:bro:type:`set` or :bro:type:`table`. Nothing happens if the
specified element does not exist in the set or table.
Example::
local myset = set("this", "test");
local mytable = table(["key1"] = 80/tcp, ["key2"] = 53/udp);
delete myset["test"];
delete mytable["key1"];
.. bro:keyword:: event
The "event" statement immediately queues invocation of an event handler.
Example::
event myevent("test", 5);
.. bro:keyword:: fallthrough
The "fallthrough" statement can be used as the last statement in a
"case" block to indicate that execution should continue into the
next "case" or "default" label.
For an example, see the :bro:keyword:`switch` statement.
.. bro:keyword:: for
A "for" loop iterates over each element in a string, set, vector, or
table and executes a statement for each iteration.
For each iteration of the loop, a loop variable will be assigned to an
element if the expression evaluates to a string or set, or an index if
the expression evaluates to a vector or table. Then the statement
is executed. However, the statement will not be executed if the expression
evaluates to an object with no elements.
If the expression is a table or a set with more than one index, then the
loop variable must be specified as a comma-separated list of different
loop variables (one for each index), enclosed in brackets.
A :bro:keyword:`break` statement can be used at any time to immediately
terminate the "for" loop, and a :bro:keyword:`next` statement can be
used to skip to the next loop iteration.
Note that the loop variable in a "for" statement is not allowed to be
a global variable, and it does not need to be declared prior to the "for"
statement. The type will be inferred from the elements of the
expression.
Example::
local myset = set(80/tcp, 81/tcp);
local mytable = table([10.0.0.1, 80/tcp]="s1", [10.0.0.2, 81/tcp]="s2");
for (p in myset)
print p;
for ([i,j] in mytable) {
if (mytable[i,j] == "done")
break;
if (mytable[i,j] == "skip")
next;
print i,j;
}
.. bro:keyword:: if
Evaluates a given expression, which must yield a :bro:type:`bool` value.
If true, then a specified statement is executed. If false, then
the statement is not executed. Example::
if ( x == 2 ) print "x is 2";
However, if the expression evaluates to false and if an "else" is
provided, then the statement following the "else" is executed. Example::
if ( x == 2 )
print "x is 2";
else
print "x is not 2";
.. bro:keyword:: local
A variable declared with the "local" keyword will be local. If a type
is not specified, then an initializer is required so that the type can
be inferred. Likewise, if an initializer is not supplied, then the
type must be specified.
Examples::
local x1 = 5.7;
local x2: double;
local x3: double = 5.7;
Variable declarations inside a function, hook, or event handler are
required to use this keyword (the only two exceptions are variables
declared with :bro:keyword:`const`, and variables implicitly declared in a
:bro:keyword:`for` statement).
The scope of a local variable starts at the location where it is declared
and persists to the end of the function, hook,
or event handler in which it is declared (this is true even if the
local variable was declared within a `compound statement`_ or is the loop
variable in a "for" statement).
.. bro:keyword:: next
The "next" statement can only appear within a :bro:keyword:`for` loop.
It causes execution to skip to the next iteration.
For an example, see the :bro:keyword:`for` statement.
.. bro:keyword:: print
The "print" statement takes a comma-separated list of one or more
expressions. Each expression in the list is evaluated and then converted
to a string. Then each string is printed, with each string separated by
a comma in the output.
Examples::
print 3.14;
print "Results", x, y;
By default, the "print" statement writes to the standard
output (stdout). However, if the first expression is of type
:bro:type:`file`, then "print" writes to that file.
If a string contains non-printable characters (i.e., byte values that are
not in the range 32 - 126), then the "print" statement converts each
non-printable character to an escape sequence before it is printed.
For more control over how the strings are formatted, see the :bro:id:`fmt`
function.
.. bro:keyword:: return
The "return" statement immediately exits the current function, hook, or
event handler. For a function, the specified expression (if any) is
evaluated and returned. A "return" statement in a hook or event handler
cannot return a value because event handlers and hooks do not have
return types.
Examples::
function my_func(): string
{
return "done";
}
event my_event(n: count)
{
if ( n == 0 ) return;
print n;
}
There is a special form of the "return" statement that is only allowed
in functions. Syntactically, it looks like a :bro:keyword:`when` statement
immediately preceded by the "return" keyword. This form of the "return"
statement is used to specify a function that delays its result (such a
function can only be called in the expression of a :bro:keyword:`when`
statement). The function returns at the time the "when"
statement's condition becomes true, and the function returns the value
that the "when" statement's body returns (or if the condition does
not become true within the specified timeout interval, then the function
returns the value that the "timeout" block returns).
Example::
global X: table[string] of count;
function a() : count
{
# This delays until condition becomes true.
return when ( "a" in X )
{
return X["a"];
}
timeout 30 sec
{
return 0;
}
}
event bro_init()
{
# Installs a trigger which fires if a() returns 42.
when ( a() == 42 )
print "expected result";
print "Waiting for a() to return...";
X["a"] = 42;
}
.. bro:keyword:: schedule
The "schedule" statement is used to raise a specified event with
specified parameters at a later time specified as an :bro:type:`interval`.
Example::
schedule 30sec { myevent(x, y, z) };
Note that the braces are always required (they do not indicate a
`compound statement`_).
Note that "schedule" is actually an expression that returns a value
of type "timer", but in practice the return value is not used.
.. bro:keyword:: switch
A "switch" statement evaluates a given expression and jumps to
the first "case" label which contains a matching value (the result of the
expression must be type-compatible with all of the values in all of the
"case" labels). If there is no matching value, then execution jumps to
the "default" label instead, and if there is no "default" label then
execution jumps out of the "switch" block.
Here is an example (assuming that "get_day_of_week" is a
function that returns a string)::
switch get_day_of_week()
{
case "Sa", "Su":
print "weekend";
fallthrough;
case "Mo", "Tu", "We", "Th", "Fr":
print "valid result";
break;
default:
print "invalid result";
break;
}
A "switch" block can have any number of "case" labels, and one
optional "default" label.
A "case" label can have a comma-separated list of
more than one value. A value in a "case" label can be an expression,
but it must be a constant expression (i.e., the expression can consist
only of constants).
Each "case" and the "default" block must
end with either a :bro:keyword:`break`, :bro:keyword:`fallthrough`, or
:bro:keyword:`return` statement (although "return" is allowed only
if the "switch" statement is inside a function, hook, or event handler).
If a "case" (or "default") block contain more than one statement, then
there is no need to wrap them in braces.
Note that the braces in a "switch" statement are always required (these
do not indicate the presence of a `compound statement`_), and that no
semicolon is needed at the end of a "switch" statement.
.. bro:keyword:: when
Evaluates a given expression, which must result in a value of type
:bro:type:`bool`. When the value of the expression becomes available
and if the result is true, then a specified statement is executed.
In the following example, if the expression evaluates to true, then
the "print" statement is executed::
when ( (local x = foo()) && x == 42 )
print x;
However, if a timeout is specified, and if the expression does not
evaluate to true within the specified timeout interval, then the
statement following the "timeout" keyword is executed::
when ( (local x = foo()) && x == 42 )
print x;
timeout 5sec {
print "timeout";
}
Note that when a timeout is specified the braces are
always required (these do not indicate a `compound statement`_).
The expression in a "when" statement can contain a declaration of a local
variable but only if the declaration is written in the form
"local *var* = *init*" (example: "local x = myfunction()"). This form
of a local declaration is actually an expression, the result of which
is always a boolean true value.
The expression in a "when" statement can contain an asynchronous function
call such as :bro:id:`lookup_hostname` (in fact, this is the only place
such a function can be called), but it can also contain an ordinary
function call. When an asynchronous function call is in the expression,
then Bro will continue processing statements in the script following
the "when" statement, and when the result of the function call is available
Bro will finish evaluating the expression in the "when" statement.
See the :bro:keyword:`return` statement for an explanation of how to
create an asynchronous function in a Bro script.
.. _compound statement:
**compound statement**
A compound statement is created by wrapping zero or more statements in
braces ``{ }``. Individual statements inside the braces need to be
terminated by a semicolon, but a semicolon is not needed at the end
(outside of the braces) of a compound statement.
A compound statement is required in order to execute more than one
statement in the body of a :bro:keyword:`for`, :bro:keyword:`if`, or
:bro:keyword:`when` statement.
Example::
if ( x == 2 ) {
print "x is 2";
++x;
}
Note that there are other places in the Bro scripting language that use
braces, but that do not indicate the presence of a compound
statement (these are noted in the documentation).
.. _null:
**null statement**
The null statement (executing it has no effect) consists of just a
semicolon. This might be useful during testing or debugging a Bro script
in places where a statement is required, but it is probably not useful
otherwise.
Example::
if ( x == 2 )
;

View file

@ -1,92 +1,114 @@
Types and Attributes
====================
Types
-----
=====
Every value in a Bro script has a type (see below for a list of all built-in
types). Although Bro variables have static types (meaning that their type
is fixed), their type is inferred from the value to which they are
initially assigned when the variable is declared without an explicit type
name.
The Bro scripting language supports the following built-in types:
Automatic conversions happen when a binary operator has operands of
different types. Automatic conversions are limited to converting between
numeric types. The numeric types are ``int``, ``count``, and ``double``
(``bool`` is not a numeric type).
When an automatic conversion occurs, values are promoted to the "highest"
type in the expression. In general, this promotion follows a simple
hierarchy: ``double`` is highest, ``int`` comes next, and ``count`` is
lowest.
+-----------------------+--------------------+
| Name | Description |
+=======================+====================+
| :bro:type:`bool` | Boolean |
+-----------------------+--------------------+
| :bro:type:`count`, | Numeric types |
| :bro:type:`int`, | |
| :bro:type:`double` | |
+-----------------------+--------------------+
| :bro:type:`time`, | Time types |
| :bro:type:`interval` | |
+-----------------------+--------------------+
| :bro:type:`string` | String |
+-----------------------+--------------------+
| :bro:type:`pattern` | Regular expression |
+-----------------------+--------------------+
| :bro:type:`port`, | Network types |
| :bro:type:`addr`, | |
| :bro:type:`subnet` | |
+-----------------------+--------------------+
| :bro:type:`enum` | Enumeration |
| | (user-defined type)|
+-----------------------+--------------------+
| :bro:type:`table`, | Container types |
| :bro:type:`set`, | |
| :bro:type:`vector`, | |
| :bro:type:`record` | |
+-----------------------+--------------------+
| :bro:type:`function`, | Executable types |
| :bro:type:`event`, | |
| :bro:type:`hook` | |
+-----------------------+--------------------+
| :bro:type:`file` | File type (only |
| | for writing) |
+-----------------------+--------------------+
| :bro:type:`opaque` | Opaque type (for |
| | some built-in |
| | functions) |
+-----------------------+--------------------+
| :bro:type:`any` | Any type (for |
| | functions or |
| | containers) |
+-----------------------+--------------------+
The Bro scripting language supports the following built-in types.
.. bro:type:: void
An internal Bro type (i.e., "void" is not a reserved keyword in the Bro
scripting language) representing the absence of a return type for a
function.
Here is a more detailed description of each type:
.. bro:type:: bool
Reflects a value with one of two meanings: true or false. The two
``bool`` constants are ``T`` and ``F``.
"bool" constants are ``T`` and ``F``.
The ``bool`` type supports the following operators: equality/inequality
The "bool" type supports the following operators: equality/inequality
(``==``, ``!=``), logical and/or (``&&``, ``||``), logical
negation (``!``), and absolute value (where ``|T|`` is 1, and ``|F|`` is 0).
negation (``!``), and absolute value (where ``|T|`` is 1, and ``|F|`` is 0,
and in both cases the result type is :bro:type:`count`).
.. bro:type:: int
A numeric type representing a 64-bit signed integer. An ``int`` constant
is a string of digits preceded by a ``+`` or ``-`` sign, e.g.
A numeric type representing a 64-bit signed integer. An "int" constant
is a string of digits preceded by a "+" or "-" sign, e.g.
``-42`` or ``+5`` (the "+" sign is optional but see note about type
inferencing below). An ``int`` constant can also be written in
inferencing below). An "int" constant can also be written in
hexadecimal notation (in which case "0x" must be between the sign and
the hex digits), e.g. ``-0xFF`` or ``+0xabc123``.
The ``int`` type supports the following operators: arithmetic
The "int" type supports the following operators: arithmetic
operators (``+``, ``-``, ``*``, ``/``, ``%``), comparison operators
(``==``, ``!=``, ``<``, ``<=``, ``>``, ``>=``), assignment operators
(``=``, ``+=``, ``-=``), pre-increment (``++``), pre-decrement
(``--``), and absolute value (e.g., ``|-3|`` is 3).
(``--``), unary plus and minus (``+``, ``-``), and absolute value
(e.g., ``|-3|`` is 3, but the result type is :bro:type:`count`).
When using type inferencing use care so that the
intended type is inferred, e.g. ``local size_difference = 0`` will
infer :bro:type:`count`, while ``local size_difference = +0``
will infer :bro:type:`int`.
intended type is inferred, e.g. "local size_difference = 0" will
infer ":bro:type:`count`", while "local size_difference = +0"
will infer "int".
.. bro:type:: count
A numeric type representing a 64-bit unsigned integer. A ``count``
constant is a string of digits, e.g. ``1234`` or ``0``. A ``count``
A numeric type representing a 64-bit unsigned integer. A "count"
constant is a string of digits, e.g. ``1234`` or ``0``. A "count"
can also be written in hexadecimal notation (in which case "0x" must
precede the hex digits), e.g. ``0xff`` or ``0xABC123``.
The ``count`` type supports the same operators as the :bro:type:`int`
type. A unary plus or minus applied to a ``count`` results in an ``int``.
.. bro:type:: counter
An alias to :bro:type:`count`.
The "count" type supports the same operators as the ":bro:type:`int`"
type, but a unary plus or minus applied to a "count" results in an
"int".
.. bro:type:: double
A numeric type representing a double-precision floating-point
number. Floating-point constants are written as a string of digits
with an optional decimal point, optional scale-factor in scientific
notation, and optional ``+`` or ``-`` sign. Examples are ``-1234``,
notation, and optional "+" or "-" sign. Examples are ``-1234``,
``-1234e0``, ``3.14159``, and ``.003E-23``.
The ``double`` type supports the following operators: arithmetic
The "double" type supports the following operators: arithmetic
operators (``+``, ``-``, ``*``, ``/``), comparison operators
(``==``, ``!=``, ``<``, ``<=``, ``>``, ``>=``), assignment operators
(``=``, ``+=``, ``-=``), and absolute value (e.g., ``|-3.14|`` is 3.14).
(``=``, ``+=``, ``-=``), unary plus and minus (``+``, ``-``), and
absolute value (e.g., ``|-3.14|`` is 3.14).
When using type inferencing use care so that the
intended type is inferred, e.g. ``local size_difference = 5`` will
infer :bro:type:`count`, while ``local size_difference = 5.0``
will infer :bro:type:`double`.
intended type is inferred, e.g. "local size_difference = 5" will
infer ":bro:type:`count`", while "local size_difference = 5.0"
will infer "double".
.. bro:type:: time
@ -97,10 +119,10 @@ The Bro scripting language supports the following built-in types.
Time values support the comparison operators (``==``, ``!=``, ``<``,
``<=``, ``>``, ``>=``). A ``time`` value can be subtracted from
another ``time`` value to produce an ``interval`` value. An ``interval``
value can be added to, or subtracted from, a ``time`` value to produce a
``time`` value. The absolute value of a ``time`` value is a ``double``
with the same numeric value.
another ``time`` value to produce an :bro:type:`interval` value. An
``interval`` value can be added to, or subtracted from, a ``time`` value
to produce a ``time`` value. The absolute value of a ``time`` value is
a :bro:type:`double` with the same numeric value.
.. bro:type:: interval
@ -115,52 +137,58 @@ The Bro scripting language supports the following built-in types.
``3.5mins``. An ``interval`` can also be negated, for example
``-12 hr`` represents "twelve hours in the past".
Intervals support addition and subtraction. Intervals also support
division (in which case the result is a ``double`` value), the
comparison operators (``==``, ``!=``, ``<``, ``<=``, ``>``, ``>=``),
and the assignment operators (``=``, ``+=``, ``-=``). Also, an
``interval`` can be multiplied or divided by an arithmetic type
(``count``, ``int``, or ``double``) to produce an ``interval`` value.
The absolute value of an ``interval`` is a ``double`` value equal to the
number of seconds in the ``interval`` (e.g., ``|-1 min|`` is 60).
Intervals support addition and subtraction, the comparison operators
(``==``, ``!=``, ``<``, ``<=``, ``>``, ``>=``), the assignment
operators (``=``, ``+=``, ``-=``), and unary plus and minus (``+``, ``-``).
Intervals also support division (in which case the result is a
:bro:type:`double` value). An ``interval`` can be multiplied or divided
by an arithmetic type (``count``, ``int``, or ``double``) to produce
an ``interval`` value. The absolute value of an ``interval`` is a
``double`` value equal to the number of seconds in the ``interval``
(e.g., ``|-1 min|`` is 60.0).
.. bro:type:: string
A type used to hold character-string values which represent text.
String constants are created by enclosing text in double quotes (")
and the backslash character (\\) introduces escape sequences (all of
the C-style escape sequences are supported).
A type used to hold character-string values which represent text, although
strings in a Bro script can actually contain any arbitrary binary data.
String constants are created by enclosing text within a pair of double
quotes ("). A string constant cannot span multiple lines in a Bro script.
The backslash character (\\) introduces escape sequences. The
following escape sequences are recognized: ``\n``, ``\t``, ``\v``, ``\b``,
``\r``, ``\f``, ``\a``, ``\ooo`` (where each 'o' is an octal digit),
``\xhh`` (where each 'h' is a hexadecimal digit). For escape sequences
that don't match any of these, Bro will just remove the backslash (so
to represent a literal backslash in a string constant, you just use
two consecutive backslashes).
Strings support concatenation (``+``), and assignment (``=``, ``+=``).
Strings also support the comparison operators (``==``, ``!=``, ``<``,
``<=``, ``>``, ``>=``). The number of characters in a string can be
found by enclosing the string within pipe characters (e.g., ``|"abc"|``
is 3).
The subscript operator can extract an individual character or a substring
of a string (string indexing is zero-based, but an index of
-1 refers to the last character in the string, and -2 refers to the
second-to-last character, etc.). When extracting a substring, the
starting and ending index values are separated by a colon. For example::
local orig = "0123456789";
local third_char = orig[2];
local last_char = orig[-1];
local first_three_chars = orig[0:2];
Substring searching can be performed using the "in" or "!in"
is 3). Substring searching can be performed using the "in" or "!in"
operators (e.g., "bar" in "foobar" yields true).
Note that Bro represents strings internally as a count and vector of
bytes rather than a NUL-terminated byte string (although string
constants are also automatically NUL-terminated). This is because
network traffic can easily introduce NULs into strings either by
nature of an application, inadvertently, or maliciously. And while
NULs are allowed in Bro strings, when present in strings passed as
arguments to many functions, a run-time error can occur as their
presence likely indicates a sort of problem. In that case, the
string will also only be represented to the user as the literal
"<string-with-NUL>" string.
The subscript operator can extract a substring of a string. To do this,
specify the starting index to extract (if the starting index is omitted,
then zero is assumed), followed by a colon and index
one past the last character to extract (if the last index is omitted,
then the extracted substring will go to the end of the original string).
However, if both the colon and last index are omitted, then a string of
length one is extracted. String indexing is zero-based, but an index
of -1 refers to the last character in the string, and -2 refers to the
second-to-last character, etc. Here are a few examples::
local orig = "0123456789";
local second_char = orig[1];
local last_char = orig[-1];
local first_two_chars = orig[:2];
local last_two_chars = orig[8:];
local no_first_and_last = orig[1:9];
Note that the subscript operator cannot be used to modify a string (i.e.,
it cannot be on the left side of an assignment operator).
.. bro:type:: pattern
@ -174,7 +202,7 @@ The Bro scripting language supports the following built-in types.
and embedded.
In exact matching the ``==`` equality relational operator is used
with one :bro:type:`pattern` operand and one :bro:type:`string`
with one "pattern" operand and one ":bro:type:`string`"
operand (order of operands does not matter) to check whether the full
string exactly matches the pattern. In exact matching, the ``^``
beginning-of-line and ``$`` end-of-line anchors are redundant since
@ -190,8 +218,8 @@ The Bro scripting language supports the following built-in types.
yields false. The ``!=`` operator would yield the negation of ``==``.
In embedded matching the ``in`` operator is used with one
:bro:type:`pattern` operand (which must be on the left-hand side) and
one :bro:type:`string` operand, but tests whether the pattern
"pattern" operand (which must be on the left-hand side) and
one ":bro:type:`string`" operand, but tests whether the pattern
appears anywhere within the given string. For example::
/foo|bar/ in "foobar"
@ -203,27 +231,12 @@ The Bro scripting language supports the following built-in types.
is false since "oob" does not appear at the start of "foobar". The
``!in`` operator would yield the negation of ``in``.
.. bro:type:: enum
A type allowing the specification of a set of related values that
have no further structure. An example declaration:
.. code:: bro
type color: enum { Red, White, Blue, };
The last comma after ``Blue`` is optional.
The only operations allowed on enumerations are equality comparisons
(``==``, ``!=``) and assignment (``=``).
Enumerations do not have associated values or ordering.
.. bro:type:: port
A type representing transport-level port numbers. Besides TCP and
A type representing transport-level port numbers (besides TCP and
UDP ports, there is a concept of an ICMP "port" where the source
port is the ICMP message type and the destination port the ICMP
message code. A ``port`` constant is written as an unsigned integer
message code). A ``port`` constant is written as an unsigned integer
followed by one of ``/tcp``, ``/udp``, ``/icmp``, or ``/unknown``.
Ports support the comparison operators (``==``, ``!=``, ``<``, ``<=``,
@ -255,14 +268,6 @@ The Bro scripting language supports the following built-in types.
address) are treated internally as IPv4 addresses (for example,
``[::ffff:192.168.1.100]`` is equal to ``192.168.1.100``).
Hostname constants can also be used, but since a hostname can
correspond to multiple IP addresses, the type of such a variable is a
:bro:type:`set` of :bro:type:`addr` elements. For example:
.. code:: bro
local a = www.google.com;
Addresses can be compared for equality (``==``, ``!=``),
and also for ordering (``<``, ``<=``, ``>``, ``>=``). The absolute value
of an address gives the size in bits (32 for IPv4, and 128 for IPv6).
@ -285,9 +290,17 @@ The Bro scripting language supports the following built-in types.
if ( a in s )
print "true";
Note that you can check if a given ``addr`` is IPv4 or IPv6 using
You can check if a given ``addr`` is IPv4 or IPv6 using
the :bro:id:`is_v4_addr` and :bro:id:`is_v6_addr` built-in functions.
Note that hostname constants can also be used, but since a hostname can
correspond to multiple IP addresses, the type of such a variable is
"set[addr]". For example:
.. code:: bro
local a = www.google.com;
.. bro:type:: subnet
A type representing a block of IP addresses in CIDR notation. A
@ -296,13 +309,24 @@ The Bro scripting language supports the following built-in types.
number. For example, ``192.168.0.0/16`` or ``[fe80::]/64``.
Subnets can be compared for equality (``==``, ``!=``). An
:bro:type:`addr` can be checked for inclusion in a subnet using
the "in" or "!in" operators.
"addr" can be checked for inclusion in a subnet using
the ``in`` or ``!in`` operators.
.. bro:type:: any
.. bro:type:: enum
Used to bypass strong typing. For example, a function can take an
argument of type ``any`` when it may be of different types.
A type allowing the specification of a set of related values that
have no further structure. An example declaration:
.. code:: bro
type color: enum { Red, White, Blue, };
The last comma after ``Blue`` is optional. Both the type name ``color``
and the individual values (``Red``, etc.) have global scope.
Enumerations do not have associated values or ordering.
The only operations allowed on enumerations are equality comparisons
(``==``, ``!=``) and assignment (``=``).
.. bro:type:: table
@ -316,24 +340,25 @@ The Bro scripting language supports the following built-in types.
table [ type^+ ] of type
where *type^+* is one or more types, separated by commas. For example:
where *type^+* is one or more types, separated by commas.
For example:
.. code:: bro
global a: table[count] of string;
declares a table indexed by :bro:type:`count` values and yielding
:bro:type:`string` values. The yield type can also be more complex:
declares a table indexed by "count" values and yielding
"string" values. The yield type can also be more complex:
.. code:: bro
global a: table[count] of table[addr, port] of string;
which declares a table indexed by :bro:type:`count` and yielding
another :bro:type:`table` which is indexed by an :bro:type:`addr`
and :bro:type:`port` to yield a :bro:type:`string`.
which declares a table indexed by "count" and yielding
another "table" which is indexed by an "addr"
and "port" to yield a "string".
Initialization of tables occurs by enclosing a set of initializers within
One way to initialize a table is by enclosing a set of initializers within
braces, for example:
.. code:: bro
@ -343,18 +368,17 @@ 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:
A table constructor can also be used to create a table:
.. code:: bro
global t2: table[count] of string = table(
[11] = "eleven",
[5] = "five"
global t2 = table(
[192.168.0.2, 22/tcp] = "ssh",
[192.168.0.3, 80/tcp] = "http"
);
Table constructors can also be explicitly named by a type, which is
useful for when a more complex index type could otherwise be
useful when a more complex index type could otherwise be
ambiguous:
.. code:: bro
@ -381,17 +405,7 @@ The Bro scripting language supports the following built-in types.
if ( 13 in t )
...
Iterate over tables with a ``for`` loop:
.. code:: bro
local t: table[count] of string;
for ( n in t )
...
local services: table[addr, port] of string;
for ( [a, p] in services )
if ( [192.168.0.2, 22/tcp] in t2 )
...
Add or overwrite individual table elements by assignment:
@ -400,7 +414,7 @@ The Bro scripting language supports the following built-in types.
t[13] = "thirteen";
Remove individual table elements with ``delete``:
Remove individual table elements with :bro:keyword:`delete`:
.. code:: bro
@ -416,6 +430,9 @@ The Bro scripting language supports the following built-in types.
|t|
See the :bro:keyword:`for` statement for info on how to iterate over
the elements in a table.
.. bro:type:: set
A set is like a :bro:type:`table`, but it is a collection of indices
@ -426,25 +443,22 @@ The Bro scripting language supports the following built-in types.
where *type^+* is one or more types separated by commas.
Sets are initialized by listing elements enclosed by curly braces:
Sets can be initialized by listing elements enclosed by curly braces:
.. code:: bro
global s: set[port] = { 21/tcp, 23/tcp, 80/tcp, 443/tcp };
global s2: set[port, string] = { [21/tcp, "ftp"], [23/tcp, "telnet"] };
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);
global s3 = 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
useful when a more complex index type could otherwise be
ambiguous:
.. code:: bro
@ -465,18 +479,10 @@ The Bro scripting language supports the following built-in types.
if ( 21/tcp in s )
...
if ( 21/tcp !in s )
if ( [21/tcp, "ftp"] !in s2 )
...
Iterate over a set with a ``for`` loop:
.. code:: bro
local s: set[port];
for ( p in s )
...
Elements are added with ``add``:
Elements are added with :bro:keyword:`add`:
.. code:: bro
@ -485,7 +491,7 @@ The Bro scripting language supports the following built-in types.
Nothing happens if the element with value ``22/tcp`` was already present in
the set.
And removed with ``delete``:
And removed with :bro:keyword:`delete`:
.. code:: bro
@ -501,6 +507,9 @@ The Bro scripting language supports the following built-in types.
|s|
See the :bro:keyword:`for` statement for info on how to iterate over
the elements in a set.
.. bro:type:: vector
A vector is like a :bro:type:`table`, except it's always indexed by a
@ -515,7 +524,7 @@ The Bro scripting language supports the following built-in types.
.. code:: bro
global v: vector of string = vector("one", "two", "three");
local v = 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
@ -539,14 +548,6 @@ The Bro scripting language supports the following built-in types.
print v[2];
Iterate over a vector with a ``for`` loop:
.. code:: bro
local v: vector of string;
for ( n in v )
...
An element can be added to a vector by assigning the value (a value
that already exists at that index will be overwritten):
@ -577,11 +578,17 @@ The Bro scripting language supports the following built-in types.
The resulting vector of bool is the logical "and" (or logical "or") of
each element of the operand vectors.
See the :bro:keyword:`for` statement for info on how to iterate over
the elements in a vector.
.. bro:type:: record
A ``record`` is a collection of values. Each value has a field name
A "record" is a collection of values. Each value has a field name
and a type. Values do not need to have the same type and the types
have no restrictions. An example record type definition:
have no restrictions. Field names must follow the same syntax as
regular variable names (except that field names are allowed to be the
same as local or global variables). An example record type
definition:
.. code:: bro
@ -590,86 +597,45 @@ The Bro scripting language supports the following built-in types.
s: string &optional;
};
Access to a record field uses the dollar sign (``$``) operator:
.. code:: bro
global r: MyRecordType;
r$c = 13;
Record assignment can be done field by field or as a whole like:
.. code:: bro
r = [$c = 13, $s = "thirteen"];
Records can be initialized or assigned as a whole in three different ways.
When assigning a whole record value, all fields that are not
:bro:attr:`&optional` or have a :bro:attr:`&default` attribute must
be specified.
be specified. First, there's a constructor syntax:
To test for existence of a field that is :bro:attr:`&optional`, use the
``?$`` operator:
.. code:: bro
local r: MyRecordType = record($c = 7);
And the constructor can be explicitly named by type, too, which
is arguably more readable:
.. code:: bro
local r = MyRecordType($c = 42);
And the third way is like this:
.. code:: bro
local r: MyRecordType = [$c = 13, $s = "thirteen"];
Access to a record field uses the dollar sign (``$``) operator, and
record fields can be assigned with this:
.. code:: bro
local r: MyRecordType;
r$c = 13;
To test if a field that is :bro:attr:`&optional` has been assigned a
value, use the ``?$`` operator (it returns a :bro:type:`bool` value of
``T`` if the field has been assigned a value, or ``F`` if not):
.. code:: bro
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
intentionally hidden, but whose values may be passed to certain
functions that can actually access the internal/hidden resources.
Opaque types are differentiated from each other by qualifying them
like ``opaque of md5`` or ``opaque of sha1``. Any valid identifier
can be used as the type qualifier.
An example use of this type is the set of built-in functions which
perform hashing:
.. code:: bro
local handle: opaque of md5 = md5_hash_init();
md5_hash_update(handle, "test");
md5_hash_update(handle, "testing");
print md5_hash_finish(handle);
Here the opaque type is used to provide a handle to a particular
resource which is calculating an MD5 checksum incrementally over
time, but the details of that resource aren't relevant, it's only
necessary to have a handle as a way of identifying it and
distinguishing it from other such resources.
.. bro:type:: file
Bro supports writing to files, but not reading from them. Files
can be opened using either the :bro:id:`open` or :bro:id:`open_for_append`
built-in functions, and closed using the :bro:id:`close` built-in
function. For example, declare, open, and write to a file
and finally close it like:
.. code:: bro
global f: file = open("myfile");
print f, "hello, world";
close(f);
Writing to files like this for logging usually isn't recommended, for better
logging support see :doc:`/frameworks/logging`.
.. bro:type:: function
Function types in Bro are declared using::
@ -700,6 +666,16 @@ The Bro scripting language supports the following built-in types.
type, but when it is, the return type and argument list (including the
name of each argument) must match exactly.
Here is an example function that takes no parameters and does not
return a value:
.. code:: bro
function my_func()
{
print "my_func";
}
Function types don't need to have a name and can be assigned anonymously:
.. code:: bro
@ -742,9 +718,20 @@ The Bro scripting language supports the following built-in types.
Event handlers are nearly identical in both syntax and semantics to
a :bro:type:`function`, with the two differences being that event
handlers have no return type since they never return a value, and
you cannot call an event handler. Instead of directly calling an
event handler from a script, event handler bodies are executed when
they are invoked by one of three different methods:
you cannot call an event handler.
Example:
.. code:: bro
event my_event(r: bool, s: string)
{
print "my_event", r, s;
}
Instead of directly calling an event handler from a script, event
handler bodies are executed when they are invoked by one of three
different methods:
- From the event engine
@ -765,7 +752,7 @@ The Bro scripting language supports the following built-in types.
This assumes that ``password_exposed`` was previously declared
as an event handler type with compatible arguments.
- Via the ``schedule`` expression in a script
- Via the :bro:keyword:`schedule` expression in a script
This delays the invocation of event handlers until some time in
the future. For example:
@ -789,8 +776,8 @@ The Bro scripting language supports the following built-in types.
immediate and they do not get scheduled through an event queue.
Also, a unique feature of a hook is that a given hook handler body
can short-circuit the execution of remaining hook handlers simply by
exiting from the body as a result of a ``break`` statement (as
opposed to a ``return`` or just reaching the end of the body).
exiting from the body as a result of a :bro:keyword:`break` statement (as
opposed to a :bro:keyword:`return` or just reaching the end of the body).
A hook type is declared like::
@ -859,142 +846,60 @@ The Bro scripting language supports the following built-in types.
executed due to one handler body exiting as a result of a ``break``
statement.
Attributes
----------
.. bro:type:: file
Attributes occur at the end of type/event declarations and change their
behavior. The syntax is ``&key`` or ``&key=val``, e.g., ``type T:
set[count] &read_expire=5min`` or ``event foo() &priority=-3``. The Bro
scripting language supports the following built-in attributes.
Bro supports writing to files, but not reading from them (to read from
files see the :doc:`/frameworks/input`). Files
can be opened using either the :bro:id:`open` or :bro:id:`open_for_append`
built-in functions, and closed using the :bro:id:`close` built-in
function. For example, declare, open, and write to a file and finally
close it like:
.. bro:attr:: &optional
.. code:: bro
Allows a record field to be missing. For example the type ``record {
a: addr; b: port &optional; }`` could be instantiated both as
singleton ``[$a=127.0.0.1]`` or pair ``[$a=127.0.0.1, $b=80/tcp]``.
local f = open("myfile");
print f, "hello, world";
close(f);
.. bro:attr:: &default
Writing to files like this for logging usually isn't recommended, for better
logging support see :doc:`/frameworks/logging`.
Uses a default value for a record field, a function/hook/event
parameter, or container elements. For example, ``table[int] of
string &default="foo"`` would create a table that returns the
:bro:type:`string` ``"foo"`` for any non-existing index.
.. bro:type:: opaque
.. bro:attr:: &redef
A data type whose actual representation/implementation is
intentionally hidden, but whose values may be passed to certain
built-in functions that can actually access the internal/hidden resources.
Opaque types are differentiated from each other by qualifying them
like "opaque of md5" or "opaque of sha1".
Allows for redefinition of initial object values. This is typically
used with constants, for example, ``const clever = T &redef;`` would
allow the constant to be redefined at some later point during script
execution.
An example use of this type is the set of built-in functions which
perform hashing:
.. bro:attr:: &rotate_interval
.. code:: bro
Rotates a file after a specified interval.
local handle = md5_hash_init();
md5_hash_update(handle, "test");
md5_hash_update(handle, "testing");
print md5_hash_finish(handle);
.. bro:attr:: &rotate_size
Here the opaque type is used to provide a handle to a particular
resource which is calculating an MD5 hash incrementally over
time, but the details of that resource aren't relevant, it's only
necessary to have a handle as a way of identifying it and
distinguishing it from other such resources.
Rotates a file after it has reached a given size in bytes.
.. bro:type:: any
.. bro:attr:: &add_func
Used to bypass strong typing. For example, a function can take an
argument of type ``any`` when it may be of different types.
The only operation allowed on a variable of type ``any`` is assignment.
Can be applied to an identifier with &redef to specify a function to
be called any time a "redef <id> += ..." declaration is parsed. The
function takes two arguments of the same type as the identifier, the first
being the old value of the variable and the second being the new
value given after the "+=" operator in the "redef" declaration. The
return value of the function will be the actual new value of the
variable after the "redef" declaration is parsed.
Note that users aren't expected to use this type. It's provided mainly
for use by some built-in functions and scripts included with Bro.
.. bro:attr:: &delete_func
.. bro:type:: void
Same as &add_func, except for "redef" declarations that use the "-="
operator.
An internal Bro type (i.e., "void" is not a reserved keyword in the Bro
scripting language) representing the absence of a return type for a
function.
.. bro:attr:: &expire_func
Called right before a container element expires. The function's
first parameter is of the same type of the container and the second
parameter the same type of the container's index. The return
value is an :bro:type:`interval` indicating the amount of additional
time to wait before expiring the container element at the given
index (which will trigger another execution of this function).
.. bro:attr:: &read_expire
Specifies a read expiration timeout for container elements. That is,
the element expires after the given amount of time since the last
time it has been read. Note that a write also counts as a read.
.. bro:attr:: &write_expire
Specifies a write expiration timeout for container elements. That
is, the element expires after the given amount of time since the
last time it has been written.
.. bro:attr:: &create_expire
Specifies a creation expiration timeout for container elements. That
is, the element expires after the given amount of time since it has
been inserted into the container, regardless of any reads or writes.
.. bro:attr:: &persistent
Makes a variable persistent, i.e., its value is written to disk (per
default at shutdown time).
.. bro:attr:: &synchronized
Synchronizes variable accesses across nodes. The value of a
``&synchronized`` variable is automatically propagated to all peers
when it changes.
.. bro:attr:: &encrypt
Encrypts files right before writing them to disk.
.. TODO: needs to be documented in more detail.
.. bro:attr:: &raw_output
Opens a file in raw mode, i.e., non-ASCII characters are not
escaped.
.. bro:attr:: &mergeable
Prefers set union to assignment for synchronized state. This
attribute is used in conjunction with :bro:attr:`&synchronized`
container types: when the same container is updated at two peers
with different value, the propagation of the state causes a race
condition, where the last update succeeds. This can cause
inconsistencies and can be avoided by unifying the two sets, rather
than merely overwriting the old value.
.. bro:attr:: &priority
Specifies the execution priority (as a signed integer) of a hook or
event handler. Higher values are executed before lower ones. The
default value is 0.
.. bro:attr:: &group
Groups event handlers such that those in the same group can be
jointly activated or deactivated.
.. bro:attr:: &log
Writes a record field to the associated log stream.
.. bro:attr:: &error_handler
Internally set on the events that are associated with the reporter
framework: :bro:id:`reporter_info`, :bro:id:`reporter_warning`, and
:bro:id:`reporter_error`. It prevents any handlers of those events
from being able to generate reporter messages that go through any of
those events (i.e., it prevents an infinite event recursion). Instead,
such nested reporter messages are output to stderr.
.. bro:attr:: &type_column
Used by the input framework. It can be used on columns of type
:bro:type:`port` and specifies the name of an additional column in
the input file which specifies the protocol of the port (tcp/udp/icmp).

View file

@ -1,13 +1,19 @@
event bro_init()
{
# Declaration of the table.
local ssl_services: table[string] of port;
# Initialize the table.
ssl_services = table(["SSH"] = 22/tcp, ["HTTPS"] = 443/tcp);
# Insert one key-yield pair into the table.
ssl_services["IMAPS"] = 993/tcp;
# Check if the key "SMTPS" is not in the table.
if ( "SMTPS" !in ssl_services )
ssl_services["SMTPS"] = 587/tcp;
# Iterate over each key in the table.
for ( k in ssl_services )
print fmt("Service Name: %s - Common Port: %s", k, ssl_services[k]);
}

View file

@ -10,6 +10,6 @@ event bro_init()
print fmt("contents of v1: %s", v1);
print fmt("length of v1: %d", |v1|);
print fmt("contents of v1: %s", v2);
print fmt("contents of v2: %s", v2);
print fmt("length of v2: %d", |v2|);
}

View file

@ -1,6 +1,6 @@
event bro_init()
{
local test_string = "The quick brown fox jumped over the lazy dog.";
local test_string = "The quick brown fox jumps over the lazy dog.";
local test_pattern = /quick|lazy/;
if ( test_pattern in test_string )

View file

@ -1,8 +1,10 @@
module Factor;
export {
# Append the value LOG to the Log::ID enumerable.
redef enum Log::ID += { LOG };
# Define a new type called Factor::Info.
type Info: record {
num: count &log;
factorial_num: count &log;
@ -20,6 +22,7 @@ function factorial(n: count): count
event bro_init()
{
# Create the logging stream.
Log::create_stream(LOG, [$columns=Info]);
}

View file

@ -2,7 +2,6 @@
@load base/protocols/ssh/
redef Notice::emailed_types += {
SSH::Interesting_Hostname_Login,
SSH::Login
SSH::Interesting_Hostname_Login
};

View file

@ -3,5 +3,4 @@
redef Notice::type_suppression_intervals += {
[SSH::Interesting_Hostname_Login] = 1day,
[SSH::Login] = 12hrs,
};

View file

@ -54,7 +54,8 @@ script and much more in following sections.
.. btest-include:: ${BRO_SRC_ROOT}/scripts/policy/frameworks/files/detect-MHR.bro
:lines: 4-6
Lines 3 to 5 of the script process the ``__load__.bro`` script in the
The first part of the script consists of ``@load`` directives which
process the ``__load__.bro`` script in the
respective directories being loaded. The ``@load`` directives are
often considered good practice or even just good manners when writing
Bro scripts to make sure they can be used on their own. While it's unlikely that in a
@ -78,29 +79,37 @@ of the :bro:id:`NOTICE` function to generate notices of type
``TeamCymruMalwareHashRegistry::Match`` as done in the next section. Notices
allow Bro to generate some kind of extra notification beyond its
default log types. Often times, this extra notification comes in the
form of an email generated and sent to a preconfigured address, but can be altered
depending on the needs of the deployment. The export section is finished off with
the definition of two constants that list the kind of files we want to match against and
the minimum percentage of detection threshold in which we are interested.
form of an email generated and sent to a preconfigured address, but can
be altered depending on the needs of the deployment. The export section
is finished off with the definition of a few constants that list the kind
of files we want to match against and the minimum percentage of
detection threshold in which we are interested.
Up until this point, the script has merely done some basic setup. With the next section,
the script starts to define instructions to take in a given event.
Up until this point, the script has merely done some basic setup. With
the next section, the script starts to define instructions to take in
a given event.
.. btest-include:: ${BRO_SRC_ROOT}/scripts/policy/frameworks/files/detect-MHR.bro
:lines: 38-71
The workhorse of the script is contained in the event handler for
``file_hash``. The :bro:see:`file_hash` event allows scripts to access
the information associated with a file for which Bro's file analysis framework has
generated a hash. The event handler is passed the file itself as ``f``, the type of digest
algorithm used as ``kind`` and the hash generated as ``hash``.
the information associated with a file for which Bro's file analysis
framework has generated a hash. The event handler is passed the
file itself as ``f``, the type of digest algorithm used as ``kind``
and the hash generated as ``hash``.
On line 3, an ``if`` statement is used to check for the correct type of hash, in this case
a SHA1 hash. It also checks for a mime type we've defined as being of interest as defined in the
constant ``match_file_types``. The comparison is made against the expression ``f$mime_type``, which uses
the ``$`` dereference operator to check the value ``mime_type`` inside the variable ``f``. Once both
values resolve to true, a local variable is defined to hold a string comprised of the SHA1 hash concatenated
with ``.malware.hash.cymru.com``; this value will be the domain queried in the malware hash registry.
In the ``file_hash`` event handler, there is an ``if`` statement that is used
to check for the correct type of hash, in this case
a SHA1 hash. It also checks for a mime type we've defined as
being of interest as defined in the constant ``match_file_types``.
The comparison is made against the expression ``f$info$mime_type``, which uses
the ``$`` dereference operator to check the value ``mime_type``
inside the variable ``f$info``. If the entire expression evaluates to true,
then a helper function is called to do the rest of the work. In that
function, a local variable is defined to hold a string comprised of
the SHA1 hash concatenated with ``.malware.hash.cymru.com``; this
value will be the domain queried in the malware hash registry.
The rest of the script is contained within a ``when`` block. In
short, a ``when`` block is used when Bro needs to perform asynchronous
@ -111,24 +120,28 @@ this event continues and upon receipt of the values returned by
:bro:id:`lookup_hostname_txt`, the ``when`` block is executed. The
``when`` block splits the string returned into a portion for the date on which
the malware was first detected and the detection rate by splitting on an text space
and storing the values returned in a local table variable. In line 12, if the table
returned by ``split1`` has two entries, indicating a successful split, we store the detection
date in ``mhr_first_detected`` and the rate in ``mhr_detect_rate`` on lines 14 and 15 respectively
and storing the values returned in a local table variable.
In the ``do_mhr_lookup`` function, if the table
returned by ``split1`` has two entries, indicating a successful split, we
store the detection
date in ``mhr_first_detected`` and the rate in ``mhr_detect_rate``
using the appropriate conversion functions. From this point on, Bro knows it has seen a file
transmitted which has a hash that has been seen by the Team Cymru Malware Hash Registry, the rest
of the script is dedicated to producing a notice.
On line 17, the detection time is processed into a string representation and stored in
``readable_first_detected``. The script then compares the detection rate against the
``notice_threshold`` that was defined earlier. If the detection rate is high enough, the script
creates a concise description of the notice on line 22, a possible URL to check the sample against
``virustotal.com``'s database, and makes the call to :bro:id:`NOTICE` to hand the relevant information
off to the Notice framework.
The detection time is processed into a string representation and stored in
``readable_first_detected``. The script then compares the detection rate
against the ``notice_threshold`` that was defined earlier. If the
detection rate is high enough, the script creates a concise description
of the notice and stores it in the ``message`` variable. It also
creates a possible URL to check the sample against
``virustotal.com``'s database, and makes the call to :bro:id:`NOTICE`
to hand the relevant information off to the Notice framework.
In approximately 25 lines of code, Bro provides an amazing
In approximately a few dozen lines of code, Bro provides an amazing
utility that would be incredibly difficult to implement and deploy
with other products. In truth, claiming that Bro does this in 25
lines is a misdirection; there is a truly massive number of things
with other products. In truth, claiming that Bro does this in such a small
number of lines is a misdirection; there is a truly massive number of things
going on behind-the-scenes in Bro, but it is the inclusion of the
scripting language that gives analysts access to those underlying
layers in a succinct and well defined manner.
@ -180,7 +193,7 @@ event definition used by Bro. As Bro detects DNS requests being
issued by an originator, it issues this event and any number of
scripts then have access to the data Bro passes along with the event.
In this example, Bro passes not only the message, the query, query
type and query class for the DNS request, but also a then record used
type and query class for the DNS request, but also a record used
for the connection itself.
The Connection Record Data Type
@ -210,8 +223,7 @@ into the connection record data type will be
:bro:id:`connection_state_remove` . As detailed in the in-line
documentation, Bro generates this event just before it decides to
remove this event from memory, effectively forgetting about it. Let's
take a look at a simple script, stored as
``connection_record_01.bro``, that will output the connection record
take a look at a simple example script, that will output the connection record
for a single connection.
.. btest-include:: ${DOC_ROOT}/scripting/connection_record_01.bro
@ -243,12 +255,12 @@ of reference for accessing data in a script.
Bro makes extensive use of nested data structures to store state and
information gleaned from the analysis of a connection as a complete
unit. To break down this collection of information, you will have to
make use of use Bro's field delimiter ``$``. For example, the
make use of Bro's field delimiter ``$``. For example, the
originating host is referenced by ``c$id$orig_h`` which if given a
narrative relates to ``orig_h`` which is a member of ``id`` which is
a member of the data structure referred to as ``c`` that was passed
into the event handler." Given that the responder port
(``c$id$resp_p``) is ``53/tcp``, it's likely that Bro's base HTTP scripts
into the event handler. Given that the responder port
``c$id$resp_p`` is ``80/tcp``, it's likely that Bro's base HTTP scripts
can further populate the connection record. Let's load the
``base/protocols/http`` scripts and check the output of our script.
@ -384,9 +396,12 @@ which it was declared. Local variables tend to be used for values
that are only needed within a specific scope and once the processing
of a script passes beyond that scope and no longer used, the variable
is deleted. Bro maintains names of locals separately from globally
visible ones, an example of which is illustrated below. The script
executes the event handler :bro:id:`bro_init` which in turn calls the
function ``add_two(i: count)`` with an argument of ``10``. Once Bro
visible ones, an example of which is illustrated below.
.. btest-include:: ${DOC_ROOT}/scripting/data_type_local.bro
The script executes the event handler :bro:id:`bro_init` which in turn calls
the function ``add_two(i: count)`` with an argument of ``10``. Once Bro
enters the ``add_two`` function, it provisions a locally scoped
variable called ``added_two`` to hold the value of ``i+2``, in this
case, ``12``. The ``add_two`` function then prints the value of the
@ -398,8 +413,6 @@ processing the ``bro_init`` function, the variable called ``test`` is
no longer in scope and, since there exist no other references to the
value ``12``, the value is also deleted.
.. btest-include:: ${DOC_ROOT}/scripting/data_type_local.bro
Data Structures
---------------
@ -506,20 +519,7 @@ Tables
A table in Bro is a mapping of a key to a value or yield. While the
values don't have to be unique, each key in the table must be unique
to preserve a one-to-one mapping of keys to values. In the example
below, we've compiled a table of SSL-enabled services and their common
ports. The explicit declaration and constructor for the table on
lines 5 and 7 lay out the data types of the keys (strings) and the
data types of the yields (ports) and then fill in some sample key and
yield pairs. Line 8 shows how to use a table accessor to insert one
key-yield pair into the table. When using the ``in`` operator on a table,
you are effectively working with the keys of the table. In the case
of an ``if`` statement, the ``in`` operator will check for membership among
the set of keys and return a true or false value. As seen on line 10,
we are checking if ``SMTPS`` is not in the set of keys for the
ssl_services table and if the condition holds true, we add the
key-yield pair to the table. Line 13 shows the use of a ``for`` statement
to iterate over each key currently in the table.
to preserve a one-to-one mapping of keys to values.
.. btest-include:: ${DOC_ROOT}/scripting/data_struct_table_declaration.bro
@ -527,6 +527,21 @@ to iterate over each key currently in the table.
@TEST-EXEC: btest-rst-cmd bro ${DOC_ROOT}/scripting/data_struct_table_declaration.bro
In this example,
we've compiled a table of SSL-enabled services and their common
ports. The explicit declaration and constructor for the table are on
two different lines and lay out the data types of the keys (strings) and the
data types of the yields (ports) and then fill in some sample key and
yield pairs. You can also use a table accessor to insert one
key-yield pair into the table. When using the ``in``
operator on a table, you are effectively working with the keys of the table.
In the case of an ``if`` statement, the ``in`` operator will check for
membership among the set of keys and return a true or false value.
The example shows how to check if ``SMTPS`` is not in the set
of keys for the ``ssl_services`` table and if the condition holds true,
we add the key-yield pair to the table. Finally, the example shows how
to use a ``for`` statement to iterate over each key currently in the table.
Simple examples aside, tables can become extremely complex as the keys
and values for the table become more intricate. Tables can have keys
comprised of multiple data types and even a series of elements called
@ -535,9 +550,15 @@ Bro implies a cost in complexity for the person writing the scripts
but pays off in effectiveness given the power of Bro as a network
security platform.
The script below shows a sample table of strings indexed by two
.. btest-include:: ${DOC_ROOT}/scripting/data_struct_table_complex.bro
.. btest:: data_struct_table_complex
@TEST-EXEC: btest-rst-cmd bro -b ${DOC_ROOT}/scripting/data_struct_table_complex.bro
This script shows a sample table of strings indexed by two
strings, a count, and a final string. With a tuple acting as an
aggregate key, the order is the important as a change in order would
aggregate key, the order is important as a change in order would
result in a new key. Here, we're using the table to track the
director, studio, year or release, and lead actor in a series of
samurai flicks. It's important to note that in the case of the ``for``
@ -546,14 +567,9 @@ iterate over, say, the directors; we have to iterate with the exact
format as the keys themselves. In this case, we need squared brackets
surrounding four temporary variables to act as a collection for our
iteration. While this is a contrived example, we could easily have
had keys containing IP addresses (``addr``), ports (``port``) and even a ``string``
calculated as the result of a reverse hostname lookup.
had keys containing IP addresses (``addr``), ports (``port``) and even
a ``string`` calculated as the result of a reverse hostname lookup.
.. btest-include:: ${DOC_ROOT}/scripting/data_struct_table_complex.bro
.. btest:: data_struct_table_complex
@TEST-EXEC: btest-rst-cmd bro -b ${DOC_ROOT}/scripting/data_struct_table_complex.bro
Vectors
~~~~~~~
@ -657,7 +673,7 @@ using a 20 bit subnet mask.
Because this is a script that doesn't use any kind of network
analysis, we can handle the event :bro:id:`bro_init` which is always
generated by Bro's core upon startup. On lines six and seven, two
generated by Bro's core upon startup. In the example script, two
locally scoped vectors are created to hold our lists of subnets and IP
addresses respectively. Then, using a set of nested ``for`` loops, we
iterate over every subnet and every IP address and use an ``if``
@ -714,7 +730,7 @@ Bro supports ``usec``, ``msec``, ``sec``, ``min``, ``hr``, or ``day`` which repr
microseconds, milliseconds, seconds, minutes, hours, and days
respectively. In fact, the interval data type allows for a surprising
amount of variation in its definitions. There can be a space between
the numeric constant or they can crammed together like a temporal
the numeric constant or they can be crammed together like a temporal
portmanteau. The time unit can be either singular or plural. All of
this adds up to to the fact that both ``42hrs`` and ``42 hr`` are
perfectly valid and logically equivalent in Bro. The point, however,
@ -760,7 +776,7 @@ string against which it will be tested to be on the right.
In the sample above, two local variables are declared to hold our
sample sentence and regular expression. Our regular expression in
this case will return true if the string contains either the word
``quick`` or the word ``fox``. The ``if`` statement on line six uses
``quick`` or the word ``fox``. The ``if`` statement in the script uses
embedded matching and the ``in`` operator to check for the existence
of the pattern within the string. If the statement resolves to true,
:bro:id:`split` is called to break the string into separate pieces.
@ -768,8 +784,8 @@ of the pattern within the string. If the statement resolves to true,
table of strings indexed by a count. Each element of the table will
be the segments before and after any matches against the pattern but
excluding the actual matches. In this case, our pattern matches
twice, and results in a table with three entries. Lines 11 through 13
print the contents of the table in order.
twice, and results in a table with three entries. The ``print`` statements
in the script will print the contents of the table in order.
.. btest:: data_type_pattern
@ -780,7 +796,7 @@ inequality operators through the ``==`` and ``!=`` operators
respectively. When used in this manner however, the string must match
entirely to resolve to true. For example, the script below uses two
ternary conditional statements to illustrate the use of the ``==``
operators with patterns. On lines 8 and 11 the output is altered based
operator with patterns. The output is altered based
on the result of the comparison between the pattern and the string.
.. btest-include:: ${DOC_ROOT}/scripting/data_type_pattern_02.bro
@ -803,7 +819,7 @@ with the ``typedef`` and ``struct`` keywords, Bro allows you to cobble
together new data types to suit the needs of your situation.
When combined with the ``type`` keyword, ``record`` can generate a
composite type. We have, in fact, already encountered a a complex
composite type. We have, in fact, already encountered a complex
example of the ``record`` data type in the earlier sections, the
:bro:type:`connection` record passed to many events. Another one,
:bro:type:`Conn::Info`, which corresponds to the fields logged into
@ -915,11 +931,7 @@ through a contrived example of simply logging the digits 1 through 10
and their corresponding factorial to the default ASCII log writer.
It's always best to work through the problem once, simulating the
desired output with ``print`` and ``fmt`` before attempting to dive
into the Logging Framework. Below is a script that defines a
factorial function to recursively calculate the factorial of a
unsigned integer passed as an argument to the function. Using
``print`` and :bro:id:`fmt` we can ensure that Bro can perform these
calculations correctly as well get an idea of the answers ourselves.
into the Logging Framework.
.. btest-include:: ${DOC_ROOT}/scripting/framework_logging_factorial_01.bro
@ -927,19 +939,28 @@ calculations correctly as well get an idea of the answers ourselves.
@TEST-EXEC: btest-rst-cmd bro ${DOC_ROOT}/scripting/framework_logging_factorial_01.bro
This script defines a factorial function to recursively calculate the
factorial of a unsigned integer passed as an argument to the function. Using
``print`` and :bro:id:`fmt` we can ensure that Bro can perform these
calculations correctly as well get an idea of the answers ourselves.
The output of the script aligns with what we expect so now it's time
to integrate the Logging Framework. As mentioned above we have to
perform a few steps before we can issue the :bro:id:`Log::write`
method and produce a logfile. As we are working within a namespace
and informing an outside entity of workings and data internal to the
namespace, we use an ``export`` block. First we need to inform Bro
to integrate the Logging Framework.
.. btest-include:: ${DOC_ROOT}/scripting/framework_logging_factorial_02.bro
As mentioned above we have to perform a few steps before we can
issue the :bro:id:`Log::write` method and produce a logfile.
As we are working within a namespace and informing an outside
entity of workings and data internal to the namespace, we use
an ``export`` block. First we need to inform Bro
that we are going to be adding another Log Stream by adding a value to
the :bro:type:`Log::ID` enumerable. In line 6 of the script, we append the
the :bro:type:`Log::ID` enumerable. In this script, we append the
value ``LOG`` to the ``Log::ID`` enumerable, however due to this being in
an export block the value appended to ``Log::ID`` is actually
``Factor::Log``. Next, we need to define the name and value pairs
that make up the data of our logs and dictate its format. Lines 8
through 11 define a new datatype called an ``Info`` record (actually,
that make up the data of our logs and dictate its format. This script
defines a new record datatype called ``Info`` (actually,
``Factor::Info``) with two fields, both unsigned integers. Each of the
fields in the ``Factor::Log`` record type include the ``&log``
attribute, indicating that these fields should be passed to the
@ -947,16 +968,14 @@ Logging Framework when ``Log::write`` is called. Were there to be
any name value pairs without the ``&log`` attribute, those fields
would simply be ignored during logging but remain available for the
lifespan of the variable. The next step is to create the logging
stream with :bro:id:`Log::create_stream` which takes a Log::ID and a
record as its arguments. In this example, on line 25, we call the
stream with :bro:id:`Log::create_stream` which takes a ``Log::ID`` and a
record as its arguments. In this example, we call the
``Log::create_stream`` method and pass ``Factor::LOG`` and the
``Factor::Info`` record as arguments. From here on out, if we issue
the ``Log::write`` command with the correct ``Log::ID`` and a properly
formatted ``Factor::Info`` record, a log entry will be generated.
.. btest-include:: ${DOC_ROOT}/scripting/framework_logging_factorial_02.bro
Now, if we run the new version of the script, instead of generating
Now, if we run this script, instead of generating
logging information to stdout, no output is created. Instead the
output is all in ``factor.log``, properly formatted and organized.
@ -995,13 +1014,13 @@ remaining logs to factor.log.
:lines: 38-62
:linenos:
To dynamically alter the file in which a stream writes its logs a
filter can specify function returns a string to be used as the
To dynamically alter the file in which a stream writes its logs, a
filter can specify a function that returns a string to be used as the
filename for the current call to ``Log::write``. The definition for
this function has to take as its parameters a ``Log::ID`` called id, a
string called ``path`` and the appropriate record type for the logs called
``rec``. You can see the definition of ``mod5`` used in this example on
line one conforms to that requirement. The function simply returns
``rec``. You can see the definition of ``mod5`` used in this example
conforms to that requirement. The function simply returns
``factor-mod5`` if the factorial is divisible evenly by 5, otherwise, it
returns ``factor-non5``. In the additional ``bro_init`` event
handler, we define a locally scoped ``Log::Filter`` and assign it a
@ -1074,7 +1093,8 @@ make a call to :bro:id:`NOTICE` supplying it with an appropriate
:bro:type:`Notice::Info` record. Often times the call to ``NOTICE``
includes just the ``Notice::Type``, and a concise message. There are
however, significantly more options available when raising notices as
seen in the table below. The only field in the table below whose
seen in the definition of :bro:type:`Notice::Info`. The only field in
``Notice::Info`` whose
attributes make it a required field is the ``note`` field. Still,
good manners are always important and including a concise message in
``$msg`` and, where necessary, the contents of the connection record
@ -1086,57 +1106,6 @@ that are commonly included, ``$identifier`` and ``$suppress_for`` are
built around the automated suppression feature of the Notice Framework
which we will cover shortly.
.. todo::
Once the link to ``Notice::Info`` work I think we should take out
the table. That's too easy to get out of date.
+---------------------+------------------------------------------------------------------+----------------+----------------------------------------+
| Field | Type | Attributes | Use |
+=====================+==================================================================+================+========================================+
| ts | time | &log &optional | The time of the notice |
+---------------------+------------------------------------------------------------------+----------------+----------------------------------------+
| uid | string | &log &optional | A unique connection ID |
+---------------------+------------------------------------------------------------------+----------------+----------------------------------------+
| id | conn_id | &log &optional | A 4-tuple to identify endpoints |
+---------------------+------------------------------------------------------------------+----------------+----------------------------------------+
| conn | connection | &optional | Shorthand for the uid and id |
+---------------------+------------------------------------------------------------------+----------------+----------------------------------------+
| iconn | icmp_conn | &optional | Shorthand for the uid and id |
+---------------------+------------------------------------------------------------------+----------------+----------------------------------------+
| proto | transport_proto | &log &optional | Transport protocol |
+---------------------+------------------------------------------------------------------+----------------+----------------------------------------+
| note | Notice::Type | &log | The Notice::Type of the notice |
+---------------------+------------------------------------------------------------------+----------------+----------------------------------------+
| msg | string | &log &optional | Human readable message |
+---------------------+------------------------------------------------------------------+----------------+----------------------------------------+
| sub | string | &log &optional | Human readable message |
+---------------------+------------------------------------------------------------------+----------------+----------------------------------------+
| src | addr | &log &optional | Source address if no conn_id |
+---------------------+------------------------------------------------------------------+----------------+----------------------------------------+
| dst | addr | &log &optional | Destination addr if no conn_id |
+---------------------+------------------------------------------------------------------+----------------+----------------------------------------+
| p | port | &log &optional | Port if no conn_id |
+---------------------+------------------------------------------------------------------+----------------+----------------------------------------+
| n | count | &log &optional | Count or status code |
+---------------------+------------------------------------------------------------------+----------------+----------------------------------------+
| src_peer | event_peer | &log &optional | Peer that raised the notice |
+---------------------+------------------------------------------------------------------+----------------+----------------------------------------+
| peer_descr | string | &log &optional | Text description of the src_peer |
+---------------------+------------------------------------------------------------------+----------------+----------------------------------------+
| actions | set[Notice::Action] | &log &optional | Actions applied to the notice |
+---------------------+------------------------------------------------------------------+----------------+----------------------------------------+
| policy_items | set[count] | &log &optional | Policy items that have been applied |
+---------------------+------------------------------------------------------------------+----------------+----------------------------------------+
| email_body_sections | vector | &optional | Body of the email for email notices. |
+---------------------+------------------------------------------------------------------+----------------+----------------------------------------+
| email_delay_tokens | set[string] | &optional | Delay functionality for email notices. |
+---------------------+------------------------------------------------------------------+----------------+----------------------------------------+
| identifier | string | &optional | A unique string identifier |
+---------------------+------------------------------------------------------------------+----------------+----------------------------------------+
| suppress_for | interval | &log &optional | Length of time to suppress a notice. |
+---------------------+------------------------------------------------------------------+----------------+----------------------------------------+
One of the default policy scripts raises a notice when an SSH login
has been heuristically detected and the originating hostname is one
that would raise suspicion. Effectively, the script attempts to
@ -1153,15 +1122,15 @@ possible while staying concise.
While much of the script relates to the actual detection, the parts
specific to the Notice Framework are actually quite interesting in
themselves. On line 18 the script's ``export`` block adds the value
themselves. The script's ``export`` block adds the value
``SSH::Interesting_Hostname_Login`` to the enumerable constant
``Notice::Type`` to indicate to the Bro core that a new type of notice
is being defined. The script then calls ``NOTICE`` and defines the
``$note``, ``$msg``, ``$sub`` and ``$conn`` fields of the
:bro:type:`Notice::Info` record. Line 42 also includes a ternary if
statement that modifies the ``$msg`` text depending on whether the
:bro:type:`Notice::Info` record. There are two ternary if
statements that modify the ``$msg`` text depending on whether the
host is a local address and whether it is the client or the server.
This use of :bro:id:`fmt` and a ternary operators is a concise way to
This use of :bro:id:`fmt` and ternary operators is a concise way to
lend readability to the notices that are generated without the need
for branching ``if`` statements that each raise a specific notice.
@ -1222,7 +1191,7 @@ from the connection relative to the behavior that has been observed by
Bro.
.. btest-include:: ${BRO_SRC_ROOT}/scripts/policy/protocols/ssl/expiring-certs.bro
:lines: 60-63
:lines: 64-68
In the :doc:`/scripts/policy/protocols/ssl/expiring-certs.bro` script
which identifies when SSL certificates are set to expire and raises
@ -1302,9 +1271,9 @@ in the call to ``NOTICE``.
.. btest-include:: ${DOC_ROOT}/scripting/framework_notice_shortcuts_01.bro
The Notice Policy shortcut above adds the ``Notice::Types`` of
SSH::Interesting_Hostname_Login and SSH::Login to the
Notice::emailed_types set while the shortcut below alters the length
The Notice Policy shortcut above adds the ``Notice::Type`` of
``SSH::Interesting_Hostname_Login`` to the
``Notice::emailed_types`` set while the shortcut below alters the length
of time for which those notices will be suppressed.
.. btest-include:: ${DOC_ROOT}/scripting/framework_notice_shortcuts_02.bro

5
man/CMakeLists.txt Normal file
View file

@ -0,0 +1,5 @@
install(DIRECTORY . DESTINATION ${BRO_MAN_INSTALL_PATH}/man8 FILES_MATCHING
PATTERN "*.8"
)

164
man/bro.8 Normal file
View file

@ -0,0 +1,164 @@
.TH BRO "8" "November 2014" "bro" "System Administration Utilities"
.SH NAME
bro \- passive network traffic analyzer
.SH SYNOPSIS
.B bro
\/\fP [\fIoptions\fR] [\fIfile\fR ...]
.SH DESCRIPTION
Bro is primarily a security monitor that inspects all traffic on a link in
depth for signs of suspicious activity. More generally, however, Bro
supports a wide range of traffic analysis tasks even outside of the
security domain, including performance measurements and helping with
trouble-shooting.
Bro comes with built-in functionality for a range of analysis and detection
tasks, including detecting malware by interfacing to external registries,
reporting vulnerable versions of software seen on the network, identifying
popular web applications, detecting SSH brute-forcing, validating SSL
certificate chains, among others.
.SH OPTIONS
.TP
.B <file>
policy file, or read stdin
.TP
\fB\-a\fR,\ \-\-parse\-only
exit immediately after parsing scripts
.TP
\fB\-b\fR,\ \-\-bare\-mode
don't load scripts from the base/ directory
.TP
\fB\-d\fR,\ \-\-debug\-policy
activate policy file debugging
.TP
\fB\-e\fR,\ \-\-exec <bro code>
augment loaded policies by given code
.TP
\fB\-f\fR,\ \-\-filter <filter>
tcpdump filter
.TP
\fB\-g\fR,\ \-\-dump\-config
dump current config into .state dir
.TP
\fB\-h\fR,\ \-\-help|\-?
command line help
.TP
\fB\-i\fR,\ \-\-iface <interface>
read from given interface
.TP
\fB\-p\fR,\ \-\-prefix <prefix>
add given prefix to policy file resolution
.TP
\fB\-r\fR,\ \-\-readfile <readfile>
read from given tcpdump file
.TP
\fB\-y\fR,\ \-\-flowfile <file>[=<ident>]
read from given flow file
.TP
\fB\-Y\fR,\ \-\-netflow <ip>:<prt>[=<id>]
read flow from socket
.TP
\fB\-s\fR,\ \-\-rulefile <rulefile>
read rules from given file
.TP
\fB\-t\fR,\ \-\-tracefile <tracefile>
activate execution tracing
.TP
\fB\-w\fR,\ \-\-writefile <writefile>
write to given tcpdump file
.TP
\fB\-v\fR,\ \-\-version
print version and exit
.TP
\fB\-x\fR,\ \-\-print\-state <file.bst>
print contents of state file
.TP
\fB\-z\fR,\ \-\-analyze <analysis>
run the specified policy file analysis
.TP
\fB\-C\fR,\ \-\-no\-checksums
ignore checksums
.TP
\fB\-D\fR,\ \-\-dfa\-size <size>
DFA state cache size
.TP
\fB\-F\fR,\ \-\-force\-dns
force DNS
.TP
\fB\-I\fR,\ \-\-print\-id <ID name>
print out given ID
.TP
\fB\-K\fR,\ \-\-md5\-hashkey <hashkey>
set key for MD5\-keyed hashing
.TP
\fB\-L\fR,\ \-\-rule\-benchmark
benchmark for rules
.TP
\fB\-N\fR,\ \-\-print\-plugins
print available plugins and exit (\fB\-NN\fR for verbose)
.TP
\fB\-O\fR,\ \-\-optimize
optimize policy script
.TP
\fB\-P\fR,\ \-\-prime\-dns
prime DNS
.TP
\fB\-Q\fR,\ \-\-time
print execution time summary to stderr
.TP
\fB\-R\fR,\ \-\-replay <events.bst>
replay events
.TP
\fB\-S\fR,\ \-\-debug\-rules
enable rule debugging
.TP
\fB\-T\fR,\ \-\-re\-level <level>
set 'RE_level' for rules
.TP
\fB\-U\fR,\ \-\-status\-file <file>
Record process status in file
.TP
\fB\-W\fR,\ \-\-watchdog
activate watchdog timer
.TP
\fB\-X\fR,\ \-\-broxygen
generate documentation based on config file
.TP
\fB\-\-pseudo\-realtime[=\fR<speedup>]
enable pseudo\-realtime for performance evaluation (default 1)
.TP
\fB\-\-load\-seeds\fR <file>
load seeds from given file
.TP
\fB\-\-save\-seeds\fR <file>
save seeds to given file
.SH ENVIRONMENT
.TP
.B BROPATH
file search path
.TP
.B BRO_PLUGIN_PATH
plugin search path
.TP
.B BRO_PLUGIN_ACTIVATE
plugins to always activate
.TP
.B BRO_PREFIXES
prefix list
.TP
.B BRO_DNS_FAKE
disable DNS lookups
.TP
.B BRO_SEED_FILE
file to load seeds from
.TP
.B BRO_LOG_SUFFIX
ASCII log file extension
.TP
.B BRO_PROFILER_FILE
Output file for script execution statistics
.TP
.B BRO_DISABLE_BROXYGEN
Disable Broxygen documentation support
.SH AUTHOR
.B bro
was written by The Bro Project <info@bro.org>.

View file

@ -16,6 +16,7 @@ the 'dpkg-dev' package, please install it first.
}
prefix=/opt/bro
localstatedir=/var/opt/bro
# During the packaging process, `dpkg-shlibs` will fail if used on a library
# that links to other internal/project libraries unless an RPATH is used or
@ -31,7 +32,7 @@ cd ..
( cd build && make package )
# Full Bro package
./configure --prefix=${prefix} --pkg-name-prefix=Bro --binary-package
./configure --prefix=${prefix} --localstatedir=${localstatedir} --pkg-name-prefix=Bro --binary-package
( cd build && make package )
# Broccoli
@ -42,6 +43,6 @@ cd ../..
# Broctl
cd aux/broctl
./configure --prefix=${prefix} --binary-package
./configure --prefix=${prefix} --localstatedir=${localstatedir} --binary-package
( cd build && make package && mv *.deb ../../../build/ )
cd ../..

View file

@ -15,6 +15,7 @@ the 'rpm-build' package, please install it first.
}
prefix=/opt/bro
localstatedir=/var/opt/bro
cd ..
@ -24,7 +25,7 @@ cd ..
( cd build && make package )
# Full Bro package
./configure --prefix=${prefix} --pkg-name-prefix=Bro --binary-package
./configure --prefix=${prefix} --localstatedir=${localstatedir} --pkg-name-prefix=Bro --binary-package
( cd build && make package )
# Broccoli
@ -35,6 +36,6 @@ cd ../..
# Broctl
cd aux/broctl
./configure --prefix=${prefix} --binary-package
./configure --prefix=${prefix} --localstatedir=${localstatedir} --binary-package
( cd build && make package && mv *.rpm ../../../build/ )
cd ../..

View file

@ -71,11 +71,50 @@ global classification_map: table[count] of string;
global sid_map: table[count] of string;
global gen_map: table[count] of string;
global num_classification_map_reads = 0;
global num_sid_map_reads = 0;
global num_gen_map_reads = 0;
global watching = F;
# For reading in config files.
type OneLine: record {
line: string;
};
function mappings_initialized(): bool
{
return num_classification_map_reads > 0 &&
num_sid_map_reads > 0 &&
num_gen_map_reads > 0;
}
function start_watching()
{
if ( watching )
return;
watching = T;
if ( watch_dir != "" )
{
Dir::monitor(watch_dir, function(fname: string)
{
Input::add_analysis([$source=fname,
$reader=Input::READER_BINARY,
$mode=Input::STREAM,
$name=fname]);
}, 10secs);
}
if ( watch_file != "" )
{
Input::add_analysis([$source=watch_file,
$reader=Input::READER_BINARY,
$mode=Input::STREAM,
$name=watch_file]);
}
}
function create_info(ev: IDSEvent): Info
{
local info = Info($ts=ev$ts,
@ -136,11 +175,33 @@ event Unified2::read_classification_line(desc: Input::EventDescription, tpe: Inp
}
}
event Input::end_of_data(name: string, source: string)
{
if ( name == classification_config )
++num_classification_map_reads;
else if ( name == sid_msg )
++num_sid_map_reads;
else if ( name == gen_msg )
++num_gen_map_reads;
else
return;
if ( watching )
return;
if ( mappings_initialized() )
start_watching();
}
event bro_init() &priority=5
{
Log::create_stream(Unified2::LOG, [$columns=Info, $ev=log_unified2]);
if ( sid_msg != "" )
if ( sid_msg == "" )
{
num_sid_map_reads = 1;
}
else
{
Input::add_event([$source=sid_msg,
$reader=Input::READER_RAW,
@ -151,7 +212,11 @@ event bro_init() &priority=5
$ev=Unified2::read_sid_msg_line]);
}
if ( gen_msg != "" )
if ( gen_msg == "" )
{
num_gen_map_reads = 1;
}
else
{
Input::add_event([$source=gen_msg,
$name=gen_msg,
@ -162,7 +227,11 @@ event bro_init() &priority=5
$ev=Unified2::read_gen_msg_line]);
}
if ( classification_config != "" )
if ( classification_config == "" )
{
num_classification_map_reads = 1;
}
else
{
Input::add_event([$source=classification_config,
$name=classification_config,
@ -173,24 +242,8 @@ event bro_init() &priority=5
$ev=Unified2::read_classification_line]);
}
if ( watch_dir != "" )
{
Dir::monitor(watch_dir, function(fname: string)
{
Input::add_analysis([$source=fname,
$reader=Input::READER_BINARY,
$mode=Input::STREAM,
$name=fname]);
}, 10secs);
}
if ( watch_file != "" )
{
Input::add_analysis([$source=watch_file,
$reader=Input::READER_BINARY,
$mode=Input::STREAM,
$name=watch_file]);
}
if ( mappings_initialized() )
start_watching();
}
event file_new(f: fa_file)

View file

@ -1,2 +1,3 @@
@load-sigs ./general
@load-sigs ./msoffice
@load-sigs ./libmagic

View file

@ -1,11 +1,137 @@
# General purpose file magic signatures.
signature file-plaintext {
file-magic /([[:print:][:space:]]{10})/
file-magic /^([[:print:][:space:]]{10})/
file-mime "text/plain", -20
}
signature file-tar {
file-magic /([[:print:]\x00]){100}(([[:digit:]\x00\x20]){8}){3}/
file-mime "application/x-tar", 150
file-magic /^[[:print:]\x00]{100}([[:digit:]\x20]{7}\x00){3}([[:digit:]\x20]{11}\x00){2}([[:digit:]\x00\x20]{7}[\x20\x00])[0-7\x00]/
file-mime "application/x-tar", 100
}
signature file-zip {
file-mime "application/zip", 10
file-magic /^PK\x03\x04.{2}/
}
signature file-jar {
file-mime "application/java-archive", 100
file-magic /^PK\x03\x04.{1,200}\x14\x00..META-INF\/MANIFEST\.MF/
}
signature file-java-applet {
file-magic /^\xca\xfe\xba\xbe...[\x2e-\x34]/
file-mime "application/x-java-applet", 71
}
# Shockwave flash
signature file-swf {
file-magic /^(F|C|Z)WS/
file-mime "application/x-shockwave-flash", 60
}
# Microsoft Outlook's Transport Neutral Encapsulation Format
signature file-tnef {
file-magic /^\x78\x9f\x3e\x22/
file-mime "application/vnd.ms-tnef", 100
}
# Mac OS X DMG files
signature file-dmg {
file-magic /^(\x78\x01\x73\x0D\x62\x62\x60|\x78\xDA\x63\x60\x18\x05|\x78\x01\x63\x60\x18\x05|\x78\xDA\x73\x0D|\x78[\x01\xDA]\xED[\xD0-\xD9])/
file-mime "application/x-dmg", 100
}
# Mac OS X Mach-O executable
signature file-mach-o {
file-magic /^[\xce\xcf]\xfa\xed\xfe/
file-mime "application/x-mach-o-executable", 100
}
# Mac OS X Universal Mach-O executable
signature file-mach-o-universal {
file-magic /^\xca\xfe\xba\xbe..\x00[\x01-\x14]/
file-mime "application/x-mach-o-executable", 100
}
# XAR (eXtensible ARchive) format.
# Mac OS X uses this for the .pkg format.
signature file-xar {
file-magic /^xar\!/
file-mime "application/x-xar", 100
}
signature file-pkcs7 {
file-magic /^MIME-Version:.*protocol=\"application\/pkcs7-signature\"/
file-mime "application/pkcs7-signature", 100
}
# Concatenated X.509 certificates in textual format.
signature file-pem {
file-magic /^-----BEGIN CERTIFICATE-----/
file-mime "application/x-pem"
}
# Java Web Start file.
signature file-jnlp {
file-magic /^\<jnlp\x20/
file-mime "application/x-java-jnlp-file", 100
}
signature file-ico {
file-magic /^\x00\x00\x01\x00/
file-mime "image/x-icon", 70
}
signature file-cur {
file-magic /^\x00\x00\x02\x00/
file-mime "image/x-cursor", 70
}
signature file-pcap {
file-magic /^(\xa1\xb2\xc3\xd4|\xd4\xc3\xb2\xa1)/
file-mime "application/vnd.tcpdump.pcap", 70
}
signature file-pcap-ng {
file-magic /^\x0a\x0d\x0d\x0a.{4}(\x1a\x2b\x3c\x4d|\x4d\x3c\x2b\x1a)/
file-mime "application/vnd.tcpdump.pcap", 100
}
signature file-shellscript {
file-mime "text/x-shellscript", 250
file-magic /^\x23\x21[^\n]{1,15}bin\/(env[[:space:]]+)?(ba|tc|c|z|fa|ae|k)?sh/
}
signature file-perl {
file-magic /^\x23\x21[^\n]{1,15}bin\/(env[[:space:]]+)?perl/
file-mime "text/x-perl", 60
}
signature file-ruby {
file-magic /^\x23\x21[^\n]{1,15}bin\/(env[[:space:]]+)?ruby/
file-mime "text/x-ruby", 60
}
signature file-python {
file-magic /^\x23\x21[^\n]{1,15}bin\/(env[[:space:]]+)?python/
file-mime "text/x-python", 60
}
signature file-php {
file-magic /^.*<\?php/
file-mime "text/x-php", 40
}
# Stereolithography ASCII format
signature file-stl-ascii {
file-magic /^solid\x20/
file-mime "application/sla", 10
}
# Sketchup model file
signature file-skp {
file-magic /^\xFF\xFE\xFF\x0E\x53\x00\x6B\x00\x65\x00\x74\x00\x63\x00\x68\x00\x55\x00\x70\x00\x20\x00\x4D\x00\x6F\x00\x64\x00\x65\x00\x6C\x00/
file-mime "application/skp", 100
}

View file

@ -7,42 +7,18 @@
# The instrumented version of the `file` command used to generate these
# is located at: https://github.com/jsiwek/file/tree/bro-signatures.
# >2080 string,=Foglio di lavoro Microsoft Exce (len=31), ["%s"], swap_endian=0
signature file-magic-auto0 {
file-mime "application/vnd.ms-excel", 340
file-magic /(.{2080})(Foglio di lavoro Microsoft Exce)/
}
# >2 string,=---BEGIN PGP PUBLIC KEY BLOCK- (len=30), ["PGP public key block"], swap_endian=0
signature file-magic-auto1 {
file-mime "application/pgp-keys", 330
file-magic /(.{2})(\x2d\x2d\x2dBEGIN PGP PUBLIC KEY BLOCK\x2d)/
}
# >2080 string,=Microsoft Excel 5.0 Worksheet (len=29), ["%s"], swap_endian=0
signature file-magic-auto2 {
file-mime "application/vnd.ms-excel", 320
file-magic /(.{2080})(Microsoft Excel 5\x2e0 Worksheet)/
}
# >11 string,=must be converted with BinHex (len=29), ["BinHex binary text"], swap_endian=0
signature file-magic-auto3 {
file-mime "application/mac-binhex40", 320
file-magic /(.{11})(must be converted with BinHex)/
}
# >2080 string,=Microsoft Word 6.0 Document (len=27), ["%s"], swap_endian=0
signature file-magic-auto4 {
file-mime "application/msword", 300
file-magic /(.{2080})(Microsoft Word 6\x2e0 Document)/
}
# >2080 string,=Documento Microsoft Word 6 (len=26), ["Spanish Microsoft Word 6 document data"], swap_endian=0
signature file-magic-auto5 {
file-mime "application/msword", 290
file-magic /(.{2080})(Documento Microsoft Word 6)/
}
# >0 string,=-----BEGIN PGP SIGNATURE- (len=25), ["PGP signature"], swap_endian=0
signature file-magic-auto6 {
file-mime "application/pgp-signature", 280
@ -92,36 +68,6 @@ signature file-magic-auto13 {
file-magic /(\x23\x21 ?\x2fusr\x2flocal\x2fbin\x2fgawk)/
}
# >0 string/wt,=#! /usr/local/bin/bash (len=22), ["Bourne-Again shell script text executable"], swap_endian=0
signature file-magic-auto14 {
file-mime "text/x-shellscript", 250
file-magic /(\x23\x21 ?\x2fusr\x2flocal\x2fbin\x2fbash)/
}
# >0 string/wt,=#! /usr/local/bin/tcsh (len=22), ["Tenex C shell script text executable"], swap_endian=0
signature file-magic-auto15 {
file-mime "text/x-shellscript", 250
file-magic /(\x23\x21 ?\x2fusr\x2flocal\x2fbin\x2ftcsh)/
}
# >0 string/wt,=#! /usr/local/bin/zsh (len=21), ["Paul Falstad's zsh script text executable"], swap_endian=0
signature file-magic-auto16 {
file-mime "text/x-shellscript", 240
file-magic /(\x23\x21 ?\x2fusr\x2flocal\x2fbin\x2fzsh)/
}
# >0 string/wt,=#! /usr/local/bin/ash (len=21), ["Neil Brown's ash script text executable"], swap_endian=0
signature file-magic-auto17 {
file-mime "text/x-shellscript", 240
file-magic /(\x23\x21 ?\x2fusr\x2flocal\x2fbin\x2fash)/
}
# >0 string/wt,=#! /usr/local/bin/ae (len=20), ["Neil Brown's ae script text executable"], swap_endian=0
signature file-magic-auto18 {
file-mime "text/x-shellscript", 230
file-magic /(\x23\x21 ?\x2fusr\x2flocal\x2fbin\x2fae)/
}
# >0 string,=# PaCkAgE DaTaStReAm (len=20), ["pkg Datastream (SVR4)"], swap_endian=0
signature file-magic-auto19 {
file-mime "application/x-svr4-package", 230
@ -140,30 +86,12 @@ signature file-magic-auto21 {
file-magic /(\x5bKDE Desktop Entry\x5d)/
}
# >512 string,=R\000o\000o\000t\000 \000E\000n\000t\000r\000y (len=19), ["Microsoft Word Document"], swap_endian=0
signature file-magic-auto22 {
file-mime "application/msword", 220
file-magic /(.{512})(R\x00o\x00o\x00t\x00 \x00E\x00n\x00t\x00r\x00y)/
}
# >0 string,=!<arch>\n__________E (len=19), ["MIPS archive"], swap_endian=0
signature file-magic-auto23 {
file-mime "application/x-archive", 220
file-magic /(\x21\x3carch\x3e\x0a\x5f\x5f\x5f\x5f\x5f\x5f\x5f\x5f\x5f\x5fE)/
}
# >0 string/wt,=#! /usr/local/tcsh (len=18), ["Tenex C shell script text executable"], swap_endian=0
signature file-magic-auto24 {
file-mime "text/x-shellscript", 210
file-magic /(\x23\x21 ?\x2fusr\x2flocal\x2ftcsh)/
}
# >0 string/wt,=#! /usr/local/bash (len=18), ["Bourne-Again shell script text executable"], swap_endian=0
signature file-magic-auto25 {
file-mime "text/x-shellscript", 210
file-magic /(\x23\x21 ?\x2fusr\x2flocal\x2fbash)/
}
# >0 string/t,=# KDE Config File (len=17), ["KDE config file"], swap_endian=0
signature file-magic-auto26 {
file-mime "application/x-kdelnk", 200
@ -189,12 +117,6 @@ signature file-magic-auto29 {
file-magic /(\x23\x21 ?\x2fusr\x2fbin\x2fnawk)/
}
# >0 string/wt,=#! /usr/bin/tcsh (len=16), ["Tenex C shell script text executable"], swap_endian=0
signature file-magic-auto30 {
file-mime "text/x-shellscript", 190
file-magic /(\x23\x21 ?\x2fusr\x2fbin\x2ftcsh)/
}
# >0 string/wt,=#! /usr/bin/gawk (len=16), ["GNU awk script text executable"], swap_endian=0
signature file-magic-auto31 {
file-mime "text/x-gawk", 190
@ -207,12 +129,6 @@ signature file-magic-auto32 {
file-magic /(.{369})(MICROSOFT PIFEX\x00)/
}
# >0 string/wt,=#! /usr/bin/bash (len=16), ["Bourne-Again shell script text executable"], swap_endian=0
signature file-magic-auto33 {
file-mime "text/x-shellscript", 190
file-magic /(\x23\x21 ?\x2fusr\x2fbin\x2fbash)/
}
# >0 string/w,=#VRML V1.0 ascii (len=16), ["VRML 1 file"], swap_endian=0
signature file-magic-auto34 {
file-mime "model/vrml", 190
@ -334,12 +250,6 @@ signature file-magic-auto51 {
file-magic /(\x23\x21 ?\x2fusr\x2fbin\x2fawk)/
}
# >0 string/wt,=#! /usr/bin/zsh (len=15), ["Paul Falstad's zsh script text executable"], swap_endian=0
signature file-magic-auto52 {
file-mime "text/x-shellscript", 180
file-magic /(\x23\x21 ?\x2fusr\x2fbin\x2fzsh)/
}
# >0 string,=MAS_UTrack_V00 (len=14), [""], swap_endian=0
# >>14 string,>/0 (len=2), ["ultratracker V1.%.1s module sound data"], swap_endian=0
signature file-magic-auto53 {
@ -457,12 +367,6 @@ signature file-magic-auto70 {
file-magic /(\x3cmap ?version)/
}
# >0 string/wt,=#! /bin/tcsh (len=12), ["Tenex C shell script text executable"], swap_endian=0
signature file-magic-auto71 {
file-mime "text/x-shellscript", 150
file-magic /(\x23\x21 ?\x2fbin\x2ftcsh)/
}
# >0 string/wt,=#! /bin/nawk (len=12), ["new awk script text executable"], swap_endian=0
signature file-magic-auto72 {
file-mime "text/x-nawk", 150
@ -475,12 +379,6 @@ signature file-magic-auto73 {
file-magic /(\x23\x21 ?\x2fbin\x2fgawk)/
}
# >0 string/wt,=#! /bin/bash (len=12), ["Bourne-Again shell script text executable"], swap_endian=0
signature file-magic-auto74 {
file-mime "text/x-shellscript", 150
file-magic /(\x23\x21 ?\x2fbin\x2fbash)/
}
# >0 string/wt,=#! /bin/awk (len=11), ["awk script text executable"], swap_endian=0
signature file-magic-auto75 {
file-mime "text/x-awk", 140
@ -505,24 +403,6 @@ signature file-magic-auto78 {
file-magic /(d8\x3aannounce)/
}
# >0 string/wt,=#! /bin/csh (len=11), ["C shell script text executable"], swap_endian=0
signature file-magic-auto79 {
file-mime "text/x-shellscript", 140
file-magic /(\x23\x21 ?\x2fbin\x2fcsh)/
}
# >0 string/wt,=#! /bin/ksh (len=11), ["Korn shell script text executable"], swap_endian=0
signature file-magic-auto80 {
file-mime "text/x-shellscript", 140
file-magic /(\x23\x21 ?\x2fbin\x2fksh)/
}
# >0 string/wt,=#! /bin/zsh (len=11), ["Paul Falstad's zsh script text executable"], swap_endian=0
signature file-magic-auto81 {
file-mime "text/x-shellscript", 140
file-magic /(\x23\x21 ?\x2fbin\x2fzsh)/
}
# >0 string/c,=BEGIN:VCARD (len=11), ["vCard visiting card"], swap_endian=0
signature file-magic-auto82 {
file-mime "text/x-vcard", 140
@ -545,12 +425,6 @@ signature file-magic-auto84 {
file-magic /(Forward to)/
}
# >0 string/wt,=#! /bin/sh (len=10), ["POSIX shell script text executable"], swap_endian=0
signature file-magic-auto85 {
file-mime "text/x-shellscript", 130
file-magic /(\x23\x21 ?\x2fbin\x2fsh)/
}
# >0 string,=II*\000\020\000\000\000CR (len=10), ["Canon CR2 raw image data"], swap_endian=0
signature file-magic-auto86 {
file-mime "image/x-canon-cr2", 130
@ -585,12 +459,6 @@ signature file-magic-auto90 {
file-magic /(\x3cBookFile)/
}
# >2112 string,=MSWordDoc (len=9), ["Microsoft Word document data"], swap_endian=0
signature file-magic-auto91 {
file-mime "application/msword", 120
file-magic /(.{2112})(MSWordDoc)/
}
# >0 string/t,=N#! rnews (len=9), ["mailed, batched news text"], swap_endian=0
signature file-magic-auto92 {
file-mime "message/rfc822", 120
@ -656,12 +524,6 @@ signature file-magic-auto100 {
file-magic /(MSCF\x00\x00\x00\x00)/
}
# >0 string/b,=\320\317\021\340\241\261\032\341 (len=8), ["Microsoft Office Document"], swap_endian=0
signature file-magic-auto101 {
file-mime "application/msword", 110
file-magic /(\xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1)/
}
# >21 string/c,=!SCREAM! (len=8), ["Screamtracker 2 module sound data"], swap_endian=0
signature file-magic-auto102 {
file-mime "audio/x-mod", 110
@ -754,10 +616,10 @@ signature file-magic-auto116 {
}
# >257 string,=ustar \000 (len=8), ["GNU tar archive"], swap_endian=0
signature file-magic-auto117 {
file-mime "application/x-tar", 110
file-magic /(.{257})(ustar \x00)/
}
#signature file-magic-auto117 {
# file-mime "application/x-tar", 110
# file-magic /(.{257})(ustar \x00)/
#}
# >0 string,=<MIFFile (len=8), ["FrameMaker MIF (ASCII) file"], swap_endian=0
signature file-magic-auto118 {
@ -771,12 +633,6 @@ signature file-magic-auto119 {
file-magic /(PK\x07\x08PK\x03\x04)/
}
# >0 string/b,=\t\004\006\000\000\000\020\000 (len=8), ["Microsoft Excel Worksheet"], swap_endian=0
signature file-magic-auto120 {
file-mime "application/vnd.ms-excel", 110
file-magic /(\x09\x04\x06\x00\x00\x00\x10\x00)/
}
# >0 string/b,=WordPro\000 (len=8), ["Lotus WordPro"], swap_endian=0
signature file-magic-auto121 {
file-mime "application/vnd.lotus-wordpro", 110
@ -844,10 +700,10 @@ signature file-magic-auto130 {
}
# >257 string,=ustar\000 (len=6), ["POSIX tar archive"], swap_endian=0
signature file-magic-auto131 {
file-mime "application/x-tar", 90
file-magic /(.{257})(ustar\x00)/
}
#signature file-magic-auto131 {
# file-mime "application/x-tar", 90
# file-magic /(.{257})(ustar\x00)/
#}
# >0 string,=AC1.40 (len=6), ["DWG AutoDesk AutoCAD Release 1.40"], swap_endian=0
signature file-magic-auto132 {
@ -994,12 +850,6 @@ signature file-magic-auto155 {
file-magic /(\x23 xmcd)/
}
# >0 string/b,=\333\245-\000\000\000 (len=6), ["Microsoft Office Document"], swap_endian=0
signature file-magic-auto156 {
file-mime "application/msword", 90
file-magic /(\xdb\xa5\x2d\x00\x00\x00)/
}
# >2 string,=MMXPR3 (len=6), ["Motorola Quark Express Document (English)"], swap_endian=0
signature file-magic-auto157 {
file-mime "application/x-quark-xpress-3", 90
@ -1046,36 +896,6 @@ signature file-magic-auto162 {
file-magic /(\x3c\x3fxml)(.{15})(.*)( xmlns\x3d)(['"]http:\x2f\x2fwww.opengis.net\x2fkml)/
}
# >0 string,=PK\003\004 (len=4), [""], swap_endian=0
# >>30 regex,=[Content_Types].xml|_rels/.rels (len=31), [""], swap_endian=0
# >>>18 (lelong,+49), search/2000,=PK\003\004 (len=4), [""], swap_endian=0
# >>>>&26 search/1000,=PK\003\004 (len=4), [""], swap_endian=0
# >>>>>&26 string,=word/ (len=5), ["Microsoft Word 2007+"], swap_endian=0
signature file-magic-auto163 {
file-mime "application/vnd.openxmlformats-officedocument.wordprocessingml.document", 80
file-magic /(PK\x03\x04)(.{26})(\[Content_Types\].xml|_rels\x2f.rels)(.*)(PK\x03\x04)(.{26})(.*)(PK\x03\x04)(.{26})(word\x2f)/
}
# >0 string,=PK\003\004 (len=4), [""], swap_endian=0
# >>30 regex,=[Content_Types].xml|_rels/.rels (len=31), [""], swap_endian=0
# >>>18 (lelong,+49), search/2000,=PK\003\004 (len=4), [""], swap_endian=0
# >>>>&26 search/1000,=PK\003\004 (len=4), [""], swap_endian=0
# >>>>>&26 string,=ppt/ (len=4), ["Microsoft PowerPoint 2007+"], swap_endian=0
signature file-magic-auto164 {
file-mime "application/vnd.openxmlformats-officedocument.presentationml.presentation", 70
file-magic /(PK\x03\x04)(.{26})(\[Content_Types\].xml|_rels\x2f.rels)(.*)(PK\x03\x04)(.{26})(.*)(PK\x03\x04)(.{26})(ppt\x2f)/
}
# >0 string,=PK\003\004 (len=4), [""], swap_endian=0
# >>30 regex,=[Content_Types].xml|_rels/.rels (len=31), [""], swap_endian=0
# >>>18 (lelong,+49), search/2000,=PK\003\004 (len=4), [""], swap_endian=0
# >>>>&26 search/1000,=PK\003\004 (len=4), [""], swap_endian=0
# >>>>>&26 string,=xl/ (len=3), ["Microsoft Excel 2007+"], swap_endian=0
signature file-magic-auto165 {
file-mime "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", 60
file-magic /(PK\x03\x04)(.{26})(\[Content_Types\].xml|_rels\x2f.rels)(.*)(PK\x03\x04)(.{26})(.*)(PK\x03\x04)(.{26})(xl\x2f)/
}
# >60 string,=RINEX (len=5), [""], swap_endian=0
# >>80 search/256,=XXRINEXB (len=8), ["RINEX Data, GEO SBAS Broadcast"], swap_endian=0
# >>>5 string,x, [", version %6.6s"], swap_endian=0
@ -1229,30 +1049,12 @@ signature file-magic-auto187 {
file-magic /(\x00\x01\x00\x00\x00)/
}
# >0 string/b,=PO^Q` (len=5), ["Microsoft Word 6.0 Document"], swap_endian=0
signature file-magic-auto188 {
file-mime "application/msword", 80
file-magic /(PO\x5eQ\x60)/
}
# >0 string,=%PDF- (len=5), ["PDF document"], swap_endian=0
signature file-magic-auto189 {
file-mime "application/pdf", 80
file-magic /(\x25PDF\x2d)/
}
# >2114 string,=Biff5 (len=5), ["Microsoft Excel 5.0 Worksheet"], swap_endian=0
signature file-magic-auto190 {
file-mime "application/vnd.ms-excel", 80
file-magic /(.{2114})(Biff5)/
}
# >2121 string,=Biff5 (len=5), ["Microsoft Excel 5.0 Worksheet"], swap_endian=0
signature file-magic-auto191 {
file-mime "application/vnd.ms-excel", 80
file-magic /(.{2121})(Biff5)/
}
# >0 string/t,=Path: (len=5), ["news text"], swap_endian=0
signature file-magic-auto192 {
file-mime "message/news", 80
@ -1383,12 +1185,6 @@ signature file-magic-auto211 {
file-magic /(\x00\x00\x00\x01)([\x07\x27\x47\x67\x87\xa7\xc7\xe7])/
}
# >0 belong&,=-889275714 (0xcafebabe), [""], swap_endian=0
signature file-magic-auto212 {
file-mime "application/x-java-applet", 71
file-magic /(\xca\xfe\xba\xbe)/
}
# >0 belong&ffffffffffffff00,=256 (0x00000100), [""], swap_endian=0
# >>3 byte&,=0xba, ["MPEG sequence"], swap_endian=0
signature file-magic-auto213 {
@ -1706,46 +1502,6 @@ signature file-magic-auto245 {
file-magic /(PK\x03\x04)(.{22})(\x08\x00\x00\x00mimetypeapplication\x2f)(epub\x2bzip)/
}
# Seems redundant with other zip signature below.
# >0 string,=PK\003\004 (len=4), [""], swap_endian=0
# >>26 string,=\b\000\000\000mimetypeapplication/ (len=24), [""], swap_endian=0
# >>>50 string,!epub+zip (len=8), [""], swap_endian=0
# >>>>50 string,!vnd.oasis.opendocument. (len=23), [""], swap_endian=0
# >>>>>50 string,!vnd.sun.xml. (len=12), [""], swap_endian=0
# >>>>>>50 string,!vnd.kde. (len=8), [""], swap_endian=0
# >>>>>>>38 regex,=[!-OQ-~]+ (len=9), ["Zip data (MIME type "%s"?)"], swap_endian=0
#signature file-magic-auto246 {
# file-mime "application/zip", 39
# file-magic /(PK\x03\x04)(.{22})(\x08\x00\x00\x00mimetypeapplication\x2f)/
#}
# >0 string,=PK\003\004 (len=4), [""], swap_endian=0
# >>26 string,=\b\000\000\000mimetype (len=12), [""], swap_endian=0
# >>>38 string,!application/ (len=12), [""], swap_endian=0
# >>>>38 regex,=[!-OQ-~]+ (len=9), ["Zip data (MIME type "%s"?)"], swap_endian=0
signature file-magic-auto247 {
file-mime "application/zip", 39
file-magic /(PK\x03\x04)(.{22})(\x08\x00\x00\x00mimetype)/
}
# The indirect offset makes this difficult to convert.
# The (.*) may be too generous.
# >0 string,=PK\003\004 (len=4), [""], swap_endian=0
# >>26 (leshort,+30), leshort&,=-13570 (0xcafe), ["Java archive data (JAR)"], swap_endian=0
signature file-magic-auto248 {
file-mime "application/java-archive", 50
file-magic /(PK\x03\x04)(.*)(\xfe\xca)/
}
# The indeirect offset and string inequality make this difficult to convert.
# >0 string,=PK\003\004 (len=4), [""], swap_endian=0
# >>26 (leshort,+30), leshort&,!-13570 (0xcafe), [""], swap_endian=0
# >>>26 string,!\b\000\000\000mimetype (len=12), ["Zip archive data"], swap_endian=0
signature file-magic-auto249 {
file-mime "application/zip", 10
file-magic /(PK\x03\x04)(.{2})/
}
# >0 belong&,=442 (0x000001ba), [""], swap_endian=0
# >>4 byte&,&0x40, [""], swap_endian=0
signature file-magic-auto250 {
@ -2065,18 +1821,6 @@ signature file-magic-auto299 {
file-magic /(PDN3)/
}
# >0 ulelong&,=2712847316 (0xa1b2c3d4), ["tcpdump capture file (little-endian)"], swap_endian=0
signature file-magic-auto300 {
file-mime "application/vnd.tcpdump.pcap", 70
file-magic /(\xd4\xc3\xb2\xa1)/
}
# >0 ubelong&,=2712847316 (0xa1b2c3d4), ["tcpdump capture file (big-endian)"], swap_endian=0
signature file-magic-auto301 {
file-mime "application/vnd.tcpdump.pcap", 70
file-magic /(\xa1\xb2\xc3\xd4)/
}
# >0 belong&,=-17957139 (0xfeedfeed), ["Java KeyStore"], swap_endian=0
signature file-magic-auto302 {
file-mime "application/x-java-keystore", 70
@ -2297,12 +2041,6 @@ signature file-magic-auto335 {
file-magic /(SIT\x21)/
}
# >0 lelong&,=574529400 (0x223e9f78), ["Transport Neutral Encapsulation Format"], swap_endian=0
signature file-magic-auto336 {
file-mime "application/vnd.ms-tnef", 70
file-magic /(\x78\x9f\x3e\x22)/
}
# >0 string,=<ar> (len=4), ["System V Release 1 ar archive"], swap_endian=0
signature file-magic-auto337 {
file-mime "application/x-archive", 70
@ -2433,48 +2171,6 @@ signature file-magic-auto357 {
file-magic /(RIFF)(.{4})(AVI )/
}
# >0 belong&,=834535424 (0x31be0000), ["Microsoft Word Document"], swap_endian=0
signature file-magic-auto358 {
file-mime "application/msword", 70
file-magic /(\x31\xbe\x00\x00)/
}
# >0 string/b,=\3767\000# (len=4), ["Microsoft Office Document"], swap_endian=0
signature file-magic-auto359 {
file-mime "application/msword", 70
file-magic /(\xfe7\x00\x23)/
}
# >0 string/b,=\333\245-\000 (len=4), ["Microsoft WinWord 2.0 Document"], swap_endian=0
signature file-magic-auto360 {
file-mime "application/msword", 70
file-magic /(\xdb\xa5\x2d\x00)/
}
# >0 string/b,=\333\245-\000 (len=4), ["Microsoft WinWord 2.0 Document"], swap_endian=0
signature file-magic-auto361 {
file-mime "application/msword", 70
file-magic /(\xdb\xa5\x2d\x00)/
}
# >0 belong&,=6656 (0x00001a00), ["Lotus 1-2-3"], swap_endian=0
signature file-magic-auto362 {
file-mime "application/x-123", 70
file-magic /(\x00\x00\x1a\x00)/
}
# >0 belong&,=512 (0x00000200), ["Lotus 1-2-3"], swap_endian=0
signature file-magic-auto363 {
file-mime "application/x-123", 70
file-magic /(\x00\x00\x02\x00)/
}
# >0 string/b,=\000\000\001\000 (len=4), ["MS Windows icon resource"], swap_endian=0
signature file-magic-auto364 {
file-mime "image/x-icon", 70
file-magic /(\x00\x00\x01\x00)/
}
# >0 lelong&,=268435536 (0x10000050), ["Psion Series 5"], swap_endian=0
# >>4 lelong&,=268435565 (0x1000006d), ["database"], swap_endian=0
# >>>8 lelong&,=268435588 (0x10000084), ["Agenda file"], swap_endian=0
@ -2737,12 +2433,6 @@ signature file-magic-auto403 {
file-magic /(SBI)/
}
# >0 string/b,=\224\246. (len=3), ["Microsoft Word Document"], swap_endian=0
signature file-magic-auto404 {
file-mime "application/msword", 60
file-magic /(\x94\xa6\x2e)/
}
# >0 string,=\004%! (len=3), ["PostScript document text"], swap_endian=0
signature file-magic-auto405 {
file-mime "application/postscript", 60
@ -2763,30 +2453,11 @@ signature file-magic-auto407 {
file-magic /(.*)([ \x09]*(class|module)[ \x09][A-Z])((modul|includ)e [A-Z]|def [a-z])(^[ \x09]*end([ \x09]*[;#].*)?$)/
}
# >512 string/b,=\354\245\301 (len=3), ["Microsoft Word Document"], swap_endian=0
signature file-magic-auto408 {
file-mime "application/msword", 60
file-magic /(.{512})(\xec\xa5\xc1)/
}
# >0 string,=FWS (len=3), ["Macromedia Flash data,"], swap_endian=0
# >>3 byte&,x, ["version %d"], swap_endian=0
signature file-magic-auto409 {
file-mime "application/x-shockwave-flash", 1
file-magic /(FWS)(.{1})/
}
# >0 string,=CWS (len=3), ["Macromedia Flash data (compressed),"], swap_endian=0
signature file-magic-auto410 {
file-mime "application/x-shockwave-flash", 60
file-magic /(CWS)/
}
# >0 regex/20,=^\.[A-Za-z0-9][A-Za-z0-9][ \t] (len=29), ["troff or preprocessor input text"], swap_endian=0
signature file-magic-auto411 {
file-mime "text/troff", 59
file-magic /(^\.[A-Za-z0-9][A-Za-z0-9][ \x09])/
}
#signature file-magic-auto411 {
# file-mime "text/troff", 59
# file-magic /(^\.[A-Za-z0-9][A-Za-z0-9][ \x09])/
#}
# >0 search/4096,=\documentclass (len=14), ["LaTeX 2e document text"], swap_endian=0
signature file-magic-auto412 {
@ -2819,10 +2490,10 @@ signature file-magic-auto416 {
}
# >0 regex/20,=^\.[A-Za-z0-9][A-Za-z0-9]$ (len=26), ["troff or preprocessor input text"], swap_endian=0
signature file-magic-auto417 {
file-mime "text/troff", 56
file-magic /(^\.[A-Za-z0-9][A-Za-z0-9]$)/
}
#signature file-magic-auto417 {
# file-mime "text/troff", 56
# file-magic /(^\.[A-Za-z0-9][A-Za-z0-9]$)/
#}
# >0 search/w/1,=#! /usr/bin/php (len=15), ["PHP script text executable"], swap_endian=0
signature file-magic-auto418 {
@ -2842,30 +2513,12 @@ signature file-magic-auto420 {
file-magic /(.*)(eval \x22exec \x2fusr\x2fbin\x2fperl)/
}
# >0 search/w/1,=#! /usr/local/bin/python (len=24), ["Python script text executable"], swap_endian=0
signature file-magic-auto421 {
file-mime "text/x-python", 54
file-magic /(.*)(\x23\x21 ?\x2fusr\x2flocal\x2fbin\x2fpython)/
}
# >0 search/1,=Common subdirectories: (len=23), ["diff output text"], swap_endian=0
signature file-magic-auto422 {
file-mime "text/x-diff", 53
file-magic /(.*)(Common subdirectories\x3a )/
}
# >0 search/1,=#! /usr/bin/env python (len=22), ["Python script text executable"], swap_endian=0
signature file-magic-auto423 {
file-mime "text/x-python", 52
file-magic /(.*)(\x23\x21 \x2fusr\x2fbin\x2fenv python)/
}
# >0 search/w/1,=#! /usr/local/bin/ruby (len=22), ["Ruby script text executable"], swap_endian=0
signature file-magic-auto424 {
file-mime "text/x-ruby", 52
file-magic /(.*)(\x23\x21 ?\x2fusr\x2flocal\x2fbin\x2fruby)/
}
# >0 search/w/1,=#! /usr/local/bin/wish (len=22), ["Tcl/Tk script text executable"], swap_endian=0
signature file-magic-auto425 {
file-mime "text/x-tcl", 52
@ -2884,12 +2537,6 @@ signature file-magic-auto427 {
file-magic /(\xff\xd8)/
}
# >0 search/1,=#!/usr/bin/env python (len=21), ["Python script text executable"], swap_endian=0
signature file-magic-auto428 {
file-mime "text/x-python", 51
file-magic /(.*)(\x23\x21\x2fusr\x2fbin\x2fenv python)/
}
# >0 search/1,=#!/usr/bin/env nodejs (len=21), ["Node.js script text executable"], swap_endian=0
signature file-magic-auto429 {
file-mime "application/javascript", 51
@ -3202,12 +2849,6 @@ signature file-magic-auto474 {
file-magic /(\x25\x21)/
}
# >0 search/1,=#! /usr/bin/env ruby (len=20), ["Ruby script text executable"], swap_endian=0
signature file-magic-auto475 {
file-mime "text/x-ruby", 50
file-magic /(.*)(\x23\x21 \x2fusr\x2fbin\x2fenv ruby)/
}
# >0 regex/1,=(^[0-9]{5})[acdn][w] (len=20), ["MARC21 Classification"], swap_endian=0
signature file-magic-auto476 {
file-mime "application/marc", 50
@ -3241,10 +2882,10 @@ signature file-magic-auto480 {
}
# >0 string,=\n( (len=2), ["Emacs v18 byte-compiled Lisp data"], swap_endian=0
signature file-magic-auto481 {
file-mime "application/x-elc", 50
file-magic /(\x0a\x28)/
}
#signature file-magic-auto481 {
# file-mime "application/x-elc", 50
# file-magic /(\x0a\x28)/
#}
# >0 string,=\021\t (len=2), ["Award BIOS Logo, 136 x 126"], swap_endian=0
signature file-magic-auto482 {
@ -3318,17 +2959,17 @@ signature file-magic-auto493 {
file-magic /(\xf7\x02)/
}
# >2 string,=\000\021 (len=2), ["TeX font metric data"], swap_endian=0
signature file-magic-auto494 {
file-mime "application/x-tex-tfm", 50
file-magic /(.{2})(\x00\x11)/
}
# >2 string,=\000\022 (len=2), ["TeX font metric data"], swap_endian=0
signature file-magic-auto495 {
file-mime "application/x-tex-tfm", 50
file-magic /(.{2})(\x00\x12)/
}
## >2 string,=\000\021 (len=2), ["TeX font metric data"], swap_endian=0
#signature file-magic-auto494 {
# file-mime "application/x-tex-tfm", 50
# file-magic /(.{2})(\x00\x11)/
#}
#
## >2 string,=\000\022 (len=2), ["TeX font metric data"], swap_endian=0
#signature file-magic-auto495 {
# file-mime "application/x-tex-tfm", 50
# file-magic /(.{2})(\x00\x12)/
#}
# >0 beshort&,=-31486 (0x8502), ["GPG encrypted data"], swap_endian=0
signature file-magic-auto496 {
@ -3483,12 +3124,6 @@ signature file-magic-auto514 {
file-magic /(.*)(\x23\x21 \x2fusr\x2fbin\x2fenv lua)/
}
# >0 search/1,=#!/usr/bin/env ruby (len=19), ["Ruby script text executable"], swap_endian=0
signature file-magic-auto515 {
file-mime "text/x-ruby", 49
file-magic /(.*)(\x23\x21\x2fusr\x2fbin\x2fenv ruby)/
}
# >0 search/1,=#! /usr/bin/env tcl (len=19), ["Tcl script text executable"], swap_endian=0
signature file-magic-auto516 {
file-mime "text/x-tcl", 49
@ -3506,12 +3141,6 @@ signature file-magic-auto519 {
file-magic /(.*)(\x23\x21\x2fusr\x2fbin\x2fenv lua)/
}
# >0 search/w/1,=#! /usr/bin/python (len=18), ["Python script text executable"], swap_endian=0
signature file-magic-auto520 {
file-mime "text/x-python", 48
file-magic /(.*)(\x23\x21 ?\x2fusr\x2fbin\x2fpython)/
}
# >0 search/w/1,=#!/usr/bin/nodejs (len=17), ["Node.js script text executable"], swap_endian=0
signature file-magic-auto521 {
file-mime "application/javascript", 47
@ -3519,10 +3148,10 @@ signature file-magic-auto521 {
}
# >0 regex,=^class[ \t\n]+ (len=12), ["C++ source text"], swap_endian=0
signature file-magic-auto522 {
file-mime "text/x-c++", 47
file-magic /(.*)(class[ \x09\x0a]+[[:alnum:]_]+)(.*)(\x7b)(.*)(public:)/
}
#signature file-magic-auto522 {
# file-mime "text/x-c++", 47
# file-magic /(.*)(class[ \x09\x0a]+[[:alnum:]_]+)(.*)(\x7b)(.*)(public:)/
#}
# >0 search/1,=This is Info file (len=17), ["GNU Info text"], swap_endian=0
signature file-magic-auto528 {
@ -3671,12 +3300,6 @@ signature file-magic-auto545 {
file-magic /(.*)(\x23\x21 ?\x2fusr\x2fbin\x2fwish)/
}
# >0 search/w/1,=#! /usr/bin/ruby (len=16), ["Ruby script text executable"], swap_endian=0
signature file-magic-auto546 {
file-mime "text/x-ruby", 46
file-magic /(.*)(\x23\x21 ?\x2fusr\x2fbin\x2fruby)/
}
# >0 search/w/1,=#! /usr/bin/lua (len=15), ["Lua script text executable"], swap_endian=0
signature file-magic-auto547 {
file-mime "text/x-lua", 45
@ -3740,10 +3363,10 @@ signature file-magic-auto556 {
}
# >0 regex,=^extern[ \t\n]+ (len=13), ["C source text"], swap_endian=0
signature file-magic-auto557 {
file-mime "text/x-c", 43
file-magic /(.*)(extern[ \x09\x0a]+)/
}
#signature file-magic-auto557 {
# file-mime "text/x-c", 43
# file-magic /(.*)(extern[ \x09\x0a]+)/
#}
# >0 search/4096,=% -*-latex-*- (len=13), ["LaTeX document text"], swap_endian=0
signature file-magic-auto558 {
@ -3759,10 +3382,10 @@ signature file-magic-auto558 {
#}
# >0 regex,=^struct[ \t\n]+ (len=13), ["C source text"], swap_endian=0
signature file-magic-auto560 {
file-mime "text/x-c", 43
file-magic /(.*)(struct[ \x09\x0a]+)/
}
#signature file-magic-auto560 {
# file-mime "text/x-c", 43
# file-magic /(.*)(struct[ \x09\x0a]+)/
#}
# >0 search/w/1,=#!/bin/nodejs (len=13), ["Node.js script text executable"], swap_endian=0
signature file-magic-auto561 {
@ -3815,10 +3438,10 @@ signature file-magic-auto567 {
}
# >0 regex,=^char[ \t\n]+ (len=11), ["C source text"], swap_endian=0
signature file-magic-auto568 {
file-mime "text/x-c", 41
file-magic /(.*)(char[ \x09\x0a]+)/
}
#signature file-magic-auto568 {
# file-mime "text/x-c", 41
# file-magic /(.*)(char[ \x09\x0a]+)/
#}
# >0 search/1,=#! (len=2), [""], swap_endian=0
# >>0 regex,=^#!.*/bin/perl$ (len=15), ["Perl script text executable"], swap_endian=0
@ -3900,23 +3523,11 @@ signature file-magic-auto578 {
file-magic /(^dnl )/
}
# >0 regex,=^all: (len=5), ["makefile script text"], swap_endian=0
signature file-magic-auto579 {
file-mime "text/x-makefile", 40
file-magic /(^all:)/
}
# >0 regex,=^.PRECIOUS (len=10), ["makefile script text"], swap_endian=0
signature file-magic-auto580 {
file-mime "text/x-makefile", 40
file-magic /(^.PRECIOUS)/
}
# >0 search/8192,=main( (len=5), ["C source text"], swap_endian=0
signature file-magic-auto581 {
file-mime "text/x-c", 40
file-magic /(.*)(main\x28)/
}
#signature file-magic-auto581 {
# file-mime "text/x-c", 40
# file-magic /(.*)(main\x28)/
#}
# Not specific enough.
# >0 search/1,=\" (len=2), ["troff or preprocessor input text"], swap_endian=0
@ -3945,22 +3556,22 @@ signature file-magic-auto584 {
#}
# >0 regex,=^#include (len=9), ["C source text"], swap_endian=0
signature file-magic-auto586 {
file-mime "text/x-c", 39
file-magic /(.*)(#include)/
}
#signature file-magic-auto586 {
# file-mime "text/x-c", 39
# file-magic /(.*)(#include)/
#}
# >0 search/1,=.\" (len=3), ["troff or preprocessor input text"], swap_endian=0
signature file-magic-auto587 {
file-mime "text/troff", 39
file-magic /(.*)(\x2e\x5c\x22)/
}
#signature file-magic-auto587 {
# file-mime "text/troff", 39
# file-magic /(.*)(\x2e\x5c\x22)/
#}
# >0 search/1,='\" (len=3), ["troff or preprocessor input text"], swap_endian=0
signature file-magic-auto588 {
file-mime "text/troff", 39
file-magic /(.*)(\x27\x5c\x22)/
}
#signature file-magic-auto588 {
# file-mime "text/troff", 39
# file-magic /(.*)(\x27\x5c\x22)/
#}
# >0 search/1,=<TeXmacs| (len=9), ["TeXmacs document text"], swap_endian=0
signature file-magic-auto589 {
@ -3987,10 +3598,10 @@ signature file-magic-auto592 {
}
# >0 search/1,=''' (len=3), ["troff or preprocessor input text"], swap_endian=0
signature file-magic-auto593 {
file-mime "text/troff", 39
file-magic /(.*)(\x27\x27\x27)/
}
#signature file-magic-auto593 {
# file-mime "text/troff", 39
# file-magic /(.*)(\x27\x27\x27)/
#}
# >0 search/4096,=try: (len=4), [""], swap_endian=0
# >>&0 regex,=^\s*except.*: (len=13), ["Python script text executable"], swap_endian=0
@ -4012,12 +3623,6 @@ signature file-magic-auto596 {
file-magic /(.*)(\x22LIBHDR\x22)/
}
# >0 regex,=^SUBDIRS (len=8), ["automake makefile script text"], swap_endian=0
signature file-magic-auto597 {
file-mime "text/x-makefile", 38
file-magic /(.*)(SUBDIRS)/
}
# >0 search/4096,=(defvar (len=8), ["Lisp/Scheme program text"], swap_endian=0
signature file-magic-auto598 {
file-mime "text/x-lisp", 38
@ -4044,19 +3649,6 @@ signature file-magic-auto600 {
# file-magic /(.*)(\x2a\x2a\x2a )/
#}
# >0 search/1,='.\" (len=4), ["troff or preprocessor input text"], swap_endian=0
signature file-magic-auto602 {
file-mime "text/troff", 38
file-magic /(.*)(\x27\x2e\x5c\x22)/
}
# LDFLAGS appears in other contexts, e.g. shell script.
# >0 regex,=^LDFLAGS (len=8), ["makefile script text"], swap_endian=0
#signature file-magic-auto603 {
# file-mime "text/x-makefile", 38
# file-magic /(.*)(LDFLAGS)/
#}
# >0 search/8192,="libhdr" (len=8), ["BCPL source text"], swap_endian=0
signature file-magic-auto604 {
file-mime "text/x-bcpl", 38
@ -4070,12 +3662,6 @@ signature file-magic-auto604 {
# file-magic /(^record)/
#}
# >0 regex,=^CFLAGS (len=7), ["makefile script text"], swap_endian=0
signature file-magic-auto606 {
file-mime "text/x-makefile", 37
file-magic /(.*)(CFLAGS)/
}
# >0 search/4096,=(defun (len=7), ["Lisp/Scheme program text"], swap_endian=0
signature file-magic-auto607 {
file-mime "text/x-lisp", 37

View file

@ -0,0 +1,28 @@
# This signature is non-specific and terrible but after
# searching for a long time there doesn't seem to be a
# better option.
signature file-msword {
file-magic /^\xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1/
file-mime "application/msword", 50
}
signature file-ooxml {
file-magic /^PK\x03\x04\x14\x00\x06\x00/
file-mime "application/vnd.openxmlformats-officedocument", 50
}
signature file-docx {
file-magic /^PK\x03\x04.{26}(\[Content_Types\]\.xml|_rels\x2f\.rels|word\x2f).*PK\x03\x04.{26}word\x2f/
file-mime "application/vnd.openxmlformats-officedocument.wordprocessingml.document", 80
}
signature file-xlsx {
file-magic /^PK\x03\x04.{26}(\[Content_Types\]\.xml|_rels\x2f\.rels|xl\2f).*PK\x03\x04.{26}xl\x2f/
file-mime "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", 80
}
signature file-pptx {
file-magic /^PK\x03\x04.{26}(\[Content_Types\]\.xml|_rels\x2f\.rels|ppt\x2f).*PK\x03\x04.{26}ppt\x2f/
file-mime "application/vnd.openxmlformats-officedocument.presentationml.presentation", 80
}

View file

@ -100,8 +100,9 @@ export {
## during the process of analysis e.g. due to dropped packets.
missing_bytes: count &log &default=0;
## The number of not all-in-sequence bytes in the file stream that
## were delivered to file analyzers due to reassembly buffer overflow.
## The number of bytes in the file stream that were not delivered to
## stream file analyzers. This could be overlapping bytes or
## bytes that couldn't be reassembled.
overflow_bytes: count &log &default=0;
## Whether the file analysis timed out at least once for the file.
@ -124,6 +125,37 @@ export {
## generate two handles that would hash to the same file id.
const salt = "I recommend changing this." &redef;
## Decide if you want to automatically attached analyzers to
## files based on the detected mime type of the file.
const analyze_by_mime_type_automatically = T &redef;
## The default setting for if the file reassembler is enabled for
## each file.
const enable_reassembler = T &redef;
## The default per-file reassembly buffer size.
const reassembly_buffer_size = 1048576 &redef;
## Allows the file reassembler to be used if it's necessary because the
## file is transferred out of order.
##
## f: the file.
global enable_reassembly: function(f: fa_file);
## Disables the file reassembler on this file. If the file is not
## transferred out of order this will have no effect.
##
## f: the file.
global disable_reassembly: function(f: fa_file);
## Set the maximum size the reassembly buffer is allowed to grow
## for the given file.
##
## f: the file.
##
## max: Maximum allowed size of the reassembly buffer.
global set_reassembly_buffer_size: function(f: fa_file, max: count);
## Sets the *timeout_interval* field of :bro:see:`fa_file`, which is
## used to determine the length of inactivity that is allowed for a file
## before internal state related to it is cleaned up. When used within
@ -225,6 +257,42 @@ export {
## callback: Function to execute when the given file analyzer is being added.
global register_analyzer_add_callback: function(tag: Files::Tag, callback: function(f: fa_file, args: AnalyzerArgs));
## Registers a set of MIME types for an analyzer. If a future connection on one of
## these types is seen, the analyzer will be automatically assigned to parsing it.
## The function *adds* to all MIME types already registered, it doesn't replace
## them.
##
## tag: The tag of the analyzer.
##
## mts: The set of MIME types, each in the form "foo/bar" (case-insensitive).
##
## Returns: True if the MIME types were successfully registered.
global register_for_mime_types: function(tag: Analyzer::Tag, mts: set[string]) : bool;
## Registers a MIME type for an analyzer. If a future file with this type is seen,
## the analyzer will be automatically assigned to parsing it. The function *adds*
## to all MIME types already registered, it doesn't replace them.
##
## tag: The tag of the analyzer.
##
## mt: The MIME type in the form "foo/bar" (case-insensitive).
##
## Returns: True if the MIME type was successfully registered.
global register_for_mime_type: function(tag: Analyzer::Tag, mt: string) : bool;
## Returns a set of all MIME types currently registered for a specific analyzer.
##
## tag: The tag of the analyzer.
##
## Returns: The set of MIME types.
global registered_mime_types: function(tag: Analyzer::Tag) : set[string];
## Returns a table of all MIME-type-to-analyzer mappings currently registered.
##
## Returns: A table mapping each analyzer to the set of MIME types
## registered for it.
global all_registered_mime_types: function() : table[Analyzer::Tag] of set[string];
## Event that can be handled to access the Info record as it is sent on
## to the logging framework.
global log_files: event(rec: Info);
@ -237,6 +305,10 @@ redef record fa_file += {
# Store the callbacks for protocol analyzers that have files.
global registered_protocols: table[Analyzer::Tag] of ProtoRegistration = table();
# Store the MIME type to analyzer mappings.
global mime_types: table[Analyzer::Tag] of set[string];
global mime_type_to_analyzers: table[string] of set[Analyzer::Tag];
global analyzer_add_callbacks: table[Files::Tag] of function(f: fa_file, args: AnalyzerArgs) = table();
event bro_init() &priority=5
@ -265,8 +337,6 @@ function set_info(f: fa_file)
f$info$overflow_bytes = f$overflow_bytes;
if ( f?$is_orig )
f$info$is_orig = f$is_orig;
if ( f?$mime_type )
f$info$mime_type = f$mime_type;
}
function set_timeout_interval(f: fa_file, t: interval): bool
@ -274,6 +344,21 @@ function set_timeout_interval(f: fa_file, t: interval): bool
return __set_timeout_interval(f$id, t);
}
function enable_reassembly(f: fa_file)
{
__enable_reassembly(f$id);
}
function disable_reassembly(f: fa_file)
{
__disable_reassembly(f$id);
}
function set_reassembly_buffer_size(f: fa_file, max: count)
{
__set_reassembly_buffer(f$id, max);
}
function add_analyzer(f: fa_file, tag: Files::Tag, args: AnalyzerArgs): bool
{
add f$info$analyzers[Files::analyzer_name(tag)];
@ -309,39 +394,6 @@ function analyzer_name(tag: Files::Tag): string
return __analyzer_name(tag);
}
event file_new(f: fa_file) &priority=10
{
set_info(f);
}
event file_over_new_connection(f: fa_file, c: connection, is_orig: bool) &priority=10
{
set_info(f);
add f$info$conn_uids[c$uid];
local cid = c$id;
add f$info$tx_hosts[f$is_orig ? cid$orig_h : cid$resp_h];
if( |Site::local_nets| > 0 )
f$info$local_orig=Site::is_local_addr(f$is_orig ? cid$orig_h : cid$resp_h);
add f$info$rx_hosts[f$is_orig ? cid$resp_h : cid$orig_h];
}
event file_timeout(f: fa_file) &priority=10
{
set_info(f);
f$info$timedout = T;
}
event file_state_remove(f: fa_file) &priority=10
{
set_info(f);
}
event file_state_remove(f: fa_file) &priority=-10
{
Log::write(Files::LOG, f$info);
}
function register_protocol(tag: Analyzer::Tag, reg: ProtoRegistration): bool
{
local result = (tag !in registered_protocols);
@ -349,6 +401,46 @@ function register_protocol(tag: Analyzer::Tag, reg: ProtoRegistration): bool
return result;
}
function register_for_mime_types(tag: Analyzer::Tag, mime_types: set[string]) : bool
{
local rc = T;
for ( mt in mime_types )
{
if ( ! register_for_mime_type(tag, mt) )
rc = F;
}
return rc;
}
function register_for_mime_type(tag: Analyzer::Tag, mt: string) : bool
{
if ( tag !in mime_types )
{
mime_types[tag] = set();
}
add mime_types[tag][mt];
if ( mt !in mime_type_to_analyzers )
{
mime_type_to_analyzers[mt] = set();
}
add mime_type_to_analyzers[mt][tag];
return T;
}
function registered_mime_types(tag: Analyzer::Tag) : set[string]
{
return tag in mime_types ? mime_types[tag] : set();
}
function all_registered_mime_types(): table[Analyzer::Tag] of set[string]
{
return mime_types;
}
function describe(f: fa_file): string
{
local tag = Analyzer::get_tag(f$source);
@ -367,3 +459,61 @@ event get_file_handle(tag: Analyzer::Tag, c: connection, is_orig: bool) &priorit
local handler = registered_protocols[tag];
set_file_handle(handler$get_file_handle(c, is_orig));
}
event file_new(f: fa_file) &priority=10
{
set_info(f);
if ( enable_reassembler )
{
Files::enable_reassembly(f);
Files::set_reassembly_buffer_size(f, reassembly_buffer_size);
}
}
event file_over_new_connection(f: fa_file, c: connection, is_orig: bool) &priority=10
{
set_info(f);
add f$info$conn_uids[c$uid];
local cid = c$id;
add f$info$tx_hosts[f$is_orig ? cid$orig_h : cid$resp_h];
if( |Site::local_nets| > 0 )
f$info$local_orig=Site::is_local_addr(f$is_orig ? cid$orig_h : cid$resp_h);
add f$info$rx_hosts[f$is_orig ? cid$resp_h : cid$orig_h];
}
event file_mime_type(f: fa_file, mime_type: string) &priority=10
{
set_info(f);
f$info$mime_type = mime_type;
if ( analyze_by_mime_type_automatically &&
mime_type in mime_type_to_analyzers )
{
local analyzers = mime_type_to_analyzers[mime_type];
for ( a in analyzers )
{
add f$info$analyzers[Files::analyzer_name(a)];
Files::add_analyzer(f, a);
}
}
}
event file_timeout(f: fa_file) &priority=10
{
set_info(f);
f$info$timedout = T;
}
event file_state_remove(f: fa_file) &priority=10
{
set_info(f);
}
event file_state_remove(f: fa_file) &priority=-10
{
Log::write(Files::LOG, f$info);
}

View file

@ -4,6 +4,17 @@
module Input;
export {
type Event: enum {
EVENT_NEW = 0,
EVENT_CHANGED = 1,
EVENT_REMOVED = 2,
};
type Mode: enum {
MANUAL = 0,
REREAD = 1,
STREAM = 2
};
## The default input reader used. Defaults to `READER_ASCII`.
const default_reader = READER_ASCII &redef;

View file

@ -67,6 +67,7 @@ export {
IN_ANYWHERE,
};
## Information about a piece of "seen" data.
type Seen: record {
## The string if the data is about a string.
indicator: string &log &optional;
@ -81,6 +82,9 @@ export {
## Where the data was discovered.
where: Where &log;
## The name of the node where the match was discovered.
node: string &optional &log;
## If the data was discovered within a connection, the
## connection record should go here to give context to the data.
conn: connection &optional;
@ -121,7 +125,7 @@ export {
sources: set[string] &log &default=string_set();
};
## Intelligence data manipulation functions.
## Intelligence data manipulation function.
global insert: function(item: Item);
## Function to declare discovery of a piece of data in order to check
@ -240,6 +244,11 @@ function Intel::seen(s: Seen)
s$indicator_type = Intel::ADDR;
}
if ( ! s?$node )
{
s$node = peer_description;
}
if ( have_full_data )
{
local items = get_items(s);
@ -281,8 +290,8 @@ event Intel::match(s: Seen, items: set[Item]) &priority=5
if ( ! info?$fuid )
info$fuid = s$f$id;
if ( ! info?$file_mime_type && s$f?$mime_type )
info$file_mime_type = s$f$mime_type;
if ( ! info?$file_mime_type && s$f?$info && s$f$info?$mime_type )
info$file_mime_type = s$f$info$mime_type;
if ( ! info?$file_desc )
info$file_desc = Files::describe(s$f);

View file

@ -1,7 +1,5 @@
@load ./main
@load ./postprocessors
@load ./writers/ascii
@load ./writers/dataseries
@load ./writers/sqlite
@load ./writers/elasticsearch
@load ./writers/none

View file

@ -5,9 +5,15 @@
module Log;
# Log::ID and Log::Writer are defined in types.bif due to circular dependencies.
export {
## Type that defines an ID unique to each log stream. Scripts creating new log
## streams need to redef this enum to add their own specific log ID. The log ID
## implicitly determines the default name of the generated log file.
type Log::ID: enum {
## Dummy place-holder.
UNKNOWN
};
## If true, local logging is by default enabled for all filters.
const enable_local_logging = T &redef;

View file

@ -26,9 +26,9 @@ export {
## This option is also available as a per-filter ``$config`` option.
const use_json = F &redef;
## Format of timestamps when writing out JSON. By default, the JSON formatter will
## use double values for timestamps which represent the number of seconds from the
## UNIX epoch.
## Format of timestamps when writing out JSON. By default, the JSON
## formatter will use double values for timestamps which represent the
## number of seconds from the UNIX epoch.
const json_timestamps: JSON::TimestampFormat = JSON::TS_EPOCH &redef;
## If true, include lines with log meta information such as column names

View file

@ -1,60 +0,0 @@
##! Interface for the DataSeries log writer.
module LogDataSeries;
export {
## Compression to use with the DS output file. Options are:
##
## 'none' -- No compression.
## 'lzf' -- LZF compression (very quick, but leads to larger output files).
## 'lzo' -- LZO compression (very fast decompression times).
## 'gz' -- GZIP compression (slower than LZF, but also produces smaller output).
## 'bz2' -- BZIP2 compression (slower than GZIP, but also produces smaller output).
const compression = "gz" &redef;
## The extent buffer size.
## Larger values here lead to better compression and more efficient writes,
## but also increase the lag between the time events are received and
## the time they are actually written to disk.
const extent_size = 65536 &redef;
## Should we dump the XML schema we use for this DS file to disk?
## If yes, the XML schema shares the name of the logfile, but has
## an XML ending.
const dump_schema = F &redef;
## How many threads should DataSeries spawn to perform compression?
## Note that this dictates the number of threads per log stream. If
## you're using a lot of streams, you may want to keep this number
## relatively small.
##
## Default value is 1, which will spawn one thread / stream.
##
## Maximum is 128, minimum is 1.
const num_threads = 1 &redef;
## Should time be stored as an integer or a double?
## Storing time as a double leads to possible precision issues and
## can (significantly) increase the size of the resulting DS log.
## That said, timestamps stored in double form are consistent
## with the rest of Bro, including the standard ASCII log. Hence, we
## use them by default.
const use_integer_for_time = F &redef;
}
# Default function to postprocess a rotated DataSeries log file. It moves the
# rotated file to a new name that includes a timestamp with the opening time,
# and then runs the writer's default postprocessor command on it.
function default_rotation_postprocessor_func(info: Log::RotationInfo) : bool
{
# Move file to name including both opening and closing time.
local dst = fmt("%s.%s.ds", info$path,
strftime(Log::default_rotation_date_format, info$open));
system(fmt("/bin/mv %s %s", info$fname, dst));
# Run default postprocessor.
return Log::run_rotation_postprocessor_cmd(info, dst);
}
redef Log::default_rotation_postprocessors += { [Log::WRITER_DATASERIES] = default_rotation_postprocessor_func };

View file

@ -1,48 +0,0 @@
##! Log writer for sending logs to an ElasticSearch server.
##!
##! Note: This module is in testing and is not yet considered stable!
##!
##! There is one known memory issue. If your elasticsearch server is
##! running slowly and taking too long to return from bulk insert
##! requests, the message queue to the writer thread will continue
##! growing larger and larger giving the appearance of a memory leak.
module LogElasticSearch;
export {
## Name of the ES cluster.
const cluster_name = "elasticsearch" &redef;
## ES server.
const server_host = "127.0.0.1" &redef;
## ES port.
const server_port = 9200 &redef;
## Name of the ES index.
const index_prefix = "bro" &redef;
## The ES type prefix comes before the name of the related log.
## e.g. prefix = "bro\_" would create types of bro_dns, bro_software, etc.
const type_prefix = "" &redef;
## The time before an ElasticSearch transfer will timeout. Note that
## the fractional part of the timeout will be ignored. In particular,
## time specifications less than a second result in a timeout value of
## 0, which means "no timeout."
const transfer_timeout = 2secs;
## The batch size is the number of messages that will be queued up before
## they are sent to be bulk indexed.
const max_batch_size = 1000 &redef;
## The maximum amount of wall-clock time that is allowed to pass without
## finishing a bulk log send. This represents the maximum delay you
## would like to have with your logs before they are sent to ElasticSearch.
const max_batch_interval = 1min &redef;
## The maximum byte size for a buffered JSON string to send to the bulk
## insert API.
const max_byte_size = 1024 * 1024 &redef;
}

View file

@ -20,7 +20,8 @@ export {
## category along with the specific notice separating words with
## underscores and using leading capitals on each word except for
## abbreviations which are kept in all capitals. For example,
## SSH::Login is for heuristically guessed successful SSH logins.
## SSH::Password_Guessing is for hosts that have crossed a threshold of
## heuristically determined failed SSH logins.
type Type: enum {
## Notice reporting a count of how often a notice occurred.
Tally,
@ -530,8 +531,8 @@ function create_file_info(f: fa_file): Notice::FileInfo
local fi: Notice::FileInfo = Notice::FileInfo($fuid = f$id,
$desc = Files::describe(f));
if ( f?$mime_type )
fi$mime = f$mime_type;
if ( f?$info && f$info?$mime_type )
fi$mime = f$info$mime_type;
if ( f?$conns && |f$conns| == 1 )
for ( id in f$conns )

View file

@ -71,7 +71,7 @@ export {
## to be logged has occurred.
ts: time &log;
## A unique identifier of the connection which triggered the
## signature match event
## signature match event.
uid: string &log &optional;
## The host which triggered the signature match event.
src_addr: addr &log &optional;

View file

@ -75,6 +75,13 @@ type addr_vec: vector of addr;
## directly and then remove this alias.
type table_string_of_string: table[string] of string;
## A set of file analyzer tags.
##
## .. todo:: We need this type definition only for declaring builtin functions
## via ``bifcl``. We should extend ``bifcl`` to understand composite types
## directly and then remove this alias.
type files_tag_set: set[Files::Tag];
## A structure indicating a MIME type and strength of a match against
## file magic signatures.
##
@ -346,9 +353,10 @@ type connection: record {
## gives up and discards any internal state related to the file.
const default_file_timeout_interval: interval = 2 mins &redef;
## Default amount of bytes that file analysis will buffer before raising
## :bro:see:`file_new`.
const default_file_bof_buffer_size: count = 1024 &redef;
## Default amount of bytes that file analysis will buffer in order to use
## for mime type matching. File analyzers attached at the time of mime type
## matching or later, will receive a copy of this buffer.
const default_file_bof_buffer_size: count = 4096 &redef;
## A file that Bro is analyzing. This is Bro's type for describing the basic
## internal metadata collected about a "file", which is essentially just a
@ -387,8 +395,10 @@ type fa_file: record {
## during the process of analysis e.g. due to dropped packets.
missing_bytes: count &default=0;
## The number of not all-in-sequence bytes in the file stream that
## were delivered to file analyzers due to reassembly buffer overflow.
## The number of bytes in the file stream that were not delivered to
## stream file analyzers. Generally, this consists of bytes that
## couldn't be reassembled, either because reassembly simply isn't
## enabled, or due to size limitations of the reassembly buffer.
overflow_bytes: count &default=0;
## The amount of time between receiving new data for this file that
@ -402,16 +412,6 @@ type fa_file: record {
## The content of the beginning of a file up to *bof_buffer_size* bytes.
## This is also the buffer that's used for file/mime type detection.
bof_buffer: string &optional;
## The mime type of the strongest file magic signature matches against
## the data chunk in *bof_buffer*, or in the cases where no buffering
## of the beginning of file occurs, an initial guess of the mime type
## based on the first data seen.
mime_type: string &optional;
## All mime types that matched file magic signatures against the data
## chunk in *bof_buffer*, in order of their strength value.
mime_types: mime_matches &optional;
} &redef;
## Fields of a SYN packet.
@ -2478,8 +2478,7 @@ type http_message_stat: record {
header_length: count;
};
## Maximum number of HTTP entity data delivered to events. The amount of data
## can be limited for better performance, zero disables truncation.
## Maximum number of HTTP entity data delivered to events.
##
## .. bro:see:: http_entity_data skip_http_entity_data skip_http_data
global http_entity_data_delivery_size = 1500 &redef;
@ -2806,6 +2805,7 @@ type ModbusRegisters: vector of count;
type ModbusHeaders: record {
tid: count;
pid: count;
len: count;
uid: count;
function_code: count;
};
@ -3431,9 +3431,6 @@ const global_hash_seed: string = "" &redef;
## The maximum is currently 128 bits.
const bits_per_uid: count = 96 &redef;
# Load BiFs defined by plugins.
@load base/bif/plugins
# Load these frameworks here because they use fairly deep integration with
# BiFs and script-land defined types.
@load base/frameworks/logging
@ -3442,3 +3439,7 @@ const bits_per_uid: count = 96 &redef;
@load base/frameworks/files
@load base/bif
# Load BiFs defined by plugins.
@load base/bif/plugins

View file

@ -46,6 +46,7 @@
@load base/protocols/http
@load base/protocols/irc
@load base/protocols/modbus
@load base/protocols/mysql
@load base/protocols/pop3
@load base/protocols/radius
@load base/protocols/snmp

View file

@ -47,13 +47,13 @@ redef record connection += {
const ports = { 67/udp, 68/udp };
redef likely_server_ports += { 67/udp };
event bro_init()
event bro_init() &priority=5
{
Log::create_stream(DHCP::LOG, [$columns=Info, $ev=log_dhcp]);
Analyzer::register_for_ports(Analyzer::ANALYZER_DHCP, ports);
}
event dhcp_ack(c: connection, msg: dhcp_msg, mask: addr, router: dhcp_router_list, lease: interval, serv_addr: addr, host_name: string)
event dhcp_ack(c: connection, msg: dhcp_msg, mask: addr, router: dhcp_router_list, lease: interval, serv_addr: addr, host_name: string) &priority=5
{
local info: Info;
info$ts = network_time();
@ -71,6 +71,9 @@ event dhcp_ack(c: connection, msg: dhcp_msg, mask: addr, router: dhcp_router_lis
info$assigned_ip = c$id$orig_h;
c$dhcp = info;
}
event dhcp_ack(c: connection, msg: dhcp_msg, mask: addr, router: dhcp_router_list, lease: interval, serv_addr: addr, host_name: string) &priority=-5
{
Log::write(DHCP::LOG, c$dhcp);
}

View file

@ -5,5 +5,11 @@ signature dpd_dnp3_server {
ip-proto == tcp
payload /\x05\x64/
tcp-state responder
enable "dnp3"
enable "dnp3_tcp"
}
signature dpd_dnp3_server_udp {
ip-proto == udp
payload /\x05\x64/
enable "dnp3_udp"
}

View file

@ -31,16 +31,16 @@ redef record connection += {
dnp3: Info &optional;
};
const ports = { 20000/tcp };
const ports = { 20000/tcp , 20000/udp };
redef likely_server_ports += { ports };
event bro_init() &priority=5
{
Log::create_stream(DNP3::LOG, [$columns=Info, $ev=log_dnp3]);
Analyzer::register_for_ports(Analyzer::ANALYZER_DNP3, ports);
Analyzer::register_for_ports(Analyzer::ANALYZER_DNP3_TCP, ports);
}
event dnp3_application_request_header(c: connection, is_orig: bool, fc: count)
event dnp3_application_request_header(c: connection, is_orig: bool, application_control: count, fc: count)
{
if ( ! c?$dnp3 )
c$dnp3 = [$ts=network_time(), $uid=c$uid, $id=c$id];
@ -49,7 +49,7 @@ event dnp3_application_request_header(c: connection, is_orig: bool, fc: count)
c$dnp3$fc_request = function_codes[fc];
}
event dnp3_application_response_header(c: connection, is_orig: bool, fc: count, iin: count)
event dnp3_application_response_header(c: connection, is_orig: bool, application_control: count, fc: count, iin: count)
{
if ( ! c?$dnp3 )
c$dnp3 = [$ts=network_time(), $uid=c$uid, $id=c$id];

View file

@ -17,6 +17,10 @@ export {
## Describe the file being transferred.
global describe_file: function(f: fa_file): string;
redef record fa_file += {
ftp: FTP::Info &optional;
};
}
function get_file_handle(c: connection, is_orig: bool): string
@ -48,7 +52,6 @@ event bro_init() &priority=5
$describe = FTP::describe_file]);
}
event file_over_new_connection(f: fa_file, c: connection, is_orig: bool) &priority=5
{
if ( [c$id$resp_h, c$id$resp_p] !in ftp_data_expected )
@ -56,6 +59,14 @@ event file_over_new_connection(f: fa_file, c: connection, is_orig: bool) &priori
local ftp = ftp_data_expected[c$id$resp_h, c$id$resp_p];
ftp$fuid = f$id;
if ( f?$mime_type )
ftp$mime_type = f$mime_type;
f$ftp = ftp;
}
event file_mime_type(f: fa_file, mime_type: string) &priority=5
{
if ( ! f?$ftp )
return;
f$ftp$mime_type = mime_type;
}

View file

@ -35,6 +35,10 @@ export {
## body.
resp_mime_depth: count &default=0;
};
redef record fa_file += {
http: HTTP::Info &optional;
};
}
event http_begin_entity(c: connection, is_orig: bool) &priority=10
@ -67,6 +71,8 @@ event file_over_new_connection(f: fa_file, c: connection, is_orig: bool) &priori
{
if ( f$source == "HTTP" && c?$http )
{
f$http = c$http;
if ( c$http?$current_entity && c$http$current_entity?$filename )
f$info$filename = c$http$current_entity$filename;
@ -76,14 +82,6 @@ event file_over_new_connection(f: fa_file, c: connection, is_orig: bool) &priori
c$http$orig_fuids = string_vec(f$id);
else
c$http$orig_fuids[|c$http$orig_fuids|] = f$id;
if ( f?$mime_type )
{
if ( ! c$http?$orig_mime_types )
c$http$orig_mime_types = string_vec(f$mime_type);
else
c$http$orig_mime_types[|c$http$orig_mime_types|] = f$mime_type;
}
}
else
{
@ -91,17 +89,29 @@ event file_over_new_connection(f: fa_file, c: connection, is_orig: bool) &priori
c$http$resp_fuids = string_vec(f$id);
else
c$http$resp_fuids[|c$http$resp_fuids|] = f$id;
}
}
}
if ( f?$mime_type )
event file_mime_type(f: fa_file, mime_type: string) &priority=5
{
if ( ! c$http?$resp_mime_types )
c$http$resp_mime_types = string_vec(f$mime_type);
else
c$http$resp_mime_types[|c$http$resp_mime_types|] = f$mime_type;
}
}
}
if ( ! f?$http || ! f?$is_orig )
return;
if ( f$is_orig )
{
if ( ! f$http?$orig_mime_types )
f$http$orig_mime_types = string_vec(mime_type);
else
f$http$orig_mime_types[|f$http$orig_mime_types|] = mime_type;
}
else
{
if ( ! f$http?$resp_mime_types )
f$http$resp_mime_types = string_vec(mime_type);
else
f$http$resp_mime_types[|f$http$resp_mime_types|] = mime_type;
}
}
event http_end_entity(c: connection, is_orig: bool) &priority=5

View file

@ -12,6 +12,10 @@ export {
## Default file handle provider for IRC.
global get_file_handle: function(c: connection, is_orig: bool): string;
redef record fa_file += {
irc: IRC::Info &optional;
};
}
function get_file_handle(c: connection, is_orig: bool): string
@ -34,6 +38,12 @@ event file_over_new_connection(f: fa_file, c: connection, is_orig: bool) &priori
irc$fuid = f$id;
if ( irc?$dcc_file_name )
f$info$filename = irc$dcc_file_name;
if ( f?$mime_type )
irc$dcc_mime_type = f$mime_type;
f$irc = irc;
}
event file_mime_type(f: fa_file, mime_type: string) &priority=5
{
if ( f?$irc )
f$irc$dcc_mime_type = mime_type;
}

View file

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

View file

@ -0,0 +1,38 @@
module MySQL;
export {
const commands: table[count] of string = {
[0] = "sleep",
[1] = "quit",
[2] = "init_db",
[3] = "query",
[4] = "field_list",
[5] = "create_db",
[6] = "drop_db",
[7] = "refresh",
[8] = "shutdown",
[9] = "statistics",
[10] = "process_info",
[11] = "connect",
[12] = "process_kill",
[13] = "debug",
[14] = "ping",
[15] = "time",
[16] = "delayed_insert",
[17] = "change_user",
[18] = "binlog_dump",
[19] = "table_dump",
[20] = "connect_out",
[21] = "register_slave",
[22] = "stmt_prepare",
[23] = "stmt_execute",
[24] = "stmt_send_long_data",
[25] = "stmt_close",
[26] = "stmt_reset",
[27] = "set_option",
[28] = "stmt_fetch",
[29] = "daemon",
[30] = "binlog_dump_gtid",
[31] = "reset_connection",
} &default=function(i: count): string { return fmt("unknown-%d", i); };
}

View file

@ -0,0 +1,132 @@
##! Implements base functionality for MySQL analysis. Generates the mysql.log file.
module MySQL;
@load ./consts
export {
redef enum Log::ID += { mysql::LOG };
type Info: record {
## Timestamp for when the event happened.
ts: time &log;
## Unique ID for the connection.
uid: string &log;
## The connection's 4-tuple of endpoint addresses/ports.
id: conn_id &log;
## The command that was issued
cmd: string &log;
## The argument issued to the command
arg: string &log;
## Did the server tell us that the command succeeded?
success: bool &log &optional;
## The number of affected rows, if any
rows: count &log &optional;
## Server message, if any
response: string &log &optional;
};
## Event that can be handled to access the MySQL record as it is sent on
## to the logging framework.
global log_mysql: event(rec: Info);
}
redef record connection += {
mysql: Info &optional;
};
const ports = { 1434/tcp, 3306/tcp };
event bro_init() &priority=5
{
Log::create_stream(mysql::LOG, [$columns=Info, $ev=log_mysql]);
Analyzer::register_for_ports(Analyzer::ANALYZER_MYSQL, ports);
}
event mysql_handshake(c: connection, username: string)
{
if ( ! c?$mysql )
{
local info: Info;
info$ts = network_time();
info$uid = c$uid;
info$id = c$id;
info$cmd = "login";
info$arg = username;
c$mysql = info;
}
}
event mysql_command_request(c: connection, command: count, arg: string) &priority=5
{
if ( c?$mysql )
{
# We got a request, but we haven't logged our
# previous request yet, so let's do that now.
Log::write(mysql::LOG, c$mysql);
delete c$mysql;
}
local info: Info;
info$ts = network_time();
info$uid = c$uid;
info$id = c$id;
info$cmd = commands[command];
info$arg = sub(arg, /\0$/, "");
c$mysql = info;
}
event mysql_command_request(c: connection, command: count, arg: string) &priority=-5
{
if ( c?$mysql && c$mysql?$cmd && c$mysql$cmd == "quit" )
{
# We get no response for quits, so let's just log it now.
Log::write(mysql::LOG, c$mysql);
delete c$mysql;
}
}
event mysql_error(c: connection, code: count, msg: string) &priority=5
{
if ( c?$mysql )
{
c$mysql$success = F;
c$mysql$response = msg;
}
}
event mysql_error(c: connection, code: count, msg: string) &priority=-5
{
if ( c?$mysql )
{
Log::write(mysql::LOG, c$mysql);
delete c$mysql;
}
}
event mysql_ok(c: connection, affected_rows: count) &priority=5
{
if ( c?$mysql )
{
c$mysql$success = T;
c$mysql$rows = affected_rows;
}
}
event mysql_ok(c: connection, affected_rows: count) &priority=-5
{
if ( c?$mysql )
{
Log::write(mysql::LOG, c$mysql);
delete c$mysql;
}
}
event connection_state_remove(c: connection) &priority=-5
{
if ( c?$mysql )
{
Log::write(mysql::LOG, c$mysql);
delete c$mysql;
}
}

View file

@ -142,7 +142,10 @@ function set_smtp_session(c: connection)
function smtp_message(c: connection)
{
if ( c$smtp$has_client_activity )
{
Log::write(SMTP::LOG, c$smtp);
c$smtp = new_smtp_log(c);
}
}
event smtp_request(c: connection, is_orig: bool, command: string, arg: string) &priority=5
@ -150,9 +153,6 @@ event smtp_request(c: connection, is_orig: bool, command: string, arg: string) &
set_smtp_session(c);
local upper_command = to_upper(command);
if ( upper_command != "QUIT" )
c$smtp$has_client_activity = T;
if ( upper_command == "HELO" || upper_command == "EHLO" )
{
c$smtp_state$helo = arg;
@ -164,12 +164,17 @@ event smtp_request(c: connection, is_orig: bool, command: string, arg: string) &
if ( ! c$smtp?$rcptto )
c$smtp$rcptto = set();
add c$smtp$rcptto[split1(arg, /:[[:blank:]]*/)[2]];
c$smtp$has_client_activity = T;
}
else if ( upper_command == "MAIL" && /^[fF][rR][oO][mM]:/ in arg )
{
# Flush last message in case we didn't see the server's acknowledgement.
smtp_message(c);
local partially_done = split1(arg, /:[[:blank:]]*/)[2];
c$smtp$mailfrom = split1(partially_done, /[[:blank:]]?/)[1];
c$smtp$has_client_activity = T;
}
}
@ -198,7 +203,6 @@ event smtp_reply(c: connection, is_orig: bool, code: count, cmd: string,
event mime_one_header(c: connection, h: mime_header_rec) &priority=5
{
if ( ! c?$smtp ) return;
c$smtp$has_client_activity = T;
if ( h$name == "MESSAGE-ID" )
c$smtp$msg_id = h$value;
@ -281,7 +285,10 @@ event connection_state_remove(c: connection) &priority=-5
event smtp_starttls(c: connection) &priority=5
{
if ( c?$smtp )
{
c$smtp$tls = T;
c$smtp$has_client_activity = T;
}
}
function describe(rec: Info): string

View file

@ -30,6 +30,7 @@ export {
const HELLO_REQUEST = 0;
const CLIENT_HELLO = 1;
const SERVER_HELLO = 2;
const HELLO_VERIFY_REQUEST = 3; # RFC 6347
const SESSION_TICKET = 4; # RFC 5077
const CERTIFICATE = 11;
const SERVER_KEY_EXCHANGE = 12;
@ -40,6 +41,7 @@ export {
const FINISHED = 20;
const CERTIFICATE_URL = 21; # RFC 3546
const CERTIFICATE_STATUS = 22; # RFC 3546
const SUPPLEMENTAL_DATA = 23; # RFC 4680
## Mapping between numeric codes and human readable strings for alert
## levels.
@ -112,7 +114,8 @@ export {
[19] = "client_certificate_type",
[20] = "server_certificate_type",
[21] = "padding", # temporary till 2015-03-12
[22] = "encrypt_then_mac", # temporary till 2015-06-05
[22] = "encrypt_then_mac",
[23] = "extended_master_secret", # temporary till 2015-09-26
[35] = "SessionTicket TLS",
[40] = "extended_random",
[13172] = "next_protocol_negotiation",
@ -155,6 +158,11 @@ export {
[26] = "brainpoolP256r1",
[27] = "brainpoolP384r1",
[28] = "brainpoolP512r1",
# draft-ietf-tls-negotiated-ff-dhe-05
[256] = "ffdhe2048",
[257] = "ffdhe3072",
[258] = "ffdhe4096",
[259] = "ffdhe8192",
[0xFF01] = "arbitrary_explicit_prime_curves",
[0xFF02] = "arbitrary_explicit_char2_curves"
} &default=function(i: count):string { return fmt("unknown-%d", i); };

View file

@ -25,9 +25,25 @@ export {
## indicates the server name that the client was requesting.
server_name: string &log &optional;
## Session ID offered by the client for session resumption.
session_id: string &log &optional;
## Not used for logging.
session_id: string &optional;
## Flag to indicate if the session was resumed reusing
## the key material exchanged in an earlier connection.
resumed: bool &log &default=F;
## Flag to indicate if we saw a non-empty session ticket being
## sent by the client using an empty session ID. This value
## is used to determine if a session is being resumed. It's
## not logged.
client_ticket_empty_session_seen: bool &default=F;
## Flag to indicate if we saw a client key exchange message sent
## by the client. This value is used to determine if a session
## is being resumed. It's not logged.
client_key_exchange_seen: bool &default=F;
## Last alert that was seen during the connection.
last_alert: string &log &optional;
## Next protocol the server chose using the application layer
## next protocol extension, if present.
next_protocol: string &log &optional;
## The analyzer ID used for the analyzer instance attached
## to each connection. It is not used for logging since it's a
@ -149,8 +165,11 @@ event ssl_client_hello(c: connection, version: count, possible_ts: time, client_
set_session(c);
# Save the session_id if there is one set.
if ( session_id != /^\x00{32}$/ )
if ( |session_id| > 0 && session_id != /^\x00{32}$/ )
{
c$ssl$session_id = bytestring_to_hexstr(session_id);
c$ssl$client_ticket_empty_session_seen = F;
}
}
event ssl_server_hello(c: connection, version: count, possible_ts: time, server_random: string, session_id: string, cipher: count, comp_method: count) &priority=5
@ -159,6 +178,9 @@ event ssl_server_hello(c: connection, version: count, possible_ts: time, server_
c$ssl$version = version_strings[version];
c$ssl$cipher = cipher_desc[cipher];
if ( c$ssl?$session_id && c$ssl$session_id == bytestring_to_hexstr(session_id) )
c$ssl$resumed = T;
}
event ssl_server_curve(c: connection, curve: count) &priority=5
@ -180,6 +202,45 @@ event ssl_extension_server_name(c: connection, is_orig: bool, names: string_vec)
}
}
event ssl_extension_application_layer_protocol_negotiation(c: connection, is_orig: bool, protocols: string_vec)
{
set_session(c);
if ( is_orig )
return;
if ( |protocols| > 0 )
c$ssl$next_protocol = protocols[0];
}
event ssl_handshake_message(c: connection, is_orig: bool, msg_type: count, length: count) &priority=5
{
set_session(c);
if ( is_orig && msg_type == SSL::CLIENT_KEY_EXCHANGE )
c$ssl$client_key_exchange_seen = T;
}
# Extension event is fired _before_ the respective client or server hello.
# Important for client_ticket_empty_session_seen.
event ssl_extension(c: connection, is_orig: bool, code: count, val: string) &priority=5
{
set_session(c);
if ( is_orig && SSL::extensions[code] == "SessionTicket TLS" && |val| > 0 )
# In this case, we might have an empty ID. Set back to F in client_hello event
# if it is not empty after all.
c$ssl$client_ticket_empty_session_seen = T;
}
event ssl_change_cipher_spec(c: connection, is_orig: bool) &priority=5
{
set_session(c);
if ( is_orig && c$ssl$client_ticket_empty_session_seen && ! c$ssl$client_key_exchange_seen )
c$ssl$resumed = T;
}
event ssl_alert(c: connection, is_orig: bool, level: count, desc: count) &priority=5
{
set_session(c);

View file

@ -65,12 +65,14 @@ function request2curl(r: Request, bodyfile: string, headersfile: string): string
cmd = fmt("%s -m %.0f", cmd, r$max_time);
if ( r?$client_data )
cmd = fmt("%s -d -", cmd);
cmd = fmt("%s -d @-", cmd);
if ( r?$addl_curl_args )
cmd = fmt("%s %s", cmd, r$addl_curl_args);
cmd = fmt("%s \"%s\"", cmd, str_shell_escape(r$url));
# Make sure file will exist even if curl did not write one.
cmd = fmt("%s && touch %s", cmd, str_shell_escape(bodyfile));
return cmd;
}

View file

@ -96,8 +96,9 @@ event Exec::file_line(description: Input::EventDescription, tpe: Input::Event, s
result$files[track_file][|result$files[track_file]|] = s;
}
event Input::end_of_data(name: string, source:string)
event Input::end_of_data(orig_name: string, source:string)
{
local name = orig_name;
local parts = split1(name, /_/);
name = parts[1];
@ -106,6 +107,15 @@ event Input::end_of_data(name: string, source:string)
local track_file = parts[2];
# If the file is empty, still add it to the result$files table. This is needed
# because it is expected that the file was read even if it was empty.
local result = results[name];
if ( ! result?$files )
result$files = table();
if ( track_file !in result$files )
result$files[track_file] = vector();
Input::remove(name);
if ( name !in pending_files )

View file

@ -3,6 +3,28 @@
## A regular expression for matching and extracting URLs.
const url_regex = /^([a-zA-Z\-]{3,5})(:\/\/[^\/?#"'\r\n><]*)([^?#"'\r\n><]*)([^[:blank:]\r\n"'><]*|\??[^"'\r\n><]*)/ &redef;
## A URI, as parsed by :bro:id:`decompose_uri`.
type URI: record {
## The URL's scheme..
scheme: string &optional;
## The location, which could be a domain name or an IP address. Left empty if not
## specified.
netlocation: string;
## Port number, if included in URI.
portnum: count &optional;
## Full including the file name. Will be '/' if there's not path given.
path: string;
## Full file name, including extension, if there is a file name.
file_name: string &optional;
## The base filename, without extension, if there is a file name.
file_base: string &optional;
## The filename's extension, if there is a file name.
file_ext: string &optional;
## A table of all query parameters, mapping their keys to values, if there's a
## query.
params: table[string] of string &optional;
};
## Extracts URLs discovered in arbitrary text.
function find_all_urls(s: string): string_set
{
@ -23,3 +45,84 @@ function find_all_urls_without_scheme(s: string): string_set
return return_urls;
}
function decompose_uri(s: string): URI
{
local parts: string_array;
local u: URI = [$netlocation="", $path="/"];
if ( /\?/ in s)
{
# Parse query.
u$params = table();
parts = split1(s, /\?/);
s = parts[1];
local query: string = parts[2];
if ( /&/ in query )
{
local opv: table[count] of string = split(query, /&/);
for ( each in opv )
{
if ( /=/ in opv[each] )
{
parts = split1(opv[each], /=/);
u$params[parts[1]] = parts[2];
}
}
}
else
{
parts = split1(query, /=/);
u$params[parts[1]] = parts[2];
}
}
if ( /:\/\// in s )
{
# Parse scheme and remove from s.
parts = split1(s, /:\/\//);
u$scheme = parts[1];
s = parts[2];
}
if ( /\// in s )
{
# Parse path and remove from s.
parts = split1(s, /\//);
s = parts[1];
u$path = fmt("/%s", parts[2]);
if ( |u$path| > 1 && u$path[|u$path| - 1] != "/" )
{
local last_token: string = find_last(u$path, /\/.+/);
local full_filename = split1(last_token, /\//)[2];
if ( /\./ in full_filename )
{
u$file_name = full_filename;
u$file_base = split1(full_filename, /\./)[1];
u$file_ext = split1(full_filename, /\./)[2];
}
else
{
u$file_name = full_filename;
u$file_base = full_filename;
}
}
}
if ( /:/ in s )
{
# Parse location and port.
parts = split1(s, /:/);
u$netlocation = parts[1];
u$portnum = to_count(parts[2]);
}
else
u$netlocation = s;
return u;
}

View file

@ -66,6 +66,7 @@ function do_mhr_lookup(hash: string, fi: Notice::FileInfo)
event file_hash(f: fa_file, kind: string, hash: string)
{
if ( kind == "sha1" && f?$mime_type && match_file_types in f$mime_type )
if ( kind == "sha1" && f?$info && f$info?$mime_type &&
match_file_types in f$info$mime_type )
do_mhr_lookup(hash, Notice::create_file_info(f));
}

View file

@ -0,0 +1,69 @@
##! Windows systems access a Microsoft Certificate Revocation List (CRL) periodically. The
##! user agent for these requests reveals which version of Crypt32.dll installed on the system,
##! which can uniquely identify the version of Windows that's running.
##!
##! This script will log the version of Windows that was identified to the Software framework.
@load base/protocols/http
@load base/frameworks/software
module OS;
export {
redef enum Software::Type += {
## Identifier for Windows operating system versions
WINDOWS,
};
type Software::name_and_version: record {
name : string;
version: Software::Version;
};
const crypto_api_mapping: table[string] of Software::name_and_version = {
["Microsoft-CryptoAPI/5.131.2195.6661"] = [$name="Windows", $version=[$major=5, $minor=131, $minor2=2195, $minor3=6661, $addl="2000 SP4"]],
["Microsoft-CryptoAPI/5.131.2195.6824"] = [$name="Windows", $version=[$major=5, $minor=131, $minor2=2195, $minor3=6824, $addl="2000 with MS04-11"]],
["Microsoft-CryptoAPI/5.131.2195.6926"] = [$name="Windows", $version=[$major=5, $minor=131, $minor2=2195, $minor3=6926, $addl="2000 with Hotfix 98830"]],
["Microsoft-CryptoAPI/5.131.2600.0"] = [$name="Windows", $version=[$major=5, $minor=131, $minor2=2600, $minor3=0, $addl="XP SP0"]],
["Microsoft-CryptoAPI/5.131.2600.1106"] = [$name="Windows", $version=[$major=5, $minor=131, $minor2=2600, $minor3=1106, $addl="XP SP1"]],
["Microsoft-CryptoAPI/5.131.2600.2180"] = [$name="Windows", $version=[$major=5, $minor=131, $minor2=2600, $minor3=2180, $addl="XP SP2"]],
["Microsoft-CryptoAPI/5.131.2600.3180"] = [$name="Windows", $version=[$major=5, $minor=131, $minor2=2600, $minor3=3180, $addl="XP SP3 Beta 1"]],
["Microsoft-CryptoAPI/5.131.2600.3205"] = [$name="Windows", $version=[$major=5, $minor=131, $minor2=2600, $minor3=3205, $addl="XP SP3 Beta 2"]],
["Microsoft-CryptoAPI/5.131.2600.3249"] = [$name="Windows", $version=[$major=5, $minor=131, $minor2=2600, $minor3=3249, $addl="XP SP3 RC Beta"]],
["Microsoft-CryptoAPI/5.131.2600.3264"] = [$name="Windows", $version=[$major=5, $minor=131, $minor2=2600, $minor3=3264, $addl="XP SP3 RC1"]],
["Microsoft-CryptoAPI/5.131.2600.3282"] = [$name="Windows", $version=[$major=5, $minor=131, $minor2=2600, $minor3=3282, $addl="XP SP3 RC1 Update"]],
["Microsoft-CryptoAPI/5.131.2600.3300"] = [$name="Windows", $version=[$major=5, $minor=131, $minor2=2600, $minor3=3300, $addl="XP SP3 RC2"]],
["Microsoft-CryptoAPI/5.131.2600.3311"] = [$name="Windows", $version=[$major=5, $minor=131, $minor2=2600, $minor3=3311, $addl="XP SP3 RC2 Update"]],
["Microsoft-CryptoAPI/5.131.2600.5508"] = [$name="Windows", $version=[$major=5, $minor=131, $minor2=2600, $minor3=5508, $addl="XP SP3 RC2 Update 2"]],
["Microsoft-CryptoAPI/5.131.2600.5512"] = [$name="Windows", $version=[$major=5, $minor=131, $minor2=2600, $minor3=5512, $addl="XP SP3"]],
["Microsoft-CryptoAPI/5.131.3790.0"] = [$name="Windows", $version=[$major=5, $minor=131, $minor2=3790, $minor3=0, $addl="XP x64 or Server 2003 SP0"]],
["Microsoft-CryptoAPI/5.131.3790.1830"] = [$name="Windows", $version=[$major=5, $minor=131, $minor2=3790, $minor3=1830, $addl="XP x64 or Server 2003 SP1"]],
["Microsoft-CryptoAPI/5.131.3790.3959"] = [$name="Windows", $version=[$major=5, $minor=131, $minor2=3790, $minor3=3959, $addl="XP x64 or Server 2003 SP2"]],
["Microsoft-CryptoAPI/5.131.3790.5235"] = [$name="Windows", $version=[$major=5, $minor=131, $minor2=3790, $minor3=5235, $addl="XP x64 or Server 2003 with MS13-095"]],
["Microsoft-CryptoAPI/6.0"] = [$name="Windows", $version=[$major=6, $minor=0, $addl="Vista or Server 2008"]],
["Microsoft-CryptoAPI/6.1"] = [$name="Windows", $version=[$major=6, $minor=1, $addl="7 or Server 2008 R2"]],
["Microsoft-CryptoAPI/6.2"] = [$name="Windows", $version=[$major=6, $minor=2, $addl="8 or Server 2012"]],
["Microsoft-CryptoAPI/6.3"] = [$name="Windows", $version=[$major=6, $minor=3, $addl="8.1 or Server 2012 R2"]],
["Microsoft-CryptoAPI/6.4"] = [$name="Windows", $version=[$major=6, $minor=4, $addl="10 Technical Preview"]],
} &redef;
}
event HTTP::log_http(rec: HTTP::Info) &priority=5
{
if ( rec?$host && rec?$user_agent && rec$host == "crl.microsoft.com" &&
/Microsoft-CryptoAPI\// in rec$user_agent )
{
if ( rec$user_agent !in crypto_api_mapping )
{
Software::found(rec$id, [$unparsed_version=sub(rec$user_agent, /Microsoft-CryptoAPI/, "Unknown CryptoAPI Version"), $host=rec$id$orig_h, $software_type=WINDOWS]);
}
else
{
local result = crypto_api_mapping[rec$user_agent];
Software::found(rec$id, [$version=result$version, $name=result$name, $host=rec$id$orig_h, $software_type=WINDOWS]);
}
}
}

View file

@ -0,0 +1,20 @@
##! Software identification and extraction for MySQL traffic.
@load base/frameworks/software
module MySQL;
export {
redef enum Software::Type += {
## Identifier for MySQL servers in the software framework.
SERVER,
};
}
event mysql_server_version(c: connection, ver: string)
{
if ( ver == "" )
return;
Software::found(c$id, [$unparsed_version=ver, $host=c$id$resp_h, $software_type=SERVER]);
}

View file

@ -22,7 +22,7 @@ export {
## The minimal key length in bits that is considered to be safe. Any shorter
## (non-EC) key lengths will trigger the notice.
const notify_minimal_key_length = 1024 &redef;
const notify_minimal_key_length = 2048 &redef;
## Warn if the DH key length is smaller than the certificate key length. This is
## potentially unsafe because it gives a wrong impression of safety due to the
@ -56,7 +56,7 @@ event ssl_established(c: connection) &priority=3
NOTICE([$note=Weak_Key,
$msg=fmt("Host uses weak certificate with %d bit key", key_length),
$conn=c, $suppress_for=1day,
$identifier=cat(c$id$orig_h, c$id$orig_p, key_length)
$identifier=cat(c$id$resp_h, c$id$resp_h, key_length)
]);
}
@ -65,13 +65,13 @@ event ssl_dh_server_params(c: connection, p: string, q: string, Ys: string) &pri
if ( ! addr_matches_host(c$id$resp_h, notify_weak_keys) )
return;
local key_length = |Ys| * 8; # key length in bits
local key_length = |p| * 8; # length of the used prime number in bits
if ( key_length < notify_minimal_key_length )
NOTICE([$note=Weak_Key,
$msg=fmt("Host uses weak DH parameters with %d key bits", key_length),
$conn=c, $suppress_for=1day,
$identifier=cat(c$id$orig_h, c$id$orig_p, key_length)
$identifier=cat(c$id$resp_h, c$id$resp_p, key_length)
]);
if ( notify_dh_length_shorter_cert_length &&
@ -86,7 +86,7 @@ event ssl_dh_server_params(c: connection, p: string, q: string, Ys: string) &pri
$msg=fmt("DH key length of %d bits is smaller certificate key length of %d bits",
key_length, c$ssl$cert_chain[0]$x509$certificate$key_length),
$conn=c, $suppress_for=1day,
$identifier=cat(c$id$orig_h, c$id$orig_p)
$identifier=cat(c$id$resp_h, c$id$resp_p)
]);
}
}

View file

@ -1,36 +0,0 @@
##! Load this script to enable global log output to an ElasticSearch database.
module LogElasticSearch;
export {
## An elasticsearch specific rotation interval.
const rotation_interval = 3hr &redef;
## Optionally ignore any :bro:type:`Log::ID` from being sent to
## ElasticSearch with this script.
const excluded_log_ids: set[Log::ID] &redef;
## If you want to explicitly only send certain :bro:type:`Log::ID`
## streams, add them to this set. If the set remains empty, all will
## be sent. The :bro:id:`LogElasticSearch::excluded_log_ids` option
## will remain in effect as well.
const send_logs: set[Log::ID] &redef;
}
event bro_init() &priority=-5
{
if ( server_host == "" )
return;
for ( stream_id in Log::active_streams )
{
if ( stream_id in excluded_log_ids ||
(|send_logs| > 0 && stream_id !in send_logs) )
next;
local filter: Log::Filter = [$name = "default-es",
$writer = Log::WRITER_ELASTICSEARCH,
$interv = LogElasticSearch::rotation_interval];
Log::add_filter(stream_id, filter);
}
}

View file

@ -32,6 +32,7 @@
@load frameworks/packet-filter/shunt.bro
@load frameworks/software/version-changes.bro
@load frameworks/software/vulnerable.bro
@load frameworks/software/windows-version-detection.bro
@load integration/barnyard2/__load__.bro
@load integration/barnyard2/main.bro
@load integration/barnyard2/types.bro
@ -75,6 +76,7 @@
@load protocols/http/var-extraction-uri.bro
@load protocols/modbus/known-masters-slaves.bro
@load protocols/modbus/track-memmap.bro
@load protocols/mysql/software.bro
@load protocols/smtp/blocklists.bro
@load protocols/smtp/detect-suspicious-orig.bro
@load protocols/smtp/entities-excerpt.bro
@ -98,7 +100,4 @@
@load tuning/defaults/packet-fragments.bro
@load tuning/defaults/warnings.bro
@load tuning/json-logs.bro
@load tuning/logs-to-elasticsearch.bro
@load tuning/track-all-assets.bro
redef LogElasticSearch::server_host = "";

View file

@ -265,6 +265,14 @@ void Attributes::CheckAttr(Attr* a)
// Ok.
break;
Expr* e = a->AttrExpr();
if ( check_and_promote_expr(e, type) )
{
a->SetAttrExpr(e);
// Ok.
break;
}
a->AttrExpr()->Error("&default value has inconsistent type", type);
}
@ -297,8 +305,11 @@ void Attributes::CheckAttr(Attr* a)
Expr* e = a->AttrExpr();
if ( check_and_promote_expr(e, ytype) )
{
a->SetAttrExpr(e);
// Ok.
break;
}
Error("&default value has inconsistent type 2");
}

View file

@ -45,6 +45,13 @@ public:
attr_tag Tag() const { return tag; }
Expr* AttrExpr() const { return expr; }
// Up to the caller to decide if previous expr can be unref'd since it may
// not always be safe; e.g. expressions (at time of writing) don't always
// keep careful track of referencing their operands, so doing something
// like SetAttrExpr(coerce(AttrExpr())) must not completely unref the
// previous expr as the new expr depends on it.
void SetAttrExpr(Expr* e) { expr = e; }
int RedundantAttrOkay() const
{ return tag == ATTR_REDEF || tag == ATTR_OPTIONAL; }

View file

@ -8,6 +8,7 @@ set(bro_ALL_GENERATED_OUTPUTS CACHE INTERNAL "automatically generated files" FO
# This collects bif inputs that we'll load automatically.
set(bro_AUTO_BIFS CACHE INTERNAL "BIFs for automatic inclusion" FORCE)
set(bro_REGISTER_BIFS CACHE INTERNAL "BIFs for automatic registering" FORCE)
set(bro_BASE_BIF_SCRIPTS CACHE INTERNAL "Bro script stubs for BIFs in base distribution of Bro" FORCE)
set(bro_PLUGIN_BIF_SCRIPTS CACHE INTERNAL "Bro script stubs for BIFs in Bro plugins" FORCE)
@ -47,7 +48,7 @@ set(BISON_FLAGS "--debug")
bison_target(BIFParser builtin-func.y
${CMAKE_CURRENT_BINARY_DIR}/bif_parse.cc
HEADER ${CMAKE_CURRENT_BINARY_DIR}/bif_parse.h
VERBOSE ${CMAKE_CURRENT_BINARY_DIR}/bif_parse.output
#VERBOSE ${CMAKE_CURRENT_BINARY_DIR}/bif_parse.output
COMPILE_FLAGS "${BISON_FLAGS}")
flex_target(BIFScanner builtin-func.l ${CMAKE_CURRENT_BINARY_DIR}/bif_lex.cc)
add_flex_bison_dependency(BIFScanner BIFParser)
@ -56,7 +57,7 @@ add_flex_bison_dependency(BIFScanner BIFParser)
bison_target(RuleParser rule-parse.y
${CMAKE_CURRENT_BINARY_DIR}/rup.cc
HEADER ${CMAKE_CURRENT_BINARY_DIR}/rup.h
VERBOSE ${CMAKE_CURRENT_BINARY_DIR}/rule_parse.output
#VERBOSE ${CMAKE_CURRENT_BINARY_DIR}/rule_parse.output
COMPILE_FLAGS "${BISON_FLAGS}")
replace_yy_prefix_target(${CMAKE_CURRENT_BINARY_DIR}/rup.cc
${CMAKE_CURRENT_BINARY_DIR}/rule-parse.cc
@ -71,7 +72,7 @@ flex_target(RuleScanner rule-scan.l ${CMAKE_CURRENT_BINARY_DIR}/rule-scan.cc
bison_target(REParser re-parse.y
${CMAKE_CURRENT_BINARY_DIR}/rep.cc
HEADER ${CMAKE_CURRENT_BINARY_DIR}/re-parse.h
VERBOSE ${CMAKE_CURRENT_BINARY_DIR}/re_parse.output
#VERBOSE ${CMAKE_CURRENT_BINARY_DIR}/re_parse.output
COMPILE_FLAGS "${BISON_FLAGS}")
replace_yy_prefix_target(${CMAKE_CURRENT_BINARY_DIR}/rep.cc
${CMAKE_CURRENT_BINARY_DIR}/re-parse.cc
@ -84,7 +85,7 @@ add_flex_bison_dependency(REScanner REParser)
bison_target(Parser parse.y
${CMAKE_CURRENT_BINARY_DIR}/p.cc
HEADER ${CMAKE_CURRENT_BINARY_DIR}/broparse.h
VERBOSE ${CMAKE_CURRENT_BINARY_DIR}/parse.output
#VERBOSE ${CMAKE_CURRENT_BINARY_DIR}/parse.output
COMPILE_FLAGS "${BISON_FLAGS}")
replace_yy_prefix_target(${CMAKE_CURRENT_BINARY_DIR}/p.cc
${CMAKE_CURRENT_BINARY_DIR}/parse.cc
@ -117,8 +118,6 @@ include(BifCl)
set(BIF_SRCS
bro.bif
logging.bif
input.bif
event.bif
const.bif
types.bif
@ -155,21 +154,25 @@ set(bro_SUBDIR_LIBS CACHE INTERNAL "subdir libraries" FORCE)
set(bro_PLUGIN_LIBS CACHE INTERNAL "plugin libraries" FORCE)
add_subdirectory(analyzer)
add_subdirectory(file_analysis)
add_subdirectory(probabilistic)
add_subdirectory(broxygen)
add_subdirectory(file_analysis)
add_subdirectory(input)
add_subdirectory(iosource)
add_subdirectory(logging)
add_subdirectory(probabilistic)
set(bro_SUBDIRS
${bro_SUBDIR_LIBS}
# Order is important here.
${bro_PLUGIN_LIBS}
${bro_SUBDIR_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(_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()
@ -252,7 +255,6 @@ set(bro_SRCS
Anon.cc
Attr.cc
Base64.cc
BPF_Program.cc
Brofiler.cc
BroString.cc
CCL.cc
@ -277,14 +279,13 @@ set(bro_SRCS
EventRegistry.cc
Expr.cc
File.cc
FlowSrc.cc
Flare.cc
Frag.cc
Frame.cc
Func.cc
Hash.cc
ID.cc
IntSet.cc
IOSource.cc
IP.cc
IPAddr.cc
List.cc
@ -297,7 +298,7 @@ set(bro_SRCS
OSFinger.cc
PacketFilter.cc
PersistenceSerializer.cc
PktSrc.cc
Pipe.cc
PolicyFile.cc
PrefixTable.cc
PriorityQueue.cc
@ -346,24 +347,6 @@ set(bro_SRCS
threading/formatters/Ascii.cc
threading/formatters/JSON.cc
logging/Manager.cc
logging/WriterBackend.cc
logging/WriterFrontend.cc
logging/writers/Ascii.cc
logging/writers/DataSeries.cc
logging/writers/SQLite.cc
logging/writers/ElasticSearch.cc
logging/writers/None.cc
input/Manager.cc
input/ReaderBackend.cc
input/ReaderFrontend.cc
input/readers/Ascii.cc
input/readers/Raw.cc
input/readers/Benchmark.cc
input/readers/Binary.cc
input/readers/SQLite.cc
3rdparty/sqlite3.c
plugin/Component.cc
@ -371,7 +354,6 @@ set(bro_SRCS
plugin/TaggedComponent.h
plugin/Manager.cc
plugin/Plugin.cc
plugin/Macros.h
nb_dns.c
digest.h
@ -387,22 +369,31 @@ else ()
target_link_libraries(bro ${bro_SUBDIRS} ${brodeps} ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS})
endif ()
if ( NOT "${bro_LINKER_FLAGS}" STREQUAL "" )
set_target_properties(bro PROPERTIES LINK_FLAGS "${bro_LINKER_FLAGS}")
endif ()
install(TARGETS bro DESTINATION bin)
set(BRO_EXE bro
CACHE STRING "Bro executable binary" FORCE)
set(BRO_EXE_PATH ${CMAKE_CURRENT_BINARY_DIR}/bro
CACHE STRING "Path to Bro executable binary" FORCE)
# Target to create all the autogenerated files.
add_custom_target(generate_outputs_stage1)
add_dependencies(generate_outputs_stage1 ${bro_ALL_GENERATED_OUTPUTS})
# Target to create the joint includes files that pull in the bif code.
bro_bif_create_includes(generate_outputs_stage2 ${CMAKE_CURRENT_BINARY_DIR} "${bro_AUTO_BIFS}")
add_dependencies(generate_outputs_stage2 generate_outputs_stage1)
bro_bif_create_includes(generate_outputs_stage2a ${CMAKE_CURRENT_BINARY_DIR} "${bro_AUTO_BIFS}")
bro_bif_create_register(generate_outputs_stage2b ${CMAKE_CURRENT_BINARY_DIR} "${bro_REGISTER_BIFS}")
add_dependencies(generate_outputs_stage2a generate_outputs_stage1)
add_dependencies(generate_outputs_stage2b generate_outputs_stage1)
# Global target to trigger creation of autogenerated code.
add_custom_target(generate_outputs)
add_dependencies(generate_outputs generate_outputs_stage2)
add_dependencies(generate_outputs generate_outputs_stage2a generate_outputs_stage2b)
# Build __load__.bro files for standard *.bif.bro.
bro_bif_create_loader(bif_loader "${bro_BASE_BIF_SCRIPTS}")

View file

@ -210,6 +210,7 @@ bool ChunkedIOFd::WriteChunk(Chunk* chunk, bool partial)
else
pending_head = pending_tail = q;
write_flare.Fire();
return Flush();
}
@ -232,6 +233,7 @@ bool ChunkedIOFd::PutIntoWriteBuffer(Chunk* chunk)
write_len += len;
delete chunk;
write_flare.Fire();
if ( network_time - last_flush > 0.005 )
FlushWriteBuffer();
@ -269,6 +271,10 @@ bool ChunkedIOFd::FlushWriteBuffer()
if ( unsigned(written) == len )
{
write_pos = write_len = 0;
if ( ! pending_head )
write_flare.Extinguish();
return true;
}
@ -318,7 +324,12 @@ bool ChunkedIOFd::Flush()
}
}
return FlushWriteBuffer();
bool rval = FlushWriteBuffer();
if ( ! pending_head && write_len == 0 )
write_flare.Extinguish();
return rval;
}
uint32 ChunkedIOFd::ChunkAvailable()
@ -394,6 +405,9 @@ bool ChunkedIOFd::Read(Chunk** chunk, bool may_block)
#ifdef DEBUG_COMMUNICATION
AddToBuffer("<false:read-chunk>", true);
#endif
if ( ! ChunkAvailable() )
read_flare.Extinguish();
return false;
}
@ -402,9 +416,15 @@ bool ChunkedIOFd::Read(Chunk** chunk, bool may_block)
#ifdef DEBUG_COMMUNICATION
AddToBuffer("<null:no-data>", true);
#endif
read_flare.Extinguish();
return true;
}
if ( ChunkAvailable() )
read_flare.Fire();
else
read_flare.Extinguish();
#ifdef DEBUG
if ( *chunk )
DBG_LOG(DBG_CHUNKEDIO, "read of size %d %s[%s]",
@ -481,6 +501,9 @@ bool ChunkedIOFd::ReadChunk(Chunk** chunk, bool may_block)
read_pos = 0;
read_len = bytes_left;
if ( ! ChunkAvailable() )
read_flare.Extinguish();
// If allowed, wait a bit for something to read.
if ( may_block )
{
@ -607,6 +630,14 @@ bool ChunkedIOFd::IsFillingUp()
return stats.pending > MAX_BUFFERED_CHUNKS_SOFT;
}
iosource::FD_Set ChunkedIOFd::ExtraReadFDs() const
{
iosource::FD_Set rval;
rval.Insert(write_flare.FD());
rval.Insert(read_flare.FD());
return rval;
}
void ChunkedIOFd::Clear()
{
while ( pending_head )
@ -618,6 +649,9 @@ void ChunkedIOFd::Clear()
}
pending_head = pending_tail = 0;
if ( write_len == 0 )
write_flare.Extinguish();
}
const char* ChunkedIOFd::Error()
@ -830,6 +864,7 @@ bool ChunkedIOSSL::Write(Chunk* chunk)
else
write_head = write_tail = q;
write_flare.Fire();
Flush();
return true;
}
@ -935,6 +970,7 @@ bool ChunkedIOSSL::Flush()
write_state = LEN;
}
write_flare.Extinguish();
return true;
}
@ -1104,6 +1140,13 @@ bool ChunkedIOSSL::IsFillingUp()
return false;
}
iosource::FD_Set ChunkedIOSSL::ExtraReadFDs() const
{
iosource::FD_Set rval;
rval.Insert(write_flare.FD());
return rval;
}
void ChunkedIOSSL::Clear()
{
while ( write_head )
@ -1114,6 +1157,7 @@ void ChunkedIOSSL::Clear()
write_head = next;
}
write_head = write_tail = 0;
write_flare.Extinguish();
}
const char* ChunkedIOSSL::Error()

View file

@ -6,7 +6,8 @@
#include "config.h"
#include "List.h"
#include "util.h"
#include "Flare.h"
#include "iosource/FD_Set.h"
#include <list>
#ifdef NEED_KRB5_H
@ -95,6 +96,11 @@ public:
// Returns underlying fd if available, -1 otherwise.
virtual int Fd() { return -1; }
// Returns supplementary file descriptors that become read-ready in order
// to signal that there is some work that can be performed.
virtual iosource::FD_Set ExtraReadFDs() const
{ return iosource::FD_Set(); }
// Makes sure that no additional protocol data is written into
// the output stream. If this is activated, the output cannot
// be read again by any of these classes!
@ -177,6 +183,7 @@ public:
virtual void Clear();
virtual bool Eof() { return eof; }
virtual int Fd() { return fd; }
virtual iosource::FD_Set ExtraReadFDs() const;
virtual void Stats(char* buffer, int length);
private:
@ -240,6 +247,8 @@ private:
ChunkQueue* pending_tail;
pid_t pid;
bro::Flare write_flare;
bro::Flare read_flare;
};
// Chunked I/O using an SSL connection.
@ -262,6 +271,7 @@ public:
virtual void Clear();
virtual bool Eof() { return eof; }
virtual int Fd() { return socket; }
virtual iosource::FD_Set ExtraReadFDs() const;
virtual void Stats(char* buffer, int length);
private:
@ -303,6 +313,8 @@ private:
// One SSL for all connections.
static SSL_CTX* ctx;
bro::Flare write_flare;
};
#include <zlib.h>
@ -328,6 +340,8 @@ public:
virtual bool Eof() { return io->Eof(); }
virtual int Fd() { return io->Fd(); }
virtual iosource::FD_Set ExtraReadFDs() const
{ return io->ExtraReadFDs(); }
virtual void Stats(char* buffer, int length);
void EnableCompression(int level)

View file

@ -35,6 +35,7 @@
#include "Net.h"
#include "Var.h"
#include "Reporter.h"
#include "iosource/Manager.h"
extern "C" {
extern int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
@ -404,17 +405,17 @@ DNS_Mgr::~DNS_Mgr()
delete [] dir;
}
bool DNS_Mgr::Init()
void DNS_Mgr::InitPostScript()
{
if ( did_init )
return true;
return;
const char* cache_dir = dir ? dir : ".";
if ( mode == DNS_PRIME && ! ensure_dir(cache_dir) )
{
did_init = 0;
return false;
return;
}
cache_name = new char[strlen(cache_dir) + 64];
@ -433,14 +434,12 @@ bool DNS_Mgr::Init()
did_init = 1;
io_sources.Register(this, true);
iosource_mgr->Register(this, true);
// We never set idle to false, having the main loop only calling us from
// time to time. If we're issuing more DNS requests than we can handle
// in this way, we are having problems anyway ...
idle = true;
return true;
SetIdle(true);
}
static TableVal* fake_name_lookup_result(const char* name)
@ -1217,9 +1216,10 @@ void DNS_Mgr::IssueAsyncRequests()
}
}
void DNS_Mgr::GetFds(int* read, int* write, int* except)
void DNS_Mgr::GetFds(iosource::FD_Set* read, iosource::FD_Set* write,
iosource::FD_Set* except)
{
*read = nb_dns_fd(nb_dns);
read->Insert(nb_dns_fd(nb_dns));
}
double DNS_Mgr::NextTimestamp(double* network_time)

View file

@ -12,7 +12,7 @@
#include "BroList.h"
#include "Dict.h"
#include "EventHandler.h"
#include "IOSource.h"
#include "iosource/IOSource.h"
#include "IPAddr.h"
class Val;
@ -40,12 +40,12 @@ enum DNS_MgrMode {
// Number of seconds we'll wait for a reply.
#define DNS_TIMEOUT 5
class DNS_Mgr : public IOSource {
class DNS_Mgr : public iosource::IOSource {
public:
DNS_Mgr(DNS_MgrMode mode);
virtual ~DNS_Mgr();
bool Init();
void InitPostScript();
void Flush();
// Looks up the address or addresses of the given host, and returns
@ -132,7 +132,8 @@ protected:
void DoProcess(bool flush);
// IOSource interface.
virtual void GetFds(int* read, int* write, int* except);
virtual void GetFds(iosource::FD_Set* read, iosource::FD_Set* write,
iosource::FD_Set* except);
virtual double NextTimestamp(double* network_time);
virtual void Process();
virtual const char* Tag() { return "DNS_Mgr"; }

View file

@ -5,6 +5,7 @@
#include "DebugLogger.h"
#include "Net.h"
#include "plugin/Plugin.h"
DebugLogger debug_logger("debug");
@ -17,7 +18,8 @@ DebugLogger::Stream DebugLogger::streams[NUM_DBGS] = {
{ "dpd", 0, false }, { "tm", 0, false },
{ "logging", 0, false }, {"input", 0, false },
{ "threading", 0, false }, { "file_analysis", 0, false },
{ "plugins", 0, false }, { "broxygen", 0, false }
{ "plugins", 0, false }, { "broxygen", 0, false },
{ "pktio", 0, false}
};
DebugLogger::DebugLogger(const char* filename)
@ -73,10 +75,12 @@ void DebugLogger::EnableStreams(const char* s)
{
if ( strcasecmp("verbose", tok) == 0 )
verbose = true;
else
else if ( strncmp(tok, "plugin-", 7) != 0 )
reporter->FatalError("unknown debug stream %s\n", tok);
}
enabled_streams.insert(tok);
tok = strtok(0, ",");
}
@ -105,4 +109,24 @@ void DebugLogger::Log(DebugStream stream, const char* fmt, ...)
fflush(file);
}
void DebugLogger::Log(const plugin::Plugin& plugin, const char* fmt, ...)
{
string tok = string("plugin-") + plugin.Name();
tok = strreplace(tok, "::", "-");
if ( enabled_streams.find(tok) == enabled_streams.end() )
return;
fprintf(file, "%17.06f/%17.06f [plugin %s] ",
network_time, current_time(true), plugin.Name().c_str());
va_list ap;
va_start(ap, fmt);
vfprintf(file, fmt, ap);
va_end(ap);
fputc('\n', file);
fflush(file);
}
#endif

View file

@ -7,6 +7,8 @@
#ifdef DEBUG
#include <stdio.h>
#include <string>
#include <set>
// To add a new debugging stream, add a constant here as well as
// an entry to DebugLogger::streams in DebugLogger.cc.
@ -27,8 +29,9 @@ enum DebugStream {
DBG_INPUT, // Input streams
DBG_THREADING, // Threading system
DBG_FILE_ANALYSIS, // File analysis
DBG_PLUGINS,
DBG_BROXYGEN,
DBG_PLUGINS, // Plugin system
DBG_BROXYGEN, // Broxygen
DBG_PKTIO, // Packet sources and dumpers.
NUM_DBGS // Has to be last
};
@ -42,6 +45,10 @@ enum DebugStream {
#define DBG_PUSH(stream) debug_logger.PushIndent(stream)
#define DBG_POP(stream) debug_logger.PopIndent(stream)
#define PLUGIN_DBG_LOG(plugin, args...) debug_logger.Log(plugin, args)
namespace plugin { class Plugin; }
class DebugLogger {
public:
// Output goes to stderr per default.
@ -49,6 +56,7 @@ public:
~DebugLogger();
void Log(DebugStream stream, const char* fmt, ...);
void Log(const plugin::Plugin& plugin, const char* fmt, ...);
void PushIndent(DebugStream stream)
{ ++streams[int(stream)].indent; }
@ -79,6 +87,8 @@ private:
bool enabled;
};
std::set<std::string> enabled_streams;
static Stream streams[NUM_DBGS];
};
@ -89,6 +99,7 @@ extern DebugLogger debug_logger;
#define DBG_LOG_VERBOSE(args...)
#define DBG_PUSH(stream)
#define DBG_POP(stream)
#define PLUGIN_DBG_LOG(plugin, args...)
#endif
#endif

View file

@ -6,6 +6,7 @@
#include "Func.h"
#include "NetVar.h"
#include "Trigger.h"
#include "plugin/Manager.h"
EventMgr mgr;
@ -77,6 +78,11 @@ EventMgr::~EventMgr()
void EventMgr::QueueEvent(Event* event)
{
bool done = PLUGIN_HOOK_WITH_RESULT(HOOK_QUEUE_EVENT, HookQueueEvent(event), false);
if ( done )
return;
if ( ! head )
head = tail = event;
else
@ -115,6 +121,8 @@ void EventMgr::Drain()
SegmentProfiler(segment_logger, "draining-events");
PLUGIN_HOOK_VOID(HOOK_DRAIN_EVENTS, HookDrainEvents());
draining = true;
while ( head )
Dispatch();

View file

@ -24,6 +24,8 @@ public:
SourceID Source() const { return src; }
analyzer::ID Analyzer() const { return aid; }
TimerMgr* Mgr() const { return mgr; }
EventHandlerPtr Handler() const { return handler; }
val_list* Args() const { return args; }
void Describe(ODesc* d) const;

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