mirror of
https://github.com/zeek/zeek.git
synced 2025-10-09 10:08:20 +00:00
Fixing SMTP state tracking.
This fixes the case that an SMTP session has multiple mails sent from the originator but we miss the server's response (e.g., because we don't see server side packets at all).
This commit is contained in:
parent
c289a2743b
commit
9301ef5a4f
6 changed files with 73 additions and 51 deletions
|
@ -58,31 +58,31 @@ export {
|
|||
## Indicates if client activity has been seen, but not yet logged.
|
||||
has_client_activity: bool &default=F;
|
||||
};
|
||||
|
||||
|
||||
type State: record {
|
||||
helo: string &optional;
|
||||
## Count the number of individual messages transmitted during
|
||||
## this SMTP session. Note, this is not the number of
|
||||
## recipients, but the number of message bodies transferred.
|
||||
messages_transferred: count &default=0;
|
||||
|
||||
|
||||
pending_messages: set[Info] &optional;
|
||||
};
|
||||
|
||||
|
||||
## Direction to capture the full "Received from" path.
|
||||
## REMOTE_HOSTS - only capture the path until an internal host is found.
|
||||
## LOCAL_HOSTS - only capture the path until the external host is discovered.
|
||||
## ALL_HOSTS - always capture the entire path.
|
||||
## NO_HOSTS - never capture the path.
|
||||
const mail_path_capture = ALL_HOSTS &redef;
|
||||
|
||||
|
||||
## Create an extremely shortened representation of a log line.
|
||||
global describe: function(rec: Info): string;
|
||||
|
||||
global log_smtp: event(rec: Info);
|
||||
}
|
||||
|
||||
redef record connection += {
|
||||
redef record connection += {
|
||||
smtp: Info &optional;
|
||||
smtp_state: State &optional;
|
||||
};
|
||||
|
@ -95,7 +95,7 @@ event bro_init() &priority=5
|
|||
Log::create_stream(SMTP::LOG, [$columns=SMTP::Info, $ev=log_smtp]);
|
||||
Analyzer::register_for_ports(Analyzer::ANALYZER_SMTP, ports);
|
||||
}
|
||||
|
||||
|
||||
function find_address_in_smtp_header(header: string): string
|
||||
{
|
||||
local ips = find_ip_addresses(header);
|
||||
|
@ -116,17 +116,17 @@ function new_smtp_log(c: connection): Info
|
|||
l$ts=network_time();
|
||||
l$uid=c$uid;
|
||||
l$id=c$id;
|
||||
# The messages_transferred count isn't incremented until the message is
|
||||
# The messages_transferred count isn't incremented until the message is
|
||||
# finished so we need to increment the count by 1 here.
|
||||
l$trans_depth = c$smtp_state$messages_transferred+1;
|
||||
|
||||
|
||||
if ( c$smtp_state?$helo )
|
||||
l$helo = c$smtp_state$helo;
|
||||
|
||||
|
||||
# The path will always end with the hosts involved in this connection.
|
||||
# The lower values in the vector are the end of the path.
|
||||
l$path = vector(c$id$resp_h, c$id$orig_h);
|
||||
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
|
@ -134,7 +134,7 @@ function set_smtp_session(c: connection)
|
|||
{
|
||||
if ( ! c?$smtp_state )
|
||||
c$smtp_state = [];
|
||||
|
||||
|
||||
if ( ! c?$smtp )
|
||||
c$smtp = new_smtp_log(c);
|
||||
}
|
||||
|
@ -142,17 +142,17 @@ function set_smtp_session(c: connection)
|
|||
function smtp_message(c: connection)
|
||||
{
|
||||
if ( c$smtp$has_client_activity )
|
||||
{
|
||||
Log::write(SMTP::LOG, c$smtp);
|
||||
c$smtp = new_smtp_log(c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
event smtp_request(c: connection, is_orig: bool, command: string, arg: string) &priority=5
|
||||
{
|
||||
set_smtp_session(c);
|
||||
local upper_command = to_upper(command);
|
||||
|
||||
if ( upper_command != "QUIT" )
|
||||
c$smtp$has_client_activity = T;
|
||||
|
||||
if ( upper_command == "HELO" || upper_command == "EHLO" )
|
||||
{
|
||||
c$smtp_state$helo = arg;
|
||||
|
@ -161,23 +161,28 @@ event smtp_request(c: connection, is_orig: bool, command: string, arg: string) &
|
|||
|
||||
else if ( upper_command == "RCPT" && /^[tT][oO]:/ in arg )
|
||||
{
|
||||
if ( ! c$smtp?$rcptto )
|
||||
if ( ! c$smtp?$rcptto )
|
||||
c$smtp$rcptto = set();
|
||||
add c$smtp$rcptto[split1(arg, /:[[:blank:]]*/)[2]];
|
||||
c$smtp$has_client_activity = T;
|
||||
}
|
||||
|
||||
else if ( upper_command == "MAIL" && /^[fF][rR][oO][mM]:/ in arg )
|
||||
{
|
||||
# Flush last message in case we didn't see the server's acknowledgement.
|
||||
smtp_message(c);
|
||||
|
||||
local partially_done = split1(arg, /:[[:blank:]]*/)[2];
|
||||
c$smtp$mailfrom = split1(partially_done, /[[:blank:]]?/)[1];
|
||||
c$smtp$has_client_activity = T;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
event smtp_reply(c: connection, is_orig: bool, code: count, cmd: string,
|
||||
msg: string, cont_resp: bool) &priority=5
|
||||
{
|
||||
set_smtp_session(c);
|
||||
|
||||
|
||||
# This continually overwrites, but we want the last reply,
|
||||
# so this actually works fine.
|
||||
c$smtp$last_reply = fmt("%d %s", code, msg);
|
||||
|
@ -198,7 +203,6 @@ event smtp_reply(c: connection, is_orig: bool, code: count, cmd: string,
|
|||
event mime_one_header(c: connection, h: mime_header_rec) &priority=5
|
||||
{
|
||||
if ( ! c?$smtp ) return;
|
||||
c$smtp$has_client_activity = T;
|
||||
|
||||
if ( h$name == "MESSAGE-ID" )
|
||||
c$smtp$msg_id = h$value;
|
||||
|
@ -241,19 +245,19 @@ event mime_one_header(c: connection, h: mime_header_rec) &priority=5
|
|||
if ( 1 in addresses )
|
||||
c$smtp$x_originating_ip = to_addr(addresses[1]);
|
||||
}
|
||||
|
||||
|
||||
else if ( h$name == "X-MAILER" ||
|
||||
h$name == "USER-AGENT" ||
|
||||
h$name == "X-USER-AGENT" )
|
||||
c$smtp$user_agent = h$value;
|
||||
}
|
||||
|
||||
# This event handler builds the "Received From" path by reading the
|
||||
|
||||
# This event handler builds the "Received From" path by reading the
|
||||
# headers in the mail
|
||||
event mime_one_header(c: connection, h: mime_header_rec) &priority=3
|
||||
{
|
||||
# If we've decided that we're done watching the received headers for
|
||||
# whatever reason, we're done. Could be due to only watching until
|
||||
# whatever reason, we're done. Could be due to only watching until
|
||||
# local addresses are seen in the received from headers.
|
||||
if ( ! c?$smtp || h$name != "RECEIVED" || ! c$smtp$process_received_from )
|
||||
return;
|
||||
|
@ -263,7 +267,7 @@ event mime_one_header(c: connection, h: mime_header_rec) &priority=3
|
|||
return;
|
||||
local ip = to_addr(text_ip);
|
||||
|
||||
if ( ! addr_matches_host(ip, mail_path_capture) &&
|
||||
if ( ! addr_matches_host(ip, mail_path_capture) &&
|
||||
! Site::is_private_addr(ip) )
|
||||
{
|
||||
c$smtp$process_received_from = F;
|
||||
|
@ -280,8 +284,11 @@ event connection_state_remove(c: connection) &priority=-5
|
|||
|
||||
event smtp_starttls(c: connection) &priority=5
|
||||
{
|
||||
if ( c?$smtp )
|
||||
if ( c?$smtp )
|
||||
{
|
||||
c$smtp$tls = T;
|
||||
c$smtp$has_client_activity = T;
|
||||
}
|
||||
}
|
||||
|
||||
function describe(rec: Info): string
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue