zeek/testing/btest/scripts/base/protocols/ssl/prevent-disable-analyzer.test
Arne Welzel abb7f9a509 Introduce global disabling_analyzer() hook to veto disable_analyzer()
This hook can be used to coordinate disabling an analyzer for a given
connection. The contract is simple: Any script can veto a disable_analyzer()
call by breaking from this hook. The decision is local to the script taking
into account any state attached to the connection object or script specific
state stored elsewhere.
A script breaking from the hook takes over the responsibility to call
disable_analyzer() at a later point when it finds the condition due to which
it vetoed fulfilled (which may be never).

Signature:

    disabling_analyzer: hook(c: connection, atype: AllAnalyzers::Tag, aid: count);

Example use-cases are keeping the SSL analyzer enabled for finger-printing
until a certain amount of bytes or packets have been transferred or
similarly the connection duration exceed a certain threshold.

Other example use-cases might be keeping analyzers for SSH, RDP or SSL
enabled for connections from specific subnets.

It's a bit quirky as it makes disable_analyzer() a maybe operation. While log
policy hooks and/or the notice hook have similar semantics, they are not as
stateful. It still seems like a quite powerful primitive.

The disable_analyzer() call in dpd/main.zeek may motivate the addition of a
force flag as a follow-up for situations where the caller "knows better" or
absolutely wants to override.

Closes #1678 #1593.
2022-08-11 09:40:36 +02:00

52 lines
1.6 KiB
Text

# @TEST-DOC: Implement disabling_analyzer hook to keep the SSL analyzer enabled for a bit longer.
# @TEST-EXEC: zeek -b -C -r $TRACES/tls/tls1.2.trace %INPUT
# @TEST-EXEC: btest-diff .stdout
@load base/protocols/ssl
# This is the default, but make it explicit.
redef SSL::disable_analyzer_after_detection = T;
redef record SSL::Info += {
encrypted_data: count &default=0;
};
# After how many ssl_encrypted_data events to disable the analyzer. The
# pcap triggers seven, the handshake is over after the first two.
global encrypted_data_wanted = 4;
# Prevent disabling the SSL analyzer for this connection until we've seen encrypted_data_wanted
# encrypted data events on it. Our ssl_encrypted_data event handler has the inverse condition.
hook disabling_analyzer(c: connection, atype: AllAnalyzers::Tag, aid: count)
{
print "disabling_analyzer", c$id, atype, aid;
if ( atype != Analyzer::ANALYZER_SSL || ! c?$ssl )
return;
if ( c$ssl$encrypted_data < encrypted_data_wanted )
{
print "preventing disabling_analyzer", c$id, atype, aid;
break;
}
print "allowing disabling_analyzer", c$id, atype, aid;
}
event ssl_established(c: connection)
{
print "established", c$id;
}
event analyzer_confirmation(c: connection, atype: AllAnalyzers::Tag, aid: count)
{
print "analyzer_confirmation", c$id, atype, aid;
}
event ssl_encrypted_data(c: connection, is_client: bool, record_version: count, content_type: count, length: count)
{
++c$ssl$encrypted_data;
print "encrypted_data", c$id, is_client, content_type, length, c$ssl$encrypted_data;
if ( c$ssl?$analyzer_id && c$ssl$encrypted_data >= encrypted_data_wanted )
disable_analyzer(c$id, c$ssl$analyzer_id);
}