Introduce analyzer-failed.log, as a replacement for dpd.log

Analyzer-failed.log is, essentially, the replacement for dpd.log. The
name should make more sense, as it does now log analyzer failures. For
protocol analyzers specifically, these are failures that lead to the
analyzer being disabled.
This commit is contained in:
Johanna Amann 2025-04-09 15:25:01 +01:00
parent c55e21da71
commit 8c814fa88c
5 changed files with 130 additions and 31 deletions

View file

@ -1,2 +1,3 @@
@load ./main
@load ./dpd
@load ./analyzer-failed-log

View file

@ -0,0 +1,88 @@
##! Logging analyzer violations into analyzer-failed.log
@load base/frameworks/logging
@load ./main
module Analyzer::Logging;
export {
## Add the analyzer logging stream identifier.
redef enum Log::ID += { LOG };
## The record type defining the columns to log in the analyzer-failed logging stream.
type Info: record {
## Timestamp of the violation.
ts: time &log;
## The kind of analyzer involved. Currently "packet", "file"
## or "protocol".
analyzer_kind: string &log;
## The name of the analyzer as produced by :zeek:see:`Analyzer::name`
## for the analyzer's tag.
analyzer_name: string &log;
## Connection UID if available.
uid: string &log &optional;
## File UID if available.
fuid: string &log &optional;
## Connection identifier if available
id: conn_id &log &optional;
## Failure or violation reason, if available.
failure_reason: string &log;
## Data causing failure or violation if available. Truncated
## to :zeek:see:`Analyzer::Logging::failure_data_max_size`.
failure_data: string &log &optional;
};
## If a violation contains information about the data causing it,
## include at most this many bytes of it in the log.
option failure_data_max_size = 40;
## An event that can be handled to access the :zeek:type:`Analyzer::Logging::Info`
## record as it is sent on to the logging framework.
global log_analyzer_failed: event(rec: Info);
## A default logging policy hook for the stream.
global log_policy: Log::PolicyHook;
}
event zeek_init() &priority=5
{
Log::create_stream(LOG, [$columns=Info, $path="analyzer-failed", $ev=log_analyzer_failed, $policy=log_policy]);
}
event analyzer_failed(ts: time, atype: AllAnalyzers::Tag, info: AnalyzerViolationInfo)
{
local rec = Info(
$ts=ts,
$analyzer_kind=Analyzer::kind(atype),
$analyzer_name=Analyzer::name(atype),
$failure_reason=info$reason
);
if ( info?$c )
{
rec$id = info$c$id;
rec$uid = info$c$uid;
}
if ( info?$f )
{
rec$fuid = info$f$id;
# If the confirmation didn't have a connection, but the
# fa_file object has exactly one, use it.
if ( ! rec?$uid && info$f?$conns && |info$f$conns| == 1 )
{
for ( _, c in info$f$conns )
{
rec$id = c$id;
rec$uid = c$uid;
}
}
}
if ( info?$data )
rec$failure_data = info$data;
Log::write(LOG, rec);
}

View file

