mirror of
https://github.com/zeek/zeek.git
synced 2025-10-11 11:08:20 +00:00
Merge remote-tracking branch 'origin/master' into topic/script-reference
Conflicts: scripts/base/frameworks/notice/actions/pp-alarms.bro scripts/base/frameworks/notice/main.bro scripts/base/init-bare.bro src/event.bif
This commit is contained in:
commit
7646ef1aed
43 changed files with 410 additions and 1277 deletions
44
CHANGES
44
CHANGES
|
@ -1,4 +1,48 @@
|
|||
|
||||
2.0-beta-177 | 2012-01-05 15:01:07 -0800
|
||||
|
||||
* Replace the --snaplen/-l command line option with a
|
||||
scripting-layer option called "snaplen" (which can also be
|
||||
redefined on the command line, e.g. `bro -i eth0 snaplen=65535`).
|
||||
|
||||
* Reduce snaplen default from 65535 to old default of 8192. Fixes
|
||||
#720. (Jon Siwek)
|
||||
|
||||
2.0-beta-174 | 2012-01-04 12:47:10 -0800
|
||||
|
||||
* SSL improvements. (Seth Hall)
|
||||
|
||||
- Added the ssl_session_ticket_handshake event back.
|
||||
|
||||
- Fixed a few bugs.
|
||||
|
||||
- Removed the SSLv2.cc file since it's not used.
|
||||
|
||||
2.0-beta-169 | 2012-01-04 12:44:39 -0800
|
||||
|
||||
* Tuning the pretty-printed alarm mails, which now include the
|
||||
covered time range into the subject. (Robin Sommer)
|
||||
|
||||
* Adding top-level "test" target to Makefile. (Robin Sommer)
|
||||
|
||||
* Adding SWIG as dependency to INSTALL. (Robin Sommer)
|
||||
|
||||
2.0-beta-155 | 2012-01-03 15:42:32 -0800
|
||||
|
||||
* Remove dead code related to record type inheritance. (Jon Siwek)
|
||||
|
||||
2.0-beta-152 | 2012-01-03 14:51:34 -0800
|
||||
|
||||
* Notices now record the transport-layer protocol. (Bernhard Amann)
|
||||
|
||||
2.0-beta-150 | 2012-01-03 14:42:45 -0800
|
||||
|
||||
* CMake 2.6 top-level 'install' target compat. Fixes #729. (Jon Siwek)
|
||||
|
||||
* Minor fixes to test process. Addresses #298.
|
||||
|
||||
* Increase timeout interval of communication-related btests. (Jon Siwek)
|
||||
|
||||
2.0-beta-145 | 2011-12-19 11:37:15 -0800
|
||||
|
||||
* Empty fields are now logged as "(empty)" by default. (Robin
|
||||
|
|
14
INSTALL
14
INSTALL
|
@ -14,10 +14,11 @@ before you begin:
|
|||
|
||||
* OpenSSL (headers and libraries) http://www.openssl.org
|
||||
|
||||
* Libmagic For identifying file types (e.g., in FTP transfers).
|
||||
* SWIG http://www.swig.org
|
||||
|
||||
* Libz For decompressing HTTP bodies by the HTTP analyzer, and for
|
||||
compressed Bro-to-Bro communication.
|
||||
* Libmagic
|
||||
|
||||
* Libz
|
||||
|
||||
Bro can make uses of some optional libraries if they are found at
|
||||
installation time:
|
||||
|
@ -32,6 +33,7 @@ already come preinstalled:
|
|||
* Flex (Fast Lexical Analyzer)
|
||||
* Perl (Used only during the Bro build process)
|
||||
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
|
@ -69,8 +71,10 @@ Running Bro
|
|||
===========
|
||||
|
||||
Bro is a complex program and it takes a bit of time to get familiar
|
||||
with it. A good place for newcomers to start is the
|
||||
:doc:`quick start guide <quickstart>`.
|
||||
with it. A good place for newcomers to start is the Quickstart Guide at
|
||||
|
||||
http://www.bro-ids.org/documentation/quickstart.bro.html
|
||||
|
||||
|
||||
For developers that wish to run Bro directly from the ``build/``
|
||||
directory (i.e., without performing ``make install``), they will have
|
||||
|
|
5
Makefile
5
Makefile
|
@ -14,7 +14,7 @@ HAVE_MODULES=git submodule | grep -v cmake >/dev/null
|
|||
all: configured
|
||||
$(MAKE) -C $(BUILD) $@
|
||||
|
||||
install: configured
|
||||
install: configured all
|
||||
$(MAKE) -C $(BUILD) $@
|
||||
|
||||
install-aux: configured
|
||||
|
@ -60,6 +60,9 @@ bindist:
|
|||
distclean:
|
||||
rm -rf $(BUILD)
|
||||
|
||||
test:
|
||||
@(cd testing && make )
|
||||
|
||||
configured:
|
||||
@test -d $(BUILD) || ( echo "Error: No build/ directory found. Did you run configure?" && exit 1 )
|
||||
@test -e $(BUILD)/Makefile || ( echo "Error: No build/Makefile found. Did you run configure?" && exit 1 )
|
||||
|
|
51
NEWS
Normal file
51
NEWS
Normal file
|
@ -0,0 +1,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.0
|
||||
-------
|
||||
|
||||
As the version number jump suggests, Bro 2.0 is a major upgrade and
|
||||
lots of things have changed. We have assembled a separate upprade
|
||||
guide with the most important changes compared to Bro 1.5 at
|
||||
http://www.bro-ids.org/documentation/upgrade.bro.html. You can find
|
||||
the offline version of that document in ``doc/upgrade.rst.``.
|
||||
|
||||
Compared to the earlier 2.0 Beta version, the major changes in the
|
||||
final release are:
|
||||
|
||||
* The default scripts now come with complete reference
|
||||
documentation. See
|
||||
http://www.bro-ids.org/documentation/index.html.
|
||||
|
||||
* libz and libmagic are now required dependencies.
|
||||
|
||||
* Reduced snaplen default from 65535 to old default of 8192. The
|
||||
large value was introducing performance problems on many
|
||||
systems.
|
||||
|
||||
* Replaced the --snaplen/-l command line option with a
|
||||
scripting-layer option called "snaplen". The new option can also
|
||||
be redefined on the command line, e.g. ``bro -i eth0
|
||||
snaplen=65535``.
|
||||
|
||||
* Reintroduced the BRO_LOG_SUFFIX environment that the ASCII
|
||||
logger now respects to add a suffix to the log files it creates.
|
||||
|
||||
* The ASCII logs now include further header information, and
|
||||
fields set to an empty value are now logged as ``(empty)`` by
|
||||
default (instead of ``-``, which is already used for fields that
|
||||
are not set at all).
|
||||
|
||||
* Some NOTICES were renamed, and the signatures of some SSL events
|
||||
have changed.
|
||||
|
||||
* Many smaller bug fixes, portability improvements, and general
|
||||
polishing.
|
||||
|
||||
|
||||
|
||||
|
10
README
10
README
|
@ -4,13 +4,15 @@ Bro Network Security Monitor
|
|||
|
||||
Bro is a powerful framework for network analysis and security
|
||||
monitoring. Please see the INSTALL file for installation instructions
|
||||
and pointers for getting started. For more documentation, research
|
||||
publications, and community contact information, see Bro's home page:
|
||||
and pointers for getting started. NEWS contains releases notes for the
|
||||
current version, and CHANGES has the complete history of changes.
|
||||
Please see COPYING for licensing information.
|
||||
|
||||
For more documentation, research publications, and community contact
|
||||
information, please see Bro's home page:
|
||||
|
||||
http://www.bro-ids.org
|
||||
|
||||
Please see COPYING for licensing information.
|
||||
|
||||
On behalf of the Bro Development Team,
|
||||
|
||||
Vern Paxson & Robin Sommer,
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
2.0-beta-145
|
||||
2.0-beta-177
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit d7b8a43759bfcbe1381d132d8ab388937e52a6d4
|
||||
Subproject commit c5cee3d5746ed3d5c14348c1f264d19404caa761
|
|
@ -1 +1 @@
|
|||
Subproject commit a42e4d133b94622c612055047f8534d5122e6e88
|
||||
Subproject commit d3d5934310a94452b1dddabb2e75f6c5c86b4860
|
17
doc/faq.rst
17
doc/faq.rst
|
@ -28,6 +28,23 @@ Here are some pointers to more information:
|
|||
Lothar Braun et. al evaluates packet capture performance on
|
||||
commodity hardware
|
||||
|
||||
Are there any gotchas regarding interface configuration for live capture? Or why might I be seeing abnormally large packets much greater than interface MTU?
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
Some NICs offload the reassembly of traffic into "superpackets" so that
|
||||
fewer packets are then passed up the stack (e.g. "TCP segmentation
|
||||
offload", or "generic segmentation offload"). The result is that the
|
||||
capturing application will observe packets much larger than the MTU size
|
||||
of the interface they were captured from and may also interfere with the
|
||||
maximum packet capture length, ``snaplen``, so it's a good idea to disable
|
||||
an interface's offloading features.
|
||||
|
||||
You can use the ``ethtool`` program on Linux to view and disable
|
||||
offloading features of an interface. See this page for more explicit
|
||||
directions:
|
||||
|
||||
http://securityonion.blogspot.com/2011/10/when-is-full-packet-capture-not-full.html
|
||||
|
||||
What does an error message like ``internal error: NB-DNS error`` mean?
|
||||
---------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -168,10 +168,6 @@ New Default Settings
|
|||
are loaded. See ``PacketFilter::all_packets`` for how to revert to old
|
||||
behavior.
|
||||
|
||||
- By default, Bro now sets a libpcap snaplen of 65535. Depending on
|
||||
the OS, this may have performance implications and you can use the
|
||||
``--snaplen`` option to change the value.
|
||||
|
||||
API Changes
|
||||
-----------
|
||||
|
||||
|
|
|
@ -10,18 +10,21 @@ module Notice;
|
|||
export {
|
||||
## Activate pretty-printed alarm summaries.
|
||||
const pretty_print_alarms = T &redef;
|
||||
|
||||
|
||||
## Address to send the pretty-printed reports to. Default if not set is
|
||||
## :bro:id:`Notice::mail_dest`.
|
||||
const mail_dest_pretty_printed = "" &redef;
|
||||
|
||||
## If an address from one of these networks is reported, we mark
|
||||
## the entry with an addition quote symbol (that is, ">"). Many MUAs
|
||||
## the entry with an additional quote symbol (i.e., ">"). Many MUAs
|
||||
## then highlight such lines differently.
|
||||
global flag_nets: set[subnet] &redef;
|
||||
|
||||
|
||||
## Function that renders a single alarm. Can be overidden.
|
||||
global pretty_print_alarm: function(out: file, n: Info) &redef;
|
||||
|
||||
## Force generating mail file, even if reading from traces or no mail
|
||||
## destination is defined. This is mainly for testing.
|
||||
global force_email_summaries = F &redef;
|
||||
}
|
||||
|
||||
# We maintain an old-style file recording the pretty-printed alarms.
|
||||
|
@ -32,6 +35,9 @@ global pp_alarms_open: bool = F;
|
|||
# Returns True if pretty-printed alarm summaries are activated.
|
||||
function want_pp() : bool
|
||||
{
|
||||
if ( force_email_summaries )
|
||||
return T;
|
||||
|
||||
return (pretty_print_alarms && ! reading_traces()
|
||||
&& (mail_dest != "" || mail_dest_pretty_printed != ""));
|
||||
}
|
||||
|
@ -41,38 +47,49 @@ function pp_open()
|
|||
{
|
||||
if ( pp_alarms_open )
|
||||
return;
|
||||
|
||||
|
||||
pp_alarms_open = T;
|
||||
pp_alarms = open(pp_alarms_name);
|
||||
|
||||
local dest = mail_dest_pretty_printed != "" ? mail_dest_pretty_printed
|
||||
: mail_dest;
|
||||
|
||||
local headers = email_headers("Alarm summary", dest);
|
||||
write_file(pp_alarms, headers + "\n");
|
||||
}
|
||||
|
||||
# Closes and mails out the current output file.
|
||||
function pp_send()
|
||||
function pp_send(rinfo: Log::RotationInfo)
|
||||
{
|
||||
if ( ! pp_alarms_open )
|
||||
return;
|
||||
|
||||
|
||||
write_file(pp_alarms, "\n\n--\n[Automatically generated]\n\n");
|
||||
close(pp_alarms);
|
||||
|
||||
system(fmt("/bin/cat %s | %s -t -oi && /bin/rm %s",
|
||||
pp_alarms_name, sendmail, pp_alarms_name));
|
||||
|
||||
pp_alarms_open = F;
|
||||
|
||||
local from = strftime("%H:%M:%S", rinfo$open);
|
||||
local to = strftime("%H:%M:%S", rinfo$close);
|
||||
local subject = fmt("Alarm summary from %s-%s", from, to);
|
||||
local dest = mail_dest_pretty_printed != "" ? mail_dest_pretty_printed
|
||||
: mail_dest;
|
||||
|
||||
if ( dest == "" )
|
||||
# No mail destination configured, just leave the file alone. This is mainly for
|
||||
# testing.
|
||||
return;
|
||||
|
||||
local headers = email_headers(subject, dest);
|
||||
|
||||
local header_name = pp_alarms_name + ".tmp";
|
||||
local header = open(header_name);
|
||||
write_file(header, headers + "\n");
|
||||
close(header);
|
||||
|
||||
system(fmt("/bin/cat %s %s | %s -t -oi && /bin/rm -f %s %s",
|
||||
header_name, pp_alarms_name, sendmail, header_name, pp_alarms_name));
|
||||
}
|
||||
|
||||
# Postprocessor function that triggers the email.
|
||||
function pp_postprocessor(info: Log::RotationInfo): bool
|
||||
{
|
||||
if ( want_pp() )
|
||||
pp_send();
|
||||
|
||||
pp_send(info);
|
||||
|
||||
return T;
|
||||
}
|
||||
|
||||
|
@ -80,7 +97,7 @@ event bro_init()
|
|||
{
|
||||
if ( ! want_pp() )
|
||||
return;
|
||||
|
||||
|
||||
# This replaces the standard non-pretty-printing filter.
|
||||
Log::add_filter(Notice::ALARM_LOG,
|
||||
[$name="alarm-mail", $writer=Log::WRITER_NONE,
|
||||
|
@ -92,13 +109,13 @@ event notice(n: Notice::Info) &priority=-5
|
|||
{
|
||||
if ( ! want_pp() )
|
||||
return;
|
||||
|
||||
if ( ACTION_LOG !in n$actions )
|
||||
|
||||
if ( ACTION_ALARM !in n$actions )
|
||||
return;
|
||||
|
||||
|
||||
if ( ! pp_alarms_open )
|
||||
pp_open();
|
||||
|
||||
|
||||
pretty_print_alarm(pp_alarms, n);
|
||||
}
|
||||
|
||||
|
@ -108,12 +125,12 @@ function do_msg(out: file, n: Info, line1: string, line2: string, line3: string,
|
|||
@ifdef ( Notice::ACTION_ADD_GEODATA ) # Make tests happy, cyclic dependency.
|
||||
if ( n?$remote_location && n$remote_location?$country_code )
|
||||
country = fmt(" (remote location %s)", n$remote_location$country_code);
|
||||
@endif
|
||||
|
||||
@endif
|
||||
|
||||
line1 = cat(line1, country);
|
||||
|
||||
|
||||
local resolved = "";
|
||||
|
||||
|
||||
if ( host1 != 0.0.0.0 )
|
||||
resolved = fmt("%s # %s = %s", resolved, host1, name1);
|
||||
|
||||
|
@ -133,64 +150,64 @@ function do_msg(out: file, n: Info, line1: string, line2: string, line3: string,
|
|||
function pretty_print_alarm(out: file, n: Info)
|
||||
{
|
||||
local pdescr = "";
|
||||
|
||||
|
||||
@if ( Cluster::is_enabled() )
|
||||
pdescr = "local";
|
||||
|
||||
|
||||
if ( n?$src_peer )
|
||||
pdescr = n$src_peer?$descr ? n$src_peer$descr : fmt("%s", n$src_peer$host);
|
||||
|
||||
pdescr = fmt("<%s> ", pdescr);
|
||||
@endif
|
||||
|
||||
|
||||
local msg = fmt( "%s%s", pdescr, n$msg);
|
||||
|
||||
|
||||
local who = "";
|
||||
local h1 = 0.0.0.0;
|
||||
local h2 = 0.0.0.0;
|
||||
|
||||
|
||||
local orig_p = "";
|
||||
local resp_p = "";
|
||||
|
||||
|
||||
if ( n?$id )
|
||||
{
|
||||
orig_p = fmt(":%s", n$id$orig_p);
|
||||
resp_p = fmt(":%s", n$id$resp_p);
|
||||
h1 = n$id$orig_h;
|
||||
h2 = n$id$resp_h;
|
||||
who = fmt("%s:%s -> %s:%s", h1, n$id$orig_p, h2, n$id$resp_p);
|
||||
}
|
||||
|
||||
if ( n?$src && n?$dst )
|
||||
else if ( n?$src && n?$dst )
|
||||
{
|
||||
h1 = n$src;
|
||||
h2 = n$dst;
|
||||
who = fmt("%s%s -> %s%s", h1, orig_p, h2, resp_p);
|
||||
|
||||
if ( n?$uid )
|
||||
who = fmt("%s (uid %s)", who, n$uid );
|
||||
who = fmt("%s -> %s", h1, h2);
|
||||
}
|
||||
|
||||
else if ( n?$src )
|
||||
{
|
||||
local p = "";
|
||||
|
||||
if ( n?$p )
|
||||
p = fmt(":%s", n$p);
|
||||
|
||||
h1 = n$src;
|
||||
who = fmt("%s%s", h1, p);
|
||||
who = fmt("%s%s", h1, (n?$p ? fmt(":%s", n$p) : ""));
|
||||
}
|
||||
|
||||
|
||||
if ( n?$uid )
|
||||
who = fmt("%s (uid %s)", who, n$uid );
|
||||
|
||||
local flag = (h1 in flag_nets || h2 in flag_nets);
|
||||
|
||||
|
||||
local line1 = fmt(">%s %D %s %s", (flag ? ">" : " "), network_time(), n$note, who);
|
||||
local line2 = fmt(" %s", msg);
|
||||
local line3 = n?$sub ? fmt(" %s", n$sub) : "";
|
||||
|
||||
|
||||
if ( h1 == 0.0.0.0 )
|
||||
{
|
||||
do_msg(out, n, line1, line2, line3, h1, "", h2, "");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if ( reading_traces() )
|
||||
{
|
||||
do_msg(out, n, line1, line2, line3, h1, "<skipped>", h2, "<skipped>");
|
||||
return;
|
||||
}
|
||||
|
||||
when ( local h1name = lookup_addr(h1) )
|
||||
{
|
||||
if ( h2 == 0.0.0.0 )
|
||||
|
|
|
@ -73,8 +73,12 @@ export {
|
|||
## reference to the actual connection will be deleted after applying
|
||||
## the notice policy.
|
||||
iconn: icmp_conn &optional;
|
||||
|
||||
## The type of the notice.
|
||||
|
||||
## The transport protocol. Filled automatically when either conn, iconn
|
||||
## or p is specified.
|
||||
proto: transport_proto &log &optional;
|
||||
|
||||
## The :bro:enum:`Notice::Type` of the notice.
|
||||
note: Type &log;
|
||||
## The human readable message for the notice.
|
||||
msg: string &log &optional;
|
||||
|
@ -535,8 +539,12 @@ function apply_policy(n: Notice::Info)
|
|||
n$p = n$id$resp_p;
|
||||
}
|
||||
|
||||
if ( n?$p )
|
||||
n$proto = get_port_transport_proto(n$p);
|
||||
|
||||
if ( n?$iconn )
|
||||
{
|
||||
n$proto = icmp;
|
||||
if ( ! n?$src )
|
||||
n$src = n$iconn$orig_h;
|
||||
if ( ! n?$dst )
|
||||
|
|
|
@ -2331,6 +2331,9 @@ const ignore_keep_alive_rexmit = F &redef;
|
|||
## .. bro:see:: tunnel_port
|
||||
const parse_udp_tunnels = F &redef;
|
||||
|
||||
# Load the logging framework here because it uses fairly deep integration with
|
||||
## Number of bytes per packet to capture from live interfaces.
|
||||
const snaplen = 8192 &redef;
|
||||
|
||||
# Load the logging framework here because it uses fairly deep integration with
|
||||
# BiFs and script-land defined types.
|
||||
@load base/frameworks/logging
|
||||
|
|
944
src/SSLv2.cc
944
src/SSLv2.cc
|
@ -1,944 +0,0 @@
|
|||
#include "SSLv2.h"
|
||||
#include "SSLv3.h"
|
||||
|
||||
// --- Initalization of static variables --------------------------------------
|
||||
|
||||
uint SSLv2_Interpreter::totalConnections = 0;
|
||||
uint SSLv2_Interpreter::analyzedConnections = 0;
|
||||
uint SSLv2_Interpreter::openedConnections = 0;
|
||||
uint SSLv2_Interpreter::failedConnections = 0;
|
||||
uint SSLv2_Interpreter::weirdConnections = 0;
|
||||
uint SSLv2_Interpreter::totalRecords = 0;
|
||||
uint SSLv2_Interpreter::clientHelloRecords = 0;
|
||||
uint SSLv2_Interpreter::serverHelloRecords = 0;
|
||||
uint SSLv2_Interpreter::clientMasterKeyRecords = 0;
|
||||
uint SSLv2_Interpreter::errorRecords = 0;
|
||||
|
||||
|
||||
// --- SSLv2_Interpreter -------------------------------------------------------
|
||||
|
||||
/*!
|
||||
* The Constructor.
|
||||
*
|
||||
* \param proxy Pointer to the SSLProxy_Analyzer who created this instance.
|
||||
*/
|
||||
SSLv2_Interpreter::SSLv2_Interpreter(SSLProxy_Analyzer* proxy)
|
||||
: SSL_Interpreter(proxy)
|
||||
{
|
||||
++totalConnections;
|
||||
records = 0;
|
||||
bAnalyzedCounted = false;
|
||||
connState = START;
|
||||
|
||||
pServerCipherSpecs = 0;
|
||||
pClientCipherSpecs = 0;
|
||||
bClientWantsCachedSession = false;
|
||||
usedCipherSpec = (SSLv2_CipherSpec) 0;
|
||||
|
||||
pConnectionId = 0;
|
||||
pChallenge = 0;
|
||||
pSessionId = 0;
|
||||
pMasterClearKey = 0;
|
||||
pMasterEncryptedKey = 0;
|
||||
pClientReadKey = 0;
|
||||
pServerReadKey = 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* The Destructor.
|
||||
*/
|
||||
SSLv2_Interpreter::~SSLv2_Interpreter()
|
||||
{
|
||||
if ( connState != CLIENT_MASTERKEY_SEEN &&
|
||||
connState != CACHED_SESSION &&
|
||||
connState != START && // we only complain if we saw some data
|
||||
connState != ERROR_SEEN )
|
||||
++failedConnections;
|
||||
|
||||
if ( connState != CLIENT_MASTERKEY_SEEN && connState != CACHED_SESSION )
|
||||
++weirdConnections;
|
||||
|
||||
delete pServerCipherSpecs;
|
||||
delete pClientCipherSpecs;
|
||||
delete pConnectionId;
|
||||
delete pChallenge;
|
||||
delete pSessionId;
|
||||
delete pMasterClearKey;
|
||||
delete pMasterEncryptedKey;
|
||||
delete pClientReadKey;
|
||||
delete pServerReadKey;
|
||||
}
|
||||
|
||||
/*!
|
||||
* This method implements SSL_Interpreter::BuildInterpreterEndpoints()
|
||||
*/
|
||||
void SSLv2_Interpreter::BuildInterpreterEndpoints()
|
||||
{
|
||||
orig = new SSLv2_Endpoint(this, 1);
|
||||
resp = new SSLv2_Endpoint(this, 0);
|
||||
}
|
||||
|
||||
/*!
|
||||
* This method prints some counters.
|
||||
*/
|
||||
void SSLv2_Interpreter::printStats()
|
||||
{
|
||||
printf("SSLv2:\n");
|
||||
printf("totalConnections = %u\n", totalConnections);
|
||||
printf("analyzedConnections = %u\n", analyzedConnections);
|
||||
printf("openedConnections = %u\n", openedConnections);
|
||||
printf("failedConnections = %u\n", failedConnections);
|
||||
printf("weirdConnections = %u\n", weirdConnections);
|
||||
|
||||
printf("totalRecords = %u\n", totalRecords);
|
||||
printf("clientHelloRecords = %u\n", clientHelloRecords);
|
||||
printf("serverHelloRecords = %u\n", serverHelloRecords);
|
||||
printf("clientMasterKeyRecords = %u\n", clientMasterKeyRecords);
|
||||
printf("errorRecords = %u\n", errorRecords);
|
||||
|
||||
printf("SSL_RecordBuilder::maxAllocCount = %u\n", SSL_RecordBuilder::maxAllocCount);
|
||||
printf("SSL_RecordBuilder::maxFragmentCount = %u\n", SSL_RecordBuilder::maxFragmentCount);
|
||||
printf("SSL_RecordBuilder::fragmentedHeaders = %u\n", SSL_RecordBuilder::fragmentedHeaders);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \return the current state of the ssl connection
|
||||
*/
|
||||
SSLv2_States SSLv2_Interpreter::ConnState()
|
||||
{
|
||||
return connState;
|
||||
}
|
||||
|
||||
/*!
|
||||
* This method is called by SSLv2_Endpoint::Deliver(). It is the main entry
|
||||
* point of this class. The header of the given SSLV2 record is analyzed and
|
||||
* its contents are then passed to the corresponding analyzer method. After
|
||||
* the record has been analyzed, the ssl connection state is updated.
|
||||
*
|
||||
* \param s Pointer to the endpoint which sent the record
|
||||
* \param length length of SSLv2 record
|
||||
* \param data pointer to SSLv2 record to analyze
|
||||
*/
|
||||
void SSLv2_Interpreter::NewSSLRecord(SSL_InterpreterEndpoint* s,
|
||||
int length, const u_char* data)
|
||||
{
|
||||
++records;
|
||||
++totalRecords;
|
||||
|
||||
if ( ! bAnalyzedCounted )
|
||||
{
|
||||
++analyzedConnections;
|
||||
bAnalyzedCounted = true;
|
||||
}
|
||||
|
||||
// We should see a maximum of 4 cleartext records.
|
||||
if ( records == 5 )
|
||||
{ // so this should never happen
|
||||
Weird("SSLv2: Saw more than 4 records, skipping connection...");
|
||||
proxy->SetSkip(1);
|
||||
return;
|
||||
}
|
||||
|
||||
// SSLv2 record header analysis
|
||||
uint32 recordLength = 0; // data length of SSLv2 record
|
||||
bool isEscape = false;
|
||||
uint8 padding = 0;
|
||||
const u_char* contents;
|
||||
|
||||
if ( (data[0] & 0x80) > 0 )
|
||||
{ // we have a two-byte record header
|
||||
recordLength = ((data[0] & 0x7f) << 8) | data[1];
|
||||
contents = data + 2;
|
||||
if ( recordLength + 2 != uint32(length) )
|
||||
{
|
||||
// This should never happen, otherwise
|
||||
// we have a bug in the SSL_RecordBuilder.
|
||||
Weird("SSLv2: FATAL: recordLength doesn't match data block length!");
|
||||
connState = ERROR_REQUIRED;
|
||||
proxy->SetSkip(1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // We have a three-byte record header.
|
||||
recordLength = ((data[0] & 0x3f) << 8) | data[1];
|
||||
isEscape = (data[0] & 0x40) != 0;
|
||||
padding = data[2];
|
||||
contents = data + 3;
|
||||
if ( recordLength + 3 != uint32(length) )
|
||||
{
|
||||
// This should never happen, otherwise
|
||||
// we have a bug in the SSL_RecordBuilder.
|
||||
Weird("SSLv2: FATAL: recordLength doesn't match data block length!");
|
||||
connState = ERROR_REQUIRED;
|
||||
proxy->SetSkip(1);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( padding == 0 && ! isEscape )
|
||||
Weird("SSLv2: 3 Byte record header, but no escape, no padding!");
|
||||
}
|
||||
|
||||
if ( recordLength == 0 )
|
||||
{
|
||||
Weird("SSLv2: Record length is zero (no record data)!");
|
||||
return;
|
||||
}
|
||||
|
||||
if ( isEscape )
|
||||
Weird("SSLv2: Record has escape bit set (security escape)!");
|
||||
|
||||
if ( padding > 0 && connState != CACHED_SESSION &&
|
||||
connState != CLIENT_MASTERKEY_SEEN )
|
||||
Weird("SSLv2 record with padding > 0 in cleartext!");
|
||||
|
||||
// MISSING:
|
||||
// A final consistency check is done when a block cipher is used
|
||||
// and the protocol is using encryption. The amount of data present
|
||||
// in a record (RECORD-LENGTH))must be a multiple of the cipher's
|
||||
// block size. If the received record is not a multiple of the
|
||||
// cipher's block size then the record is considered damaged, and it
|
||||
// is to be treated as if an "I/O Error" had occurred (i.e. an
|
||||
// unrecoverable error is asserted and the connection is closed).
|
||||
|
||||
switch ( connState ) {
|
||||
case START:
|
||||
// Only CLIENT-HELLLOs allowed here.
|
||||
if ( contents[0] != SSLv2_MT_CLIENT_HELLO )
|
||||
{
|
||||
Weird("SSLv2: First packet is not a CLIENT-HELLO!");
|
||||
analyzeRecord(s, recordLength, contents);
|
||||
connState = ERROR_REQUIRED;
|
||||
}
|
||||
else
|
||||
connState = ClientHelloRecord(s, recordLength, contents);
|
||||
break;
|
||||
|
||||
case CLIENT_HELLO_SEEN:
|
||||
// Only SERVER-HELLOs or ERRORs allowed here.
|
||||
if ( contents[0] == SSLv2_MT_SERVER_HELLO )
|
||||
connState = ServerHelloRecord(s, recordLength, contents);
|
||||
else if ( contents[0] == SSLv2_MT_ERROR )
|
||||
connState = ErrorRecord(s, recordLength, contents);
|
||||
else
|
||||
{
|
||||
Weird("SSLv2: State violation in CLIENT_HELLO_SEEN!");
|
||||
analyzeRecord(s, recordLength, contents);
|
||||
connState = ERROR_REQUIRED;
|
||||
}
|
||||
break;
|
||||
|
||||
case NEW_SESSION:
|
||||
// We expect a client master key.
|
||||
if ( contents[0] == SSLv2_MT_CLIENT_MASTER_KEY )
|
||||
connState = ClientMasterKeyRecord(s, recordLength, contents);
|
||||
else if ( contents[0] == SSLv2_MT_ERROR )
|
||||
connState = ErrorRecord(s, recordLength, contents);
|
||||
else
|
||||
{
|
||||
Weird("SSLv2: State violation in NEW_SESSION or encrypted record!");
|
||||
analyzeRecord(s, recordLength, contents);
|
||||
connState = ERROR_REQUIRED;
|
||||
}
|
||||
|
||||
delete pServerCipherSpecs;
|
||||
pServerCipherSpecs = 0;
|
||||
break;
|
||||
|
||||
case CACHED_SESSION:
|
||||
delete pServerCipherSpecs;
|
||||
pServerCipherSpecs = 0;
|
||||
// No break here.
|
||||
|
||||
case CLIENT_MASTERKEY_SEEN:
|
||||
// If no error record, no further analysis.
|
||||
if ( contents[0] == SSLv2_MT_ERROR &&
|
||||
recordLength == SSLv2_ERROR_RECORD_SIZE )
|
||||
connState = ErrorRecord(s, recordLength, contents);
|
||||
else
|
||||
{
|
||||
// So we finished the cleartext handshake.
|
||||
// Skip all further data.
|
||||
|
||||
proxy->SetSkip(1);
|
||||
++openedConnections;
|
||||
}
|
||||
break;
|
||||
|
||||
case ERROR_REQUIRED:
|
||||
if ( contents[0] == SSLv2_MT_ERROR )
|
||||
connState = ErrorRecord(s, recordLength, contents);
|
||||
else
|
||||
{
|
||||
// We lost tracking: this should not happen.
|
||||
Weird("SSLv2: State inconsistency in ERROR_REQUIRED (lost tracking!)!");
|
||||
analyzeRecord(s, recordLength, contents);
|
||||
connState = ERROR_REQUIRED;
|
||||
}
|
||||
break;
|
||||
|
||||
case ERROR_SEEN:
|
||||
// We don't have recoverable errors in cleartext phase,
|
||||
// so we shouldn't see anymore packets.
|
||||
Weird("SSLv2: Traffic after error record!");
|
||||
analyzeRecord(s, recordLength, contents);
|
||||
break;
|
||||
|
||||
default:
|
||||
reporter->InternalError("SSLv2: unknown state");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* This method is called whenever the connection tracking failed. It calls
|
||||
* the corresponding analyzer method for the given SSLv2 record, but does not
|
||||
* update the ssl connection state.
|
||||
*
|
||||
* \param s Pointer to the endpoint which sent the record
|
||||
* \param length length of SSLv2 record
|
||||
* \param data pointer to SSLv2 record to analyze
|
||||
*/
|
||||
void SSLv2_Interpreter::analyzeRecord(SSL_InterpreterEndpoint* s,
|
||||
int length, const u_char* data)
|
||||
{
|
||||
switch ( data[0] ) {
|
||||
case SSLv2_MT_ERROR:
|
||||
ErrorRecord(s, length, data);
|
||||
break;
|
||||
|
||||
case SSLv2_MT_CLIENT_HELLO:
|
||||
ClientHelloRecord(s, length, data);
|
||||
break;
|
||||
|
||||
case SSLv2_MT_CLIENT_MASTER_KEY:
|
||||
ClientMasterKeyRecord(s, length, data);
|
||||
break;
|
||||
|
||||
case SSLv2_MT_SERVER_HELLO:
|
||||
ServerHelloRecord(s, length, data);
|
||||
break;
|
||||
|
||||
case SSLv2_MT_CLIENT_FINISHED:
|
||||
case SSLv2_MT_SERVER_VERIFY:
|
||||
case SSLv2_MT_SERVER_FINISHED:
|
||||
case SSLv2_MT_REQUEST_CERTIFICATE:
|
||||
case SSLv2_MT_CLIENT_CERTIFICATE:
|
||||
Weird("SSLv2: Encrypted record type seems to be in cleartext");
|
||||
break;
|
||||
|
||||
default:
|
||||
// Unknown record type.
|
||||
Weird("SSLv2: Unknown record type or encrypted record");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* This method analyses a SSLv2 CLIENT-HELLO record.
|
||||
*
|
||||
* \param s Pointer to the endpoint which sent the record
|
||||
* \param length length of SSLv2 CLIENT-HELLO record
|
||||
* \param data pointer to SSLv2 CLIENT-HELLO record to analyze
|
||||
*
|
||||
* \return the updated state of the current ssl connection
|
||||
*/
|
||||
SSLv2_States SSLv2_Interpreter::ClientHelloRecord(SSL_InterpreterEndpoint* s,
|
||||
int recordLength, const u_char* recordData)
|
||||
{
|
||||
// This method gets the record's data (without the header).
|
||||
++clientHelloRecords;
|
||||
|
||||
if ( s != orig )
|
||||
Weird("SSLv2: CLIENT-HELLO record from server!");
|
||||
|
||||
// There should not be any pending data in the SSLv2 reassembler,
|
||||
// because the client should wait for a server response.
|
||||
if ( ((SSLv2_Endpoint*) s)->isDataPending() )
|
||||
Weird("SSLv2: Pending data in SSL_RecordBuilder after CLIENT-HELLO!");
|
||||
|
||||
// Client hello minimum header size check.
|
||||
if ( recordLength < SSLv2_CLIENT_HELLO_HEADER_SIZE )
|
||||
{
|
||||
Weird("SSLv2: CLIENT-HELLO is too small!");
|
||||
return ERROR_REQUIRED;
|
||||
}
|
||||
|
||||
// Extract the data of the client hello header.
|
||||
SSLv2_ClientHelloHeader ch;
|
||||
ch.clientVersion = uint16(recordData[1] << 8) | recordData[2];
|
||||
ch.cipherSpecLength = uint16(recordData[3] << 8) | recordData[4];
|
||||
ch.sessionIdLength = uint16(recordData[5] << 8) | recordData[6];
|
||||
ch.challengeLength = uint16(recordData[7] << 8) | recordData[8];
|
||||
|
||||
if ( ch.clientVersion != SSLProxy_Analyzer::SSLv20 &&
|
||||
ch.clientVersion != SSLProxy_Analyzer::SSLv30 &&
|
||||
ch.clientVersion != SSLProxy_Analyzer::SSLv31 )
|
||||
{
|
||||
Weird("SSLv2: Unsupported SSL-Version in CLIENT-HELLO");
|
||||
return ERROR_REQUIRED;
|
||||
}
|
||||
|
||||
if ( ch.challengeLength + ch.cipherSpecLength + ch.sessionIdLength +
|
||||
SSLv2_CLIENT_HELLO_HEADER_SIZE != recordLength )
|
||||
{
|
||||
Weird("SSLv2: Size inconsistency in CLIENT-HELLO");
|
||||
return ERROR_REQUIRED;
|
||||
}
|
||||
|
||||
// The CIPHER-SPECS-LENGTH must be > 0 and a multiple of 3.
|
||||
if ( ch.cipherSpecLength == 0 || ch.cipherSpecLength % 3 != 0 )
|
||||
{
|
||||
Weird("SSLv2: Nonconform CIPHER-SPECS-LENGTH in CLIENT-HELLO.");
|
||||
return ERROR_REQUIRED;
|
||||
}
|
||||
|
||||
// The SESSION-ID-LENGTH must either be zero or 16.
|
||||
if ( ch.sessionIdLength != 0 && ch.sessionIdLength != 16 )
|
||||
Weird("SSLv2: Nonconform SESSION-ID-LENGTH in CLIENT-HELLO.");
|
||||
|
||||
if ( (ch.challengeLength < 16) || (ch.challengeLength > 32))
|
||||
Weird("SSLv2: Nonconform CHALLENGE-LENGTH in CLIENT-HELLO.");
|
||||
|
||||
const u_char* ptr = recordData;
|
||||
ptr += SSLv2_CLIENT_HELLO_HEADER_SIZE + ch.cipherSpecLength;
|
||||
|
||||
pSessionId = new SSL_DataBlock(ptr, ch.sessionIdLength);
|
||||
|
||||
// If decrypting, store the challenge.
|
||||
if ( ssl_store_key_material && ch.challengeLength <= 32 )
|
||||
pChallenge = new SSL_DataBlock(ptr, ch.challengeLength);
|
||||
|
||||
bClientWantsCachedSession = ch.sessionIdLength != 0;
|
||||
|
||||
TableVal* currentCipherSuites =
|
||||
analyzeCiphers(s, ch.cipherSpecLength,
|
||||
recordData + SSLv2_CLIENT_HELLO_HEADER_SIZE);
|
||||
|
||||
fire_ssl_conn_attempt(ch.clientVersion, currentCipherSuites);
|
||||
|
||||
return CLIENT_HELLO_SEEN;
|
||||
}
|
||||
|
||||
/*!
|
||||
* This method analyses a SSLv2 SERVER-HELLO record.
|
||||
*
|
||||
* \param s Pointer to the endpoint which sent the record
|
||||
* \param length length of SSLv2 SERVER-HELLO record
|
||||
* \param data pointer to SSLv2 SERVER-HELLO record to analyze
|
||||
*
|
||||
* \return the updated state of the current ssl connection
|
||||
*/
|
||||
SSLv2_States SSLv2_Interpreter::ServerHelloRecord(SSL_InterpreterEndpoint* s,
|
||||
int recordLength, const u_char* recordData)
|
||||
{
|
||||
++serverHelloRecords;
|
||||
TableVal* currentCipherSuites = NULL;
|
||||
|
||||
if ( s != resp )
|
||||
Weird("SSLv2: SERVER-HELLO from client!");
|
||||
|
||||
if ( recordLength < SSLv2_SERVER_HELLO_HEADER_SIZE )
|
||||
{
|
||||
Weird("SSLv2: SERVER-HELLO is too small!");
|
||||
return ERROR_REQUIRED;
|
||||
}
|
||||
|
||||
// Extract the data of the client hello header.
|
||||
SSLv2_ServerHelloHeader sh;
|
||||
sh.sessionIdHit = recordData[1];
|
||||
sh.certificateType = recordData[2];
|
||||
sh.serverVersion = uint16(recordData[3] << 8) | recordData[4];
|
||||
sh.certificateLength = uint16(recordData[5] << 8) | recordData[6];
|
||||
sh.cipherSpecLength = uint16(recordData[7] << 8) | recordData[8];
|
||||
sh.connectionIdLength = uint16(recordData[9] << 8) | recordData[10];
|
||||
|
||||
if ( sh.serverVersion != SSLProxy_Analyzer::SSLv20 )
|
||||
{
|
||||
Weird("SSLv2: Unsupported SSL-Version in SERVER-HELLO");
|
||||
return ERROR_REQUIRED;
|
||||
}
|
||||
|
||||
if ( sh.certificateLength + sh.cipherSpecLength +
|
||||
sh.connectionIdLength +
|
||||
SSLv2_SERVER_HELLO_HEADER_SIZE != recordLength )
|
||||
{
|
||||
Weird("SSLv2: Size inconsistency in SERVER-HELLO");
|
||||
return ERROR_REQUIRED;
|
||||
}
|
||||
|
||||
// The length of the CONNECTION-ID must be between 16 and 32 bytes.
|
||||
if ( sh.connectionIdLength < 16 || sh.connectionIdLength > 32 )
|
||||
Weird("SSLv2: Nonconform CONNECTION-ID-LENGTH in SERVER-HELLO");
|
||||
|
||||
// If decrypting, store the connection ID.
|
||||
if ( ssl_store_key_material && sh.connectionIdLength <= 32 )
|
||||
{
|
||||
const u_char* ptr = recordData;
|
||||
|
||||
ptr += SSLv2_SERVER_HELLO_HEADER_SIZE + sh.cipherSpecLength +
|
||||
sh.certificateLength;
|
||||
|
||||
pConnectionId = new SSL_DataBlock(ptr, sh.connectionIdLength);
|
||||
}
|
||||
|
||||
if ( sh.sessionIdHit == 0 )
|
||||
{
|
||||
// Generating reusing-connection event.
|
||||
EventHandlerPtr event = ssl_session_insertion;
|
||||
|
||||
if ( event )
|
||||
{
|
||||
TableVal* sessionIDTable =
|
||||
MakeSessionID(
|
||||
recordData +
|
||||
SSLv2_SERVER_HELLO_HEADER_SIZE +
|
||||
sh.certificateLength +
|
||||
sh.cipherSpecLength,
|
||||
sh.connectionIdLength);
|
||||
|
||||
val_list* vl = new val_list;
|
||||
vl->append(proxy->BuildConnVal());
|
||||
vl->append(sessionIDTable);
|
||||
|
||||
proxy->ConnectionEvent(ssl_session_insertion, vl);
|
||||
}
|
||||
}
|
||||
|
||||
SSLv2_States nextState;
|
||||
|
||||
if ( sh.sessionIdHit != 0 )
|
||||
{ // we're using a cached session
|
||||
|
||||
// There should not be any pending data in the SSLv2
|
||||
// reassembler, because the server should wait for a
|
||||
// client response.
|
||||
if ( ((SSLv2_Endpoint*) s)->isDataPending() )
|
||||
{
|
||||
// But turns out some SSL Implementations do this
|
||||
// when using a cached session.
|
||||
}
|
||||
|
||||
// Consistency check for SESSION-ID-HIT.
|
||||
if ( ! bClientWantsCachedSession )
|
||||
Weird("SSLv2: SESSION-ID hit in SERVER-HELLO, but no SESSION-ID in CLIENT-HELLO!");
|
||||
|
||||
// If the SESSION-ID-HIT flag is non-zero then the
|
||||
// CERTIFICATE-TYPE, CERTIFICATE-LENGTH and
|
||||
// CIPHER-SPECS-LENGTH fields will be zero.
|
||||
if ( sh.certificateType != 0 || sh.certificateLength != 0 ||
|
||||
sh.cipherSpecLength != 0 )
|
||||
Weird("SSLv2: SESSION-ID-HIT, but session data in SERVER-HELLO");
|
||||
|
||||
// Generate reusing-connection event.
|
||||
if ( pSessionId )
|
||||
{
|
||||
fire_ssl_conn_reused(pSessionId);
|
||||
delete pSessionId;
|
||||
pSessionId = 0;
|
||||
}
|
||||
|
||||
nextState = CACHED_SESSION;
|
||||
}
|
||||
else
|
||||
{ // we're starting a new session
|
||||
|
||||
// There should not be any pending data in the SSLv2
|
||||
// reassembler, because the server should wait for
|
||||
// a client response.
|
||||
if ( ((SSLv2_Endpoint*) s)->isDataPending() )
|
||||
Weird("SSLv2: Pending data in SSL_RecordBuilder after SERVER-HELLO (new session)!");
|
||||
|
||||
// TODO: check certificate length ???
|
||||
if ( sh.certificateLength == 0 )
|
||||
Weird("SSLv2: No certificate in SERVER-HELLO!");
|
||||
|
||||
// The CIPHER-SPECS-LENGTH must be > zero and a multiple of 3.
|
||||
if ( sh.cipherSpecLength == 0 )
|
||||
Weird("SSLv2: No CIPHER-SPECS in SERVER-HELLO!");
|
||||
|
||||
if ( sh.cipherSpecLength % 3 != 0 )
|
||||
{
|
||||
Weird("SSLv2: Nonconform CIPHER-SPECS-LENGTH in SERVER-HELLO");
|
||||
return ERROR_REQUIRED;
|
||||
}
|
||||
|
||||
const u_char* ptr = recordData;
|
||||
ptr += sh.certificateLength + SSLv2_SERVER_HELLO_HEADER_SIZE;
|
||||
currentCipherSuites = analyzeCiphers(s, sh.cipherSpecLength, ptr);
|
||||
|
||||
nextState = NEW_SESSION;
|
||||
}
|
||||
|
||||
// Check if at least one cipher is supported by the client.
|
||||
if ( pClientCipherSpecs && pServerCipherSpecs )
|
||||
{
|
||||
bool bFound = false;
|
||||
for ( int i = 0; i < pClientCipherSpecs->len; i += 3 )
|
||||
{
|
||||
for ( int j = 0; j < pServerCipherSpecs->len; j += 3 )
|
||||
{
|
||||
if ( memcmp(pClientCipherSpecs + i,
|
||||
pServerCipherSpecs + j, 3) == 0 )
|
||||
{
|
||||
bFound = true;
|
||||
i = pClientCipherSpecs->len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! bFound )
|
||||
{
|
||||
Weird("SSLv2: Client's and server's CIPHER-SPECS don't match!");
|
||||
nextState = ERROR_REQUIRED;
|
||||
}
|
||||
|
||||
delete pClientCipherSpecs;
|
||||
pClientCipherSpecs = 0;
|
||||
}
|
||||
|
||||
// Certificate analysis.
|
||||
if ( sh.certificateLength > 0 && ssl_analyze_certificates != 0 )
|
||||
{
|
||||
analyzeCertificate(s, recordData + SSLv2_SERVER_HELLO_HEADER_SIZE,
|
||||
sh.certificateLength, sh.certificateType, false);
|
||||
}
|
||||
|
||||
if ( nextState == NEW_SESSION )
|
||||
// generate server-reply event
|
||||
fire_ssl_conn_server_reply(sh.serverVersion, currentCipherSuites);
|
||||
|
||||
else if ( nextState == CACHED_SESSION )
|
||||
{ // generate server-reply event
|
||||
fire_ssl_conn_server_reply(sh.serverVersion, currentCipherSuites);
|
||||
// Generate a connection-established event with a dummy
|
||||
// cipher suite, since we can't remember session information
|
||||
// (yet).
|
||||
// Note: A new session identifier is sent encrypted in SSLv2!
|
||||
fire_ssl_conn_established(sh.serverVersion, 0xABCD);
|
||||
}
|
||||
else
|
||||
// Unref, since the table is not delivered to any event.
|
||||
Unref(currentCipherSuites);
|
||||
|
||||
return nextState;
|
||||
}
|
||||
|
||||
/*!
|
||||
* This method analyses a SSLv2 CLIENT-MASTER-KEY record.
|
||||
*
|
||||
* \param s Pointer to the endpoint which sent the record
|
||||
* \param length length of SSLv2 CLIENT-MASTER-KEY record
|
||||
* \param data pointer to SSLv2 CLIENT-MASTER-KEY record to analyze
|
||||
*
|
||||
* \return the updated state of the current ssl connection
|
||||
*/
|
||||
SSLv2_States SSLv2_Interpreter::
|
||||
ClientMasterKeyRecord(SSL_InterpreterEndpoint* s, int recordLength,
|
||||
const u_char* recordData)
|
||||
{
|
||||
++clientMasterKeyRecords;
|
||||
SSLv2_States nextState = CLIENT_MASTERKEY_SEEN;
|
||||
|
||||
if ( s != orig )
|
||||
Weird("SSLv2: CLIENT-MASTER-KEY from server!");
|
||||
|
||||
if ( recordLength < SSLv2_CLIENT_MASTER_KEY_HEADER_SIZE )
|
||||
{
|
||||
Weird("SSLv2: CLIENT-MASTER-KEY is too small!");
|
||||
return ERROR_REQUIRED;
|
||||
}
|
||||
|
||||
// Extract the data of the client master key header.
|
||||
SSLv2_ClientMasterKeyHeader cmk;
|
||||
cmk.cipherKind =
|
||||
((recordData[1] << 16) | recordData[2] << 8) | recordData[3];
|
||||
cmk.clearKeyLength = uint16(recordData[4] << 8) | recordData[5];
|
||||
cmk.encryptedKeyLength = uint16(recordData[6] << 8) | recordData[7];
|
||||
cmk.keyArgLength = uint16(recordData[8] << 8) | recordData[9];
|
||||
|
||||
if ( cmk.clearKeyLength + cmk.encryptedKeyLength + cmk.keyArgLength +
|
||||
SSLv2_CLIENT_MASTER_KEY_HEADER_SIZE != recordLength )
|
||||
{
|
||||
Weird("SSLv2: Size inconsistency in CLIENT-MASTER-KEY");
|
||||
return ERROR_REQUIRED;
|
||||
}
|
||||
|
||||
// Check if cipher is supported by the server.
|
||||
if ( pServerCipherSpecs )
|
||||
{
|
||||
bool bFound = false;
|
||||
for ( int i = 0; i < pServerCipherSpecs->len; i += 3 )
|
||||
{
|
||||
uint32 cipherSpec =
|
||||
((pServerCipherSpecs->data[i] << 16) |
|
||||
pServerCipherSpecs->data[i+1] << 8) |
|
||||
pServerCipherSpecs->data[i+2];
|
||||
|
||||
if ( cmk.cipherKind == cipherSpec )
|
||||
{
|
||||
bFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! bFound )
|
||||
{
|
||||
Weird("SSLv2: Client chooses unadvertised cipher in CLIENT-MASTER-KEY!");
|
||||
nextState = ERROR_REQUIRED;
|
||||
}
|
||||
else
|
||||
nextState = CLIENT_MASTERKEY_SEEN;
|
||||
|
||||
delete pServerCipherSpecs;
|
||||
pServerCipherSpecs = 0;
|
||||
}
|
||||
|
||||
// TODO: check if cipher has been advertised before.
|
||||
|
||||
SSL_CipherSpec* pCipherSpecTemp = 0;
|
||||
|
||||
HashKey h(static_cast<bro_uint_t>(cmk.cipherKind));
|
||||
pCipherSpecTemp = (SSL_CipherSpec*) SSL_CipherSpecDict.Lookup(&h);
|
||||
if ( ! pCipherSpecTemp || ! (pCipherSpecTemp->flags & SSL_FLAG_SSLv20) )
|
||||
Weird("SSLv2: Unknown CIPHER-SPEC in CLIENT-MASTER-KEY!");
|
||||
else
|
||||
{ // check for conistency of clearKeyLength
|
||||
if ( cmk.clearKeyLength * 8 != pCipherSpecTemp->clearKeySize )
|
||||
{
|
||||
Weird("SSLv2: Inconsistency of clearKeyLength in CLIENT-MASTER-KEY!");
|
||||
// nextState = ERROR_REQUIRED;
|
||||
}
|
||||
|
||||
// TODO: check for consistency of encryptedKeyLength.
|
||||
// TODO: check for consistency of keyArgLength.
|
||||
// switch ( cmk.cipherKind )
|
||||
// {
|
||||
// case SSL_CK_RC4_128_WITH_MD5:
|
||||
// case SSL_CK_RC4_128_EXPORT40_WITH_MD5:
|
||||
// if ( cmk.keyArgLength != 0 )
|
||||
// {
|
||||
// Weird("SSLv2: Inconsistency of keyArgLength in CLIENT-MASTER-KEY!");
|
||||
// //nextState = ERROR_REQUIRED;
|
||||
// }
|
||||
// break;
|
||||
// case SSL_CK_DES_64_CBC_WITH_MD5:
|
||||
// case SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5:
|
||||
// case SSL_CK_RC2_128_CBC_WITH_MD5:
|
||||
// case SSL_CK_IDEA_128_CBC_WITH_MD5:
|
||||
// case SSL_CK_DES_192_EDE3_CBC_WITH_MD5:
|
||||
// if ( cmk.keyArgLength != 8 )
|
||||
// {
|
||||
// Weird("SSLv2: Inconsistency of keyArgLength in CLIENT-MASTER-KEY!");
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
}
|
||||
|
||||
// Remember the used cipher spec.
|
||||
usedCipherSpec = SSLv2_CipherSpec(cmk.cipherKind);
|
||||
|
||||
// If decrypting, store the clear key part of the master key.
|
||||
if ( ssl_store_key_material /* && cmk.clearKeyLength == 11 */ )
|
||||
{
|
||||
pMasterClearKey =
|
||||
new SSL_DataBlock((recordData + SSLv2_CLIENT_MASTER_KEY_HEADER_SIZE), cmk.clearKeyLength);
|
||||
|
||||
pMasterEncryptedKey =
|
||||
new SSL_DataBlock((recordData + SSLv2_CLIENT_MASTER_KEY_HEADER_SIZE + cmk.clearKeyLength ), cmk.encryptedKeyLength);
|
||||
}
|
||||
|
||||
if ( nextState == CLIENT_MASTERKEY_SEEN )
|
||||
fire_ssl_conn_established(SSLProxy_Analyzer::SSLv20,
|
||||
cmk.cipherKind);
|
||||
|
||||
return nextState;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* This method analyses a SSLv2 ERROR record.
|
||||
*
|
||||
* \param s Pointer to the endpoint which sent the record
|
||||
* \param length length of SSLv2 ERROR record
|
||||
* \param data pointer to SSLv2 ERROR record to analyze
|
||||
*
|
||||
* \return the updated state of the current ssl connection
|
||||
*/
|
||||
SSLv2_States SSLv2_Interpreter::ErrorRecord(SSL_InterpreterEndpoint* s,
|
||||
int recordLength, const u_char* recordData)
|
||||
{
|
||||
++errorRecords;
|
||||
|
||||
if ( unsigned(recordLength) != SSLv2_ERROR_RECORD_SIZE )
|
||||
{
|
||||
Weird("SSLv2: Size mismatch in Error Record!");
|
||||
return ERROR_REQUIRED;
|
||||
}
|
||||
|
||||
SSLv2_ErrorRecord er;
|
||||
er.errorCode = (recordData[1] << 8) | recordData[2];
|
||||
SSL3x_AlertLevel al = SSL3x_AlertLevel(255);
|
||||
|
||||
switch ( er.errorCode ) {
|
||||
case SSLv2_PE_NO_CIPHER:
|
||||
// The client doesn't support a cipher which the server
|
||||
// supports. Only from client to server and not recoverable!
|
||||
al = SSL3x_ALERT_LEVEL_FATAL;
|
||||
break;
|
||||
|
||||
case SSLv2_PE_NO_CERTIFICATE:
|
||||
if ( s == orig )
|
||||
// from client to server: not recoverable
|
||||
al = SSL3x_ALERT_LEVEL_FATAL;
|
||||
else
|
||||
// from server to client: recoverable
|
||||
al = SSL3x_ALERT_LEVEL_WARNING;
|
||||
break;
|
||||
|
||||
case SSLv2_PE_BAD_CERTIFICATE:
|
||||
if ( s == orig )
|
||||
// from client to server: not recoverable
|
||||
al = SSL3x_ALERT_LEVEL_FATAL;
|
||||
else
|
||||
// from server to client: recoverable
|
||||
al = SSL3x_ALERT_LEVEL_WARNING;
|
||||
break;
|
||||
|
||||
case SSLv2_PE_UNSUPPORTED_CERTIFICATE_TYPE:
|
||||
if ( s == orig )
|
||||
// from client to server: not recoverable
|
||||
al = SSL3x_ALERT_LEVEL_FATAL;
|
||||
else
|
||||
// from server to client: recoverable
|
||||
al = SSL3x_ALERT_LEVEL_WARNING;
|
||||
break;
|
||||
|
||||
default:
|
||||
al = SSL3x_ALERT_LEVEL_FATAL;
|
||||
break;
|
||||
}
|
||||
|
||||
fire_ssl_conn_alert(SSLProxy_Analyzer::SSLv20, al, er.errorCode);
|
||||
|
||||
return ERROR_SEEN;
|
||||
}
|
||||
|
||||
/*!
|
||||
* This method analyses a set of SSLv2 cipher suites.
|
||||
*
|
||||
* \param s Pointer to the endpoint which sent the cipher suites
|
||||
* \param length length of cipher suites
|
||||
* \param data pointer to cipher suites to analyze
|
||||
*
|
||||
* \return a pointer to a Bro TableVal (of type cipher_suites_list) which contains
|
||||
* the cipher suites list of the current analyzed record
|
||||
*/
|
||||
TableVal* SSLv2_Interpreter::analyzeCiphers(SSL_InterpreterEndpoint* s,
|
||||
int length, const u_char* data)
|
||||
{
|
||||
if ( length > MAX_CIPHERSPEC_SIZE )
|
||||
{
|
||||
if ( s == orig )
|
||||
Weird("SSLv2: Client has CipherSpecs > MAX_CIPHERSPEC_SIZE");
|
||||
else
|
||||
Weird("SSLv2: Server has CipherSpecs > MAX_CIPHERSPEC_SIZE");
|
||||
}
|
||||
else
|
||||
{ // cipher specs are not too big
|
||||
if ( ssl_compare_cipherspecs )
|
||||
{ // store cipher specs for state analysis
|
||||
if ( s == resp )
|
||||
pServerCipherSpecs =
|
||||
new SSL_DataBlock(data, length);
|
||||
else
|
||||
pClientCipherSpecs =
|
||||
new SSL_DataBlock(data, length);
|
||||
}
|
||||
}
|
||||
|
||||
const u_char* pCipher = data;
|
||||
bool bExtractCipherSuite = false;
|
||||
TableVal* pCipherTable = 0;
|
||||
|
||||
// We only extract the cipher suite when the corresponding
|
||||
// ssl events are defined (otherwise we do work for nothing
|
||||
// and suffer a memory leak).
|
||||
// FIXME: This check needs to be done only once!
|
||||
if ( (s == orig && ssl_conn_attempt) ||
|
||||
(s == resp && ssl_conn_server_reply) )
|
||||
{
|
||||
pCipherTable = new TableVal(cipher_suites_list);
|
||||
bExtractCipherSuite = true;
|
||||
}
|
||||
|
||||
for ( int i = 0; i < length; i += 3 )
|
||||
{
|
||||
SSL_CipherSpec* pCurrentCipherSpec;
|
||||
uint32 cipherSpecID =
|
||||
((pCipher[0] << 16) | pCipher[1] << 8) | pCipher[2];
|
||||
|
||||
// Check for unknown cipher specs.
|
||||
HashKey h(static_cast<bro_uint_t>(cipherSpecID));
|
||||
pCurrentCipherSpec =
|
||||
(SSL_CipherSpec*) SSL_CipherSpecDict.Lookup(&h);
|
||||
|
||||
if ( ! pCurrentCipherSpec )
|
||||
{
|
||||
if ( s == orig )
|
||||
Weird("SSLv2: Unknown CIPHER-SPEC in CLIENT-HELLO!");
|
||||
else
|
||||
Weird("SSLv2: Unknown CIPHER-SPEC in SERVER-HELLO!");
|
||||
}
|
||||
|
||||
if ( bExtractCipherSuite )
|
||||
{
|
||||
Val* index = new Val(cipherSpecID, TYPE_COUNT);
|
||||
pCipherTable->Assign(index, 0);
|
||||
Unref(index);
|
||||
}
|
||||
|
||||
pCipher += 3;
|
||||
}
|
||||
|
||||
return pCipherTable;
|
||||
}
|
||||
|
||||
// --- SSLv2_EndPoint ---------------------------------------------------------
|
||||
|
||||
/*!
|
||||
* The constructor.
|
||||
*
|
||||
* \param interpreter Pointer to the SSLv2 interpreter to whom this endpoint belongs to
|
||||
* \param is_orig true if this is the originating endpoint of the ssl connection,
|
||||
* false otherwise
|
||||
*/
|
||||
SSLv2_Endpoint::SSLv2_Endpoint(SSLv2_Interpreter* interpreter, int is_orig)
|
||||
: SSL_InterpreterEndpoint(interpreter, is_orig)
|
||||
{
|
||||
sentRecords = 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* The destructor.
|
||||
*/
|
||||
SSLv2_Endpoint::~SSLv2_Endpoint()
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* This method is called by the SSLProxy_Analyzer with a complete reassembled
|
||||
* SSLv2 record. It passes the record to SSLv2_Interpreter::NewSSLRecord().
|
||||
*
|
||||
* \param t <b>reserved</b> (always zero)
|
||||
* \param seq <b>reserved</b> (always zero)
|
||||
* \param len length of the data block containing the ssl record
|
||||
* \param data pointer to the data block containing the ssl record
|
||||
*/
|
||||
void SSLv2_Endpoint::Deliver(int len, const u_char* data)
|
||||
{
|
||||
++((SSLv2_Endpoint*)peer)->sentRecords;
|
||||
|
||||
((SSLv2_Interpreter*)interpreter)->NewSSLRecord(this, len, data);
|
||||
}
|
|
@ -121,7 +121,7 @@ protected:
|
|||
|
||||
// This will be increased whenever there is an incompatible change
|
||||
// in the data format.
|
||||
static const uint32 DATA_FORMAT_VERSION = 20;
|
||||
static const uint32 DATA_FORMAT_VERSION = 21;
|
||||
|
||||
ChunkedIO* io;
|
||||
|
||||
|
|
154
src/Type.cc
154
src/Type.cc
|
@ -876,74 +876,12 @@ void CommentedTypeDecl::DescribeReST(ODesc* d) const
|
|||
}
|
||||
}
|
||||
|
||||
RecordField::RecordField(int arg_base, int arg_offset, int arg_total_offset)
|
||||
{
|
||||
base = arg_base;
|
||||
offset = arg_offset;
|
||||
total_offset = arg_total_offset;
|
||||
}
|
||||
|
||||
RecordType::RecordType(type_decl_list* arg_types) : BroType(TYPE_RECORD)
|
||||
{
|
||||
types = arg_types;
|
||||
base = 0;
|
||||
fields = 0;
|
||||
num_fields = types ? types->length() : 0;
|
||||
}
|
||||
|
||||
RecordType::RecordType(TypeList* arg_base, type_decl_list* refinements)
|
||||
: BroType(TYPE_RECORD)
|
||||
{
|
||||
if ( refinements )
|
||||
arg_base->Append(new RecordType(refinements));
|
||||
|
||||
Init(arg_base);
|
||||
}
|
||||
|
||||
void RecordType::Init(TypeList* arg_base)
|
||||
{
|
||||
assert(false); // Is this ever used?
|
||||
|
||||
base = arg_base;
|
||||
|
||||
if ( ! base )
|
||||
Internal("empty RecordType");
|
||||
|
||||
fields = new PDict(RecordField)(ORDERED);
|
||||
types = 0;
|
||||
|
||||
type_list* t = base->Types();
|
||||
|
||||
loop_over_list(*t, i)
|
||||
{
|
||||
BroType* ti = (*t)[i];
|
||||
|
||||
if ( ti->Tag() != TYPE_RECORD )
|
||||
(*t)[i]->Error("non-record in base type list");
|
||||
|
||||
RecordType* rti = ti->AsRecordType();
|
||||
int n = rti->NumFields();
|
||||
|
||||
for ( int j = 0; j < n; ++j )
|
||||
{
|
||||
const TypeDecl* tdij = rti->FieldDecl(j);
|
||||
|
||||
if ( fields->Lookup(tdij->id) )
|
||||
{
|
||||
reporter->Error("duplicate field %s", tdij->id);
|
||||
continue;
|
||||
}
|
||||
|
||||
RecordField* rf = new RecordField(i, j, fields->Length());
|
||||
|
||||
if ( fields->Insert(tdij->id, rf) )
|
||||
Internal("duplicate field when constructing record");
|
||||
}
|
||||
}
|
||||
|
||||
num_fields = fields->Length();
|
||||
}
|
||||
|
||||
RecordType::~RecordType()
|
||||
{
|
||||
if ( types )
|
||||
|
@ -953,9 +891,6 @@ RecordType::~RecordType()
|
|||
|
||||
delete types;
|
||||
}
|
||||
|
||||
delete fields;
|
||||
Unref(base);
|
||||
}
|
||||
|
||||
int RecordType::HasField(const char* field) const
|
||||
|
@ -971,17 +906,7 @@ BroType* RecordType::FieldType(const char* field) const
|
|||
|
||||
BroType* RecordType::FieldType(int field) const
|
||||
{
|
||||
if ( types )
|
||||
return (*types)[field]->type;
|
||||
else
|
||||
{
|
||||
RecordField* rf = fields->NthEntry(field);
|
||||
if ( ! rf )
|
||||
Internal("missing field in RecordType::FieldType");
|
||||
BroType* bt = (*base->Types())[rf->base];
|
||||
RecordType* rbt = bt->AsRecordType();
|
||||
return rbt->FieldType(rf->offset);
|
||||
}
|
||||
return (*types)[field]->type;
|
||||
}
|
||||
|
||||
Val* RecordType::FieldDefault(int field) const
|
||||
|
@ -998,26 +923,14 @@ Val* RecordType::FieldDefault(int field) const
|
|||
|
||||
int RecordType::FieldOffset(const char* field) const
|
||||
{
|
||||
if ( types )
|
||||
loop_over_list(*types, i)
|
||||
{
|
||||
loop_over_list(*types, i)
|
||||
{
|
||||
TypeDecl* td = (*types)[i];
|
||||
if ( streq(td->id, field) )
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
TypeDecl* td = (*types)[i];
|
||||
if ( streq(td->id, field) )
|
||||
return i;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
RecordField* rf = fields->Lookup(field);
|
||||
if ( ! rf )
|
||||
return -1;
|
||||
else
|
||||
return rf->total_offset;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char* RecordType::FieldName(int field) const
|
||||
|
@ -1027,33 +940,12 @@ const char* RecordType::FieldName(int field) const
|
|||
|
||||
const TypeDecl* RecordType::FieldDecl(int field) const
|
||||
{
|
||||
if ( types )
|
||||
return (*types)[field];
|
||||
else
|
||||
{
|
||||
RecordField* rf = fields->NthEntry(field);
|
||||
if ( ! rf )
|
||||
reporter->InternalError("missing field in RecordType::FieldDecl");
|
||||
|
||||
BroType* bt = (*base->Types())[rf->base];
|
||||
RecordType* rbt = bt->AsRecordType();
|
||||
return rbt->FieldDecl(rf->offset);
|
||||
}
|
||||
return (*types)[field];
|
||||
}
|
||||
|
||||
TypeDecl* RecordType::FieldDecl(int field)
|
||||
{
|
||||
if ( types )
|
||||
return (*types)[field];
|
||||
else
|
||||
{
|
||||
RecordField* rf = fields->NthEntry(field);
|
||||
if ( ! rf )
|
||||
Internal("missing field in RecordType::FieldDecl");
|
||||
BroType* bt = (*base->Types())[rf->base];
|
||||
RecordType* rbt = bt->AsRecordType();
|
||||
return rbt->FieldDecl(rf->offset);
|
||||
}
|
||||
return (*types)[field];
|
||||
}
|
||||
|
||||
void RecordType::Describe(ODesc* d) const
|
||||
|
@ -1151,11 +1043,6 @@ void RecordType::DescribeFields(ODesc* d) const
|
|||
d->SP();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
d->AddCount(1);
|
||||
base->Describe(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1208,9 +1095,6 @@ bool RecordType::DoSerialize(SerialInfo* info) const
|
|||
else if ( ! SERIALIZE(false) )
|
||||
return false;
|
||||
|
||||
SERIALIZE_OPTIONAL(base);
|
||||
|
||||
// We don't serialize the fields as we can reconstruct them.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1245,13 +1129,6 @@ bool RecordType::DoUnserialize(UnserialInfo* info)
|
|||
else
|
||||
types = 0;
|
||||
|
||||
BroType* type;
|
||||
UNSERIALIZE_OPTIONAL(type, BroType::Unserialize(info, TYPE_LIST));
|
||||
base = (TypeList*) type;
|
||||
|
||||
if ( base )
|
||||
Init(base);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1594,21 +1471,6 @@ bool VectorType::DoUnserialize(UnserialInfo* info)
|
|||
return yield_type != 0;
|
||||
}
|
||||
|
||||
BroType* refine_type(TypeList* base, type_decl_list* refinements)
|
||||
{
|
||||
type_list* t = base->Types();
|
||||
|
||||
if ( t->length() == 1 && ! refinements )
|
||||
{ // Just a direct reference to a single type.
|
||||
BroType* rt = (*t)[0]->Ref();
|
||||
Unref(base);
|
||||
return rt;
|
||||
}
|
||||
|
||||
return new RecordType(base, refinements);
|
||||
}
|
||||
|
||||
|
||||
BroType* base_type(TypeTag tag)
|
||||
{
|
||||
static BroType* base_types[NUM_TYPES];
|
||||
|
|
21
src/Type.h
21
src/Type.h
|
@ -426,20 +426,9 @@ public:
|
|||
std::list<std::string>* comments;
|
||||
};
|
||||
|
||||
class RecordField {
|
||||
public:
|
||||
RecordField(int arg_base, int arg_offset, int arg_total_offset);
|
||||
|
||||
int base; // which base element it belongs to
|
||||
int offset; // where it is in that base
|
||||
int total_offset; // where it is in the aggregate record
|
||||
};
|
||||
declare(PDict,RecordField);
|
||||
|
||||
class RecordType : public BroType {
|
||||
public:
|
||||
RecordType(type_decl_list* types);
|
||||
RecordType(TypeList* base, type_decl_list* refinements);
|
||||
|
||||
~RecordType();
|
||||
|
||||
|
@ -473,15 +462,11 @@ public:
|
|||
void DescribeFieldsReST(ODesc* d, bool func_args) const;
|
||||
|
||||
protected:
|
||||
RecordType() { fields = 0; base = 0; types = 0; }
|
||||
|
||||
void Init(TypeList* arg_base);
|
||||
RecordType() { types = 0; }
|
||||
|
||||
DECLARE_SERIAL(RecordType)
|
||||
|
||||
int num_fields;
|
||||
PDict(RecordField)* fields;
|
||||
TypeList* base;
|
||||
type_decl_list* types;
|
||||
};
|
||||
|
||||
|
@ -587,10 +572,6 @@ protected:
|
|||
BroType* yield_type;
|
||||
};
|
||||
|
||||
|
||||
// Returns the given type refinement, or error_type() if it's illegal.
|
||||
extern BroType* refine_type(TypeList* base, type_decl_list* refinements);
|
||||
|
||||
// Returns the BRO basic (non-parameterized) type with the given type.
|
||||
extern BroType* base_type(TypeTag tag);
|
||||
|
||||
|
|
|
@ -4574,7 +4574,8 @@ event ssh_server_version%(c: connection, version: string%);
|
|||
## maps them to descriptive names.
|
||||
##
|
||||
## .. bro:see:: ssl_alert ssl_established ssl_extension ssl_server_hello
|
||||
## x509_certificate x509_error x509_extension ssl_max_cipherspec_size
|
||||
## ssl_session_ticket_handshake x509_certificate x509_error x509_extension
|
||||
## ssl_max_cipherspec_size
|
||||
event ssl_client_hello%(c: connection, version: count, possible_ts: time, session_id: string, ciphers: count_set%);
|
||||
|
||||
## Generated for an SSL/TLS servers's initial *hello* message. SSL/TLS sessions
|
||||
|
@ -4604,7 +4605,8 @@ event ssl_client_hello%(c: connection, version: count, possible_ts: time, sessio
|
|||
## standardized as part of the SSL/TLS protocol.
|
||||
##
|
||||
## .. bro:see:: ssl_alert ssl_client_hello ssl_established ssl_extension
|
||||
## x509_certificate x509_error x509_extension ssl_max_cipherspec_size
|
||||
## ssl_session_ticket_handshake x509_certificate x509_error x509_extension
|
||||
## ssl_max_cipherspec_size
|
||||
event ssl_server_hello%(c: connection, version: count, possible_ts: time, session_id: string, cipher: count, comp_method: count%);
|
||||
|
||||
## Generated for SSL/TLS extensions seen in an initial handshake. SSL/TLS sessions
|
||||
|
@ -4623,7 +4625,7 @@ event ssl_server_hello%(c: connection, version: count, possible_ts: time, sessio
|
|||
## val: The raw extension value that was sent in the message.
|
||||
##
|
||||
## .. bro:see:: ssl_alert ssl_client_hello ssl_established ssl_server_hello
|
||||
## x509_certificate x509_error x509_extension
|
||||
## ssl_session_ticket_handshake x509_certificate x509_error x509_extension
|
||||
event ssl_extension%(c: connection, is_orig: bool, code: count, val: string%);
|
||||
|
||||
## Generated at the end of an SSL/TLS handshake. SSL/TLS sessions start with
|
||||
|
@ -4638,7 +4640,7 @@ event ssl_extension%(c: connection, is_orig: bool, code: count, val: string%);
|
|||
## c: The connection.
|
||||
##
|
||||
## .. bro:see:: ssl_alert ssl_client_hello ssl_extension ssl_server_hello
|
||||
## x509_certificate x509_error x509_extension
|
||||
## ssl_session_ticket_handshake x509_certificate x509_error x509_extension
|
||||
event ssl_established%(c: connection%);
|
||||
|
||||
## Generated for SSL/TLS alert records. SSL/TLS sessions start with an unencrypted
|
||||
|
@ -4661,9 +4663,28 @@ event ssl_established%(c: connection%);
|
|||
## defined as part of the SSL/TLS protocol.
|
||||
##
|
||||
## .. bro:see:: ssl_client_hello ssl_established ssl_extension ssl_server_hello
|
||||
## x509_certificate x509_error x509_extension
|
||||
## ssl_session_ticket_handshake x509_certificate x509_error x509_extension
|
||||
event ssl_alert%(c: connection, is_orig: bool, level: count, desc: count%);
|
||||
|
||||
## Generated for SSL/TLS handshake. SSL/TLS sessions start with an unencrypted
|
||||
## handshake, and Bro extracts as much information out of that as it can. This
|
||||
## event is raised when an SSL/TLS server passes session ticket to the client that
|
||||
## can later be used for resuming the session.
|
||||
##
|
||||
## See `Wikipedia <http://en.wikipedia.org/wiki/Transport_Layer_Security>`__ for
|
||||
## more information about the SSL/TLS protocol.
|
||||
##
|
||||
## c: The connection.
|
||||
##
|
||||
## ticket_lifetime_hint: A hint to the client indicating how long the ticket should
|
||||
## be valid.
|
||||
##
|
||||
## ticket: The raw ticket.
|
||||
##
|
||||
## .. bro:see:: ssl_client_hello ssl_established ssl_extension ssl_server_hello
|
||||
## x509_certificate x509_error x509_extension ssl_alert
|
||||
event ssl_session_ticket_handshake%(c: connection, ticket_lifetime_hint: count, ticket: string%);
|
||||
|
||||
## Generated for x509 certificates seen in SSL/TLS connections. During the initial
|
||||
## SSL/TLS handshake, certificates are exchanged in the clear. Bro raises this
|
||||
## event for each certificate seen (including both a site's primary cert, and
|
||||
|
|
10
src/main.cc
10
src/main.cc
|
@ -97,7 +97,7 @@ extern char version[];
|
|||
char* command_line_policy = 0;
|
||||
vector<string> params;
|
||||
char* proc_status_file = 0;
|
||||
int snaplen = 65535; // really want "capture entire packet"
|
||||
int snaplen = 0; // this gets set from the scripting-layer's value
|
||||
|
||||
int FLAGS_use_binpac = false;
|
||||
|
||||
|
@ -145,7 +145,6 @@ void usage()
|
|||
fprintf(stderr, " -g|--dump-config | dump current config into .state dir\n");
|
||||
fprintf(stderr, " -h|--help|-? | command line help\n");
|
||||
fprintf(stderr, " -i|--iface <interface> | read from given interface\n");
|
||||
fprintf(stderr, " -l|--snaplen <snaplen> | number of bytes per packet to capture from interfaces (default 65535)\n");
|
||||
fprintf(stderr, " -p|--prefix <prefix> | add given prefix to policy file resolution\n");
|
||||
fprintf(stderr, " -r|--readfile <readfile> | read from given tcpdump file\n");
|
||||
fprintf(stderr, " -y|--flowfile <file>[=<ident>] | read from given flow file\n");
|
||||
|
@ -372,7 +371,6 @@ int main(int argc, char** argv)
|
|||
{"filter", required_argument, 0, 'f'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"iface", required_argument, 0, 'i'},
|
||||
{"snaplen", required_argument, 0, 'l'},
|
||||
{"doc-scripts", no_argument, 0, 'Z'},
|
||||
{"prefix", required_argument, 0, 'p'},
|
||||
{"readfile", required_argument, 0, 'r'},
|
||||
|
@ -481,10 +479,6 @@ int main(int argc, char** argv)
|
|||
interfaces.append(optarg);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
snaplen = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
prefixes.append(optarg);
|
||||
break;
|
||||
|
@ -833,6 +827,8 @@ int main(int argc, char** argv)
|
|||
}
|
||||
}
|
||||
|
||||
snaplen = internal_val("snaplen")->AsCount();
|
||||
|
||||
// Initialize the secondary path, if it's needed.
|
||||
secondary_path = new SecondaryPath();
|
||||
|
||||
|
|
15
src/parse.y
15
src/parse.y
|
@ -2,7 +2,7 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
%}
|
||||
|
||||
%expect 88
|
||||
%expect 87
|
||||
|
||||
%token TOK_ADD TOK_ADD_TO TOK_ADDR TOK_ANY
|
||||
%token TOK_ATENDIF TOK_ATELSE TOK_ATIF TOK_ATIFDEF TOK_ATIFNDEF
|
||||
|
@ -53,7 +53,7 @@
|
|||
%type <expr> expr init anonymous_function
|
||||
%type <event_expr> event
|
||||
%type <stmt> stmt stmt_list func_body for_head
|
||||
%type <type> type opt_type refined_type enum_body
|
||||
%type <type> type opt_type enum_body
|
||||
%type <func_type> func_hdr func_params
|
||||
%type <type_l> type_list
|
||||
%type <type_decl> type_decl formal_args_decl
|
||||
|
@ -1104,7 +1104,7 @@ decl:
|
|||
}
|
||||
}
|
||||
|
||||
| TOK_TYPE global_id ':' refined_type opt_attr ';'
|
||||
| TOK_TYPE global_id ':' type opt_attr ';'
|
||||
{
|
||||
add_type($2, $4, $5, 0);
|
||||
|
||||
|
@ -1134,7 +1134,7 @@ decl:
|
|||
}
|
||||
}
|
||||
|
||||
| TOK_EVENT event_id ':' refined_type opt_attr ';'
|
||||
| TOK_EVENT event_id ':' type_list opt_attr ';'
|
||||
{
|
||||
add_type($2, $4, $5, 1);
|
||||
|
||||
|
@ -1220,13 +1220,6 @@ func_params:
|
|||
{ $$ = new FuncType($2, base_type(TYPE_VOID), 0); }
|
||||
;
|
||||
|
||||
refined_type:
|
||||
type_list '{' type_decl_list '}'
|
||||
{ $$ = refine_type($1, $3); }
|
||||
| type_list
|
||||
{ $$ = refine_type($1, 0); }
|
||||
;
|
||||
|
||||
opt_type:
|
||||
':' type
|
||||
{ $$ = $2; }
|
||||
|
|
|
@ -144,7 +144,7 @@ refine connection SSL_Conn += {
|
|||
if ( ssl_client_hello )
|
||||
{
|
||||
vector<int>* cipher_suites = new vector<int>();
|
||||
if ( cipher_suites16 )
|
||||
if ( cipher_suites16 )
|
||||
std::copy(cipher_suites16->begin(), cipher_suites16->end(), std::back_inserter(*cipher_suites));
|
||||
else
|
||||
std::transform(cipher_suites24->begin(), cipher_suites24->end(), std::back_inserter(*cipher_suites), to_int());
|
||||
|
@ -205,6 +205,18 @@ refine connection SSL_Conn += {
|
|||
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_session_ticket_handshake(rec: SessionTicketHandshake, is_orig: bool): bool
|
||||
%{
|
||||
if ( ssl_session_ticket_handshake )
|
||||
{
|
||||
BifEvent::generate_ssl_session_ticket_handshake(bro_analyzer(),
|
||||
bro_analyzer()->Conn(),
|
||||
${rec.ticket_lifetime_hint},
|
||||
new StringVal(${rec.data}.length(), (const char*) ${rec.data}.data()));
|
||||
}
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_ssl_extension(rec: SSLRecord, type: int, data: bytestring) : bool
|
||||
%{
|
||||
|
@ -269,13 +281,14 @@ refine connection SSL_Conn += {
|
|||
der_cert);
|
||||
|
||||
// Are there any X509 extensions?
|
||||
//printf("Number of x509 extensions: %d\n", X509_get_ext_count(pTemp));
|
||||
if ( x509_extension && X509_get_ext_count(pTemp) > 0 )
|
||||
{
|
||||
int num_ext = X509_get_ext_count(pTemp);
|
||||
for ( int k = 0; k < num_ext; ++k )
|
||||
{
|
||||
unsigned char *pBuffer = 0;
|
||||
int length = 0;
|
||||
uint length = 0;
|
||||
|
||||
X509_EXTENSION* ex = X509_get_ext(pTemp, k);
|
||||
if (ex)
|
||||
|
@ -283,7 +296,7 @@ refine connection SSL_Conn += {
|
|||
ASN1_STRING *pString = X509_EXTENSION_get_data(ex);
|
||||
length = ASN1_STRING_to_UTF8(&pBuffer, pString);
|
||||
//i2t_ASN1_OBJECT(&pBuffer, length, obj)
|
||||
|
||||
// printf("extension length: %u\n", length);
|
||||
// -1 indicates an error.
|
||||
if ( length < 0 )
|
||||
continue;
|
||||
|
@ -442,6 +455,10 @@ refine typeattr Handshake += &let {
|
|||
proc : bool = $context.connection.proc_handshake(this, rec.is_orig);
|
||||
};
|
||||
|
||||
refine typeattr SessionTicketHandshake += &let {
|
||||
proc : bool = $context.connection.proc_session_ticket_handshake(this, rec.is_orig);
|
||||
}
|
||||
|
||||
refine typeattr UnknownRecord += &let {
|
||||
proc : bool = $context.connection.proc_unknown_record(rec);
|
||||
};
|
||||
|
|
|
@ -61,17 +61,10 @@ type RecordText(rec: SSLRecord) = case $context.connection.state() of {
|
|||
-> plaintext : PlaintextRecord(rec);
|
||||
};
|
||||
|
||||
type PossibleEncryptedHandshake(rec: SSLRecord) = case $context.connection.state() of {
|
||||
# Deal with encrypted handshakes before the server cipher spec change.
|
||||
STATE_CLIENT_FINISHED, STATE_CLIENT_ENCRYPTED
|
||||
-> ct : CiphertextRecord(rec);
|
||||
default -> hs : Handshake(rec);
|
||||
};
|
||||
|
||||
type PlaintextRecord(rec: SSLRecord) = case rec.content_type of {
|
||||
CHANGE_CIPHER_SPEC -> ch_cipher : ChangeCipherSpec(rec);
|
||||
ALERT -> alert : Alert(rec);
|
||||
HANDSHAKE -> handshake : PossibleEncryptedHandshake(rec);
|
||||
HANDSHAKE -> handshake : Handshake(rec);
|
||||
APPLICATION_DATA -> app_data : ApplicationData(rec);
|
||||
V2_ERROR -> v2_error : V2Error(rec);
|
||||
V2_CLIENT_HELLO -> v2_client_hello : V2ClientHello(rec);
|
||||
|
@ -260,18 +253,19 @@ enum AnalyzerState {
|
|||
######################################################################
|
||||
|
||||
enum HandshakeType {
|
||||
HELLO_REQUEST = 0,
|
||||
CLIENT_HELLO = 1,
|
||||
SERVER_HELLO = 2,
|
||||
CERTIFICATE = 11,
|
||||
SERVER_KEY_EXCHANGE = 12,
|
||||
CERTIFICATE_REQUEST = 13,
|
||||
SERVER_HELLO_DONE = 14,
|
||||
CERTIFICATE_VERIFY = 15,
|
||||
CLIENT_KEY_EXCHANGE = 16,
|
||||
FINISHED = 20,
|
||||
CERTIFICATE_URL = 21, # RFC 3546
|
||||
CERTIFICATE_STATUS = 22, # RFC 3546
|
||||
HELLO_REQUEST = 0,
|
||||
CLIENT_HELLO = 1,
|
||||
SERVER_HELLO = 2,
|
||||
SESSION_TICKET = 4, # RFC 5077
|
||||
CERTIFICATE = 11,
|
||||
SERVER_KEY_EXCHANGE = 12,
|
||||
CERTIFICATE_REQUEST = 13,
|
||||
SERVER_HELLO_DONE = 14,
|
||||
CERTIFICATE_VERIFY = 15,
|
||||
CLIENT_KEY_EXCHANGE = 16,
|
||||
FINISHED = 20,
|
||||
CERTIFICATE_URL = 21, # RFC 3546
|
||||
CERTIFICATE_STATUS = 22, # RFC 3546
|
||||
};
|
||||
|
||||
%code{
|
||||
|
@ -281,6 +275,7 @@ enum HandshakeType {
|
|||
case HELLO_REQUEST: return string("HELLO_REQUEST");
|
||||
case CLIENT_HELLO: return string("CLIENT_HELLO");
|
||||
case SERVER_HELLO: return string("SERVER_HELLO");
|
||||
case SESSION_TICKET: return string("SESSION_TICKET");
|
||||
case CERTIFICATE: return string("CERTIFICATE");
|
||||
case SERVER_KEY_EXCHANGE: return string("SERVER_KEY_EXCHANGE");
|
||||
case CERTIFICATE_REQUEST: return string("CERTIFICATE_REQUEST");
|
||||
|
@ -452,8 +447,7 @@ type V2ServerHello(rec: SSLRecord) = record {
|
|||
cert_data : bytestring &length = cert_len;
|
||||
ciphers : uint24[ciph_len/3];
|
||||
conn_id_data : bytestring &length = conn_id_len;
|
||||
} #&length = 8 + cert_len + ciph_len + conn_id_len,
|
||||
&let {
|
||||
} &let {
|
||||
state_changed : bool =
|
||||
(session_id_hit > 0 ?
|
||||
$context.connection.transition(STATE_CLIENT_HELLO_RCVD,
|
||||
|
@ -603,7 +597,7 @@ type CertificateVerify(rec: SSLRecord) = record {
|
|||
######################################################################
|
||||
|
||||
# The finished messages are always sent after encryption is in effect,
|
||||
# so we will not be able to read those message.
|
||||
# so we will not be able to read those messages.
|
||||
type Finished(rec: SSLRecord) = record {
|
||||
cont : bytestring &restofdata &transient;
|
||||
} &let {
|
||||
|
@ -615,13 +609,17 @@ type Finished(rec: SSLRecord) = record {
|
|||
$context.connection.lost_track();
|
||||
};
|
||||
|
||||
type SessionTicketHandshake(rec: SSLRecord) = record {
|
||||
ticket_lifetime_hint: uint32;
|
||||
data: bytestring &restofdata;
|
||||
};
|
||||
|
||||
######################################################################
|
||||
# V3 Handshake Protocol (7.)
|
||||
######################################################################
|
||||
|
||||
type UnknownHandshake(hs: Handshake, is_orig: bool) = record {
|
||||
cont : bytestring &restofdata &transient;
|
||||
data : bytestring &restofdata &transient;
|
||||
} &let {
|
||||
state_changed : bool = $context.connection.lost_track();
|
||||
};
|
||||
|
@ -631,19 +629,20 @@ type Handshake(rec: SSLRecord) = record {
|
|||
length : uint24;
|
||||
|
||||
body : case msg_type of {
|
||||
HELLO_REQUEST -> hello_request : HelloRequest(rec);
|
||||
CLIENT_HELLO -> client_hello : ClientHello(rec);
|
||||
SERVER_HELLO -> server_hello : ServerHello(rec);
|
||||
CERTIFICATE -> certificate : Certificate(rec);
|
||||
SERVER_KEY_EXCHANGE -> server_key_exchange : ServerKeyExchange(rec);
|
||||
CERTIFICATE_REQUEST -> certificate_request : CertificateRequest(rec);
|
||||
SERVER_HELLO_DONE -> server_hello_done : ServerHelloDone(rec);
|
||||
CERTIFICATE_VERIFY -> certificate_verify : CertificateVerify(rec);
|
||||
CLIENT_KEY_EXCHANGE -> client_key_exchange : ClientKeyExchange(rec);
|
||||
FINISHED -> finished : Finished(rec);
|
||||
CERTIFICATE_URL -> certificate_url : bytestring &restofdata &transient;
|
||||
CERTIFICATE_STATUS -> certificate_status : bytestring &restofdata &transient;
|
||||
default -> unknown_handshake : UnknownHandshake(this, rec.is_orig);
|
||||
HELLO_REQUEST -> hello_request : HelloRequest(rec);
|
||||
CLIENT_HELLO -> client_hello : ClientHello(rec);
|
||||
SERVER_HELLO -> server_hello : ServerHello(rec);
|
||||
SESSION_TICKET -> session_ticket : SessionTicketHandshake(rec);
|
||||
CERTIFICATE -> certificate : Certificate(rec);
|
||||
SERVER_KEY_EXCHANGE -> server_key_exchange : ServerKeyExchange(rec);
|
||||
CERTIFICATE_REQUEST -> certificate_request : CertificateRequest(rec);
|
||||
SERVER_HELLO_DONE -> server_hello_done : ServerHelloDone(rec);
|
||||
CERTIFICATE_VERIFY -> certificate_verify : CertificateVerify(rec);
|
||||
CLIENT_KEY_EXCHANGE -> client_key_exchange : ClientKeyExchange(rec);
|
||||
FINISHED -> finished : Finished(rec);
|
||||
CERTIFICATE_URL -> certificate_url : bytestring &restofdata &transient;
|
||||
CERTIFICATE_STATUS -> certificate_status : bytestring &restofdata &transient;
|
||||
default -> unknown_handshake : UnknownHandshake(this, rec.is_orig);
|
||||
} &length = to_int()(length);
|
||||
};
|
||||
|
||||
|
|
|
@ -3,6 +3,6 @@
|
|||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path notice
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p note msg sub src dst p n peer_descr actions policy_items suppress_for dropped remote_location.country_code remote_location.region remote_location.city remote_location.latitude remote_location.longitude metric_index.host metric_index.str metric_index.network
|
||||
#types time string addr port addr port enum string string addr addr port count string table[enum] table[count] interval bool string string string double double addr string subnet
|
||||
1324314350.184962 - - - - - Test_Notice Threshold crossed by metric_index(host=1.2.3.4) 100/100 - 1.2.3.4 - - 100 manager-1 Notice::ACTION_LOG 6 3600.000000 F - - - - - 1.2.3.4 - -
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto note msg sub src dst p n peer_descr actions policy_items suppress_for dropped remote_location.country_code remote_location.region remote_location.city remote_location.latitude remote_location.longitude metric_index.host metric_index.str metric_index.network
|
||||
#types time string addr port addr port enum enum string string addr addr port count string table[enum] table[count] interval bool string string string double double addr string subnet
|
||||
1325633225.777902 - - - - - - Test_Notice Threshold crossed by metric_index(host=1.2.3.4) 100/100 - 1.2.3.4 - - 100 manager-1 Notice::ACTION_LOG 6 3600.000000 F - - - - - 1.2.3.4 - -
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path notice
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p note msg sub src dst p n peer_descr actions policy_items suppress_for dropped remote_location.country_code remote_location.region remote_location.city remote_location.latitude remote_location.longitude metric_index.host metric_index.str metric_index.network
|
||||
#types time string addr port addr port enum string string addr addr port count string table[enum] table[count] interval bool string string string double double addr string subnet
|
||||
1324314359.357148 - - - - - Test_Notice Threshold crossed by metric_index(host=1.2.3.4) 3/2 - 1.2.3.4 - - 3 bro Notice::ACTION_LOG 6 3600.000000 F - - - - - 1.2.3.4 - -
|
||||
1324314359.357148 - - - - - Test_Notice Threshold crossed by metric_index(host=6.5.4.3) 2/2 - 6.5.4.3 - - 2 bro Notice::ACTION_LOG 6 3600.000000 F - - - - - 6.5.4.3 - -
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto note msg sub src dst p n peer_descr actions policy_items suppress_for dropped remote_location.country_code remote_location.region remote_location.city remote_location.latitude remote_location.longitude metric_index.host metric_index.str metric_index.network
|
||||
#types time string addr port addr port enum enum string string addr addr port count string table[enum] table[count] interval bool string string string double double addr string subnet
|
||||
1325633274.875473 - - - - - - Test_Notice Threshold crossed by metric_index(host=1.2.3.4) 3/2 - 1.2.3.4 - - 3 bro Notice::ACTION_LOG 6 3600.000000 F - - - - - 1.2.3.4 - -
|
||||
1325633274.875473 - - - - - - Test_Notice Threshold crossed by metric_index(host=6.5.4.3) 2/2 - 6.5.4.3 - - 2 bro Notice::ACTION_LOG 6 3600.000000 F - - - - - 6.5.4.3 - -
|
||||
|
|
|
@ -3,6 +3,6 @@
|
|||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path notice
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p note msg sub src dst p n peer_descr actions policy_items suppress_for dropped remote_location.country_code remote_location.region remote_location.city remote_location.latitude remote_location.longitude metric_index.host metric_index.str metric_index.network
|
||||
#types time string addr port addr port enum string string addr addr port count string table[enum] table[count] interval bool string string string double double addr string subnet
|
||||
1324314363.721823 - - - - - Test_Notice test notice! - - - - - worker-1 Notice::ACTION_LOG 6 3600.000000 F - - - - - - - -
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto note msg sub src dst p n peer_descr actions policy_items suppress_for dropped remote_location.country_code remote_location.region remote_location.city remote_location.latitude remote_location.longitude metric_index.host metric_index.str metric_index.network
|
||||
#types time string addr port addr port enum enum string string addr addr port count string table[enum] table[count] interval bool string string string double double addr string subnet
|
||||
1325633122.490990 - - - - - - Test_Notice test notice! - - - - - worker-1 Notice::ACTION_LOG 6 3600.000000 F - - - - - - - -
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
> 2005-10-07-23:23:55 Test_Notice 141.42.64.125:56730/tcp -> 125.190.109.199:80/tcp (uid arKYeMETxOg)
|
||||
test
|
||||
# 141.42.64.125 = <skipped> 125.190.109.199 = <skipped>
|
||||
|
|
@ -3,6 +3,6 @@
|
|||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path notice
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p note msg sub src dst p n peer_descr actions policy_items suppress_for dropped remote_location.country_code remote_location.region remote_location.city remote_location.latitude remote_location.longitude metric_index.host metric_index.str metric_index.network
|
||||
#types time string addr port addr port enum string string addr addr port count string table[enum] table[count] interval bool string string string double double addr string subnet
|
||||
1324314378.560010 - - - - - Test_Notice test notice! - - - - - worker-2 Notice::ACTION_LOG 6 3600.000000 F - - - - - - - -
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto note msg sub src dst p n peer_descr actions policy_items suppress_for dropped remote_location.country_code remote_location.region remote_location.city remote_location.latitude remote_location.longitude metric_index.host metric_index.str metric_index.network
|
||||
#types time string addr port addr port enum enum string string addr addr port count string table[enum] table[count] interval bool string string string double double addr string subnet
|
||||
1325633150.723248 - - - - - - Test_Notice test notice! - - - - - worker-2 Notice::ACTION_LOG 6 3600.000000 F - - - - - - - -
|
||||
|
|
|
@ -3,6 +3,6 @@
|
|||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path notice
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p note msg sub src dst p n peer_descr actions policy_items suppress_for dropped remote_location.country_code remote_location.region remote_location.city remote_location.latitude remote_location.longitude
|
||||
#types time string addr port addr port enum string string addr addr port count string table[enum] table[count] interval bool string string string double double
|
||||
1324314387.663586 - - - - - Test_Notice test - - - - - bro Notice::ACTION_LOG 6 3600.000000 F - - - - -
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto note msg sub src dst p n peer_descr actions policy_items suppress_for dropped remote_location.country_code remote_location.region remote_location.city remote_location.latitude remote_location.longitude
|
||||
#types time string addr port addr port enum enum string string addr addr port count string table[enum] table[count] interval bool string string string double double
|
||||
1325633207.922993 - - - - - - Test_Notice test - - - - - bro Notice::ACTION_LOG 6 3600.000000 F - - - - -
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# @TEST-EXEC: btest-bg-run proxy-2 BROPATH=$BROPATH:.. CLUSTER_NODE=proxy-2 bro %INPUT
|
||||
# @TEST-EXEC: btest-bg-run worker-1 BROPATH=$BROPATH:.. CLUSTER_NODE=worker-1 bro %INPUT
|
||||
# @TEST-EXEC: btest-bg-run worker-2 BROPATH=$BROPATH:.. CLUSTER_NODE=worker-2 bro %INPUT
|
||||
# @TEST-EXEC: btest-bg-wait -k 2
|
||||
# @TEST-EXEC: btest-bg-wait -k 10
|
||||
# @TEST-EXEC: btest-diff manager-1/.stdout
|
||||
# @TEST-EXEC: btest-diff proxy-1/.stdout
|
||||
# @TEST-EXEC: btest-diff proxy-2/.stdout
|
||||
|
@ -23,4 +23,4 @@ redef Cluster::nodes = {
|
|||
event remote_connection_handshake_done(p: event_peer)
|
||||
{
|
||||
print "Connected to a peer";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
# @TEST-EXEC: btest-bg-run receiver bro -b ../receiver.bro
|
||||
# @TEST-EXEC: btest-bg-run sender bro -b ../sender.bro
|
||||
# @TEST-EXEC: btest-bg-wait -k 2
|
||||
# @TEST-EXEC: btest-bg-wait -k 10
|
||||
#
|
||||
# Don't diff the receiver log just because port is always going to change
|
||||
# @TEST-EXEC: egrep -v 'pid|socket buffer size' sender/communication.log >send.log
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# @TEST-EXEC: btest-bg-run controllee BROPATH=$BROPATH:.. bro %INPUT frameworks/control/controllee Communication::listen_port=65531/tcp
|
||||
# @TEST-EXEC: btest-bg-run controller BROPATH=$BROPATH:.. bro %INPUT test-redef frameworks/control/controller Control::host=127.0.0.1 Control::host_port=65531/tcp Control::cmd=configuration_update
|
||||
# @TEST-EXEC: btest-bg-run controller2 BROPATH=$BROPATH:.. bro %INPUT frameworks/control/controller Control::host=127.0.0.1 Control::host_port=65531/tcp Control::cmd=shutdown
|
||||
# @TEST-EXEC: btest-bg-wait 1
|
||||
# @TEST-EXEC: btest-bg-wait 10
|
||||
# @TEST-EXEC: btest-diff controllee/.stdout
|
||||
|
||||
redef Communication::nodes = {
|
||||
|
@ -23,4 +23,4 @@ event bro_init()
|
|||
event bro_done()
|
||||
{
|
||||
print test_var;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# @TEST-EXEC: btest-bg-run controllee BROPATH=$BROPATH:.. bro %INPUT only-for-controllee frameworks/control/controllee Communication::listen_port=65532/tcp
|
||||
# @TEST-EXEC: btest-bg-run controller BROPATH=$BROPATH:.. bro %INPUT frameworks/control/controller Control::host=127.0.0.1 Control::host_port=65532/tcp Control::cmd=id_value Control::arg=test_var
|
||||
# @TEST-EXEC: btest-bg-wait -k 1
|
||||
# @TEST-EXEC: btest-bg-wait -k 10
|
||||
# @TEST-EXEC: btest-diff controller/.stdout
|
||||
|
||||
redef Communication::nodes = {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# @TEST-EXEC: btest-bg-run controllee BROPATH=$BROPATH:.. bro %INPUT frameworks/control/controllee Communication::listen_port=65530/tcp
|
||||
# @TEST-EXEC: btest-bg-run controller BROPATH=$BROPATH:.. bro %INPUT frameworks/control/controller Control::host=127.0.0.1 Control::host_port=65530/tcp Control::cmd=shutdown
|
||||
# @TEST-EXEC: btest-bg-wait 1
|
||||
# @TEST-EXEC: btest-bg-wait 10
|
||||
|
||||
redef Communication::nodes = {
|
||||
# We're waiting for connections from this host for control.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
# @TEST-EXEC: btest-bg-run sender bro --pseudo-realtime %INPUT ../sender.bro
|
||||
# @TEST-EXEC: btest-bg-run receiver bro --pseudo-realtime %INPUT ../receiver.bro
|
||||
# @TEST-EXEC: btest-bg-wait -k 1
|
||||
# @TEST-EXEC: btest-bg-wait -k 10
|
||||
# @TEST-EXEC: btest-diff receiver/test.log
|
||||
# @TEST-EXEC: cmp receiver/test.log sender/test.log
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# @TEST-EXEC: sleep 1
|
||||
# @TEST-EXEC: btest-bg-run receiver bro --pseudo-realtime %INPUT ../receiver.bro
|
||||
# @TEST-EXEC: sleep 1
|
||||
# @TEST-EXEC: btest-bg-wait -k 1
|
||||
# @TEST-EXEC: btest-bg-wait -k 10
|
||||
# @TEST-EXEC: btest-diff sender/test.log
|
||||
# @TEST-EXEC: btest-diff sender/test.failure.log
|
||||
# @TEST-EXEC: btest-diff sender/test.success.log
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# @TEST-EXEC: sleep 1
|
||||
# @TEST-EXEC: btest-bg-run worker-1 BROPATH=$BROPATH:.. CLUSTER_NODE=worker-1 bro %INPUT
|
||||
# @TEST-EXEC: btest-bg-run worker-2 BROPATH=$BROPATH:.. CLUSTER_NODE=worker-2 bro %INPUT
|
||||
# @TEST-EXEC: btest-bg-wait -k 6
|
||||
# @TEST-EXEC: btest-bg-wait -k 10
|
||||
# @TEST-EXEC: btest-diff manager-1/metrics.log
|
||||
|
||||
@TEST-START-FILE cluster-layout.bro
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# @TEST-EXEC: sleep 1
|
||||
# @TEST-EXEC: btest-bg-run worker-1 BROPATH=$BROPATH:.. CLUSTER_NODE=worker-1 bro %INPUT
|
||||
# @TEST-EXEC: btest-bg-run worker-2 BROPATH=$BROPATH:.. CLUSTER_NODE=worker-2 bro %INPUT
|
||||
# @TEST-EXEC: btest-bg-wait -k 5
|
||||
# @TEST-EXEC: btest-bg-wait -k 10
|
||||
# @TEST-EXEC: btest-diff manager-1/notice.log
|
||||
|
||||
@TEST-START-FILE cluster-layout.bro
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# @TEST-EXEC: btest-bg-run proxy-1 BROPATH=$BROPATH:.. CLUSTER_NODE=proxy-1 bro %INPUT
|
||||
# @TEST-EXEC: sleep 1
|
||||
# @TEST-EXEC: btest-bg-run worker-1 BROPATH=$BROPATH:.. CLUSTER_NODE=worker-1 bro %INPUT
|
||||
# @TEST-EXEC: btest-bg-wait -k 6
|
||||
# @TEST-EXEC: btest-bg-wait -k 10
|
||||
# @TEST-EXEC: btest-diff manager-1/notice.log
|
||||
|
||||
@TEST-START-FILE cluster-layout.bro
|
||||
|
|
17
testing/btest/scripts/base/frameworks/notice/mail-alarms.bro
Normal file
17
testing/btest/scripts/base/frameworks/notice/mail-alarms.bro
Normal file
|
@ -0,0 +1,17 @@
|
|||
# @TEST-EXEC: bro -C -r $TRACES/web.trace %INPUT
|
||||
# @TEST-EXEC: btest-diff alarm-mail.txt
|
||||
|
||||
redef Notice::policy += { [$action = Notice::ACTION_ALARM, $priority = 1 ] };
|
||||
redef Notice::force_email_summaries = T;
|
||||
|
||||
redef enum Notice::Type += {
|
||||
Test_Notice,
|
||||
};
|
||||
|
||||
event connection_established(c: connection)
|
||||
{
|
||||
NOTICE([$note=Test_Notice, $conn=c, $msg="test", $identifier="static"]);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
# @TEST-EXEC: sleep 1
|
||||
# @TEST-EXEC: btest-bg-run worker-1 BROPATH=$BROPATH:.. CLUSTER_NODE=worker-1 bro %INPUT
|
||||
# @TEST-EXEC: btest-bg-run worker-2 BROPATH=$BROPATH:.. CLUSTER_NODE=worker-2 bro %INPUT
|
||||
# @TEST-EXEC: btest-bg-wait -k 5
|
||||
# @TEST-EXEC: btest-bg-wait -k 10
|
||||
# @TEST-EXEC: btest-diff manager-1/notice.log
|
||||
|
||||
@TEST-START-FILE cluster-layout.bro
|
||||
|
|
11
testing/external/scripts/diff-all
vendored
11
testing/external/scripts/diff-all
vendored
|
@ -22,7 +22,16 @@ files_cwd=`ls $@`
|
|||
files_baseline=`cd $TEST_BASELINE && ls $@`
|
||||
|
||||
for i in `echo $files_cwd $files_baseline | sort | uniq`; do
|
||||
if [[ "$i" != "loaded_scripts.log" && "$i" != "prof.log" ]]; then
|
||||
if [[ "$i" != "loaded_scripts.log" && "$i" != "prof.log" && "$i" != "debug.log" ]]; then
|
||||
|
||||
if [[ "$i" == "reporter.log" ]]; then
|
||||
# Do not diff the reporter.log if it only complains about missing
|
||||
# GeoIP support.
|
||||
if ! egrep -v "^#|Bro was not configured for GeoIP support" $i; then
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! btest-diff $i; then
|
||||
echo "" >>$diag
|
||||
echo "#### btest-diff $i" >>$diag
|
||||
|
|
|
@ -5,3 +5,4 @@
|
|||
`dirname $0`/diff-remove-timestamps \
|
||||
| `dirname $0`/diff-remove-uids \
|
||||
| `dirname $0`/diff-remove-mime-types \
|
||||
| `dirname $0`/diff-remove-x509-names \
|
||||
|
|
32
testing/scripts/diff-remove-x509-names
Executable file
32
testing/scripts/diff-remove-x509-names
Executable file
|
@ -0,0 +1,32 @@
|
|||
#! /usr/bin/awk -f
|
||||
#
|
||||
# A diff canonifier that removes all X.509 Distinguished Name subject fields
|
||||
# because that output can differ depending on installed OpenSSL version.
|
||||
|
||||
BEGIN { FS="\t"; OFS="\t"; s_col = -1; i_col = -1 }
|
||||
|
||||
/^#fields/ {
|
||||
for ( i = 2; i < NF; ++i )
|
||||
{
|
||||
if ( $i == "subject" )
|
||||
s_col = i-1;
|
||||
if ( $i == "issuer_subject" )
|
||||
i_col = i-1;
|
||||
}
|
||||
}
|
||||
|
||||
s_col >= 0 {
|
||||
if ( $s_col != "-" )
|
||||
# Mark that it's set, but ignore content.
|
||||
$s_col = "+";
|
||||
}
|
||||
|
||||
i_col >= 0 {
|
||||
if ( $i_col != "-" )
|
||||
# Mark that it's set, but ignore content.
|
||||
$i_col = "+";
|
||||
}
|
||||
|
||||
{
|
||||
print;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue