zeek/scripts/base/frameworks/analyzer/dpd.zeek
Arne Welzel 7ed6cbeee5 Make connection$service_violation a set[string]
To stay consistent with connection$service.
2022-09-20 23:07:26 +02:00

124 lines
3.6 KiB
Text

##! Activates port-independent protocol detection and selectively disables
##! analyzers if protocol violations occur.
module DPD;
export {
## Add the DPD logging stream identifier.
redef enum Log::ID += { LOG };
## A default logging policy hook for the stream.
global log_policy: Log::PolicyHook;
## The record type defining the columns to log in the DPD logging stream.
type Info: record {
## Timestamp for when protocol analysis failed.
ts: time &log;
## Connection unique ID.
uid: string &log;
## Connection ID containing the 4-tuple which identifies endpoints.
id: conn_id &log;
## Transport protocol for the violation.
proto: transport_proto &log;
## The analyzer that generated the violation.
analyzer: string &log;
## The textual reason for the analysis failure.
failure_reason: string &log;
};
## Ongoing DPD state tracking information.
type State: record {
## Current number of protocol violations seen per analyzer instance.
violations: table[count] of count;
};
## Number of protocol violations to tolerate before disabling an analyzer.
option max_violations: table[Analyzer::Tag] of count = table() &default = 5;
## Analyzers which you don't want to throw
option ignore_violations: set[Analyzer::Tag] = set();
## Ignore violations which go this many bytes into the connection.
## Set to 0 to never ignore protocol violations.
option ignore_violations_after = 10 * 1024;
}
redef record connection += {
dpd: Info &optional;
dpd_state: State &optional;
## The set of services (analyzers) for which Zeek has observed a
## violation after the same service had previously been confirmed.
service_violation: set[string] &default=set();
};
event zeek_init() &priority=5
{
Log::create_stream(DPD::LOG, [$columns=Info, $path="dpd", $policy=log_policy]);
}
event analyzer_confirmation(c: connection, atype: AllAnalyzers::Tag, aid: count) &priority=10
{
local analyzer = Analyzer::name(atype);
add c$service[analyzer];
}
event analyzer_violation(c: connection, atype: AllAnalyzers::Tag, aid: count,
reason: string) &priority=10
{
local analyzer = Analyzer::name(atype);
# If the service hasn't been confirmed yet, don't generate a log message
# for the protocol violation.
if ( analyzer !in c$service )
return;
delete c$service[analyzer];
add c$service_violation[analyzer];
local info: Info;
info$ts=network_time();
info$uid=c$uid;
info$id=c$id;
info$proto=get_port_transport_proto(c$id$orig_p);
info$analyzer=analyzer;
info$failure_reason=reason;
c$dpd = info;
}
event analyzer_violation(c: connection, atype: AllAnalyzers::Tag, aid: count, reason: string) &priority=5
{
if ( atype in ignore_violations )
return;
local size = c$orig$size + c$resp$size;
if ( ignore_violations_after > 0 && size > ignore_violations_after )
return;
if ( ! c?$dpd_state )
{
local s: State;
c$dpd_state = s;
}
if ( aid in c$dpd_state$violations )
++c$dpd_state$violations[aid];
else
c$dpd_state$violations[aid] = 1;
if ( c?$dpd || c$dpd_state$violations[aid] > max_violations[atype] )
{
# Disable an analyzer we've previously confirmed, but is now in
# violation, or else any analyzer in excess of the max allowed
# violations, regardless of whether it was previously confirmed.
disable_analyzer(c$id, aid, F);
}
}
event analyzer_violation(c: connection, atype: AllAnalyzers::Tag, aid: count,
reason: string) &priority=-5
{
if ( c?$dpd )
{
Log::write(DPD::LOG, c$dpd);
delete c$dpd;
}
}