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
* Updates to the Software framework to simplify the API.
(Bernhard Amann)
* Updates to the Software framework to simplify the API. (Bernhard
Amann)
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

View file

@ -1,5 +1,5 @@
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)
########################################################################
@ -89,15 +89,29 @@ if (LIBGEOIP_FOUND)
endif ()
set(USE_PERFTOOLS false)
if (ENABLE_PERFTOOLS)
find_package(GooglePerftools)
if (GOOGLEPERFTOOLS_FOUND)
set(USE_PERFTOOLS true)
include_directories(BEFORE ${GooglePerftools_INCLUDE_DIR})
set(USE_PERFTOOLS_DEBUG false)
find_package(GooglePerftools)
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})
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
${BinPAC_LIBRARY}
${PCAP_LIBRARY}
@ -183,6 +197,7 @@ message(
"\n"
"\nGeoIP: ${USE_GEOIP}"
"\nGoogle perftools: ${USE_PERFTOOLS}"
"\n debugging: ${USE_PERFTOOLS_DEBUG}"
"\n"
"\n================================================================\n"
)

View file

@ -8,7 +8,7 @@ Prerequisites
Bro relies on the following libraries and tools, which need to be installed
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

46
NEWS
View file

@ -5,6 +5,51 @@ Release Notes
This document summarizes the most important changes in the current Bro
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
-------
@ -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
pcap_compile_nopcap */
#cmakedefine DONT_HAVE_LIBPCAP_PCAP_FREECODE
@ -112,7 +109,10 @@
#cmakedefine HAVE_GEOIP_CITY_EDITION_REV0_V6
/* Use Google's perftools */
#cmakedefine USE_PERFTOOLS
#cmakedefine USE_PERFTOOLS_DEBUG
/* Analyze Mobile IPv6 traffic */
#cmakedefine ENABLE_MOBILE_IPV6
/* Version number of package */
#define VERSION "@VERSION@"
@ -152,3 +152,47 @@
#ifndef HAVE_DLT_PPP_SERIAL
#define DLT_PPP_SERIAL @DLT_PPP_SERIAL@
#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]
--scriptdir=PATH root installation directory for Bro scripts
[PREFIX/share/bro]
--conf-files-dir=PATH config files installation directory [PREFIX/etc]
Optional Features:
--enable-debug compile in debugging mode
--enable-brov6 enable IPv6 processing
--enable-perftools use Google's perftools
--enable-mobile-ipv6 analyze mobile IPv6 features defined by RFC 6275
--enable-perftools-debug use Google's perftools for debugging
--disable-broccoli don't build or install the Broccoli library
--disable-broctl don't install Broctl
--disable-auxtools don't build or install auxilliary tools
@ -86,20 +87,22 @@ append_cache_entry () {
# set defaults
builddir=build
prefix=/usr/local/bro
CMakeCacheEntries=""
append_cache_entry CMAKE_INSTALL_PREFIX PATH /usr/local/bro
append_cache_entry BRO_ROOT_DIR PATH /usr/local/bro
append_cache_entry PY_MOD_INSTALL_DIR PATH /usr/local/bro/lib/broctl
append_cache_entry BRO_SCRIPT_INSTALL_PATH STRING /usr/local/bro/share/bro
append_cache_entry CMAKE_INSTALL_PREFIX PATH $prefix
append_cache_entry BRO_ROOT_DIR PATH $prefix
append_cache_entry PY_MOD_INSTALL_DIR PATH $prefix/lib/broctl
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 BROv6 BOOL false
append_cache_entry ENABLE_PERFTOOLS BOOL false
append_cache_entry ENABLE_PERFTOOLS_DEBUG BOOL false
append_cache_entry BinPAC_SKIP_INSTALL BOOL true
append_cache_entry BUILD_SHARED_LIBS BOOL true
append_cache_entry INSTALL_AUX_TOOLS BOOL true
append_cache_entry INSTALL_BROCCOLI BOOL true
append_cache_entry INSTALL_BROCTL BOOL true
append_cache_entry CPACK_SOURCE_IGNORE_FILES STRING
append_cache_entry ENABLE_MOBILE_IPV6 BOOL false
# parse arguments
while [ $# -ne 0 ]; do
@ -120,25 +123,27 @@ while [ $# -ne 0 ]; do
CMakeGenerator="$optarg"
;;
--prefix=*)
prefix=$optarg
append_cache_entry CMAKE_INSTALL_PREFIX PATH $optarg
append_cache_entry BRO_ROOT_DIR PATH $optarg
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=*)
append_cache_entry BRO_SCRIPT_INSTALL_PATH STRING $optarg
user_set_scriptdir="true"
;;
--conf-files-dir=*)
append_cache_entry BRO_ETC_INSTALL_DIR PATH $optarg
user_set_conffilesdir="true"
;;
--enable-debug)
append_cache_entry ENABLE_DEBUG BOOL true
;;
--enable-brov6)
append_cache_entry BROv6 BOOL true
--enable-mobile-ipv6)
append_cache_entry ENABLE_MOBILE_IPV6 BOOL true
;;
--enable-perftools)
append_cache_entry ENABLE_PERFTOOLS BOOL true
--enable-perftools-debug)
append_cache_entry ENABLE_PERFTOOLS_DEBUG BOOL true
;;
--disable-broccoli)
append_cache_entry INSTALL_BROCCOLI BOOL false
@ -183,7 +188,6 @@ while [ $# -ne 0 ]; do
append_cache_entry LibGeoIP_ROOT_DIR PATH $optarg
;;
--with-perftools=*)
append_cache_entry ENABLE_PERFTOOLS BOOL true
append_cache_entry GooglePerftools_ROOT_DIR PATH $optarg
;;
--with-python=*)
@ -232,6 +236,14 @@ while [ $# -ne 0 ]; do
shift
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 build directory exists, check if it has a CMake cache
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
sending emails.
* RPM/RedHat-based Linux:
* RedHat Enterprise Linux:
.. console::
sudo yum install geoip-devel sendmail
* CentOS Linux:
.. 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.
``-42`` or ``+5``. When using type inferencing use care so that the
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`.
.. bro:type:: count
@ -32,7 +32,7 @@ The Bro scripting language supports the following built-in types.
.. bro:type:: counter
An alias to :bro:type:`count`
An alias to :bro:type:`count`.
.. 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.
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
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, };
The last comma is after ``Blue`` is optional.
The last comma after ``Blue`` is optional.
.. 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``.
Ports can be compared for equality and also for ordering. When
comparing order across transport-level protocols, ``/unknown`` <
``/tcp`` < ``/udp`` < ``icmp``, for example ``65535/tcp`` is smaller
comparing order across transport-level protocols, ``unknown`` <
``tcp`` < ``udp`` < ``icmp``, for example ``65535/tcp`` is smaller
than ``0/udp``.
.. bro:type:: addr
A type representing an IP address. Currently, Bro defaults to only
supporting IPv4 addresses unless configured/built with
``--enable-brov6``, in which case, IPv6 addresses are supported.
A type representing an IP address.
IPv4 address constants are written in "dotted quad" format,
``A1.A2.A3.A4``, where Ai all lie between 0 and 255.
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
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
``subnet`` constant is written as an :bro:type:`addr` followed by a
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
@ -230,7 +232,7 @@ The Bro scripting language supports the following built-in types.
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`
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
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:
.. code:: bro
@ -412,7 +414,7 @@ The Bro scripting language supports the following built-in types.
print f, "hello, world";
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`.
.. bro:type:: func
@ -512,22 +514,22 @@ scripting language supports the following built-in attributes.
.. 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
singleton ``[$a=127.0.0.1]`` or pair ``[$a=127.0.0.1, $b=80/tcp]``.
.. bro:attr:: &default
Uses a default value for a record field or container elements. For
example, ``table[int] of string &default="foo" }`` would create
table that returns The :bro:type:`string` ``"foo"`` for any
example, ``table[int] of string &default="foo" }`` would create a
table that returns the :bro:type:`string` ``"foo"`` for any
non-existing index.
.. bro:attr:: &redef
Allows for redefinition of initial object values. This is typically
used with constants, for example, ``const clever = T &redef;`` would
allow the constant to be redifined at some later point during script
allow the constant to be redefined at some later point during script
execution.
.. bro:attr:: &rotate_interval
@ -536,7 +538,7 @@ scripting language supports the following built-in attributes.
.. 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
@ -548,7 +550,12 @@ scripting language supports the following built-in attributes.
.. 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

View file

@ -46,6 +46,13 @@ type index_vec: vector of count;
## then remove this alias.
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.
##
## .. 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.
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.
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
@ -93,11 +102,13 @@ type icmp_conn: record {
## .. bro:see:: icmp_time_exceeded icmp_unreachable
type icmp_context: record {
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.
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
## the case, the other fields will all be set to null values.
## True if the packet's IP header is not fully included in the context
## 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_checksum: bool; ##< True if the packet's IP checksum is not correct.
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
## 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;
## ``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;
# 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_TCP = 6; ##< TCP.
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.
## 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
type ip_hdr: record {
## .. bro:see:: ip6_hdr ip6_hdr_chain ip6_hopopts ip6_dstopts
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.
tos: count; ##< Type of service.
len: count; ##< Total length.
@ -987,10 +1305,11 @@ type icmp_hdr: record {
##
## .. bro:see:: new_packet
type pkt_hdr: record {
ip: ip_hdr; ##< The IP header.
tcp: tcp_hdr &optional; ##< The TCP header if a TCP packet.
udp: udp_hdr &optional; ##< The UDP header if a UDP packet.
icmp: icmp_hdr &optional; ##< The ICMP header if an ICMP packet.
ip: ip4_hdr &optional; ##< The IPv4 header if an IPv4 packet.
ip6: ip6_hdr &optional; ##< The IPv6 header if an IPv6 packet.
tcp: tcp_hdr &optional; ##< The TCP header if a TCP 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
@ -1010,7 +1329,7 @@ global discarder_maxlen = 128 &redef;
## analysis. If the function signals to discard a packet, no further processing
## 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.
##
@ -1019,15 +1338,15 @@ global discarder_maxlen = 128 &redef;
##
## .. note:: This is very low-level functionality and potentially expensive.
## 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 will be called for all TCP packets before Bro performs any further
## analysis. If the function signals to discard a packet, no further processing
## will be performed on it.
##
## i: The IP header of the considered packet.
## t: The TCP header.
## p: The IP and TCP headers of the considered packet.
##
## d: Up to :bro:see:`discarder_maxlen` bytes of the TCP payload.
##
## 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.
## 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 will be called for all UDP packets before Bro performs any further
## analysis. If the function signals to discard a packet, no further processing
## will be performed on it.
##
## i: The IP header of the considered packet.
## t: The UDP header.
## p: The IP and UDP headers of the considered packet.
##
## d: Up to :bro:see:`discarder_maxlen` bytes of the UDP payload.
##
## 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.
## 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 will be called for all ICMP packets before Bro performs any further
## analysis. If the function signals to discard a packet, no further processing
## will be performed on it.
##
## i: The IP header of the considered packet.
## ih: The ICMP header.
## p: The IP and ICMP headers of the considered packet.
##
## 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.
## 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.
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.
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.
##
## .. bro:see:: x509_certificate
@ -1725,10 +2036,6 @@ type X509: record {
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.
##
## .. bro:see:: http_stats
@ -2146,26 +2453,6 @@ const forward_remote_state_changes = F &redef;
## Place-holder constant indicating "no peer".
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.
# todo::use enum to help autodoc
# todo::Still used?

View file

@ -40,8 +40,6 @@ export {
rcode: count &log &optional;
## A descriptive name for the response code value.
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 responding name server is an authority for the domain name
## 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_AAAA_reply(c: connection, msg: dns_msg, ans: dns_answer, a: addr,
astr: string) &priority=5
event dns_AAAA_reply(c: connection, msg: dns_msg, ans: dns_answer, a: addr) &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));
}

View file

@ -24,7 +24,7 @@ export {
const default_capture_password = F &redef;
## 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 {
## Time when the command was sent.
@ -160,12 +160,21 @@ function ftp_message(s: Info)
# or it's a deliberately logged command.
if ( |s$tags| > 0 || (s?$cmdarg && s$cmdarg$cmd in logged_commands) )
{
if ( s?$password && to_lower(s$user) !in guest_ids )
if ( s?$password &&
! s$capture_password &&
to_lower(s$user) !in guest_ids )
{
s$password = "<hidden>";
}
local arg = s$cmdarg$arg;
if ( s$cmdarg$cmd in file_cmds )
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$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;
if ( code == 229 && data$h == 0.0.0.0 )
if ( code == 229 && data$h == [::] )
data$h = id$resp_h;
ftp_data_expected[data$h, data$p] = c$ftp;

View file

@ -13,7 +13,7 @@ export {
[TLSv10] = "TLSv10",
[TLSv11] = "TLSv11",
[TLSv12] = "TLSv12",
} &default="UNKNOWN";
} &default=function(i: count):string { return fmt("unknown-%d", i); };
## Mapping between numeric codes and human readable strings for alert
## levels.
@ -77,7 +77,9 @@ export {
[12] = "srp",
[13] = "signature_algorithms",
[14] = "use_srtp",
[15] = "heartbeat",
[35] = "SessionTicket TLS",
[40] = "extended_random",
[13172] = "next_protocol_negotiation",
[65281] = "renegotiation_info"
} &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_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",
} &default="UNKNOWN";
} &default=function(i: count):string { return fmt("unknown-%d", i); };
## Mapping between the constants and string values for SSL/TLS errors.
const x509_errors: table[count] of string = {
@ -573,6 +575,6 @@ export {
[31] = "keyusage no certsign",
[32] = "unable to get crl issuer",
[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 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);
if ( c$id$resp_h in Software::tracked &&
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*) (pkt + hdr_size - 2);

View file

@ -31,9 +31,6 @@ public:
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,
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,
const char* spa, const char* sha,
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:
AddrVal* ConstructAddrVal(const void* 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,
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,
TCP_Analyzer::Available, 0, false },

View file

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

View file

@ -153,7 +153,9 @@ void AnonymizeIPAddr_A50::init()
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 )
{

View file

@ -5,7 +5,7 @@
#include "Attr.h"
#include "Expr.h"
#include "Serializer.h"
#include "LogMgr.h"
#include "threading/SerialTypes.h"
const char* attr_name(attr_tag t)
{
@ -416,7 +416,7 @@ void Attributes::CheckAttr(Attr* a)
break;
case ATTR_LOG:
if ( ! LogVal::IsCompatibleType(type) )
if ( ! threading::Value::IsCompatibleType(type) )
Error("&log applied to a type that cannot be logged");
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)
{
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);
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 )
{ // entry point is somewhere in the gap
DeliverWeird("Stopping BitTorrent analysis: cannot recover from content gap", orig);
this_stop = true;
if ( stop_orig && stop_resp )
ProtocolViolation("BitTorrent: content gap and/or protocol violation");
}
else
{ // fill the gap
try
{
u_char gap[len];
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");
}
}
//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;
//
//this_stream_len += len;
//
//if ( entry_offset < this_stream_len )
// { // entry point is somewhere in the gap
// DeliverWeird("Stopping BitTorrent analysis: cannot recover from content gap", orig);
// this_stop = true;
// if ( stop_orig && stop_resp )
// ProtocolViolation("BitTorrent: content gap and/or protocol violation");
// }
//else
// { // fill the gap
// try
// {
// u_char gap[len];
// 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)

View file

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

View file

@ -1,11 +1,12 @@
#include <cstdio>
#include <cstring>
#include <utility>
#include <algorithm>
#include "Brofiler.h"
#include "util.h"
Brofiler::Brofiler()
: delim('\t'), ignoring(0)
: ignoring(0), delim('\t')
{
}
@ -48,10 +49,27 @@ bool Brofiler::WriteStats()
char* bf = getenv("BRO_PROFILER_FILE");
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 )
{
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;
}

View file

@ -26,7 +26,9 @@ public:
/**
* Combines usage stats from current run with any read from ReadStats(),
* 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.
*/

View file

@ -213,6 +213,8 @@ binpac_target(syslog.pac
########################################################################
## bro target
find_package (Threads)
# 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".
macro(COLLECT_HEADERS _var)
@ -288,7 +290,6 @@ set(bro_SRCS
ChunkedIO.cc
CompHash.cc
Conn.cc
ConnCompressor.cc
ConnSizeAnalyzer.cc
ContentLine.cc
DCE_RPC.cc
@ -331,13 +332,11 @@ set(bro_SRCS
IntSet.cc
InterConn.cc
IOSource.cc
IP.cc
IPAddr.cc
IRC.cc
List.cc
Reporter.cc
LogMgr.cc
LogWriter.cc
LogWriterAscii.cc
LogWriterNone.cc
Login.cc
MIME.cc
NCP.cc
@ -402,6 +401,7 @@ set(bro_SRCS
XDR.cc
ZIP.cc
bsd-getopt-long.c
bro_inet_ntop.c
cq.c
md5.c
patricia.c
@ -409,6 +409,18 @@ set(bro_SRCS
PacketDumper.cc
strsep.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}
${openssl_SRCS}
)
@ -421,7 +433,7 @@ add_definitions(-DBRO_BUILD_PATH="${CMAKE_CURRENT_BINARY_DIR}")
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(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:
{
// Use uint32 instead of int, because 'int' is not
// guaranteed to be 32-bit.
uint32* kp = AlignAndPadType<uint32>(kp0);
#ifdef BROv6
const addr_type av = v->AsAddr();
kp[0] = av[0];
kp[1] = av[1];
kp[2] = av[2];
kp[3] = av[3];
v->AsAddr().CopyIPv6(kp);
kp1 = reinterpret_cast<char*>(kp+4);
#else
*kp = v->AsAddr();
kp1 = reinterpret_cast<char*>(kp+1);
#endif
}
break;
case TYPE_INTERNAL_SUBNET:
{
uint32* kp = AlignAndPadType<uint32>(kp0);
#ifdef BROv6
const subnet_type* sv = v->AsSubNet();
kp[0] = sv->net[0];
kp[1] = sv->net[1];
kp[2] = sv->net[2];
kp[3] = sv->net[3];
kp[4] = sv->width;
v->AsSubNet().Prefix().CopyIPv6(kp);
kp[4] = v->AsSubNet().Length();
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;
@ -358,26 +336,16 @@ HashKey* CompositeHash::ComputeSingletonHash(const Val* v, int type_check) const
if ( type_check && v->Type()->InternalType() != singleton_tag )
return 0;
uint32 tmp_addr;
switch ( singleton_tag ) {
case TYPE_INTERNAL_INT:
case TYPE_INTERNAL_UNSIGNED:
return new HashKey(v->ForceAsInt());
case TYPE_INTERNAL_ADDR:
#ifdef BROv6
return new HashKey(v->AsAddr(), 4);
#else
return new HashKey(v->AsAddr());
#endif
return v->AsAddr().GetHashKey();
case TYPE_INTERNAL_SUBNET:
#ifdef BROv6
return new HashKey((const uint32*) v->AsSubNet(), 5);
#else
return new HashKey((const uint32*) v->AsSubNet(), 2);
#endif
return v->AsSubNet().GetHashKey();
case TYPE_INTERNAL_DOUBLE:
return new HashKey(v->InternalDouble());
@ -425,22 +393,13 @@ int CompositeHash::SingleTypeKeySize(BroType* bt, const Val* v,
break;
case TYPE_INTERNAL_ADDR:
#ifdef BROv6
sz = SizeAlign(sz, sizeof(uint32));
sz += sizeof(uint32) * 3; // to make a total of 4 words
#else
sz = SizeAlign(sz, sizeof(uint32));
#endif
break;
case TYPE_INTERNAL_SUBNET:
#ifdef BROv6
sz = SizeAlign(sz, sizeof(uint32));
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;
case TYPE_INTERNAL_DOUBLE:
@ -748,16 +707,13 @@ const char* CompositeHash::RecoverOneVal(const HashKey* k, const char* kp0,
case TYPE_INTERNAL_ADDR:
{
const uint32* const kp = AlignType<uint32>(kp0);
#ifdef BROv6
const_addr_type addr_val = kp;
kp1 = reinterpret_cast<const char*>(kp+4);
#else
const_addr_type addr_val = *kp;
kp1 = reinterpret_cast<const char*>(kp+1);
#endif
IPAddr addr(IPv6, kp, IPAddr::Network);
switch ( tag ) {
case TYPE_ADDR:
pval = new AddrVal(addr_val);
pval = new AddrVal(addr);
break;
default:
@ -770,12 +726,9 @@ const char* CompositeHash::RecoverOneVal(const HashKey* k, const char* kp0,
case TYPE_INTERNAL_SUBNET:
{
const subnet_type* const kp =
reinterpret_cast<const subnet_type*>(
AlignType<uint32>(kp0));
kp1 = reinterpret_cast<const char*>(kp+1);
pval = new SubNetVal(kp->net, kp->width);
const uint32* const kp = AlignType<uint32>(kp0);
kp1 = reinterpret_cast<const char*>(kp+5);
pval = new SubNetVal(kp, kp[4]);
}
break;

View file

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

View file

@ -12,6 +12,7 @@
#include "PersistenceSerializer.h"
#include "RuleMatcher.h"
#include "AnalyzerTags.h"
#include "IPAddr.h"
class Connection;
class ConnectionTimer;
@ -32,52 +33,17 @@ typedef enum {
typedef void (Connection::*timer_func)(double t);
struct ConnID {
const uint32* src_addr;
const uint32* dst_addr;
IPAddr src_addr;
IPAddr dst_addr;
uint32 src_port;
uint32 dst_port;
bool is_one_way; // if true, don't canonicalize
// 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;
};
bool is_one_way; // if true, don't canonicalize order
};
static inline int addr_port_canon_lt(const uint32* a1, uint32 p1,
const uint32* a2, uint32 p2)
static inline int addr_port_canon_lt(const IPAddr& addr1, uint32 p1,
const IPAddr& addr2, uint32 p2)
{
#ifdef BROv6
// 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
return addr1 < addr2 || (addr1 == addr2 && p1 < p2);
}
class Analyzer;
@ -119,8 +85,8 @@ public:
double LastTime() const { return last_time; }
void SetLastTime(double t) { last_time = t; }
const uint32* OrigAddr() const { return orig_addr; }
const uint32* RespAddr() const { return resp_addr; }
const IPAddr& OrigAddr() const { return orig_addr; }
const IPAddr& RespAddr() const { return resp_addr; }
uint32 OrigPort() const { return orig_port; }
uint32 RespPort() const { return resp_port; }
@ -185,11 +151,11 @@ public:
// Raises a software_version_found event based on the
// 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);
// 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);
void Event(EventHandlerPtr f, Analyzer* analyzer, const char* name = 0);
@ -273,30 +239,6 @@ public:
// Sets the transport protocol in use.
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; }
protected:
@ -325,8 +267,8 @@ protected:
TimerMgr::Tag* conn_timer_mgr;
timer_list timers;
uint32 orig_addr[NUM_ADDR_WORDS]; // in network order
uint32 resp_addr[NUM_ADDR_WORDS]; // in network order
IPAddr orig_addr;
IPAddr resp_addr;
uint32 orig_port, resp_port; // in network order
TransportProto proto;
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)
{
#ifdef BROv6
if ( ! is_v4_addr(id->dst_addr) )
if ( id->dst_addr.GetFamily() == IPv6 )
// TODO: Does the protocol support v6 addresses? #773
return false;
#endif
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.proto = proto;
@ -160,12 +160,7 @@ static void add_dce_rpc_endpoint(const dce_rpc_endpoint_addr& addr,
// of the dce_rpc_endpoints table.
// FIXME: Don't hard-code the timeout.
// Convert the address to a v4/v6 address (depending on how
// 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,
dpm->ExpectConnection(IPAddr(), addr.addr, addr.port, addr.proto,
AnalyzerTag::DCE_RPC, 5 * 60, 0);
}
@ -418,8 +413,8 @@ void DCE_RPC_Session::DeliverEpmapperMapResponse(
break;
case binpac::DCE_RPC_Simple::EPM_PROTOCOL_IP:
mapped.addr.addr =
floor->rhs()->data()->ip();
uint32 hostip = floor->rhs()->data()->ip();
mapped.addr.addr = IPAddr(IPv4, &hostip, IPAddr::Host);
break;
}
}
@ -433,7 +428,7 @@ void DCE_RPC_Session::DeliverEpmapperMapResponse(
vl->append(analyzer->BuildConnVal());
vl->append(new StringVal(mapped.uuid.to_string()));
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);
}

View file

@ -8,6 +8,7 @@
#include "NetVar.h"
#include "TCP.h"
#include "IPAddr.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 {
// All fields are in host byteorder.
uint32 addr;
IPAddr addr;
u_short port;
TransportProto proto;
dce_rpc_endpoint_addr()
{
addr = 0;
addr = IPAddr();
port = 0;
proto = TRANSPORT_UNKNOWN;
}
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
{
@ -64,7 +65,7 @@ struct dce_rpc_endpoint_addr {
{
static char buf[128];
snprintf(buf, sizeof(buf), "%s/%d/%s",
dotted_addr(htonl(addr)), port,
addr.AsString().c_str(), port,
proto == TRANSPORT_TCP ? "tcp" :
(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,
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];
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 )
{
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;
}
}
// Currently, dns_AAAA_reply is treated like dns_A_reply, since
// IPv6 addresses are not generally processed. This needs to be
// fixed. ###
if ( dns_A_reply && ! msg->skip_event )
EventHandlerPtr event;
if ( msg->atype == TYPE_AAAA )
event = dns_AAAA_reply;
else
event = dns_A6_reply;
if ( event && ! msg->skip_event )
{
val_list* vl = new val_list;
vl->append(analyzer->BuildConnVal());
vl->append(msg->BuildHdrVal());
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));
#else
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);
analyzer->ConnectionEvent(event, vl);
}
#endif
return 1;
}

View file

@ -46,13 +46,13 @@ extern int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
class DNS_Mgr_Request {
public:
DNS_Mgr_Request(const char* h) { host = copy_string(h); addr = 0; }
DNS_Mgr_Request(uint32 a) { addr = a; host = 0; }
DNS_Mgr_Request(const char* h, int af) { host = copy_string(h); fam = af; }
DNS_Mgr_Request(const IPAddr& a) { addr = a; host = 0; fam = 0; }
~DNS_Mgr_Request() { delete [] host; }
// Returns nil if this was an address request.
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 RequestPending() const { return request_pending; }
@ -61,8 +61,8 @@ public:
protected:
char* host; // if non-nil, this is a host request
uint32 addr;
uint32 ttl;
int fam; // address family query type for host requests
IPAddr addr;
int request_pending;
};
@ -75,15 +75,20 @@ int DNS_Mgr_Request::MakeRequest(nb_dns_info* nb_dns)
char err[NB_DNS_ERRSIZE];
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
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 {
public:
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);
int NoMapping() const { return no_mapping; }
@ -93,9 +98,11 @@ public:
// Returns nil if this was an address request.
const char* ReqHost() const { return req_host; }
uint32 ReqAddr() const { return req_addr; }
const char* ReqStr() const
{ return req_host ? req_host : dotted_addr(ReqAddr()); }
IPAddr ReqAddr() const { return req_addr; }
string ReqStr() const
{
return req_host ? req_host : req_addr;
}
ListVal* Addrs();
TableVal* AddrsSet(); // addresses returned as a set
@ -109,7 +116,14 @@ public:
int Valid() const { return ! failed; }
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:
friend class DNS_Mgr;
@ -121,7 +135,7 @@ protected:
int init_failed;
char* req_host;
uint32 req_addr;
IPAddr req_addr;
uint32 req_ttl;
int num_names;
@ -129,11 +143,12 @@ protected:
StringVal* host_val;
int num_addrs;
uint32* addrs;
IPAddr* addrs;
ListVal* addrs_val;
int failed;
double creation_time;
int map_type;
};
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);
req_host = copy_string(host);
req_addr = 0;
req_ttl = ttl;
if ( names && ! names[0] )
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);
req_addr = addr;
@ -175,7 +189,6 @@ DNS_Mapping::DNS_Mapping(FILE* f)
init_failed = 1;
req_host = 0;
req_addr = 0;
char buf[512];
@ -188,14 +201,15 @@ DNS_Mapping::DNS_Mapping(FILE* f)
char req_buf[512+1], name_buf[512+1];
int is_req_host;
if ( sscanf(buf, "%lf %d %512s %d %512s %d", &creation_time, &is_req_host,
req_buf, &failed, name_buf, &num_addrs) != 6 )
if ( sscanf(buf, "%lf %d %512s %d %512s %d %d %"PRIu32, &creation_time,
&is_req_host, req_buf, &failed, name_buf, &map_type, &num_addrs,
&req_ttl) != 8 )
return;
if ( is_req_host )
req_host = copy_string(req_buf);
else
req_addr = dotted_to_addr(req_buf);
req_addr = IPAddr(req_buf);
num_names = 1;
names = new char*[num_names];
@ -203,7 +217,7 @@ DNS_Mapping::DNS_Mapping(FILE* f)
if ( num_addrs > 0 )
{
addrs = new uint32[num_addrs];
addrs = new IPAddr[num_addrs];
for ( int i = 0; i < num_addrs; ++i )
{
@ -217,7 +231,7 @@ DNS_Mapping::DNS_Mapping(FILE* f)
if ( newline )
*newline = '\0';
addrs[i] = dotted_to_addr(buf);
addrs[i] = IPAddr(buf);
}
}
else
@ -280,14 +294,6 @@ StringVal* DNS_Mapping::Host()
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)
{
no_mapping = 0;
@ -296,12 +302,13 @@ void DNS_Mapping::Init(struct hostent* h)
host_val = 0;
addrs_val = 0;
if ( ! h || h->h_addrtype != AF_INET || h->h_length != 4 )
if ( ! h )
{
Clear();
return;
}
map_type = h->h_addrtype;
num_names = 1; // for now, just use official name
names = new char*[num_names];
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 )
{
addrs = new uint32[num_addrs];
addrs = new IPAddr[num_addrs];
for ( int i = 0; i < num_addrs; ++i )
addrs[i] = raw_bytes_to_addr(
(unsigned char*)h->h_addr_list[i]);
if ( h->h_addrtype == AF_INET )
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
addrs = 0;
@ -330,18 +341,19 @@ void DNS_Mapping::Clear()
host_val = 0;
addrs_val = 0;
no_mapping = 0;
map_type = 0;
failed = 1;
}
void DNS_Mapping::Save(FILE* f) const
{
fprintf(f, "%.0f %d %s %d %s %d\n", creation_time, req_host != 0,
req_host ? req_host : dotted_addr(req_addr),
fprintf(f, "%.0f %d %s %d %s %d %d %"PRIu32"\n", creation_time, req_host != 0,
req_host ? req_host : req_addr.AsString().c_str(),
failed, (names && names[0]) ? names[0] : "*",
num_addrs);
map_type, num_addrs, req_ttl);
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;
host_mappings.SetDeleteFunc(DNS_Mgr_mapping_delete_func);
addr_mappings.SetDeleteFunc(DNS_Mgr_mapping_delete_func);
char err[NB_DNS_ERRSIZE];
nb_dns = nb_dns_init(err);
@ -440,24 +449,34 @@ TableVal* DNS_Mgr::LookupHost(const char* name)
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() )
return d->Addrs()->ConvertToSet();
else
DNS_Mapping* d4 = it->second.first;
DNS_Mapping* d6 = it->second.second;
if ( (d4 && d4->Failed()) || (d6 && d6->Failed()) )
{
reporter->Warning("no such host: %s", name);
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.
switch ( mode ) {
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();
case DNS_FORCE:
@ -465,7 +484,8 @@ TableVal* DNS_Mgr::LookupHost(const char* name)
return 0;
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();
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 )
Init();
if ( mode != DNS_PRIME )
{
HashKey h(&addr, 1);
DNS_Mapping* d = addr_mappings.Lookup(&h);
AddrMap::iterator it = addr_mappings.find(addr);
if ( d )
if ( it != addr_mappings.end() )
{
DNS_Mapping* d = it->second;
if ( d->Valid() )
return d->Host();
else
{
reporter->Warning("can't resolve IP address: %s", dotted_addr(addr));
return new StringVal(dotted_addr(addr));
string s(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:
reporter->FatalError("can't find DNS entry for %s in cache",
dotted_addr(addr));
addr.AsString().c_str());
return 0;
case DNS_DEFAULT:
@ -681,28 +702,53 @@ void DNS_Mgr::AddResult(DNS_Mgr_Request* dr, struct nb_dns_result* r)
if ( dr->ReqHost() )
{
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() )
{
// Put previous, valid entry back - CompareMappings
// 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;
}
}
else
{
new_dm = new DNS_Mapping(dr->ReqAddr(), h, ttl);
uint32 tmp_addr = dr->ReqAddr();
HashKey k(&tmp_addr, 1);
prev_dm = addr_mappings.Insert(&k, new_dm);
AddrMap::iterator it = addr_mappings.find(dr->ReqAddr());
prev_dm = (it == addr_mappings.end()) ? 0 : it->second;
addr_mappings[dr->ReqAddr()] = new_dm;
if ( new_dm->Failed() && prev_dm && prev_dm->Valid() )
{
uint32 tmp_addr = dr->ReqAddr();
HashKey k2(&tmp_addr, 1);
(void) addr_mappings.Insert(&k2, prev_dm);
addr_mappings[dr->ReqAddr()] = prev_dm;
++keep_prev;
}
}
@ -774,17 +820,13 @@ ListVal* DNS_Mgr::AddrListDelta(ListVal* al1, ListVal* al2)
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;
for ( j = 0; j < al2->Length(); ++j )
{
addr_type al2_j = al2->Index(j)->AsAddr();
#ifdef BROv6
if ( addr_eq(al1_i, al2_j) )
#else
const IPAddr& al2_j = al2->Index(j)->AsAddr();
if ( al1_i == al2_j )
#endif
break;
}
@ -800,8 +842,8 @@ void DNS_Mgr::DumpAddrList(FILE* f, ListVal* al)
{
for ( int i = 0; i < al->Length(); ++i )
{
addr_type al_i = al->Index(i)->AsAddr();
fprintf(f, "%s%s", i > 0 ? "," : "", dotted_addr(al_i));
const IPAddr& al_i = al->Index(i)->AsAddr();
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) )
{
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
{
uint32 tmp_addr = m->ReqAddr();
HashKey h(&tmp_addr, 1);
addr_mappings.Insert(&h, m);
addr_mappings[m->ReqAddr()] = m;
}
}
@ -830,26 +880,41 @@ void DNS_Mgr::LoadCache(FILE* 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();
DNS_Mapping* dm;
while ( (dm = m.NextEntry(cookie)) )
dm->Save(f);
for ( AddrMap::const_iterator it = m.begin(); it != m.end(); ++it )
{
if ( it->second )
it->second->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);
DNS_Mapping* d = dns_mgr->addr_mappings.Lookup(&h);
HostMap::const_iterator it;
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;
DNS_Mapping* d = it->second;
if ( d->Expired() )
{
dns_mgr->addr_mappings.Remove(&h);
dns_mgr->addr_mappings.erase(it);
delete d;
return 0;
}
@ -861,23 +926,32 @@ const char* DNS_Mgr::LookupAddrInCache(dns_mgr_addr_type addr)
TableVal* DNS_Mgr::LookupNameInCache(string name)
{
DNS_Mapping* d = dns_mgr->host_mappings.Lookup(name.c_str());
if ( ! d || ! d->names )
HostMap::iterator it = dns_mgr->host_mappings.find(name);
if ( it == dns_mgr->host_mappings.end() )
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.Remove(&h);
delete d;
dns_mgr->host_mappings.erase(it);
delete d4;
delete d6;
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 )
Init();
@ -956,10 +1030,15 @@ void DNS_Mgr::IssueAsyncRequests()
++num_requests;
DNS_Mgr_Request* dr;
DNS_Mgr_Request* dr6 = 0;
if ( req->IsAddrReq() )
dr = new DNS_Mgr_Request(req->host);
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) )
{
@ -969,6 +1048,14 @@ void DNS_Mgr::IssueAsyncRequests()
continue;
}
if ( dr6 && ! dr6->MakeRequest(nb_dns) )
{
reporter->Warning("can't issue DNS request");
++failed;
req->Timeout();
continue;
}
req->time = current_time();
asyncs_timeouts.push(req);
@ -987,7 +1074,7 @@ double DNS_Mgr::NextTimestamp(double* network_time)
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.
@ -1060,11 +1147,18 @@ void DNS_Mgr::Flush()
{
DoProcess(false);
IterCookie* cookie = addr_mappings.InitForIteration();
DNS_Mapping* dm;
HostMap::iterator it;
for ( it = host_mappings.begin(); it != host_mappings.end(); ++it )
{
delete it->second.first;
delete it->second.second;
}
host_mappings.Clear();
addr_mappings.Clear();
for ( AddrMap::iterator it2 = addr_mappings.begin(); it2 != addr_mappings.end(); ++it2 )
delete it2->second;
host_mappings.clear();
addr_mappings.clear();
}
void DNS_Mgr::Process()
@ -1107,6 +1201,14 @@ void DNS_Mgr::DoProcess(bool flush)
else if ( status > 0 )
{
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() )
{
AddResult(dr, &r);
@ -1116,7 +1218,7 @@ void DNS_Mgr::DoProcess(bool flush)
if ( ! dr->ReqHost() )
CheckAsyncAddrRequest(dr->ReqAddr(), true);
else
CheckAsyncHostRequest(dr->ReqHost(), true);
CheckAsyncHostRequest(dr->ReqHost(), do_host_timeout);
IssueAsyncRequests();
@ -1167,7 +1269,7 @@ void DNS_Mgr::GetStats(Stats* stats)
stats->successful = successful;
stats->failed = failed;
stats->pending = asyncs_pending;
stats->cached_hosts = host_mappings.Length();
stats->cached_addresses = addr_mappings.Length();
stats->cached_hosts = host_mappings.size();
stats->cached_addresses = addr_mappings.size();
}

View file

@ -6,12 +6,14 @@
#include <list>
#include <map>
#include <queue>
#include <utility>
#include "util.h"
#include "BroList.h"
#include "Dict.h"
#include "EventHandler.h"
#include "IOSource.h"
#include "IPAddr.h"
class Val;
class ListVal;
@ -27,7 +29,6 @@ struct nb_dns_result;
declare(PDict,ListVal);
class DNS_Mapping;
declare(PDict,DNS_Mapping);
enum DNS_MgrMode {
DNS_PRIME, // used to prime the cache
@ -39,10 +40,6 @@ enum DNS_MgrMode {
// Number of seconds we'll wait for a reply.
#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 {
public:
DNS_Mgr(DNS_MgrMode mode);
@ -55,7 +52,7 @@ public:
// a set of addr.
TableVal* LookupHost(const char* host);
Val* LookupAddr(uint32 addr);
Val* LookupAddr(const IPAddr& addr);
// Define the directory where to store the data.
void SetDir(const char* arg_dir) { dir = copy_string(arg_dir); }
@ -64,7 +61,7 @@ public:
void Resolve();
int Save();
const char* LookupAddrInCache(dns_mgr_addr_type addr);
const char* LookupAddrInCache(const IPAddr& addr);
TableVal* LookupNameInCache(string name);
// Support for async lookups.
@ -78,7 +75,7 @@ public:
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);
struct Stats {
@ -107,8 +104,11 @@ protected:
ListVal* AddrListDelta(ListVal* al1, ListVal* al2);
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 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
// 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
// requested.
void CheckAsyncAddrRequest(dns_mgr_addr_type addr, bool timeout);
void CheckAsyncAddrRequest(const IPAddr& addr, bool timeout);
void CheckAsyncHostRequest(const char* host, bool timeout);
// Process outstanding requests.
@ -136,8 +136,8 @@ protected:
PDict(ListVal) services;
PDict(DNS_Mapping) host_mappings;
PDict(DNS_Mapping) addr_mappings;
HostMap host_mappings;
AddrMap addr_mappings;
DNS_mgr_request_list requests;
@ -163,7 +163,7 @@ protected:
struct AsyncRequest {
double time;
dns_mgr_addr_type host;
IPAddr host;
string name;
CallbackList callbacks;
@ -204,7 +204,7 @@ protected:
};
typedef map<dns_mgr_addr_type, AsyncRequest*> AsyncRequestAddrMap;
typedef map<IPAddr, AsyncRequest*> AsyncRequestAddrMap;
AsyncRequestAddrMap asyncs_addrs;
typedef map<string, AsyncRequest*> AsyncRequestNameMap;

View file

@ -11,53 +11,28 @@
#include "ConnSizeAnalyzer.h"
ExpectedConn::ExpectedConn(const uint32* _orig, const uint32* _resp,
ExpectedConn::ExpectedConn(const IPAddr& _orig, const IPAddr& _resp,
uint16 _resp_p, uint16 _proto)
{
if ( orig )
copy_addr(_orig, orig);
if ( _orig == IPAddr(string("0.0.0.0")) )
// don't use the IPv4 mapping, use the literal unspecified address
// to indicate a wildcard
orig = IPAddr(string("::"));
else
{
for ( int i = 0; i < NUM_ADDR_WORDS; ++i )
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
orig = _orig;
resp = _resp;
resp_p = _resp_p;
proto = _proto;
}
ExpectedConn::ExpectedConn(const ExpectedConn& c)
{
copy_addr(c.orig, orig);
copy_addr(c.resp, resp);
orig = c.orig;
resp = c.resp;
resp_p = c.resp_p;
proto = c.proto;
}
DPM::DPM()
: expected_conns_queue(AssignedAnalyzer::compare)
{
@ -99,7 +74,7 @@ void DPM::PostScriptInit()
void DPM::AddConfig(const Analyzer::Config& cfg)
{
#ifdef USE_PERFTOOLS
#ifdef USE_PERFTOOLS_DEBUG
HeapLeakChecker::Disabler disabler;
#endif
@ -158,23 +133,18 @@ AnalyzerTag::Tag DPM::GetExpected(int proto, const Connection* conn)
ExpectedConn c(conn->OrigAddr(), conn->RespAddr(),
ntohs(conn->RespPort()), proto);
// Can't use sizeof(c) due to potential alignment issues.
// FIXME: I guess this is still not portable ...
HashKey key(&c, sizeof(c.orig) + sizeof(c.resp) +
sizeof(c.resp_p) + sizeof(c.proto));
AssignedAnalyzer* a = expected_conns.Lookup(&key);
HashKey* key = BuildExpectedConnHashKey(c);
AssignedAnalyzer* a = expected_conns.Lookup(key);
delete key;
if ( ! a )
{
// Wildcard for originator.
for ( int i = 0; i < NUM_ADDR_WORDS; ++i )
c.orig[i] = 0;
c.orig = IPAddr(string("::"));
HashKey key(&c, sizeof(c.orig) + sizeof(c.resp) +
sizeof(c.resp_p) + sizeof(c.proto));
a = expected_conns.Lookup(&key);
HashKey* key = BuildExpectedConnHashKey(c);
a = expected_conns.Lookup(key);
delete key;
}
if ( ! a )
@ -215,46 +185,8 @@ bool DPM::BuildInitialAnalyzerTree(TransportProto proto, Connection* conn,
break;
case TRANSPORT_ICMP: {
const struct icmp* icmpp = (const struct icmp *) data;
switch ( icmpp->icmp_type ) {
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);
root = icmp = new ICMP_Analyzer(conn);
DBG_DPD(conn, "activated ICMP analyzer");
analyzed = true;
break;
}
@ -404,7 +336,8 @@ bool DPM::BuildInitialAnalyzerTree(TransportProto proto, Connection* conn,
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,
double timeout, void* cookie)
{
@ -416,11 +349,7 @@ void DPM::ExpectConnection(addr_type orig, addr_type resp, uint16 resp_p,
{
if ( ! a->deleted )
{
HashKey* key = new HashKey(&a->conn,
sizeof(a->conn.orig) +
sizeof(a->conn.resp) +
sizeof(a->conn.resp_p) +
sizeof(a->conn.proto));
HashKey* key = BuildExpectedConnHashKey(a->conn);
expected_conns.Remove(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);
HashKey key(&c, sizeof(c.orig) + sizeof(c.resp) +
sizeof(c.resp_p) + sizeof(c.proto));
HashKey* key = BuildExpectedConnHashKey(c);
AssignedAnalyzer* a = expected_conns.Lookup(&key);
AssignedAnalyzer* a = expected_conns.Lookup(key);
if ( a )
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->deleted = false;
expected_conns.Insert(&key, a);
expected_conns.Insert(key, a);
expected_conns_queue.push(a);
delete key;
}
void DPM::Done()
@ -466,11 +395,7 @@ void DPM::Done()
AssignedAnalyzer* a = expected_conns_queue.top();
if ( ! a->deleted )
{
HashKey* key = new HashKey(&a->conn,
sizeof(a->conn.orig) +
sizeof(a->conn.resp) +
sizeof(a->conn.resp_p) +
sizeof(a->conn.proto));
HashKey* key = BuildExpectedConnHashKey(a->conn);
expected_conns.Remove(key);
delete key;
}

View file

@ -27,19 +27,13 @@
// Map to assign expected connections to analyzers.
class ExpectedConn {
public:
// This form can be used for IPv6 as well as IPv4.
ExpectedConn(const uint32* _orig, const uint32* _resp,
ExpectedConn(const IPAddr& _orig, const IPAddr& _resp,
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);
uint32 orig[NUM_ADDR_WORDS];
uint32 resp[NUM_ADDR_WORDS];
IPAddr orig;
IPAddr resp;
uint16 resp_p;
uint16 proto;
};
@ -90,7 +84,7 @@ public:
// Schedules a particular analyzer for an upcoming connection.
// 0 acts as a wildcard for orig. (Cookie is currently unused.
// Eventually, we may pass it on to the analyzer).
void ExpectConnection(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,
double timeout, void* cookie);

View file

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

View file

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

View file

@ -24,6 +24,7 @@ enum DebugStream {
DBG_DPD, // Dynamic application detection framework
DBG_TM, // Time-machine packet input via Brocolli
DBG_LOGGING, // Logging streams
DBG_THREADING, // Threading system
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)
{
int n = strlen(s);

View file

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

View file

@ -10,11 +10,6 @@
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_tcp = internal_func("discarder_check_tcp");
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;
const struct ip* ip4 = ip->IP4_Hdr();
if ( check_ip )
{
val_list* args = new val_list;
args->append(BuildHeader(ip4));
args->append(ip->BuildPktHdrVal());
try
{
@ -59,19 +52,18 @@ int Discarder::NextPacket(const IP_Hdr* ip, int len, int caplen)
return discard_packet;
}
int proto = ip4->ip_p;
int proto = ip->NextProto();
if ( proto != IPPROTO_TCP && proto != IPPROTO_UDP &&
proto != IPPROTO_ICMP )
// This is not a protocol we understand.
return 0;
// XXX shall we only check the first packet???
uint32 frag_field = ntohs(ip4->ip_off);
if ( (frag_field & 0x3fff) != 0 )
if ( ip->IsFragment() )
// Never check any fragment.
return 0;
int ip_hdr_len = ip4->ip_hl * 4;
int ip_hdr_len = ip->HdrLen();
len -= ip_hdr_len; // remove IP header
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,
// 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 )
{
@ -97,8 +89,7 @@ int Discarder::NextPacket(const IP_Hdr* ip, int len, int caplen)
int th_len = tp->th_off * 4;
val_list* args = new val_list;
args->append(BuildHeader(ip4));
args->append(BuildHeader(tp, len));
args->append(ip->BuildPktHdrVal());
args->append(BuildData(data, th_len, len, caplen));
try
@ -123,8 +114,7 @@ int Discarder::NextPacket(const IP_Hdr* ip, int len, int caplen)
int uh_len = sizeof (struct udphdr);
val_list* args = new val_list;
args->append(BuildHeader(ip4));
args->append(BuildHeader(up));
args->append(ip->BuildPktHdrVal());
args->append(BuildData(data, uh_len, len, caplen));
try
@ -148,8 +138,7 @@ int Discarder::NextPacket(const IP_Hdr* ip, int len, int caplen)
const struct icmp* ih = (const struct icmp*) data;
val_list* args = new val_list;
args->append(BuildHeader(ip4));
args->append(BuildHeader(ih));
args->append(ip->BuildPktHdrVal());
try
{
@ -168,62 +157,6 @@ int Discarder::NextPacket(const IP_Hdr* ip, int len, int caplen)
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)
{
len -= hdrlen;

View file

@ -25,17 +25,8 @@ public:
int NextPacket(const IP_Hdr* ip, int len, int caplen);
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);
RecordType* ip_hdr;
RecordType* tcp_hdr;
RecordType* udp_hdr;
RecordType* icmp_hdr;
Func* check_ip;
Func* check_tcp;
Func* check_udp;

View file

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

View file

@ -14,6 +14,7 @@
#include "Net.h"
#include "Traverse.h"
#include "Trigger.h"
#include "IPAddr.h"
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
{
addr_type a1 = v1->AsAddr();
addr_type a2 = v2->AsAddr();
IPAddr a1 = v1->AsAddr();
IPAddr a2 = v2->AsAddr();
int result = 0;
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_LE: DO_FOLD(<=)
case EXPR_EQ: DO_FOLD(==)
case EXPR_NE: DO_FOLD(!=)
case EXPR_GE: DO_FOLD(>=)
case EXPR_GT: DO_FOLD(>)
case EXPR_LT:
result = a1 < a2;
break;
case EXPR_LE:
result = a1 < a2 || a1 == a2;
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:
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
{
subnet_type* n1 = v1->AsSubNet();
subnet_type* n2 = v2->AsSubNet();
const IPPrefix& n1 = v1->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);
#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()
@ -1681,15 +1675,13 @@ DivideExpr::DivideExpr(Expr* arg_op1, Expr* arg_op2)
Val* DivideExpr::AddrFold(Val* v1, Val* v2) const
{
addr_type a1 = v1->AsAddr();
uint32 mask;
if ( v2->Type()->Tag() == TYPE_COUNT )
mask = static_cast<uint32>(v2->InternalUnsigned());
else
mask = static_cast<uint32>(v2->InternalInt());
return new SubNetVal(a1, mask);
return new SubNetVal(v1->AsAddr(), mask);
}
Expr* DivideExpr::DoSimplify()
@ -2672,8 +2664,6 @@ void AssignExpr::EvalIntoAggregate(const BroType* t, Val* aggr, Frame* f) const
Error("bad table insertion");
TableVal* tv = aggr->AsTableVal();
const TableType* tt = tv->Type()->AsTableType();
const BroType* yt = tv->Type()->YieldType();
Val* index = op1->Eval(f);
Val* v = op2->Eval(f);
@ -3643,151 +3633,6 @@ bool FieldAssignExpr::DoUnserialize(UnserialInfo* info)
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)
: UnaryExpr(EXPR_ARITH_COERCE, arg_op)
{
@ -4918,6 +4763,7 @@ Val* ListExpr::Eval(Frame* f) const
if ( ! ev )
{
Error("uninitialized list value");
Unref(v);
return 0;
}

View file

@ -823,32 +823,6 @@ protected:
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 {
public:
ArithCoerceExpr(Expr* op, TypeTag t);

View file

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

View file

@ -27,21 +27,30 @@ void FragTimer::Dispatch(double t, int /* is_expire */)
FragReassembler::FragReassembler(NetSessions* arg_s,
const IP_Hdr* ip, const u_char* pkt,
uint32 frag_field, HashKey* k, double t)
: Reassembler(0, ip->DstAddr(), REASSEM_IP)
HashKey* k, double t)
: Reassembler(0, REASSEM_IP)
{
s = arg_s;
key = k;
const struct ip* ip4 = ip->IP4_Hdr();
proto_hdr_len = ip4->ip_hl * 4;
proto_hdr = (struct ip*) 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);
if ( ip4 )
{
proto_hdr_len = ip->HdrLen();
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;
frag_size = 0; // flag meaning "not known"
AddFragment(t, ip, pkt, frag_field);
next_proto = ip->NextProto();
if ( frag_timeout != 0.0 )
{
@ -50,6 +59,8 @@ FragReassembler::FragReassembler(NetSessions* arg_s,
}
else
expire_timer = 0;
AddFragment(t, ip, pkt);
}
FragReassembler::~FragReassembler()
@ -60,28 +71,42 @@ FragReassembler::~FragReassembler()
delete key;
}
void FragReassembler::AddFragment(double t, const IP_Hdr* ip, const u_char* pkt,
uint32 frag_field)
void FragReassembler::AddFragment(double t, const IP_Hdr* ip, const u_char* pkt)
{
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
// don't check TOS, there's at least one stack that actually
// uses different values, and it's hard to see an associated
// attack.
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.
s->Weird("fragment_with_DF", ip);
int offset = (ntohs(ip4->ip_off) & 0x1fff) * 8;
int len = ntohs(ip4->ip_len);
int hdr_len = proto_hdr->ip_hl * 4;
int offset = ip->FragOffset();
int len = ip->TotalLen();
int hdr_len = ip->HdrLen();
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.
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)
{
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) )
s->Weird("fragment_inconsistency", &proto_h);
@ -157,7 +182,7 @@ void FragReassembler::BlockInserted(DataBlock* /* start_block */)
// can happen for benign reasons when we're
// 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);
// 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 )
{
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);
frag_size = last_block->upper;
}
@ -193,8 +218,7 @@ void FragReassembler::BlockInserted(DataBlock* /* start_block */)
u_char* pkt = new u_char[n];
memcpy((void*) pkt, (const void*) proto_hdr, proto_hdr_len);
struct ip* reassem4 = (struct ip*) pkt;
reassem4->ip_len = htons(frag_size + proto_hdr_len);
u_char* pkt_start = pkt;
pkt += proto_hdr_len;
@ -214,7 +238,27 @@ void FragReassembler::BlockInserted(DataBlock* /* start_block */)
}
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();
}

View file

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

View file

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

View file

@ -35,6 +35,7 @@ public:
class Gnutella_Analyzer : public TCP_ApplicationAnalyzer {
public:
Gnutella_Analyzer(Connection* conn);
~Gnutella_Analyzer();
virtual void Done ();
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)
{
int len = ver.length;

View file

@ -8,6 +8,7 @@
#include "MIME.h"
#include "binpac_bro.h"
#include "ZIP.h"
#include "IPAddr.h"
enum CHUNKED_TRANSFER_STATE {
NON_CHUNKED_TRANSFER,
@ -212,7 +213,7 @@ protected:
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 ExpectReplyMessageBody();

View file

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

View file

@ -9,6 +9,8 @@
#include "Event.h"
#include "ICMP.h"
#include <netinet/icmp6.h>
ICMP_Analyzer::ICMP_Analyzer(Connection* c)
: TransportLayerAnalyzer(AnalyzerTag::ICMP, c)
{
@ -32,7 +34,7 @@ void ICMP_Analyzer::Done()
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)
{
assert(ip);
@ -46,13 +48,33 @@ void ICMP_Analyzer::DeliverPacket(int arg_len, const u_char* data,
PacketContents(data + 8, min(len, caplen) - 8);
const struct icmp* icmpp = (const struct icmp*) data;
len = arg_len;
if ( ! ignore_checksums && caplen >= len &&
icmp_checksum(icmpp, len) != 0xffff )
assert(caplen >= len); // Should have been caught earlier already.
if ( ! ignore_checksums )
{
Weird("bad_ICMP_checksum");
return;
int chksum = 0;
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);
@ -77,7 +99,13 @@ void ICMP_Analyzer::DeliverPacket(int arg_len, const u_char* data,
else
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 )
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);
}
void ICMP_Analyzer::NextICMP(double /* t */, const struct icmp* /* icmpp */,
int /* len */, int /* caplen */,
const u_char*& /* data */)
void ICMP_Analyzer::NextICMP4(double t, const struct icmp* icmpp, int len, int caplen,
const u_char*& data, const IP_Hdr* ip_hdr )
{
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 )
return;
val_list* vl = new val_list;
vl->append(BuildConnVal());
vl->append(BuildICMPVal());
vl->append(BuildICMPVal(icmpp, len, icmpv6, ip_hdr));
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 )
{
@ -114,9 +207,11 @@ RecordVal* ICMP_Analyzer::BuildICMPVal()
icmp_conn_val->Assign(0, new AddrVal(Conn()->OrigAddr()));
icmp_conn_val->Assign(1, new AddrVal(Conn()->RespAddr()));
icmp_conn_val->Assign(2, new Val(type, TYPE_COUNT));
icmp_conn_val->Assign(3, new Val(code, TYPE_COUNT));
icmp_conn_val->Assign(2, new Val(icmpp->icmp_type, 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(5, new Val(ip_hdr->TTL(), TYPE_COUNT));
icmp_conn_val->Assign(6, new Val(icmpv6, TYPE_BOOL));
}
Ref(icmp_conn_val);
@ -124,91 +219,115 @@ RecordVal* ICMP_Analyzer::BuildICMPVal()
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;
uint32 ip_hdr_len = ip->ip_hl * 4;
const u_char* transport_hdr;
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;
TransportProto proto = TRANSPORT_UNKNOWN;
int DF, MF, bad_hdr_len, bad_checksum;
uint32 src_addr, dst_addr;
IPAddr src_addr, dst_addr;
uint32 src_port, dst_port;
if ( ip_hdr_len < sizeof(struct ip) || ip_hdr_len > uint32(len) )
{ // We don't have an entire IP header.
if ( len < (int)sizeof(struct ip) || ip_hdr_len > uint32(len) )
{
// We don't have an entire IP header.
bad_hdr_len = 1;
ip_len = frag_offset = 0;
DF = MF = bad_checksum = 0;
src_addr = dst_addr = 0;
src_port = dst_port = 0;
}
else
{
bad_hdr_len = 0;
ip_len = ntohs(ip->ip_len);
bad_checksum = ones_complement_checksum((void*) ip, ip_hdr_len, 0) != 0xffff;
ip_len = ip_hdr->TotalLen();
bad_checksum = (ones_complement_checksum((void*) ip_hdr->IP4_Hdr(), ip_hdr_len, 0) != 0xffff);
src_addr = uint32(ip->ip_src.s_addr);
dst_addr = uint32(ip->ip_dst.s_addr);
src_addr = ip_hdr->SrcAddr();
dst_addr = ip_hdr->DstAddr();
switch ( ip->ip_p ) {
case 1: proto = TRANSPORT_ICMP; break;
case 6: proto = TRANSPORT_TCP; break;
case 17: proto = TRANSPORT_UDP; break;
DF = ip_hdr->DF();
MF = ip_hdr->MF();
frag_offset = ip_hdr->FragOffset();
// Default uses TRANSPORT_UNKNOWN, per initialization above.
}
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 )
if ( uint32(len) >= ip_hdr_len + 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.
bad_hdr_len = 1;
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);
@ -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(2, new AddrVal(dst_addr));
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(2, new Val(proto, 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;
}
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 */)
{
return 0;
@ -243,7 +422,7 @@ void ICMP_Analyzer::Describe(ODesc* d) const
d->Add(Conn()->LastTime());
d->AddSP(")");
d->Add(dotted_addr(Conn()->OrigAddr()));
d->Add(Conn()->OrigAddr());
d->Add(".");
d->Add(type);
d->Add(".");
@ -252,7 +431,7 @@ void ICMP_Analyzer::Describe(ODesc* d) const
d->SP();
d->AddSP("->");
d->Add(dotted_addr(Conn()->RespAddr()));
d->Add(Conn()->RespAddr());
}
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_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,
int caplen, const u_char*& data)
void ICMP_Analyzer::Echo(double t, const struct icmp* icmpp, int len,
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 )
return;
@ -313,7 +497,7 @@ void ICMP_Echo_Analyzer::NextICMP(double t, const struct icmp* icmpp, int len,
val_list* vl = new val_list;
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(iseq, TYPE_COUNT));
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);
}
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,
int caplen, const u_char*& data)
void ICMP_Analyzer::RouterAdvert(double t, const struct icmp* icmpp, int len,
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;
vl->append(BuildConnVal());
vl->append(BuildICMPVal());
vl->append(new AddrVal(htonl(addr)));
vl->append(BuildICMPVal(icmpp, len, 1, ip_hdr));
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,
int len, int caplen, const u_char*& data)
void ICMP_Analyzer::NeighborAdvert(double t, const struct icmp* icmpp, int len,
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;
switch ( type ) {
case ICMP_UNREACH: f = icmp_unreachable; break;
case ICMP_TIMXCEED: f = icmp_time_exceeded; break;
switch ( icmpp->icmp_type )
{
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 )
{
val_list* vl = new val_list;
vl->append(BuildConnVal());
vl->append(BuildICMPVal());
vl->append(new Val(code, TYPE_COUNT));
vl->append(ExtractICMPContext(caplen, data));
vl->append(BuildICMPVal(icmpp, len, 0, ip_hdr));
vl->append(new Val(icmpp->icmp_code, TYPE_COUNT));
vl->append(ExtractICMP4Context(caplen, data));
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;
// 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.
// Note that for the two-way ICMP messages, icmp_code is
// always 0 (RFC 792).
switch ( icmp_type ) {
case ICMP_ECHO: return ICMP_ECHOREPLY;
case ICMP_ECHOREPLY: return ICMP_ECHO;
case ICMP_TSTAMP: return ICMP_TSTAMPREPLY;
case ICMP_TSTAMPREPLY: return ICMP_TSTAMP;
case ICMP_IREQ: return ICMP_IREQREPLY;
case ICMP_IREQREPLY: return ICMP_IREQ;
case ICMP_ROUTERSOLICIT: return ICMP_ROUTERADVERT;
case ICMP_MASKREQ: return ICMP_MASKREPLY;
case ICMP_MASKREPLY: return ICMP_MASKREQ;
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 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;
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,
int len, int caplen, const u_char*& data);
void NextICMP4(double t, const struct icmp* icmpp, int len, int caplen,
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;
int type;
int code;
int len;
int request_len, reply_len;
RuleMatcherState matcher_state;
@ -56,81 +86,9 @@ private:
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
// 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

View file

@ -372,7 +372,7 @@ ID* ID::Unserialize(UnserialInfo* info)
Ref(id);
global_scope()->Insert(id->Name(), id);
#ifdef USE_PERFTOOLS
#ifdef USE_PERFTOOLS_DEBUG
heap_checker->IgnoreObject(id);
#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
#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 {
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;
ip6 = 0;
del = 1;
#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
if ( ((const struct ip*)p)->ip_v == 4 )
ip4 = (const struct ip*)p;
else if ( ((const struct ip*)p)->ip_v == 6 )
{
ip6 = (const struct ip6_hdr*)p;
ip6_hdrs = new IPv6_Hdr_Chain(ip6, len);
}
else
{
if ( arg_del )
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()
{
if ( ip6 )
delete ip6_hdrs;
if ( del )
{
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; }
/**
* If an IPv6 packet is wrapped, return a pointer to it, else null.
*/
const struct ip6_hdr* IP6_Hdr() const { return ip6; }
#ifdef BROv6
const uint32* SrcAddr() const { return src_addr; }
const uint32* DstAddr() const { return dst_addr; }
#else
const uint32* SrcAddr() const
{ return ip4 ? &(ip4->ip_src.s_addr) : 0; }
const uint32* DstAddr() const
{ return ip4 ? &(ip4->ip_dst.s_addr) : 0; }
#endif
/**
* Returns the source address held in the IP header.
*/
IPAddr IPHeaderSrcAddr() const
{ return ip4 ? IPAddr(ip4->ip_src) : IPAddr(ip6->ip6_src); }
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
{
if ( ip4 )
return ((const u_char*) ip4) + ip4->ip_hl * 4;
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
{
if ( ip4 )
return ntohs(ip4->ip_len) - ip4->ip_hl * 4;
else
return ntohs(ip6->ip6_plen);
return ntohs(ip6->ip6_plen) + 40 - ip6_hdrs->TotalLength();
}
uint16 TotalLen() const
{
if ( ip4 )
return ntohs(ip4->ip_len);
else
return ntohs(ip6->ip6_plen) + 40;
}
/**
* Returns the length of the IP packet (length of headers and payload).
*/
uint32 TotalLen() const
{ return ip4 ? ntohs(ip4->ip_len) : 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
{ 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
{ 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
{ return ip4 ? ((ntohs(ip4->ip_off) & IP_DF) != 0) : 0; }
uint16 IP_ID() const
{ return ip4 ? (ntohs(ip4->ip_id)) : 0; }
{ return ip4 ? ((ntohs(ip4->ip_off) & 0x4000) != 0) : 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:
const struct ip* ip4;
const struct ip6_hdr* ip6;
#ifdef BROv6
uint32 src_addr[NUM_ADDR_WORDS];
uint32 dst_addr[NUM_ADDR_WORDS];
#endif
int del;
bool del;
const IPv6_Hdr_Chain* ip6_hdrs;
};
#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 )
{
#ifdef USE_PERFTOOLS
#ifdef USE_PERFTOOLS_DEBUG
HeapLeakChecker::Disabler disabler;
#endif
re_skip_authentication = init_RE(skip_authentication);

View file

@ -225,5 +225,7 @@ NCP_Analyzer::NCP_Analyzer(Connection* conn)
NCP_Analyzer::~NCP_Analyzer()
{
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;
// FIXME: We should really merge PktDumper and PacketDumper.
// It's on my to-do [Robin].
PktDumper* pkt_dumper = 0;
int reading_live = 0;
@ -248,12 +247,14 @@ void net_init(name_list& interfaces, name_list& readfiles,
FlowSocketSrc* fs = new FlowSocketSrc(netflows[i]);
if ( ! fs->IsOpen() )
{
reporter->Error("%s: problem with netflow socket %s - %s\n",
prog, netflows[i], fs->ErrorMsg());
else
{
io_sources.Register(fs);
delete fs;
}
else
io_sources.Register(fs);
}
}
@ -454,6 +455,7 @@ void net_run()
// date on timers and events.
network_time = ct;
expire_timers();
usleep(1); // Just yield.
}
}
@ -483,6 +485,8 @@ void net_run()
// since Bro timers are not high-precision anyway.)
if ( ! using_communication )
usleep(100000);
else
usleep(1000);
// 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_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;
double non_analyzed_lifetime;
@ -192,8 +183,6 @@ StringVal* ssl_ca_certificate;
StringVal* ssl_private_key;
StringVal* ssl_passphrase;
StringVal* x509_crl_file;
Val* profiling_file;
double profiling_interval;
int expensive_profiling_multiple;
@ -213,11 +202,6 @@ int sig_max_group_size;
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;
RecordType* irc_join_info;
TableVal* irc_servers;
@ -358,17 +342,7 @@ void init_net_var()
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_crl_file = opt_internal_string("X509_crl_file");
non_analyzed_lifetime = opt_internal_double("non_analyzed_lifetime");
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");
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_list = internal_type("irc_join_list")->AsTableType();
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_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 StringVal* x509_crl_file;
extern double non_analyzed_lifetime;
extern double tcp_inactivity_timeout;
@ -216,11 +206,6 @@ extern int sig_max_group_size;
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 RecordType* irc_join_info;
extern TableVal* irc_servers;

View file

@ -131,6 +131,9 @@ int NetbiosSSN_Interpreter::ParseBroadcast(const u_char* data, int len,
return 0;
}
delete srcname;
delete dstname;
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;
*pid=id;
int* prev = os_matches.Insert(&key, pid);
int* prev = os_matches.Insert(key, pid);
bool ret = (prev ? *prev != id : 1);
if (prev)
delete prev;
delete key;
return ret;
}

View file

@ -14,6 +14,7 @@
#include "util.h"
#include "Dict.h"
#include "Reporter.h"
#include "IPAddr.h"
// Size limit for size wildcards.
#define PACKET_BIG 100
@ -88,7 +89,7 @@ public:
int FindMatch(struct os_type* retval, uint16 tot, uint8 DF_flag,
uint8 TTL, uint16 WSS, uint8 ocnt, uint8* op, uint16 MSS,
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,
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;
// 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 )
{
copy_addr(Conn()->OrigAddr(), &ip4->ip_src.s_addr);
copy_addr(Conn()->RespAddr(), &ip4->ip_dst.s_addr);
Conn()->OrigAddr().CopyIPv4(&ip4->ip_src);
Conn()->RespAddr().CopyIPv4(&ip4->ip_dst);
tcp4->th_sport = htons(Conn()->OrigPort());
tcp4->th_dport = htons(Conn()->RespPort());
}
else
{
copy_addr(Conn()->RespAddr(), &ip4->ip_src.s_addr);
copy_addr(Conn()->OrigAddr(), &ip4->ip_dst.s_addr);
Conn()->RespAddr().CopyIPv4(&ip4->ip_src);
Conn()->OrigAddr().CopyIPv4(&ip4->ip_dst);
tcp4->th_sport = htons(Conn()->RespPort());
tcp4->th_dport = htons(Conn()->OrigPort());
}

View file

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

View file

@ -1,11 +1,11 @@
#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;
f->tcp_flags = tcp_flags;
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)
@ -16,12 +16,12 @@ void PacketFilter::AddSrc(Val* src, uint32 tcp_flags, double probability)
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;
f->tcp_flags = tcp_flags;
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)
@ -32,9 +32,9 @@ void PacketFilter::AddDst(Val* dst, uint32 tcp_flags, double probability)
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)
@ -42,9 +42,9 @@ bool PacketFilter::RemoveSrc(Val* src)
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)
@ -54,21 +54,11 @@ bool PacketFilter::RemoveDst(Val* dst)
bool PacketFilter::Match(const IP_Hdr* ip, int len, int caplen)
{
#ifdef BROv6
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
Filter* f = (Filter*) src_filter.Lookup(ip->SrcAddr(), 128);
if ( f )
return MatchFilter(*f, *ip, len, caplen);
#ifdef BROv6
f = (Filter*) dst_filter.Lookup(ip->DstAddr(), NUM_ADDR_WORDS * 32);
#else
f = (Filter*) dst_filter.Lookup(*ip->DstAddr(), NUM_ADDR_WORDS * 32);
#endif
f = (Filter*) dst_filter.Lookup(ip->DstAddr(), 128);
if ( f )
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 )
{
// Caution! The packet sanity checks have not been performed yet
const struct ip* ip4 = ip.IP4_Hdr();
int ip_hdr_len = ip4->ip_hl * 4;
int ip_hdr_len = ip.HdrLen();
len -= ip_hdr_len; // remove IP header
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.
return false;
const struct tcphdr* tp =
(const struct tcphdr*) ((u_char*) ip4 + ip_hdr_len);
const struct tcphdr* tp = (const struct tcphdr*) ip.Payload();
if ( tp->th_flags & f.tcp_flags )
// 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
// as an AddrVal or a SubnetVal) which hasn't any of TCP flags set
// (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 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);
// Removes the filter entry for the given src/dst
// Returns false if filter doesn not exist.
bool RemoveSrc(addr_type src);
bool RemoveSrc(const IPAddr& src);
bool RemoveSrc(Val* dst);
bool RemoveDst(addr_type dst);
bool RemoveDst(const IPAddr& dst);
bool RemoveDst(Val* dst);
// 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);
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
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 &&
// Note: can't sort fragmented packets
(ip_hdr->FragField() & 0x3fff) == 0 )
( ! ip_hdr->IsFragment() ) )
{
tcp_offset = hdr_size + ip_hdr->HdrLen();
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;
key = id.BuildConnKey();
key = BuildConnIDHashKey(id);
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)
{
#ifdef USE_PERFTOOLS
#ifdef USE_PERFTOOLS_DEBUG
HeapLeakChecker::Disabler disabler;
#endif

View file

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

View file

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

View file

@ -3,6 +3,7 @@
#include "Val.h"
#include "net_util.h"
#include "IPAddr.h"
extern "C" {
#include "patricia.h"
@ -24,7 +25,7 @@ public:
// Addr in network byte order. If data is zero, acts like a set.
// Returns ptr to old data if already existing.
// 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.
void* Insert(const Val* value, void* data = 0);
@ -32,11 +33,11 @@ public:
// Returns nil if not found, pointer to data otherwise.
// For items without data, returns non-nil if found.
// 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;
// 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 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;
Reassembler::Reassembler(int init_seq, const uint32* ip_addr,
ReassemblerType arg_type)
Reassembler::Reassembler(int init_seq, ReassemblerType arg_type)
{
blocks = last_block = 0;
trim_seq = last_reassem_seq = init_seq;

View file

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

View file

@ -183,8 +183,11 @@
#include "Sessions.h"
#include "File.h"
#include "Conn.h"
#include "LogMgr.h"
#include "Reporter.h"
#include "threading/SerialTypes.h"
#include "logging/Manager.h"
#include "IPAddr.h"
#include "bro_inet_ntop.h"
extern "C" {
#include "setsignal.h"
@ -463,7 +466,7 @@ static inline const char* ip2a(uint32 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;
@ -530,6 +533,7 @@ RemoteSerializer::RemoteSerializer()
terminating = false;
in_sync = 0;
last_flush = 0;
received_logs = 0;
}
RemoteSerializer::~RemoteSerializer()
@ -670,8 +674,8 @@ void RemoteSerializer::Fork()
}
}
RemoteSerializer::PeerID RemoteSerializer::Connect(addr_type ip, uint16 port,
const char* our_class, double retry, bool use_ssl)
RemoteSerializer::PeerID RemoteSerializer::Connect(const IPAddr& ip,
uint16 port, const char* our_class, double retry, bool use_ssl)
{
if ( ! using_communication )
return true;
@ -679,16 +683,12 @@ RemoteSerializer::PeerID RemoteSerializer::Connect(addr_type ip, uint16 port,
if ( ! initialized )
reporter->InternalError("remote serializer not initialized");
#ifdef BROv6
if ( ! is_v4_addr(ip) )
if ( ip.GetFamily() == IPv6 )
Error("inter-Bro communication not supported over IPv6");
uint32 ip4 = to_v4_addr(ip);
#else
uint32 ip4 = ip;
#endif
ip4 = ntohl(ip4);
const uint32* bytes;
ip.GetBytes(&bytes);
uint32 ip4 = ntohl(*bytes);
if ( ! child_pid )
Fork();
@ -1232,7 +1232,7 @@ bool RemoteSerializer::SendCapabilities(Peer* peer)
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 )
return true;
@ -1240,16 +1240,12 @@ bool RemoteSerializer::Listen(addr_type ip, uint16 port, bool expect_ssl)
if ( ! initialized )
reporter->InternalError("remote serializer not initialized");
#ifdef BROv6
if ( ! is_v4_addr(ip) )
if ( ip.GetFamily() == IPv6 )
Error("inter-Bro communication not supported over IPv6");
uint32 ip4 = to_v4_addr(ip);
#else
uint32 ip4 = ip;
#endif
ip4 = ntohl(ip4);
const uint32* bytes;
ip.GetBytes(&bytes);
uint32 ip4 = ntohl(*bytes);
if ( ! SendToChild(MSG_LISTEN, 0, 3, ip4, port, expect_ssl) )
return false;
@ -1359,6 +1355,14 @@ double RemoteSerializer::NextTimestamp(double* local_network_time)
{
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 pt = packets.length() ? packets[0]->time : -1;
@ -2476,7 +2480,7 @@ bool RemoteSerializer::ProcessRemotePrint()
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)
{
@ -2486,7 +2490,7 @@ bool RemoteSerializer::SendLogCreateWriter(EnumVal* id, EnumVal* writer, string
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");
@ -2499,6 +2503,9 @@ bool RemoteSerializer::SendLogCreateWriter(PeerID peer_id, EnumVal* id, EnumVal*
if ( peer->phase != Peer::HANDSHAKE && peer->phase != Peer::RUNNING )
return false;
if ( ! peer->logs_requested )
return false;
BinarySerializationFormat fmt;
fmt.StartWrite();
@ -2540,7 +2547,7 @@ error:
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)
{
@ -2550,7 +2557,7 @@ bool RemoteSerializer::SendLogWrite(EnumVal* id, EnumVal* writer, string path, i
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 )
return false;
@ -2558,7 +2565,9 @@ bool RemoteSerializer::SendLogWrite(Peer* peer, EnumVal* id, EnumVal* writer, st
if ( ! peer->logs_requested )
return false;
assert(peer->log_buffer);
if ( ! peer->log_buffer )
// Peer shutting down.
return false;
// 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 ( ! FlushLogBuffer(peer) )
{
delete [] data;
return false;
}
}
// If the data is actually larger than our complete buffer, just send it out.
@ -2616,6 +2628,9 @@ error:
bool RemoteSerializer::FlushLogBuffer(Peer* p)
{
if ( ! p->logs_requested )
return false;
last_flush = network_time;
if ( p->state == Peer::CLOSING )
@ -2637,11 +2652,17 @@ bool RemoteSerializer::ProcessLogCreateWriter()
if ( current_peer->state == Peer::CLOSING )
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);
EnumVal* id_val = 0;
EnumVal* writer_val = 0;
LogField** fields = 0;
threading::Field** fields = 0;
BinarySerializationFormat fmt;
fmt.StartRead(current_args->data, current_args->len);
@ -2658,11 +2679,11 @@ bool RemoteSerializer::ProcessLogCreateWriter()
if ( ! success )
goto error;
fields = new LogField* [num_fields];
fields = new threading::Field* [num_fields];
for ( int i = 0; i < num_fields; i++ )
{
fields[i] = new LogField;
fields[i] = new threading::Field;
if ( ! fields[i]->Read(&fmt) )
goto error;
}
@ -2672,7 +2693,7 @@ bool RemoteSerializer::ProcessLogCreateWriter()
id_val = new EnumVal(id, BifType::Enum::Log::ID);
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;
Unref(id_val);
@ -2703,7 +2724,7 @@ bool RemoteSerializer::ProcessLogWrite()
// Unserialize one entry.
EnumVal* id_val = 0;
EnumVal* writer_val = 0;
LogVal** vals = 0;
threading::Value** vals = 0;
int id, writer;
string path;
@ -2717,11 +2738,11 @@ bool RemoteSerializer::ProcessLogWrite()
if ( ! success )
goto error;
vals = new LogVal* [num_fields];
vals = new threading::Value* [num_fields];
for ( int i = 0; i < num_fields; i++ )
{
vals[i] = new LogVal;
vals[i] = new threading::Value;
if ( ! vals[i]->Read(&fmt) )
goto error;
}
@ -2741,6 +2762,8 @@ bool RemoteSerializer::ProcessLogWrite()
fmt.EndRead();
++received_logs;
return true;
error:
@ -2850,7 +2873,7 @@ void RemoteSerializer::GotID(ID* id, Val* val)
(desc && *desc) ? desc : "not set"),
current_peer);
#ifdef USE_PERFTOOLS
#ifdef USE_PERFTOOLS_DEBUG
// May still be cached, but we don't care.
heap_checker->IgnoreObject(id);
#endif
@ -3382,6 +3405,11 @@ void SocketComm::Run()
small_timeout.tv_usec =
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,
&small_timeout);

View file

@ -14,8 +14,11 @@
// FIXME: Change this to network byte order
class IncrementalSendTimer;
class LogField;
class LogVal;
namespace threading {
class Field;
class Value;
}
// This class handles the communication done in Bro's main loop.
class RemoteSerializer : public Serializer, public IOSource {
@ -32,7 +35,7 @@ public:
static const PeerID PEER_NONE = SOURCE_LOCAL;
// 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.
bool CloseConnection(PeerID peer);
@ -60,7 +63,7 @@ public:
bool CompleteHandshake(PeerID peer);
// 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.
bool StopListening();
@ -99,13 +102,13 @@ public:
bool SendPrintHookEvent(BroFile* f, const char* txt, size_t len);
// 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.
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.
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
// current sync-point, or -1 on error.
@ -300,7 +303,7 @@ protected:
bool SendID(SerialInfo* info, Peer* peer, const ID& id);
bool SendCapabilities(Peer* peer);
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 RaiseEvent(EventHandlerPtr event, Peer* peer, const char* arg = 0);
@ -335,6 +338,7 @@ private:
int propagate_accesses;
bool ignore_accesses;
bool terminating;
int received_logs;
Peer* source_peer;
PeerID id_counter; // Keeps track of assigned IDs.
uint32 current_sync_point;

View file

@ -155,7 +155,7 @@ void Reporter::WeirdHelper(EventHandlerPtr event, Val* conn_val, const char* add
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);
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);
}
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);
}

View file

@ -9,8 +9,8 @@
#include <utility>
#include "util.h"
#include "net_util.h"
#include "EventHandler.h"
#include "IPAddr.h"
class Connection;
class Location;
@ -74,7 +74,7 @@ public:
void Weird(const char* name); // Raises net_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(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
// offline from a trace.
@ -121,7 +121,7 @@ private:
// The order if addl, name needs to be like that since fmt_name can
// contain format specifiers
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;
bool via_events;

View file

@ -73,6 +73,9 @@ RuleHdrTest::RuleHdrTest(RuleHdrTest& h)
copied_set->ids = orig_set->ids;
loop_over_list(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)
{
#ifdef USE_PERFTOOLS
#ifdef USE_PERFTOOLS_DEBUG
HeapLeakChecker::Disabler disabler;
#endif
@ -1067,16 +1070,22 @@ static bool val_to_maskedval(Val* v, maskedvalue_list* append_to)
break;
case TYPE_SUBNET:
#ifdef BROv6
{
uint32* n = v->AsSubNet()->net;
uint32* m = v->AsSubNetVal()->Mask();
const uint32* n;
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 &&
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];
}
@ -1087,10 +1096,6 @@ static bool val_to_maskedval(Val* v, maskedvalue_list* append_to)
mval->mask = 0;
}
}
#else
mval->val = ntohl(v->AsSubNet()->net);
mval->mask = v->AsSubNetVal()->Mask();
#endif
break;
default:
@ -1114,7 +1119,12 @@ void id_to_maskedvallist(const char* id, maskedvalue_list* append_to)
val_list* vals = v->AsTableVal()->ConvertToPureList()->Vals();
loop_over_list(*vals, i )
if ( ! val_to_maskedval((*vals)[i], append_to) )
{
delete_vals(vals);
return;
}
delete_vals(vals);
}
else

View file

@ -353,7 +353,6 @@ void SMTP_Analyzer::ProcessLine(int length, const char* line, bool orig)
int ext_len;
get_word(end_of_line - line, line, ext_len, ext);
line = skip_whitespace(line + ext_len, end_of_line);
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 )
{
const uint32* dst;
IPAddr dst;
if ( is_orig )
dst = TCP()->Orig()->dst_addr;
else

View file

@ -125,7 +125,7 @@ SERIAL_EXPR(FIELD_EXPR, 22)
SERIAL_EXPR(HAS_FIELD_EXPR, 23)
SERIAL_EXPR(RECORD_CONSTRUCTOR_EXPR, 24)
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(RECORD_COERCE_EXPR, 28)
SERIAL_EXPR(FLATTEN_EXPR, 29)

View file

@ -230,6 +230,71 @@ bool BinarySerializationFormat::Read(string* v, const char* tag)
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)
{
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);
}
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)
{
return true;
@ -389,6 +501,30 @@ bool XMLSerializationFormat::Read(string* s, const char* tag)
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)
{
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);
}
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)
{
while ( len-- )

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