Merge remote-tracking branch 'origin/master' into topic/seth/scripts-for-2.1

Conflicts:
	scripts/base/frameworks/packet-filter/main.bro
This commit is contained in:
Seth Hall 2012-04-25 11:56:54 -04:00
commit 7b19dcd0e7
353 changed files with 11398 additions and 6029 deletions

383
CHANGES
View file

@ -1,13 +1,388 @@
2.0-306 | 2012-04-24 14:37:00 -0700
* Add further TLS extension values "extended_random" and
"heartbeat". (Seth Hall)
* Fix problem with extracting FTP passwords and add "ftpuser" as
another anonymous username. (Seth Hall, discovered by Patrik
Lundin).
2.0-303 | 2012-04-19 10:01:06 -0700
* Changes related to ICMPv6 Neighbor Discovery messages. (Jon Siwek)
- The 'icmp_conn' record now contains an 'hlim' field since hop limit
in the IP header is an interesting field for at least these ND
messages.
- Fixed and extended 'icmp_router_advertisement' event parameters.
- Changed 'icmp_neighbor_advertisement' event parameters to add
more of the known boolean flags.
2.0-301 | 2012-04-17 17:58:55 -0700
* Bro now support ICMPv6. (Matti Mantere, Jon Siwek, Robin Sommer,
Daniel Thayer).
Overall, Bro now raises the following ICMP events for v4 and v6 as
appropiate:
event icmp_sent(c: connection, icmp: icmp_conn);
event icmp_echo_request(c: connection, icmp: icmp_conn, id: count, seq: count, payload: string);
event icmp_echo_reply(c: connection, icmp: icmp_conn, id: count, seq: count, payload: string);
event icmp_error_message(c: connection, icmp: icmp_conn, code: count, context: icmp_context);
event icmp_unreachable(c: connection, icmp: icmp_conn, code: count, context: icmp_context);
event icmp_packet_too_big(c: connection, icmp: icmp_conn, code: count, context: icmp_context);
event icmp_time_exceeded(c: connection, icmp: icmp_conn, code: count, context: icmp_context);
event icmp_parameter_problem(c: connection, icmp: icmp_conn, code: count, context: icmp_context);
event icmp_router_solicitation(c: connection, icmp: icmp_conn);
event icmp_router_advertisement(c: connection, icmp: icmp_conn, hop_limit: count, managed: bool, router_lifetime: count, reachable_time: interval, retrans_timer: interval);
event icmp_neighbor_solicitation(c: connection, icmp: icmp_conn, tgt:addr);
event icmp_neighbor_advertisement(c: connection, icmp: icmp_conn, tgt:addr);
event icmp_redirect(c: connection, icmp: icmp_conn, tgt: addr, dest: addr);
The `icmp_conn` record got a new boolean field 'v6' that indicates
whether the ICMP message is v4 or v6.
This change also includes further low-level work on existing IP
and ICMP code, including a reorganization of how ICMPv4 is
handled.
2.0-281 | 2012-04-17 17:40:39 -0700
* Small updates for the bittorrent analyzer to support 64bit types
in binpac. (Seth Hall)
* Removed the attempt at bittorrent resynchronization. (Seth Hall)
2.0-276 | 2012-04-17 17:35:56 -0700
* Add more support for <netinet/ip6.h>'s that lack some structure
definitions. (Jon Siwek)
2.0-273 | 2012-04-16 18:08:56 -0700
* Removing QR flag from DNS log in response, which should not have
been there in the first place. (Seth Hall)
* Sync up patricia.c/h with pysubnettree repo. (Daniel Thayer)
* Adding missing leak groups to a couple tests. Also activating leak
checking for proxy in basic-cluster test. (Robin Sommer)
2.0-267 | 2012-04-09 17:47:28 -0700
* Add support for mobile IPv6 Mobility Header (RFC 6275). (Jon
Siwek)
- Enabled through a new --enable-mobile-ipv6 configure-time
option. If not enabled, the mobility header (routing type 2) and
Home Address Destination option are ignored.
- Accessible at script-layer through 'mobile_ipv6_message' event.
* Refactor IP_Hdr routing header handling, add MobileIPv6 Home
Address handling. Packets that use the Home Address Destination
option use that option's address as the connection's originator.
(Jon Siwek)
* Revert TCP checksumming to cache common data, like it did before.
(Jon Siwek)
* Improve handling of IPv6 routing type 0 extension headers. (Jon
Siwek)
- flow_weird event with name argument value of "routing0_hdr" is raised
for packets containing an IPv6 routing type 0 header because this
type of header is now deprecated according to RFC 5095.
- Packets with a routing type 0 header and non-zero segments left
now use the last address in that header in order to associate
with a connection/flow and for calculating TCP/UDP checksums.
- Added a set of IPv4/IPv6 TCP/UDP checksum unit tests (Jon Siwek)
* Fix table expiry for values assigned in bro_init() when reading
live. (Jon Siwek)
2.0-257 | 2012-04-05 15:32:43 -0700
* Fix CMake from warning about unused ENABLE_PERFTOOLS_DEBUG
variable. (Jon Siwek)
* Fix handling of IPv6 atomic fragments. (Jon Siwek)
* Fix that prevents Bro processes that do neither local logging nor
request remote logs from spawning threads. (Robin Sommer)
* Fixing perftools-debug support. (Robin Sommer)
* Reverting SocketComm change tuning I/O behaviour. (Robin Sommer)
* Adding notice_policy.log canonification for external tests. (Robin Sommer)
2.0-245 | 2012-04-04 17:25:20 -0700
* Internal restructuring of the logging framework: we now spawn
threads doing the I/O. From a user's perspective not much should
change, except that the OS may now show a bunch of Bro threads.
(Gilbert Clark and Robin Sommer).
* When building Bro, we now always link in tcmalloc if it's found at
configure time. If it's installed but not picked up,
--with-perftools may help. (Robin Sommer)
* Renaming the configure option --enable-perftools to
--enable-perftool-debug to indicate that the switch is only
relevant for debugging the heap. It's not needed to pick up
tcmalloc for better performance. (Robin Sommer)
2.0-184 | 2012-03-28 15:11:11 -0700
* Improve handling of IPv6 Routing Type 0 headers. (Jon Siwek)
- For RH0 headers with non-zero segments left, a
"routing0_segleft" flow_weird event is raised (with a
destination indicating the last address in the routing header),
and an "rh0_segleft" event can also be handled if the other
contents of the packet header are of interest. No further
analysis is done as the complexity required to correctly
identify destination endpoints of connections doesn't seem worth
it as RH0 has been deprecated by RFC 5095.
- For RH0 headers without any segments left, a "routing0_header"
flow_weird event is raised, but further analysis still occurs as
normal.
2.0-182 | 2012-03-28 15:01:57 -0700
* Remove dead tcp_checksum function from net_util. (Jon Siwek)
* Change routing0_data_to_addrs BIF to return vector of addresses.
The order of addresses in type 0 routing headers is
interesting/important. (Jon Siwek)
2.0-179 | 2012-03-23 17:43:31 -0700
* Remove the default "tcp or udp or icmp" filter. In default mode,
Bro would load the packet filter script framework which installs a
filter that allows all packets, but in bare mode (the -b option),
this old filter would not follow IPv6 protocol chains and thus
filter out packets with extension headers. (Jon Siwek)
* Update PacketFilter/Discarder code for IP version independence.
(Jon Siwek)
* Fix some IPv6 header related bugs. (Jon Siwek)
* Add IPv6 fragment reassembly. (Jon Siwek)
* Add handling for IPv6 extension header chains. Addresses #531.
(Jon Siwek)
- The script-layer 'pkt_hdr' type is extended with a new 'ip6' field
representing the full IPv6 header chain.
- The 'new_packet' event is now raised for IPv6 packets. Addresses
#523.
- A new event called 'ipv6_ext_header' is raised for any IPv6
packet containing extension headers.
- A new event called 'esp_packet' is raised for any packets using
ESP ('new_packet' and 'ipv6_ext_header' events provide
connection info, but that info can't be provided here since the
upper-layer payload is encrypted).
- The 'unknown_protocol' weird is now raised more reliably when
Bro sees a transport protocol or IPv6 extension header it can't
handle. Addresses #522.
* Add unit tests for IPv6 fragment reassembly, ipv6_ext_headers and
esp_packet events. (Jon Siwek)
* Adapt FreeBSD's inet_ntop implementation for internal use. Now we
get consistent text representations of IPv6 addresses across
platforms. (Jon Siwek)
* Update documentation for new syntax of IPv6 literals. (Jon Siwek)
2.0-150 | 2012-03-13 16:16:22 -0700
* Changing the regular expression to allow Site::local_nets in
signatures. (Julien Sentier)
* Removing a line of dead code. Found by . Closes #786. (Julien
Sentier)
2.0-146 | 2012-03-13 15:39:38 -0700
* Change IPv6 literal constant syntax to require encasing square
brackets. (Jon Siwek)
2.0-145 | 2012-03-09 15:10:35 -0800
* Remove the match expression. 'match' and 'using' are no longer
keywords. Addressed #753. (Jon Siwek)
2.0-143 | 2012-03-09 15:07:42 -0800
* Fix a BRO_PROFILER_FILE/mkstemp portability issue. Addresses #794.
(Jon Siwek)
2.0-139 | 2012-03-02 09:33:04 -0800
* Changes to how script coverage integrates with test suites. (Jon Siwek)
- BRO_PROFILER_FILE now passes .X* templated filenames to mkstemp
for generating unique coverage state files.
- Rearranging Makefile targets. The general rule is that if the
all/brief target fails out due to a test failure, then the dependent
coverage target won't run, but can still be invoked directly later.
(e.g. make brief || make coverage)
* Standardized on the &default function for SSL constants. (Seth
Hall)
* Adding btest group "leaks" to leak tests. (Robin Sommer)
* Adding btest group "comm" to communication tests for parallelizing
execution with new btest version. (Robin Sommer)
* Sorting all output for diffing in the external tests. (Robin
Sommer)
* Cleaned up dead code from the old SSL analyzers. Reported by
Julien Sentier. (Seth Hall)
* Update/add tests for broccoli IPv6 addr/subnet support. Addresses
#448. (Jon Siwek)
* Remove connection compressor. Addresses #559. (Jon Siwek)
* Refactor IP_Hdr class ctors. Addresses #532. (Jon Siwek)
2.0-121 | 2012-02-24 16:34:17 -0800
* A number of smaller memory fixes and code cleanups. (Julien
Sentier)
* Add to_subnet bif. Fixes #782). (Jon Siwek)
* Fix IPAddr::Mask/ReverseMask not allowing argument of 0. (Jon
Siwek)
* Refactor IPAddr v4 initialization from string. Fixes #775. (Jon Siwek)
* Parse the dotted address string directly instead of canonicalizing
and passing to inet_pton. (Jon Siwek)
2.0-108 | 2012-02-24 15:21:07 -0800
* Refactoring a number of usages of new IPAddr class. (Jon Siwek)
* Fixed a bug in remask_addr bif. (Jon Siwek)
2.0-106 | 2012-02-24 15:02:20 -0800
* Raise minimum required CMake version to 2.6.3. (Jon Siwek)
2.0-104 | 2012-02-24 14:59:12 -0800
* Add test case for FTP over IPv4. (Daniel Thayer)
* Fix IPv6 URLs in ftp.log. (Daniel Thayer)
* Add a test for FTP over IPv6 (Daniel Thayer)
* Fix parsing of FTP EPRT command and EPSV response. (Daniel Thayer)
2.0-95 | 2012-02-22 05:27:34 -0800
* GeoIP installation documentation update. (Seth Hall)
* Decrease strictness of parsing IPv4 strings into addrs. Fixes #775. (Jon Siwek)
* Fix memory leak in DNS manager. Fixes #777. (Jon Siwek)
* Fix IPAddr/IPPrefix serialization bugs. (Jon Siwek)
* Fix compile error. (Jon Siwek)
2.0-86 | 2012-02-17 15:41:06 -0800
* Changing ARP detection to always kick in even if no analyzer is
activated. (Robin Sommer)
* DNS name lookups performed by Bro now also query AAAA records.
DNS_Mgr handles combining the results of the A and AAAA queries
for a given hostname such that at the scripting layer, the name
resolution can yield a set with both IPv4 and IPv6 addresses. (Jon
Siwek)
* Add counts_to_addr and addr_to_counts conversion BIFs. (Jon Siwek)
* Change HashKey threshold for using H3 to 36 bytes. (Jon Siwek)
* Remove mention of --enable-brov6 in docs. (Daniel Thayer)
* Remove --enable-brov6 from configure usage text (Daniel Thayer)
* Add a test and baseline for addr_to_ptr_name BiF. (Daniel Thayer)
* Adding a test and baseline for ptr_name_to_addr BiF. (Seth Hall)
* Fix the ptr_name_to_addr BiF to work with IPv6 (Daniel Thayer)
* Fix a memory leak that perftools now complains about. (Jon Siwek)
* Remove --enable-brov6 flag, IPv6 now supported by default. (Jon Siwek)
Some script-layer changes of note:
- dns_AAAA_reply event signature changed: the string representation
of an IPv6 addr is easily derived from the addr value, it doesn't
need to be another parameter. This event also now generated directly
by the DNS analyzer instead of being "faked" into a dns_A_reply event.
- Removed addr_to_count BIF. It used to return the host-order
count representation of IPv4 addresses only. To make it more
generic, we might later add a BIF to return a vector of counts
in order to support IPv6.
- Changed the result of enclosing addr variables in vertical pipes
(e.g. |my_addr|) to return the bit-width of the address type which
is 128 for IPv6 and 32 for IPv4. It used to function the same
way as addr_to_count mentioned above.
- Remove bro_has_ipv6 BIF
2.0-57 | 2012-02-10 00:02:35 -0800
* Fix typos in the documentation. (Daniel Thayer)
* Fix compiler warning about Brofiler ctor init list order. (Jon Siwek)
* Fix missing optional field access in webapp signature_match handler. (Jon Siwek)
2.0-41 | 2012-02-03 04:10:53 -0500 2.0-41 | 2012-02-03 04:10:53 -0500
* Updates to the Software framework to simplify the API. * Updates to the Software framework to simplify the API. (Bernhard
(Bernhard Amann) Amann)
2.0-40 | 2012-02-03 01:55:27 -0800 2.0-40 | 2012-02-03 01:55:27 -0800
* Fix typos in documentation. (Daniel Thayer) * Fix typos in documentation. (Daniel Thayer)
* Fix sorting of lines in Brofiler coverage.log. (Daniel Thayer) * Fix sorting of lines in Brofiler coverage.log. (Daniel Thayer)
2.0-38 | 2012-01-31 11:50:53 -0800 2.0-38 | 2012-01-31 11:50:53 -0800

View file

@ -1,5 +1,5 @@
project(Bro C CXX) project(Bro C CXX)
cmake_minimum_required(VERSION 2.6 FATAL_ERROR) cmake_minimum_required(VERSION 2.6.3 FATAL_ERROR)
include(cmake/CommonCMakeConfig.cmake) include(cmake/CommonCMakeConfig.cmake)
######################################################################## ########################################################################
@ -89,15 +89,29 @@ if (LIBGEOIP_FOUND)
endif () endif ()
set(USE_PERFTOOLS false) set(USE_PERFTOOLS false)
if (ENABLE_PERFTOOLS) set(USE_PERFTOOLS_DEBUG false)
find_package(GooglePerftools)
if (GOOGLEPERFTOOLS_FOUND) find_package(GooglePerftools)
set(USE_PERFTOOLS true)
include_directories(BEFORE ${GooglePerftools_INCLUDE_DIR}) if (GOOGLEPERFTOOLS_FOUND)
include_directories(BEFORE ${GooglePerftools_INCLUDE_DIR})
set(USE_PERFTOOLS true)
if (ENABLE_PERFTOOLS_DEBUG)
# Enable heap debugging with perftools.
set(USE_PERFTOOLS_DEBUG true)
list(APPEND OPTLIBS ${GooglePerftools_LIBRARIES_DEBUG})
else ()
# Link in tcmalloc for better performance.
list(APPEND OPTLIBS ${GooglePerftools_LIBRARIES}) list(APPEND OPTLIBS ${GooglePerftools_LIBRARIES})
endif () endif ()
endif () endif ()
if (ENABLE_PERFTOOLS_DEBUG)
# Just a no op to prevent CMake from complaining about manually-specified
# ENABLE_PERFTOOLS_DEBUG not being used if google perftools weren't found
endif ()
set(brodeps set(brodeps
${BinPAC_LIBRARY} ${BinPAC_LIBRARY}
${PCAP_LIBRARY} ${PCAP_LIBRARY}
@ -183,6 +197,7 @@ message(
"\n" "\n"
"\nGeoIP: ${USE_GEOIP}" "\nGeoIP: ${USE_GEOIP}"
"\nGoogle perftools: ${USE_PERFTOOLS}" "\nGoogle perftools: ${USE_PERFTOOLS}"
"\n debugging: ${USE_PERFTOOLS_DEBUG}"
"\n" "\n"
"\n================================================================\n" "\n================================================================\n"
) )

View file

@ -8,7 +8,7 @@ Prerequisites
Bro relies on the following libraries and tools, which need to be installed Bro relies on the following libraries and tools, which need to be installed
before you begin: before you begin:
* CMake 2.6 or greater http://www.cmake.org * CMake 2.6.3 or greater http://www.cmake.org
* Libpcap (headers and libraries) http://www.tcpdump.org * Libpcap (headers and libraries) http://www.tcpdump.org

46
NEWS
View file

@ -5,6 +5,51 @@ Release Notes
This document summarizes the most important changes in the current Bro This document summarizes the most important changes in the current Bro
release. For a complete list of changes, see the ``CHANGES`` file. release. For a complete list of changes, see the ``CHANGES`` file.
Bro 2.1
-------
- Dependencies:
* Bro now requires CMake >= 2.6.3.
* Bro now links in tcmalloc (part of Google perftools) if found at
configure time. Doing so can significantly improve memory and
CPU use.
- Bro now supports IPv6 out of the box; the configure switch
--enable-brov6 is gone.
- DNS name lookups performed by Bro now also query AAAA records. The
results of the A and AAAA queries for a given hostname are combined
such that at the scripting layer, the name resolution can yield a
set with both IPv4 and IPv6 addresses.
- The connection compressor was already deprecated in 2.0 and has now
been removed from the code base.
- We removed the "match" statement, which was no longer used by any of
the default scripts, nor was it likely to be used by anybody anytime
soon. With that, "match" and "using" are no longer reserved keywords.
- The syntax for IPv6 literals changed from "2607:f8b0:4009:802::1012"
to "[2607:f8b0:4009:802::1012]".
- Bro now spawn threads for doing its logging. From a user's
perspective not much should change, except that the OS may now show
a bunch of Bro threads.
- We renamed the configure option --enable-perftools to
--enable-perftool-debug to indicate that the switch is only relevant
for debugging the heap.
- Bro's ICMP analyzer now handles both IPv4 and IPv6 messages with a
joint set of events. The `icmp_conn` record got a new boolean field
'v6' that indicates whether the ICMP message is v4 or v6.
TODO: Extend.
Bro 2.0 Bro 2.0
------- -------
@ -61,4 +106,3 @@ final release are:

View file

@ -1 +1 @@
2.0-41 2.0-306

@ -1 +1 @@
Subproject commit 43308aab47a3357ca1885e1b6954154a2744d821 Subproject commit 71c37019bc371eb7863fb6aa47a7daa4540f4f1f

@ -1 +1 @@
Subproject commit 139cc2e1e049c4e1cc7e95f20866102be1d3d599 Subproject commit d885987e7968669e34504b0403ac89bd13928e9a

@ -1 +1 @@
Subproject commit 930e7c78221929849086a578308e2fdc99ac3fb8 Subproject commit 55f368b0ad283b2e7d68ef72922b5d9683e2a880

@ -1 +1 @@
Subproject commit e908ba686dceb56065bdf569c18dd0f67f662f6b Subproject commit ff35c3c144885902c898bf8b47e351c7b8d55e10

@ -1 +1 @@
Subproject commit ee87db37b520b88a55323a9767234c30b801e439 Subproject commit 045a02749b20b3c5896497959e6fda02d060508f

2
cmake

@ -1 +1 @@
Subproject commit 2cc105577044a2d214124568f3f2496ed2ccbb34 Subproject commit 49278736c1404cb8c077272b80312c947e68bf52

View file

@ -1,6 +1,3 @@
/* enable IPV6 processing */
#cmakedefine BROv6
/* Old libpcap versions (< 0.6.1) need defining pcap_freecode and /* Old libpcap versions (< 0.6.1) need defining pcap_freecode and
pcap_compile_nopcap */ pcap_compile_nopcap */
#cmakedefine DONT_HAVE_LIBPCAP_PCAP_FREECODE #cmakedefine DONT_HAVE_LIBPCAP_PCAP_FREECODE
@ -112,7 +109,10 @@
#cmakedefine HAVE_GEOIP_CITY_EDITION_REV0_V6 #cmakedefine HAVE_GEOIP_CITY_EDITION_REV0_V6
/* Use Google's perftools */ /* Use Google's perftools */
#cmakedefine USE_PERFTOOLS #cmakedefine USE_PERFTOOLS_DEBUG
/* Analyze Mobile IPv6 traffic */
#cmakedefine ENABLE_MOBILE_IPV6
/* Version number of package */ /* Version number of package */
#define VERSION "@VERSION@" #define VERSION "@VERSION@"
@ -152,3 +152,47 @@
#ifndef HAVE_DLT_PPP_SERIAL #ifndef HAVE_DLT_PPP_SERIAL
#define DLT_PPP_SERIAL @DLT_PPP_SERIAL@ #define DLT_PPP_SERIAL @DLT_PPP_SERIAL@
#endif #endif
/* IPv6 Next Header values defined by RFC 3542 */
#cmakedefine HAVE_IPPROTO_HOPOPTS
#ifndef HAVE_IPPROTO_HOPOPTS
#define IPPROTO_HOPOPTS 0
#endif
#cmakedefine HAVE_IPPROTO_IPV6
#ifndef HAVE_IPPROTO_IPV6
#define IPPROTO_IPV6 41
#endif
#cmakedefine HAVE_IPPROTO_ROUTING
#ifndef HAVE_IPPROTO_ROUTING
#define IPPROTO_ROUTING 43
#endif
#cmakedefine HAVE_IPPROTO_FRAGMENT
#ifndef HAVE_IPPROTO_FRAGMENT
#define IPPROTO_FRAGMENT 44
#endif
#cmakedefine HAVE_IPPROTO_ESP
#ifndef HAVE_IPPROTO_ESP
#define IPPROTO_ESP 50
#endif
#cmakedefine HAVE_IPPROTO_AH
#ifndef HAVE_IPPROTO_AH
#define IPPROTO_AH 51
#endif
#cmakedefine HAVE_IPPROTO_ICMPV6
#ifndef HAVE_IPPROTO_ICMPV6
#define IPPROTO_ICMPV6 58
#endif
#cmakedefine HAVE_IPPROTO_NONE
#ifndef HAVE_IPPROTO_NONE
#define IPPROTO_NONE 59
#endif
#cmakedefine HAVE_IPPROTO_DSTOPTS
#ifndef HAVE_IPPROTO_DSTOPTS
#define IPPROTO_DSTOPTS 60
#endif
/* IPv6 options structure defined by RFC 3542 */
#cmakedefine HAVE_IP6_OPT
/* Common IPv6 extension structure */
#cmakedefine HAVE_IP6_EXT

44
configure vendored
View file

@ -24,11 +24,12 @@ Usage: $0 [OPTION]... [VAR=VALUE]...
--prefix=PREFIX installation directory [/usr/local/bro] --prefix=PREFIX installation directory [/usr/local/bro]
--scriptdir=PATH root installation directory for Bro scripts --scriptdir=PATH root installation directory for Bro scripts
[PREFIX/share/bro] [PREFIX/share/bro]
--conf-files-dir=PATH config files installation directory [PREFIX/etc]
Optional Features: Optional Features:
--enable-debug compile in debugging mode --enable-debug compile in debugging mode
--enable-brov6 enable IPv6 processing --enable-mobile-ipv6 analyze mobile IPv6 features defined by RFC 6275
--enable-perftools use Google's perftools --enable-perftools-debug use Google's perftools for debugging
--disable-broccoli don't build or install the Broccoli library --disable-broccoli don't build or install the Broccoli library
--disable-broctl don't install Broctl --disable-broctl don't install Broctl
--disable-auxtools don't build or install auxilliary tools --disable-auxtools don't build or install auxilliary tools
@ -86,20 +87,22 @@ append_cache_entry () {
# set defaults # set defaults
builddir=build builddir=build
prefix=/usr/local/bro
CMakeCacheEntries="" CMakeCacheEntries=""
append_cache_entry CMAKE_INSTALL_PREFIX PATH /usr/local/bro append_cache_entry CMAKE_INSTALL_PREFIX PATH $prefix
append_cache_entry BRO_ROOT_DIR PATH /usr/local/bro append_cache_entry BRO_ROOT_DIR PATH $prefix
append_cache_entry PY_MOD_INSTALL_DIR PATH /usr/local/bro/lib/broctl append_cache_entry PY_MOD_INSTALL_DIR PATH $prefix/lib/broctl
append_cache_entry BRO_SCRIPT_INSTALL_PATH STRING /usr/local/bro/share/bro append_cache_entry BRO_SCRIPT_INSTALL_PATH STRING $prefix/share/bro
append_cache_entry BRO_ETC_INSTALL_DIR PATH $prefix/etc
append_cache_entry ENABLE_DEBUG BOOL false append_cache_entry ENABLE_DEBUG BOOL false
append_cache_entry BROv6 BOOL false append_cache_entry ENABLE_PERFTOOLS_DEBUG BOOL false
append_cache_entry ENABLE_PERFTOOLS BOOL false
append_cache_entry BinPAC_SKIP_INSTALL BOOL true append_cache_entry BinPAC_SKIP_INSTALL BOOL true
append_cache_entry BUILD_SHARED_LIBS BOOL true append_cache_entry BUILD_SHARED_LIBS BOOL true
append_cache_entry INSTALL_AUX_TOOLS BOOL true append_cache_entry INSTALL_AUX_TOOLS BOOL true
append_cache_entry INSTALL_BROCCOLI BOOL true append_cache_entry INSTALL_BROCCOLI BOOL true
append_cache_entry INSTALL_BROCTL BOOL true append_cache_entry INSTALL_BROCTL BOOL true
append_cache_entry CPACK_SOURCE_IGNORE_FILES STRING append_cache_entry CPACK_SOURCE_IGNORE_FILES STRING
append_cache_entry ENABLE_MOBILE_IPV6 BOOL false
# parse arguments # parse arguments
while [ $# -ne 0 ]; do while [ $# -ne 0 ]; do
@ -120,25 +123,27 @@ while [ $# -ne 0 ]; do
CMakeGenerator="$optarg" CMakeGenerator="$optarg"
;; ;;
--prefix=*) --prefix=*)
prefix=$optarg
append_cache_entry CMAKE_INSTALL_PREFIX PATH $optarg append_cache_entry CMAKE_INSTALL_PREFIX PATH $optarg
append_cache_entry BRO_ROOT_DIR PATH $optarg append_cache_entry BRO_ROOT_DIR PATH $optarg
append_cache_entry PY_MOD_INSTALL_DIR PATH $optarg/lib/broctl append_cache_entry PY_MOD_INSTALL_DIR PATH $optarg/lib/broctl
if [ "$user_set_scriptdir" != "true" ]; then
append_cache_entry BRO_SCRIPT_INSTALL_PATH STRING $optarg/share/bro
fi
;; ;;
--scriptdir=*) --scriptdir=*)
append_cache_entry BRO_SCRIPT_INSTALL_PATH STRING $optarg append_cache_entry BRO_SCRIPT_INSTALL_PATH STRING $optarg
user_set_scriptdir="true" user_set_scriptdir="true"
;; ;;
--conf-files-dir=*)
append_cache_entry BRO_ETC_INSTALL_DIR PATH $optarg
user_set_conffilesdir="true"
;;
--enable-debug) --enable-debug)
append_cache_entry ENABLE_DEBUG BOOL true append_cache_entry ENABLE_DEBUG BOOL true
;; ;;
--enable-brov6) --enable-mobile-ipv6)
append_cache_entry BROv6 BOOL true append_cache_entry ENABLE_MOBILE_IPV6 BOOL true
;; ;;
--enable-perftools) --enable-perftools-debug)
append_cache_entry ENABLE_PERFTOOLS BOOL true append_cache_entry ENABLE_PERFTOOLS_DEBUG BOOL true
;; ;;
--disable-broccoli) --disable-broccoli)
append_cache_entry INSTALL_BROCCOLI BOOL false append_cache_entry INSTALL_BROCCOLI BOOL false
@ -183,7 +188,6 @@ while [ $# -ne 0 ]; do
append_cache_entry LibGeoIP_ROOT_DIR PATH $optarg append_cache_entry LibGeoIP_ROOT_DIR PATH $optarg
;; ;;
--with-perftools=*) --with-perftools=*)
append_cache_entry ENABLE_PERFTOOLS BOOL true
append_cache_entry GooglePerftools_ROOT_DIR PATH $optarg append_cache_entry GooglePerftools_ROOT_DIR PATH $optarg
;; ;;
--with-python=*) --with-python=*)
@ -232,6 +236,14 @@ while [ $# -ne 0 ]; do
shift shift
done done
if [ "$user_set_scriptdir" != "true" ]; then
append_cache_entry BRO_SCRIPT_INSTALL_PATH STRING $prefix/share/bro
fi
if [ "$user_set_conffilesdir" != "true" ]; then
append_cache_entry BRO_ETC_INSTALL_DIR PATH $prefix/etc
fi
if [ -d $builddir ]; then if [ -d $builddir ]; then
# If build directory exists, check if it has a CMake cache # If build directory exists, check if it has a CMake cache
if [ -f $builddir/CMakeCache.txt ]; then if [ -f $builddir/CMakeCache.txt ]; then

View file

@ -103,7 +103,13 @@ Optional Dependencies
Bro can use libGeoIP for geo-locating IP addresses, and sendmail for Bro can use libGeoIP for geo-locating IP addresses, and sendmail for
sending emails. sending emails.
* RPM/RedHat-based Linux: * RedHat Enterprise Linux:
.. console::
sudo yum install geoip-devel sendmail
* CentOS Linux:
.. console:: .. console::

View file

@ -22,7 +22,7 @@ The Bro scripting language supports the following built-in types.
is a string of digits preceded by a ``+`` or ``-`` sign, e.g. is a string of digits preceded by a ``+`` or ``-`` sign, e.g.
``-42`` or ``+5``. When using type inferencing use care so that the ``-42`` or ``+5``. When using type inferencing use care so that the
intended type is inferred, e.g. ``local size_difference = 0`` will intended type is inferred, e.g. ``local size_difference = 0`` will
infer the :bro:type:`count` while ``local size_difference = +0`` infer :bro:type:`count`, while ``local size_difference = +0``
will infer :bro:type:`int`. will infer :bro:type:`int`.
.. bro:type:: count .. bro:type:: count
@ -32,7 +32,7 @@ The Bro scripting language supports the following built-in types.
.. bro:type:: counter .. bro:type:: counter
An alias to :bro:type:`count` An alias to :bro:type:`count`.
.. TODO: is there anything special about this type? .. TODO: is there anything special about this type?
@ -70,7 +70,7 @@ The Bro scripting language supports the following built-in types.
A type used to hold character-string values which represent text. A type used to hold character-string values which represent text.
String constants are created by enclosing text in double quotes (") String constants are created by enclosing text in double quotes (")
and the backslash character (\) introduces escape sequences. and the backslash character (\\) introduces escape sequences.
Note that Bro represents strings internally as a count and vector of Note that Bro represents strings internally as a count and vector of
bytes rather than a NUL-terminated byte string (although string bytes rather than a NUL-terminated byte string (although string
@ -135,7 +135,7 @@ The Bro scripting language supports the following built-in types.
type color: enum { Red, White, Blue, }; type color: enum { Red, White, Blue, };
The last comma is after ``Blue`` is optional. The last comma after ``Blue`` is optional.
.. bro:type:: timer .. bro:type:: timer
@ -150,21 +150,23 @@ The Bro scripting language supports the following built-in types.
followed by one of ``/tcp``, ``/udp``, ``/icmp``, or ``/unknown``. followed by one of ``/tcp``, ``/udp``, ``/icmp``, or ``/unknown``.
Ports can be compared for equality and also for ordering. When Ports can be compared for equality and also for ordering. When
comparing order across transport-level protocols, ``/unknown`` < comparing order across transport-level protocols, ``unknown`` <
``/tcp`` < ``/udp`` < ``icmp``, for example ``65535/tcp`` is smaller ``tcp`` < ``udp`` < ``icmp``, for example ``65535/tcp`` is smaller
than ``0/udp``. than ``0/udp``.
.. bro:type:: addr .. bro:type:: addr
A type representing an IP address. Currently, Bro defaults to only A type representing an IP address.
supporting IPv4 addresses unless configured/built with
``--enable-brov6``, in which case, IPv6 addresses are supported.
IPv4 address constants are written in "dotted quad" format, IPv4 address constants are written in "dotted quad" format,
``A1.A2.A3.A4``, where Ai all lie between 0 and 255. ``A1.A2.A3.A4``, where Ai all lie between 0 and 255.
IPv6 address constants are written as colon-separated hexadecimal form IPv6 address constants are written as colon-separated hexadecimal form
as described by :rfc:`2373`. as described by :rfc:`2373`, but additionally encased in square brackets.
The mixed notation with embedded IPv4 addresses as dotted-quads in the
lower 32 bits is also allowed.
Some examples: ``[2001:db8::1]``, ``[::ffff:192.168.1.100]``, or
``[aaaa:bbbb:cccc:dddd:eeee:ffff:1111:2222]``.
Hostname constants can also be used, but since a hostname can Hostname constants can also be used, but since a hostname can
correspond to multiple IP addresses, the type of such variable is a correspond to multiple IP addresses, the type of such variable is a
@ -198,7 +200,7 @@ The Bro scripting language supports the following built-in types.
A type representing a block of IP addresses in CIDR notation. A A type representing a block of IP addresses in CIDR notation. A
``subnet`` constant is written as an :bro:type:`addr` followed by a ``subnet`` constant is written as an :bro:type:`addr` followed by a
slash (/) and then the network prefix size specified as a decimal slash (/) and then the network prefix size specified as a decimal
number. For example, ``192.168.0.0/16``. number. For example, ``192.168.0.0/16`` or ``[fe80::]/64``.
.. bro:type:: any .. bro:type:: any
@ -230,7 +232,7 @@ The Bro scripting language supports the following built-in types.
global a: table[count] of table[addr, port] of string; global a: table[count] of table[addr, port] of string;
which declared a table indexed by :bro:type:`count` and yielding which declares a table indexed by :bro:type:`count` and yielding
another :bro:type:`table` which is indexed by an :bro:type:`addr` another :bro:type:`table` which is indexed by an :bro:type:`addr`
and :bro:type:`port` to yield a :bro:type:`string`. and :bro:type:`port` to yield a :bro:type:`string`.
@ -392,7 +394,7 @@ The Bro scripting language supports the following built-in types.
:bro:attr:`&optional` or have a :bro:attr:`&default` attribute must :bro:attr:`&optional` or have a :bro:attr:`&default` attribute must
be specified. be specified.
To test for existence of field that is :bro:attr:`&optional`, use the To test for existence of a field that is :bro:attr:`&optional`, use the
``?$`` operator: ``?$`` operator:
.. code:: bro .. code:: bro
@ -412,7 +414,7 @@ The Bro scripting language supports the following built-in types.
print f, "hello, world"; print f, "hello, world";
close(f); close(f);
Writing to files like this for logging usually isn't recommend, for better Writing to files like this for logging usually isn't recommended, for better
logging support see :doc:`/logging`. logging support see :doc:`/logging`.
.. bro:type:: func .. bro:type:: func
@ -512,22 +514,22 @@ scripting language supports the following built-in attributes.
.. bro:attr:: &optional .. bro:attr:: &optional
Allows record field to be missing. For example the type ``record { Allows a record field to be missing. For example the type ``record {
a: int, b: port &optional }`` could be instantiated both as a: int, b: port &optional }`` could be instantiated both as
singleton ``[$a=127.0.0.1]`` or pair ``[$a=127.0.0.1, $b=80/tcp]``. singleton ``[$a=127.0.0.1]`` or pair ``[$a=127.0.0.1, $b=80/tcp]``.
.. bro:attr:: &default .. bro:attr:: &default
Uses a default value for a record field or container elements. For Uses a default value for a record field or container elements. For
example, ``table[int] of string &default="foo" }`` would create example, ``table[int] of string &default="foo" }`` would create a
table that returns The :bro:type:`string` ``"foo"`` for any table that returns the :bro:type:`string` ``"foo"`` for any
non-existing index. non-existing index.
.. bro:attr:: &redef .. bro:attr:: &redef
Allows for redefinition of initial object values. This is typically Allows for redefinition of initial object values. This is typically
used with constants, for example, ``const clever = T &redef;`` would used with constants, for example, ``const clever = T &redef;`` would
allow the constant to be redifined at some later point during script allow the constant to be redefined at some later point during script
execution. execution.
.. bro:attr:: &rotate_interval .. bro:attr:: &rotate_interval
@ -536,7 +538,7 @@ scripting language supports the following built-in attributes.
.. bro:attr:: &rotate_size .. bro:attr:: &rotate_size
Rotates af file after it has reached a given size in bytes. Rotates a file after it has reached a given size in bytes.
.. bro:attr:: &add_func .. bro:attr:: &add_func
@ -548,7 +550,12 @@ scripting language supports the following built-in attributes.
.. bro:attr:: &expire_func .. bro:attr:: &expire_func
Called right before a container element expires. 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 a :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 .. bro:attr:: &read_expire

View file

@ -46,6 +46,13 @@ type index_vec: vector of count;
## then remove this alias. ## then remove this alias.
type string_vec: vector of string; type string_vec: vector of string;
## A vector of addresses.
##
## .. 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 addr_vec: vector of addr;
## A table of strings indexed by strings. ## A table of strings indexed by strings.
## ##
## .. todo:: We need this type definition only for declaring builtin functions via ## .. todo:: We need this type definition only for declaring builtin functions via
@ -85,6 +92,8 @@ type icmp_conn: record {
itype: count; ##< The ICMP type of the packet that triggered the instantiation of the record. itype: count; ##< The ICMP type of the packet that triggered the instantiation of the record.
icode: count; ##< The ICMP code of the packet that triggered the instantiation of the record. icode: count; ##< The ICMP code of the packet that triggered the instantiation of the record.
len: count; ##< The length of the ICMP payload of the packet that triggered the instantiation of the record. len: count; ##< The length of the ICMP payload of the packet that triggered the instantiation of the record.
hlim: count; ##< The encapsulating IP header's Hop Limit value.
v6: bool; ##< True if it's an ICMPv6 packet.
}; };
## Packet context part of an ICMP message. The fields of this record reflect the ## Packet context part of an ICMP message. The fields of this record reflect the
@ -93,11 +102,13 @@ type icmp_conn: record {
## .. bro:see:: icmp_time_exceeded icmp_unreachable ## .. bro:see:: icmp_time_exceeded icmp_unreachable
type icmp_context: record { type icmp_context: record {
id: conn_id; ##< The packet's 4-tuple. id: conn_id; ##< The packet's 4-tuple.
len: count; ##< The lenght of the packet's IP header. len: count; ##< The length of the IP packet (headers + payload).
proto: count; ##< The packet's transport-layer protocol. proto: count; ##< The packet's transport-layer protocol.
frag_offset: count; ##< The packet's fragementation offset. frag_offset: count; ##< The packet's fragementation offset.
## True if the packet's IP header is fully included in the context. If that is not ## True if the packet's IP header is not fully included in the context
## the case, the other fields will all be set to null values. ## or if there is not enough of the transport header to determine source
## and destination ports. If that is the cast, the appropriate fields
## of this record will be set to null values.
bad_hdr_len: bool; bad_hdr_len: bool;
bad_checksum: bool; ##< True if the packet's IP checksum is not correct. bad_checksum: bool; ##< True if the packet's IP checksum is not correct.
MF: bool; ##< True if the packets *more fragements* flag is set. MF: bool; ##< True if the packets *more fragements* flag is set.
@ -601,10 +612,10 @@ function add_signature_file(sold: string, snew: string): string
} }
## Signature files to read. Use ``redef signature_files += "foo.sig"`` to ## Signature files to read. Use ``redef signature_files += "foo.sig"`` to
## extend. Signature files will be searched relative to ``BRO_PATH``. ## extend. Signature files will be searched relative to ``BROPATH``.
global signature_files = "" &add_func = add_signature_file; global signature_files = "" &add_func = add_signature_file;
## ``p0f`` fingerprint file to use. Will be searched relative to ``BRO_PATH``. ## ``p0f`` fingerprint file to use. Will be searched relative to ``BROPATH``.
const passive_fingerprint_file = "base/misc/p0f.fp" &redef; const passive_fingerprint_file = "base/misc/p0f.fp" &redef;
# TCP values for :bro:see:`endpoint` *state* field. # TCP values for :bro:see:`endpoint` *state* field.
@ -926,12 +937,319 @@ const IPPROTO_IGMP = 2; ##< Group management protocol.
const IPPROTO_IPIP = 4; ##< IP encapsulation in IP. const IPPROTO_IPIP = 4; ##< IP encapsulation in IP.
const IPPROTO_TCP = 6; ##< TCP. const IPPROTO_TCP = 6; ##< TCP.
const IPPROTO_UDP = 17; ##< User datagram protocol. const IPPROTO_UDP = 17; ##< User datagram protocol.
const IPPROTO_IPV6 = 41; ##< IPv6 header.
const IPPROTO_ICMPV6 = 58; ##< ICMP for IPv6.
const IPPROTO_RAW = 255; ##< Raw IP packet. const IPPROTO_RAW = 255; ##< Raw IP packet.
## Values extracted from an IP header. # Definitions for IPv6 extension headers.
const IPPROTO_HOPOPTS = 0; ##< IPv6 hop-by-hop-options header.
const IPPROTO_ROUTING = 43; ##< IPv6 routing header.
const IPPROTO_FRAGMENT = 44; ##< IPv6 fragment header.
const IPPROTO_ESP = 50; ##< IPv6 encapsulating security payload header.
const IPPROTO_AH = 51; ##< IPv6 authentication header.
const IPPROTO_NONE = 59; ##< IPv6 no next header.
const IPPROTO_DSTOPTS = 60; ##< IPv6 destination options header.
const IPPROTO_MOBILITY = 135; ##< IPv6 mobility header.
## Values extracted from an IPv6 extension header's (e.g. hop-by-hop or
## destination option headers) option field.
## ##
## .. bro:see:: pkt_hdr discarder_check_ip ## .. bro:see:: ip6_hdr ip6_hdr_chain ip6_hopopts ip6_dstopts
type ip_hdr: record { type ip6_option: record {
otype: count; ##< Option type.
len: count; ##< Option data length.
data: string; ##< Option data.
};
## Values extracted from an IPv6 Hop-by-Hop options extension header.
##
## .. bro:see:: pkt_hdr ip4_hdr ip6_hdr ip6_hdr_chain ip6_option
type ip6_hopopts: record {
## Protocol number of the next header (RFC 1700 et seq., IANA assigned
## number), e.g. :bro:id:`IPPROTO_ICMP`.
nxt: count;
## Length of header in 8-octet units, excluding first unit.
len: count;
## The TLV encoded options;
options: vector of ip6_option;
};
## Values extracted from an IPv6 Destination options extension header.
##
## .. bro:see:: pkt_hdr ip4_hdr ip6_hdr ip6_hdr_chain ip6_option
type ip6_dstopts: record {
## Protocol number of the next header (RFC 1700 et seq., IANA assigned
## number), e.g. :bro:id:`IPPROTO_ICMP`.
nxt: count;
## Length of header in 8-octet units, excluding first unit.
len: count;
## The TLV encoded options;
options: vector of ip6_option;
};
## Values extracted from an IPv6 Routing extension header.
##
## .. bro:see:: pkt_hdr ip4_hdr ip6_hdr ip6_hdr_chain
type ip6_routing: record {
## Protocol number of the next header (RFC 1700 et seq., IANA assigned
## number), e.g. :bro:id:`IPPROTO_ICMP`.
nxt: count;
## Length of header in 8-octet units, excluding first unit.
len: count;
## Routing type.
rtype: count;
## Segments left.
segleft: count;
## Type-specific data.
data: string;
};
## Values extracted from an IPv6 Fragment extension header.
##
## .. bro:see:: pkt_hdr ip4_hdr ip6_hdr ip6_hdr_chain
type ip6_fragment: record {
## Protocol number of the next header (RFC 1700 et seq., IANA assigned
## number), e.g. :bro:id:`IPPROTO_ICMP`.
nxt: count;
## 8-bit reserved field.
rsv1: count;
## Fragmentation offset.
offset: count;
## 2-bit reserved field.
rsv2: count;
## More fragments.
more: bool;
## Fragment identification.
id: count;
};
## Values extracted from an IPv6 Authentication extension header.
##
## .. bro:see:: pkt_hdr ip4_hdr ip6_hdr ip6_hdr_chain
type ip6_ah: record {
## Protocol number of the next header (RFC 1700 et seq., IANA assigned
## number), e.g. :bro:id:`IPPROTO_ICMP`.
nxt: count;
## Length of header in 4-octet units, excluding first two units.
len: count;
## Reserved field.
rsv: count;
## Security Parameter Index.
spi: count;
## Sequence number.
seq: count;
## Authentication data.
data: string;
};
## Values extracted from an IPv6 ESP extension header.
##
## .. bro:see:: pkt_hdr ip4_hdr ip6_hdr ip6_hdr_chain
type ip6_esp: record {
## Security Parameters Index.
spi: count;
## Sequence number.
seq: count;
};
## Values extracted from an IPv6 Mobility Binding Refresh Request message.
##
## .. bro:see:: ip6_mobility_hdr ip6_hdr ip6_hdr_chain ip6_mobility_msg
type ip6_mobility_brr: record {
## Reserved.
rsv: count;
## Mobility Options.
options: vector of ip6_option;
};
## Values extracted from an IPv6 Mobility Home Test Init message.
##
## .. bro:see:: ip6_mobility_hdr ip6_hdr ip6_hdr_chain ip6_mobility_msg
type ip6_mobility_hoti: record {
## Reserved.
rsv: count;
## Home Init Cookie.
cookie: count;
## Mobility Options.
options: vector of ip6_option;
};
## Values extracted from an IPv6 Mobility Care-of Test Init message.
##
## .. bro:see:: ip6_mobility_hdr ip6_hdr ip6_hdr_chain ip6_mobility_msg
type ip6_mobility_coti: record {
## Reserved.
rsv: count;
## Care-of Init Cookie.
cookie: count;
## Mobility Options.
options: vector of ip6_option;
};
## Values extracted from an IPv6 Mobility Home Test message.
##
## .. bro:see:: ip6_mobility_hdr ip6_hdr ip6_hdr_chain ip6_mobility_msg
type ip6_mobility_hot: record {
## Home Nonce Index.
nonce_idx: count;
## Home Init Cookie.
cookie: count;
## Home Keygen Token.
token: count;
## Mobility Options.
options: vector of ip6_option;
};
## Values extracted from an IPv6 Mobility Care-of Test message.
##
## .. bro:see:: ip6_mobility_hdr ip6_hdr ip6_hdr_chain ip6_mobility_msg
type ip6_mobility_cot: record {
## Care-of Nonce Index.
nonce_idx: count;
## Care-of Init Cookie.
cookie: count;
## Care-of Keygen Token.
token: count;
## Mobility Options.
options: vector of ip6_option;
};
## Values extracted from an IPv6 Mobility Binding Update message.
##
## .. bro:see:: ip6_mobility_hdr ip6_hdr ip6_hdr_chain ip6_mobility_msg
type ip6_mobility_bu: record {
## Sequence number.
seq: count;
## Acknowledge bit.
a: bool;
## Home Registration bit.
h: bool;
## Link-Local Address Compatibility bit.
l: bool;
## Key Management Mobility Capability bit.
k: bool;
## Lifetime.
life: count;
## Mobility Options.
options: vector of ip6_option;
};
## Values extracted from an IPv6 Mobility Binding Acknowledgement message.
##
## .. bro:see:: ip6_mobility_hdr ip6_hdr ip6_hdr_chain ip6_mobility_msg
type ip6_mobility_back: record {
## Status.
status: count;
## Key Management Mobility Capability.
k: bool;
## Sequence number.
seq: count;
## Lifetime.
life: count;
## Mobility Options.
options: vector of ip6_option;
};
## Values extracted from an IPv6 Mobility Binding Error message.
##
## .. bro:see:: ip6_mobility_hdr ip6_hdr ip6_hdr_chain ip6_mobility_msg
type ip6_mobility_be: record {
## Status.
status: count;
## Home Address.
hoa: addr;
## Mobility Options.
options: vector of ip6_option;
};
## Values extracted from an IPv6 Mobility header's message data.
##
## .. bro:see:: ip6_mobility_hdr ip6_hdr ip6_hdr_chain
type ip6_mobility_msg: record {
## The type of message from the header's MH Type field.
id: count;
## Binding Refresh Request.
brr: ip6_mobility_brr &optional;
## Home Test Init.
hoti: ip6_mobility_hoti &optional;
## Care-of Test Init.
coti: ip6_mobility_coti &optional;
## Home Test.
hot: ip6_mobility_hot &optional;
## Care-of Test.
cot: ip6_mobility_cot &optional;
## Binding Update.
bu: ip6_mobility_bu &optional;
## Binding Acknowledgement.
back: ip6_mobility_back &optional;
## Binding Error.
be: ip6_mobility_be &optional;
};
## Values extracted from an IPv6 Mobility header.
##
## .. bro:see:: pkt_hdr ip4_hdr ip6_hdr ip6_hdr_chain
type ip6_mobility_hdr: record {
## Protocol number of the next header (RFC 1700 et seq., IANA assigned
## number), e.g. :bro:id:`IPPROTO_ICMP`.
nxt: count;
## Length of header in 8-octet units, excluding first unit.
len: count;
## Mobility header type used to identify header's the message.
mh_type: count;
## Reserved field.
rsv: count;
## Mobility header checksum.
chksum: count;
## Mobility header message
msg: ip6_mobility_msg;
};
## A general container for a more specific IPv6 extension header.
##
## .. bro:see:: pkt_hdr ip4_hdr ip6_hopopts ip6_dstopts ip6_routing ip6_fragment
## ip6_ah ip6_esp
type ip6_ext_hdr: record {
## The RFC 1700 et seq. IANA assigned number identifying the type of
## the extension header.
id: count;
## Hop-by-hop option extension header.
hopopts: ip6_hopopts &optional;
## Destination option extension header.
dstopts: ip6_dstopts &optional;
## Routing extension header.
routing: ip6_routing &optional;
## Fragment header.
fragment: ip6_fragment &optional;
## Authentication extension header.
ah: ip6_ah &optional;
## Encapsulating security payload header.
esp: ip6_esp &optional;
## Mobility header.
mobility: ip6_mobility_hdr &optional;
};
## Values extracted from an IPv6 header.
##
## .. bro:see:: pkt_hdr ip4_hdr ip6_hdr_chain ip6_hopopts ip6_dstopts
## ip6_routing ip6_fragment ip6_ah ip6_esp
type ip6_hdr: record {
class: count; ##< Traffic class.
flow: count; ##< Flow label.
len: count; ##< Payload length.
nxt: count; ##< Protocol number of the next header
##< (RFC 1700 et seq., IANA assigned number)
##< e.g. :bro:id:`IPPROTO_ICMP`.
hlim: count; ##< Hop limit.
src: addr; ##< Source address.
dst: addr; ##< Destination address.
exts: vector of ip6_ext_hdr; ##< Extension header chain.
};
## Values extracted from an IPv4 header.
##
## .. bro:see:: pkt_hdr ip6_hdr discarder_check_ip
type ip4_hdr: record {
hl: count; ##< Header length in bytes. hl: count; ##< Header length in bytes.
tos: count; ##< Type of service. tos: count; ##< Type of service.
len: count; ##< Total length. len: count; ##< Total length.
@ -987,10 +1305,11 @@ type icmp_hdr: record {
## ##
## .. bro:see:: new_packet ## .. bro:see:: new_packet
type pkt_hdr: record { type pkt_hdr: record {
ip: ip_hdr; ##< The IP header. ip: ip4_hdr &optional; ##< The IPv4 header if an IPv4 packet.
tcp: tcp_hdr &optional; ##< The TCP header if a TCP packet. ip6: ip6_hdr &optional; ##< The IPv6 header if an IPv6 packet.
udp: udp_hdr &optional; ##< The UDP header if a UDP packet. tcp: tcp_hdr &optional; ##< The TCP header if a TCP packet.
icmp: icmp_hdr &optional; ##< The ICMP header if an ICMP packet. udp: udp_hdr &optional; ##< The UDP header if a UDP packet.
icmp: icmp_hdr &optional; ##< The ICMP header if an ICMP packet.
}; };
## Definition of "secondary filters". A secondary filter is a BPF filter given as ## Definition of "secondary filters". A secondary filter is a BPF filter given as
@ -1010,7 +1329,7 @@ global discarder_maxlen = 128 &redef;
## analysis. If the function signals to discard a packet, no further processing ## analysis. If the function signals to discard a packet, no further processing
## will be performed on it. ## will be performed on it.
## ##
## i: The IP header of the considered packet. ## p: The IP header of the considered packet.
## ##
## Returns: True if the packet should not be analyzed any further. ## Returns: True if the packet should not be analyzed any further.
## ##
@ -1019,15 +1338,15 @@ global discarder_maxlen = 128 &redef;
## ##
## .. note:: This is very low-level functionality and potentially expensive. ## .. note:: This is very low-level functionality and potentially expensive.
## Avoid using it. ## Avoid using it.
global discarder_check_ip: function(i: ip_hdr): bool; global discarder_check_ip: function(p: pkt_hdr): bool;
## Function for skipping packets based on their TCP header. If defined, this ## Function for skipping packets based on their TCP header. If defined, this
## function will be called for all TCP packets before Bro performs any further ## function will be called for all TCP packets before Bro performs any further
## analysis. If the function signals to discard a packet, no further processing ## analysis. If the function signals to discard a packet, no further processing
## will be performed on it. ## will be performed on it.
## ##
## i: The IP header of the considered packet. ## p: The IP and TCP headers of the considered packet.
## t: The TCP header. ##
## d: Up to :bro:see:`discarder_maxlen` bytes of the TCP payload. ## d: Up to :bro:see:`discarder_maxlen` bytes of the TCP payload.
## ##
## Returns: True if the packet should not be analyzed any further. ## Returns: True if the packet should not be analyzed any further.
@ -1037,15 +1356,15 @@ global discarder_check_ip: function(i: ip_hdr): bool;
## ##
## .. note:: This is very low-level functionality and potentially expensive. ## .. note:: This is very low-level functionality and potentially expensive.
## Avoid using it. ## Avoid using it.
global discarder_check_tcp: function(i: ip_hdr, t: tcp_hdr, d: string): bool; global discarder_check_tcp: function(p: pkt_hdr, d: string): bool;
## Function for skipping packets based on their UDP header. If defined, this ## Function for skipping packets based on their UDP header. If defined, this
## function will be called for all UDP packets before Bro performs any further ## function will be called for all UDP packets before Bro performs any further
## analysis. If the function signals to discard a packet, no further processing ## analysis. If the function signals to discard a packet, no further processing
## will be performed on it. ## will be performed on it.
## ##
## i: The IP header of the considered packet. ## p: The IP and UDP headers of the considered packet.
## t: The UDP header. ##
## d: Up to :bro:see:`discarder_maxlen` bytes of the UDP payload. ## d: Up to :bro:see:`discarder_maxlen` bytes of the UDP payload.
## ##
## Returns: True if the packet should not be analyzed any further. ## Returns: True if the packet should not be analyzed any further.
@ -1055,15 +1374,14 @@ global discarder_check_tcp: function(i: ip_hdr, t: tcp_hdr, d: string): bool;
## ##
## .. note:: This is very low-level functionality and potentially expensive. ## .. note:: This is very low-level functionality and potentially expensive.
## Avoid using it. ## Avoid using it.
global discarder_check_udp: function(i: ip_hdr, u: udp_hdr, d: string): bool; global discarder_check_udp: function(p: pkt_hdr, d: string): bool;
## Function for skipping packets based on their ICMP header. If defined, this ## Function for skipping packets based on their ICMP header. If defined, this
## function will be called for all ICMP packets before Bro performs any further ## function will be called for all ICMP packets before Bro performs any further
## analysis. If the function signals to discard a packet, no further processing ## analysis. If the function signals to discard a packet, no further processing
## will be performed on it. ## will be performed on it.
## ##
## i: The IP header of the considered packet. ## p: The IP and ICMP headers of the considered packet.
## ih: The ICMP header.
## ##
## Returns: True if the packet should not be analyzed any further. ## Returns: True if the packet should not be analyzed any further.
## ##
@ -1072,7 +1390,7 @@ global discarder_check_udp: function(i: ip_hdr, u: udp_hdr, d: string): bool;
## ##
## .. note:: This is very low-level functionality and potentially expensive. ## .. note:: This is very low-level functionality and potentially expensive.
## Avoid using it. ## Avoid using it.
global discarder_check_icmp: function(i: ip_hdr, ih: icmp_hdr): bool; global discarder_check_icmp: function(p: pkt_hdr): bool;
## Bro's watchdog interval. ## Bro's watchdog interval.
const watchdog_interval = 10 sec &redef; const watchdog_interval = 10 sec &redef;
@ -1706,13 +2024,6 @@ global dns_skip_all_addl = T &redef;
## traffic and do not process it. Set to 0 to turn off this functionality. ## traffic and do not process it. Set to 0 to turn off this functionality.
global dns_max_queries = 5; global dns_max_queries = 5;
## The maxiumum size in bytes for an SSL cipher specifcation. If we see a packet
## that has bigger cipherspecs, we won't do a comparisons of cipherspecs.
const ssl_max_cipherspec_size = 68 &redef;
# todo::Is this still used?
# type X509_extensions: table[count] of string;
## An X509 certificate. ## An X509 certificate.
## ##
## .. bro:see:: x509_certificate ## .. bro:see:: x509_certificate
@ -1725,10 +2036,6 @@ type X509: record {
not_valid_after: time; ##< Timestamp after when certificate is not valid. not_valid_after: time; ##< Timestamp after when certificate is not valid.
}; };
# This is indexed with the CA's name and yields a DER (binary) encoded certificate.
# todo::Is this still used?
# const root_ca_certs: table[string] of string = {} &redef;
## HTTP session statistics. ## HTTP session statistics.
## ##
## .. bro:see:: http_stats ## .. bro:see:: http_stats
@ -2146,26 +2453,6 @@ const forward_remote_state_changes = F &redef;
## Place-holder constant indicating "no peer". ## Place-holder constant indicating "no peer".
const PEER_ID_NONE = 0; const PEER_ID_NONE = 0;
## Deprecated.
##
## .. todo:: The connection compressor is scheduled to be removed from Bro.
const use_connection_compressor = F &redef;
## Deprecated.
##
## .. todo:: The connection compressor is scheduled to be removed from Bro.
const cc_handle_resets = F &redef;
## Deprecated.
##
## .. todo:: The connection compressor is scheduled to be removed from Bro.
const cc_handle_only_syns = T &redef;
## Deprecated.
##
## .. todo:: The connection compressor is scheduled to be removed from Bro.
const cc_instantiate_on_data = F &redef;
# Signature payload pattern types. # Signature payload pattern types.
# todo::use enum to help autodoc # todo::use enum to help autodoc
# todo::Still used? # todo::Still used?

View file

@ -40,8 +40,6 @@ export {
rcode: count &log &optional; rcode: count &log &optional;
## A descriptive name for the response code value. ## A descriptive name for the response code value.
rcode_name: string &log &optional; rcode_name: string &log &optional;
## Whether the message is a query (F) or response (T).
QR: bool &log &default=F;
## The Authoritative Answer bit for response messages specifies that ## The Authoritative Answer bit for response messages specifies that
## the responding name server is an authority for the domain name ## the responding name server is an authority for the domain name
## in the question section. ## in the question section.
@ -250,10 +248,13 @@ event dns_TXT_reply(c: connection, msg: dns_msg, ans: dns_answer, str: string) &
event DNS::do_reply(c, msg, ans, str); event DNS::do_reply(c, msg, ans, str);
} }
event dns_AAAA_reply(c: connection, msg: dns_msg, ans: dns_answer, a: addr, event dns_AAAA_reply(c: connection, msg: dns_msg, ans: dns_answer, a: addr) &priority=5
astr: string) &priority=5 {
event DNS::do_reply(c, msg, ans, fmt("%s", a));
}
event dns_A6_reply(c: connection, msg: dns_msg, ans: dns_answer, a: addr) &priority=5
{ {
# TODO: What should we do with astr?
event DNS::do_reply(c, msg, ans, fmt("%s", a)); event DNS::do_reply(c, msg, ans, fmt("%s", a));
} }

View file

@ -24,7 +24,7 @@ export {
const default_capture_password = F &redef; const default_capture_password = F &redef;
## User IDs that can be considered "anonymous". ## User IDs that can be considered "anonymous".
const guest_ids = { "anonymous", "ftp", "guest" } &redef; const guest_ids = { "anonymous", "ftp", "ftpuser", "guest" } &redef;
type Info: record { type Info: record {
## Time when the command was sent. ## Time when the command was sent.
@ -160,12 +160,21 @@ function ftp_message(s: Info)
# or it's a deliberately logged command. # or it's a deliberately logged command.
if ( |s$tags| > 0 || (s?$cmdarg && s$cmdarg$cmd in logged_commands) ) if ( |s$tags| > 0 || (s?$cmdarg && s$cmdarg$cmd in logged_commands) )
{ {
if ( s?$password && to_lower(s$user) !in guest_ids ) if ( s?$password &&
! s$capture_password &&
to_lower(s$user) !in guest_ids )
{
s$password = "<hidden>"; s$password = "<hidden>";
}
local arg = s$cmdarg$arg; local arg = s$cmdarg$arg;
if ( s$cmdarg$cmd in file_cmds ) if ( s$cmdarg$cmd in file_cmds )
arg = fmt("ftp://%s%s", s$id$resp_h, build_path_compressed(s$cwd, arg)); {
if ( is_v4_addr(s$id$resp_h) )
arg = fmt("ftp://%s%s", s$id$resp_h, build_path_compressed(s$cwd, arg));
else
arg = fmt("ftp://[%s]%s", s$id$resp_h, build_path_compressed(s$cwd, arg));
}
s$ts=s$cmdarg$ts; s$ts=s$cmdarg$ts;
s$command=s$cmdarg$cmd; s$command=s$cmdarg$cmd;
@ -270,7 +279,7 @@ event ftp_reply(c: connection, code: count, msg: string, cont_resp: bool) &prior
{ {
c$ftp$passive=T; c$ftp$passive=T;
if ( code == 229 && data$h == 0.0.0.0 ) if ( code == 229 && data$h == [::] )
data$h = id$resp_h; data$h = id$resp_h;
ftp_data_expected[data$h, data$p] = c$ftp; ftp_data_expected[data$h, data$p] = c$ftp;

View file

@ -13,7 +13,7 @@ export {
[TLSv10] = "TLSv10", [TLSv10] = "TLSv10",
[TLSv11] = "TLSv11", [TLSv11] = "TLSv11",
[TLSv12] = "TLSv12", [TLSv12] = "TLSv12",
} &default="UNKNOWN"; } &default=function(i: count):string { return fmt("unknown-%d", i); };
## Mapping between numeric codes and human readable strings for alert ## Mapping between numeric codes and human readable strings for alert
## levels. ## levels.
@ -77,7 +77,9 @@ export {
[12] = "srp", [12] = "srp",
[13] = "signature_algorithms", [13] = "signature_algorithms",
[14] = "use_srtp", [14] = "use_srtp",
[15] = "heartbeat",
[35] = "SessionTicket TLS", [35] = "SessionTicket TLS",
[40] = "extended_random",
[13172] = "next_protocol_negotiation", [13172] = "next_protocol_negotiation",
[65281] = "renegotiation_info" [65281] = "renegotiation_info"
} &default=function(i: count):string { return fmt("unknown-%d", i); }; } &default=function(i: count):string { return fmt("unknown-%d", i); };
@ -535,7 +537,7 @@ export {
[SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA] = "SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA", [SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA] = "SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA",
[SSL_RSA_FIPS_WITH_DES_CBC_SHA_2] = "SSL_RSA_FIPS_WITH_DES_CBC_SHA_2", [SSL_RSA_FIPS_WITH_DES_CBC_SHA_2] = "SSL_RSA_FIPS_WITH_DES_CBC_SHA_2",
[SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA_2] = "SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA_2", [SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA_2] = "SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA_2",
} &default="UNKNOWN"; } &default=function(i: count):string { return fmt("unknown-%d", i); };
## Mapping between the constants and string values for SSL/TLS errors. ## Mapping between the constants and string values for SSL/TLS errors.
const x509_errors: table[count] of string = { const x509_errors: table[count] of string = {
@ -573,6 +575,6 @@ export {
[31] = "keyusage no certsign", [31] = "keyusage no certsign",
[32] = "unable to get crl issuer", [32] = "unable to get crl issuer",
[33] = "unhandled critical extension", [33] = "unhandled critical extension",
}; } &default=function(i: count):string { return fmt("unknown-%d", i); };
} }

View file

@ -28,7 +28,7 @@ event signature_match(state: signature_state, msg: string, data: string) &priori
local c = state$conn; local c = state$conn;
local si = Software::Info; local si = Software::Info;
si = [$unparsed_version=msg, $host=c$id$resp_h, $host_p=c$id$resp_p, $software_type=WEB_APPLICATION]; si = [$name=msg, $unparsed_version=msg, $host=c$id$resp_h, $host_p=c$id$resp_p, $software_type=WEB_APPLICATION];
si$url = build_url_http(c$http); si$url = build_url_http(c$http);
if ( c$id$resp_h in Software::tracked && if ( c$id$resp_h in Software::tracked &&
si$name in Software::tracked[c$id$resp_h] ) si$name in Software::tracked[c$id$resp_h] )

View file

@ -17,7 +17,7 @@ ARP_Analyzer::~ARP_Analyzer()
{ {
} }
bool ARP_Analyzer::IsARP(const u_char* pkt, int hdr_size) const bool ARP_Analyzer::IsARP(const u_char* pkt, int hdr_size)
{ {
unsigned short network_protocol = unsigned short network_protocol =
*(unsigned short*) (pkt + hdr_size - 2); *(unsigned short*) (pkt + hdr_size - 2);

View file

@ -31,9 +31,6 @@ public:
ARP_Analyzer(); ARP_Analyzer();
virtual ~ARP_Analyzer(); virtual ~ARP_Analyzer();
// Whether a packet is of interest for ARP analysis.
bool IsARP(const u_char* pkt, int hdr_size) const;
void NextPacket(double t, const struct pcap_pkthdr* hdr, void NextPacket(double t, const struct pcap_pkthdr* hdr,
const u_char* const pkt, int hdr_size); const u_char* const pkt, int hdr_size);
@ -41,6 +38,10 @@ public:
void RREvent(EventHandlerPtr e, const u_char* src, const u_char* dst, void RREvent(EventHandlerPtr e, const u_char* src, const u_char* dst,
const char* spa, const char* sha, const char* spa, const char* sha,
const char* tpa, const char* tha); const char* tpa, const char* tha);
// Whether a packet is of interest for ARP analysis.
static bool IsARP(const u_char* pkt, int hdr_size);
protected: protected:
AddrVal* ConstructAddrVal(const void* addr); AddrVal* ConstructAddrVal(const void* addr);
StringVal* EthAddrToStr(const u_char* addr); StringVal* EthAddrToStr(const u_char* addr);

View file

@ -49,18 +49,6 @@ const Analyzer::Config Analyzer::analyzer_configs[] = {
{ AnalyzerTag::ICMP, "ICMP", ICMP_Analyzer::InstantiateAnalyzer, { AnalyzerTag::ICMP, "ICMP", ICMP_Analyzer::InstantiateAnalyzer,
ICMP_Analyzer::Available, 0, false }, ICMP_Analyzer::Available, 0, false },
{ AnalyzerTag::ICMP_TimeExceeded, "ICMP_TIMEEXCEEDED",
ICMP_TimeExceeded_Analyzer::InstantiateAnalyzer,
ICMP_TimeExceeded_Analyzer::Available, 0, false },
{ AnalyzerTag::ICMP_Unreachable, "ICMP_UNREACHABLE",
ICMP_Unreachable_Analyzer::InstantiateAnalyzer,
ICMP_Unreachable_Analyzer::Available, 0, false },
{ AnalyzerTag::ICMP_Echo, "ICMP_ECHO",
ICMP_Echo_Analyzer::InstantiateAnalyzer,
ICMP_Echo_Analyzer::Available, 0, false },
{ AnalyzerTag::ICMP_Redir, "ICMP_REDIR",
ICMP_Redir_Analyzer::InstantiateAnalyzer,
ICMP_Redir_Analyzer::Available, 0, false },
{ AnalyzerTag::TCP, "TCP", TCP_Analyzer::InstantiateAnalyzer, { AnalyzerTag::TCP, "TCP", TCP_Analyzer::InstantiateAnalyzer,
TCP_Analyzer::Available, 0, false }, TCP_Analyzer::Available, 0, false },

View file

@ -20,9 +20,7 @@ namespace AnalyzerTag {
PIA_TCP, PIA_UDP, PIA_TCP, PIA_UDP,
// Transport-layer analyzers. // Transport-layer analyzers.
ICMP, ICMP, TCP, UDP,
ICMP_TimeExceeded, ICMP_Unreachable, ICMP_Echo, ICMP_Redir,
TCP, UDP,
// Application-layer analyzers (hand-written). // Application-layer analyzers (hand-written).
BitTorrent, BitTorrentTracker, BitTorrent, BitTorrentTracker,

View file

@ -153,7 +153,9 @@ void AnonymizeIPAddr_A50::init()
int AnonymizeIPAddr_A50::PreservePrefix(ipaddr32_t input, int num_bits) int AnonymizeIPAddr_A50::PreservePrefix(ipaddr32_t input, int num_bits)
{ {
DEBUG_MSG("%s/%d\n", dotted_addr(input), num_bits); DEBUG_MSG("%s/%d\n",
IPAddr(IPv4, &input, IPAddr::Network).AsString().c_str(),
num_bits);
if ( ! before_anonymization ) if ( ! before_anonymization )
{ {

View file

@ -5,7 +5,7 @@
#include "Attr.h" #include "Attr.h"
#include "Expr.h" #include "Expr.h"
#include "Serializer.h" #include "Serializer.h"
#include "LogMgr.h" #include "threading/SerialTypes.h"
const char* attr_name(attr_tag t) const char* attr_name(attr_tag t)
{ {
@ -416,7 +416,7 @@ void Attributes::CheckAttr(Attr* a)
break; break;
case ATTR_LOG: case ATTR_LOG:
if ( ! LogVal::IsCompatibleType(type) ) if ( ! threading::Value::IsCompatibleType(type) )
Error("&log applied to a type that cannot be logged"); Error("&log applied to a type that cannot be logged");
break; break;

View file

@ -66,39 +66,44 @@ void BitTorrent_Analyzer::DeliverStream(int len, const u_char* data, bool orig)
void BitTorrent_Analyzer::Undelivered(int seq, int len, bool orig) void BitTorrent_Analyzer::Undelivered(int seq, int len, bool orig)
{ {
uint64 entry_offset = orig ?
*interp->upflow()->next_message_offset() :
*interp->downflow()->next_message_offset();
uint64& this_stream_len = orig ? stream_len_orig : stream_len_resp;
bool& this_stop = orig ? stop_orig : stop_resp;
TCP_ApplicationAnalyzer::Undelivered(seq, len, orig); TCP_ApplicationAnalyzer::Undelivered(seq, len, orig);
this_stream_len += len; // TODO: Code commented out for now. I think that shoving data that
// is definitely wrong into the parser seems like a really bad idea.
// The way it's currently tracking the next message offset isn't
// compatible with new 64bit int support in binpac either.
if ( entry_offset < this_stream_len ) //uint64 entry_offset = orig ?
{ // entry point is somewhere in the gap // *interp->upflow()->next_message_offset() :
DeliverWeird("Stopping BitTorrent analysis: cannot recover from content gap", orig); // *interp->downflow()->next_message_offset();
this_stop = true; //uint64& this_stream_len = orig ? stream_len_orig : stream_len_resp;
if ( stop_orig && stop_resp ) //bool& this_stop = orig ? stop_orig : stop_resp;
ProtocolViolation("BitTorrent: content gap and/or protocol violation"); //
} //this_stream_len += len;
else //
{ // fill the gap //if ( entry_offset < this_stream_len )
try // { // entry point is somewhere in the gap
{ // DeliverWeird("Stopping BitTorrent analysis: cannot recover from content gap", orig);
u_char gap[len]; // this_stop = true;
memset(gap, 0, len); // if ( stop_orig && stop_resp )
interp->NewData(orig, gap, gap + len); // ProtocolViolation("BitTorrent: content gap and/or protocol violation");
} // }
catch ( binpac::Exception const &e ) //else
{ // { // fill the gap
DeliverWeird("Stopping BitTorrent analysis: filling content gap failed", orig); // try
this_stop = true; // {
if ( stop_orig && stop_resp ) // u_char gap[len];
ProtocolViolation("BitTorrent: content gap and/or protocol violation"); // memset(gap, 0, len);
} // interp->NewData(orig, gap, gap + len);
} // }
// catch ( binpac::Exception const &e )
// {
// DeliverWeird("Stopping BitTorrent analysis: filling content gap failed", orig);
// this_stop = true;
// if ( stop_orig && stop_resp )
// ProtocolViolation("BitTorrent: content gap and/or protocol violation");
// }
// }
} }
void BitTorrent_Analyzer::EndpointEOF(TCP_Reassembler* endp) void BitTorrent_Analyzer::EndpointEOF(TCP_Reassembler* endp)

View file

@ -85,12 +85,13 @@ void BroDoc::AddImport(const std::string& s)
if ( ext_pos != std::string::npos ) if ( ext_pos != std::string::npos )
lname = lname.substr(0, ext_pos); lname = lname.substr(0, ext_pos);
const char* full_filename = "<error>"; const char* full_filename = NULL;
const char* subpath = "<error>"; const char* subpath = NULL;
FILE* f = search_for_file(lname.c_str(), "bro", &full_filename, true, FILE* f = search_for_file(lname.c_str(), "bro", &full_filename, true,
&subpath); &subpath);
if ( f ) if ( f && full_filename && subpath )
{ {
fclose(f); fclose(f);
@ -126,12 +127,14 @@ void BroDoc::AddImport(const std::string& s)
} }
delete [] tmp; delete [] tmp;
delete [] full_filename;
delete [] subpath;
} }
else else
fprintf(stderr, "Failed to document '@load %s' in file: %s\n", fprintf(stderr, "Failed to document '@load %s' in file: %s\n",
s.c_str(), reST_filename.c_str()); s.c_str(), reST_filename.c_str());
delete [] full_filename;
delete [] subpath;
} }
void BroDoc::SetPacketFilter(const std::string& s) void BroDoc::SetPacketFilter(const std::string& s)

View file

@ -1,11 +1,12 @@
#include <cstdio> #include <cstdio>
#include <cstring>
#include <utility> #include <utility>
#include <algorithm> #include <algorithm>
#include "Brofiler.h" #include "Brofiler.h"
#include "util.h" #include "util.h"
Brofiler::Brofiler() Brofiler::Brofiler()
: delim('\t'), ignoring(0) : ignoring(0), delim('\t')
{ {
} }
@ -48,10 +49,27 @@ bool Brofiler::WriteStats()
char* bf = getenv("BRO_PROFILER_FILE"); char* bf = getenv("BRO_PROFILER_FILE");
if ( ! bf ) return false; if ( ! bf ) return false;
FILE* f = fopen(bf, "w"); FILE* f;
const char* p = strstr(bf, ".XXXXXX");
if ( p && ! p[7] )
{
int fd = mkstemp(bf);
if ( fd == -1 )
{
reporter->Error("Failed to generate unique file name from BRO_PROFILER_FILE: %s", bf);
return false;
}
f = fdopen(fd, "w");
}
else
{
f = fopen(bf, "w");
}
if ( ! f ) if ( ! f )
{ {
reporter->Error("Failed to open BRO_PROFILER_FILE destination '%s' for writing\n", bf); reporter->Error("Failed to open BRO_PROFILER_FILE destination '%s' for writing", bf);
return false; return false;
} }

View file

@ -26,7 +26,9 @@ public:
/** /**
* Combines usage stats from current run with any read from ReadStats(), * Combines usage stats from current run with any read from ReadStats(),
* then writes information to file pointed to by environment variable * then writes information to file pointed to by environment variable
* BRO_PROFILER_FILE. * BRO_PROFILER_FILE. If the value of that env. variable ends with
* ".XXXXXX" (exactly 6 X's), then it is first passed through mkstemp
* to get a unique file.
* *
* @return: true when usage info is written, otherwise false. * @return: true when usage info is written, otherwise false.
*/ */

View file

@ -213,6 +213,8 @@ binpac_target(syslog.pac
######################################################################## ########################################################################
## bro target ## bro target
find_package (Threads)
# This macro stores associated headers for any C/C++ source files given # This macro stores associated headers for any C/C++ source files given
# as arguments (past _var) as a list in the CMake variable named "_var". # as arguments (past _var) as a list in the CMake variable named "_var".
macro(COLLECT_HEADERS _var) macro(COLLECT_HEADERS _var)
@ -288,7 +290,6 @@ set(bro_SRCS
ChunkedIO.cc ChunkedIO.cc
CompHash.cc CompHash.cc
Conn.cc Conn.cc
ConnCompressor.cc
ConnSizeAnalyzer.cc ConnSizeAnalyzer.cc
ContentLine.cc ContentLine.cc
DCE_RPC.cc DCE_RPC.cc
@ -331,13 +332,11 @@ set(bro_SRCS
IntSet.cc IntSet.cc
InterConn.cc InterConn.cc
IOSource.cc IOSource.cc
IP.cc
IPAddr.cc
IRC.cc IRC.cc
List.cc List.cc
Reporter.cc Reporter.cc
LogMgr.cc
LogWriter.cc
LogWriterAscii.cc
LogWriterNone.cc
Login.cc Login.cc
MIME.cc MIME.cc
NCP.cc NCP.cc
@ -402,6 +401,7 @@ set(bro_SRCS
XDR.cc XDR.cc
ZIP.cc ZIP.cc
bsd-getopt-long.c bsd-getopt-long.c
bro_inet_ntop.c
cq.c cq.c
md5.c md5.c
patricia.c patricia.c
@ -409,6 +409,18 @@ set(bro_SRCS
PacketDumper.cc PacketDumper.cc
strsep.c strsep.c
modp_numtoa.c modp_numtoa.c
threading/BasicThread.cc
threading/Manager.cc
threading/MsgThread.cc
threading/SerialTypes.cc
logging/Manager.cc
logging/WriterBackend.cc
logging/WriterFrontend.cc
logging/writers/Ascii.cc
logging/writers/None.cc
${dns_SRCS} ${dns_SRCS}
${openssl_SRCS} ${openssl_SRCS}
) )
@ -421,7 +433,7 @@ add_definitions(-DBRO_BUILD_PATH="${CMAKE_CURRENT_BINARY_DIR}")
add_executable(bro ${bro_SRCS} ${bro_HEADERS}) add_executable(bro ${bro_SRCS} ${bro_HEADERS})
target_link_libraries(bro ${brodeps}) target_link_libraries(bro ${brodeps} ${CMAKE_THREAD_LIBS_INIT})
install(TARGETS bro DESTINATION bin) install(TARGETS bro DESTINATION bin)
install(FILES ${INSTALL_BIF_OUTPUTS} DESTINATION ${BRO_SCRIPT_INSTALL_PATH}/base) install(FILES ${INSTALL_BIF_OUTPUTS} DESTINATION ${BRO_SCRIPT_INSTALL_PATH}/base)

View file

@ -107,40 +107,18 @@ char* CompositeHash::SingleValHash(int type_check, char* kp0,
case TYPE_INTERNAL_ADDR: case TYPE_INTERNAL_ADDR:
{ {
// Use uint32 instead of int, because 'int' is not
// guaranteed to be 32-bit.
uint32* kp = AlignAndPadType<uint32>(kp0); uint32* kp = AlignAndPadType<uint32>(kp0);
#ifdef BROv6 v->AsAddr().CopyIPv6(kp);
const addr_type av = v->AsAddr();
kp[0] = av[0];
kp[1] = av[1];
kp[2] = av[2];
kp[3] = av[3];
kp1 = reinterpret_cast<char*>(kp+4); kp1 = reinterpret_cast<char*>(kp+4);
#else
*kp = v->AsAddr();
kp1 = reinterpret_cast<char*>(kp+1);
#endif
} }
break; break;
case TYPE_INTERNAL_SUBNET: case TYPE_INTERNAL_SUBNET:
{ {
uint32* kp = AlignAndPadType<uint32>(kp0); uint32* kp = AlignAndPadType<uint32>(kp0);
#ifdef BROv6 v->AsSubNet().Prefix().CopyIPv6(kp);
const subnet_type* sv = v->AsSubNet(); kp[4] = v->AsSubNet().Length();
kp[0] = sv->net[0];
kp[1] = sv->net[1];
kp[2] = sv->net[2];
kp[3] = sv->net[3];
kp[4] = sv->width;
kp1 = reinterpret_cast<char*>(kp+5); kp1 = reinterpret_cast<char*>(kp+5);
#else
const subnet_type* sv = v->AsSubNet();
kp[0] = sv->net;
kp[1] = sv->width;
kp1 = reinterpret_cast<char*>(kp+2);
#endif
} }
break; break;
@ -358,26 +336,16 @@ HashKey* CompositeHash::ComputeSingletonHash(const Val* v, int type_check) const
if ( type_check && v->Type()->InternalType() != singleton_tag ) if ( type_check && v->Type()->InternalType() != singleton_tag )
return 0; return 0;
uint32 tmp_addr;
switch ( singleton_tag ) { switch ( singleton_tag ) {
case TYPE_INTERNAL_INT: case TYPE_INTERNAL_INT:
case TYPE_INTERNAL_UNSIGNED: case TYPE_INTERNAL_UNSIGNED:
return new HashKey(v->ForceAsInt()); return new HashKey(v->ForceAsInt());
case TYPE_INTERNAL_ADDR: case TYPE_INTERNAL_ADDR:
#ifdef BROv6 return v->AsAddr().GetHashKey();
return new HashKey(v->AsAddr(), 4);
#else
return new HashKey(v->AsAddr());
#endif
case TYPE_INTERNAL_SUBNET: case TYPE_INTERNAL_SUBNET:
#ifdef BROv6 return v->AsSubNet().GetHashKey();
return new HashKey((const uint32*) v->AsSubNet(), 5);
#else
return new HashKey((const uint32*) v->AsSubNet(), 2);
#endif
case TYPE_INTERNAL_DOUBLE: case TYPE_INTERNAL_DOUBLE:
return new HashKey(v->InternalDouble()); return new HashKey(v->InternalDouble());
@ -425,22 +393,13 @@ int CompositeHash::SingleTypeKeySize(BroType* bt, const Val* v,
break; break;
case TYPE_INTERNAL_ADDR: case TYPE_INTERNAL_ADDR:
#ifdef BROv6
sz = SizeAlign(sz, sizeof(uint32)); sz = SizeAlign(sz, sizeof(uint32));
sz += sizeof(uint32) * 3; // to make a total of 4 words sz += sizeof(uint32) * 3; // to make a total of 4 words
#else
sz = SizeAlign(sz, sizeof(uint32));
#endif
break; break;
case TYPE_INTERNAL_SUBNET: case TYPE_INTERNAL_SUBNET:
#ifdef BROv6
sz = SizeAlign(sz, sizeof(uint32)); sz = SizeAlign(sz, sizeof(uint32));
sz += sizeof(uint32) * 4; // to make a total of 5 words sz += sizeof(uint32) * 4; // to make a total of 5 words
#else
sz = SizeAlign(sz, sizeof(uint32));
sz += sizeof(uint32); // make room for width
#endif
break; break;
case TYPE_INTERNAL_DOUBLE: case TYPE_INTERNAL_DOUBLE:
@ -748,16 +707,13 @@ const char* CompositeHash::RecoverOneVal(const HashKey* k, const char* kp0,
case TYPE_INTERNAL_ADDR: case TYPE_INTERNAL_ADDR:
{ {
const uint32* const kp = AlignType<uint32>(kp0); const uint32* const kp = AlignType<uint32>(kp0);
#ifdef BROv6
const_addr_type addr_val = kp;
kp1 = reinterpret_cast<const char*>(kp+4); kp1 = reinterpret_cast<const char*>(kp+4);
#else
const_addr_type addr_val = *kp; IPAddr addr(IPv6, kp, IPAddr::Network);
kp1 = reinterpret_cast<const char*>(kp+1);
#endif
switch ( tag ) { switch ( tag ) {
case TYPE_ADDR: case TYPE_ADDR:
pval = new AddrVal(addr_val); pval = new AddrVal(addr);
break; break;
default: default:
@ -770,12 +726,9 @@ const char* CompositeHash::RecoverOneVal(const HashKey* k, const char* kp0,
case TYPE_INTERNAL_SUBNET: case TYPE_INTERNAL_SUBNET:
{ {
const subnet_type* const kp = const uint32* const kp = AlignType<uint32>(kp0);
reinterpret_cast<const subnet_type*>( kp1 = reinterpret_cast<const char*>(kp+5);
AlignType<uint32>(kp0)); pval = new SubNetVal(kp, kp[4]);
kp1 = reinterpret_cast<const char*>(kp+1);
pval = new SubNetVal(kp->net, kp->width);
} }
break; break;

View file

@ -14,32 +14,6 @@
#include "PIA.h" #include "PIA.h"
#include "binpac.h" #include "binpac.h"
HashKey* ConnID::BuildConnKey() const
{
Key key;
// Lookup up connection based on canonical ordering, which is
// the smaller of <src addr, src port> and <dst addr, dst port>
// followed by the other.
if ( is_one_way ||
addr_port_canon_lt(src_addr, src_port, dst_addr, dst_port) )
{
copy_addr(src_addr, key.ip1);
copy_addr(dst_addr, key.ip2);
key.port1 = src_port;
key.port2 = dst_port;
}
else
{
copy_addr(dst_addr, key.ip1);
copy_addr(src_addr, key.ip2);
key.port1 = dst_port;
key.port2 = src_port;
}
return new HashKey(&key, sizeof(key));
}
void ConnectionTimer::Init(Connection* arg_conn, timer_func arg_timer, void ConnectionTimer::Init(Connection* arg_conn, timer_func arg_timer,
int arg_do_expire) int arg_do_expire)
{ {
@ -143,8 +117,8 @@ Connection::Connection(NetSessions* s, HashKey* k, double t, const ConnID* id)
key = k; key = k;
start_time = last_time = t; start_time = last_time = t;
copy_addr(id->src_addr, orig_addr); orig_addr = id->src_addr;
copy_addr(id->dst_addr, resp_addr); resp_addr = id->dst_addr;
orig_port = id->src_port; orig_port = id->src_port;
resp_port = id->dst_port; resp_port = id->dst_port;
proto = TRANSPORT_UNKNOWN; proto = TRANSPORT_UNKNOWN;
@ -521,7 +495,7 @@ Val* Connection::BuildVersionVal(const char* s, int len)
return sw; return sw;
} }
int Connection::VersionFoundEvent(const uint32* addr, const char* s, int len, int Connection::VersionFoundEvent(const IPAddr& addr, const char* s, int len,
Analyzer* analyzer) Analyzer* analyzer)
{ {
if ( ! software_version_found && ! software_parse_error ) if ( ! software_version_found && ! software_parse_error )
@ -559,7 +533,7 @@ int Connection::VersionFoundEvent(const uint32* addr, const char* s, int len,
return 1; return 1;
} }
int Connection::UnparsedVersionFoundEvent(const uint32* addr, int Connection::UnparsedVersionFoundEvent(const IPAddr& addr,
const char* full, int len, Analyzer* analyzer) const char* full, int len, Analyzer* analyzer)
{ {
// Skip leading white space. // Skip leading white space.
@ -693,10 +667,9 @@ TimerMgr* Connection::GetTimerMgr() const
void Connection::FlipRoles() void Connection::FlipRoles()
{ {
uint32 tmp_addr[NUM_ADDR_WORDS]; IPAddr tmp_addr = resp_addr;
copy_addr(resp_addr, tmp_addr); orig_addr = resp_addr;
copy_addr(orig_addr, resp_addr); resp_addr = tmp_addr;
copy_addr(tmp_addr, orig_addr);
uint32 tmp_port = resp_port; uint32 tmp_port = resp_port;
resp_port = orig_port; resp_port = orig_port;
@ -752,14 +725,14 @@ void Connection::Describe(ODesc* d) const
} }
d->SP(); d->SP();
d->Add(dotted_addr(orig_addr)); d->Add(orig_addr);
d->Add(":"); d->Add(":");
d->Add(ntohs(orig_port)); d->Add(ntohs(orig_port));
d->SP(); d->SP();
d->AddSP("->"); d->AddSP("->");
d->Add(dotted_addr(resp_addr)); d->Add(resp_addr);
d->Add(":"); d->Add(":");
d->Add(ntohs(resp_port)); d->Add(ntohs(resp_port));
@ -782,9 +755,8 @@ bool Connection::DoSerialize(SerialInfo* info) const
// First we write the members which are needed to // First we write the members which are needed to
// create the HashKey. // create the HashKey.
for ( int j = 0; j < NUM_ADDR_WORDS; ++j ) if ( ! SERIALIZE(orig_addr) || ! SERIALIZE(resp_addr) )
if ( ! SERIALIZE(orig_addr[j]) || ! SERIALIZE(resp_addr[j]) ) return false;
return false;
if ( ! SERIALIZE(orig_port) || ! SERIALIZE(resp_port) ) if ( ! SERIALIZE(orig_port) || ! SERIALIZE(resp_port) )
return false; return false;
@ -830,21 +802,21 @@ bool Connection::DoUnserialize(UnserialInfo* info)
// Build the hash key first. Some of the recursive *::Unserialize() // Build the hash key first. Some of the recursive *::Unserialize()
// functions may need it. // functions may need it.
for ( int i = 0; i < NUM_ADDR_WORDS; ++i ) ConnID id;
if ( ! UNSERIALIZE(&orig_addr[i]) || ! UNSERIALIZE(&resp_addr[i]) )
goto error; if ( ! UNSERIALIZE(&orig_addr) || ! UNSERIALIZE(&resp_addr) )
goto error;
if ( ! UNSERIALIZE(&orig_port) || ! UNSERIALIZE(&resp_port) ) if ( ! UNSERIALIZE(&orig_port) || ! UNSERIALIZE(&resp_port) )
goto error; goto error;
ConnID id;
id.src_addr = orig_addr; id.src_addr = orig_addr;
id.dst_addr = resp_addr; id.dst_addr = resp_addr;
// This doesn't work for ICMP. But I guess this is not really important. // This doesn't work for ICMP. But I guess this is not really important.
id.src_port = orig_port; id.src_port = orig_port;
id.dst_port = resp_port; id.dst_port = resp_port;
id.is_one_way = 0; // ### incorrect for ICMP id.is_one_way = 0; // ### incorrect for ICMP
key = id.BuildConnKey(); key = BuildConnIDHashKey(id);
int len; int len;
if ( ! UNSERIALIZE(&len) ) if ( ! UNSERIALIZE(&len) )

View file

@ -12,6 +12,7 @@
#include "PersistenceSerializer.h" #include "PersistenceSerializer.h"
#include "RuleMatcher.h" #include "RuleMatcher.h"
#include "AnalyzerTags.h" #include "AnalyzerTags.h"
#include "IPAddr.h"
class Connection; class Connection;
class ConnectionTimer; class ConnectionTimer;
@ -32,52 +33,17 @@ typedef enum {
typedef void (Connection::*timer_func)(double t); typedef void (Connection::*timer_func)(double t);
struct ConnID { struct ConnID {
const uint32* src_addr; IPAddr src_addr;
const uint32* dst_addr; IPAddr dst_addr;
uint32 src_port; uint32 src_port;
uint32 dst_port; uint32 dst_port;
bool is_one_way; // if true, don't canonicalize bool is_one_way; // if true, don't canonicalize order
// Returns a ListVal suitable for looking up a connection in
// a hash table. addr/ports are expected to be in network order.
// Unless is_one_way is true, the lookup sorts src and dst,
// so src_addr/src_port and dst_addr/dst_port just have to
// reflect the two different sides of the connection,
// neither has to be the particular source/destination
// or originator/responder.
HashKey* BuildConnKey() const;
// The structure used internally for hashing.
struct Key {
uint32 ip1[NUM_ADDR_WORDS];
uint32 ip2[NUM_ADDR_WORDS];
uint16 port1;
uint16 port2;
};
}; };
static inline int addr_port_canon_lt(const uint32* a1, uint32 p1, static inline int addr_port_canon_lt(const IPAddr& addr1, uint32 p1,
const uint32* a2, uint32 p2) const IPAddr& addr2, uint32 p2)
{ {
#ifdef BROv6 return addr1 < addr2 || (addr1 == addr2 && p1 < p2);
// Because it's a canonical ordering, not a strict ordering,
// we can choose to give more weight to the least significant
// word than to the most significant word. This matters
// because for the common case of IPv4 addresses embedded in
// a IPv6 address, the top three words are identical, so we can
// save a few cycles by first testing the bottom word.
return a1[3] < a2[3] ||
(a1[3] == a2[3] &&
(a1[2] < a2[2] ||
(a1[2] == a2[2] &&
(a1[1] < a2[1] ||
(a1[1] == a2[1] &&
(a1[0] < a2[0] ||
(a1[0] == a2[0] &&
p1 < p2)))))));
#else
return *a1 < *a2 || (*a1 == *a2 && p1 < p2);
#endif
} }
class Analyzer; class Analyzer;
@ -119,8 +85,8 @@ public:
double LastTime() const { return last_time; } double LastTime() const { return last_time; }
void SetLastTime(double t) { last_time = t; } void SetLastTime(double t) { last_time = t; }
const uint32* OrigAddr() const { return orig_addr; } const IPAddr& OrigAddr() const { return orig_addr; }
const uint32* RespAddr() const { return resp_addr; } const IPAddr& RespAddr() const { return resp_addr; }
uint32 OrigPort() const { return orig_port; } uint32 OrigPort() const { return orig_port; }
uint32 RespPort() const { return resp_port; } uint32 RespPort() const { return resp_port; }
@ -185,11 +151,11 @@ public:
// Raises a software_version_found event based on the // Raises a software_version_found event based on the
// given string (returns false if it's not parseable). // given string (returns false if it's not parseable).
int VersionFoundEvent(const uint32* addr, const char* s, int len, int VersionFoundEvent(const IPAddr& addr, const char* s, int len,
Analyzer* analyzer = 0); Analyzer* analyzer = 0);
// Raises a software_unparsed_version_found event. // Raises a software_unparsed_version_found event.
int UnparsedVersionFoundEvent(const uint32* addr, int UnparsedVersionFoundEvent(const IPAddr& addr,
const char* full_descr, int len, Analyzer* analyzer); const char* full_descr, int len, Analyzer* analyzer);
void Event(EventHandlerPtr f, Analyzer* analyzer, const char* name = 0); void Event(EventHandlerPtr f, Analyzer* analyzer, const char* name = 0);
@ -273,30 +239,6 @@ public:
// Sets the transport protocol in use. // Sets the transport protocol in use.
void SetTransport(TransportProto arg_proto) { proto = arg_proto; } void SetTransport(TransportProto arg_proto) { proto = arg_proto; }
// If the connection compressor is activated, we need a special memory
// layout for connections. (See ConnCompressor.h)
void* operator new(size_t size)
{
if ( ! use_connection_compressor )
return ::operator new(size);
void* c = ::operator new(size + 4);
// We have to turn off the is_pending bit. By setting the
// first four bytes to zero, we'll achieve this.
*((uint32*) c) = 0;
return ((char *) c) + 4;
}
void operator delete(void* ptr)
{
if ( ! use_connection_compressor )
::operator delete(ptr);
else
::operator delete(((char*) ptr) - 4);
}
void SetUID(uint64 arg_uid) { uid = arg_uid; } void SetUID(uint64 arg_uid) { uid = arg_uid; }
protected: protected:
@ -325,8 +267,8 @@ protected:
TimerMgr::Tag* conn_timer_mgr; TimerMgr::Tag* conn_timer_mgr;
timer_list timers; timer_list timers;
uint32 orig_addr[NUM_ADDR_WORDS]; // in network order IPAddr orig_addr;
uint32 resp_addr[NUM_ADDR_WORDS]; // in network order IPAddr resp_addr;
uint32 orig_port, resp_port; // in network order uint32 orig_port, resp_port; // in network order
TransportProto proto; TransportProto proto;
double start_time, last_time; double start_time, last_time;

File diff suppressed because it is too large Load diff

View file

@ -1,235 +0,0 @@
// The ConnCompressor keeps track of the first packet seen for a conn_id using
// only a minimal amount of memory. This helps us to avoid instantiating
// full Connection objects for never-established sessions.
//
// TCP only.
#ifndef CONNCOMPRESSOR_H
#define CONNCOMPRESSOR_H
#include "Conn.h"
#include "Dict.h"
#include "NetVar.h"
#include "TCP.h"
class ConnCompressor {
public:
ConnCompressor();
~ConnCompressor();
// Handle next packet. Returns 0 if packet in handled internally.
// Takes ownership of key.
Connection* NextPacket(double t, HashKey* k, const IP_Hdr* ip_hdr,
const struct pcap_pkthdr* hdr, const u_char* const pkt);
// Look up a connection. Returns non-nil for connections for
// which a Connection object has already been instantiated.
Connection* Lookup(HashKey* k)
{
ConnData* c = conns.Lookup(k);
return c && IsConnPtr(c) ? MakeConnPtr(c) : 0;
}
// Inserts connection into compressor. If another entry with this key
// already exists, it's replaced. If that was a full connection, it is
// also returned.
Connection* Insert(Connection* c);
// Remove all state belonging to the given connection. Returns
// true if the connection was found in the compressor's table,
// false if not.
bool Remove(HashKey* k);
// Flush state.
void Drain();
struct Sizes {
// Current number of already fully instantiated connections.
unsigned int connections;
// Total number of fully instantiated connections.
unsigned int connections_total;
// Current number of seen but non-yet instantiated connections.
unsigned int pending_valid;
// Total number of seen but non-yet instantiated connections.
unsigned int pending_total;
// Total number of all entries in pending list (some a which
// may already been invalid, but not yet removed from memory).
unsigned int pending_in_mem;
// Total number of hash table entires
// (should equal connections + pending_valid)
unsigned int hash_table_size;
// Total memory usage;
unsigned int memory;
};
const Sizes& Size()
{ sizes.hash_table_size = conns.Length(); return sizes; }
unsigned int MemoryAllocation() const { return sizes.memory; }
// As long as we have only seen packets from one side, we just
// store a PendingConn.
struct PendingConn {
// True if the block is indeed a PendingConn (see below).
unsigned int is_pending:1;
// Whether roles in key are flipped.
unsigned int ip1_is_src:1;
unsigned int invalid:1; // deleted
int window_scale:4;
unsigned int SYN:1;
unsigned int FIN:1;
unsigned int RST:1;
unsigned int ACK:1;
double time;
ConnID::Key key;
uint32 seq;
uint32 ack;
hash_t hash;
uint16 window;
uint64 uid;
// The following are set if use_conn_size_analyzer is T.
uint16 num_pkts;
uint16 num_bytes_ip;
};
private:
// Helpers to extract addrs/ports from PendingConn.
const uint32* SrcAddr(const PendingConn* c)
{ return c->ip1_is_src ? c->key.ip1 : c->key.ip2; }
const uint32* DstAddr(const PendingConn* c)
{ return c->ip1_is_src ? c->key.ip2 : c->key.ip1; }
uint16 SrcPort(const PendingConn* c)
{ return c->ip1_is_src ? c->key.port1 : c->key.port2; }
uint16 DstPort(const PendingConn* c)
{ return c->ip1_is_src ? c->key.port2 : c->key.port1; }
// Called for the first packet in a connection.
Connection* FirstFromOrig(double t, HashKey* key,
const IP_Hdr* ip, const tcphdr* tp);
// Called for more packets from the orginator w/o seeing a response.
Connection* NextFromOrig(PendingConn* pending, double t, HashKey* key,
const IP_Hdr* ip, const tcphdr* tp);
// Called for the first response packet. Instantiates a Connection.
Connection* Response(PendingConn* pending, double t, HashKey* key,
const IP_Hdr* ip, const tcphdr* tp);
// Instantiates a full TCP connection (invalidates pending connection).
Connection* Instantiate(HashKey* key, PendingConn* pending);
// Same but based on packet.
Connection* Instantiate(double t, HashKey* key, const IP_Hdr* ip);
// Fills the attributes of a PendingConn based on the given arguments.
void PktHdrToPendingConn(double time, const HashKey* key,
const IP_Hdr* ip, const struct tcphdr* tp, PendingConn* c);
// Fakes a TCP packet based on the available information.
const IP_Hdr* PendingConnToPacket(const PendingConn* c);
// Construct a TCP-flags byte.
uint8 MakeFlags(const PendingConn* c) const;
// Allocate room for a new (Ext)PendingConn.
PendingConn* MakeNewState(double t);
// Expire PendingConns.
void DoExpire(double t);
// Remove all state belonging to the given connection.
void Invalidate(HashKey* k);
// Sends the given connection_* event. If orig_state is
// TCP_ENDPOINT__INACTIVE, tries to guess a better one based
// on pending. If arg in non-nil, it will be used as the
// *first* argument of the event call (this is for conn_weird()).
void Event(const PendingConn* pending, double t,
const EventHandlerPtr& event, int orig_state,
int orig_size, int resp_state, Val* arg = 0);
void Weird(const PendingConn* pending, double t, const char* msg)
{
// This will actually go through the Reporter; Event() takes
// care of that.
Event(pending, t, conn_weird, TCP_ENDPOINT_INACTIVE, 0,
TCP_ENDPOINT_INACTIVE, new StringVal(msg));
}
static const int BLOCK_SIZE = 16 * 1024;
// The memory managment for PendConns.
struct Block {
double time;
Block* prev;
Block* next;
int bytes_used;
unsigned char data[BLOCK_SIZE];
};
// In the connection hash table, we store pointers to both PendingConns
// and Connections. Thus, we need a way to differentiate between
// these two types. To avoid an additional indirection, we use a little
// hack: a pointer retrieved from the table is interpreted as a
// PendingConn first. However, if is_pending is false, it's in fact a
// Connection which starts at offset 4. The methods below help to
// implement this scheme transparently. An "operator new" in
// Connection takes care of building Connection's accordingly.
typedef PendingConn ConnData;
declare(PDict, ConnData);
typedef PDict(ConnData) ConnMap;
ConnMap conns;
static ConnData* MakeMapPtr(PendingConn* c)
{ assert(c->is_pending); return c; }
static ConnData* MakeMapPtr(Connection* c)
{
ConnData* p = (ConnData*) (((char*) c) - 4);
assert(!p->is_pending);
return p;
}
static PendingConn* MakePendingConnPtr(ConnData* c)
{ assert(c->is_pending); return c; }
static Connection* MakeConnPtr(ConnData* c)
{
assert(!c->is_pending);
return (Connection*) (((char*) c) + 4);
}
static bool IsConnPtr(ConnData* c)
{ return ! c->is_pending; }
// New blocks are inserted at the end.
Block* first_block;
Block* last_block;
// If we have already expired some entries in a block,
// this points to the first non-expired.
unsigned char* first_non_expired;
// Last "connection" that we have build.
RecordVal* conn_val;
// Statistics.
Sizes sizes;
};
extern ConnCompressor* conn_compressor;
#endif

View file

@ -137,12 +137,12 @@ static bool is_mapped_dce_rpc_endpoint(const dce_rpc_endpoint_addr& addr)
bool is_mapped_dce_rpc_endpoint(const ConnID* id, TransportProto proto) bool is_mapped_dce_rpc_endpoint(const ConnID* id, TransportProto proto)
{ {
#ifdef BROv6 if ( id->dst_addr.GetFamily() == IPv6 )
if ( ! is_v4_addr(id->dst_addr) ) // TODO: Does the protocol support v6 addresses? #773
return false; return false;
#endif
dce_rpc_endpoint_addr addr; dce_rpc_endpoint_addr addr;
addr.addr = ntohl(to_v4_addr(id->dst_addr)); addr.addr = id->dst_addr;
addr.port = ntohs(id->dst_port); addr.port = ntohs(id->dst_port);
addr.proto = proto; addr.proto = proto;
@ -160,12 +160,7 @@ static void add_dce_rpc_endpoint(const dce_rpc_endpoint_addr& addr,
// of the dce_rpc_endpoints table. // of the dce_rpc_endpoints table.
// FIXME: Don't hard-code the timeout. // FIXME: Don't hard-code the timeout.
// Convert the address to a v4/v6 address (depending on how dpm->ExpectConnection(IPAddr(), addr.addr, addr.port, addr.proto,
// Bro was configured). This is all based on the address currently
// being a 32-bit host-order v4 address.
AddrVal a(htonl(addr.addr));
const addr_type at = a.AsAddr();
dpm->ExpectConnection(0, at, addr.port, addr.proto,
AnalyzerTag::DCE_RPC, 5 * 60, 0); AnalyzerTag::DCE_RPC, 5 * 60, 0);
} }
@ -418,8 +413,8 @@ void DCE_RPC_Session::DeliverEpmapperMapResponse(
break; break;
case binpac::DCE_RPC_Simple::EPM_PROTOCOL_IP: case binpac::DCE_RPC_Simple::EPM_PROTOCOL_IP:
mapped.addr.addr = uint32 hostip = floor->rhs()->data()->ip();
floor->rhs()->data()->ip(); mapped.addr.addr = IPAddr(IPv4, &hostip, IPAddr::Host);
break; break;
} }
} }
@ -433,7 +428,7 @@ void DCE_RPC_Session::DeliverEpmapperMapResponse(
vl->append(analyzer->BuildConnVal()); vl->append(analyzer->BuildConnVal());
vl->append(new StringVal(mapped.uuid.to_string())); vl->append(new StringVal(mapped.uuid.to_string()));
vl->append(new PortVal(mapped.addr.port, mapped.addr.proto)); vl->append(new PortVal(mapped.addr.port, mapped.addr.proto));
vl->append(new AddrVal(htonl(mapped.addr.addr))); vl->append(new AddrVal(mapped.addr.addr));
analyzer->ConnectionEvent(epm_map_response, vl); analyzer->ConnectionEvent(epm_map_response, vl);
} }

View file

@ -8,6 +8,7 @@
#include "NetVar.h" #include "NetVar.h"
#include "TCP.h" #include "TCP.h"
#include "IPAddr.h"
#include "dce_rpc_simple_pac.h" #include "dce_rpc_simple_pac.h"
@ -34,19 +35,19 @@ const char* uuid_to_string(const u_char* uuid_data);
struct dce_rpc_endpoint_addr { struct dce_rpc_endpoint_addr {
// All fields are in host byteorder. // All fields are in host byteorder.
uint32 addr; IPAddr addr;
u_short port; u_short port;
TransportProto proto; TransportProto proto;
dce_rpc_endpoint_addr() dce_rpc_endpoint_addr()
{ {
addr = 0; addr = IPAddr();
port = 0; port = 0;
proto = TRANSPORT_UNKNOWN; proto = TRANSPORT_UNKNOWN;
} }
bool is_valid_addr() const bool is_valid_addr() const
{ return addr != 0 && port != 0 && proto != TRANSPORT_UNKNOWN; } { return addr != IPAddr() && port != 0 && proto != TRANSPORT_UNKNOWN; }
bool operator<(dce_rpc_endpoint_addr const &e) const bool operator<(dce_rpc_endpoint_addr const &e) const
{ {
@ -64,7 +65,7 @@ struct dce_rpc_endpoint_addr {
{ {
static char buf[128]; static char buf[128];
snprintf(buf, sizeof(buf), "%s/%d/%s", snprintf(buf, sizeof(buf), "%s/%d/%s",
dotted_addr(htonl(addr)), port, addr.AsString().c_str(), port,
proto == TRANSPORT_TCP ? "tcp" : proto == TRANSPORT_TCP ? "tcp" :
(proto == TRANSPORT_UDP ? "udp" : "?")); (proto == TRANSPORT_UDP ? "udp" : "?"));

View file

@ -758,62 +758,37 @@ int DNS_Interpreter::ParseRR_A(DNS_MsgInfo* msg,
int DNS_Interpreter::ParseRR_AAAA(DNS_MsgInfo* msg, int DNS_Interpreter::ParseRR_AAAA(DNS_MsgInfo* msg,
const u_char*& data, int& len, int rdlength) const u_char*& data, int& len, int rdlength)
{ {
// We need to parse an IPv6 address, high-order byte first.
// ### Currently, we fake an A reply rather than an AAAA reply,
// since for the latter we won't be able to express the full
// address (unless Bro was compiled for IPv6 addresses). We do
// this fake by using just the bottom 4 bytes of the IPv6 address.
uint32 addr[4]; uint32 addr[4];
int i;
for ( i = 0; i < 4; ++i ) for ( int i = 0; i < 4; ++i )
{ {
addr[i] = ntohl(ExtractLong(data, len)); addr[i] = htonl(ExtractLong(data, len));
if ( len < 0 ) if ( len < 0 )
{ {
analyzer->Weird("DNS_AAAA_neg_length"); if ( msg->atype == TYPE_AAAA )
analyzer->Weird("DNS_AAAA_neg_length");
else
analyzer->Weird("DNS_A6_neg_length");
return 0; return 0;
} }
} }
// Currently, dns_AAAA_reply is treated like dns_A_reply, since EventHandlerPtr event;
// IPv6 addresses are not generally processed. This needs to be if ( msg->atype == TYPE_AAAA )
// fixed. ### event = dns_AAAA_reply;
if ( dns_A_reply && ! msg->skip_event ) else
event = dns_A6_reply;
if ( event && ! msg->skip_event )
{ {
val_list* vl = new val_list; val_list* vl = new val_list;
vl->append(analyzer->BuildConnVal()); vl->append(analyzer->BuildConnVal());
vl->append(msg->BuildHdrVal()); vl->append(msg->BuildHdrVal());
vl->append(msg->BuildAnswerVal()); vl->append(msg->BuildAnswerVal());
vl->append(new AddrVal(htonl(addr[3])));
analyzer->ConnectionEvent(dns_A_reply, vl);
}
#if 0
alternative AAAA code from Chris
if ( dns_AAAA_reply && ! msg->skip_event )
{
val_list* vl = new val_list;
vl->append(analyzer->BuildConnVal());
vl->append(msg->BuildHdrVal());
vl->append(msg->BuildAnswerVal());
#ifdef BROv6
// FIXME: might need to htonl the addr first
vl->append(new AddrVal(addr)); vl->append(new AddrVal(addr));
#else analyzer->ConnectionEvent(event, vl);
vl->append(new AddrVal((uint32)0x0000));
#endif
char addrstr[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, addr, addrstr, INET6_ADDRSTRLEN);
vl->append(new StringVal(addrstr));
analyzer->ConnectionEvent(dns_AAAA_reply, vl);
} }
#endif
return 1; return 1;
} }

View file

@ -46,13 +46,13 @@ extern int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
class DNS_Mgr_Request { class DNS_Mgr_Request {
public: public:
DNS_Mgr_Request(const char* h) { host = copy_string(h); addr = 0; } DNS_Mgr_Request(const char* h, int af) { host = copy_string(h); fam = af; }
DNS_Mgr_Request(uint32 a) { addr = a; host = 0; } DNS_Mgr_Request(const IPAddr& a) { addr = a; host = 0; fam = 0; }
~DNS_Mgr_Request() { delete [] host; } ~DNS_Mgr_Request() { delete [] host; }
// Returns nil if this was an address request. // Returns nil if this was an address request.
const char* ReqHost() const { return host; } const char* ReqHost() const { return host; }
uint32 ReqAddr() const { return addr; } const IPAddr& ReqAddr() const { return addr; }
int MakeRequest(nb_dns_info* nb_dns); int MakeRequest(nb_dns_info* nb_dns);
int RequestPending() const { return request_pending; } int RequestPending() const { return request_pending; }
@ -61,8 +61,8 @@ public:
protected: protected:
char* host; // if non-nil, this is a host request char* host; // if non-nil, this is a host request
uint32 addr; int fam; // address family query type for host requests
uint32 ttl; IPAddr addr;
int request_pending; int request_pending;
}; };
@ -75,15 +75,20 @@ int DNS_Mgr_Request::MakeRequest(nb_dns_info* nb_dns)
char err[NB_DNS_ERRSIZE]; char err[NB_DNS_ERRSIZE];
if ( host ) if ( host )
return nb_dns_host_request(nb_dns, host, (void*) this, err) >= 0; return nb_dns_host_request2(nb_dns, host, fam, (void*) this, err) >= 0;
else else
return nb_dns_addr_request(nb_dns, addr, (void*) this, err) >= 0; {
const uint32* bytes;
int len = addr.GetBytes(&bytes);
return nb_dns_addr_request2(nb_dns, (char*) bytes,
len == 1 ? AF_INET : AF_INET6, (void*) this, err) >= 0;
}
} }
class DNS_Mapping { class DNS_Mapping {
public: public:
DNS_Mapping(const char* host, struct hostent* h, uint32 ttl); DNS_Mapping(const char* host, struct hostent* h, uint32 ttl);
DNS_Mapping(uint32 addr, struct hostent* h, uint32 ttl); DNS_Mapping(const IPAddr& addr, struct hostent* h, uint32 ttl);
DNS_Mapping(FILE* f); DNS_Mapping(FILE* f);
int NoMapping() const { return no_mapping; } int NoMapping() const { return no_mapping; }
@ -93,9 +98,11 @@ public:
// Returns nil if this was an address request. // Returns nil if this was an address request.
const char* ReqHost() const { return req_host; } const char* ReqHost() const { return req_host; }
uint32 ReqAddr() const { return req_addr; } IPAddr ReqAddr() const { return req_addr; }
const char* ReqStr() const string ReqStr() const
{ return req_host ? req_host : dotted_addr(ReqAddr()); } {
return req_host ? req_host : req_addr;
}
ListVal* Addrs(); ListVal* Addrs();
TableVal* AddrsSet(); // addresses returned as a set TableVal* AddrsSet(); // addresses returned as a set
@ -109,7 +116,14 @@ public:
int Valid() const { return ! failed; } int Valid() const { return ! failed; }
bool Expired() const bool Expired() const
{ return current_time() > (creation_time + req_ttl); } {
if ( req_host && num_addrs == 0)
return false; // nothing to expire
return current_time() > (creation_time + req_ttl);
}
int Type() const { return map_type; }
protected: protected:
friend class DNS_Mgr; friend class DNS_Mgr;
@ -121,7 +135,7 @@ protected:
int init_failed; int init_failed;
char* req_host; char* req_host;
uint32 req_addr; IPAddr req_addr;
uint32 req_ttl; uint32 req_ttl;
int num_names; int num_names;
@ -129,11 +143,12 @@ protected:
StringVal* host_val; StringVal* host_val;
int num_addrs; int num_addrs;
uint32* addrs; IPAddr* addrs;
ListVal* addrs_val; ListVal* addrs_val;
int failed; int failed;
double creation_time; double creation_time;
int map_type;
}; };
void DNS_Mgr_mapping_delete_func(void* v) void DNS_Mgr_mapping_delete_func(void* v)
@ -154,14 +169,13 @@ DNS_Mapping::DNS_Mapping(const char* host, struct hostent* h, uint32 ttl)
{ {
Init(h); Init(h);
req_host = copy_string(host); req_host = copy_string(host);
req_addr = 0;
req_ttl = ttl; req_ttl = ttl;
if ( names && ! names[0] ) if ( names && ! names[0] )
names[0] = copy_string(host); names[0] = copy_string(host);
} }
DNS_Mapping::DNS_Mapping(uint32 addr, struct hostent* h, uint32 ttl) DNS_Mapping::DNS_Mapping(const IPAddr& addr, struct hostent* h, uint32 ttl)
{ {
Init(h); Init(h);
req_addr = addr; req_addr = addr;
@ -175,7 +189,6 @@ DNS_Mapping::DNS_Mapping(FILE* f)
init_failed = 1; init_failed = 1;
req_host = 0; req_host = 0;
req_addr = 0;
char buf[512]; char buf[512];
@ -188,14 +201,15 @@ DNS_Mapping::DNS_Mapping(FILE* f)
char req_buf[512+1], name_buf[512+1]; char req_buf[512+1], name_buf[512+1];
int is_req_host; int is_req_host;
if ( sscanf(buf, "%lf %d %512s %d %512s %d", &creation_time, &is_req_host, if ( sscanf(buf, "%lf %d %512s %d %512s %d %d %"PRIu32, &creation_time,
req_buf, &failed, name_buf, &num_addrs) != 6 ) &is_req_host, req_buf, &failed, name_buf, &map_type, &num_addrs,
&req_ttl) != 8 )
return; return;
if ( is_req_host ) if ( is_req_host )
req_host = copy_string(req_buf); req_host = copy_string(req_buf);
else else
req_addr = dotted_to_addr(req_buf); req_addr = IPAddr(req_buf);
num_names = 1; num_names = 1;
names = new char*[num_names]; names = new char*[num_names];
@ -203,7 +217,7 @@ DNS_Mapping::DNS_Mapping(FILE* f)
if ( num_addrs > 0 ) if ( num_addrs > 0 )
{ {
addrs = new uint32[num_addrs]; addrs = new IPAddr[num_addrs];
for ( int i = 0; i < num_addrs; ++i ) for ( int i = 0; i < num_addrs; ++i )
{ {
@ -217,7 +231,7 @@ DNS_Mapping::DNS_Mapping(FILE* f)
if ( newline ) if ( newline )
*newline = '\0'; *newline = '\0';
addrs[i] = dotted_to_addr(buf); addrs[i] = IPAddr(buf);
} }
} }
else else
@ -280,14 +294,6 @@ StringVal* DNS_Mapping::Host()
return host_val; return host_val;
} }
// Converts an array of 4 bytes in network order to the corresponding
// 32-bit network long.
static uint32 raw_bytes_to_addr(const unsigned char b[4])
{
uint32 l = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
return uint32(htonl(l));
}
void DNS_Mapping::Init(struct hostent* h) void DNS_Mapping::Init(struct hostent* h)
{ {
no_mapping = 0; no_mapping = 0;
@ -296,12 +302,13 @@ void DNS_Mapping::Init(struct hostent* h)
host_val = 0; host_val = 0;
addrs_val = 0; addrs_val = 0;
if ( ! h || h->h_addrtype != AF_INET || h->h_length != 4 ) if ( ! h )
{ {
Clear(); Clear();
return; return;
} }
map_type = h->h_addrtype;
num_names = 1; // for now, just use official name num_names = 1; // for now, just use official name
names = new char*[num_names]; names = new char*[num_names];
names[0] = h->h_name ? copy_string(h->h_name) : 0; names[0] = h->h_name ? copy_string(h->h_name) : 0;
@ -311,10 +318,14 @@ void DNS_Mapping::Init(struct hostent* h)
if ( num_addrs > 0 ) if ( num_addrs > 0 )
{ {
addrs = new uint32[num_addrs]; addrs = new IPAddr[num_addrs];
for ( int i = 0; i < num_addrs; ++i ) for ( int i = 0; i < num_addrs; ++i )
addrs[i] = raw_bytes_to_addr( if ( h->h_addrtype == AF_INET )
(unsigned char*)h->h_addr_list[i]); addrs[i] = IPAddr(IPv4, (uint32*)h->h_addr_list[i],
IPAddr::Network);
else if ( h->h_addrtype == AF_INET6 )
addrs[i] = IPAddr(IPv6, (uint32*)h->h_addr_list[i],
IPAddr::Network);
} }
else else
addrs = 0; addrs = 0;
@ -330,18 +341,19 @@ void DNS_Mapping::Clear()
host_val = 0; host_val = 0;
addrs_val = 0; addrs_val = 0;
no_mapping = 0; no_mapping = 0;
map_type = 0;
failed = 1; failed = 1;
} }
void DNS_Mapping::Save(FILE* f) const void DNS_Mapping::Save(FILE* f) const
{ {
fprintf(f, "%.0f %d %s %d %s %d\n", creation_time, req_host != 0, fprintf(f, "%.0f %d %s %d %s %d %d %"PRIu32"\n", creation_time, req_host != 0,
req_host ? req_host : dotted_addr(req_addr), req_host ? req_host : req_addr.AsString().c_str(),
failed, (names && names[0]) ? names[0] : "*", failed, (names && names[0]) ? names[0] : "*",
num_addrs); map_type, num_addrs, req_ttl);
for ( int i = 0; i < num_addrs; ++i ) for ( int i = 0; i < num_addrs; ++i )
fprintf(f, "%s\n", dotted_addr(addrs[i])); fprintf(f, "%s\n", addrs[i].AsString().c_str());
} }
@ -351,9 +363,6 @@ DNS_Mgr::DNS_Mgr(DNS_MgrMode arg_mode)
mode = arg_mode; mode = arg_mode;
host_mappings.SetDeleteFunc(DNS_Mgr_mapping_delete_func);
addr_mappings.SetDeleteFunc(DNS_Mgr_mapping_delete_func);
char err[NB_DNS_ERRSIZE]; char err[NB_DNS_ERRSIZE];
nb_dns = nb_dns_init(err); nb_dns = nb_dns_init(err);
@ -440,24 +449,34 @@ TableVal* DNS_Mgr::LookupHost(const char* name)
if ( mode != DNS_PRIME ) if ( mode != DNS_PRIME )
{ {
DNS_Mapping* d = host_mappings.Lookup(name); HostMap::iterator it = host_mappings.find(name);
if ( d ) if ( it != host_mappings.end() )
{ {
if ( d->Valid() ) DNS_Mapping* d4 = it->second.first;
return d->Addrs()->ConvertToSet(); DNS_Mapping* d6 = it->second.second;
else
if ( (d4 && d4->Failed()) || (d6 && d6->Failed()) )
{ {
reporter->Warning("no such host: %s", name); reporter->Warning("no such host: %s", name);
return empty_addr_set(); return empty_addr_set();
} }
else if ( d4 && d6 )
{
TableVal* tv4 = d4->AddrsSet();
TableVal* tv6 = d6->AddrsSet();
tv4->AddTo(tv6, false);
Unref(tv4);
return tv6;
}
} }
} }
// Not found, or priming. // Not found, or priming.
switch ( mode ) { switch ( mode ) {
case DNS_PRIME: case DNS_PRIME:
requests.append(new DNS_Mgr_Request(name)); requests.append(new DNS_Mgr_Request(name, AF_INET));
requests.append(new DNS_Mgr_Request(name, AF_INET6));
return empty_addr_set(); return empty_addr_set();
case DNS_FORCE: case DNS_FORCE:
@ -465,7 +484,8 @@ TableVal* DNS_Mgr::LookupHost(const char* name)
return 0; return 0;
case DNS_DEFAULT: case DNS_DEFAULT:
requests.append(new DNS_Mgr_Request(name)); requests.append(new DNS_Mgr_Request(name, AF_INET));
requests.append(new DNS_Mgr_Request(name, AF_INET6));
Resolve(); Resolve();
return LookupHost(name); return LookupHost(name);
@ -475,24 +495,25 @@ TableVal* DNS_Mgr::LookupHost(const char* name)
} }
} }
Val* DNS_Mgr::LookupAddr(uint32 addr) Val* DNS_Mgr::LookupAddr(const IPAddr& addr)
{ {
if ( ! did_init ) if ( ! did_init )
Init(); Init();
if ( mode != DNS_PRIME ) if ( mode != DNS_PRIME )
{ {
HashKey h(&addr, 1); AddrMap::iterator it = addr_mappings.find(addr);
DNS_Mapping* d = addr_mappings.Lookup(&h);
if ( d ) if ( it != addr_mappings.end() )
{ {
DNS_Mapping* d = it->second;
if ( d->Valid() ) if ( d->Valid() )
return d->Host(); return d->Host();
else else
{ {
reporter->Warning("can't resolve IP address: %s", dotted_addr(addr)); string s(addr);
return new StringVal(dotted_addr(addr)); reporter->Warning("can't resolve IP address: %s", s.c_str());
return new StringVal(s.c_str());
} }
} }
} }
@ -505,7 +526,7 @@ Val* DNS_Mgr::LookupAddr(uint32 addr)
case DNS_FORCE: case DNS_FORCE:
reporter->FatalError("can't find DNS entry for %s in cache", reporter->FatalError("can't find DNS entry for %s in cache",
dotted_addr(addr)); addr.AsString().c_str());
return 0; return 0;
case DNS_DEFAULT: case DNS_DEFAULT:
@ -681,28 +702,53 @@ void DNS_Mgr::AddResult(DNS_Mgr_Request* dr, struct nb_dns_result* r)
if ( dr->ReqHost() ) if ( dr->ReqHost() )
{ {
new_dm = new DNS_Mapping(dr->ReqHost(), h, ttl); new_dm = new DNS_Mapping(dr->ReqHost(), h, ttl);
prev_dm = host_mappings.Insert(dr->ReqHost(), new_dm); prev_dm = 0;
HostMap::iterator it = host_mappings.find(dr->ReqHost());
if ( it == host_mappings.end() )
{
host_mappings[dr->ReqHost()].first =
new_dm->Type() == AF_INET ? new_dm : 0;
host_mappings[dr->ReqHost()].second =
new_dm->Type() == AF_INET ? 0 : new_dm;
}
else
{
if ( new_dm->Type() == AF_INET )
{
prev_dm = it->second.first;
it->second.first = new_dm;
}
else
{
prev_dm = it->second.second;
it->second.second = new_dm;
}
}
if ( new_dm->Failed() && prev_dm && prev_dm->Valid() ) if ( new_dm->Failed() && prev_dm && prev_dm->Valid() )
{ {
// Put previous, valid entry back - CompareMappings // Put previous, valid entry back - CompareMappings
// will generate a corresponding warning. // will generate a corresponding warning.
(void) host_mappings.Insert(dr->ReqHost(), prev_dm); if ( prev_dm->Type() == AF_INET )
host_mappings[dr->ReqHost()].first = prev_dm;
else
host_mappings[dr->ReqHost()].second = prev_dm;
++keep_prev; ++keep_prev;
} }
} }
else else
{ {
new_dm = new DNS_Mapping(dr->ReqAddr(), h, ttl); new_dm = new DNS_Mapping(dr->ReqAddr(), h, ttl);
uint32 tmp_addr = dr->ReqAddr(); AddrMap::iterator it = addr_mappings.find(dr->ReqAddr());
HashKey k(&tmp_addr, 1); prev_dm = (it == addr_mappings.end()) ? 0 : it->second;
prev_dm = addr_mappings.Insert(&k, new_dm); addr_mappings[dr->ReqAddr()] = new_dm;
if ( new_dm->Failed() && prev_dm && prev_dm->Valid() ) if ( new_dm->Failed() && prev_dm && prev_dm->Valid() )
{ {
uint32 tmp_addr = dr->ReqAddr(); addr_mappings[dr->ReqAddr()] = prev_dm;
HashKey k2(&tmp_addr, 1);
(void) addr_mappings.Insert(&k2, prev_dm);
++keep_prev; ++keep_prev;
} }
} }
@ -774,17 +820,13 @@ ListVal* DNS_Mgr::AddrListDelta(ListVal* al1, ListVal* al2)
for ( int i = 0; i < al1->Length(); ++i ) for ( int i = 0; i < al1->Length(); ++i )
{ {
addr_type al1_i = al1->Index(i)->AsAddr(); const IPAddr& al1_i = al1->Index(i)->AsAddr();
int j; int j;
for ( j = 0; j < al2->Length(); ++j ) for ( j = 0; j < al2->Length(); ++j )
{ {
addr_type al2_j = al2->Index(j)->AsAddr(); const IPAddr& al2_j = al2->Index(j)->AsAddr();
#ifdef BROv6
if ( addr_eq(al1_i, al2_j) )
#else
if ( al1_i == al2_j ) if ( al1_i == al2_j )
#endif
break; break;
} }
@ -800,8 +842,8 @@ void DNS_Mgr::DumpAddrList(FILE* f, ListVal* al)
{ {
for ( int i = 0; i < al->Length(); ++i ) for ( int i = 0; i < al->Length(); ++i )
{ {
addr_type al_i = al->Index(i)->AsAddr(); const IPAddr& al_i = al->Index(i)->AsAddr();
fprintf(f, "%s%s", i > 0 ? "," : "", dotted_addr(al_i)); fprintf(f, "%s%s", i > 0 ? "," : "", al_i.AsString().c_str());
} }
} }
@ -814,12 +856,20 @@ void DNS_Mgr::LoadCache(FILE* f)
for ( ; ! m->NoMapping() && ! m->InitFailed(); m = new DNS_Mapping(f) ) for ( ; ! m->NoMapping() && ! m->InitFailed(); m = new DNS_Mapping(f) )
{ {
if ( m->ReqHost() ) if ( m->ReqHost() )
host_mappings.Insert(m->ReqHost(), m); {
if ( host_mappings.find(m->ReqHost()) == host_mappings.end() )
{
host_mappings[m->ReqHost()].first = 0;
host_mappings[m->ReqHost()].second = 0;
}
if ( m->Type() == AF_INET )
host_mappings[m->ReqHost()].first = m;
else
host_mappings[m->ReqHost()].second = m;
}
else else
{ {
uint32 tmp_addr = m->ReqAddr(); addr_mappings[m->ReqAddr()] = m;
HashKey h(&tmp_addr, 1);
addr_mappings.Insert(&h, m);
} }
} }
@ -830,26 +880,41 @@ void DNS_Mgr::LoadCache(FILE* f)
fclose(f); fclose(f);
} }
void DNS_Mgr::Save(FILE* f, PDict(DNS_Mapping)& m) void DNS_Mgr::Save(FILE* f, const AddrMap& m)
{ {
IterCookie* cookie = m.InitForIteration(); for ( AddrMap::const_iterator it = m.begin(); it != m.end(); ++it )
DNS_Mapping* dm; {
if ( it->second )
while ( (dm = m.NextEntry(cookie)) ) it->second->Save(f);
dm->Save(f); }
} }
const char* DNS_Mgr::LookupAddrInCache(dns_mgr_addr_type addr) void DNS_Mgr::Save(FILE* f, const HostMap& m)
{ {
HashKey h(&addr, 1); HostMap::const_iterator it;
DNS_Mapping* d = dns_mgr->addr_mappings.Lookup(&h);
if ( ! d ) for ( it = m.begin(); it != m.end(); ++it )
{
if ( it->second.first )
it->second.first->Save(f);
if ( it->second.second )
it->second.second->Save(f);
}
}
const char* DNS_Mgr::LookupAddrInCache(const IPAddr& addr)
{
AddrMap::iterator it = dns_mgr->addr_mappings.find(addr);
if ( it == addr_mappings.end() )
return 0; return 0;
DNS_Mapping* d = it->second;
if ( d->Expired() ) if ( d->Expired() )
{ {
dns_mgr->addr_mappings.Remove(&h); dns_mgr->addr_mappings.erase(it);
delete d; delete d;
return 0; return 0;
} }
@ -861,23 +926,32 @@ const char* DNS_Mgr::LookupAddrInCache(dns_mgr_addr_type addr)
TableVal* DNS_Mgr::LookupNameInCache(string name) TableVal* DNS_Mgr::LookupNameInCache(string name)
{ {
DNS_Mapping* d = dns_mgr->host_mappings.Lookup(name.c_str()); HostMap::iterator it = dns_mgr->host_mappings.find(name);
if ( it == dns_mgr->host_mappings.end() )
if ( ! d || ! d->names )
return 0; return 0;
if ( d->Expired() ) DNS_Mapping* d4 = it->second.first;
DNS_Mapping* d6 = it->second.second;
if ( ! d4 || ! d4->names || ! d6 || ! d6->names )
return 0;
if ( d4->Expired() || d6->Expired() )
{ {
HashKey h(name.c_str()); dns_mgr->host_mappings.erase(it);
dns_mgr->host_mappings.Remove(&h); delete d4;
delete d; delete d6;
return 0; return 0;
} }
return d->AddrsSet(); TableVal* tv4 = d4->AddrsSet();
TableVal* tv6 = d6->AddrsSet();
tv4->AddTo(tv6, false);
Unref(tv4);
return tv6;
} }
void DNS_Mgr::AsyncLookupAddr(dns_mgr_addr_type host, LookupCallback* callback) void DNS_Mgr::AsyncLookupAddr(const IPAddr& host, LookupCallback* callback)
{ {
if ( ! did_init ) if ( ! did_init )
Init(); Init();
@ -956,10 +1030,15 @@ void DNS_Mgr::IssueAsyncRequests()
++num_requests; ++num_requests;
DNS_Mgr_Request* dr; DNS_Mgr_Request* dr;
DNS_Mgr_Request* dr6 = 0;
if ( req->IsAddrReq() ) if ( req->IsAddrReq() )
dr = new DNS_Mgr_Request(req->host); dr = new DNS_Mgr_Request(req->host);
else else
dr = new DNS_Mgr_Request(req->name.c_str()); {
dr = new DNS_Mgr_Request(req->name.c_str(), AF_INET);
dr6 = new DNS_Mgr_Request(req->name.c_str(), AF_INET6);
}
if ( ! dr->MakeRequest(nb_dns) ) if ( ! dr->MakeRequest(nb_dns) )
{ {
@ -969,6 +1048,14 @@ void DNS_Mgr::IssueAsyncRequests()
continue; continue;
} }
if ( dr6 && ! dr6->MakeRequest(nb_dns) )
{
reporter->Warning("can't issue DNS request");
++failed;
req->Timeout();
continue;
}
req->time = current_time(); req->time = current_time();
asyncs_timeouts.push(req); asyncs_timeouts.push(req);
@ -987,7 +1074,7 @@ double DNS_Mgr::NextTimestamp(double* network_time)
return asyncs_timeouts.size() ? timer_mgr->Time() : -1.0; return asyncs_timeouts.size() ? timer_mgr->Time() : -1.0;
} }
void DNS_Mgr::CheckAsyncAddrRequest(dns_mgr_addr_type addr, bool timeout) void DNS_Mgr::CheckAsyncAddrRequest(const IPAddr& addr, bool timeout)
{ {
// Note that this code is a mirror of that for CheckAsyncHostRequest. // Note that this code is a mirror of that for CheckAsyncHostRequest.
@ -1060,11 +1147,18 @@ void DNS_Mgr::Flush()
{ {
DoProcess(false); DoProcess(false);
IterCookie* cookie = addr_mappings.InitForIteration(); HostMap::iterator it;
DNS_Mapping* dm; for ( it = host_mappings.begin(); it != host_mappings.end(); ++it )
{
delete it->second.first;
delete it->second.second;
}
host_mappings.Clear(); for ( AddrMap::iterator it2 = addr_mappings.begin(); it2 != addr_mappings.end(); ++it2 )
addr_mappings.Clear(); delete it2->second;
host_mappings.clear();
addr_mappings.clear();
} }
void DNS_Mgr::Process() void DNS_Mgr::Process()
@ -1107,6 +1201,14 @@ void DNS_Mgr::DoProcess(bool flush)
else if ( status > 0 ) else if ( status > 0 )
{ {
DNS_Mgr_Request* dr = (DNS_Mgr_Request*) r.cookie; DNS_Mgr_Request* dr = (DNS_Mgr_Request*) r.cookie;
bool do_host_timeout = true;
if ( dr->ReqHost() &&
host_mappings.find(dr->ReqHost()) == host_mappings.end() )
// Don't timeout when this is the first result in an expected pair
// (one result each for A and AAAA queries).
do_host_timeout = false;
if ( dr->RequestPending() ) if ( dr->RequestPending() )
{ {
AddResult(dr, &r); AddResult(dr, &r);
@ -1116,7 +1218,7 @@ void DNS_Mgr::DoProcess(bool flush)
if ( ! dr->ReqHost() ) if ( ! dr->ReqHost() )
CheckAsyncAddrRequest(dr->ReqAddr(), true); CheckAsyncAddrRequest(dr->ReqAddr(), true);
else else
CheckAsyncHostRequest(dr->ReqHost(), true); CheckAsyncHostRequest(dr->ReqHost(), do_host_timeout);
IssueAsyncRequests(); IssueAsyncRequests();
@ -1167,7 +1269,7 @@ void DNS_Mgr::GetStats(Stats* stats)
stats->successful = successful; stats->successful = successful;
stats->failed = failed; stats->failed = failed;
stats->pending = asyncs_pending; stats->pending = asyncs_pending;
stats->cached_hosts = host_mappings.Length(); stats->cached_hosts = host_mappings.size();
stats->cached_addresses = addr_mappings.Length(); stats->cached_addresses = addr_mappings.size();
} }

View file

@ -6,12 +6,14 @@
#include <list> #include <list>
#include <map> #include <map>
#include <queue> #include <queue>
#include <utility>
#include "util.h" #include "util.h"
#include "BroList.h" #include "BroList.h"
#include "Dict.h" #include "Dict.h"
#include "EventHandler.h" #include "EventHandler.h"
#include "IOSource.h" #include "IOSource.h"
#include "IPAddr.h"
class Val; class Val;
class ListVal; class ListVal;
@ -27,7 +29,6 @@ struct nb_dns_result;
declare(PDict,ListVal); declare(PDict,ListVal);
class DNS_Mapping; class DNS_Mapping;
declare(PDict,DNS_Mapping);
enum DNS_MgrMode { enum DNS_MgrMode {
DNS_PRIME, // used to prime the cache DNS_PRIME, // used to prime the cache
@ -39,10 +40,6 @@ enum DNS_MgrMode {
// Number of seconds we'll wait for a reply. // Number of seconds we'll wait for a reply.
#define DNS_TIMEOUT 5 #define DNS_TIMEOUT 5
// ### For now, we don't support IPv6 lookups. When we do, this
// should become addr_type.
typedef uint32 dns_mgr_addr_type;
class DNS_Mgr : public IOSource { class DNS_Mgr : public IOSource {
public: public:
DNS_Mgr(DNS_MgrMode mode); DNS_Mgr(DNS_MgrMode mode);
@ -55,7 +52,7 @@ public:
// a set of addr. // a set of addr.
TableVal* LookupHost(const char* host); TableVal* LookupHost(const char* host);
Val* LookupAddr(uint32 addr); Val* LookupAddr(const IPAddr& addr);
// Define the directory where to store the data. // Define the directory where to store the data.
void SetDir(const char* arg_dir) { dir = copy_string(arg_dir); } void SetDir(const char* arg_dir) { dir = copy_string(arg_dir); }
@ -64,7 +61,7 @@ public:
void Resolve(); void Resolve();
int Save(); int Save();
const char* LookupAddrInCache(dns_mgr_addr_type addr); const char* LookupAddrInCache(const IPAddr& addr);
TableVal* LookupNameInCache(string name); TableVal* LookupNameInCache(string name);
// Support for async lookups. // Support for async lookups.
@ -78,7 +75,7 @@ public:
virtual void Timeout() = 0; virtual void Timeout() = 0;
}; };
void AsyncLookupAddr(dns_mgr_addr_type host, LookupCallback* callback); void AsyncLookupAddr(const IPAddr& host, LookupCallback* callback);
void AsyncLookupName(string name, LookupCallback* callback); void AsyncLookupName(string name, LookupCallback* callback);
struct Stats { struct Stats {
@ -107,8 +104,11 @@ protected:
ListVal* AddrListDelta(ListVal* al1, ListVal* al2); ListVal* AddrListDelta(ListVal* al1, ListVal* al2);
void DumpAddrList(FILE* f, ListVal* al); void DumpAddrList(FILE* f, ListVal* al);
typedef map<string, pair<DNS_Mapping*, DNS_Mapping*> > HostMap;
typedef map<IPAddr, DNS_Mapping*> AddrMap;
void LoadCache(FILE* f); void LoadCache(FILE* f);
void Save(FILE* f, PDict(DNS_Mapping)& m); void Save(FILE* f, const AddrMap& m);
void Save(FILE* f, const HostMap& m);
// Selects on the fd to see if there is an answer available (timeout // Selects on the fd to see if there is an answer available (timeout
// is secs). Returns 0 on timeout, -1 on EINTR or other error, and 1 // is secs). Returns 0 on timeout, -1 on EINTR or other error, and 1
@ -120,7 +120,7 @@ protected:
// Finish the request if we have a result. If not, time it out if // Finish the request if we have a result. If not, time it out if
// requested. // requested.
void CheckAsyncAddrRequest(dns_mgr_addr_type addr, bool timeout); void CheckAsyncAddrRequest(const IPAddr& addr, bool timeout);
void CheckAsyncHostRequest(const char* host, bool timeout); void CheckAsyncHostRequest(const char* host, bool timeout);
// Process outstanding requests. // Process outstanding requests.
@ -136,8 +136,8 @@ protected:
PDict(ListVal) services; PDict(ListVal) services;
PDict(DNS_Mapping) host_mappings; HostMap host_mappings;
PDict(DNS_Mapping) addr_mappings; AddrMap addr_mappings;
DNS_mgr_request_list requests; DNS_mgr_request_list requests;
@ -163,7 +163,7 @@ protected:
struct AsyncRequest { struct AsyncRequest {
double time; double time;
dns_mgr_addr_type host; IPAddr host;
string name; string name;
CallbackList callbacks; CallbackList callbacks;
@ -204,7 +204,7 @@ protected:
}; };
typedef map<dns_mgr_addr_type, AsyncRequest*> AsyncRequestAddrMap; typedef map<IPAddr, AsyncRequest*> AsyncRequestAddrMap;
AsyncRequestAddrMap asyncs_addrs; AsyncRequestAddrMap asyncs_addrs;
typedef map<string, AsyncRequest*> AsyncRequestNameMap; typedef map<string, AsyncRequest*> AsyncRequestNameMap;

View file

@ -11,53 +11,28 @@
#include "ConnSizeAnalyzer.h" #include "ConnSizeAnalyzer.h"
ExpectedConn::ExpectedConn(const uint32* _orig, const uint32* _resp, ExpectedConn::ExpectedConn(const IPAddr& _orig, const IPAddr& _resp,
uint16 _resp_p, uint16 _proto) uint16 _resp_p, uint16 _proto)
{ {
if ( orig ) if ( _orig == IPAddr(string("0.0.0.0")) )
copy_addr(_orig, orig); // don't use the IPv4 mapping, use the literal unspecified address
// to indicate a wildcard
orig = IPAddr(string("::"));
else else
{ orig = _orig;
for ( int i = 0; i < NUM_ADDR_WORDS; ++i ) resp = _resp;
orig[i] = 0;
}
copy_addr(_resp, resp);
resp_p = _resp_p;
proto = _proto;
}
ExpectedConn::ExpectedConn(uint32 _orig, uint32 _resp,
uint16 _resp_p, uint16 _proto)
{
#ifdef BROv6
// Use the IPv4-within-IPv6 convention, as this is what's
// needed when we mix uint32's (like in this construction)
// with addr_type's (for example, when looking up expected
// connections).
orig[0] = orig[1] = orig[2] = 0;
resp[0] = resp[1] = resp[2] = 0;
orig[3] = _orig;
resp[3] = _resp;
#else
orig[0] = _orig;
resp[0] = _resp;
#endif
resp_p = _resp_p; resp_p = _resp_p;
proto = _proto; proto = _proto;
} }
ExpectedConn::ExpectedConn(const ExpectedConn& c) ExpectedConn::ExpectedConn(const ExpectedConn& c)
{ {
copy_addr(c.orig, orig); orig = c.orig;
copy_addr(c.resp, resp); resp = c.resp;
resp_p = c.resp_p; resp_p = c.resp_p;
proto = c.proto; proto = c.proto;
} }
DPM::DPM() DPM::DPM()
: expected_conns_queue(AssignedAnalyzer::compare) : expected_conns_queue(AssignedAnalyzer::compare)
{ {
@ -99,7 +74,7 @@ void DPM::PostScriptInit()
void DPM::AddConfig(const Analyzer::Config& cfg) void DPM::AddConfig(const Analyzer::Config& cfg)
{ {
#ifdef USE_PERFTOOLS #ifdef USE_PERFTOOLS_DEBUG
HeapLeakChecker::Disabler disabler; HeapLeakChecker::Disabler disabler;
#endif #endif
@ -158,23 +133,18 @@ AnalyzerTag::Tag DPM::GetExpected(int proto, const Connection* conn)
ExpectedConn c(conn->OrigAddr(), conn->RespAddr(), ExpectedConn c(conn->OrigAddr(), conn->RespAddr(),
ntohs(conn->RespPort()), proto); ntohs(conn->RespPort()), proto);
// Can't use sizeof(c) due to potential alignment issues. HashKey* key = BuildExpectedConnHashKey(c);
// FIXME: I guess this is still not portable ... AssignedAnalyzer* a = expected_conns.Lookup(key);
HashKey key(&c, sizeof(c.orig) + sizeof(c.resp) + delete key;
sizeof(c.resp_p) + sizeof(c.proto));
AssignedAnalyzer* a = expected_conns.Lookup(&key);
if ( ! a ) if ( ! a )
{ {
// Wildcard for originator. // Wildcard for originator.
for ( int i = 0; i < NUM_ADDR_WORDS; ++i ) c.orig = IPAddr(string("::"));
c.orig[i] = 0;
HashKey key(&c, sizeof(c.orig) + sizeof(c.resp) + HashKey* key = BuildExpectedConnHashKey(c);
sizeof(c.resp_p) + sizeof(c.proto)); a = expected_conns.Lookup(key);
delete key;
a = expected_conns.Lookup(&key);
} }
if ( ! a ) if ( ! a )
@ -215,46 +185,8 @@ bool DPM::BuildInitialAnalyzerTree(TransportProto proto, Connection* conn,
break; break;
case TRANSPORT_ICMP: { case TRANSPORT_ICMP: {
const struct icmp* icmpp = (const struct icmp *) data; root = icmp = new ICMP_Analyzer(conn);
switch ( icmpp->icmp_type ) { DBG_DPD(conn, "activated ICMP analyzer");
case ICMP_ECHO:
case ICMP_ECHOREPLY:
if ( ICMP_Echo_Analyzer::Available() )
{
root = icmp = new ICMP_Echo_Analyzer(conn);
DBG_DPD(conn, "activated ICMP Echo analyzer");
}
break;
case ICMP_REDIRECT:
if ( ICMP_Redir_Analyzer::Available() )
{
root = new ICMP_Redir_Analyzer(conn);
DBG_DPD(conn, "activated ICMP Redir analyzer");
}
break;
case ICMP_UNREACH:
if ( ICMP_Unreachable_Analyzer::Available() )
{
root = icmp = new ICMP_Unreachable_Analyzer(conn);
DBG_DPD(conn, "activated ICMP Unreachable analyzer");
}
break;
case ICMP_TIMXCEED:
if ( ICMP_TimeExceeded_Analyzer::Available() )
{
root = icmp = new ICMP_TimeExceeded_Analyzer(conn);
DBG_DPD(conn, "activated ICMP Time Exceeded analyzer");
}
break;
}
if ( ! root )
root = icmp = new ICMP_Analyzer(conn);
analyzed = true; analyzed = true;
break; break;
} }
@ -404,7 +336,8 @@ bool DPM::BuildInitialAnalyzerTree(TransportProto proto, Connection* conn,
return true; return true;
} }
void DPM::ExpectConnection(addr_type orig, addr_type resp, uint16 resp_p, void DPM::ExpectConnection(const IPAddr& orig, const IPAddr& resp,
uint16 resp_p,
TransportProto proto, AnalyzerTag::Tag analyzer, TransportProto proto, AnalyzerTag::Tag analyzer,
double timeout, void* cookie) double timeout, void* cookie)
{ {
@ -416,11 +349,7 @@ void DPM::ExpectConnection(addr_type orig, addr_type resp, uint16 resp_p,
{ {
if ( ! a->deleted ) if ( ! a->deleted )
{ {
HashKey* key = new HashKey(&a->conn, HashKey* key = BuildExpectedConnHashKey(a->conn);
sizeof(a->conn.orig) +
sizeof(a->conn.resp) +
sizeof(a->conn.resp_p) +
sizeof(a->conn.proto));
expected_conns.Remove(key); expected_conns.Remove(key);
delete key; delete key;
} }
@ -439,10 +368,9 @@ void DPM::ExpectConnection(addr_type orig, addr_type resp, uint16 resp_p,
ExpectedConn c(orig, resp, resp_p, proto); ExpectedConn c(orig, resp, resp_p, proto);
HashKey key(&c, sizeof(c.orig) + sizeof(c.resp) + HashKey* key = BuildExpectedConnHashKey(c);
sizeof(c.resp_p) + sizeof(c.proto));
AssignedAnalyzer* a = expected_conns.Lookup(&key); AssignedAnalyzer* a = expected_conns.Lookup(key);
if ( a ) if ( a )
a->deleted = true; a->deleted = true;
@ -454,8 +382,9 @@ void DPM::ExpectConnection(addr_type orig, addr_type resp, uint16 resp_p,
a->timeout = network_time + timeout; a->timeout = network_time + timeout;
a->deleted = false; a->deleted = false;
expected_conns.Insert(&key, a); expected_conns.Insert(key, a);
expected_conns_queue.push(a); expected_conns_queue.push(a);
delete key;
} }
void DPM::Done() void DPM::Done()
@ -466,11 +395,7 @@ void DPM::Done()
AssignedAnalyzer* a = expected_conns_queue.top(); AssignedAnalyzer* a = expected_conns_queue.top();
if ( ! a->deleted ) if ( ! a->deleted )
{ {
HashKey* key = new HashKey(&a->conn, HashKey* key = BuildExpectedConnHashKey(a->conn);
sizeof(a->conn.orig) +
sizeof(a->conn.resp) +
sizeof(a->conn.resp_p) +
sizeof(a->conn.proto));
expected_conns.Remove(key); expected_conns.Remove(key);
delete key; delete key;
} }

View file

@ -27,19 +27,13 @@
// Map to assign expected connections to analyzers. // Map to assign expected connections to analyzers.
class ExpectedConn { class ExpectedConn {
public: public:
// This form can be used for IPv6 as well as IPv4. ExpectedConn(const IPAddr& _orig, const IPAddr& _resp,
ExpectedConn(const uint32* _orig, const uint32* _resp,
uint16 _resp_p, uint16 _proto); uint16 _resp_p, uint16 _proto);
// This form only works for expecting an IPv4 connection. Note
// that we do the right thing whether we're built IPv4-only or
// BROv6.
ExpectedConn(uint32 _orig, uint32 _resp, uint16 _resp_p, uint16 _proto);
ExpectedConn(const ExpectedConn& c); ExpectedConn(const ExpectedConn& c);
uint32 orig[NUM_ADDR_WORDS]; IPAddr orig;
uint32 resp[NUM_ADDR_WORDS]; IPAddr resp;
uint16 resp_p; uint16 resp_p;
uint16 proto; uint16 proto;
}; };
@ -90,7 +84,7 @@ public:
// Schedules a particular analyzer for an upcoming connection. // Schedules a particular analyzer for an upcoming connection.
// 0 acts as a wildcard for orig. (Cookie is currently unused. // 0 acts as a wildcard for orig. (Cookie is currently unused.
// Eventually, we may pass it on to the analyzer). // Eventually, we may pass it on to the analyzer).
void ExpectConnection(addr_type orig, addr_type resp, uint16 resp_p, void ExpectConnection(const IPAddr& orig, const IPAddr& resp, uint16 resp_p,
TransportProto proto, AnalyzerTag::Tag analyzer, TransportProto proto, AnalyzerTag::Tag analyzer,
double timeout, void* cookie); double timeout, void* cookie);

View file

@ -142,7 +142,7 @@ int TraceState::LogTrace(const char* fmt, ...)
if ( ! loc.filename ) if ( ! loc.filename )
{ {
loc.filename = "<no filename>"; loc.filename = copy_string("<no filename>");
loc.last_line = 0; loc.last_line = 0;
} }
@ -735,7 +735,7 @@ string get_context_description(const Stmt* stmt, const Frame* frame)
loc = *stmt->GetLocationInfo(); loc = *stmt->GetLocationInfo();
else else
{ {
loc.filename = "<no filename>"; loc.filename = copy_string("<no filename>");
loc.last_line = 0; loc.last_line = 0;
} }

View file

@ -15,7 +15,7 @@ DebugLogger::Stream DebugLogger::streams[NUM_DBGS] = {
{ "compressor", 0, false }, {"string", 0, false }, { "compressor", 0, false }, {"string", 0, false },
{ "notifiers", 0, false }, { "main-loop", 0, false }, { "notifiers", 0, false }, { "main-loop", 0, false },
{ "dpd", 0, false }, { "tm", 0, false }, { "dpd", 0, false }, { "tm", 0, false },
{ "logging", 0, false } { "logging", 0, false }, { "threading", 0, false }
}; };
DebugLogger::DebugLogger(const char* filename) DebugLogger::DebugLogger(const char* filename)

View file

@ -24,6 +24,7 @@ enum DebugStream {
DBG_DPD, // Dynamic application detection framework DBG_DPD, // Dynamic application detection framework
DBG_TM, // Time-machine packet input via Brocolli DBG_TM, // Time-machine packet input via Brocolli
DBG_LOGGING, // Logging streams DBG_LOGGING, // Logging streams
DBG_THREADING, // Threading system
NUM_DBGS // Has to be last NUM_DBGS // Has to be last
}; };

View file

@ -157,6 +157,16 @@ void ODesc::Add(double d)
} }
} }
void ODesc::Add(const IPAddr& addr)
{
Add(addr.AsString());
}
void ODesc::Add(const IPPrefix& prefix)
{
Add(prefix.AsString());
}
void ODesc::AddCS(const char* s) void ODesc::AddCS(const char* s)
{ {
int n = strlen(s); int n = strlen(s);

View file

@ -6,6 +6,7 @@
#include <stdio.h> #include <stdio.h>
#include <list> #include <list>
#include <utility> #include <utility>
#include "BroString.h" #include "BroString.h"
typedef enum { typedef enum {
@ -21,6 +22,8 @@ typedef enum {
} desc_style; } desc_style;
class BroFile; class BroFile;
class IPAddr;
class IPPrefix;
class ODesc { class ODesc {
public: public:
@ -68,11 +71,14 @@ public:
void Add(const char* s, int do_indent=1); void Add(const char* s, int do_indent=1);
void AddN(const char* s, int len) { AddBytes(s, len); } void AddN(const char* s, int len) { AddBytes(s, len); }
void Add(const string& s) { AddBytes(s.data(), s.size()); }
void Add(int i); void Add(int i);
void Add(uint32 u); void Add(uint32 u);
void Add(int64 i); void Add(int64 i);
void Add(uint64 u); void Add(uint64 u);
void Add(double d); void Add(double d);
void Add(const IPAddr& addr);
void Add(const IPPrefix& prefix);
// Add s as a counted string. // Add s as a counted string.
void AddCS(const char* s); void AddCS(const char* s);

View file

@ -10,11 +10,6 @@
Discarder::Discarder() Discarder::Discarder()
{ {
ip_hdr = internal_type("ip_hdr")->AsRecordType();
tcp_hdr = internal_type("tcp_hdr")->AsRecordType();
udp_hdr = internal_type("udp_hdr")->AsRecordType();
icmp_hdr = internal_type("icmp_hdr")->AsRecordType();
check_ip = internal_func("discarder_check_ip"); check_ip = internal_func("discarder_check_ip");
check_tcp = internal_func("discarder_check_tcp"); check_tcp = internal_func("discarder_check_tcp");
check_udp = internal_func("discarder_check_udp"); check_udp = internal_func("discarder_check_udp");
@ -36,12 +31,10 @@ int Discarder::NextPacket(const IP_Hdr* ip, int len, int caplen)
{ {
int discard_packet = 0; int discard_packet = 0;
const struct ip* ip4 = ip->IP4_Hdr();
if ( check_ip ) if ( check_ip )
{ {
val_list* args = new val_list; val_list* args = new val_list;
args->append(BuildHeader(ip4)); args->append(ip->BuildPktHdrVal());
try try
{ {
@ -59,19 +52,18 @@ int Discarder::NextPacket(const IP_Hdr* ip, int len, int caplen)
return discard_packet; return discard_packet;
} }
int proto = ip4->ip_p; int proto = ip->NextProto();
if ( proto != IPPROTO_TCP && proto != IPPROTO_UDP && if ( proto != IPPROTO_TCP && proto != IPPROTO_UDP &&
proto != IPPROTO_ICMP ) proto != IPPROTO_ICMP )
// This is not a protocol we understand. // This is not a protocol we understand.
return 0; return 0;
// XXX shall we only check the first packet??? // XXX shall we only check the first packet???
uint32 frag_field = ntohs(ip4->ip_off); if ( ip->IsFragment() )
if ( (frag_field & 0x3fff) != 0 )
// Never check any fragment. // Never check any fragment.
return 0; return 0;
int ip_hdr_len = ip4->ip_hl * 4; int ip_hdr_len = ip->HdrLen();
len -= ip_hdr_len; // remove IP header len -= ip_hdr_len; // remove IP header
caplen -= ip_hdr_len; caplen -= ip_hdr_len;
@ -87,7 +79,7 @@ int Discarder::NextPacket(const IP_Hdr* ip, int len, int caplen)
// Where the data starts - if this is a protocol we know about, // Where the data starts - if this is a protocol we know about,
// this gets advanced past the transport header. // this gets advanced past the transport header.
const u_char* data = ((u_char*) ip4 + ip_hdr_len); const u_char* data = ip->Payload();
if ( is_tcp ) if ( is_tcp )
{ {
@ -97,8 +89,7 @@ int Discarder::NextPacket(const IP_Hdr* ip, int len, int caplen)
int th_len = tp->th_off * 4; int th_len = tp->th_off * 4;
val_list* args = new val_list; val_list* args = new val_list;
args->append(BuildHeader(ip4)); args->append(ip->BuildPktHdrVal());
args->append(BuildHeader(tp, len));
args->append(BuildData(data, th_len, len, caplen)); args->append(BuildData(data, th_len, len, caplen));
try try
@ -123,8 +114,7 @@ int Discarder::NextPacket(const IP_Hdr* ip, int len, int caplen)
int uh_len = sizeof (struct udphdr); int uh_len = sizeof (struct udphdr);
val_list* args = new val_list; val_list* args = new val_list;
args->append(BuildHeader(ip4)); args->append(ip->BuildPktHdrVal());
args->append(BuildHeader(up));
args->append(BuildData(data, uh_len, len, caplen)); args->append(BuildData(data, uh_len, len, caplen));
try try
@ -148,8 +138,7 @@ int Discarder::NextPacket(const IP_Hdr* ip, int len, int caplen)
const struct icmp* ih = (const struct icmp*) data; const struct icmp* ih = (const struct icmp*) data;
val_list* args = new val_list; val_list* args = new val_list;
args->append(BuildHeader(ip4)); args->append(ip->BuildPktHdrVal());
args->append(BuildHeader(ih));
try try
{ {
@ -168,62 +157,6 @@ int Discarder::NextPacket(const IP_Hdr* ip, int len, int caplen)
return discard_packet; return discard_packet;
} }
Val* Discarder::BuildHeader(const struct ip* ip)
{
RecordVal* hdr = new RecordVal(ip_hdr);
hdr->Assign(0, new Val(ip->ip_hl * 4, TYPE_COUNT));
hdr->Assign(1, new Val(ip->ip_tos, TYPE_COUNT));
hdr->Assign(2, new Val(ntohs(ip->ip_len), TYPE_COUNT));
hdr->Assign(3, new Val(ntohs(ip->ip_id), TYPE_COUNT));
hdr->Assign(4, new Val(ip->ip_ttl, TYPE_COUNT));
hdr->Assign(5, new Val(ip->ip_p, TYPE_COUNT));
hdr->Assign(6, new AddrVal(ip->ip_src.s_addr));
hdr->Assign(7, new AddrVal(ip->ip_dst.s_addr));
return hdr;
}
Val* Discarder::BuildHeader(const struct tcphdr* tp, int tcp_len)
{
RecordVal* hdr = new RecordVal(tcp_hdr);
hdr->Assign(0, new PortVal(ntohs(tp->th_sport), TRANSPORT_TCP));
hdr->Assign(1, new PortVal(ntohs(tp->th_dport), TRANSPORT_TCP));
hdr->Assign(2, new Val(uint32(ntohl(tp->th_seq)), TYPE_COUNT));
hdr->Assign(3, new Val(uint32(ntohl(tp->th_ack)), TYPE_COUNT));
int tcp_hdr_len = tp->th_off * 4;
hdr->Assign(4, new Val(tcp_hdr_len, TYPE_COUNT));
hdr->Assign(5, new Val(tcp_len - tcp_hdr_len, TYPE_COUNT));
hdr->Assign(6, new Val(tp->th_flags, TYPE_COUNT));
hdr->Assign(7, new Val(ntohs(tp->th_win), TYPE_COUNT));
return hdr;
}
Val* Discarder::BuildHeader(const struct udphdr* up)
{
RecordVal* hdr = new RecordVal(udp_hdr);
hdr->Assign(0, new PortVal(ntohs(up->uh_sport), TRANSPORT_UDP));
hdr->Assign(1, new PortVal(ntohs(up->uh_dport), TRANSPORT_UDP));
hdr->Assign(2, new Val(ntohs(up->uh_ulen), TYPE_COUNT));
return hdr;
}
Val* Discarder::BuildHeader(const struct icmp* icmp)
{
RecordVal* hdr = new RecordVal(icmp_hdr);
hdr->Assign(0, new Val(icmp->icmp_type, TYPE_COUNT));
return hdr;
}
Val* Discarder::BuildData(const u_char* data, int hdrlen, int len, int caplen) Val* Discarder::BuildData(const u_char* data, int hdrlen, int len, int caplen)
{ {
len -= hdrlen; len -= hdrlen;

View file

@ -25,17 +25,8 @@ public:
int NextPacket(const IP_Hdr* ip, int len, int caplen); int NextPacket(const IP_Hdr* ip, int len, int caplen);
protected: protected:
Val* BuildHeader(const struct ip* ip);
Val* BuildHeader(const struct tcphdr* tp, int tcp_len);
Val* BuildHeader(const struct udphdr* up);
Val* BuildHeader(const struct icmp* icmp);
Val* BuildData(const u_char* data, int hdrlen, int len, int caplen); Val* BuildData(const u_char* data, int hdrlen, int len, int caplen);
RecordType* ip_hdr;
RecordType* tcp_hdr;
RecordType* udp_hdr;
RecordType* icmp_hdr;
Func* check_ip; Func* check_ip;
Func* check_tcp; Func* check_tcp;
Func* check_udp; Func* check_udp;

View file

@ -7,7 +7,6 @@
#include "List.h" #include "List.h"
#include "BroList.h" #include "BroList.h"
#include "net_util.h"
class Func; class Func;
class FuncType; class FuncType;

View file

@ -14,6 +14,7 @@
#include "Net.h" #include "Net.h"
#include "Traverse.h" #include "Traverse.h"
#include "Trigger.h" #include "Trigger.h"
#include "IPAddr.h"
const char* expr_name(BroExprTag t) const char* expr_name(BroExprTag t)
{ {
@ -834,30 +835,30 @@ Val* BinaryExpr::StringFold(Val* v1, Val* v2) const
Val* BinaryExpr::AddrFold(Val* v1, Val* v2) const Val* BinaryExpr::AddrFold(Val* v1, Val* v2) const
{ {
addr_type a1 = v1->AsAddr(); IPAddr a1 = v1->AsAddr();
addr_type a2 = v2->AsAddr(); IPAddr a2 = v2->AsAddr();
int result = 0; int result = 0;
switch ( tag ) { switch ( tag ) {
#undef DO_FOLD
#ifdef BROv6
#define DO_FOLD(sense) { result = memcmp(a1, a2, 16) sense 0; break; }
#else
#define DO_FOLD(sense) \
{ \
a1 = ntohl(a1); \
a2 = ntohl(a2); \
result = (a1 < a2 ? -1 : (a1 == a2 ? 0 : 1)) sense 0; \
break; \
}
#endif
case EXPR_LT: DO_FOLD(<) case EXPR_LT:
case EXPR_LE: DO_FOLD(<=) result = a1 < a2;
case EXPR_EQ: DO_FOLD(==) break;
case EXPR_NE: DO_FOLD(!=) case EXPR_LE:
case EXPR_GE: DO_FOLD(>=) result = a1 < a2 || a1 == a2;
case EXPR_GT: DO_FOLD(>) break;
case EXPR_EQ:
result = a1 == a2;
break;
case EXPR_NE:
result = a1 != a2;
break;
case EXPR_GE:
result = ! ( a1 < a2 );
break;
case EXPR_GT:
result = ( ! ( a1 < a2 ) ) && ( a1 != a2 );
break;
default: default:
BadTag("BinaryExpr::AddrFold", expr_name(tag)); BadTag("BinaryExpr::AddrFold", expr_name(tag));
@ -868,20 +869,13 @@ Val* BinaryExpr::AddrFold(Val* v1, Val* v2) const
Val* BinaryExpr::SubNetFold(Val* v1, Val* v2) const Val* BinaryExpr::SubNetFold(Val* v1, Val* v2) const
{ {
subnet_type* n1 = v1->AsSubNet(); const IPPrefix& n1 = v1->AsSubNet();
subnet_type* n2 = v2->AsSubNet(); const IPPrefix& n2 = v2->AsSubNet();
if ( n1->width != n2->width ) if ( n1 == n2 )
return new Val(1, TYPE_BOOL);
else
return new Val(0, TYPE_BOOL); return new Val(0, TYPE_BOOL);
#ifdef BROv6
if ( memcmp(n1->net, n2->net, 16) )
#else
if ( n1->net != n2->net )
#endif
return new Val(0, TYPE_BOOL);
return new Val(1, TYPE_BOOL);
} }
void BinaryExpr::SwapOps() void BinaryExpr::SwapOps()
@ -1681,15 +1675,13 @@ DivideExpr::DivideExpr(Expr* arg_op1, Expr* arg_op2)
Val* DivideExpr::AddrFold(Val* v1, Val* v2) const Val* DivideExpr::AddrFold(Val* v1, Val* v2) const
{ {
addr_type a1 = v1->AsAddr();
uint32 mask; uint32 mask;
if ( v2->Type()->Tag() == TYPE_COUNT ) if ( v2->Type()->Tag() == TYPE_COUNT )
mask = static_cast<uint32>(v2->InternalUnsigned()); mask = static_cast<uint32>(v2->InternalUnsigned());
else else
mask = static_cast<uint32>(v2->InternalInt()); mask = static_cast<uint32>(v2->InternalInt());
return new SubNetVal(a1, mask); return new SubNetVal(v1->AsAddr(), mask);
} }
Expr* DivideExpr::DoSimplify() Expr* DivideExpr::DoSimplify()
@ -2672,8 +2664,6 @@ void AssignExpr::EvalIntoAggregate(const BroType* t, Val* aggr, Frame* f) const
Error("bad table insertion"); Error("bad table insertion");
TableVal* tv = aggr->AsTableVal(); TableVal* tv = aggr->AsTableVal();
const TableType* tt = tv->Type()->AsTableType();
const BroType* yt = tv->Type()->YieldType();
Val* index = op1->Eval(f); Val* index = op1->Eval(f);
Val* v = op2->Eval(f); Val* v = op2->Eval(f);
@ -3643,151 +3633,6 @@ bool FieldAssignExpr::DoUnserialize(UnserialInfo* info)
return true; return true;
} }
RecordMatchExpr::RecordMatchExpr(Expr* op1 /* record to match */,
Expr* op2 /* cases to match against */)
: BinaryExpr(EXPR_MATCH, op1, op2)
{
BroType* result_type = 0;
// Make sure the second argument is of a suitable type.
if ( ! op2->Type()->IsSet() )
{
ExprError("matching must be done against a set of match records");
return;
}
type_list* elt_types = op2->Type()->AsSetType()->Indices()->Types();
if ( ! elt_types->length() ||
(*elt_types)[0]->Tag() != TYPE_RECORD )
{
ExprError("matching must be done against a set of match records");
return;
}
RecordType* case_rec_type = (*elt_types)[0]->AsRecordType();
// NOTE: The "result" and "pred" field names are hardcoded here.
result_field_index = case_rec_type->FieldOffset("result");
if ( result_field_index < 0 )
{
ExprError("match records must have a $result field");
return;
}
result_type = case_rec_type->FieldType("result")->Ref();
// Check that pred exists, and that the first argument matches it.
if ( (pred_field_index = case_rec_type->FieldOffset("pred")) < 0 ||
case_rec_type->FieldType("pred")->Tag() != TYPE_FUNC )
{
ExprError("match records must have a $pred' field of function type");
return;
}
FuncType* pred_type = case_rec_type->FieldType("pred")->AsFuncType();
type_list* pred_arg_types = pred_type->ArgTypes()->Types();
if ( pred_arg_types->length() != 1 ||
! check_and_promote_expr(op1, (*pred_arg_types)[0]) )
ExprError("record to match does not have the same type as predicate argument");
// NOTE: The "priority" field name is hardcoded here.
if ( (priority_field_index = case_rec_type->FieldOffset("priority")) >= 0 &&
! IsArithmetic(case_rec_type->FieldType("priority")->Tag()) )
ExprError("$priority field must have a numeric type");
SetType(result_type);
}
void RecordMatchExpr::ExprDescribe(ODesc* d) const
{
if ( d->IsReadable() )
{
d->Add("match ");
op1->Describe(d);
d->Add(" using ");
op2->Describe(d);
}
}
Val* RecordMatchExpr::Fold(Val* v1, Val* v2) const
{
TableVal* match_set = v2->AsTableVal();
if ( ! match_set )
Internal("non-table in RecordMatchExpr");
Val* return_val = 0;
double highest_priority = -1e100;
ListVal* match_recs = match_set->ConvertToList(TYPE_ANY);
for ( int i = 0; i < match_recs->Length(); ++i )
{
val_list args(1);
args.append(v1->Ref());
double this_priority = 0;
// ### Get rid of the double Index if TYPE_ANY->TYPE_RECORD.
Val* v = match_recs->Index(i)->AsListVal()->Index(0);
const RecordVal* match_rec = v->AsRecordVal();
if ( ! match_rec )
Internal("Element of match set is not a record");
if ( priority_field_index >= 0 )
{
this_priority =
match_rec->Lookup(priority_field_index)->CoerceToDouble();
if ( this_priority <= highest_priority )
{
Unref(v1);
continue;
}
}
// No try/catch here; we pass exceptions upstream.
Val* pred_val =
match_rec->Lookup(pred_field_index)->AsFunc()->Call(&args);
bool is_zero = pred_val->IsZero();
Unref(pred_val);
if ( ! is_zero )
{
Val* new_return_val =
match_rec->Lookup(result_field_index);
Unref(return_val);
return_val = new_return_val->Ref();
if ( priority_field_index >= 0 )
highest_priority = this_priority;
else
break;
}
}
Unref(match_recs);
return return_val;
}
IMPLEMENT_SERIAL(RecordMatchExpr, SER_RECORD_MATCH_EXPR);
bool RecordMatchExpr::DoSerialize(SerialInfo* info) const
{
DO_SERIALIZE(SER_RECORD_MATCH_EXPR, BinaryExpr);
return SERIALIZE(pred_field_index) && SERIALIZE(result_field_index) &&
SERIALIZE(priority_field_index);
}
bool RecordMatchExpr::DoUnserialize(UnserialInfo* info)
{
DO_UNSERIALIZE(BinaryExpr);
return UNSERIALIZE(&pred_field_index) && UNSERIALIZE(&result_field_index) &&
UNSERIALIZE(&priority_field_index);
}
ArithCoerceExpr::ArithCoerceExpr(Expr* arg_op, TypeTag t) ArithCoerceExpr::ArithCoerceExpr(Expr* arg_op, TypeTag t)
: UnaryExpr(EXPR_ARITH_COERCE, arg_op) : UnaryExpr(EXPR_ARITH_COERCE, arg_op)
{ {
@ -4918,6 +4763,7 @@ Val* ListExpr::Eval(Frame* f) const
if ( ! ev ) if ( ! ev )
{ {
Error("uninitialized list value"); Error("uninitialized list value");
Unref(v);
return 0; return 0;
} }

View file

@ -823,32 +823,6 @@ protected:
string field_name; string field_name;
}; };
class RecordMatchExpr : public BinaryExpr {
public:
RecordMatchExpr(Expr* op1 /* record to match */,
Expr* op2 /* cases to match against */);
protected:
friend class Expr;
RecordMatchExpr()
{
pred_field_index = result_field_index =
priority_field_index = 0;
}
virtual Val* Fold(Val* v1, Val* v2) const;
void ExprDescribe(ODesc*) const;
DECLARE_SERIAL(RecordMatchExpr);
// The following are used to hold the field offset of
// $pred, $result, $priority, so the names only need to
// be looked up at compile-time.
int pred_field_index;
int result_field_index;
int priority_field_index;
};
class ArithCoerceExpr : public UnaryExpr { class ArithCoerceExpr : public UnaryExpr {
public: public:
ArithCoerceExpr(Expr* op, TypeTag t); ArithCoerceExpr(Expr* op, TypeTag t);

View file

@ -232,7 +232,7 @@ BroFile::~BroFile()
delete [] access; delete [] access;
delete [] cipher_buffer; delete [] cipher_buffer;
#ifdef USE_PERFTOOLS #ifdef USE_PERFTOOLS_DEBUG
heap_checker->UnIgnoreObject(this); heap_checker->UnIgnoreObject(this);
#endif #endif
} }
@ -255,7 +255,7 @@ void BroFile::Init()
cipher_ctx = 0; cipher_ctx = 0;
cipher_buffer = 0; cipher_buffer = 0;
#ifdef USE_PERFTOOLS #ifdef USE_PERFTOOLS_DEBUG
heap_checker->IgnoreObject(this); heap_checker->IgnoreObject(this);
#endif #endif
} }

View file

@ -27,21 +27,30 @@ void FragTimer::Dispatch(double t, int /* is_expire */)
FragReassembler::FragReassembler(NetSessions* arg_s, FragReassembler::FragReassembler(NetSessions* arg_s,
const IP_Hdr* ip, const u_char* pkt, const IP_Hdr* ip, const u_char* pkt,
uint32 frag_field, HashKey* k, double t) HashKey* k, double t)
: Reassembler(0, ip->DstAddr(), REASSEM_IP) : Reassembler(0, REASSEM_IP)
{ {
s = arg_s; s = arg_s;
key = k; key = k;
const struct ip* ip4 = ip->IP4_Hdr(); const struct ip* ip4 = ip->IP4_Hdr();
proto_hdr_len = ip4->ip_hl * 4; if ( ip4 )
proto_hdr = (struct ip*) new u_char[64]; // max IP header + slop {
// Don't do a structure copy - need to pick up options, too. proto_hdr_len = ip->HdrLen();
memcpy((void*) proto_hdr, (const void*) ip4, proto_hdr_len); proto_hdr = new u_char[64]; // max IP header + slop
// Don't do a structure copy - need to pick up options, too.
memcpy((void*) proto_hdr, (const void*) ip4, proto_hdr_len);
}
else
{
proto_hdr_len = ip->HdrLen() - 8; // minus length of fragment header
proto_hdr = new u_char[proto_hdr_len];
memcpy(proto_hdr, ip->IP6_Hdr(), proto_hdr_len);
}
reassembled_pkt = 0; reassembled_pkt = 0;
frag_size = 0; // flag meaning "not known" frag_size = 0; // flag meaning "not known"
next_proto = ip->NextProto();
AddFragment(t, ip, pkt, frag_field);
if ( frag_timeout != 0.0 ) if ( frag_timeout != 0.0 )
{ {
@ -50,6 +59,8 @@ FragReassembler::FragReassembler(NetSessions* arg_s,
} }
else else
expire_timer = 0; expire_timer = 0;
AddFragment(t, ip, pkt);
} }
FragReassembler::~FragReassembler() FragReassembler::~FragReassembler()
@ -60,28 +71,42 @@ FragReassembler::~FragReassembler()
delete key; delete key;
} }
void FragReassembler::AddFragment(double t, const IP_Hdr* ip, const u_char* pkt, void FragReassembler::AddFragment(double t, const IP_Hdr* ip, const u_char* pkt)
uint32 frag_field)
{ {
const struct ip* ip4 = ip->IP4_Hdr(); const struct ip* ip4 = ip->IP4_Hdr();
if ( ip4->ip_p != proto_hdr->ip_p || ip4->ip_hl != proto_hdr->ip_hl ) if ( ip4 )
{
if ( ip4->ip_p != ((const struct ip*)proto_hdr)->ip_p ||
ip4->ip_hl != ((const struct ip*)proto_hdr)->ip_hl )
// || ip4->ip_tos != proto_hdr->ip_tos // || ip4->ip_tos != proto_hdr->ip_tos
// don't check TOS, there's at least one stack that actually // don't check TOS, there's at least one stack that actually
// uses different values, and it's hard to see an associated // uses different values, and it's hard to see an associated
// attack. // attack.
s->Weird("fragment_protocol_inconsistency", ip); s->Weird("fragment_protocol_inconsistency", ip);
}
else
{
if ( ip->NextProto() != next_proto ||
ip->HdrLen() - 8 != proto_hdr_len )
s->Weird("fragment_protocol_inconsistency", ip);
// TODO: more detailed unfrag header consistency checks?
}
if ( frag_field & 0x4000 ) if ( ip->DF() )
// Linux MTU discovery for UDP can do this, for example. // Linux MTU discovery for UDP can do this, for example.
s->Weird("fragment_with_DF", ip); s->Weird("fragment_with_DF", ip);
int offset = (ntohs(ip4->ip_off) & 0x1fff) * 8; int offset = ip->FragOffset();
int len = ntohs(ip4->ip_len); int len = ip->TotalLen();
int hdr_len = proto_hdr->ip_hl * 4; int hdr_len = ip->HdrLen();
int upper_seq = offset + len - hdr_len; int upper_seq = offset + len - hdr_len;
if ( (frag_field & 0x2000) == 0 ) if ( ! offset )
// Make sure to use the first fragment header's next field.
next_proto = ip->NextProto();
if ( ! ip->MF() )
{ {
// Last fragment. // Last fragment.
if ( frag_size == 0 ) if ( frag_size == 0 )
@ -125,7 +150,7 @@ void FragReassembler::AddFragment(double t, const IP_Hdr* ip, const u_char* pkt,
void FragReassembler::Overlap(const u_char* b1, const u_char* b2, int n) void FragReassembler::Overlap(const u_char* b1, const u_char* b2, int n)
{ {
IP_Hdr proto_h((const struct ip*) proto_hdr); IP_Hdr proto_h(proto_hdr, false, proto_hdr_len);
if ( memcmp((const void*) b1, (const void*) b2, n) ) if ( memcmp((const void*) b1, (const void*) b2, n) )
s->Weird("fragment_inconsistency", &proto_h); s->Weird("fragment_inconsistency", &proto_h);
@ -157,7 +182,7 @@ void FragReassembler::BlockInserted(DataBlock* /* start_block */)
// can happen for benign reasons when we're // can happen for benign reasons when we're
// intermingling parts of two fragmented packets. // intermingling parts of two fragmented packets.
IP_Hdr proto_h((const struct ip*) proto_hdr); IP_Hdr proto_h(proto_hdr, false, proto_hdr_len);
s->Weird("fragment_size_inconsistency", &proto_h); s->Weird("fragment_size_inconsistency", &proto_h);
// We decide to analyze the contiguous portion now. // We decide to analyze the contiguous portion now.
@ -171,7 +196,7 @@ void FragReassembler::BlockInserted(DataBlock* /* start_block */)
else if ( last_block->upper > frag_size ) else if ( last_block->upper > frag_size )
{ {
IP_Hdr proto_h((const struct ip*) proto_hdr); IP_Hdr proto_h(proto_hdr, false, proto_hdr_len);
s->Weird("fragment_size_inconsistency", &proto_h); s->Weird("fragment_size_inconsistency", &proto_h);
frag_size = last_block->upper; frag_size = last_block->upper;
} }
@ -193,8 +218,7 @@ void FragReassembler::BlockInserted(DataBlock* /* start_block */)
u_char* pkt = new u_char[n]; u_char* pkt = new u_char[n];
memcpy((void*) pkt, (const void*) proto_hdr, proto_hdr_len); memcpy((void*) pkt, (const void*) proto_hdr, proto_hdr_len);
struct ip* reassem4 = (struct ip*) pkt; u_char* pkt_start = pkt;
reassem4->ip_len = htons(frag_size + proto_hdr_len);
pkt += proto_hdr_len; pkt += proto_hdr_len;
@ -214,7 +238,27 @@ void FragReassembler::BlockInserted(DataBlock* /* start_block */)
} }
delete reassembled_pkt; delete reassembled_pkt;
reassembled_pkt = new IP_Hdr(reassem4);
if ( ((const struct ip*)pkt_start)->ip_v == 4 )
{
struct ip* reassem4 = (struct ip*) pkt_start;
reassem4->ip_len = htons(frag_size + proto_hdr_len);
reassembled_pkt = new IP_Hdr(reassem4, true);
}
else if ( ((const struct ip*)pkt_start)->ip_v == 6 )
{
struct ip6_hdr* reassem6 = (struct ip6_hdr*) pkt_start;
reassem6->ip6_plen = htons(frag_size + proto_hdr_len - 40);
const IPv6_Hdr_Chain* chain = new IPv6_Hdr_Chain(reassem6, next_proto, n);
reassembled_pkt = new IP_Hdr(reassem6, true, n, chain);
}
else
{
reporter->InternalError("bad IP version in fragment reassembly");
}
DeleteTimer(); DeleteTimer();
} }

View file

@ -20,11 +20,10 @@ typedef void (FragReassembler::*frag_timer_func)(double t);
class FragReassembler : public Reassembler { class FragReassembler : public Reassembler {
public: public:
FragReassembler(NetSessions* s, const IP_Hdr* ip, const u_char* pkt, FragReassembler(NetSessions* s, const IP_Hdr* ip, const u_char* pkt,
uint32 frag_field, HashKey* k, double t); HashKey* k, double t);
~FragReassembler(); ~FragReassembler();
void AddFragment(double t, const IP_Hdr* ip, const u_char* pkt, void AddFragment(double t, const IP_Hdr* ip, const u_char* pkt);
uint32 frag_field);
void Expire(double t); void Expire(double t);
void DeleteTimer(); void DeleteTimer();
@ -37,11 +36,12 @@ protected:
void BlockInserted(DataBlock* start_block); void BlockInserted(DataBlock* start_block);
void Overlap(const u_char* b1, const u_char* b2, int n); void Overlap(const u_char* b1, const u_char* b2, int n);
struct ip* proto_hdr; u_char* proto_hdr;
IP_Hdr* reassembled_pkt; IP_Hdr* reassembled_pkt;
int proto_hdr_len; int proto_hdr_len;
NetSessions* s; NetSessions* s;
int frag_size; // size of fully reassembled fragment int frag_size; // size of fully reassembled fragment
uint16 next_proto; // first IPv6 fragment header's next proto field
HashKey* key; HashKey* key;
FragTimer* expire_timer; FragTimer* expire_timer;

View file

@ -42,6 +42,12 @@ Gnutella_Analyzer::Gnutella_Analyzer(Connection* conn)
resp_msg_state = new GnutellaMsgState(); resp_msg_state = new GnutellaMsgState();
} }
Gnutella_Analyzer::~Gnutella_Analyzer()
{
delete orig_msg_state;
delete resp_msg_state;
}
void Gnutella_Analyzer::Done() void Gnutella_Analyzer::Done()
{ {
TCP_ApplicationAnalyzer::Done(); TCP_ApplicationAnalyzer::Done();

View file

@ -35,6 +35,7 @@ public:
class Gnutella_Analyzer : public TCP_ApplicationAnalyzer { class Gnutella_Analyzer : public TCP_ApplicationAnalyzer {
public: public:
Gnutella_Analyzer(Connection* conn); Gnutella_Analyzer(Connection* conn);
~Gnutella_Analyzer();
virtual void Done (); virtual void Done ();
virtual void DeliverStream(int len, const u_char* data, bool orig); virtual void DeliverStream(int len, const u_char* data, bool orig);

View file

@ -1543,7 +1543,7 @@ void HTTP_Analyzer::HTTP_Header(int is_orig, MIME_Header* h)
} }
} }
void HTTP_Analyzer::ParseVersion(data_chunk_t ver, const uint32* host, void HTTP_Analyzer::ParseVersion(data_chunk_t ver, const IPAddr& host,
bool user_agent) bool user_agent)
{ {
int len = ver.length; int len = ver.length;

View file

@ -8,6 +8,7 @@
#include "MIME.h" #include "MIME.h"
#include "binpac_bro.h" #include "binpac_bro.h"
#include "ZIP.h" #include "ZIP.h"
#include "IPAddr.h"
enum CHUNKED_TRANSFER_STATE { enum CHUNKED_TRANSFER_STATE {
NON_CHUNKED_TRANSFER, NON_CHUNKED_TRANSFER,
@ -212,7 +213,7 @@ protected:
const BroString* UnansweredRequestMethod(); const BroString* UnansweredRequestMethod();
void ParseVersion(data_chunk_t ver, const uint32* host, bool user_agent); void ParseVersion(data_chunk_t ver, const IPAddr& host, bool user_agent);
int HTTP_ReplyCode(const char* code_str); int HTTP_ReplyCode(const char* code_str);
int ExpectReplyMessageBody(); int ExpectReplyMessageBody();

View file

@ -7,7 +7,7 @@
#include "BroString.h" #include "BroString.h"
#define UHASH_KEY_SIZE 32 #define UHASH_KEY_SIZE 36
typedef uint64 hash_t; typedef uint64 hash_t;

View file

@ -9,6 +9,8 @@
#include "Event.h" #include "Event.h"
#include "ICMP.h" #include "ICMP.h"
#include <netinet/icmp6.h>
ICMP_Analyzer::ICMP_Analyzer(Connection* c) ICMP_Analyzer::ICMP_Analyzer(Connection* c)
: TransportLayerAnalyzer(AnalyzerTag::ICMP, c) : TransportLayerAnalyzer(AnalyzerTag::ICMP, c)
{ {
@ -32,7 +34,7 @@ void ICMP_Analyzer::Done()
matcher_state.FinishEndpointMatcher(); matcher_state.FinishEndpointMatcher();
} }
void ICMP_Analyzer::DeliverPacket(int arg_len, const u_char* data, void ICMP_Analyzer::DeliverPacket(int len, const u_char* data,
bool is_orig, int seq, const IP_Hdr* ip, int caplen) bool is_orig, int seq, const IP_Hdr* ip, int caplen)
{ {
assert(ip); assert(ip);
@ -46,13 +48,33 @@ void ICMP_Analyzer::DeliverPacket(int arg_len, const u_char* data,
PacketContents(data + 8, min(len, caplen) - 8); PacketContents(data + 8, min(len, caplen) - 8);
const struct icmp* icmpp = (const struct icmp*) data; const struct icmp* icmpp = (const struct icmp*) data;
len = arg_len;
if ( ! ignore_checksums && caplen >= len && assert(caplen >= len); // Should have been caught earlier already.
icmp_checksum(icmpp, len) != 0xffff )
if ( ! ignore_checksums )
{ {
Weird("bad_ICMP_checksum"); int chksum = 0;
return;
switch ( ip->NextProto() )
{
case IPPROTO_ICMP:
chksum = icmp_checksum(icmpp, len);
break;
case IPPROTO_ICMPV6:
chksum = icmp6_checksum(icmpp, ip, len);
break;
default:
reporter->InternalError("unexpected IP proto in ICMP analyzer");
break;
}
if ( chksum != 0xffff )
{
Weird("bad_ICMP_checksum");
return;
}
} }
Conn()->SetLastTime(current_timestamp); Conn()->SetLastTime(current_timestamp);
@ -77,7 +99,13 @@ void ICMP_Analyzer::DeliverPacket(int arg_len, const u_char* data,
else else
len_stat += len; len_stat += len;
NextICMP(current_timestamp, icmpp, len, caplen, data); if ( ip->NextProto() == IPPROTO_ICMP )
NextICMP4(current_timestamp, icmpp, len, caplen, data, ip);
else if ( ip->NextProto() == IPPROTO_ICMPV6 )
NextICMP6(current_timestamp, icmpp, len, caplen, data, ip);
else
reporter->InternalError("unexpected next protocol in ICMP::DeliverPacket()");
if ( caplen >= len ) if ( caplen >= len )
ForwardPacket(len, data, is_orig, seq, ip, caplen); ForwardPacket(len, data, is_orig, seq, ip, caplen);
@ -87,26 +115,91 @@ void ICMP_Analyzer::DeliverPacket(int arg_len, const u_char* data,
false, false, true); false, false, true);
} }
void ICMP_Analyzer::NextICMP(double /* t */, const struct icmp* /* icmpp */, void ICMP_Analyzer::NextICMP4(double t, const struct icmp* icmpp, int len, int caplen,
int /* len */, int /* caplen */, const u_char*& data, const IP_Hdr* ip_hdr )
const u_char*& /* data */)
{ {
ICMPEvent(icmp_sent); switch ( icmpp->icmp_type )
{
case ICMP_ECHO:
case ICMP_ECHOREPLY:
Echo(t, icmpp, len, caplen, data, ip_hdr);
break;
case ICMP_UNREACH:
case ICMP_TIMXCEED:
Context4(t, icmpp, len, caplen, data, ip_hdr);
break;
default:
ICMPEvent(icmp_sent, icmpp, len, 0, ip_hdr);
break;
}
} }
void ICMP_Analyzer::ICMPEvent(EventHandlerPtr f) void ICMP_Analyzer::NextICMP6(double t, const struct icmp* icmpp, int len, int caplen,
const u_char*& data, const IP_Hdr* ip_hdr )
{ {
switch ( icmpp->icmp_type )
{
// Echo types.
case ICMP6_ECHO_REQUEST:
case ICMP6_ECHO_REPLY:
Echo(t, icmpp, len, caplen, data, ip_hdr);
break;
// Error messages all have the same structure for their context,
// and are handled by the same function.
case ICMP6_PARAM_PROB:
case ICMP6_TIME_EXCEEDED:
case ICMP6_PACKET_TOO_BIG:
case ICMP6_DST_UNREACH:
Context6(t, icmpp, len, caplen, data, ip_hdr);
break;
// Router related messages.
case ND_REDIRECT:
Redirect(t, icmpp, len, caplen, data, ip_hdr);
break;
case ND_ROUTER_ADVERT:
RouterAdvert(t, icmpp, len, caplen, data, ip_hdr);
break;
case ND_NEIGHBOR_ADVERT:
NeighborAdvert(t, icmpp, len, caplen, data, ip_hdr);
break;
case ND_NEIGHBOR_SOLICIT:
NeighborSolicit(t, icmpp, len, caplen, data, ip_hdr);
break;
case ND_ROUTER_SOLICIT:
case ICMP6_ROUTER_RENUMBERING:
Router(t, icmpp, len, caplen, data, ip_hdr);
break;
#if 0
// Currently not specifically implemented.
case MLD_LISTENER_QUERY:
case MLD_LISTENER_REPORT:
case MLD_LISTENER_REDUCTION:
#endif
default:
ICMPEvent(icmp_sent, icmpp, len, 1, ip_hdr);
break;
}
}
void ICMP_Analyzer::ICMPEvent(EventHandlerPtr f, const struct icmp* icmpp,
int len, int icmpv6, const IP_Hdr* ip_hdr)
{
if ( ! f ) if ( ! f )
return; return;
val_list* vl = new val_list; val_list* vl = new val_list;
vl->append(BuildConnVal()); vl->append(BuildConnVal());
vl->append(BuildICMPVal()); vl->append(BuildICMPVal(icmpp, len, icmpv6, ip_hdr));
ConnectionEvent(f, vl); ConnectionEvent(f, vl);
} }
RecordVal* ICMP_Analyzer::BuildICMPVal() RecordVal* ICMP_Analyzer::BuildICMPVal(const struct icmp* icmpp, int len,
int icmpv6, const IP_Hdr* ip_hdr)
{ {
if ( ! icmp_conn_val ) if ( ! icmp_conn_val )
{ {
@ -114,9 +207,11 @@ RecordVal* ICMP_Analyzer::BuildICMPVal()
icmp_conn_val->Assign(0, new AddrVal(Conn()->OrigAddr())); icmp_conn_val->Assign(0, new AddrVal(Conn()->OrigAddr()));
icmp_conn_val->Assign(1, new AddrVal(Conn()->RespAddr())); icmp_conn_val->Assign(1, new AddrVal(Conn()->RespAddr()));
icmp_conn_val->Assign(2, new Val(type, TYPE_COUNT)); icmp_conn_val->Assign(2, new Val(icmpp->icmp_type, TYPE_COUNT));
icmp_conn_val->Assign(3, new Val(code, TYPE_COUNT)); icmp_conn_val->Assign(3, new Val(icmpp->icmp_code, TYPE_COUNT));
icmp_conn_val->Assign(4, new Val(len, TYPE_COUNT)); icmp_conn_val->Assign(4, new Val(len, TYPE_COUNT));
icmp_conn_val->Assign(5, new Val(ip_hdr->TTL(), TYPE_COUNT));
icmp_conn_val->Assign(6, new Val(icmpv6, TYPE_BOOL));
} }
Ref(icmp_conn_val); Ref(icmp_conn_val);
@ -124,91 +219,115 @@ RecordVal* ICMP_Analyzer::BuildICMPVal()
return icmp_conn_val; return icmp_conn_val;
} }
RecordVal* ICMP_Analyzer::ExtractICMPContext(int len, const u_char*& data) TransportProto ICMP_Analyzer::GetContextProtocol(const IP_Hdr* ip_hdr, uint32* src_port, uint32* dst_port)
{ {
const struct ip* ip = (const struct ip *) data; const u_char* transport_hdr;
uint32 ip_hdr_len = ip->ip_hl * 4; uint32 ip_hdr_len = ip_hdr->HdrLen();
bool ip4 = ip_hdr->IP4_Hdr();
if ( ip4 )
transport_hdr = ((u_char *) ip_hdr->IP4_Hdr() + ip_hdr_len);
else
transport_hdr = ((u_char *) ip_hdr->IP6_Hdr() + ip_hdr_len);
TransportProto proto;
switch ( ip_hdr->NextProto() ) {
case 1: proto = TRANSPORT_ICMP; break;
case 6: proto = TRANSPORT_TCP; break;
case 17: proto = TRANSPORT_UDP; break;
case 58: proto = TRANSPORT_ICMP; break;
default: proto = TRANSPORT_UNKNOWN; break;
}
switch ( proto ) {
case TRANSPORT_ICMP:
{
const struct icmp* icmpp =
(const struct icmp *) transport_hdr;
bool is_one_way; // dummy
*src_port = ntohs(icmpp->icmp_type);
if ( ip4 )
*dst_port = ntohs(ICMP4_counterpart(icmpp->icmp_type,
icmpp->icmp_code, is_one_way));
else
*dst_port = ntohs(ICMP6_counterpart(icmpp->icmp_type,
icmpp->icmp_code, is_one_way));
break;
}
case TRANSPORT_TCP:
{
const struct tcphdr* tp =
(const struct tcphdr *) transport_hdr;
*src_port = ntohs(tp->th_sport);
*dst_port = ntohs(tp->th_dport);
break;
}
case TRANSPORT_UDP:
{
const struct udphdr* up =
(const struct udphdr *) transport_hdr;
*src_port = ntohs(up->uh_sport);
*dst_port = ntohs(up->uh_dport);
break;
}
default:
*src_port = *dst_port = ntohs(0);
break;
}
return proto;
}
RecordVal* ICMP_Analyzer::ExtractICMP4Context(int len, const u_char*& data)
{
const IP_Hdr ip_hdr_data((const struct ip*) data, false);
const IP_Hdr* ip_hdr = &ip_hdr_data;
uint32 ip_hdr_len = ip_hdr->HdrLen();
uint32 ip_len, frag_offset; uint32 ip_len, frag_offset;
TransportProto proto = TRANSPORT_UNKNOWN; TransportProto proto = TRANSPORT_UNKNOWN;
int DF, MF, bad_hdr_len, bad_checksum; int DF, MF, bad_hdr_len, bad_checksum;
uint32 src_addr, dst_addr; IPAddr src_addr, dst_addr;
uint32 src_port, dst_port; uint32 src_port, dst_port;
if ( ip_hdr_len < sizeof(struct ip) || ip_hdr_len > uint32(len) ) if ( len < (int)sizeof(struct ip) || ip_hdr_len > uint32(len) )
{ // We don't have an entire IP header. {
// We don't have an entire IP header.
bad_hdr_len = 1; bad_hdr_len = 1;
ip_len = frag_offset = 0; ip_len = frag_offset = 0;
DF = MF = bad_checksum = 0; DF = MF = bad_checksum = 0;
src_addr = dst_addr = 0;
src_port = dst_port = 0; src_port = dst_port = 0;
} }
else else
{ {
bad_hdr_len = 0; bad_hdr_len = 0;
ip_len = ntohs(ip->ip_len); ip_len = ip_hdr->TotalLen();
bad_checksum = ones_complement_checksum((void*) ip, ip_hdr_len, 0) != 0xffff; bad_checksum = (ones_complement_checksum((void*) ip_hdr->IP4_Hdr(), ip_hdr_len, 0) != 0xffff);
src_addr = uint32(ip->ip_src.s_addr); src_addr = ip_hdr->SrcAddr();
dst_addr = uint32(ip->ip_dst.s_addr); dst_addr = ip_hdr->DstAddr();
switch ( ip->ip_p ) { DF = ip_hdr->DF();
case 1: proto = TRANSPORT_ICMP; break; MF = ip_hdr->MF();
case 6: proto = TRANSPORT_TCP; break; frag_offset = ip_hdr->FragOffset();
case 17: proto = TRANSPORT_UDP; break;
// Default uses TRANSPORT_UNKNOWN, per initialization above. if ( uint32(len) >= ip_hdr_len + 4 )
} proto = GetContextProtocol(ip_hdr, &src_port, &dst_port);
else
uint32 frag_field = ntohs(ip->ip_off);
DF = frag_field & 0x4000;
MF = frag_field & 0x2000;
frag_offset = frag_field & /* IP_OFFMASK not portable */ 0x1fff;
const u_char* transport_hdr = ((u_char *) ip + ip_hdr_len);
if ( uint32(len) < ip_hdr_len + 4 )
{ {
// 4 above is the magic number meaning that both // 4 above is the magic number meaning that both
// port numbers are included in the ICMP. // port numbers are included in the ICMP.
bad_hdr_len = 1;
src_port = dst_port = 0; src_port = dst_port = 0;
bad_hdr_len = 1;
} }
switch ( proto ) {
case TRANSPORT_ICMP:
{
const struct icmp* icmpp =
(const struct icmp *) transport_hdr;
bool is_one_way; // dummy
src_port = ntohs(icmpp->icmp_type);
dst_port = ntohs(ICMP_counterpart(icmpp->icmp_type,
icmpp->icmp_code,
is_one_way));
}
break;
case TRANSPORT_TCP:
{
const struct tcphdr* tp =
(const struct tcphdr *) transport_hdr;
src_port = ntohs(tp->th_sport);
dst_port = ntohs(tp->th_dport);
}
break;
case TRANSPORT_UDP:
{
const struct udphdr* up =
(const struct udphdr *) transport_hdr;
src_port = ntohs(up->uh_sport);
dst_port = ntohs(up->uh_dport);
}
break;
default:
src_port = dst_port = ntohs(0);
}
} }
RecordVal* iprec = new RecordVal(icmp_context); RecordVal* iprec = new RecordVal(icmp_context);
@ -218,8 +337,8 @@ RecordVal* ICMP_Analyzer::ExtractICMPContext(int len, const u_char*& data)
id_val->Assign(1, new PortVal(src_port, proto)); id_val->Assign(1, new PortVal(src_port, proto));
id_val->Assign(2, new AddrVal(dst_addr)); id_val->Assign(2, new AddrVal(dst_addr));
id_val->Assign(3, new PortVal(dst_port, proto)); id_val->Assign(3, new PortVal(dst_port, proto));
iprec->Assign(0, id_val);
iprec->Assign(0, id_val);
iprec->Assign(1, new Val(ip_len, TYPE_COUNT)); iprec->Assign(1, new Val(ip_len, TYPE_COUNT));
iprec->Assign(2, new Val(proto, TYPE_COUNT)); iprec->Assign(2, new Val(proto, TYPE_COUNT));
iprec->Assign(3, new Val(frag_offset, TYPE_COUNT)); iprec->Assign(3, new Val(frag_offset, TYPE_COUNT));
@ -231,6 +350,66 @@ RecordVal* ICMP_Analyzer::ExtractICMPContext(int len, const u_char*& data)
return iprec; return iprec;
} }
RecordVal* ICMP_Analyzer::ExtractICMP6Context(int len, const u_char*& data)
{
int DF = 0, MF = 0, bad_hdr_len = 0;
TransportProto proto = TRANSPORT_UNKNOWN;
IPAddr src_addr;
IPAddr dst_addr;
uint32 ip_len, frag_offset = 0;
uint32 src_port, dst_port;
if ( len < (int)sizeof(struct ip6_hdr) )
{
bad_hdr_len = 1;
ip_len = 0;
src_port = dst_port = 0;
}
else
{
const IP_Hdr ip_hdr_data((const struct ip6_hdr*) data, false, len);
const IP_Hdr* ip_hdr = &ip_hdr_data;
ip_len = ip_hdr->TotalLen();
src_addr = ip_hdr->SrcAddr();
dst_addr = ip_hdr->DstAddr();
frag_offset = ip_hdr->FragOffset();
MF = ip_hdr->MF();
DF = ip_hdr->DF();
if ( uint32(len) >= uint32(ip_hdr->HdrLen() + 4) )
proto = GetContextProtocol(ip_hdr, &src_port, &dst_port);
else
{
// 4 above is the magic number meaning that both
// port numbers are included in the ICMP.
src_port = dst_port = 0;
bad_hdr_len = 1;
}
}
RecordVal* iprec = new RecordVal(icmp_context);
RecordVal* id_val = new RecordVal(conn_id);
id_val->Assign(0, new AddrVal(src_addr));
id_val->Assign(1, new PortVal(src_port, proto));
id_val->Assign(2, new AddrVal(dst_addr));
id_val->Assign(3, new PortVal(dst_port, proto));
iprec->Assign(0, id_val);
iprec->Assign(1, new Val(ip_len, TYPE_COUNT));
iprec->Assign(2, new Val(proto, TYPE_COUNT));
iprec->Assign(3, new Val(frag_offset, TYPE_COUNT));
iprec->Assign(4, new Val(bad_hdr_len, TYPE_BOOL));
// bad_checksum is always false since IPv6 layer doesn't have a checksum.
iprec->Assign(5, new Val(0, TYPE_BOOL));
iprec->Assign(6, new Val(MF, TYPE_BOOL));
iprec->Assign(7, new Val(DF, TYPE_BOOL));
return iprec;
}
bool ICMP_Analyzer::IsReuse(double /* t */, const u_char* /* pkt */) bool ICMP_Analyzer::IsReuse(double /* t */, const u_char* /* pkt */)
{ {
return 0; return 0;
@ -243,7 +422,7 @@ void ICMP_Analyzer::Describe(ODesc* d) const
d->Add(Conn()->LastTime()); d->Add(Conn()->LastTime());
d->AddSP(")"); d->AddSP(")");
d->Add(dotted_addr(Conn()->OrigAddr())); d->Add(Conn()->OrigAddr());
d->Add("."); d->Add(".");
d->Add(type); d->Add(type);
d->Add("."); d->Add(".");
@ -252,7 +431,7 @@ void ICMP_Analyzer::Describe(ODesc* d) const
d->SP(); d->SP();
d->AddSP("->"); d->AddSP("->");
d->Add(dotted_addr(Conn()->RespAddr())); d->Add(Conn()->RespAddr());
} }
void ICMP_Analyzer::UpdateConnVal(RecordVal *conn_val) void ICMP_Analyzer::UpdateConnVal(RecordVal *conn_val)
@ -294,15 +473,20 @@ unsigned int ICMP_Analyzer::MemoryAllocation() const
+ (icmp_conn_val ? icmp_conn_val->MemoryAllocation() : 0); + (icmp_conn_val ? icmp_conn_val->MemoryAllocation() : 0);
} }
ICMP_Echo_Analyzer::ICMP_Echo_Analyzer(Connection* c)
: ICMP_Analyzer(AnalyzerTag::ICMP_Echo, c)
{
}
void ICMP_Echo_Analyzer::NextICMP(double t, const struct icmp* icmpp, int len, void ICMP_Analyzer::Echo(double t, const struct icmp* icmpp, int len,
int caplen, const u_char*& data) int caplen, const u_char*& data, const IP_Hdr* ip_hdr)
{ {
EventHandlerPtr f = type == ICMP_ECHO ? icmp_echo_request : icmp_echo_reply; // For handling all Echo related ICMP messages
EventHandlerPtr f = 0;
if ( ip_hdr->NextProto() == IPPROTO_ICMPV6 )
f = (icmpp->icmp_type == ICMP6_ECHO_REQUEST)
? icmp_echo_request : icmp_echo_reply;
else
f = (icmpp->icmp_type == ICMP_ECHO)
? icmp_echo_request : icmp_echo_reply;
if ( ! f ) if ( ! f )
return; return;
@ -313,7 +497,7 @@ void ICMP_Echo_Analyzer::NextICMP(double t, const struct icmp* icmpp, int len,
val_list* vl = new val_list; val_list* vl = new val_list;
vl->append(BuildConnVal()); vl->append(BuildConnVal());
vl->append(BuildICMPVal()); vl->append(BuildICMPVal(icmpp, len, ip_hdr->NextProto() != IPPROTO_ICMP, ip_hdr));
vl->append(new Val(iid, TYPE_COUNT)); vl->append(new Val(iid, TYPE_COUNT));
vl->append(new Val(iseq, TYPE_COUNT)); vl->append(new Val(iseq, TYPE_COUNT));
vl->append(new StringVal(payload)); vl->append(new StringVal(payload));
@ -321,66 +505,232 @@ void ICMP_Echo_Analyzer::NextICMP(double t, const struct icmp* icmpp, int len,
ConnectionEvent(f, vl); ConnectionEvent(f, vl);
} }
ICMP_Redir_Analyzer::ICMP_Redir_Analyzer(Connection* c)
: ICMP_Analyzer(AnalyzerTag::ICMP_Redir, c)
{
}
void ICMP_Redir_Analyzer::NextICMP(double t, const struct icmp* icmpp, int len, void ICMP_Analyzer::RouterAdvert(double t, const struct icmp* icmpp, int len,
int caplen, const u_char*& data) int caplen, const u_char*& data, const IP_Hdr* ip_hdr)
{ {
uint32 addr = ntohl(icmpp->icmp_hun.ih_void); EventHandlerPtr f = icmp_router_advertisement;
uint32 reachable, retrans;
memcpy(&reachable, data, sizeof(reachable));
memcpy(&retrans, data + sizeof(reachable), sizeof(retrans));
val_list* vl = new val_list; val_list* vl = new val_list;
vl->append(BuildConnVal()); vl->append(BuildConnVal());
vl->append(BuildICMPVal()); vl->append(BuildICMPVal(icmpp, len, 1, ip_hdr));
vl->append(new AddrVal(htonl(addr))); vl->append(new Val(icmpp->icmp_num_addrs, TYPE_COUNT)); // Cur Hop Limit
vl->append(new Val(icmpp->icmp_wpa & 0x80, TYPE_BOOL)); // Managed
vl->append(new Val(icmpp->icmp_wpa & 0x40, TYPE_BOOL)); // Other
vl->append(new Val(icmpp->icmp_wpa & 0x20, TYPE_BOOL)); // Home Agent
vl->append(new Val((icmpp->icmp_wpa & 0x18)>>3, TYPE_COUNT)); // Pref
vl->append(new Val(icmpp->icmp_wpa & 0x04, TYPE_BOOL)); // Proxy
vl->append(new Val(icmpp->icmp_wpa & 0x02, TYPE_COUNT)); // Reserved
vl->append(new IntervalVal((double)ntohs(icmpp->icmp_lifetime), Seconds));
vl->append(new IntervalVal((double)ntohl(reachable), Milliseconds));
vl->append(new IntervalVal((double)ntohl(retrans), Milliseconds));
ConnectionEvent(icmp_redirect, vl); ConnectionEvent(f, vl);
} }
void ICMP_Context_Analyzer::NextICMP(double t, const struct icmp* icmpp, void ICMP_Analyzer::NeighborAdvert(double t, const struct icmp* icmpp, int len,
int len, int caplen, const u_char*& data) int caplen, const u_char*& data, const IP_Hdr* ip_hdr)
{
EventHandlerPtr f = icmp_neighbor_advertisement;
in6_addr tgtaddr;
memcpy(&tgtaddr.s6_addr, data, sizeof(tgtaddr.s6_addr));
val_list* vl = new val_list;
vl->append(BuildConnVal());
vl->append(BuildICMPVal(icmpp, len, 1, ip_hdr));
vl->append(new Val(icmpp->icmp_num_addrs & 0x80, TYPE_BOOL)); // Router
vl->append(new Val(icmpp->icmp_num_addrs & 0x40, TYPE_BOOL)); // Solicited
vl->append(new Val(icmpp->icmp_num_addrs & 0x20, TYPE_BOOL)); // Override
vl->append(new AddrVal(IPAddr(tgtaddr)));
ConnectionEvent(f, vl);
}
void ICMP_Analyzer::NeighborSolicit(double t, const struct icmp* icmpp, int len,
int caplen, const u_char*& data, const IP_Hdr* ip_hdr)
{
EventHandlerPtr f = icmp_neighbor_solicitation;
in6_addr tgtaddr;
memcpy(&tgtaddr.s6_addr, data, sizeof(tgtaddr.s6_addr));
val_list* vl = new val_list;
vl->append(BuildConnVal());
vl->append(BuildICMPVal(icmpp, len, 1, ip_hdr));
vl->append(new AddrVal(IPAddr(tgtaddr)));
ConnectionEvent(f, vl);
}
void ICMP_Analyzer::Redirect(double t, const struct icmp* icmpp, int len,
int caplen, const u_char*& data, const IP_Hdr* ip_hdr)
{
EventHandlerPtr f = icmp_redirect;
in6_addr tgtaddr, dstaddr;
memcpy(&tgtaddr.s6_addr, data, sizeof(tgtaddr.s6_addr));
memcpy(&dstaddr.s6_addr, data + sizeof(tgtaddr.s6_addr), sizeof(dstaddr.s6_addr));
val_list* vl = new val_list;
vl->append(BuildConnVal());
vl->append(BuildICMPVal(icmpp, len, 1, ip_hdr));
vl->append(new AddrVal(IPAddr(tgtaddr)));
vl->append(new AddrVal(IPAddr(dstaddr)));
ConnectionEvent(f, vl);
}
void ICMP_Analyzer::Router(double t, const struct icmp* icmpp, int len,
int caplen, const u_char*& data, const IP_Hdr* ip_hdr)
{ {
EventHandlerPtr f = 0; EventHandlerPtr f = 0;
switch ( type ) {
case ICMP_UNREACH: f = icmp_unreachable; break; switch ( icmpp->icmp_type )
case ICMP_TIMXCEED: f = icmp_time_exceeded; break; {
case ND_ROUTER_SOLICIT:
f = icmp_router_solicitation;
break;
case ICMP6_ROUTER_RENUMBERING:
default:
ICMPEvent(icmp_sent, icmpp, len, 1, ip_hdr);
return;
}
val_list* vl = new val_list;
vl->append(BuildConnVal());
vl->append(BuildICMPVal(icmpp, len, 1, ip_hdr));
ConnectionEvent(f, vl);
} }
void ICMP_Analyzer::Context4(double t, const struct icmp* icmpp,
int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr)
{
EventHandlerPtr f = 0;
switch ( icmpp->icmp_type )
{
case ICMP_UNREACH:
f = icmp_unreachable;
break;
case ICMP_TIMXCEED:
f = icmp_time_exceeded;
break;
}
if ( f ) if ( f )
{ {
val_list* vl = new val_list; val_list* vl = new val_list;
vl->append(BuildConnVal()); vl->append(BuildConnVal());
vl->append(BuildICMPVal()); vl->append(BuildICMPVal(icmpp, len, 0, ip_hdr));
vl->append(new Val(code, TYPE_COUNT)); vl->append(new Val(icmpp->icmp_code, TYPE_COUNT));
vl->append(ExtractICMPContext(caplen, data)); vl->append(ExtractICMP4Context(caplen, data));
ConnectionEvent(f, vl); ConnectionEvent(f, vl);
} }
} }
int ICMP_counterpart(int icmp_type, int icmp_code, bool& is_one_way) void ICMP_Analyzer::Context6(double t, const struct icmp* icmpp,
int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr)
{
EventHandlerPtr f = 0;
switch ( icmpp->icmp_type )
{
case ICMP6_DST_UNREACH:
f = icmp_unreachable;
break;
case ICMP6_PARAM_PROB:
f = icmp_parameter_problem;
break;
case ICMP6_TIME_EXCEEDED:
f = icmp_time_exceeded;
break;
case ICMP6_PACKET_TOO_BIG:
f = icmp_packet_too_big;
break;
}
if ( f )
{
val_list* vl = new val_list;
vl->append(BuildConnVal());
vl->append(BuildICMPVal(icmpp, len, 1, ip_hdr));
vl->append(new Val(icmpp->icmp_code, TYPE_COUNT));
vl->append(ExtractICMP6Context(caplen, data));
ConnectionEvent(f, vl);
}
}
int ICMP4_counterpart(int icmp_type, int icmp_code, bool& is_one_way)
{ {
is_one_way = false; is_one_way = false;
// return the counterpart type if one exists. This allows us // Return the counterpart type if one exists. This allows us
// to track corresponding ICMP requests/replies. // to track corresponding ICMP requests/replies.
// Note that for the two-way ICMP messages, icmp_code is // Note that for the two-way ICMP messages, icmp_code is
// always 0 (RFC 792). // always 0 (RFC 792).
switch ( icmp_type ) { switch ( icmp_type ) {
case ICMP_ECHO: return ICMP_ECHOREPLY; case ICMP_ECHO: return ICMP_ECHOREPLY;
case ICMP_ECHOREPLY: return ICMP_ECHO; case ICMP_ECHOREPLY: return ICMP_ECHO;
case ICMP_TSTAMP: return ICMP_TSTAMPREPLY; case ICMP_TSTAMP: return ICMP_TSTAMPREPLY;
case ICMP_TSTAMPREPLY: return ICMP_TSTAMP; case ICMP_TSTAMPREPLY: return ICMP_TSTAMP;
case ICMP_IREQ: return ICMP_IREQREPLY; case ICMP_IREQ: return ICMP_IREQREPLY;
case ICMP_IREQREPLY: return ICMP_IREQ; case ICMP_IREQREPLY: return ICMP_IREQ;
case ICMP_ROUTERSOLICIT: return ICMP_ROUTERADVERT; case ICMP_ROUTERSOLICIT: return ICMP_ROUTERADVERT;
case ICMP_MASKREQ: return ICMP_MASKREPLY; case ICMP_MASKREQ: return ICMP_MASKREPLY;
case ICMP_MASKREPLY: return ICMP_MASKREQ; case ICMP_MASKREPLY: return ICMP_MASKREQ;
default: is_one_way = true; return icmp_code; default: is_one_way = true; return icmp_code;
} }
} }
int ICMP6_counterpart(int icmp_type, int icmp_code, bool& is_one_way)
{
is_one_way = false;
switch ( icmp_type ) {
case ICMP6_ECHO_REQUEST: return ICMP6_ECHO_REPLY;
case ICMP6_ECHO_REPLY: return ICMP6_ECHO_REQUEST;
case ND_ROUTER_SOLICIT: return ND_ROUTER_ADVERT;
case ND_ROUTER_ADVERT: return ND_ROUTER_SOLICIT;
case ND_NEIGHBOR_SOLICIT: return ND_NEIGHBOR_ADVERT;
case ND_NEIGHBOR_ADVERT: return ND_NEIGHBOR_SOLICIT;
case MLD_LISTENER_QUERY: return MLD_LISTENER_REPORT;
case MLD_LISTENER_REPORT: return MLD_LISTENER_QUERY;
// ICMP node information query and response respectively (not defined in
// icmp6.h)
case 139: return 140;
case 140: return 139;
// Home Agent Address Discovery Request Message and reply
case 144: return 145;
case 145: return 144;
// TODO: Add further counterparts.
default: is_one_way = true; return icmp_code;
}
}

View file

@ -33,21 +33,51 @@ protected:
virtual bool IsReuse(double t, const u_char* pkt); virtual bool IsReuse(double t, const u_char* pkt);
virtual unsigned int MemoryAllocation() const; virtual unsigned int MemoryAllocation() const;
void ICMPEvent(EventHandlerPtr f); void ICMPEvent(EventHandlerPtr f, const struct icmp* icmpp, int len,
int icmpv6, const IP_Hdr* ip_hdr);
void Echo(double t, const struct icmp* icmpp, int len,
int caplen, const u_char*& data, const IP_Hdr* ip_hdr);
void Context(double t, const struct icmp* icmpp, int len,
int caplen, const u_char*& data, const IP_Hdr* ip_hdr);
void Redirect(double t, const struct icmp* icmpp, int len,
int caplen, const u_char*& data, const IP_Hdr* ip_hdr);
void RouterAdvert(double t, const struct icmp* icmpp, int len,
int caplen, const u_char*& data, const IP_Hdr* ip_hdr);
void NeighborAdvert(double t, const struct icmp* icmpp, int len,
int caplen, const u_char*& data, const IP_Hdr* ip_hdr);
void NeighborSolicit(double t, const struct icmp* icmpp, int len,
int caplen, const u_char*& data, const IP_Hdr* ip_hdr);
void Router(double t, const struct icmp* icmpp, int len,
int caplen, const u_char*& data, const IP_Hdr* ip_hdr);
void Describe(ODesc* d) const; void Describe(ODesc* d) const;
RecordVal* BuildICMPVal(); RecordVal* BuildICMPVal(const struct icmp* icmpp, int len, int icmpv6,
const IP_Hdr* ip_hdr);
virtual void NextICMP(double t, const struct icmp* icmpp, void NextICMP4(double t, const struct icmp* icmpp, int len, int caplen,
int len, int caplen, const u_char*& data); const u_char*& data, const IP_Hdr* ip_hdr );
RecordVal* ExtractICMPContext(int len, const u_char*& data); RecordVal* ExtractICMP4Context(int len, const u_char*& data);
void Context4(double t, const struct icmp* icmpp, int len, int caplen,
const u_char*& data, const IP_Hdr* ip_hdr);
TransportProto GetContextProtocol(const IP_Hdr* ip_hdr, uint32* src_port,
uint32* dst_port);
void NextICMP6(double t, const struct icmp* icmpp, int len, int caplen,
const u_char*& data, const IP_Hdr* ip_hdr );
RecordVal* ExtractICMP6Context(int len, const u_char*& data);
void Context6(double t, const struct icmp* icmpp, int len, int caplen,
const u_char*& data, const IP_Hdr* ip_hdr);
RecordVal* icmp_conn_val; RecordVal* icmp_conn_val;
int type; int type;
int code; int code;
int len;
int request_len, reply_len; int request_len, reply_len;
RuleMatcherState matcher_state; RuleMatcherState matcher_state;
@ -56,81 +86,9 @@ private:
void UpdateEndpointVal(RecordVal* endp, int is_orig); void UpdateEndpointVal(RecordVal* endp, int is_orig);
}; };
class ICMP_Echo_Analyzer : public ICMP_Analyzer {
public:
ICMP_Echo_Analyzer(Connection* conn);
static Analyzer* InstantiateAnalyzer(Connection* conn)
{ return new ICMP_Echo_Analyzer(conn); }
static bool Available() { return icmp_echo_request || icmp_echo_reply; }
protected:
ICMP_Echo_Analyzer() { }
virtual void NextICMP(double t, const struct icmp* icmpp,
int len, int caplen, const u_char*& data);
};
class ICMP_Redir_Analyzer : public ICMP_Analyzer {
public:
ICMP_Redir_Analyzer(Connection* conn);
static Analyzer* InstantiateAnalyzer(Connection* conn)
{ return new ICMP_Redir_Analyzer(conn); }
static bool Available() { return icmp_redirect; }
protected:
ICMP_Redir_Analyzer() { }
virtual void NextICMP(double t, const struct icmp* icmpp,
int len, int caplen, const u_char*& data);
};
class ICMP_Context_Analyzer : public ICMP_Analyzer {
public:
ICMP_Context_Analyzer(AnalyzerTag::Tag tag, Connection* conn)
: ICMP_Analyzer(tag, conn) { }
protected:
ICMP_Context_Analyzer() { }
virtual void NextICMP(double t, const struct icmp* icmpp,
int len, int caplen, const u_char*& data);
};
class ICMP_TimeExceeded_Analyzer : public ICMP_Context_Analyzer {
public:
ICMP_TimeExceeded_Analyzer(Connection* conn)
: ICMP_Context_Analyzer(AnalyzerTag::ICMP_TimeExceeded, conn) { }
static Analyzer* InstantiateAnalyzer(Connection* conn)
{ return new ICMP_TimeExceeded_Analyzer(conn); }
static bool Available() { return icmp_time_exceeded; }
protected:
ICMP_TimeExceeded_Analyzer() { }
};
class ICMP_Unreachable_Analyzer : public ICMP_Context_Analyzer {
public:
ICMP_Unreachable_Analyzer(Connection* conn)
: ICMP_Context_Analyzer(AnalyzerTag::ICMP_Unreachable, conn) { }
static Analyzer* InstantiateAnalyzer(Connection* conn)
{ return new ICMP_Unreachable_Analyzer(conn); }
static bool Available() { return icmp_unreachable; }
protected:
ICMP_Unreachable_Analyzer() { }
};
// Returns the counterpart type to the given type (e.g., the counterpart // Returns the counterpart type to the given type (e.g., the counterpart
// to ICMP_ECHOREPLY is ICMP_ECHO). // to ICMP_ECHOREPLY is ICMP_ECHO).
extern int ICMP_counterpart(int icmp_type, int icmp_code, bool& is_one_way); extern int ICMP4_counterpart(int icmp_type, int icmp_code, bool& is_one_way);
extern int ICMP6_counterpart(int icmp_type, int icmp_code, bool& is_one_way);
#endif #endif

View file

@ -372,7 +372,7 @@ ID* ID::Unserialize(UnserialInfo* info)
Ref(id); Ref(id);
global_scope()->Insert(id->Name(), id); global_scope()->Insert(id->Name(), id);
#ifdef USE_PERFTOOLS #ifdef USE_PERFTOOLS_DEBUG
heap_checker->IgnoreObject(id); heap_checker->IgnoreObject(id);
#endif #endif
} }

627
src/IP.cc Normal file
View file

@ -0,0 +1,627 @@
// See the file "COPYING" in the main distribution directory for copyright.
#include "IP.h"
#include "Type.h"
#include "Val.h"
#include "Var.h"
static RecordType* ip4_hdr_type = 0;
static RecordType* ip6_hdr_type = 0;
static RecordType* ip6_ext_hdr_type = 0;
static RecordType* ip6_option_type = 0;
static RecordType* ip6_hopopts_type = 0;
static RecordType* ip6_dstopts_type = 0;
static RecordType* ip6_routing_type = 0;
static RecordType* ip6_fragment_type = 0;
static RecordType* ip6_ah_type = 0;
static RecordType* ip6_esp_type = 0;
static RecordType* ip6_mob_type = 0;
static RecordType* ip6_mob_msg_type = 0;
static RecordType* ip6_mob_brr_type = 0;
static RecordType* ip6_mob_hoti_type = 0;
static RecordType* ip6_mob_coti_type = 0;
static RecordType* ip6_mob_hot_type = 0;
static RecordType* ip6_mob_cot_type = 0;
static RecordType* ip6_mob_bu_type = 0;
static RecordType* ip6_mob_back_type = 0;
static RecordType* ip6_mob_be_type = 0;
static inline RecordType* hdrType(RecordType*& type, const char* name)
{
if ( ! type )
type = internal_type(name)->AsRecordType();
return type;
}
static VectorVal* BuildOptionsVal(const u_char* data, int len)
{
VectorVal* vv = new VectorVal(new VectorType(
hdrType(ip6_option_type, "ip6_option")->Ref()));
while ( len > 0 )
{
const struct ip6_opt* opt = (const struct ip6_opt*) data;
RecordVal* rv = new RecordVal(ip6_option_type);
rv->Assign(0, new Val(opt->ip6o_type, TYPE_COUNT));
if ( opt->ip6o_type == 0 )
{
// Pad1 option
rv->Assign(1, new Val(0, TYPE_COUNT));
rv->Assign(2, new StringVal(""));
data += sizeof(uint8);
len -= sizeof(uint8);
}
else
{
// PadN or other option
uint16 off = 2 * sizeof(uint8);
rv->Assign(1, new Val(opt->ip6o_len, TYPE_COUNT));
rv->Assign(2, new StringVal(
new BroString(data + off, opt->ip6o_len, 1)));
data += opt->ip6o_len + off;
len -= opt->ip6o_len + off;
}
vv->Assign(vv->Size(), rv, 0);
}
return vv;
}
RecordVal* IPv6_Hdr::BuildRecordVal(VectorVal* chain) const
{
RecordVal* rv = 0;
switch ( type ) {
case IPPROTO_IPV6:
{
rv = new RecordVal(hdrType(ip6_hdr_type, "ip6_hdr"));
const struct ip6_hdr* ip6 = (const struct ip6_hdr*)data;
rv->Assign(0, new Val((ntohl(ip6->ip6_flow) & 0x0ff00000)>>20, TYPE_COUNT));
rv->Assign(1, new Val(ntohl(ip6->ip6_flow) & 0x000fffff, TYPE_COUNT));
rv->Assign(2, new Val(ntohs(ip6->ip6_plen), TYPE_COUNT));
rv->Assign(3, new Val(ip6->ip6_nxt, TYPE_COUNT));
rv->Assign(4, new Val(ip6->ip6_hlim, TYPE_COUNT));
rv->Assign(5, new AddrVal(IPAddr(ip6->ip6_src)));
rv->Assign(6, new AddrVal(IPAddr(ip6->ip6_dst)));
if ( ! chain )
chain = new VectorVal(new VectorType(
hdrType(ip6_ext_hdr_type, "ip6_ext_hdr")->Ref()));
rv->Assign(7, chain);
}
break;
case IPPROTO_HOPOPTS:
{
rv = new RecordVal(hdrType(ip6_hopopts_type, "ip6_hopopts"));
const struct ip6_hbh* hbh = (const struct ip6_hbh*)data;
rv->Assign(0, new Val(hbh->ip6h_nxt, TYPE_COUNT));
rv->Assign(1, new Val(hbh->ip6h_len, TYPE_COUNT));
uint16 off = 2 * sizeof(uint8);
rv->Assign(2, BuildOptionsVal(data + off, Length() - off));
}
break;
case IPPROTO_DSTOPTS:
{
rv = new RecordVal(hdrType(ip6_dstopts_type, "ip6_dstopts"));
const struct ip6_dest* dst = (const struct ip6_dest*)data;
rv->Assign(0, new Val(dst->ip6d_nxt, TYPE_COUNT));
rv->Assign(1, new Val(dst->ip6d_len, TYPE_COUNT));
uint16 off = 2 * sizeof(uint8);
rv->Assign(2, BuildOptionsVal(data + off, Length() - off));
}
break;
case IPPROTO_ROUTING:
{
rv = new RecordVal(hdrType(ip6_routing_type, "ip6_routing"));
const struct ip6_rthdr* rt = (const struct ip6_rthdr*)data;
rv->Assign(0, new Val(rt->ip6r_nxt, TYPE_COUNT));
rv->Assign(1, new Val(rt->ip6r_len, TYPE_COUNT));
rv->Assign(2, new Val(rt->ip6r_type, TYPE_COUNT));
rv->Assign(3, new Val(rt->ip6r_segleft, TYPE_COUNT));
uint16 off = 4 * sizeof(uint8);
rv->Assign(4, new StringVal(new BroString(data + off, Length() - off, 1)));
}
break;
case IPPROTO_FRAGMENT:
{
rv = new RecordVal(hdrType(ip6_fragment_type, "ip6_fragment"));
const struct ip6_frag* frag = (const struct ip6_frag*)data;
rv->Assign(0, new Val(frag->ip6f_nxt, TYPE_COUNT));
rv->Assign(1, new Val(frag->ip6f_reserved, TYPE_COUNT));
rv->Assign(2, new Val((ntohs(frag->ip6f_offlg) & 0xfff8)>>3, TYPE_COUNT));
rv->Assign(3, new Val((ntohs(frag->ip6f_offlg) & 0x0006)>>1, TYPE_COUNT));
rv->Assign(4, new Val(ntohs(frag->ip6f_offlg) & 0x0001, TYPE_BOOL));
rv->Assign(5, new Val(ntohl(frag->ip6f_ident), TYPE_COUNT));
}
break;
case IPPROTO_AH:
{
rv = new RecordVal(hdrType(ip6_ah_type, "ip6_ah"));
rv->Assign(0, new Val(((ip6_ext*)data)->ip6e_nxt, TYPE_COUNT));
rv->Assign(1, new Val(((ip6_ext*)data)->ip6e_len, TYPE_COUNT));
rv->Assign(2, new Val(ntohs(((uint16*)data)[1]), TYPE_COUNT));
rv->Assign(3, new Val(ntohl(((uint32*)data)[1]), TYPE_COUNT));
rv->Assign(4, new Val(ntohl(((uint32*)data)[2]), TYPE_COUNT));
uint16 off = 3 * sizeof(uint32);
rv->Assign(5, new StringVal(new BroString(data + off, Length() - off, 1)));
}
break;
case IPPROTO_ESP:
{
rv = new RecordVal(hdrType(ip6_esp_type, "ip6_esp"));
const uint32* esp = (const uint32*)data;
rv->Assign(0, new Val(ntohl(esp[0]), TYPE_COUNT));
rv->Assign(1, new Val(ntohl(esp[1]), TYPE_COUNT));
}
break;
#ifdef ENABLE_MOBILE_IPV6
case IPPROTO_MOBILITY:
{
rv = new RecordVal(hdrType(ip6_mob_type, "ip6_mobility_hdr"));
const struct ip6_mobility* mob = (const struct ip6_mobility*) data;
rv->Assign(0, new Val(mob->ip6mob_payload, TYPE_COUNT));
rv->Assign(1, new Val(mob->ip6mob_len, TYPE_COUNT));
rv->Assign(2, new Val(mob->ip6mob_type, TYPE_COUNT));
rv->Assign(3, new Val(mob->ip6mob_rsv, TYPE_COUNT));
rv->Assign(4, new Val(ntohs(mob->ip6mob_chksum), TYPE_COUNT));
RecordVal* msg = new RecordVal(hdrType(ip6_mob_msg_type, "ip6_mobility_msg"));
msg->Assign(0, new Val(mob->ip6mob_type, TYPE_COUNT));
uint16 off = sizeof(ip6_mobility);
const u_char* msg_data = data + off;
switch ( mob->ip6mob_type ) {
case 0:
{
RecordVal* m = new RecordVal(hdrType(ip6_mob_brr_type, "ip6_mobility_brr"));
m->Assign(0, new Val(ntohs(*((uint16*)msg_data)), TYPE_COUNT));
off += sizeof(uint16);
m->Assign(1, BuildOptionsVal(data + off, Length() - off));
msg->Assign(1, m);
}
break;
case 1:
{
RecordVal* m = new RecordVal(hdrType(ip6_mob_brr_type, "ip6_mobility_hoti"));
m->Assign(0, new Val(ntohs(*((uint16*)msg_data)), TYPE_COUNT));
m->Assign(1, new Val(ntohll(*((uint64*)(msg_data + sizeof(uint16)))), TYPE_COUNT));
off += sizeof(uint16) + sizeof(uint64);
m->Assign(2, BuildOptionsVal(data + off, Length() - off));
msg->Assign(2, m);
break;
}
case 2:
{
RecordVal* m = new RecordVal(hdrType(ip6_mob_brr_type, "ip6_mobility_coti"));
m->Assign(0, new Val(ntohs(*((uint16*)msg_data)), TYPE_COUNT));
m->Assign(1, new Val(ntohll(*((uint64*)(msg_data + sizeof(uint16)))), TYPE_COUNT));
off += sizeof(uint16) + sizeof(uint64);
m->Assign(2, BuildOptionsVal(data + off, Length() - off));
msg->Assign(3, m);
break;
}
case 3:
{
RecordVal* m = new RecordVal(hdrType(ip6_mob_brr_type, "ip6_mobility_hot"));
m->Assign(0, new Val(ntohs(*((uint16*)msg_data)), TYPE_COUNT));
m->Assign(1, new Val(ntohll(*((uint64*)(msg_data + sizeof(uint16)))), TYPE_COUNT));
m->Assign(2, new Val(ntohll(*((uint64*)(msg_data + sizeof(uint16) + sizeof(uint64)))), TYPE_COUNT));
off += sizeof(uint16) + 2 * sizeof(uint64);
m->Assign(3, BuildOptionsVal(data + off, Length() - off));
msg->Assign(4, m);
break;
}
case 4:
{
RecordVal* m = new RecordVal(hdrType(ip6_mob_brr_type, "ip6_mobility_cot"));
m->Assign(0, new Val(ntohs(*((uint16*)msg_data)), TYPE_COUNT));
m->Assign(1, new Val(ntohll(*((uint64*)(msg_data + sizeof(uint16)))), TYPE_COUNT));
m->Assign(2, new Val(ntohll(*((uint64*)(msg_data + sizeof(uint16) + sizeof(uint64)))), TYPE_COUNT));
off += sizeof(uint16) + 2 * sizeof(uint64);
m->Assign(3, BuildOptionsVal(data + off, Length() - off));
msg->Assign(5, m);
break;
}
case 5:
{
RecordVal* m = new RecordVal(hdrType(ip6_mob_brr_type, "ip6_mobility_bu"));
m->Assign(0, new Val(ntohs(*((uint16*)msg_data)), TYPE_COUNT));
m->Assign(1, new Val(ntohs(*((uint16*)(msg_data + sizeof(uint16)))) & 0x8000, TYPE_BOOL));
m->Assign(2, new Val(ntohs(*((uint16*)(msg_data + sizeof(uint16)))) & 0x4000, TYPE_BOOL));
m->Assign(3, new Val(ntohs(*((uint16*)(msg_data + sizeof(uint16)))) & 0x2000, TYPE_BOOL));
m->Assign(4, new Val(ntohs(*((uint16*)(msg_data + sizeof(uint16)))) & 0x1000, TYPE_BOOL));
m->Assign(5, new Val(ntohs(*((uint16*)(msg_data + 2*sizeof(uint16)))), TYPE_COUNT));
off += 3 * sizeof(uint16);
m->Assign(6, BuildOptionsVal(data + off, Length() - off));
msg->Assign(6, m);
break;
}
case 6:
{
RecordVal* m = new RecordVal(hdrType(ip6_mob_brr_type, "ip6_mobility_back"));
m->Assign(0, new Val(*((uint8*)msg_data), TYPE_COUNT));
m->Assign(1, new Val(*((uint8*)(msg_data + sizeof(uint8))) & 0x80, TYPE_BOOL));
m->Assign(2, new Val(ntohs(*((uint16*)(msg_data + sizeof(uint16)))), TYPE_COUNT));
m->Assign(3, new Val(ntohs(*((uint16*)(msg_data + 2*sizeof(uint16)))), TYPE_COUNT));
off += 3 * sizeof(uint16);
m->Assign(4, BuildOptionsVal(data + off, Length() - off));
msg->Assign(7, m);
break;
}
case 7:
{
RecordVal* m = new RecordVal(hdrType(ip6_mob_brr_type, "ip6_mobility_be"));
m->Assign(0, new Val(*((uint8*)msg_data), TYPE_COUNT));
const in6_addr* hoa = (const in6_addr*)(msg_data + sizeof(uint16));
m->Assign(1, new AddrVal(IPAddr(*hoa)));
off += sizeof(uint16) + sizeof(in6_addr);
m->Assign(2, BuildOptionsVal(data + off, Length() - off));
msg->Assign(8, m);
break;
}
default:
reporter->Weird(fmt("unknown_mobility_type_%d", mob->ip6mob_type));
break;
}
rv->Assign(5, msg);
}
break;
#endif //ENABLE_MOBILE_IPV6
default:
break;
}
return rv;
}
RecordVal* IP_Hdr::BuildIPHdrVal() const
{
RecordVal* rval = 0;
if ( ip4 )
{
rval = new RecordVal(hdrType(ip4_hdr_type, "ip4_hdr"));
rval->Assign(0, new Val(ip4->ip_hl * 4, TYPE_COUNT));
rval->Assign(1, new Val(ip4->ip_tos, TYPE_COUNT));
rval->Assign(2, new Val(ntohs(ip4->ip_len), TYPE_COUNT));
rval->Assign(3, new Val(ntohs(ip4->ip_id), TYPE_COUNT));
rval->Assign(4, new Val(ip4->ip_ttl, TYPE_COUNT));
rval->Assign(5, new Val(ip4->ip_p, TYPE_COUNT));
rval->Assign(6, new AddrVal(ip4->ip_src.s_addr));
rval->Assign(7, new AddrVal(ip4->ip_dst.s_addr));
}
else
{
rval = ((*ip6_hdrs)[0])->BuildRecordVal(ip6_hdrs->BuildVal());
}
return rval;
}
RecordVal* IP_Hdr::BuildPktHdrVal() const
{
static RecordType* pkt_hdr_type = 0;
static RecordType* tcp_hdr_type = 0;
static RecordType* udp_hdr_type = 0;
static RecordType* icmp_hdr_type = 0;
if ( ! pkt_hdr_type )
{
pkt_hdr_type = internal_type("pkt_hdr")->AsRecordType();
tcp_hdr_type = internal_type("tcp_hdr")->AsRecordType();
udp_hdr_type = internal_type("udp_hdr")->AsRecordType();
icmp_hdr_type = internal_type("icmp_hdr")->AsRecordType();
}
RecordVal* pkt_hdr = new RecordVal(pkt_hdr_type);
if ( ip4 )
pkt_hdr->Assign(0, BuildIPHdrVal());
else
pkt_hdr->Assign(1, BuildIPHdrVal());
// L4 header.
const u_char* data = Payload();
int proto = NextProto();
switch ( proto ) {
case IPPROTO_TCP:
{
const struct tcphdr* tp = (const struct tcphdr*) data;
RecordVal* tcp_hdr = new RecordVal(tcp_hdr_type);
int tcp_hdr_len = tp->th_off * 4;
int data_len = PayloadLen() - tcp_hdr_len;
tcp_hdr->Assign(0, new PortVal(ntohs(tp->th_sport), TRANSPORT_TCP));
tcp_hdr->Assign(1, new PortVal(ntohs(tp->th_dport), TRANSPORT_TCP));
tcp_hdr->Assign(2, new Val(uint32(ntohl(tp->th_seq)), TYPE_COUNT));
tcp_hdr->Assign(3, new Val(uint32(ntohl(tp->th_ack)), TYPE_COUNT));
tcp_hdr->Assign(4, new Val(tcp_hdr_len, TYPE_COUNT));
tcp_hdr->Assign(5, new Val(data_len, TYPE_COUNT));
tcp_hdr->Assign(6, new Val(tp->th_flags, TYPE_COUNT));
tcp_hdr->Assign(7, new Val(ntohs(tp->th_win), TYPE_COUNT));
pkt_hdr->Assign(2, tcp_hdr);
break;
}
case IPPROTO_UDP:
{
const struct udphdr* up = (const struct udphdr*) data;
RecordVal* udp_hdr = new RecordVal(udp_hdr_type);
udp_hdr->Assign(0, new PortVal(ntohs(up->uh_sport), TRANSPORT_UDP));
udp_hdr->Assign(1, new PortVal(ntohs(up->uh_dport), TRANSPORT_UDP));
udp_hdr->Assign(2, new Val(ntohs(up->uh_ulen), TYPE_COUNT));
pkt_hdr->Assign(3, udp_hdr);
break;
}
case IPPROTO_ICMP:
{
const struct icmp* icmpp = (const struct icmp *) data;
RecordVal* icmp_hdr = new RecordVal(icmp_hdr_type);
icmp_hdr->Assign(0, new Val(icmpp->icmp_type, TYPE_COUNT));
pkt_hdr->Assign(4, icmp_hdr);
break;
}
default:
{
// This is not a protocol we understand.
break;
}
}
return pkt_hdr;
}
static inline bool isIPv6ExtHeader(uint8 type)
{
switch (type) {
case IPPROTO_HOPOPTS:
case IPPROTO_ROUTING:
case IPPROTO_DSTOPTS:
case IPPROTO_FRAGMENT:
case IPPROTO_AH:
case IPPROTO_ESP:
#ifdef ENABLE_MOBILE_IPV6
case IPPROTO_MOBILITY:
#endif
return true;
default:
return false;
}
}
void IPv6_Hdr_Chain::Init(const struct ip6_hdr* ip6, int total_len,
bool set_next, uint16 next)
{
length = 0;
uint8 current_type, next_type;
next_type = IPPROTO_IPV6;
const u_char* hdrs = (const u_char*) ip6;
if ( total_len < (int)sizeof(struct ip6_hdr) )
reporter->InternalError("IPv6_HdrChain::Init with truncated IP header");
do
{
// We can't determine a given header's length if there's less than
// two bytes of data available (2nd byte of extension headers is length)
if ( total_len < 2 )
return;
current_type = next_type;
IPv6_Hdr* p = new IPv6_Hdr(current_type, hdrs);
next_type = p->NextHdr();
uint16 cur_len = p->Length();
// If this header is truncated, don't add it to chain, don't go further.
if ( cur_len > total_len )
{
delete p;
return;
}
if ( set_next && next_type == IPPROTO_FRAGMENT )
{
p->ChangeNext(next);
next_type = next;
}
chain.push_back(p);
// Check for routing headers and remember final destination address.
if ( current_type == IPPROTO_ROUTING )
ProcessRoutingHeader((const struct ip6_rthdr*) hdrs, cur_len);
#ifdef ENABLE_MOBILE_IPV6
// Only Mobile IPv6 has a destination option we care about right now.
if ( current_type == IPPROTO_DSTOPTS )
ProcessDstOpts((const struct ip6_dest*) hdrs, cur_len);
#endif
hdrs += cur_len;
length += cur_len;
total_len -= cur_len;
} while ( current_type != IPPROTO_FRAGMENT &&
current_type != IPPROTO_ESP &&
#ifdef ENABLE_MOBILE_IPV6
current_type != IPPROTO_MOBILITY &&
#endif
isIPv6ExtHeader(next_type) );
}
void IPv6_Hdr_Chain::ProcessRoutingHeader(const struct ip6_rthdr* r, uint16 len)
{
if ( finalDst )
{
// RFC 2460 section 4.1 says Routing should occur at most once.
reporter->Weird(SrcAddr(), DstAddr(), "multiple_routing_headers");
return;
}
// Last 16 bytes of header (for all known types) is the address we want.
const in6_addr* addr = (const in6_addr*)(((const u_char*)r) + len - 16);
switch ( r->ip6r_type ) {
case 0: // Defined by RFC 2460, deprecated by RFC 5095
{
if ( r->ip6r_segleft > 0 && r->ip6r_len >= 2 )
{
if ( r->ip6r_len % 2 == 0 )
finalDst = new IPAddr(*addr);
else
reporter->Weird(SrcAddr(), DstAddr(), "odd_routing0_len");
}
// Always raise a weird since this type is deprecated.
reporter->Weird(SrcAddr(), DstAddr(), "routing0_hdr");
}
break;
#ifdef ENABLE_MOBILE_IPV6
case 2: // Defined by Mobile IPv6 RFC 6275.
{
if ( r->ip6r_segleft > 0 )
{
if ( r->ip6r_len == 2 )
finalDst = new IPAddr(*addr);
else
reporter->Weird(SrcAddr(), DstAddr(), "bad_routing2_len");
}
}
break;
#endif
default:
reporter->Weird(fmt("unknown_routing_type_%d", r->ip6r_type));
break;
}
}
#ifdef ENABLE_MOBILE_IPV6
void IPv6_Hdr_Chain::ProcessDstOpts(const struct ip6_dest* d, uint16 len)
{
const u_char* data = (const u_char*) d;
len -= 2 * sizeof(uint8);
data += 2* sizeof(uint8);
while ( len > 0 )
{
const struct ip6_opt* opt = (const struct ip6_opt*) data;
switch ( opt->ip6o_type ) {
case 201: // Home Address Option, Mobile IPv6 RFC 6275 section 6.3
{
if ( opt->ip6o_len == 16 )
if ( homeAddr )
reporter->Weird(SrcAddr(), DstAddr(), "multiple_home_addr_opts");
else
homeAddr = new IPAddr(*((const in6_addr*)(data + 2)));
else
reporter->Weird(SrcAddr(), DstAddr(), "bad_home_addr_len");
}
break;
default:
break;
}
if ( opt->ip6o_type == 0 )
{
data += sizeof(uint8);
len -= sizeof(uint8);
}
else
{
data += 2 * sizeof(uint8) + opt->ip6o_len;
len -= 2 * sizeof(uint8) + opt->ip6o_len;
}
}
}
#endif
VectorVal* IPv6_Hdr_Chain::BuildVal() const
{
if ( ! ip6_ext_hdr_type )
{
ip6_ext_hdr_type = internal_type("ip6_ext_hdr")->AsRecordType();
ip6_hopopts_type = internal_type("ip6_hopopts")->AsRecordType();
ip6_dstopts_type = internal_type("ip6_dstopts")->AsRecordType();
ip6_routing_type = internal_type("ip6_routing")->AsRecordType();
ip6_fragment_type = internal_type("ip6_fragment")->AsRecordType();
ip6_ah_type = internal_type("ip6_ah")->AsRecordType();
ip6_esp_type = internal_type("ip6_esp")->AsRecordType();
ip6_mob_type = internal_type("ip6_mobility_hdr")->AsRecordType();
}
VectorVal* rval = new VectorVal(new VectorType(ip6_ext_hdr_type->Ref()));
for ( size_t i = 1; i < chain.size(); ++i )
{
RecordVal* v = chain[i]->BuildRecordVal();
RecordVal* ext_hdr = new RecordVal(ip6_ext_hdr_type);
uint8 type = chain[i]->Type();
ext_hdr->Assign(0, new Val(type, TYPE_COUNT));
switch (type) {
case IPPROTO_HOPOPTS:
ext_hdr->Assign(1, v);
break;
case IPPROTO_DSTOPTS:
ext_hdr->Assign(2, v);
break;
case IPPROTO_ROUTING:
ext_hdr->Assign(3, v);
break;
case IPPROTO_FRAGMENT:
ext_hdr->Assign(4, v);
break;
case IPPROTO_AH:
ext_hdr->Assign(5, v);
break;
case IPPROTO_ESP:
ext_hdr->Assign(6, v);
break;
#ifdef ENABLE_MOBILE_IPV6
case IPPROTO_MOBILITY:
ext_hdr->Assign(7, v);
break;
#endif
default:
reporter->InternalError("IPv6_Hdr_Chain bad header %d", type);
break;
}
rval->Assign(rval->Size(), ext_hdr, 0);
}
return rval;
}

568
src/IP.h
View file

@ -4,67 +4,370 @@
#define ip_h #define ip_h
#include "config.h" #include "config.h"
#include "net_util.h"
#include "IPAddr.h"
#include "Reporter.h"
#include "Val.h"
#include "Type.h"
#include <vector>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <net_util.h> #ifdef ENABLE_MOBILE_IPV6
#ifndef IPPROTO_MOBILITY
#define IPPROTO_MOBILITY 135
#endif
struct ip6_mobility {
uint8 ip6mob_payload;
uint8 ip6mob_len;
uint8 ip6mob_type;
uint8 ip6mob_rsv;
uint16 ip6mob_chksum;
};
#endif //ENABLE_MOBILE_IPV6
/**
* Base class for IPv6 header/extensions.
*/
class IPv6_Hdr {
public:
/**
* Construct an IPv6 header or extension header from assigned type number.
*/
IPv6_Hdr(uint8 t, const u_char* d) : type(t), data(d) {}
/**
* Replace the value of the next protocol field.
*/
void ChangeNext(uint8 next_type)
{
switch ( type ) {
case IPPROTO_IPV6:
((ip6_hdr*)data)->ip6_nxt = next_type;
break;
case IPPROTO_HOPOPTS:
case IPPROTO_DSTOPTS:
case IPPROTO_ROUTING:
case IPPROTO_FRAGMENT:
case IPPROTO_AH:
#ifdef ENABLE_MOBILE_IPV6
case IPPROTO_MOBILITY:
#endif
((ip6_ext*)data)->ip6e_nxt = next_type;
break;
case IPPROTO_ESP:
default:
break;
}
}
~IPv6_Hdr() {}
/**
* Returns the assigned IPv6 extension header type number of the header
* that immediately follows this one.
*/
uint8 NextHdr() const
{
switch ( type ) {
case IPPROTO_IPV6:
return ((ip6_hdr*)data)->ip6_nxt;
case IPPROTO_HOPOPTS:
case IPPROTO_DSTOPTS:
case IPPROTO_ROUTING:
case IPPROTO_FRAGMENT:
case IPPROTO_AH:
#ifdef ENABLE_MOBILE_IPV6
case IPPROTO_MOBILITY:
#endif
return ((ip6_ext*)data)->ip6e_nxt;
case IPPROTO_ESP:
default:
return IPPROTO_NONE;
}
}
/**
* Returns the length of the header in bytes.
*/
uint16 Length() const
{
switch ( type ) {
case IPPROTO_IPV6:
return 40;
case IPPROTO_HOPOPTS:
case IPPROTO_DSTOPTS:
case IPPROTO_ROUTING:
#ifdef ENABLE_MOBILE_IPV6
case IPPROTO_MOBILITY:
#endif
return 8 + 8 * ((ip6_ext*)data)->ip6e_len;
case IPPROTO_FRAGMENT:
return 8;
case IPPROTO_AH:
return 8 + 4 * ((ip6_ext*)data)->ip6e_len;
case IPPROTO_ESP:
return 8; //encrypted payload begins after 8 bytes
default:
return 0;
}
}
/**
* Returns the RFC 1700 et seq. IANA assigned number for the header.
*/
uint8 Type() const { return type; }
/**
* Returns pointer to the start of where header structure resides in memory.
*/
const u_char* Data() const { return data; }
/**
* Returns the script-layer record representation of the header.
*/
RecordVal* BuildRecordVal(VectorVal* chain = 0) const;
protected:
uint8 type;
const u_char* data;
};
class IPv6_Hdr_Chain {
public:
/**
* Initializes the header chain from an IPv6 header structure.
*/
IPv6_Hdr_Chain(const struct ip6_hdr* ip6, int len) :
#ifdef ENABLE_MOBILE_IPV6
homeAddr(0),
#endif
finalDst(0)
{ Init(ip6, len, false); }
~IPv6_Hdr_Chain()
{
for ( size_t i = 0; i < chain.size(); ++i ) delete chain[i];
#ifdef ENABLE_MOBILE_IPV6
delete homeAddr;
#endif
delete finalDst;
}
/**
* Returns the number of headers in the chain.
*/
size_t Size() const { return chain.size(); }
/**
* Returns the sum of the length of all headers in the chain in bytes.
*/
uint16 TotalLength() const { return length; }
/**
* Accesses the header at the given location in the chain.
*/
const IPv6_Hdr* operator[](const size_t i) const { return chain[i]; }
/**
* Returns whether the header chain indicates a fragmented packet.
*/
bool IsFragment() const
{ return chain[chain.size()-1]->Type() == IPPROTO_FRAGMENT; }
/**
* Returns pointer to fragment header structure if the chain contains one.
*/
const struct ip6_frag* GetFragHdr() const
{ return IsFragment() ?
(const struct ip6_frag*)chain[chain.size()-1]->Data(): 0; }
/**
* If the header chain is a fragment, returns the offset in number of bytes
* relative to the start of the Fragmentable Part of the original packet.
*/
uint16 FragOffset() const
{ return IsFragment() ?
(ntohs(GetFragHdr()->ip6f_offlg) & 0xfff8) : 0; }
/**
* If the header chain is a fragment, returns the identification field.
*/
uint32 ID() const
{ return IsFragment() ? ntohl(GetFragHdr()->ip6f_ident) : 0; }
/**
* If the header chain is a fragment, returns the M (more fragments) flag.
*/
int MF() const
{ return IsFragment() ?
(ntohs(GetFragHdr()->ip6f_offlg) & 0x0001) != 0 : 0; }
/**
* If the chain contains a Destination Options header with a Home Address
* option as defined by Mobile IPv6 (RFC 6275), then return it, else
* return the source address in the main IPv6 header.
*/
IPAddr SrcAddr() const
{
#ifdef ENABLE_MOBILE_IPV6
if ( homeAddr )
return IPAddr(*homeAddr);
else
#endif
return IPAddr(((const struct ip6_hdr*)(chain[0]->Data()))->ip6_src);
}
/**
* If the chain contains a Routing header with non-zero segments left,
* then return the last address of the first such header, else return
* the destination address of the main IPv6 header.
*/
IPAddr DstAddr() const
{
if ( finalDst )
return IPAddr(*finalDst);
else
return IPAddr(((const struct ip6_hdr*)(chain[0]->Data()))->ip6_dst);
}
/**
* Returns a vector of ip6_ext_hdr RecordVals that includes script-layer
* representation of all extension headers in the chain.
*/
VectorVal* BuildVal() const;
protected:
// for access to protected ctor that changes next header values that
// point to a fragment
friend class FragReassembler;
/**
* Initializes the header chain from an IPv6 header structure, and replaces
* the first next protocol pointer field that points to a fragment header.
*/
IPv6_Hdr_Chain(const struct ip6_hdr* ip6, uint16 next, int len) :
#ifdef ENABLE_MOBILE_IPV6
homeAddr(0),
#endif
finalDst(0)
{ Init(ip6, len, true, next); }
/**
* Initializes the header chain from an IPv6 header structure of a given
* length, possibly setting the first next protocol pointer field that
* points to a fragment header.
*/
void Init(const struct ip6_hdr* ip6, int total_len, bool set_next,
uint16 next = 0);
/**
* Process a routing header and allocate/remember the final destination
* address if it has segments left and is a valid routing header.
*/
void ProcessRoutingHeader(const struct ip6_rthdr* r, uint16 len);
#ifdef ENABLE_MOBILE_IPV6
/**
* Inspect a Destination Option header's options for things we need to
* remember, such as the Home Address option from Mobile IPv6.
*/
void ProcessDstOpts(const struct ip6_dest* d, uint16 len);
#endif
vector<IPv6_Hdr*> chain;
/**
* The summation of all header lengths in the chain in bytes.
*/
uint16 length;
#ifdef ENABLE_MOBILE_IPV6
/**
* Home Address of the packet's source as defined by Mobile IPv6 (RFC 6275).
*/
IPAddr* homeAddr;
#endif
/**
* The final destination address in chain's first Routing header that has
* non-zero segments left.
*/
IPAddr* finalDst;
};
/**
* A class that wraps either an IPv4 or IPv6 packet and abstracts methods
* for inquiring about common features between the two.
*/
class IP_Hdr { class IP_Hdr {
public: public:
IP_Hdr(struct ip* arg_ip4) /**
* Attempts to construct the header from some blob of data based on IP
* version number. Caller must have already checked that the header
* is not truncated.
* @param p pointer to memory containing an IPv4 or IPv6 packet.
* @param arg_del whether to take ownership of \a p pointer's memory.
* @param len the length of data, in bytes, pointed to by \a p.
*/
IP_Hdr(const u_char* p, bool arg_del, int len)
: ip4(0), ip6(0), del(arg_del), ip6_hdrs(0)
{ {
ip4 = arg_ip4; if ( ((const struct ip*)p)->ip_v == 4 )
ip6 = 0; ip4 = (const struct ip*)p;
del = 1; else if ( ((const struct ip*)p)->ip_v == 6 )
{
#ifdef BROv6 ip6 = (const struct ip6_hdr*)p;
src_addr[0] = src_addr[1] = src_addr[2] = 0; ip6_hdrs = new IPv6_Hdr_Chain(ip6, len);
dst_addr[0] = dst_addr[1] = dst_addr[2] = 0; }
else
src_addr[3] = ip4->ip_src.s_addr; {
dst_addr[3] = ip4->ip_dst.s_addr; if ( arg_del )
#endif delete [] p;
reporter->InternalError("bad IP version in IP_Hdr ctor");
}
} }
IP_Hdr(const struct ip* arg_ip4) /**
* Construct the header wrapper from an IPv4 packet. Caller must have
* already checked that the header is not truncated.
* @param arg_ip4 pointer to memory containing an IPv4 packet.
* @param arg_del whether to take ownership of \a arg_ip4 pointer's memory.
*/
IP_Hdr(const struct ip* arg_ip4, bool arg_del)
: ip4(arg_ip4), ip6(0), del(arg_del), ip6_hdrs(0)
{ {
ip4 = arg_ip4;
ip6 = 0;
del = 0;
#ifdef BROv6
src_addr[0] = src_addr[1] = src_addr[2] = 0;
dst_addr[0] = dst_addr[1] = dst_addr[2] = 0;
src_addr[3] = ip4->ip_src.s_addr;
dst_addr[3] = ip4->ip_dst.s_addr;
#endif
} }
IP_Hdr(struct ip6_hdr* arg_ip6) /**
* Construct the header wrapper from an IPv6 packet. Caller must have
* already checked that the static IPv6 header is not truncated. If
* the packet contains extension headers and they are truncated, that can
* be checked afterwards by comparing \a len with \a TotalLen. E.g.
* NetSessions::DoNextPacket does this to skip truncated packets.
* @param arg_ip6 pointer to memory containing an IPv6 packet.
* @param arg_del whether to take ownership of \a arg_ip6 pointer's memory.
* @param len the packet's length in bytes.
* @param c an already-constructed header chain to take ownership of.
*/
IP_Hdr(const struct ip6_hdr* arg_ip6, bool arg_del, int len,
const IPv6_Hdr_Chain* c = 0)
: ip4(0), ip6(arg_ip6), del(arg_del),
ip6_hdrs(c ? c : new IPv6_Hdr_Chain(ip6, len))
{ {
ip4 = 0;
ip6 = arg_ip6;
del = 1;
#ifdef BROv6
memcpy(src_addr, ip6->ip6_src.s6_addr, 16);
memcpy(dst_addr, ip6->ip6_dst.s6_addr, 16);
#endif
}
IP_Hdr(const struct ip6_hdr* arg_ip6)
{
ip4 = 0;
ip6 = arg_ip6;
del = 0;
#ifdef BROv6
memcpy(src_addr, ip6->ip6_src.s6_addr, 16);
memcpy(dst_addr, ip6->ip6_dst.s6_addr, 16);
#endif
} }
/**
* Destructor.
*/
~IP_Hdr() ~IP_Hdr()
{ {
if ( ip6 )
delete ip6_hdrs;
if ( del ) if ( del )
{ {
if ( ip4 ) if ( ip4 )
@ -74,68 +377,175 @@ public:
} }
} }
/**
* If an IPv4 packet is wrapped, return a pointer to it, else null.
*/
const struct ip* IP4_Hdr() const { return ip4; } const struct ip* IP4_Hdr() const { return ip4; }
/**
* If an IPv6 packet is wrapped, return a pointer to it, else null.
*/
const struct ip6_hdr* IP6_Hdr() const { return ip6; } const struct ip6_hdr* IP6_Hdr() const { return ip6; }
#ifdef BROv6 /**
const uint32* SrcAddr() const { return src_addr; } * Returns the source address held in the IP header.
const uint32* DstAddr() const { return dst_addr; } */
#else IPAddr IPHeaderSrcAddr() const
const uint32* SrcAddr() const { return ip4 ? IPAddr(ip4->ip_src) : IPAddr(ip6->ip6_src); }
{ return ip4 ? &(ip4->ip_src.s_addr) : 0; }
const uint32* DstAddr() const
{ return ip4 ? &(ip4->ip_dst.s_addr) : 0; }
#endif
uint32 SrcAddr4() const { return ip4->ip_src.s_addr; } /**
uint32 DstAddr4() const { return ip4->ip_dst.s_addr; } * Returns the destination address held in the IP header.
*/
IPAddr IPHeaderDstAddr() const
{ return ip4 ? IPAddr(ip4->ip_dst) : IPAddr(ip6->ip6_dst); }
uint16 ID4() const { return ip4 ? ip4->ip_id : 0; } /**
* For IPv4 or IPv6 headers that don't contain a Home Address option
* (Mobile IPv6, RFC 6275), return source address held in the IP header.
* For IPv6 headers that contain a Home Address option, return that address.
*/
IPAddr SrcAddr() const
{ return ip4 ? IPAddr(ip4->ip_src) : ip6_hdrs->SrcAddr(); }
/**
* For IPv4 or IPv6 headers that don't contain a Routing header with
* non-zero segments left, return destination address held in the IP header.
* For IPv6 headers with a Routing header that has non-zero segments left,
* return the last address in the first such Routing header.
*/
IPAddr DstAddr() const
{ return ip4 ? IPAddr(ip4->ip_dst) : ip6_hdrs->DstAddr(); }
/**
* Returns a pointer to the payload of the IP packet, usually an
* upper-layer protocol.
*/
const u_char* Payload() const const u_char* Payload() const
{ {
if ( ip4 ) if ( ip4 )
return ((const u_char*) ip4) + ip4->ip_hl * 4; return ((const u_char*) ip4) + ip4->ip_hl * 4;
else else
return ((const u_char*) ip6) + 40; return ((const u_char*) ip6) + ip6_hdrs->TotalLength();
} }
#ifdef ENABLE_MOBILE_IPV6
/**
* Returns a pointer to the mobility header of the IP packet, if present,
* else a null pointer.
*/
const ip6_mobility* MobilityHeader() const
{
if ( ip4 )
return 0;
else if ( (*ip6_hdrs)[ip6_hdrs->Size()-1]->Type() != IPPROTO_MOBILITY )
return 0;
else
return (const ip6_mobility*)(*ip6_hdrs)[ip6_hdrs->Size()-1]->Data();
}
#endif
/**
* Returns the length of the IP packet's payload (length of packet minus
* header length or, for IPv6, also minus length of all extension headers).
*/
uint16 PayloadLen() const uint16 PayloadLen() const
{ {
if ( ip4 ) if ( ip4 )
return ntohs(ip4->ip_len) - ip4->ip_hl * 4; return ntohs(ip4->ip_len) - ip4->ip_hl * 4;
else else
return ntohs(ip6->ip6_plen); return ntohs(ip6->ip6_plen) + 40 - ip6_hdrs->TotalLength();
} }
uint16 TotalLen() const /**
{ * Returns the length of the IP packet (length of headers and payload).
if ( ip4 ) */
return ntohs(ip4->ip_len); uint32 TotalLen() const
else { return ip4 ? ntohs(ip4->ip_len) : ntohs(ip6->ip6_plen) + 40; }
return ntohs(ip6->ip6_plen) + 40;
}
uint16 HdrLen() const { return ip4 ? ip4->ip_hl * 4 : 40; } /**
* Returns length of IP packet header (includes extension headers for IPv6).
*/
uint16 HdrLen() const
{ return ip4 ? ip4->ip_hl * 4 : ip6_hdrs->TotalLength(); }
/**
* For IPv6 header chains, returns the type of the last header in the chain.
*/
uint8 LastHeader() const
{ return ip4 ? IPPROTO_RAW :
((*ip6_hdrs)[ip6_hdrs->Size()-1])->Type(); }
/**
* Returns the protocol type of the IP packet's payload, usually an
* upper-layer protocol. For IPv6, this returns the last (extension)
* header's Next Header value.
*/
unsigned char NextProto() const unsigned char NextProto() const
{ return ip4 ? ip4->ip_p : ip6->ip6_nxt; } { return ip4 ? ip4->ip_p :
((*ip6_hdrs)[ip6_hdrs->Size()-1])->NextHdr(); }
/**
* Returns the IPv4 Time to Live or IPv6 Hop Limit field.
*/
unsigned char TTL() const unsigned char TTL() const
{ return ip4 ? ip4->ip_ttl : ip6->ip6_hlim; } { return ip4 ? ip4->ip_ttl : ip6->ip6_hlim; }
uint16 FragField() const
{ return ntohs(ip4 ? ip4->ip_off : 0); } /**
* Returns whether the IP header indicates this packet is a fragment.
*/
bool IsFragment() const
{ return ip4 ? (ntohs(ip4->ip_off) & 0x3fff) != 0 :
ip6_hdrs->IsFragment(); }
/**
* Returns the fragment packet's offset in relation to the original
* packet in bytes.
*/
uint16 FragOffset() const
{ return ip4 ? (ntohs(ip4->ip_off) & 0x1fff) * 8 :
ip6_hdrs->FragOffset(); }
/**
* Returns the fragment packet's identification field.
*/
uint32 ID() const
{ return ip4 ? ntohs(ip4->ip_id) : ip6_hdrs->ID(); }
/**
* Returns whether a fragment packet's "More Fragments" field is set.
*/
int MF() const
{ return ip4 ? (ntohs(ip4->ip_off) & 0x2000) != 0 : ip6_hdrs->MF(); }
/**
* Returns whether a fragment packet's "Don't Fragment" field is set.
* Note that IPv6 has no such field.
*/
int DF() const int DF() const
{ return ip4 ? ((ntohs(ip4->ip_off) & IP_DF) != 0) : 0; } { return ip4 ? ((ntohs(ip4->ip_off) & 0x4000) != 0) : 0; }
uint16 IP_ID() const
{ return ip4 ? (ntohs(ip4->ip_id)) : 0; } /**
* Returns number of IP headers in packet (includes IPv6 extension headers).
*/
size_t NumHeaders() const
{ return ip4 ? 1 : ip6_hdrs->Size(); }
/**
* Returns an ip_hdr or ip6_hdr_chain RecordVal.
*/
RecordVal* BuildIPHdrVal() const;
/**
* Returns a pkt_hdr RecordVal, which includes not only the IP header, but
* also upper-layer (tcp/udp/icmp) headers.
*/
RecordVal* BuildPktHdrVal() const;
private: private:
const struct ip* ip4; const struct ip* ip4;
const struct ip6_hdr* ip6; const struct ip6_hdr* ip6;
#ifdef BROv6 bool del;
uint32 src_addr[NUM_ADDR_WORDS]; const IPv6_Hdr_Chain* ip6_hdrs;
uint32 dst_addr[NUM_ADDR_WORDS];
#endif
int del;
}; };
#endif #endif

286
src/IPAddr.cc Normal file
View file

@ -0,0 +1,286 @@
// See the file "COPYING" in the main distribution directory for copyright.
#include <string>
#include <vector>
#include "IPAddr.h"
#include "Reporter.h"
#include "Conn.h"
#include "DPM.h"
#include "bro_inet_ntop.h"
const uint8_t IPAddr::v4_mapped_prefix[12] = { 0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0xff, 0xff };
HashKey* BuildConnIDHashKey(const ConnID& id)
{
struct {
in6_addr ip1;
in6_addr ip2;
uint16 port1;
uint16 port2;
} key;
// Lookup up connection based on canonical ordering, which is
// the smaller of <src addr, src port> and <dst addr, dst port>
// followed by the other.
if ( id.is_one_way ||
addr_port_canon_lt(id.src_addr, id.src_port, id.dst_addr, id.dst_port)
)
{
key.ip1 = id.src_addr.in6;
key.ip2 = id.dst_addr.in6;
key.port1 = id.src_port;
key.port2 = id.dst_port;
}
else
{
key.ip1 = id.dst_addr.in6;
key.ip2 = id.src_addr.in6;
key.port1 = id.dst_port;
key.port2 = id.src_port;
}
return new HashKey(&key, sizeof(key));
}
HashKey* BuildExpectedConnHashKey(const ExpectedConn& c)
{
struct {
in6_addr orig;
in6_addr resp;
uint16 resp_p;
uint16 proto;
} key;
key.orig = c.orig.in6;
key.resp = c.resp.in6;
key.resp_p = c.resp_p;
key.proto = c.proto;
return new HashKey(&key, sizeof(key));
}
void IPAddr::Mask(int top_bits_to_keep)
{
if ( top_bits_to_keep < 0 || top_bits_to_keep > 128 )
{
reporter->Error("Bad IPAddr::Mask value %d", top_bits_to_keep);
return;
}
uint32_t tmp[4];
memcpy(tmp, in6.s6_addr, sizeof(in6.s6_addr));
int word = 3;
int bits_to_chop = 128 - top_bits_to_keep;
while ( bits_to_chop >= 32 )
{
tmp[word] = 0;
--word;
bits_to_chop -= 32;
}
uint32_t w = ntohl(tmp[word]);
w >>= bits_to_chop;
w <<= bits_to_chop;
tmp[word] = htonl(w);
memcpy(in6.s6_addr, tmp, sizeof(in6.s6_addr));
}
void IPAddr::ReverseMask(int top_bits_to_chop)
{
if ( top_bits_to_chop < 0 || top_bits_to_chop > 128 )
{
reporter->Error("Bad IPAddr::ReverseMask value %d", top_bits_to_chop);
return;
}
uint32_t tmp[4];
memcpy(tmp, in6.s6_addr, sizeof(in6.s6_addr));
int word = 0;
int bits_to_chop = top_bits_to_chop;
while ( bits_to_chop >= 32 )
{
tmp[word] = 0;
++word;
bits_to_chop -= 32;
}
uint32_t w = ntohl(tmp[word]);
w <<= bits_to_chop;
w >>= bits_to_chop;
tmp[word] = htonl(w);
memcpy(in6.s6_addr, tmp, sizeof(in6.s6_addr));
}
void IPAddr::Init(const std::string& s)
{
if ( s.find(':') == std::string::npos ) // IPv4.
{
memcpy(in6.s6_addr, v4_mapped_prefix, sizeof(v4_mapped_prefix));
// Parse the address directly instead of using inet_pton since
// some platforms have more sensitive implementations than others
// that can't e.g. handle leading zeroes.
int a[4];
int n = sscanf(s.c_str(), "%d.%d.%d.%d", a+0, a+1, a+2, a+3);
if ( n != 4 || a[0] < 0 || a[1] < 0 || a[2] < 0 || a[3] < 0 ||
a[0] > 255 || a[1] > 255 || a[2] > 255 || a[3] > 255 )
{
reporter->Error("Bad IP address: %s", s.c_str());
memset(in6.s6_addr, 0, sizeof(in6.s6_addr));
return;
}
uint32_t addr = (a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3];
addr = htonl(addr);
memcpy(&in6.s6_addr[12], &addr, sizeof(uint32_t));
}
else
{
if ( inet_pton(AF_INET6, s.c_str(), in6.s6_addr) <=0 )
{
reporter->Error("Bad IP address: %s", s.c_str());
memset(in6.s6_addr, 0, sizeof(in6.s6_addr));
}
}
}
string IPAddr::AsString() const
{
if ( GetFamily() == IPv4 )
{
char s[INET_ADDRSTRLEN];
if ( ! bro_inet_ntop(AF_INET, &in6.s6_addr[12], s, INET_ADDRSTRLEN) )
return "<bad IPv4 address conversion";
else
return s;
}
else
{
char s[INET6_ADDRSTRLEN];
if ( ! bro_inet_ntop(AF_INET6, in6.s6_addr, s, INET6_ADDRSTRLEN) )
return "<bad IPv6 address conversion";
else
return s;
}
}
string IPAddr::AsHexString() const
{
char buf[33];
if ( GetFamily() == IPv4 )
{
uint32_t* p = (uint32_t*) &in6.s6_addr[12];
snprintf(buf, sizeof(buf), "%08x", (uint32_t) ntohl(*p));
}
else
{
uint32_t* p = (uint32_t*) in6.s6_addr;
snprintf(buf, sizeof(buf), "%08x%08x%08x%08x",
(uint32_t) ntohl(p[0]), (uint32_t) ntohl(p[1]),
(uint32_t) ntohl(p[2]), (uint32_t) ntohl(p[3]));
}
return buf;
}
string IPAddr::PtrName() const
{
if ( GetFamily() == IPv4 )
{
char buf[256];
uint32_t* p = (uint32_t*) &in6.s6_addr[12];
uint32_t a = ntohl(*p);
uint32_t a3 = (a >> 24) & 0xff;
uint32_t a2 = (a >> 16) & 0xff;
uint32_t a1 = (a >> 8) & 0xff;
uint32_t a0 = a & 0xff;
snprintf(buf, sizeof(buf), "%u.%u.%u.%u.in-addr.arpa", a0, a1, a2, a3);
return buf;
}
else
{
static const char hex_digit[] = "0123456789abcdef";
string ptr_name("ip6.arpa");
uint32_t* p = (uint32_t*) in6.s6_addr;
for ( unsigned int i = 0; i < 4; ++i )
{
uint32 a = ntohl(p[i]);
for ( unsigned int j = 1; j <=8; ++j )
{
ptr_name.insert(0, 1, '.');
ptr_name.insert(0, 1, hex_digit[(a >> (32-j*4)) & 0x0f]);
}
}
return ptr_name;
}
}
IPPrefix::IPPrefix(const in4_addr& in4, uint8_t length)
: prefix(in4), length(96 + length)
{
if ( length > 32 )
reporter->InternalError("Bad in4_addr IPPrefix length : %d", length);
prefix.Mask(this->length);
}
IPPrefix::IPPrefix(const in6_addr& in6, uint8_t length)
: prefix(in6), length(length)
{
if ( length > 128 )
reporter->InternalError("Bad in6_addr IPPrefix length : %d", length);
prefix.Mask(this->length);
}
IPPrefix::IPPrefix(const IPAddr& addr, uint8_t length)
: prefix(addr)
{
if ( prefix.GetFamily() == IPv4 )
{
if ( length > 32 )
reporter->InternalError("Bad IPAddr(v4) IPPrefix length : %d",
length);
this->length = length + 96;
}
else
{
if ( length > 128 )
reporter->InternalError("Bad IPAddr(v6) IPPrefix length : %d",
length);
this->length = length;
}
prefix.Mask(this->length);
}
string IPPrefix::AsString() const
{
char l[16];
if ( prefix.GetFamily() == IPv4 )
modp_uitoa10(length - 96, l);
else
modp_uitoa10(length, l);
return prefix.AsString() +"/" + l;
}

586
src/IPAddr.h Normal file
View file

@ -0,0 +1,586 @@
// See the file "COPYING" in the main distribution directory for copyright.
#ifndef IPADDR_H
#define IPADDR_H
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string>
#include "BroString.h"
#include "Hash.h"
#include "util.h"
#include "Type.h"
#include "threading/SerialTypes.h"
struct ConnID;
class ExpectedConn;
typedef in_addr in4_addr;
/**
* Class storing both IPv4 and IPv6 addresses.
*/
class IPAddr
{
public:
/**
* Address family.
*/
typedef IPFamily Family;
/**
* Byte order.
*/
enum ByteOrder { Host, Network };
/**
* Constructs the unspecified IPv6 address (all 128 bits zeroed).
*/
IPAddr()
{
memset(in6.s6_addr, 0, sizeof(in6.s6_addr));
}
/**
* Constructs an address instance from an IPv4 address.
*
* @param in6 The IPv6 address.
*/
explicit IPAddr(const in4_addr& in4)
{
memcpy(in6.s6_addr, v4_mapped_prefix, sizeof(v4_mapped_prefix));
memcpy(&in6.s6_addr[12], &in4.s_addr, sizeof(in4.s_addr));
}
/**
* Constructs an address instance from an IPv6 address.
*
* @param in6 The IPv6 address.
*/
explicit IPAddr(const in6_addr& arg_in6) : in6(arg_in6) { }
/**
* Constructs an address instance from a string representation.
*
* @param s String containing an IP address as either a dotted IPv4
* address or a hex IPv6 address.
*/
IPAddr(const std::string& s)
{
Init(s);
}
/**
* Constructs an address instance from a string representation.
*
* @param s ASCIIZ string containing an IP address as either a
* dotted IPv4 address or a hex IPv6 address.
*/
IPAddr(const char* s)
{
Init(s);
}
/**
* Constructs an address instance from a string representation.
*
* @param s String containing an IP address as either a dotted IPv4
* address or a hex IPv6 address.
*/
IPAddr(const BroString& s)
{
Init(s.CheckString());
}
/**
* Constructs an address instance from a raw byte representation.
*
* @param family The address family.
*
* @param bytes A pointer to the raw byte representation. This must point
* to 4 bytes if \a family is IPv4, and to 16 bytes if \a family is
* IPv6.
*
* @param order Indicates whether the raw representation pointed to
* by \a bytes is stored in network or host order.
*/
IPAddr(Family family, const uint32_t* bytes, ByteOrder order);
/**
* Copy constructor.
*/
IPAddr(const IPAddr& other) : in6(other.in6) { };
/**
* Destructor.
*/
~IPAddr() { };
/**
* Returns the address' family.
*/
Family GetFamily() const
{
if ( memcmp(in6.s6_addr, v4_mapped_prefix, 12) == 0 )
return IPv4;
else
return IPv6;
}
/**
* Returns true if the address represents a loopback device.
*/
bool IsLoopback() const;
/**
* Returns true if the address represents a multicast address.
*/
bool IsMulticast() const
{
if ( GetFamily() == IPv4 )
return in6.s6_addr[12] == 224;
else
return in6.s6_addr[0] == 0xff;
}
/**
* Returns true if the address represents a broadcast address.
*/
bool IsBroadcast() const
{
if ( GetFamily() == IPv4 )
return ((in6.s6_addr[12] == 0xff) && (in6.s6_addr[13] == 0xff)
&& (in6.s6_addr[14] == 0xff) && (in6.s6_addr[15] == 0xff));
else
return false;
}
/**
* Retrieves the raw byte representation of the address.
*
* @param bytes The pointer to which \a bytes points will be set to
* the address of the raw representation in network-byte order.
* The return value indicates how many 32-bit words are valid starting at
* that address. The pointer will be valid as long as the address instance
* exists.
*
* @return The number of 32-bit words the raw representation uses. This
* will be 1 for an IPv4 address and 4 for an IPv6 address.
*/
int GetBytes(const uint32_t** bytes) const
{
if ( GetFamily() == IPv4 )
{
*bytes = (uint32_t*) &in6.s6_addr[12];
return 1;
}
else
{
*bytes = (uint32_t*) in6.s6_addr;
return 4;
}
}
/**
* Retrieves a copy of the IPv6 raw byte representation of the address.
* If the internal address is IPv4, then the copied bytes use the
* IPv4 to IPv6 address mapping to return a full 16 bytes.
*
* @param bytes The pointer to a memory location in which the
* raw bytes of the address are to be copied in network byte-order.
*/
void CopyIPv6(uint32_t* bytes) const
{
memcpy(bytes, in6.s6_addr, sizeof(in6.s6_addr));
}
/**
* Retrieves a copy of the IPv6 raw byte representation of the address.
* @see CopyIPv6(uint32_t)
*/
void CopyIPv6(in6_addr* arg_in6) const
{
memcpy(arg_in6->s6_addr, in6.s6_addr, sizeof(in6.s6_addr));
}
/**
* Retrieves a copy of the IPv4 raw byte representation of the address.
* The caller should verify the address is of the IPv4 family type
* beforehand. @see GetFamily().
*
* @param in4 The pointer to a memory location in which the raw bytes
* of the address are to be copied in network byte-order.
*/
void CopyIPv4(in4_addr* in4) const
{
memcpy(&in4->s_addr, &in6.s6_addr[12], sizeof(in4->s_addr));
}
/**
* Returns a key that can be used to lookup the IP Address in a hash
* table. Passes ownership to caller.
*/
HashKey* GetHashKey() const
{
return new HashKey((void*)in6.s6_addr, sizeof(in6.s6_addr));
}
/**
* Masks out lower bits of the address.
*
* @param top_bits_to_keep The number of bits \a not to mask out,
* counting from the highest order bit. The value is always
* interpreted relative to the IPv6 bit width, even if the address
* is IPv4. That means if compute ``192.168.1.2/16``, you need to
* pass in 112 (i.e., 96 + 16). The value must be in the range from
* 0 to 128.
*/
void Mask(int top_bits_to_keep);
/**
* Masks out top bits of the address.
*
* @param top_bits_to_chop The number of bits to mask out, counting
* from the highest order bit. The value is always interpreted relative
* to the IPv6 bit width, even if the address is IPv4. So to mask out
* the first 16 bits of an IPv4 address, pass in 112 (i.e., 96 + 16).
* The value must be in the range from 0 to 128.
*/
void ReverseMask(int top_bits_to_chop);
/**
* Assignment operator.
*/
IPAddr& operator=(const IPAddr& other)
{
// No self-assignment check here because it's correct without it and
// makes the common case faster.
in6 = other.in6;
return *this;
}
/**
* Bitwise OR operator returns the IP address resulting from the bitwise
* OR operation on the raw bytes of this address with another.
*/
IPAddr operator|(const IPAddr& other)
{
in6_addr result;
for ( int i = 0; i < 16; ++i )
result.s6_addr[i] = this->in6.s6_addr[i] | other.in6.s6_addr[i];
return IPAddr(result);
}
/**
* Returns a string representation of the address. IPv4 addresses
* will be returned in dotted representation, IPv6 addresses in
* compressed hex.
*/
string AsString() const;
/**
* Returns a host-order, plain hex string representation of the address.
*/
string AsHexString() const;
/**
* Returns a string representation of the address. This returns the
* same as AsString().
*/
operator std::string() const { return AsString(); }
/**
* Returns a reverse pointer name associated with the IP address.
* For example, 192.168.0.1's reverse pointer is 1.0.168.192.in-addr.arpa.
*/
string PtrName() const;
/**
* Comparison operator for IP address.
*/
friend bool operator==(const IPAddr& addr1, const IPAddr& addr2)
{
return memcmp(&addr1.in6, &addr2.in6, sizeof(in6_addr)) == 0;
}
friend bool operator!=(const IPAddr& addr1, const IPAddr& addr2)
{
return ! (addr1 == addr2);
}
/**
* Comparison operator IP addresses. This defines a well-defined order for
* IP addresses. However, the order does not necessarily correspond to
* their numerical values.
*/
friend bool operator<(const IPAddr& addr1, const IPAddr& addr2)
{
return memcmp(&addr1.in6, &addr2.in6, sizeof(in6_addr)) < 0;
}
/** Converts the address into the type used internally by the
* inter-thread communication.
*/
void ConvertToThreadingValue(threading::Value::addr_t* v) const;
friend HashKey* BuildConnIDHashKey(const ConnID& id);
friend HashKey* BuildExpectedConnHashKey(const ExpectedConn& c);
unsigned int MemoryAllocation() const { return padded_sizeof(*this); }
private:
friend class IPPrefix;
/**
* Initializes an address instance from a string representation.
*
* @param s String containing an IP address as either a dotted IPv4
* address or a hex IPv6 address.
*/
void Init(const std::string& s);
in6_addr in6; // IPv6 or v4-to-v6-mapped address
static const uint8_t v4_mapped_prefix[12]; // top 96 bits of v4-mapped-addr
};
inline IPAddr::IPAddr(Family family, const uint32_t* bytes, ByteOrder order)
{
if ( family == IPv4 )
{
memcpy(in6.s6_addr, v4_mapped_prefix, sizeof(v4_mapped_prefix));
memcpy(&in6.s6_addr[12], bytes, sizeof(uint32_t));
if ( order == Host )
{
uint32_t* p = (uint32_t*) &in6.s6_addr[12];
*p = htonl(*p);
}
}
else
{
memcpy(in6.s6_addr, bytes, sizeof(in6.s6_addr));
if ( order == Host )
{
for ( unsigned int i = 0; i < 4; ++ i)
{
uint32_t* p = (uint32_t*) &in6.s6_addr[i*4];
*p = htonl(*p);
}
}
}
}
inline bool IPAddr::IsLoopback() const
{
if ( GetFamily() == IPv4 )
return in6.s6_addr[12] == 127;
else
return ((in6.s6_addr[0] == 0) && (in6.s6_addr[1] == 0)
&& (in6.s6_addr[2] == 0) && (in6.s6_addr[3] == 0)
&& (in6.s6_addr[4] == 0) && (in6.s6_addr[5] == 0)
&& (in6.s6_addr[6] == 0) && (in6.s6_addr[7] == 0)
&& (in6.s6_addr[8] == 0) && (in6.s6_addr[9] == 0)
&& (in6.s6_addr[10] == 0) && (in6.s6_addr[11] == 0)
&& (in6.s6_addr[12] == 0) && (in6.s6_addr[13] == 0)
&& (in6.s6_addr[14] == 0) && (in6.s6_addr[15] == 1));
}
inline void IPAddr::ConvertToThreadingValue(threading::Value::addr_t* v) const
{
v->family = GetFamily();
switch ( v->family ) {
case IPv4:
CopyIPv4(&v->in.in4);
return;
case IPv6:
CopyIPv6(&v->in.in6);
return;
// Can't be reached.
abort();
}
}
/**
* Returns a hash key for a given ConnID. Passes ownership to caller.
*/
HashKey* BuildConnIDHashKey(const ConnID& id);
/**
* Returns a hash key for a given ExpectedConn instance. Passes ownership to caller.
*/
HashKey* BuildExpectedConnHashKey(const ExpectedConn& c);
/**
* Class storing both IPv4 and IPv6 prefixes
* (i.e., \c 192.168.1.1/16 and \c FD00::/8.
*/
class IPPrefix
{
public:
/**
* Constructs a prefix 0/0.
*/
IPPrefix() : length(0) {}
/**
* Constructs a prefix instance from an IPv4 address and a prefix
* length.
*
* @param in4 The IPv4 address.
*
* @param length The prefix length in the range from 0 to 32.
*/
IPPrefix(const in4_addr& in4, uint8_t length);
/**
* Constructs a prefix instance from an IPv6 address and a prefix
* length.
*
* @param in6 The IPv6 address.
*
* @param length The prefix length in the range from 0 to 128.
*/
IPPrefix(const in6_addr& in6, uint8_t length);
/**
* Constructs a prefix instance from an IPAddr object and prefix length.
*
* @param addr The IP address.
*
* @param length The prefix length in the range from 0 to 128
*/
IPPrefix(const IPAddr& addr, uint8_t length);
/**
* Copy constructor.
*/
IPPrefix(const IPPrefix& other)
: prefix(other.prefix), length(other.length) { }
/**
* Destructor.
*/
~IPPrefix() { }
/**
* Returns the prefix in the form of an IP address. The address will
* have all bits not part of the prefixed set to zero.
*/
const IPAddr& Prefix() const { return prefix; }
/**
* Returns the bit length of the prefix, relative to the 32 bits
* of an IPv4 prefix or relative to the 128 bits of an IPv6 prefix.
*/
uint8_t Length() const
{
return prefix.GetFamily() == IPv4 ? length - 96 : length;
}
/**
* Returns the bit length of the prefix always relative to a full
* 128 bits of an IPv6 prefix (or IPv4 mapped to IPv6).
*/
uint8_t LengthIPv6() const { return length; }
/** Returns true if the given address is part of the prefix.
*
* @param addr The address to test.
*/
bool Contains(const IPAddr& addr) const
{
IPAddr p(addr);
p.Mask(length);
return p == prefix;
}
/**
* Assignment operator.
*/
IPPrefix& operator=(const IPPrefix& other)
{
// No self-assignment check here because it's correct without it and
// makes the common case faster.
prefix = other.prefix;
length = other.length;
return *this;
}
/**
* Returns a string representation of the prefix. IPv4 addresses
* will be returned in dotted representation, IPv6 addresses in
* compressed hex.
*/
string AsString() const;
operator std::string() const { return AsString(); }
/**
* Returns a key that can be used to lookup the IP Prefix in a hash
* table. Passes ownership to caller.
*/
HashKey* GetHashKey() const
{
struct {
in6_addr ip;
uint32 len;
} key;
key.ip = prefix.in6;
key.len = Length();
return new HashKey(&key, sizeof(key));
}
/** Converts the prefix into the type used internally by the
* inter-thread communication.
*/
void ConvertToThreadingValue(threading::Value::subnet_t* v) const
{
v->length = length;
prefix.ConvertToThreadingValue(&v->prefix);
}
unsigned int MemoryAllocation() const { return padded_sizeof(*this); }
/**
* Comparison operator for IP prefix.
*/
friend bool operator==(const IPPrefix& net1, const IPPrefix& net2)
{
return net1.Prefix() == net2.Prefix() && net1.Length() == net2.Length();
}
/**
* Comparison operator IP prefixes. This defines a well-defined order for
* IP prefix. However, the order does not necessarily corresponding to their
* numerical values.
*/
friend bool operator<(const IPPrefix& net1, const IPPrefix& net2)
{
if ( net1.Prefix() < net2.Prefix() )
return true;
else if ( net1.Prefix() == net2.Prefix() )
return net1.Length() < net2.Length();
else
return false;
}
private:
IPAddr prefix; // We store it as an address with the non-prefix bits masked out via Mask().
uint8_t length; // The bit length of the prefix relative to full IPv6 addr.
};
#endif

View file

@ -1,142 +0,0 @@
// See the file "COPYING" in the main distribution directory for copyright.
//
// A class managing log writers and filters.
#ifndef LOGMGR_H
#define LOGMGR_H
#include "Val.h"
#include "EventHandler.h"
#include "RemoteSerializer.h"
class SerializationFormat;
// Description of a log field.
struct LogField {
string name;
TypeTag type;
// inner type of sets
TypeTag subtype;
LogField() { subtype = TYPE_VOID; }
LogField(const LogField& other)
: name(other.name), type(other.type), subtype(other.subtype) { }
// (Un-)serialize.
bool Read(SerializationFormat* fmt);
bool Write(SerializationFormat* fmt) const;
};
// Values as logged by a writer.
struct LogVal {
TypeTag type;
bool present; // False for unset fields.
// The following union is a subset of BroValUnion, including only the
// types we can log directly.
struct set_t { bro_int_t size; LogVal** vals; };
typedef set_t vec_t;
union _val {
bro_int_t int_val;
bro_uint_t uint_val;
uint32 addr_val[NUM_ADDR_WORDS];
subnet_type subnet_val;
double double_val;
string* string_val;
set_t set_val;
vec_t vector_val;
} val;
LogVal(TypeTag arg_type = TYPE_ERROR, bool arg_present = true)
: type(arg_type), present(arg_present) {}
~LogVal();
// (Un-)serialize.
bool Read(SerializationFormat* fmt);
bool Write(SerializationFormat* fmt) const;
// Returns true if the type can be logged the framework. If
// `atomic_only` is true, will not permit composite types.
static bool IsCompatibleType(BroType* t, bool atomic_only=false);
private:
LogVal(const LogVal& other) { }
};
class LogWriter;
class RemoteSerializer;
class RotationTimer;
class LogMgr {
public:
LogMgr();
~LogMgr();
// These correspond to the BiFs visible on the scripting layer. The
// actual BiFs just forward here.
bool CreateStream(EnumVal* id, RecordVal* stream);
bool EnableStream(EnumVal* id);
bool DisableStream(EnumVal* id);
bool AddFilter(EnumVal* id, RecordVal* filter);
bool RemoveFilter(EnumVal* id, StringVal* name);
bool RemoveFilter(EnumVal* id, string name);
bool Write(EnumVal* id, RecordVal* columns);
bool SetBuf(EnumVal* id, bool enabled); // Adjusts all writers.
bool Flush(EnumVal* id); // Flushes all writers..
protected:
friend class LogWriter;
friend class RemoteSerializer;
friend class RotationTimer;
//// Function also used by the RemoteSerializer.
// Takes ownership of fields.
LogWriter* CreateWriter(EnumVal* id, EnumVal* writer, string path,
int num_fields, LogField** fields);
// Takes ownership of values..
bool Write(EnumVal* id, EnumVal* writer, string path,
int num_fields, LogVal** vals);
// Announces all instantiated writers to peer.
void SendAllWritersTo(RemoteSerializer::PeerID peer);
//// Functions safe to use by writers.
// Signals that a file has been rotated.
bool FinishedRotation(LogWriter* writer, string new_name, string old_name,
double open, double close, bool terminating);
// Reports an error for the given writer.
void Error(LogWriter* writer, const char* msg);
// Deletes the values as passed into Write().
void DeleteVals(int num_fields, LogVal** vals);
private:
struct Filter;
struct Stream;
struct WriterInfo;
bool TraverseRecord(Stream* stream, Filter* filter, RecordType* rt,
TableVal* include, TableVal* exclude, string path, list<int> indices);
LogVal** RecordToFilterVals(Stream* stream, Filter* filter,
RecordVal* columns);
LogVal* ValToLogVal(Val* val, BroType* ty = 0);
Stream* FindStream(EnumVal* id);
void RemoveDisabledWriters(Stream* stream);
void InstallRotationTimer(WriterInfo* winfo);
void Rotate(WriterInfo* info);
Filter* FindFilter(EnumVal* id, StringVal* filter);
WriterInfo* FindWriter(LogWriter* writer);
vector<Stream *> streams; // Indexed by stream enum.
};
extern LogMgr* log_mgr;
#endif

View file

@ -1,158 +0,0 @@
// See the file "COPYING" in the main distribution directory for copyright.
#include "util.h"
#include "LogWriter.h"
LogWriter::LogWriter()
{
buf = 0;
buf_len = 1024;
buffering = true;
disabled = false;
}
LogWriter::~LogWriter()
{
if ( buf )
free(buf);
for(int i = 0; i < num_fields; ++i)
delete fields[i];
delete [] fields;
}
bool LogWriter::Init(string arg_path, int arg_num_fields,
const LogField* const * arg_fields)
{
path = arg_path;
num_fields = arg_num_fields;
fields = arg_fields;
if ( ! DoInit(arg_path, arg_num_fields, arg_fields) )
{
disabled = true;
return false;
}
return true;
}
bool LogWriter::Write(int arg_num_fields, LogVal** vals)
{
// Double-check that the arguments match. If we get this from remote,
// something might be mixed up.
if ( num_fields != arg_num_fields )
{
DBG_LOG(DBG_LOGGING, "Number of fields don't match in LogWriter::Write() (%d vs. %d)",
arg_num_fields, num_fields);
DeleteVals(vals);
return false;
}
for ( int i = 0; i < num_fields; ++i )
{
if ( vals[i]->type != fields[i]->type )
{
DBG_LOG(DBG_LOGGING, "Field type doesn't match in LogWriter::Write() (%d vs. %d)",
vals[i]->type, fields[i]->type);
DeleteVals(vals);
return false;
}
}
bool result = DoWrite(num_fields, fields, vals);
DeleteVals(vals);
if ( ! result )
disabled = true;
return result;
}
bool LogWriter::SetBuf(bool enabled)
{
if ( enabled == buffering )
// No change.
return true;
buffering = enabled;
if ( ! DoSetBuf(enabled) )
{
disabled = true;
return false;
}
return true;
}
bool LogWriter::Rotate(string rotated_path, double open,
double close, bool terminating)
{
if ( ! DoRotate(rotated_path, open, close, terminating) )
{
disabled = true;
return false;
}
return true;
}
bool LogWriter::Flush()
{
if ( ! DoFlush() )
{
disabled = true;
return false;
}
return true;
}
void LogWriter::Finish()
{
DoFinish();
}
const char* LogWriter::Fmt(const char* format, ...)
{
if ( ! buf )
buf = (char*) malloc(buf_len);
va_list al;
va_start(al, format);
int n = safe_vsnprintf(buf, buf_len, format, al);
va_end(al);
if ( (unsigned int) n >= buf_len )
{ // Not enough room, grow the buffer.
buf_len = n + 32;
buf = (char*) realloc(buf, buf_len);
// Is it portable to restart?
va_start(al, format);
n = safe_vsnprintf(buf, buf_len, format, al);
va_end(al);
}
return buf;
}
void LogWriter::Error(const char *msg)
{
log_mgr->Error(this, msg);
}
void LogWriter::DeleteVals(LogVal** vals)
{
log_mgr->DeleteVals(num_fields, vals);
}
bool LogWriter::FinishedRotation(string new_name, string old_name, double open,
double close, bool terminating)
{
return log_mgr->FinishedRotation(this, new_name, old_name, open, close, terminating);
}

View file

@ -1,192 +0,0 @@
// See the file "COPYING" in the main distribution directory for copyright.
//
// Interface API for a log writer backend. The LogMgr creates a separate
// writer instance of pair of (writer type, output path).
//
// Note thay classes derived from LogWriter must be fully thread-safe and not
// use any non-thread-safe Bro functionality (which includes almost
// everything ...). In particular, do not use fmt() but LogWriter::Fmt()!.
//
// The one exception to this rule is the constructor: it is guaranteed to be
// executed inside the main thread and can thus in particular access global
// script variables.
#ifndef LOGWRITER_H
#define LOGWRITER_H
#include "LogMgr.h"
#include "BroString.h"
class LogWriter {
public:
LogWriter();
virtual ~LogWriter();
//// Interface methods to interact with the writer. Note that these
//// methods are not necessarily thread-safe and must be called only
//// from the main thread (which will typically mean only from the
//// LogMgr). In particular, they must not be called from the
//// writer's derived implementation.
// One-time initialization of the writer to define the logged fields.
// Interpretation of "path" is left to the writer, and will be
// corresponding the value configured on the script-level.
//
// Returns false if an error occured, in which case the writer must
// not be used further.
//
// The new instance takes ownership of "fields", and will delete them
// when done.
bool Init(string path, int num_fields, const LogField* const * fields);
// Writes one log entry. The method takes ownership of "vals" and
// will return immediately after queueing the write request, which is
// potentially before output has actually been written out.
//
// num_fields and the types of the LogVals must match what was passed
// to Init().
//
// Returns false if an error occured, in which case the writer must
// not be used any further.
bool Write(int num_fields, LogVal** vals);
// Sets the buffering status for the writer, if the writer supports
// that. (If not, it will be ignored).
bool SetBuf(bool enabled);
// Flushes any currently buffered output, if the writer supports
// that. (If not, it will be ignored).
bool Flush();
// Triggers rotation, if the writer supports that. (If not, it will
// be ignored).
bool Rotate(string rotated_path, double open, double close, bool terminating);
// Finishes writing to this logger regularly. Must not be called if
// an error has been indicated earlier. After calling this, no
// further writing must be performed.
void Finish();
//// Thread-safe methods that may be called from the writer
//// implementation.
// The following methods return the information as passed to Init().
const string Path() const { return path; }
int NumFields() const { return num_fields; }
const LogField* const * Fields() const { return fields; }
protected:
// Methods for writers to override. If any of these returs false, it
// will be assumed that a fatal error has occured that prevents the
// writer from further operation. It will then be disabled and
// deleted. When return false, the writer should also report the
// error via Error(). Note that even if a writer does not support the
// functionality for one these methods (like rotation), it must still
// return true if that is not to be considered a fatal error.
//
// Called once for initialization of the writer.
virtual bool DoInit(string path, int num_fields,
const LogField* const * fields) = 0;
// Called once per log entry to record.
virtual bool DoWrite(int num_fields, const LogField* const * fields,
LogVal** vals) = 0;
// Called when the buffering status for this writer is changed. If
// buffering is disabled, the writer should attempt to write out
// information as quickly as possible even if doing so may have a
// performance impact. If enabled (which is the default), it may
// buffer data as helpful and write it out later in a way optimized
// for performance. The current buffering state can be queried via
// IsBuf().
//
// A writer may ignore buffering changes if it doesn't fit with its
// semantics (but must still return true in that case).
virtual bool DoSetBuf(bool enabled) = 0;
// Called to flush any currently buffered output.
//
// A writer may ignore flush requests if it doesn't fit with its
// semantics (but must still return true in that case).
virtual bool DoFlush() = 0;
// Called when a log output is to be rotated. Most directly this only
// applies to writers writing into files, which should then close the
// current file and open a new one. However, a writer may also
// trigger other apppropiate actions if semantics are similar.
//
// Once rotation has finished, the implementation should call
// RotationDone() to signal the log manager that potential
// postprocessors can now run.
//
// "rotate_path" reflects the path to where the rotated output is to
// be moved, with specifics depending on the writer. It should
// generally be interpreted in a way consistent with that of "path"
// as passed into DoInit(). As an example, for file-based output,
// "rotate_path" could be the original filename extended with a
// timestamp indicating the time of the rotation.
//
// "open" and "close" are the network time's when the *current* file
// was opened and closed, respectively.
//
// "terminating" indicated whether the rotation request occurs due
// the main Bro prcoess terminating (and not because we've reach a
// regularly scheduled time for rotation).
//
// A writer may ignore rotation requests if it doesn't fit with its
// semantics (but must still return true in that case).
virtual bool DoRotate(string rotated_path, double open, double close,
bool terminating) = 0;
// Called once on termination. Not called when any of the other
// methods has previously signaled an error, i.e., executing this
// method signals a regular shutdown of the writer.
virtual void DoFinish() = 0;
//// Methods for writers to use. These are thread-safe.
// A thread-safe version of fmt().
const char* Fmt(const char* format, ...);
// Returns the current buffering state.
bool IsBuf() { return buffering; }
// Reports an error to the user.
void Error(const char *msg);
// Signals to the log manager that a file has been rotated.
//
// new_name: The filename of the rotated file. old_name: The filename
// of the origina file.
//
// open/close: The timestamps when the original file was opened and
// closed, respectively.
//
// terminating: True if rotation request occured due to the main Bro
// process shutting down.
bool FinishedRotation(string new_name, string old_name, double open,
double close, bool terminating);
private:
friend class LogMgr;
// When an error occurs, we call this method to set a flag marking
// the writer as disabled. The LogMgr will check the flag later and
// remove the writer.
bool Disabled() { return disabled; }
// Deletes the values as passed into Write().
void DeleteVals(LogVal** vals);
string path;
int num_fields;
const LogField* const * fields;
bool buffering;
bool disabled;
// For implementing Fmt().
char* buf;
unsigned int buf_len;
};
#endif

View file

@ -1,30 +0,0 @@
// See the file "COPYING" in the main distribution directory for copyright.
//
// Dummy log writer that just discards everything (but still pretends to rotate).
#ifndef LOGWRITERNONE_H
#define LOGWRITERNONE_H
#include "LogWriter.h"
class LogWriterNone : public LogWriter {
public:
LogWriterNone() {}
~LogWriterNone() {};
static LogWriter* Instantiate() { return new LogWriterNone; }
protected:
virtual bool DoInit(string path, int num_fields,
const LogField* const * fields) { return true; }
virtual bool DoWrite(int num_fields, const LogField* const * fields,
LogVal** vals) { return true; }
virtual bool DoSetBuf(bool enabled) { return true; }
virtual bool DoRotate(string rotated_path, double open, double close,
bool terminating);
virtual bool DoFlush() { return true; }
virtual void DoFinish() {}
};
#endif

View file

@ -38,7 +38,7 @@ Login_Analyzer::Login_Analyzer(AnalyzerTag::Tag tag, Connection* conn)
if ( ! re_skip_authentication ) if ( ! re_skip_authentication )
{ {
#ifdef USE_PERFTOOLS #ifdef USE_PERFTOOLS_DEBUG
HeapLeakChecker::Disabler disabler; HeapLeakChecker::Disabler disabler;
#endif #endif
re_skip_authentication = init_RE(skip_authentication); re_skip_authentication = init_RE(skip_authentication);

View file

@ -225,5 +225,7 @@ NCP_Analyzer::NCP_Analyzer(Connection* conn)
NCP_Analyzer::~NCP_Analyzer() NCP_Analyzer::~NCP_Analyzer()
{ {
delete session; delete session;
delete o_ncp;
delete r_ncp;
} }

View file

@ -42,7 +42,6 @@ extern int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
PList(PktSrc) pkt_srcs; PList(PktSrc) pkt_srcs;
// FIXME: We should really merge PktDumper and PacketDumper. // FIXME: We should really merge PktDumper and PacketDumper.
// It's on my to-do [Robin].
PktDumper* pkt_dumper = 0; PktDumper* pkt_dumper = 0;
int reading_live = 0; int reading_live = 0;
@ -248,12 +247,14 @@ void net_init(name_list& interfaces, name_list& readfiles,
FlowSocketSrc* fs = new FlowSocketSrc(netflows[i]); FlowSocketSrc* fs = new FlowSocketSrc(netflows[i]);
if ( ! fs->IsOpen() ) if ( ! fs->IsOpen() )
{
reporter->Error("%s: problem with netflow socket %s - %s\n", reporter->Error("%s: problem with netflow socket %s - %s\n",
prog, netflows[i], fs->ErrorMsg()); prog, netflows[i], fs->ErrorMsg());
else delete fs;
{
io_sources.Register(fs);
} }
else
io_sources.Register(fs);
} }
} }
@ -454,6 +455,7 @@ void net_run()
// date on timers and events. // date on timers and events.
network_time = ct; network_time = ct;
expire_timers(); expire_timers();
usleep(1); // Just yield.
} }
} }
@ -483,6 +485,8 @@ void net_run()
// since Bro timers are not high-precision anyway.) // since Bro timers are not high-precision anyway.)
if ( ! using_communication ) if ( ! using_communication )
usleep(100000); usleep(100000);
else
usleep(1000);
// Flawfinder says about usleep: // Flawfinder says about usleep:
// //

View file

@ -47,15 +47,6 @@ int tcp_max_initial_window;
int tcp_max_above_hole_without_any_acks; int tcp_max_above_hole_without_any_acks;
int tcp_excessive_data_without_further_acks; int tcp_excessive_data_without_further_acks;
int ssl_compare_cipherspecs;
int ssl_analyze_certificates;
int ssl_store_certificates;
int ssl_verify_certificates;
int ssl_store_key_material;
int ssl_max_cipherspec_size;
StringVal* ssl_store_cert_path;
StringVal* x509_trusted_cert_path;
TableType* cipher_suites_list;
RecordType* x509_type; RecordType* x509_type;
double non_analyzed_lifetime; double non_analyzed_lifetime;
@ -192,8 +183,6 @@ StringVal* ssl_ca_certificate;
StringVal* ssl_private_key; StringVal* ssl_private_key;
StringVal* ssl_passphrase; StringVal* ssl_passphrase;
StringVal* x509_crl_file;
Val* profiling_file; Val* profiling_file;
double profiling_interval; double profiling_interval;
int expensive_profiling_multiple; int expensive_profiling_multiple;
@ -213,11 +202,6 @@ int sig_max_group_size;
int enable_syslog; int enable_syslog;
int use_connection_compressor;
int cc_handle_resets;
int cc_handle_only_syns;
int cc_instantiate_on_data;
TableType* irc_join_list; TableType* irc_join_list;
RecordType* irc_join_info; RecordType* irc_join_info;
TableVal* irc_servers; TableVal* irc_servers;
@ -358,17 +342,7 @@ void init_net_var()
tcp_excessive_data_without_further_acks = tcp_excessive_data_without_further_acks =
opt_internal_int("tcp_excessive_data_without_further_acks"); opt_internal_int("tcp_excessive_data_without_further_acks");
ssl_compare_cipherspecs = opt_internal_int("ssl_compare_cipherspecs");
ssl_analyze_certificates = opt_internal_int("ssl_analyze_certificates");
ssl_store_certificates = opt_internal_int("ssl_store_certificates");
ssl_verify_certificates = opt_internal_int("ssl_verify_certificates");
ssl_store_key_material = opt_internal_int("ssl_store_key_material");
ssl_max_cipherspec_size = opt_internal_int("ssl_max_cipherspec_size");
x509_trusted_cert_path = opt_internal_string("X509_trusted_cert_path");
ssl_store_cert_path = opt_internal_string("ssl_store_cert_path");
x509_type = internal_type("X509")->AsRecordType(); x509_type = internal_type("X509")->AsRecordType();
x509_crl_file = opt_internal_string("X509_crl_file");
non_analyzed_lifetime = opt_internal_double("non_analyzed_lifetime"); non_analyzed_lifetime = opt_internal_double("non_analyzed_lifetime");
tcp_inactivity_timeout = opt_internal_double("tcp_inactivity_timeout"); tcp_inactivity_timeout = opt_internal_double("tcp_inactivity_timeout");
@ -525,12 +499,6 @@ void init_net_var()
gap_report_freq = opt_internal_double("gap_report_freq"); gap_report_freq = opt_internal_double("gap_report_freq");
use_connection_compressor =
opt_internal_int("use_connection_compressor");
cc_handle_resets = opt_internal_int("cc_handle_resets");
cc_handle_only_syns = opt_internal_int("cc_handle_only_syns");
cc_instantiate_on_data = opt_internal_int("cc_instantiate_on_data");
irc_join_info = internal_type("irc_join_info")->AsRecordType(); irc_join_info = internal_type("irc_join_info")->AsRecordType();
irc_join_list = internal_type("irc_join_list")->AsTableType(); irc_join_list = internal_type("irc_join_list")->AsTableType();
irc_servers = internal_val("irc_servers")->AsTableVal(); irc_servers = internal_val("irc_servers")->AsTableVal();

View file

@ -50,17 +50,7 @@ extern int tcp_max_initial_window;
extern int tcp_max_above_hole_without_any_acks; extern int tcp_max_above_hole_without_any_acks;
extern int tcp_excessive_data_without_further_acks; extern int tcp_excessive_data_without_further_acks;
// see policy/ssl.bro for details
extern int ssl_compare_cipherspecs;
extern int ssl_analyze_certificates;
extern int ssl_store_certificates;
extern int ssl_verify_certificates;
extern int ssl_store_key_material;
extern int ssl_max_cipherspec_size;
extern StringVal* ssl_store_cert_path;
extern StringVal* x509_trusted_cert_path;
extern RecordType* x509_type; extern RecordType* x509_type;
extern StringVal* x509_crl_file;
extern double non_analyzed_lifetime; extern double non_analyzed_lifetime;
extern double tcp_inactivity_timeout; extern double tcp_inactivity_timeout;
@ -216,11 +206,6 @@ extern int sig_max_group_size;
extern int enable_syslog; extern int enable_syslog;
extern int use_connection_compressor;
extern int cc_handle_resets;
extern int cc_handle_only_syns;
extern int cc_instantiate_on_data;
extern TableType* irc_join_list; extern TableType* irc_join_list;
extern RecordType* irc_join_info; extern RecordType* irc_join_info;
extern TableVal* irc_servers; extern TableVal* irc_servers;

View file

@ -131,6 +131,9 @@ int NetbiosSSN_Interpreter::ParseBroadcast(const u_char* data, int len,
return 0; return 0;
} }
delete srcname;
delete dstname;
return 0; return 0;
} }

View file

@ -63,15 +63,16 @@ OSFingerprint::OSFingerprint(FingerprintMode arg_mode)
} }
} }
bool OSFingerprint::CacheMatch(uint32 addr, int id) bool OSFingerprint::CacheMatch(const IPAddr& addr, int id)
{ {
HashKey key = HashKey(&addr, 1); HashKey* key = addr.GetHashKey();
int* pid = new int; int* pid = new int;
*pid=id; *pid=id;
int* prev = os_matches.Insert(&key, pid); int* prev = os_matches.Insert(key, pid);
bool ret = (prev ? *prev != id : 1); bool ret = (prev ? *prev != id : 1);
if (prev) if (prev)
delete prev; delete prev;
delete key;
return ret; return ret;
} }

View file

@ -14,6 +14,7 @@
#include "util.h" #include "util.h"
#include "Dict.h" #include "Dict.h"
#include "Reporter.h" #include "Reporter.h"
#include "IPAddr.h"
// Size limit for size wildcards. // Size limit for size wildcards.
#define PACKET_BIG 100 #define PACKET_BIG 100
@ -88,7 +89,7 @@ public:
int FindMatch(struct os_type* retval, uint16 tot, uint8 DF_flag, int FindMatch(struct os_type* retval, uint16 tot, uint8 DF_flag,
uint8 TTL, uint16 WSS, uint8 ocnt, uint8* op, uint16 MSS, uint8 TTL, uint16 WSS, uint8 ocnt, uint8* op, uint16 MSS,
uint8 win_scale, uint32 tstamp, uint32 quirks, uint8 ECN) const; uint8 win_scale, uint32 tstamp, uint32 quirks, uint8 ECN) const;
bool CacheMatch(uint32 addr, int id); bool CacheMatch(const IPAddr& addr, int id);
int Get_OS_From_SYN(struct os_type* retval, int Get_OS_From_SYN(struct os_type* retval,
uint16 tot, uint8 DF_flag, uint8 TTL, uint16 WSS, uint16 tot, uint8 DF_flag, uint8 TTL, uint16 WSS,

View file

@ -196,20 +196,20 @@ void PIA_TCP::FirstPacket(bool is_orig, const IP_Hdr* ip)
ip4->ip_p = IPPROTO_TCP; ip4->ip_p = IPPROTO_TCP;
// Cast to const so that it doesn't delete it. // Cast to const so that it doesn't delete it.
ip4_hdr = new IP_Hdr((const struct ip*) ip4); ip4_hdr = new IP_Hdr(ip4, false);
} }
if ( is_orig ) if ( is_orig )
{ {
copy_addr(Conn()->OrigAddr(), &ip4->ip_src.s_addr); Conn()->OrigAddr().CopyIPv4(&ip4->ip_src);
copy_addr(Conn()->RespAddr(), &ip4->ip_dst.s_addr); Conn()->RespAddr().CopyIPv4(&ip4->ip_dst);
tcp4->th_sport = htons(Conn()->OrigPort()); tcp4->th_sport = htons(Conn()->OrigPort());
tcp4->th_dport = htons(Conn()->RespPort()); tcp4->th_dport = htons(Conn()->RespPort());
} }
else else
{ {
copy_addr(Conn()->RespAddr(), &ip4->ip_src.s_addr); Conn()->RespAddr().CopyIPv4(&ip4->ip_src);
copy_addr(Conn()->OrigAddr(), &ip4->ip_dst.s_addr); Conn()->OrigAddr().CopyIPv4(&ip4->ip_dst);
tcp4->th_sport = htons(Conn()->RespPort()); tcp4->th_sport = htons(Conn()->RespPort());
tcp4->th_dport = htons(Conn()->OrigPort()); tcp4->th_dport = htons(Conn()->OrigPort());
} }

View file

@ -158,6 +158,7 @@ void POP3_Analyzer::ProcessRequest(int length, const char* line)
if ( e >= end ) if ( e >= end )
{ {
Weird("pop3_malformed_auth_plain"); Weird("pop3_malformed_auth_plain");
delete decoded;
return; return;
} }
@ -167,6 +168,7 @@ void POP3_Analyzer::ProcessRequest(int length, const char* line)
if ( s >= end ) if ( s >= end )
{ {
Weird("pop3_malformed_auth_plain"); Weird("pop3_malformed_auth_plain");
delete decoded;
return; return;
} }

View file

@ -1,11 +1,11 @@
#include "PacketFilter.h" #include "PacketFilter.h"
void PacketFilter::AddSrc(addr_type src, uint32 tcp_flags, double probability) void PacketFilter::AddSrc(const IPAddr& src, uint32 tcp_flags, double probability)
{ {
Filter* f = new Filter; Filter* f = new Filter;
f->tcp_flags = tcp_flags; f->tcp_flags = tcp_flags;
f->probability = uint32(probability * RAND_MAX); f->probability = uint32(probability * RAND_MAX);
src_filter.Insert(src, NUM_ADDR_WORDS * 32, f); src_filter.Insert(src, 128, f);
} }
void PacketFilter::AddSrc(Val* src, uint32 tcp_flags, double probability) void PacketFilter::AddSrc(Val* src, uint32 tcp_flags, double probability)
@ -16,12 +16,12 @@ void PacketFilter::AddSrc(Val* src, uint32 tcp_flags, double probability)
src_filter.Insert(src, f); src_filter.Insert(src, f);
} }
void PacketFilter::AddDst(addr_type dst, uint32 tcp_flags, double probability) void PacketFilter::AddDst(const IPAddr& dst, uint32 tcp_flags, double probability)
{ {
Filter* f = new Filter; Filter* f = new Filter;
f->tcp_flags = tcp_flags; f->tcp_flags = tcp_flags;
f->probability = uint32(probability * RAND_MAX); f->probability = uint32(probability * RAND_MAX);
dst_filter.Insert(dst, NUM_ADDR_WORDS * 32, f); dst_filter.Insert(dst, 128, f);
} }
void PacketFilter::AddDst(Val* dst, uint32 tcp_flags, double probability) void PacketFilter::AddDst(Val* dst, uint32 tcp_flags, double probability)
@ -32,9 +32,9 @@ void PacketFilter::AddDst(Val* dst, uint32 tcp_flags, double probability)
dst_filter.Insert(dst, f); dst_filter.Insert(dst, f);
} }
bool PacketFilter::RemoveSrc(addr_type src) bool PacketFilter::RemoveSrc(const IPAddr& src)
{ {
return src_filter.Remove(src, NUM_ADDR_WORDS * 32) != 0; return src_filter.Remove(src, 128) != 0;
} }
bool PacketFilter::RemoveSrc(Val* src) bool PacketFilter::RemoveSrc(Val* src)
@ -42,9 +42,9 @@ bool PacketFilter::RemoveSrc(Val* src)
return src_filter.Remove(src) != NULL; return src_filter.Remove(src) != NULL;
} }
bool PacketFilter::RemoveDst(addr_type dst) bool PacketFilter::RemoveDst(const IPAddr& dst)
{ {
return dst_filter.Remove(dst, NUM_ADDR_WORDS * 32) != NULL; return dst_filter.Remove(dst, 128) != NULL;
} }
bool PacketFilter::RemoveDst(Val* dst) bool PacketFilter::RemoveDst(Val* dst)
@ -54,21 +54,11 @@ bool PacketFilter::RemoveDst(Val* dst)
bool PacketFilter::Match(const IP_Hdr* ip, int len, int caplen) bool PacketFilter::Match(const IP_Hdr* ip, int len, int caplen)
{ {
#ifdef BROv6 Filter* f = (Filter*) src_filter.Lookup(ip->SrcAddr(), 128);
Filter* f = (Filter*) src_filter.Lookup(ip->SrcAddr(),
NUM_ADDR_WORDS * 32);
#else
Filter* f = (Filter*) src_filter.Lookup(*ip->SrcAddr(),
NUM_ADDR_WORDS * 32);
#endif
if ( f ) if ( f )
return MatchFilter(*f, *ip, len, caplen); return MatchFilter(*f, *ip, len, caplen);
#ifdef BROv6 f = (Filter*) dst_filter.Lookup(ip->DstAddr(), 128);
f = (Filter*) dst_filter.Lookup(ip->DstAddr(), NUM_ADDR_WORDS * 32);
#else
f = (Filter*) dst_filter.Lookup(*ip->DstAddr(), NUM_ADDR_WORDS * 32);
#endif
if ( f ) if ( f )
return MatchFilter(*f, *ip, len, caplen); return MatchFilter(*f, *ip, len, caplen);
@ -81,9 +71,7 @@ bool PacketFilter::MatchFilter(const Filter& f, const IP_Hdr& ip,
if ( ip.NextProto() == IPPROTO_TCP && f.tcp_flags ) if ( ip.NextProto() == IPPROTO_TCP && f.tcp_flags )
{ {
// Caution! The packet sanity checks have not been performed yet // Caution! The packet sanity checks have not been performed yet
const struct ip* ip4 = ip.IP4_Hdr(); int ip_hdr_len = ip.HdrLen();
int ip_hdr_len = ip4->ip_hl * 4;
len -= ip_hdr_len; // remove IP header len -= ip_hdr_len; // remove IP header
caplen -= ip_hdr_len; caplen -= ip_hdr_len;
@ -92,8 +80,7 @@ bool PacketFilter::MatchFilter(const Filter& f, const IP_Hdr& ip,
// Packet too short, will be dropped anyway. // Packet too short, will be dropped anyway.
return false; return false;
const struct tcphdr* tp = const struct tcphdr* tp = (const struct tcphdr*) ip.Payload();
(const struct tcphdr*) ((u_char*) ip4 + ip_hdr_len);
if ( tp->th_flags & f.tcp_flags ) if ( tp->th_flags & f.tcp_flags )
// At least one of the flags is set, so don't drop // At least one of the flags is set, so don't drop

View file

@ -14,16 +14,16 @@ public:
// Drops all packets from a particular source (which may be given // Drops all packets from a particular source (which may be given
// as an AddrVal or a SubnetVal) which hasn't any of TCP flags set // as an AddrVal or a SubnetVal) which hasn't any of TCP flags set
// (TH_*) with the given probability (from 0..MAX_PROB). // (TH_*) with the given probability (from 0..MAX_PROB).
void AddSrc(addr_type src, uint32 tcp_flags, double probability); void AddSrc(const IPAddr& src, uint32 tcp_flags, double probability);
void AddSrc(Val* src, uint32 tcp_flags, double probability); void AddSrc(Val* src, uint32 tcp_flags, double probability);
void AddDst(addr_type src, uint32 tcp_flags, double probability); void AddDst(const IPAddr& src, uint32 tcp_flags, double probability);
void AddDst(Val* src, uint32 tcp_flags, double probability); void AddDst(Val* src, uint32 tcp_flags, double probability);
// Removes the filter entry for the given src/dst // Removes the filter entry for the given src/dst
// Returns false if filter doesn not exist. // Returns false if filter doesn not exist.
bool RemoveSrc(addr_type src); bool RemoveSrc(const IPAddr& src);
bool RemoveSrc(Val* dst); bool RemoveSrc(Val* dst);
bool RemoveDst(addr_type dst); bool RemoveDst(const IPAddr& dst);
bool RemoveDst(Val* dst); bool RemoveDst(Val* dst);
// Returns true if packet matches a drop filter // Returns true if packet matches a drop filter

View file

@ -27,13 +27,16 @@ PacketSortElement::PacketSortElement(PktSrc* arg_src,
{ {
const struct ip* ip = (const struct ip*) (pkt + hdr_size); const struct ip* ip = (const struct ip*) (pkt + hdr_size);
if ( ip->ip_v == 4 ) if ( ip->ip_v == 4 )
ip_hdr = new IP_Hdr(ip); ip_hdr = new IP_Hdr(ip, false);
else if ( ip->ip_v == 6 && (caplen >= sizeof(struct ip6_hdr) + hdr_size) )
ip_hdr = new IP_Hdr((const struct ip6_hdr*) ip, false, caplen - hdr_size);
else else
ip_hdr = new IP_Hdr((const struct ip6_hdr*) ip); // Weird will be generated later in NetSessions::NextPacket.
return;
if ( ip_hdr->NextProto() == IPPROTO_TCP && if ( ip_hdr->NextProto() == IPPROTO_TCP &&
// Note: can't sort fragmented packets // Note: can't sort fragmented packets
(ip_hdr->FragField() & 0x3fff) == 0 ) ( ! ip_hdr->IsFragment() ) )
{ {
tcp_offset = hdr_size + ip_hdr->HdrLen(); tcp_offset = hdr_size + ip_hdr->HdrLen();
if ( caplen >= tcp_offset + sizeof(struct tcphdr) ) if ( caplen >= tcp_offset + sizeof(struct tcphdr) )
@ -65,7 +68,7 @@ PacketSortElement::PacketSortElement(PktSrc* arg_src,
payload_length = ip_hdr->PayloadLen() - tp->th_off * 4; payload_length = ip_hdr->PayloadLen() - tp->th_off * 4;
key = id.BuildConnKey(); key = BuildConnIDHashKey(id);
is_tcp = 1; is_tcp = 1;
} }

View file

@ -137,7 +137,7 @@ bool PersistenceSerializer::CheckForFile(UnserialInfo* info, const char* file,
bool PersistenceSerializer::ReadAll(bool is_init, bool delete_files) bool PersistenceSerializer::ReadAll(bool is_init, bool delete_files)
{ {
#ifdef USE_PERFTOOLS #ifdef USE_PERFTOOLS_DEBUG
HeapLeakChecker::Disabler disabler; HeapLeakChecker::Disabler disabler;
#endif #endif

View file

@ -382,6 +382,7 @@ void PktSrc::AddSecondaryTablePrograms()
{ {
delete program; delete program;
Close(); Close();
return;
} }
SecondaryProgram* sp = new SecondaryProgram(program, se); SecondaryProgram* sp = new SecondaryProgram(program, se);

View file

@ -1,34 +1,19 @@
#include "PrefixTable.h" #include "PrefixTable.h"
#include "Reporter.h" #include "Reporter.h"
// IPv4 version. inline static prefix_t* make_prefix(const IPAddr& addr, int width)
inline static prefix_t* make_prefix(const uint32 addr, int width)
{ {
prefix_t* prefix = (prefix_t*) safe_malloc(sizeof(prefix_t)); prefix_t* prefix = (prefix_t*) safe_malloc(sizeof(prefix_t));
memcpy(&prefix->add.sin, &addr, sizeof(prefix->add.sin)) ; addr.CopyIPv6(&prefix->add.sin6);
prefix->family = AF_INET;
prefix->bitlen = width;
prefix->ref_count = 1;
return prefix;
}
#ifdef BROv6
inline static prefix_t* make_prefix(const uint32* addr, int width)
{
prefix_t* prefix = (prefix_t*) safe_malloc(sizeof(prefix_t));
memcpy(&prefix->add.sin6, addr, 4 * sizeof(uint32));
prefix->family = AF_INET6; prefix->family = AF_INET6;
prefix->bitlen = width; prefix->bitlen = width;
prefix->ref_count = 1; prefix->ref_count = 1;
return prefix; return prefix;
} }
#endif
void* PrefixTable::Insert(const_addr_type addr, int width, void* data) void* PrefixTable::Insert(const IPAddr& addr, int width, void* data)
{ {
prefix_t* prefix = make_prefix(addr, width); prefix_t* prefix = make_prefix(addr, width);
patricia_node_t* node = patricia_lookup(tree, prefix); patricia_node_t* node = patricia_lookup(tree, prefix);
@ -55,12 +40,12 @@ void* PrefixTable::Insert(const Val* value, void* data)
switch ( value->Type()->Tag() ) { switch ( value->Type()->Tag() ) {
case TYPE_ADDR: case TYPE_ADDR:
return Insert(value->AsAddr(), NUM_ADDR_WORDS * 32, data); return Insert(value->AsAddr(), 128, data);
break; break;
case TYPE_SUBNET: case TYPE_SUBNET:
return Insert(value->AsSubNet()->net, return Insert(value->AsSubNet().Prefix(),
value->AsSubNet()->width, data); value->AsSubNet().LengthIPv6(), data);
break; break;
default: default:
@ -69,7 +54,7 @@ void* PrefixTable::Insert(const Val* value, void* data)
} }
} }
void* PrefixTable::Lookup(const_addr_type addr, int width, bool exact) const void* PrefixTable::Lookup(const IPAddr& addr, int width, bool exact) const
{ {
prefix_t* prefix = make_prefix(addr, width); prefix_t* prefix = make_prefix(addr, width);
patricia_node_t* node = patricia_node_t* node =
@ -89,12 +74,12 @@ void* PrefixTable::Lookup(const Val* value, bool exact) const
switch ( value->Type()->Tag() ) { switch ( value->Type()->Tag() ) {
case TYPE_ADDR: case TYPE_ADDR:
return Lookup(value->AsAddr(), NUM_ADDR_WORDS * 32, exact); return Lookup(value->AsAddr(), 128, exact);
break; break;
case TYPE_SUBNET: case TYPE_SUBNET:
return Lookup(value->AsSubNet()->net, return Lookup(value->AsSubNet().Prefix(),
value->AsSubNet()->width, exact); value->AsSubNet().LengthIPv6(), exact);
break; break;
default: default:
@ -104,7 +89,7 @@ void* PrefixTable::Lookup(const Val* value, bool exact) const
} }
} }
void* PrefixTable::Remove(const_addr_type addr, int width) void* PrefixTable::Remove(const IPAddr& addr, int width)
{ {
prefix_t* prefix = make_prefix(addr, width); prefix_t* prefix = make_prefix(addr, width);
patricia_node_t* node = patricia_search_exact(tree, prefix); patricia_node_t* node = patricia_search_exact(tree, prefix);
@ -128,11 +113,12 @@ void* PrefixTable::Remove(const Val* value)
switch ( value->Type()->Tag() ) { switch ( value->Type()->Tag() ) {
case TYPE_ADDR: case TYPE_ADDR:
return Remove(value->AsAddr(), NUM_ADDR_WORDS * 32); return Remove(value->AsAddr(), 128);
break; break;
case TYPE_SUBNET: case TYPE_SUBNET:
return Remove(value->AsSubNet()->net, value->AsSubNet()->width); return Remove(value->AsSubNet().Prefix(),
value->AsSubNet().LengthIPv6());
break; break;
default: default:

View file

@ -3,6 +3,7 @@
#include "Val.h" #include "Val.h"
#include "net_util.h" #include "net_util.h"
#include "IPAddr.h"
extern "C" { extern "C" {
#include "patricia.h" #include "patricia.h"
@ -24,7 +25,7 @@ public:
// Addr in network byte order. If data is zero, acts like a set. // Addr in network byte order. If data is zero, acts like a set.
// Returns ptr to old data if already existing. // Returns ptr to old data if already existing.
// For existing items without data, returns non-nil if found. // For existing items without data, returns non-nil if found.
void* Insert(const_addr_type addr, int width, void* data = 0); void* Insert(const IPAddr& addr, int width, void* data = 0);
// Value may be addr or subnet. // Value may be addr or subnet.
void* Insert(const Val* value, void* data = 0); void* Insert(const Val* value, void* data = 0);
@ -32,11 +33,11 @@ public:
// Returns nil if not found, pointer to data otherwise. // Returns nil if not found, pointer to data otherwise.
// For items without data, returns non-nil if found. // For items without data, returns non-nil if found.
// If exact is false, performs exact rather than longest-prefix match. // If exact is false, performs exact rather than longest-prefix match.
void* Lookup(const_addr_type addr, int width, bool exact = false) const; void* Lookup(const IPAddr& addr, int width, bool exact = false) const;
void* Lookup(const Val* value, bool exact = false) const; void* Lookup(const Val* value, bool exact = false) const;
// Returns pointer to data or nil if not found. // Returns pointer to data or nil if not found.
void* Remove(const_addr_type addr, int width); void* Remove(const IPAddr& addr, int width);
void* Remove(const Val* value); void* Remove(const Val* value);
void Clear() { Clear_Patricia(tree, 0); } void Clear() { Clear_Patricia(tree, 0); }

View file

@ -43,8 +43,7 @@ DataBlock::DataBlock(const u_char* data, int size, int arg_seq,
unsigned int Reassembler::total_size = 0; unsigned int Reassembler::total_size = 0;
Reassembler::Reassembler(int init_seq, const uint32* ip_addr, Reassembler::Reassembler(int init_seq, ReassemblerType arg_type)
ReassemblerType arg_type)
{ {
blocks = last_block = 0; blocks = last_block = 0;
trim_seq = last_reassem_seq = init_seq; trim_seq = last_reassem_seq = init_seq;

View file

@ -4,6 +4,7 @@
#define reassem_h #define reassem_h
#include "Obj.h" #include "Obj.h"
#include "IPAddr.h"
class DataBlock { class DataBlock {
public: public:
@ -25,8 +26,7 @@ enum ReassemblerType { REASSEM_IP, REASSEM_TCP };
class Reassembler : public BroObj { class Reassembler : public BroObj {
public: public:
Reassembler(int init_seq, const uint32* ip_addr, Reassembler(int init_seq, ReassemblerType arg_type);
ReassemblerType arg_type);
virtual ~Reassembler(); virtual ~Reassembler();
void NewBlock(double t, int seq, int len, const u_char* data); void NewBlock(double t, int seq, int len, const u_char* data);

View file

@ -183,8 +183,11 @@
#include "Sessions.h" #include "Sessions.h"
#include "File.h" #include "File.h"
#include "Conn.h" #include "Conn.h"
#include "LogMgr.h"
#include "Reporter.h" #include "Reporter.h"
#include "threading/SerialTypes.h"
#include "logging/Manager.h"
#include "IPAddr.h"
#include "bro_inet_ntop.h"
extern "C" { extern "C" {
#include "setsignal.h" #include "setsignal.h"
@ -463,7 +466,7 @@ static inline const char* ip2a(uint32 ip)
addr.s_addr = htonl(ip); addr.s_addr = htonl(ip);
return inet_ntop(AF_INET, &addr, buffer, 32); return bro_inet_ntop(AF_INET, &addr, buffer, 32);
} }
static pid_t child_pid = 0; static pid_t child_pid = 0;
@ -530,6 +533,7 @@ RemoteSerializer::RemoteSerializer()
terminating = false; terminating = false;
in_sync = 0; in_sync = 0;
last_flush = 0; last_flush = 0;
received_logs = 0;
} }
RemoteSerializer::~RemoteSerializer() RemoteSerializer::~RemoteSerializer()
@ -670,8 +674,8 @@ void RemoteSerializer::Fork()
} }
} }
RemoteSerializer::PeerID RemoteSerializer::Connect(addr_type ip, uint16 port, RemoteSerializer::PeerID RemoteSerializer::Connect(const IPAddr& ip,
const char* our_class, double retry, bool use_ssl) uint16 port, const char* our_class, double retry, bool use_ssl)
{ {
if ( ! using_communication ) if ( ! using_communication )
return true; return true;
@ -679,16 +683,12 @@ RemoteSerializer::PeerID RemoteSerializer::Connect(addr_type ip, uint16 port,
if ( ! initialized ) if ( ! initialized )
reporter->InternalError("remote serializer not initialized"); reporter->InternalError("remote serializer not initialized");
#ifdef BROv6 if ( ip.GetFamily() == IPv6 )
if ( ! is_v4_addr(ip) )
Error("inter-Bro communication not supported over IPv6"); Error("inter-Bro communication not supported over IPv6");
uint32 ip4 = to_v4_addr(ip); const uint32* bytes;
#else ip.GetBytes(&bytes);
uint32 ip4 = ip; uint32 ip4 = ntohl(*bytes);
#endif
ip4 = ntohl(ip4);
if ( ! child_pid ) if ( ! child_pid )
Fork(); Fork();
@ -1232,7 +1232,7 @@ bool RemoteSerializer::SendCapabilities(Peer* peer)
return caps ? SendToChild(MSG_CAPS, peer, 3, caps, 0, 0) : true; return caps ? SendToChild(MSG_CAPS, peer, 3, caps, 0, 0) : true;
} }
bool RemoteSerializer::Listen(addr_type ip, uint16 port, bool expect_ssl) bool RemoteSerializer::Listen(const IPAddr& ip, uint16 port, bool expect_ssl)
{ {
if ( ! using_communication ) if ( ! using_communication )
return true; return true;
@ -1240,16 +1240,12 @@ bool RemoteSerializer::Listen(addr_type ip, uint16 port, bool expect_ssl)
if ( ! initialized ) if ( ! initialized )
reporter->InternalError("remote serializer not initialized"); reporter->InternalError("remote serializer not initialized");
#ifdef BROv6 if ( ip.GetFamily() == IPv6 )
if ( ! is_v4_addr(ip) )
Error("inter-Bro communication not supported over IPv6"); Error("inter-Bro communication not supported over IPv6");
uint32 ip4 = to_v4_addr(ip); const uint32* bytes;
#else ip.GetBytes(&bytes);
uint32 ip4 = ip; uint32 ip4 = ntohl(*bytes);
#endif
ip4 = ntohl(ip4);
if ( ! SendToChild(MSG_LISTEN, 0, 3, ip4, port, expect_ssl) ) if ( ! SendToChild(MSG_LISTEN, 0, 3, ip4, port, expect_ssl) )
return false; return false;
@ -1359,6 +1355,14 @@ double RemoteSerializer::NextTimestamp(double* local_network_time)
{ {
Poll(false); Poll(false);
if ( received_logs > 0 )
{
// If we processed logs last time, assume there's more.
idle = false;
received_logs = 0;
return timer_mgr->Time();
}
double et = events.length() ? events[0]->time : -1; double et = events.length() ? events[0]->time : -1;
double pt = packets.length() ? packets[0]->time : -1; double pt = packets.length() ? packets[0]->time : -1;
@ -2476,7 +2480,7 @@ bool RemoteSerializer::ProcessRemotePrint()
return true; return true;
} }
bool RemoteSerializer::SendLogCreateWriter(EnumVal* id, EnumVal* writer, string path, int num_fields, const LogField* const * fields) bool RemoteSerializer::SendLogCreateWriter(EnumVal* id, EnumVal* writer, string path, int num_fields, const threading::Field* const * fields)
{ {
loop_over_list(peers, i) loop_over_list(peers, i)
{ {
@ -2486,7 +2490,7 @@ bool RemoteSerializer::SendLogCreateWriter(EnumVal* id, EnumVal* writer, string
return true; return true;
} }
bool RemoteSerializer::SendLogCreateWriter(PeerID peer_id, EnumVal* id, EnumVal* writer, string path, int num_fields, const LogField* const * fields) bool RemoteSerializer::SendLogCreateWriter(PeerID peer_id, EnumVal* id, EnumVal* writer, string path, int num_fields, const threading::Field* const * fields)
{ {
SetErrorDescr("logging"); SetErrorDescr("logging");
@ -2499,6 +2503,9 @@ bool RemoteSerializer::SendLogCreateWriter(PeerID peer_id, EnumVal* id, EnumVal*
if ( peer->phase != Peer::HANDSHAKE && peer->phase != Peer::RUNNING ) if ( peer->phase != Peer::HANDSHAKE && peer->phase != Peer::RUNNING )
return false; return false;
if ( ! peer->logs_requested )
return false;
BinarySerializationFormat fmt; BinarySerializationFormat fmt;
fmt.StartWrite(); fmt.StartWrite();
@ -2540,7 +2547,7 @@ error:
return false; return false;
} }
bool RemoteSerializer::SendLogWrite(EnumVal* id, EnumVal* writer, string path, int num_fields, const LogVal* const * vals) bool RemoteSerializer::SendLogWrite(EnumVal* id, EnumVal* writer, string path, int num_fields, const threading::Value* const * vals)
{ {
loop_over_list(peers, i) loop_over_list(peers, i)
{ {
@ -2550,7 +2557,7 @@ bool RemoteSerializer::SendLogWrite(EnumVal* id, EnumVal* writer, string path, i
return true; return true;
} }
bool RemoteSerializer::SendLogWrite(Peer* peer, EnumVal* id, EnumVal* writer, string path, int num_fields, const LogVal* const * vals) bool RemoteSerializer::SendLogWrite(Peer* peer, EnumVal* id, EnumVal* writer, string path, int num_fields, const threading::Value* const * vals)
{ {
if ( peer->phase != Peer::HANDSHAKE && peer->phase != Peer::RUNNING ) if ( peer->phase != Peer::HANDSHAKE && peer->phase != Peer::RUNNING )
return false; return false;
@ -2558,7 +2565,9 @@ bool RemoteSerializer::SendLogWrite(Peer* peer, EnumVal* id, EnumVal* writer, st
if ( ! peer->logs_requested ) if ( ! peer->logs_requested )
return false; return false;
assert(peer->log_buffer); if ( ! peer->log_buffer )
// Peer shutting down.
return false;
// Serialize the log record entry. // Serialize the log record entry.
@ -2593,7 +2602,10 @@ bool RemoteSerializer::SendLogWrite(Peer* peer, EnumVal* id, EnumVal* writer, st
if ( len > (LOG_BUFFER_SIZE - peer->log_buffer_used) || (network_time - last_flush > 1.0) ) if ( len > (LOG_BUFFER_SIZE - peer->log_buffer_used) || (network_time - last_flush > 1.0) )
{ {
if ( ! FlushLogBuffer(peer) ) if ( ! FlushLogBuffer(peer) )
{
delete [] data;
return false; return false;
}
} }
// If the data is actually larger than our complete buffer, just send it out. // If the data is actually larger than our complete buffer, just send it out.
@ -2616,6 +2628,9 @@ error:
bool RemoteSerializer::FlushLogBuffer(Peer* p) bool RemoteSerializer::FlushLogBuffer(Peer* p)
{ {
if ( ! p->logs_requested )
return false;
last_flush = network_time; last_flush = network_time;
if ( p->state == Peer::CLOSING ) if ( p->state == Peer::CLOSING )
@ -2637,11 +2652,17 @@ bool RemoteSerializer::ProcessLogCreateWriter()
if ( current_peer->state == Peer::CLOSING ) if ( current_peer->state == Peer::CLOSING )
return false; return false;
#ifdef USE_PERFTOOLS_DEBUG
// Don't track allocations here, they'll be released only after the
// main loop exists. And it's just a tiny amount anyway.
HeapLeakChecker::Disabler disabler;
#endif
assert(current_args); assert(current_args);
EnumVal* id_val = 0; EnumVal* id_val = 0;
EnumVal* writer_val = 0; EnumVal* writer_val = 0;
LogField** fields = 0; threading::Field** fields = 0;
BinarySerializationFormat fmt; BinarySerializationFormat fmt;
fmt.StartRead(current_args->data, current_args->len); fmt.StartRead(current_args->data, current_args->len);
@ -2658,11 +2679,11 @@ bool RemoteSerializer::ProcessLogCreateWriter()
if ( ! success ) if ( ! success )
goto error; goto error;
fields = new LogField* [num_fields]; fields = new threading::Field* [num_fields];
for ( int i = 0; i < num_fields; i++ ) for ( int i = 0; i < num_fields; i++ )
{ {
fields[i] = new LogField; fields[i] = new threading::Field;
if ( ! fields[i]->Read(&fmt) ) if ( ! fields[i]->Read(&fmt) )
goto error; goto error;
} }
@ -2672,7 +2693,7 @@ bool RemoteSerializer::ProcessLogCreateWriter()
id_val = new EnumVal(id, BifType::Enum::Log::ID); id_val = new EnumVal(id, BifType::Enum::Log::ID);
writer_val = new EnumVal(writer, BifType::Enum::Log::Writer); writer_val = new EnumVal(writer, BifType::Enum::Log::Writer);
if ( ! log_mgr->CreateWriter(id_val, writer_val, path, num_fields, fields) ) if ( ! log_mgr->CreateWriter(id_val, writer_val, path, num_fields, fields, true, false) )
goto error; goto error;
Unref(id_val); Unref(id_val);
@ -2703,7 +2724,7 @@ bool RemoteSerializer::ProcessLogWrite()
// Unserialize one entry. // Unserialize one entry.
EnumVal* id_val = 0; EnumVal* id_val = 0;
EnumVal* writer_val = 0; EnumVal* writer_val = 0;
LogVal** vals = 0; threading::Value** vals = 0;
int id, writer; int id, writer;
string path; string path;
@ -2717,11 +2738,11 @@ bool RemoteSerializer::ProcessLogWrite()
if ( ! success ) if ( ! success )
goto error; goto error;
vals = new LogVal* [num_fields]; vals = new threading::Value* [num_fields];
for ( int i = 0; i < num_fields; i++ ) for ( int i = 0; i < num_fields; i++ )
{ {
vals[i] = new LogVal; vals[i] = new threading::Value;
if ( ! vals[i]->Read(&fmt) ) if ( ! vals[i]->Read(&fmt) )
goto error; goto error;
} }
@ -2741,6 +2762,8 @@ bool RemoteSerializer::ProcessLogWrite()
fmt.EndRead(); fmt.EndRead();
++received_logs;
return true; return true;
error: error:
@ -2850,7 +2873,7 @@ void RemoteSerializer::GotID(ID* id, Val* val)
(desc && *desc) ? desc : "not set"), (desc && *desc) ? desc : "not set"),
current_peer); current_peer);
#ifdef USE_PERFTOOLS #ifdef USE_PERFTOOLS_DEBUG
// May still be cached, but we don't care. // May still be cached, but we don't care.
heap_checker->IgnoreObject(id); heap_checker->IgnoreObject(id);
#endif #endif
@ -3382,6 +3405,11 @@ void SocketComm::Run()
small_timeout.tv_usec = small_timeout.tv_usec =
io->CanWrite() || io->CanRead() ? 1 : 10; io->CanWrite() || io->CanRead() ? 1 : 10;
#if 0
if ( ! io->CanWrite() )
usleep(10);
#endif
int a = select(max_fd + 1, &fd_read, &fd_write, &fd_except, int a = select(max_fd + 1, &fd_read, &fd_write, &fd_except,
&small_timeout); &small_timeout);

View file

@ -14,8 +14,11 @@
// FIXME: Change this to network byte order // FIXME: Change this to network byte order
class IncrementalSendTimer; class IncrementalSendTimer;
class LogField;
class LogVal; namespace threading {
class Field;
class Value;
}
// This class handles the communication done in Bro's main loop. // This class handles the communication done in Bro's main loop.
class RemoteSerializer : public Serializer, public IOSource { class RemoteSerializer : public Serializer, public IOSource {
@ -32,7 +35,7 @@ public:
static const PeerID PEER_NONE = SOURCE_LOCAL; static const PeerID PEER_NONE = SOURCE_LOCAL;
// Connect to host (returns PEER_NONE on error). // Connect to host (returns PEER_NONE on error).
PeerID Connect(addr_type ip, uint16 port, const char* our_class, double retry, bool use_ssl); PeerID Connect(const IPAddr& ip, uint16 port, const char* our_class, double retry, bool use_ssl);
// Close connection to host. // Close connection to host.
bool CloseConnection(PeerID peer); bool CloseConnection(PeerID peer);
@ -60,7 +63,7 @@ public:
bool CompleteHandshake(PeerID peer); bool CompleteHandshake(PeerID peer);
// Start to listen. // Start to listen.
bool Listen(addr_type ip, uint16 port, bool expect_ssl); bool Listen(const IPAddr& ip, uint16 port, bool expect_ssl);
// Stop it. // Stop it.
bool StopListening(); bool StopListening();
@ -99,13 +102,13 @@ public:
bool SendPrintHookEvent(BroFile* f, const char* txt, size_t len); bool SendPrintHookEvent(BroFile* f, const char* txt, size_t len);
// Send a request to create a writer on a remote side. // Send a request to create a writer on a remote side.
bool SendLogCreateWriter(PeerID peer, EnumVal* id, EnumVal* writer, string path, int num_fields, const LogField* const * fields); bool SendLogCreateWriter(PeerID peer, EnumVal* id, EnumVal* writer, string path, int num_fields, const threading::Field* const * fields);
// Broadcasts a request to create a writer. // Broadcasts a request to create a writer.
bool SendLogCreateWriter(EnumVal* id, EnumVal* writer, string path, int num_fields, const LogField* const * fields); bool SendLogCreateWriter(EnumVal* id, EnumVal* writer, string path, int num_fields, const threading::Field* const * fields);
// Broadcast a log entry to everybody interested. // Broadcast a log entry to everybody interested.
bool SendLogWrite(EnumVal* id, EnumVal* writer, string path, int num_fields, const LogVal* const * vals); bool SendLogWrite(EnumVal* id, EnumVal* writer, string path, int num_fields, const threading::Value* const * vals);
// Synchronzizes time with all connected peers. Returns number of // Synchronzizes time with all connected peers. Returns number of
// current sync-point, or -1 on error. // current sync-point, or -1 on error.
@ -300,7 +303,7 @@ protected:
bool SendID(SerialInfo* info, Peer* peer, const ID& id); bool SendID(SerialInfo* info, Peer* peer, const ID& id);
bool SendCapabilities(Peer* peer); bool SendCapabilities(Peer* peer);
bool SendPacket(SerialInfo* info, Peer* peer, const Packet& p); bool SendPacket(SerialInfo* info, Peer* peer, const Packet& p);
bool SendLogWrite(Peer* peer, EnumVal* id, EnumVal* writer, string path, int num_fields, const LogVal* const * vals); bool SendLogWrite(Peer* peer, EnumVal* id, EnumVal* writer, string path, int num_fields, const threading::Value* const * vals);
void UnregisterHandlers(Peer* peer); void UnregisterHandlers(Peer* peer);
void RaiseEvent(EventHandlerPtr event, Peer* peer, const char* arg = 0); void RaiseEvent(EventHandlerPtr event, Peer* peer, const char* arg = 0);
@ -335,6 +338,7 @@ private:
int propagate_accesses; int propagate_accesses;
bool ignore_accesses; bool ignore_accesses;
bool terminating; bool terminating;
int received_logs;
Peer* source_peer; Peer* source_peer;
PeerID id_counter; // Keeps track of assigned IDs. PeerID id_counter; // Keeps track of assigned IDs.
uint32 current_sync_point; uint32 current_sync_point;

View file

@ -155,7 +155,7 @@ void Reporter::WeirdHelper(EventHandlerPtr event, Val* conn_val, const char* add
delete vl; delete vl;
} }
void Reporter::WeirdFlowHelper(const uint32* orig, const uint32* resp, const char* fmt_name, ...) void Reporter::WeirdFlowHelper(const IPAddr& orig, const IPAddr& resp, const char* fmt_name, ...)
{ {
val_list* vl = new val_list(2); val_list* vl = new val_list(2);
vl->append(new AddrVal(orig)); vl->append(new AddrVal(orig));
@ -184,7 +184,7 @@ void Reporter::Weird(Val* conn_val, const char* name, const char* addl)
WeirdHelper(conn_weird, conn_val, addl, "%s", name); WeirdHelper(conn_weird, conn_val, addl, "%s", name);
} }
void Reporter::Weird(const uint32* orig, const uint32* resp, const char* name) void Reporter::Weird(const IPAddr& orig, const IPAddr& resp, const char* name)
{ {
WeirdFlowHelper(orig, resp, "%s", name); WeirdFlowHelper(orig, resp, "%s", name);
} }

View file

@ -9,8 +9,8 @@
#include <utility> #include <utility>
#include "util.h" #include "util.h"
#include "net_util.h"
#include "EventHandler.h" #include "EventHandler.h"
#include "IPAddr.h"
class Connection; class Connection;
class Location; class Location;
@ -74,7 +74,7 @@ public:
void Weird(const char* name); // Raises net_weird(). void Weird(const char* name); // Raises net_weird().
void Weird(Connection* conn, const char* name, const char* addl = ""); // Raises conn_weird(). void Weird(Connection* conn, const char* name, const char* addl = ""); // Raises conn_weird().
void Weird(Val* conn_val, const char* name, const char* addl = ""); // Raises conn_weird(). void Weird(Val* conn_val, const char* name, const char* addl = ""); // Raises conn_weird().
void Weird(const uint32* orig, const uint32* resp, const char* name); // Raises flow_weird(). void Weird(const IPAddr& orig, const IPAddr& resp, const char* name); // Raises flow_weird().
// Syslog a message. This methods does nothing if we're running // Syslog a message. This methods does nothing if we're running
// offline from a trace. // offline from a trace.
@ -121,7 +121,7 @@ private:
// The order if addl, name needs to be like that since fmt_name can // The order if addl, name needs to be like that since fmt_name can
// contain format specifiers // contain format specifiers
void WeirdHelper(EventHandlerPtr event, Val* conn_val, const char* addl, const char* fmt_name, ...); void WeirdHelper(EventHandlerPtr event, Val* conn_val, const char* addl, const char* fmt_name, ...);
void WeirdFlowHelper(const uint32* orig, const uint32* resp, const char* fmt_name, ...); void WeirdFlowHelper(const IPAddr& orig, const IPAddr& resp, const char* fmt_name, ...);
int errors; int errors;
bool via_events; bool via_events;

View file

@ -73,6 +73,9 @@ RuleHdrTest::RuleHdrTest(RuleHdrTest& h)
copied_set->ids = orig_set->ids; copied_set->ids = orig_set->ids;
loop_over_list(orig_set->patterns, l) loop_over_list(orig_set->patterns, l)
copied_set->patterns.append(copy_string(orig_set->patterns[l])); copied_set->patterns.append(copy_string(orig_set->patterns[l]));
delete copied_set;
// TODO: Why do we create copied_set only to then
// never use it?
} }
} }
@ -188,7 +191,7 @@ void RuleMatcher::Delete(RuleHdrTest* node)
bool RuleMatcher::ReadFiles(const name_list& files) bool RuleMatcher::ReadFiles(const name_list& files)
{ {
#ifdef USE_PERFTOOLS #ifdef USE_PERFTOOLS_DEBUG
HeapLeakChecker::Disabler disabler; HeapLeakChecker::Disabler disabler;
#endif #endif
@ -1067,16 +1070,22 @@ static bool val_to_maskedval(Val* v, maskedvalue_list* append_to)
break; break;
case TYPE_SUBNET: case TYPE_SUBNET:
#ifdef BROv6
{ {
uint32* n = v->AsSubNet()->net; const uint32* n;
uint32* m = v->AsSubNetVal()->Mask(); uint32 m[4];
v->AsSubNet().Prefix().GetBytes(&n);
v->AsSubNetVal()->Mask().CopyIPv6(m);
for ( unsigned int i = 0; i < 4; ++i )
m[i] = ntohl(m[i]);
bool is_v4_mask = m[0] == 0xffffffff && bool is_v4_mask = m[0] == 0xffffffff &&
m[1] == m[0] && m[2] == m[0]; m[1] == m[0] && m[2] == m[0];
if ( is_v4_addr(n) && is_v4_mask ) if ( v->AsSubNet().Prefix().GetFamily() == IPv4 &&
is_v4_mask )
{ {
mval->val = ntohl(to_v4_addr(n)); mval->val = ntohl(*n);
mval->mask = m[3]; mval->mask = m[3];
} }
@ -1087,10 +1096,6 @@ static bool val_to_maskedval(Val* v, maskedvalue_list* append_to)
mval->mask = 0; mval->mask = 0;
} }
} }
#else
mval->val = ntohl(v->AsSubNet()->net);
mval->mask = v->AsSubNetVal()->Mask();
#endif
break; break;
default: default:
@ -1114,7 +1119,12 @@ void id_to_maskedvallist(const char* id, maskedvalue_list* append_to)
val_list* vals = v->AsTableVal()->ConvertToPureList()->Vals(); val_list* vals = v->AsTableVal()->ConvertToPureList()->Vals();
loop_over_list(*vals, i ) loop_over_list(*vals, i )
if ( ! val_to_maskedval((*vals)[i], append_to) ) if ( ! val_to_maskedval((*vals)[i], append_to) )
{
delete_vals(vals);
return; return;
}
delete_vals(vals);
} }
else else

View file

@ -353,7 +353,6 @@ void SMTP_Analyzer::ProcessLine(int length, const char* line, bool orig)
int ext_len; int ext_len;
get_word(end_of_line - line, line, ext_len, ext); get_word(end_of_line - line, line, ext_len, ext);
line = skip_whitespace(line + ext_len, end_of_line);
ProcessExtension(ext_len, ext); ProcessExtension(ext_len, ext);
} }
} }

View file

@ -66,7 +66,8 @@ void SSH_Analyzer::DeliverStream(int length, const u_char* data, bool is_orig)
{ {
if ( length >= i ) if ( length >= i )
{ {
const uint32* dst; IPAddr dst;
if ( is_orig ) if ( is_orig )
dst = TCP()->Orig()->dst_addr; dst = TCP()->Orig()->dst_addr;
else else

View file

@ -125,7 +125,7 @@ SERIAL_EXPR(FIELD_EXPR, 22)
SERIAL_EXPR(HAS_FIELD_EXPR, 23) SERIAL_EXPR(HAS_FIELD_EXPR, 23)
SERIAL_EXPR(RECORD_CONSTRUCTOR_EXPR, 24) SERIAL_EXPR(RECORD_CONSTRUCTOR_EXPR, 24)
SERIAL_EXPR(FIELD_ASSIGN_EXPR, 25) SERIAL_EXPR(FIELD_ASSIGN_EXPR, 25)
SERIAL_EXPR(RECORD_MATCH_EXPR, 26) // There used to be a SERIAL_EXPR(RECORD_MATCH_EXPR, 26) here
SERIAL_EXPR(ARITH_COERCE_EXPR, 27) SERIAL_EXPR(ARITH_COERCE_EXPR, 27)
SERIAL_EXPR(RECORD_COERCE_EXPR, 28) SERIAL_EXPR(RECORD_COERCE_EXPR, 28)
SERIAL_EXPR(FLATTEN_EXPR, 29) SERIAL_EXPR(FLATTEN_EXPR, 29)

View file

@ -230,6 +230,71 @@ bool BinarySerializationFormat::Read(string* v, const char* tag)
return true; return true;
} }
bool BinarySerializationFormat::Read(IPAddr* addr, const char* tag)
{
int n = 0;
if ( ! Read(&n, "addr-len") )
return false;
if ( n != 1 && n != 4 )
return false;
uint32_t raw[4];
for ( int i = 0; i < n; ++i )
{
if ( ! Read(&raw[i], "addr-part") )
return false;
raw[i] = htonl(raw[i]);
}
if ( n == 1 )
*addr = IPAddr(IPv4, raw, IPAddr::Network);
else
*addr = IPAddr(IPv6, raw, IPAddr::Network);
return true;
}
bool BinarySerializationFormat::Read(IPPrefix* prefix, const char* tag)
{
IPAddr addr;
int len;
if ( ! (Read(&addr, "prefix") && Read(&len, "width")) )
return false;
*prefix = IPPrefix(addr, len);
return true;
}
bool BinarySerializationFormat::Read(struct in_addr* addr, const char* tag)
{
uint32_t* bytes = (uint32_t*) &addr->s_addr;
if ( ! Read(&bytes[0], "addr4") )
return false;
bytes[0] = htonl(bytes[0]);
return true;
}
bool BinarySerializationFormat::Read(struct in6_addr* addr, const char* tag)
{
uint32_t* bytes = (uint32_t*) &addr->s6_addr;
for ( int i = 0; i < 4; ++i )
{
if ( ! Read(&bytes[i], "addr6-part") )
return false;
bytes[i] = htonl(bytes[i]);
}
return true;
}
bool BinarySerializationFormat::Write(char v, const char* tag) bool BinarySerializationFormat::Write(char v, const char* tag)
{ {
DBG_LOG(DBG_SERIAL, "Write char %s [%s]", fmt_bytes(&v, 1), tag); DBG_LOG(DBG_SERIAL, "Write char %s [%s]", fmt_bytes(&v, 1), tag);
@ -299,6 +364,53 @@ bool BinarySerializationFormat::Write(const string& s, const char* tag)
return Write(s.data(), s.size(), tag); return Write(s.data(), s.size(), tag);
} }
bool BinarySerializationFormat::Write(const IPAddr& addr, const char* tag)
{
const uint32_t* raw;
int n = addr.GetBytes(&raw);
assert(n == 1 || n == 4);
if ( ! Write(n, "addr-len") )
return false;
for ( int i = 0; i < n; ++i )
{
if ( ! Write(ntohl(raw[i]), "addr-part") )
return false;
}
return true;
}
bool BinarySerializationFormat::Write(const IPPrefix& prefix, const char* tag)
{
return Write(prefix.Prefix(), "prefix") && Write(prefix.Length(), "width");
}
bool BinarySerializationFormat::Write(const struct in_addr& addr, const char* tag)
{
const uint32_t* bytes = (uint32_t*) &addr.s_addr;
if ( ! Write(ntohl(bytes[0]), "addr4") )
return false;
return true;
}
bool BinarySerializationFormat::Write(const struct in6_addr& addr, const char* tag)
{
const uint32_t* bytes = (uint32_t*) &addr.s6_addr;
for ( int i = 0; i < 4; ++i )
{
if ( ! Write(ntohl(bytes[i]), "addr6-part") )
return false;
}
return true;
}
bool BinarySerializationFormat::WriteOpenTag(const char* tag) bool BinarySerializationFormat::WriteOpenTag(const char* tag)
{ {
return true; return true;
@ -389,6 +501,30 @@ bool XMLSerializationFormat::Read(string* s, const char* tag)
return false; return false;
} }
bool XMLSerializationFormat::Read(IPAddr* addr, const char* tag)
{
reporter->InternalError("no reading of xml");
return false;
}
bool XMLSerializationFormat::Read(IPPrefix* prefix, const char* tag)
{
reporter->InternalError("no reading of xml");
return false;
}
bool XMLSerializationFormat::Read(struct in_addr* addr, const char* tag)
{
reporter->InternalError("no reading of xml");
return false;
}
bool XMLSerializationFormat::Read(struct in6_addr* addr, const char* tag)
{
reporter->InternalError("no reading of xml");
return false;
}
bool XMLSerializationFormat::Write(char v, const char* tag) bool XMLSerializationFormat::Write(char v, const char* tag)
{ {
return WriteElem(tag, "char", &v, 1); return WriteElem(tag, "char", &v, 1);
@ -469,6 +605,30 @@ bool XMLSerializationFormat::Write(const char* buf, int len, const char* tag)
return WriteElem(tag, "string", buf, len); return WriteElem(tag, "string", buf, len);
} }
bool XMLSerializationFormat::Write(const IPAddr& addr, const char* tag)
{
reporter->InternalError("XML output of addresses not implemented");
return false;
}
bool XMLSerializationFormat::Write(const IPPrefix& prefix, const char* tag)
{
reporter->InternalError("XML output of prefixes not implemented");
return false;
}
bool XMLSerializationFormat::Write(const struct in_addr& addr, const char* tag)
{
reporter->InternalError("XML output of in_addr not implemented");
return false;
}
bool XMLSerializationFormat::Write(const struct in6_addr& addr, const char* tag)
{
reporter->InternalError("XML output of in6_addr not implemented");
return false;
}
bool XMLSerializationFormat::WriteEncodedString(const char* s, int len) bool XMLSerializationFormat::WriteEncodedString(const char* s, int len)
{ {
while ( len-- ) while ( len-- )

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