zeek/scripts/policy/protocols/conn/known-services.bro

100 lines
3.2 KiB
Text

##! This script logs and tracks services. In the case of this script, a service
##! is defined as an IP address and port which has responded to and fully
##! completed a TCP handshake with another host. If a protocol is detected
##! during the session, the protocol will also be logged.
@load base/utils/directions-and-hosts
module Known;
export {
## The known-services logging stream identifier.
redef enum Log::ID += { SERVICES_LOG };
## The record type which contains the column fields of the known-services
## log.
type ServicesInfo: record {
## The time at which the service was detected.
ts: time &log;
## The host address on which the service is running.
host: addr &log;
## The port number on which the service is running.
port_num: port &log;
## The transport-layer protocol which the service uses.
port_proto: transport_proto &log;
## A set of protocols that match the service's connection payloads.
service: set[string] &log;
};
## The hosts whose services should be tracked and logged.
## See :bro:type:`Host` for possible choices.
const service_tracking = LOCAL_HOSTS &redef;
## Tracks the set of daily-detected services for preventing the logging
## of duplicates, but can also be inspected by other scripts for
## different purposes.
global known_services: set[addr, port] &create_expire=1day &synchronized;
## Event that can be handled to access the :bro:type:`Known::ServicesInfo`
## record as it is sent on to the logging framework.
global log_known_services: event(rec: ServicesInfo);
}
redef record connection += {
# This field is to indicate whether or not the processing for detecting
# and logging the service for this connection is complete.
known_services_done: bool &default=F;
};
event bro_init() &priority=5
{
Log::create_stream(Known::SERVICES_LOG, [$columns=ServicesInfo,
$ev=log_known_services]);
}
event log_it(ts: time, a: addr, p: port, services: set[string])
{
if ( [a, p] !in known_services )
{
add known_services[a, p];
local i: ServicesInfo;
i$ts=ts;
i$host=a;
i$port_num=p;
i$port_proto=get_port_transport_proto(p);
i$service=services;
Log::write(Known::SERVICES_LOG, i);
}
}
function known_services_done(c: connection)
{
local id = c$id;
c$known_services_done = T;
if ( ! addr_matches_host(id$resp_h, service_tracking) ||
"ftp-data" in c$service || # don't include ftp data sessions
("DNS" in c$service && c$resp$size == 0) ) # for dns, require that the server talks.
return;
# If no protocol was detected, wait a short
# time before attempting to log in case a protocol is detected
# on another connection.
if ( |c$service| == 0 )
schedule 5min { log_it(network_time(), id$resp_h, id$resp_p, c$service) };
else
event log_it(network_time(), id$resp_h, id$resp_p, c$service);
}
event protocol_confirmation(c: connection, atype: count, aid: count) &priority=-5
{
known_services_done(c);
}
# Handle the connection ending in case no protocol was ever detected.
event connection_state_remove(c: connection) &priority=-5
{
if ( ! c$known_services_done && c$resp$state == TCP_ESTABLISHED )
known_services_done(c);
}