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

Conflicts:
	src/parse.y
This commit is contained in:
Bernhard Amann 2012-01-05 01:11:13 -08:00
commit 5bef49d625
37 changed files with 294 additions and 1254 deletions

35
CHANGES
View file

@ -1,4 +1,39 @@
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 2.0-beta-145 | 2011-12-19 11:37:15 -0800
* Empty fields are now logged as "(empty)" by default. (Robin * Empty fields are now logged as "(empty)" by default. (Robin

14
INSTALL
View file

@ -14,10 +14,11 @@ before you begin:
* OpenSSL (headers and libraries) http://www.openssl.org * 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 * Libmagic
compressed Bro-to-Bro communication.
* Libz
Bro can make uses of some optional libraries if they are found at Bro can make uses of some optional libraries if they are found at
installation time: installation time:
@ -32,6 +33,7 @@ already come preinstalled:
* Flex (Fast Lexical Analyzer) * Flex (Fast Lexical Analyzer)
* Perl (Used only during the Bro build process) * Perl (Used only during the Bro build process)
Installation Installation
============ ============
@ -69,8 +71,10 @@ Running Bro
=========== ===========
Bro is a complex program and it takes a bit of time to get familiar 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 with it. A good place for newcomers to start is the Quickstart Guide at
:doc:`quick start guide <quickstart>`.
http://www.bro-ids.org/documentation/quickstart.bro.html
For developers that wish to run Bro directly from the ``build/`` For developers that wish to run Bro directly from the ``build/``
directory (i.e., without performing ``make install``), they will have directory (i.e., without performing ``make install``), they will have

View file

@ -14,7 +14,7 @@ HAVE_MODULES=git submodule | grep -v cmake >/dev/null
all: configured all: configured
$(MAKE) -C $(BUILD) $@ $(MAKE) -C $(BUILD) $@
install: configured install: configured all
$(MAKE) -C $(BUILD) $@ $(MAKE) -C $(BUILD) $@
install-aux: configured install-aux: configured
@ -60,6 +60,9 @@ bindist:
distclean: distclean:
rm -rf $(BUILD) rm -rf $(BUILD)
test:
@(cd testing && make )
configured: configured:
@test -d $(BUILD) || ( echo "Error: No build/ directory found. Did you run configure?" && exit 1 ) @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 ) @test -e $(BUILD)/Makefile || ( echo "Error: No build/Makefile found. Did you run configure?" && exit 1 )

View file

@ -1 +1 @@
2.0-beta-145 2.0-beta-174

@ -1 +1 @@
Subproject commit d7b8a43759bfcbe1381d132d8ab388937e52a6d4 Subproject commit c5cee3d5746ed3d5c14348c1f264d19404caa761

@ -1 +1 @@
Subproject commit a42e4d133b94622c612055047f8534d5122e6e88 Subproject commit d3d5934310a94452b1dddabb2e75f6c5c86b4860

View file

@ -15,13 +15,17 @@ export {
## :bro:id:`Notice::mail_dest`. ## :bro:id:`Notice::mail_dest`.
const mail_dest_pretty_printed = "" &redef; const mail_dest_pretty_printed = "" &redef;
## If an address from one of these networks is reported, we mark ## If an address from one of these networks is reported, we mark
## the entry with an addition quote symbol (i.e., ">"). Many MUAs ## the entry with an addition quote symbol (i.e., ">"). Many MUAs
## then highlight such lines differently. ## then highlight such lines differently.
global flag_nets: set[subnet] &redef; global flag_nets: set[subnet] &redef;
## Function that renders a single alarm. Can be overidden. ## Function that renders a single alarm. Can be overidden.
global pretty_print_alarm: function(out: file, n: Info) &redef; 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. # We maintain an old-style file recording the pretty-printed alarms.
@ -32,6 +36,9 @@ global pp_alarms_open: bool = F;
# Returns True if pretty-printed alarm summaries are activated. # Returns True if pretty-printed alarm summaries are activated.
function want_pp() : bool function want_pp() : bool
{ {
if ( force_email_summaries )
return T;
return (pretty_print_alarms && ! reading_traces() return (pretty_print_alarms && ! reading_traces()
&& (mail_dest != "" || mail_dest_pretty_printed != "")); && (mail_dest != "" || mail_dest_pretty_printed != ""));
} }
@ -44,34 +51,45 @@ function pp_open()
pp_alarms_open = T; pp_alarms_open = T;
pp_alarms = open(pp_alarms_name); 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. # Closes and mails out the current output file.
function pp_send() function pp_send(rinfo: Log::RotationInfo)
{ {
if ( ! pp_alarms_open ) if ( ! pp_alarms_open )
return; return;
write_file(pp_alarms, "\n\n--\n[Automatically generated]\n\n"); write_file(pp_alarms, "\n\n--\n[Automatically generated]\n\n");
close(pp_alarms); 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; 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. # Postprocessor function that triggers the email.
function pp_postprocessor(info: Log::RotationInfo): bool function pp_postprocessor(info: Log::RotationInfo): bool
{ {
if ( want_pp() ) if ( want_pp() )
pp_send(); pp_send(info);
return T; return T;
} }
@ -93,7 +111,7 @@ event notice(n: Notice::Info) &priority=-5
if ( ! want_pp() ) if ( ! want_pp() )
return; return;
if ( ACTION_LOG !in n$actions ) if ( ACTION_ALARM !in n$actions )
return; return;
if ( ! pp_alarms_open ) if ( ! pp_alarms_open )
@ -154,31 +172,25 @@ function pretty_print_alarm(out: file, n: Info)
if ( n?$id ) if ( n?$id )
{ {
orig_p = fmt(":%s", n$id$orig_p); h1 = n$id$orig_h;
resp_p = fmt(":%s", n$id$resp_p); h2 = n$id$resp_h;
who = fmt("%s:%s -> %s:%s", h1, n$id$orig_p, h2, n$id$resp_p);
} }
else if ( n?$src && n?$dst )
if ( n?$src && n?$dst )
{ {
h1 = n$src; h1 = n$src;
h2 = n$dst; h2 = n$dst;
who = fmt("%s%s -> %s%s", h1, orig_p, h2, resp_p); who = fmt("%s -> %s", h1, h2);
if ( n?$uid )
who = fmt("%s (uid %s)", who, n$uid );
} }
else if ( n?$src ) else if ( n?$src )
{ {
local p = "";
if ( n?$p )
p = fmt(":%s", n$p);
h1 = n$src; 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 flag = (h1 in flag_nets || h2 in flag_nets);
local line1 = fmt(">%s %D %s %s", (flag ? ">" : " "), network_time(), n$note, who); local line1 = fmt(">%s %D %s %s", (flag ? ">" : " "), network_time(), n$note, who);
@ -191,6 +203,12 @@ function pretty_print_alarm(out: file, n: Info)
return; return;
} }
if ( reading_traces() )
{
do_msg(out, n, line1, line2, line3, h1, "<skipped>", h2, "<skipped>");
return;
}
when ( local h1name = lookup_addr(h1) ) when ( local h1name = lookup_addr(h1) )
{ {
if ( h2 == 0.0.0.0 ) if ( h2 == 0.0.0.0 )

View file

@ -64,6 +64,10 @@ export {
conn: connection &optional; conn: connection &optional;
iconn: icmp_conn &optional; iconn: icmp_conn &optional;
## 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. ## The :bro:enum:`Notice::Type` of the notice.
note: Type &log; note: Type &log;
## The human readable message for the notice. ## The human readable message for the notice.
@ -491,8 +495,12 @@ function apply_policy(n: Notice::Info)
n$p = n$id$resp_p; n$p = n$id$resp_p;
} }
if ( n?$p )
n$proto = get_port_transport_proto(n$p);
if ( n?$iconn ) if ( n?$iconn )
{ {
n$proto = icmp;
if ( ! n?$src ) if ( ! n?$src )
n$src = n$iconn$orig_h; n$src = n$iconn$orig_h;
if ( ! n?$dst ) if ( ! n?$dst )

View file

@ -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);
}

View file

@ -121,7 +121,7 @@ protected:
// This will be increased whenever there is an incompatible change // This will be increased whenever there is an incompatible change
// in the data format. // in the data format.
static const uint32 DATA_FORMAT_VERSION = 20; static const uint32 DATA_FORMAT_VERSION = 21;
ChunkedIO* io; ChunkedIO* io;

View file

@ -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) RecordType::RecordType(type_decl_list* arg_types) : BroType(TYPE_RECORD)
{ {
types = arg_types; types = arg_types;
base = 0;
fields = 0;
num_fields = types ? types->length() : 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() RecordType::~RecordType()
{ {
if ( types ) if ( types )
@ -953,9 +891,6 @@ RecordType::~RecordType()
delete types; delete types;
} }
delete fields;
Unref(base);
} }
int RecordType::HasField(const char* field) const int RecordType::HasField(const char* field) const
@ -971,17 +906,7 @@ BroType* RecordType::FieldType(const char* field) const
BroType* RecordType::FieldType(int field) const BroType* RecordType::FieldType(int field) const
{ {
if ( types ) return (*types)[field]->type;
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);
}
} }
Val* RecordType::FieldDefault(int field) const Val* RecordType::FieldDefault(int field) const
@ -998,26 +923,14 @@ Val* RecordType::FieldDefault(int field) const
int RecordType::FieldOffset(const char* 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) )
TypeDecl* td = (*types)[i]; return i;
if ( streq(td->id, field) )
return i;
}
return -1;
} }
else return -1;
{
RecordField* rf = fields->Lookup(field);
if ( ! rf )
return -1;
else
return rf->total_offset;
}
} }
const char* RecordType::FieldName(int field) const 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 const TypeDecl* RecordType::FieldDecl(int field) const
{ {
if ( types ) return (*types)[field];
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);
}
} }
TypeDecl* RecordType::FieldDecl(int field) TypeDecl* RecordType::FieldDecl(int field)
{ {
if ( types ) return (*types)[field];
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);
}
} }
void RecordType::Describe(ODesc* d) const void RecordType::Describe(ODesc* d) const
@ -1151,11 +1043,6 @@ void RecordType::DescribeFields(ODesc* d) const
d->SP(); d->SP();
} }
} }
else
{
d->AddCount(1);
base->Describe(d);
}
} }
} }
@ -1208,9 +1095,6 @@ bool RecordType::DoSerialize(SerialInfo* info) const
else if ( ! SERIALIZE(false) ) else if ( ! SERIALIZE(false) )
return false; return false;
SERIALIZE_OPTIONAL(base);
// We don't serialize the fields as we can reconstruct them.
return true; return true;
} }
@ -1245,13 +1129,6 @@ bool RecordType::DoUnserialize(UnserialInfo* info)
else else
types = 0; types = 0;
BroType* type;
UNSERIALIZE_OPTIONAL(type, BroType::Unserialize(info, TYPE_LIST));
base = (TypeList*) type;
if ( base )
Init(base);
return true; return true;
} }
@ -1594,21 +1471,6 @@ bool VectorType::DoUnserialize(UnserialInfo* info)
return yield_type != 0; 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) BroType* base_type(TypeTag tag)
{ {
static BroType* base_types[NUM_TYPES]; static BroType* base_types[NUM_TYPES];

View file

@ -426,20 +426,9 @@ public:
std::list<std::string>* comments; 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 { class RecordType : public BroType {
public: public:
RecordType(type_decl_list* types); RecordType(type_decl_list* types);
RecordType(TypeList* base, type_decl_list* refinements);
~RecordType(); ~RecordType();
@ -473,15 +462,11 @@ public:
void DescribeFieldsReST(ODesc* d, bool func_args) const; void DescribeFieldsReST(ODesc* d, bool func_args) const;
protected: protected:
RecordType() { fields = 0; base = 0; types = 0; } RecordType() { types = 0; }
void Init(TypeList* arg_base);
DECLARE_SERIAL(RecordType) DECLARE_SERIAL(RecordType)
int num_fields; int num_fields;
PDict(RecordField)* fields;
TypeList* base;
type_decl_list* types; type_decl_list* types;
}; };
@ -587,10 +572,6 @@ protected:
BroType* yield_type; 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. // Returns the BRO basic (non-parameterized) type with the given type.
extern BroType* base_type(TypeTag tag); extern BroType* base_type(TypeTag tag);

View file

@ -279,6 +279,7 @@ event ssh_server_version%(c: connection, version: string%);
event ssl_client_hello%(c: connection, version: count, possible_ts: time, session_id: string, ciphers: count_set%); event ssl_client_hello%(c: connection, version: count, possible_ts: time, session_id: string, ciphers: count_set%);
event ssl_server_hello%(c: connection, version: count, possible_ts: time, session_id: string, cipher: count, comp_method: count%); event ssl_server_hello%(c: connection, version: count, possible_ts: time, session_id: string, cipher: count, comp_method: count%);
event ssl_session_ticket_handshake%(c: connection, ticket_lifetime_hint: count, ticket: string%);
event ssl_extension%(c: connection, is_orig: bool, code: count, val: string%); event ssl_extension%(c: connection, is_orig: bool, code: count, val: string%);
event ssl_alert%(c: connection, is_orig: bool, level: count, desc: count%); event ssl_alert%(c: connection, is_orig: bool, level: count, desc: count%);
event ssl_established%(c: connection%); event ssl_established%(c: connection%);

View file

@ -2,7 +2,7 @@
// See the file "COPYING" in the main distribution directory for copyright. // See the file "COPYING" in the main distribution directory for copyright.
%} %}
%expect 91 %expect 90
%token TOK_ADD TOK_ADD_TO TOK_ADDR TOK_ANY %token TOK_ADD TOK_ADD_TO TOK_ADDR TOK_ANY
%token TOK_ATENDIF TOK_ATELSE TOK_ATIF TOK_ATIFDEF TOK_ATIFNDEF %token TOK_ATENDIF TOK_ATELSE TOK_ATIF TOK_ATIFDEF TOK_ATIFNDEF
@ -54,7 +54,7 @@
%type <expr> expr init anonymous_function %type <expr> expr init anonymous_function
%type <event_expr> event %type <event_expr> event
%type <stmt> stmt stmt_list func_body for_head %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 <func_type> func_hdr func_params
%type <type_l> type_list %type <type_l> type_list
%type <type_decl> type_decl formal_args_decl %type <type_decl> type_decl formal_args_decl
@ -1105,7 +1105,7 @@ decl:
} }
} }
| TOK_TYPE global_id ':' refined_type opt_attr ';' | TOK_TYPE global_id ':' type opt_attr ';'
{ {
add_type($2, $4, $5, 0); add_type($2, $4, $5, 0);
@ -1135,7 +1135,7 @@ decl:
} }
} }
| TOK_EVENT event_id ':' refined_type opt_attr ';' | TOK_EVENT event_id ':' type_list opt_attr ';'
{ {
add_type($2, $4, $5, 1); add_type($2, $4, $5, 1);
@ -1221,13 +1221,6 @@ func_params:
{ $$ = new FuncType($2, base_type(TYPE_VOID), 0); } { $$ = 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: opt_type:
':' type ':' type
{ $$ = $2; } { $$ = $2; }

View file

@ -144,7 +144,7 @@ refine connection SSL_Conn += {
if ( ssl_client_hello ) if ( ssl_client_hello )
{ {
vector<int>* cipher_suites = new vector<int>(); 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)); std::copy(cipher_suites16->begin(), cipher_suites16->end(), std::back_inserter(*cipher_suites));
else else
std::transform(cipher_suites24->begin(), cipher_suites24->end(), std::back_inserter(*cipher_suites), to_int()); std::transform(cipher_suites24->begin(), cipher_suites24->end(), std::back_inserter(*cipher_suites), to_int());
@ -206,6 +206,18 @@ refine connection SSL_Conn += {
return true; 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 function proc_ssl_extension(rec: SSLRecord, type: int, data: bytestring) : bool
%{ %{
if ( ssl_extension ) if ( ssl_extension )
@ -269,13 +281,14 @@ refine connection SSL_Conn += {
der_cert); der_cert);
// Are there any X509 extensions? // 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 ) if ( x509_extension && X509_get_ext_count(pTemp) > 0 )
{ {
int num_ext = X509_get_ext_count(pTemp); int num_ext = X509_get_ext_count(pTemp);
for ( int k = 0; k < num_ext; ++k ) for ( int k = 0; k < num_ext; ++k )
{ {
unsigned char *pBuffer = 0; unsigned char *pBuffer = 0;
int length = 0; uint length = 0;
X509_EXTENSION* ex = X509_get_ext(pTemp, k); X509_EXTENSION* ex = X509_get_ext(pTemp, k);
if (ex) if (ex)
@ -283,7 +296,7 @@ refine connection SSL_Conn += {
ASN1_STRING *pString = X509_EXTENSION_get_data(ex); ASN1_STRING *pString = X509_EXTENSION_get_data(ex);
length = ASN1_STRING_to_UTF8(&pBuffer, pString); length = ASN1_STRING_to_UTF8(&pBuffer, pString);
//i2t_ASN1_OBJECT(&pBuffer, length, obj) //i2t_ASN1_OBJECT(&pBuffer, length, obj)
// printf("extension length: %u\n", length);
// -1 indicates an error. // -1 indicates an error.
if ( length < 0 ) if ( length < 0 )
continue; continue;
@ -442,6 +455,10 @@ refine typeattr Handshake += &let {
proc : bool = $context.connection.proc_handshake(this, rec.is_orig); 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 { refine typeattr UnknownRecord += &let {
proc : bool = $context.connection.proc_unknown_record(rec); proc : bool = $context.connection.proc_unknown_record(rec);
}; };

View file

@ -61,17 +61,10 @@ type RecordText(rec: SSLRecord) = case $context.connection.state() of {
-> plaintext : PlaintextRecord(rec); -> 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 { type PlaintextRecord(rec: SSLRecord) = case rec.content_type of {
CHANGE_CIPHER_SPEC -> ch_cipher : ChangeCipherSpec(rec); CHANGE_CIPHER_SPEC -> ch_cipher : ChangeCipherSpec(rec);
ALERT -> alert : Alert(rec); ALERT -> alert : Alert(rec);
HANDSHAKE -> handshake : PossibleEncryptedHandshake(rec); HANDSHAKE -> handshake : Handshake(rec);
APPLICATION_DATA -> app_data : ApplicationData(rec); APPLICATION_DATA -> app_data : ApplicationData(rec);
V2_ERROR -> v2_error : V2Error(rec); V2_ERROR -> v2_error : V2Error(rec);
V2_CLIENT_HELLO -> v2_client_hello : V2ClientHello(rec); V2_CLIENT_HELLO -> v2_client_hello : V2ClientHello(rec);
@ -260,18 +253,19 @@ enum AnalyzerState {
###################################################################### ######################################################################
enum HandshakeType { enum HandshakeType {
HELLO_REQUEST = 0, HELLO_REQUEST = 0,
CLIENT_HELLO = 1, CLIENT_HELLO = 1,
SERVER_HELLO = 2, SERVER_HELLO = 2,
CERTIFICATE = 11, SESSION_TICKET = 4, # RFC 5077
SERVER_KEY_EXCHANGE = 12, CERTIFICATE = 11,
CERTIFICATE_REQUEST = 13, SERVER_KEY_EXCHANGE = 12,
SERVER_HELLO_DONE = 14, CERTIFICATE_REQUEST = 13,
CERTIFICATE_VERIFY = 15, SERVER_HELLO_DONE = 14,
CLIENT_KEY_EXCHANGE = 16, CERTIFICATE_VERIFY = 15,
FINISHED = 20, CLIENT_KEY_EXCHANGE = 16,
CERTIFICATE_URL = 21, # RFC 3546 FINISHED = 20,
CERTIFICATE_STATUS = 22, # RFC 3546 CERTIFICATE_URL = 21, # RFC 3546
CERTIFICATE_STATUS = 22, # RFC 3546
}; };
%code{ %code{
@ -281,6 +275,7 @@ enum HandshakeType {
case HELLO_REQUEST: return string("HELLO_REQUEST"); case HELLO_REQUEST: return string("HELLO_REQUEST");
case CLIENT_HELLO: return string("CLIENT_HELLO"); case CLIENT_HELLO: return string("CLIENT_HELLO");
case SERVER_HELLO: return string("SERVER_HELLO"); case SERVER_HELLO: return string("SERVER_HELLO");
case SESSION_TICKET: return string("SESSION_TICKET");
case CERTIFICATE: return string("CERTIFICATE"); case CERTIFICATE: return string("CERTIFICATE");
case SERVER_KEY_EXCHANGE: return string("SERVER_KEY_EXCHANGE"); case SERVER_KEY_EXCHANGE: return string("SERVER_KEY_EXCHANGE");
case CERTIFICATE_REQUEST: return string("CERTIFICATE_REQUEST"); case CERTIFICATE_REQUEST: return string("CERTIFICATE_REQUEST");
@ -452,8 +447,7 @@ type V2ServerHello(rec: SSLRecord) = record {
cert_data : bytestring &length = cert_len; cert_data : bytestring &length = cert_len;
ciphers : uint24[ciph_len/3]; ciphers : uint24[ciph_len/3];
conn_id_data : bytestring &length = conn_id_len; conn_id_data : bytestring &length = conn_id_len;
} #&length = 8 + cert_len + ciph_len + conn_id_len, } &let {
&let {
state_changed : bool = state_changed : bool =
(session_id_hit > 0 ? (session_id_hit > 0 ?
$context.connection.transition(STATE_CLIENT_HELLO_RCVD, $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, # 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 { type Finished(rec: SSLRecord) = record {
cont : bytestring &restofdata &transient; cont : bytestring &restofdata &transient;
} &let { } &let {
@ -615,13 +609,17 @@ type Finished(rec: SSLRecord) = record {
$context.connection.lost_track(); $context.connection.lost_track();
}; };
type SessionTicketHandshake(rec: SSLRecord) = record {
ticket_lifetime_hint: uint32;
data: bytestring &restofdata;
};
###################################################################### ######################################################################
# V3 Handshake Protocol (7.) # V3 Handshake Protocol (7.)
###################################################################### ######################################################################
type UnknownHandshake(hs: Handshake, is_orig: bool) = record { type UnknownHandshake(hs: Handshake, is_orig: bool) = record {
cont : bytestring &restofdata &transient; data : bytestring &restofdata &transient;
} &let { } &let {
state_changed : bool = $context.connection.lost_track(); state_changed : bool = $context.connection.lost_track();
}; };
@ -631,19 +629,20 @@ type Handshake(rec: SSLRecord) = record {
length : uint24; length : uint24;
body : case msg_type of { body : case msg_type of {
HELLO_REQUEST -> hello_request : HelloRequest(rec); HELLO_REQUEST -> hello_request : HelloRequest(rec);
CLIENT_HELLO -> client_hello : ClientHello(rec); CLIENT_HELLO -> client_hello : ClientHello(rec);
SERVER_HELLO -> server_hello : ServerHello(rec); SERVER_HELLO -> server_hello : ServerHello(rec);
CERTIFICATE -> certificate : Certificate(rec); SESSION_TICKET -> session_ticket : SessionTicketHandshake(rec);
SERVER_KEY_EXCHANGE -> server_key_exchange : ServerKeyExchange(rec); CERTIFICATE -> certificate : Certificate(rec);
CERTIFICATE_REQUEST -> certificate_request : CertificateRequest(rec); SERVER_KEY_EXCHANGE -> server_key_exchange : ServerKeyExchange(rec);
SERVER_HELLO_DONE -> server_hello_done : ServerHelloDone(rec); CERTIFICATE_REQUEST -> certificate_request : CertificateRequest(rec);
CERTIFICATE_VERIFY -> certificate_verify : CertificateVerify(rec); SERVER_HELLO_DONE -> server_hello_done : ServerHelloDone(rec);
CLIENT_KEY_EXCHANGE -> client_key_exchange : ClientKeyExchange(rec); CERTIFICATE_VERIFY -> certificate_verify : CertificateVerify(rec);
FINISHED -> finished : Finished(rec); CLIENT_KEY_EXCHANGE -> client_key_exchange : ClientKeyExchange(rec);
CERTIFICATE_URL -> certificate_url : bytestring &restofdata &transient; FINISHED -> finished : Finished(rec);
CERTIFICATE_STATUS -> certificate_status : bytestring &restofdata &transient; CERTIFICATE_URL -> certificate_url : bytestring &restofdata &transient;
default -> unknown_handshake : UnknownHandshake(this, rec.is_orig); CERTIFICATE_STATUS -> certificate_status : bytestring &restofdata &transient;
default -> unknown_handshake : UnknownHandshake(this, rec.is_orig);
} &length = to_int()(length); } &length = to_int()(length);
}; };

View file

@ -3,6 +3,6 @@
#empty_field (empty) #empty_field (empty)
#unset_field - #unset_field -
#path notice #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 #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 string string addr addr port count string table[enum] table[count] interval bool string string string double double addr string subnet #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
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 - - 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 - -

View file

@ -3,7 +3,7 @@
#empty_field (empty) #empty_field (empty)
#unset_field - #unset_field -
#path notice #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 #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 string string addr addr port count string table[enum] table[count] interval bool string string string double double addr string subnet #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
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 - - 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 - -
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 - - 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 - -

View file

@ -3,6 +3,6 @@
#empty_field (empty) #empty_field (empty)
#unset_field - #unset_field -
#path notice #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 #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 string string addr addr port count string table[enum] table[count] interval bool string string string double double addr string subnet #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
1324314363.721823 - - - - - Test_Notice test notice! - - - - - worker-1 Notice::ACTION_LOG 6 3600.000000 F - - - - - - - - 1325633122.490990 - - - - - - Test_Notice test notice! - - - - - worker-1 Notice::ACTION_LOG 6 3600.000000 F - - - - - - - -

View file

@ -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>

View file

@ -3,6 +3,6 @@
#empty_field (empty) #empty_field (empty)
#unset_field - #unset_field -
#path notice #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 #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 string string addr addr port count string table[enum] table[count] interval bool string string string double double addr string subnet #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
1324314378.560010 - - - - - Test_Notice test notice! - - - - - worker-2 Notice::ACTION_LOG 6 3600.000000 F - - - - - - - - 1325633150.723248 - - - - - - Test_Notice test notice! - - - - - worker-2 Notice::ACTION_LOG 6 3600.000000 F - - - - - - - -

View file

@ -3,6 +3,6 @@
#empty_field (empty) #empty_field (empty)
#unset_field - #unset_field -
#path notice #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 #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 string string addr addr port count string table[enum] table[count] interval bool string string string double double #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
1324314387.663586 - - - - - Test_Notice test - - - - - bro Notice::ACTION_LOG 6 3600.000000 F - - - - - 1325633207.922993 - - - - - - Test_Notice test - - - - - bro Notice::ACTION_LOG 6 3600.000000 F - - - - -

View file

@ -3,7 +3,7 @@
# @TEST-EXEC: btest-bg-run proxy-2 BROPATH=$BROPATH:.. CLUSTER_NODE=proxy-2 bro %INPUT # @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-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-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 manager-1/.stdout
# @TEST-EXEC: btest-diff proxy-1/.stdout # @TEST-EXEC: btest-diff proxy-1/.stdout
# @TEST-EXEC: btest-diff proxy-2/.stdout # @TEST-EXEC: btest-diff proxy-2/.stdout

View file

@ -1,7 +1,7 @@
# #
# @TEST-EXEC: btest-bg-run receiver bro -b ../receiver.bro # @TEST-EXEC: btest-bg-run receiver bro -b ../receiver.bro
# @TEST-EXEC: btest-bg-run sender bro -b ../sender.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 # 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 # @TEST-EXEC: egrep -v 'pid|socket buffer size' sender/communication.log >send.log

View file

@ -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 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 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-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 # @TEST-EXEC: btest-diff controllee/.stdout
redef Communication::nodes = { redef Communication::nodes = {

View file

@ -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 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-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 # @TEST-EXEC: btest-diff controller/.stdout
redef Communication::nodes = { redef Communication::nodes = {

View file

@ -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 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-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 = { redef Communication::nodes = {
# We're waiting for connections from this host for control. # We're waiting for connections from this host for control.

View file

@ -1,7 +1,7 @@
# #
# @TEST-EXEC: btest-bg-run sender bro --pseudo-realtime %INPUT ../sender.bro # @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-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: btest-diff receiver/test.log
# @TEST-EXEC: cmp receiver/test.log sender/test.log # @TEST-EXEC: cmp receiver/test.log sender/test.log

View file

@ -3,7 +3,7 @@
# @TEST-EXEC: sleep 1 # @TEST-EXEC: sleep 1
# @TEST-EXEC: btest-bg-run receiver bro --pseudo-realtime %INPUT ../receiver.bro # @TEST-EXEC: btest-bg-run receiver bro --pseudo-realtime %INPUT ../receiver.bro
# @TEST-EXEC: sleep 1 # @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.log
# @TEST-EXEC: btest-diff sender/test.failure.log # @TEST-EXEC: btest-diff sender/test.failure.log
# @TEST-EXEC: btest-diff sender/test.success.log # @TEST-EXEC: btest-diff sender/test.success.log

View file

@ -3,7 +3,7 @@
# @TEST-EXEC: sleep 1 # @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-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-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-EXEC: btest-diff manager-1/metrics.log
@TEST-START-FILE cluster-layout.bro @TEST-START-FILE cluster-layout.bro

View file

@ -3,7 +3,7 @@
# @TEST-EXEC: sleep 1 # @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-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-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-EXEC: btest-diff manager-1/notice.log
@TEST-START-FILE cluster-layout.bro @TEST-START-FILE cluster-layout.bro

View file

@ -2,7 +2,7 @@
# @TEST-EXEC: btest-bg-run proxy-1 BROPATH=$BROPATH:.. CLUSTER_NODE=proxy-1 bro %INPUT # @TEST-EXEC: btest-bg-run proxy-1 BROPATH=$BROPATH:.. CLUSTER_NODE=proxy-1 bro %INPUT
# @TEST-EXEC: sleep 1 # @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-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-EXEC: btest-diff manager-1/notice.log
@TEST-START-FILE cluster-layout.bro @TEST-START-FILE cluster-layout.bro

View 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"]);
}

View file

@ -3,7 +3,7 @@
# @TEST-EXEC: sleep 1 # @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-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-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-EXEC: btest-diff manager-1/notice.log
@TEST-START-FILE cluster-layout.bro @TEST-START-FILE cluster-layout.bro

View file

@ -22,7 +22,16 @@ files_cwd=`ls $@`
files_baseline=`cd $TEST_BASELINE && ls $@` files_baseline=`cd $TEST_BASELINE && ls $@`
for i in `echo $files_cwd $files_baseline | sort | uniq`; do 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 if ! btest-diff $i; then
echo "" >>$diag echo "" >>$diag
echo "#### btest-diff $i" >>$diag echo "#### btest-diff $i" >>$diag

View file

@ -5,3 +5,4 @@
`dirname $0`/diff-remove-timestamps \ `dirname $0`/diff-remove-timestamps \
| `dirname $0`/diff-remove-uids \ | `dirname $0`/diff-remove-uids \
| `dirname $0`/diff-remove-mime-types \ | `dirname $0`/diff-remove-mime-types \
| `dirname $0`/diff-remove-x509-names \

View 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;
}