DPD: change handling of pre-confirmation violations, remove max_violations

This commit revamps the handling of analyzer violations that happen
before an analyzer confirms the protocol.

The current state is that an analyzer is disabled after 5 violations, if
it has not been confirmed. If it has been confirmed, it is disabled
after a single violation.

The reason for this is a historic mistake. In Zeek up to versions 1.5,
analyzers were unconditianally removed when they raised the first
protocol violation.

When this script was ported to the new layout for Zeek 2.0 in
b4b990cfb5, a logic error was introduced
that caused analyzers to no longer be disabled if they were not
confirmed.

This was the state for ~8 years, till the DPD::max_violations options
was added, which instates the current approach of disabling unconfirmed
analyzers after 5 violations. Sadly, there is not much discussion about
this change - from my hazy memory, I think this was discovered during
performance tests and the new behavior was added without checking into
the history of previous changes.

This commit reinstates the originally intended behavior of DPD. When an
analyzer that has not been confirmed raises a protocol violation, it is
immediately removed from the connection. This also makes a lot of sense
- this allows the analyzer to be in a "tasting" phase at the beginning
of the connection, and to error out quickly once it realizes that it was
attached to a connection not containing the desired protocol.

This change also removes the DPD::max_violations option, as it no longer
serves any purpose after this change. (In practice, the option remains
with an &deprecated warning, but it is no longer used for anything).

There are relatively minimal test-baseline changes due to this; they are
mostly triggered by the removal of the data structure and by less
analyzer errors being thrown, as unconfirmed analyzers are disabled
after the first error.
This commit is contained in:
Johanna Amann 2025-01-21 14:59:03 +00:00
parent e6ed61c47a
commit c72c1cba6f
27 changed files with 2184 additions and 2518 deletions

View file

@ -26,14 +26,8 @@ export {
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;
## Deprecated, please see https://github.com/zeek/zeek/pull/4200 for details
option max_violations: table[Analyzer::Tag] of count = table() &deprecated="Remove in v8.1: This has become non-functional in Zeek 7.2, see PR #4200" &default = 5;
## Analyzers which you don't want to throw
option ignore_violations: set[Analyzer::Tag] = set();
@ -45,7 +39,6 @@ export {
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();
@ -127,24 +120,7 @@ event analyzer_violation_info(atype: AllAnalyzers::Tag, info: AnalyzerViolationI
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);
}
disable_analyzer(c$id, aid, F);
}
event analyzer_violation_info(atype: AllAnalyzers::Tag, info: AnalyzerViolationInfo ) &priority=-5

View file

@ -214,10 +214,5 @@ hook Analyzer::disabling_analyzer(c: connection, atype: AllAnalyzers::Tag, aid:
populate_from_conn(rec, c);
if ( c?$dpd_state && aid in c$dpd_state$violations )
{
rec$failure_data = fmt("Disabled after %d violations", c$dpd_state$violations[aid]);
}
Log::write(LOG, rec);
}