@ -1,13 +1,15 @@
##! Disables analyzers if protocol violations occur, and add service information
##! to connection log.
@load ./main
module DPD;
export {
## 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
## Analyzers which you don't want to remove on violations.
option ignore_violations: set[Analyzer::Tag] = set();
## Ignore violations which go this many bytes into the connection.
@ -43,7 +45,7 @@ event analyzer_confirmation_info(atype: AllAnalyzers::Tag, info: AnalyzerConfirm
}
## Remove failed analyzers from service field and add them to c$service_violation
event analyzer_violation_info(atype: AllAnalyzers::Tag, info: AnalyzerViolationInfo) &priority=10
event analyzer_failed(ts: time, atype: AllAnalyzers::Tag, info: AnalyzerViolationInfo)
{
if ( ! is_protocol_analyzer(atype) && ! is_packet_analyzer(atype) )
return;
@ -64,12 +66,17 @@ event analyzer_violation_info(atype: AllAnalyzers::Tag, info: AnalyzerViolationI
# if statement is separate, to allow repeated removal of service, in case there are several
# confirmation and violation events
if ( analyzer in c$service_violation )
return;
if ( analyzer !in c$service_violation )
add c$service_violation[analyzer];
}
# add "-service" to the list of services on removal due to violation, if analyzer was confirmed before
if ( track_removed_services_in_connection && Analyzer::name(atype) in c$service )
{
local rname = cat("-", Analyzer::name(atype));
if ( rname !in c$service )
add c$service[rname];
}
}
event analyzer_violation_info(atype: AllAnalyzers::Tag, info: AnalyzerViolationInfo ) &priority=5
{
@ -90,13 +97,7 @@ event analyzer_violation_info(atype: AllAnalyzers::Tag, info: AnalyzerViolationI
local disabled = disable_analyzer(c$id, aid, F);
# add "-service" to the list of services on removal due to violation, if analyzer was confirmed before
if ( track_removed_services_in_connection && disabled && Analyzer::name(atype) in c$service )
{
local rname = cat("-", Analyzer::name(atype));
if ( rname !in c$service )
add c$service[rname];
}
# If no one objected to the removal, send failed event
event analyzer_failed(network_time(), atype, info);
}

View file

@ -88,6 +88,15 @@ export {
## Returns: The analyzer name corresponding to the tag.
global name: function(tag: Analyzer::Tag) : string;
## Translates an analyzer type to a string with the analyzer's type.
##
## Possible values are "protocol", "packet", "file", or "unknown".
##
## tag: The analyzer tag.
##
## Returns: The analyzer kind corresponding to the tag.
global kind: function(tag: Analyzer::Tag) : string;
## Check whether the given analyzer name exists.
##
## This can be used before calling :zeek:see:`Analyzer::get_tag` to
@ -246,6 +255,19 @@ function name(atype: AllAnalyzers::Tag) : string
return __name(atype);
}
function kind(atype: AllAnalyzers::Tag): string
{
if ( is_protocol_analyzer(atype) )
return "protocol";
else if ( is_packet_analyzer(atype) )
return "packet";
else if ( is_file_analyzer(atype) )
return "file";
Reporter::warning(fmt("Unknown kind of analyzer %s", atype));
return "unknown";
}
function has_tag(name: string): bool
{
return __has_tag(name);

View file

@ -1,4 +1,4 @@
##! Logging analyzer confirmations and violations into analyzer-debug.log
#! Logging analyzer confirmations and violations into analyzer-debug.log
@load base/frameworks/config
@load base/frameworks/logging
@ -117,19 +117,6 @@ event zeek_init() &priority=5
}
function analyzer_kind(atype: AllAnalyzers::Tag): string
{
if ( is_protocol_analyzer(atype) )
return "protocol";
else if ( is_packet_analyzer(atype) )
return "packet";
else if ( is_file_analyzer(atype) )
return "file";
Reporter::warning(fmt("Unknown kind of analyzer %s", atype));
return "unknown";
}
function populate_from_conn(rec: Info, c: connection)
{
rec$id = c$id;
@ -159,7 +146,7 @@ event analyzer_confirmation_info(atype: AllAnalyzers::Tag, info: AnalyzerConfirm
local rec = Info(
$ts=network_time(),
$cause="confirmation",
$analyzer_kind=analyzer_kind(atype),
$analyzer_kind=Analyzer::kind(atype),
$analyzer_name=Analyzer::name(atype),
);
@ -180,7 +167,7 @@ event analyzer_violation_info(atype: AllAnalyzers::Tag, info: AnalyzerViolationI
local rec = Info(
$ts=network_time(),
$cause="violation",
$analyzer_kind=analyzer_kind(atype),
$analyzer_kind=Analyzer::kind(atype),
$analyzer_name=Analyzer::name(atype),
$failure_reason=info$reason,
);
@ -210,7 +197,7 @@ hook Analyzer::disabling_analyzer(c: connection, atype: AllAnalyzers::Tag, aid:
local rec = Info(
$ts=network_time(),
$cause="disabled",
$analyzer_kind=analyzer_kind(atype),
$analyzer_kind=Analyzer::kind(atype),
$analyzer_name=Analyzer::name(atype),
);