##! 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. module KnownServices; redef enum Log::ID += { KNOWN_SERVICES }; export { type Info: record { ts: time &log; host: addr &log; port_num: port &log; port_proto: transport_proto &log; service: set[string] &log; done: bool &default=F; }; ## The hosts whose services should be tracked and logged. const asset_tracking = LOCAL_HOSTS &redef; global known_services: set[addr, port] &create_expire=1day &synchronized; global log_known_services: event(rec: Info); } redef record connection += { known_services_done: bool &default=F; known_services_watch: bool &default=F; }; event bro_init() { Log::create_stream(KNOWN_SERVICES, [$columns=Info, $ev=log_known_services]); } function known_services_done(c: connection) { local id = c$id; if ( ! c$known_services_done && get_port_transport_proto(id$resp_p) == tcp && addr_matches_host(id$resp_h, asset_tracking) && [id$resp_h, id$resp_p] !in known_services && "ftp-data" !in c$service ) # don't include ftp data sessions { local i: Info; i$ts=c$start_time; i$host=id$resp_h; i$port_num=id$resp_p; i$port_proto=get_port_transport_proto(id$resp_p); i$service=c$service; add known_services[id$resp_h, id$resp_p]; Log::write(KNOWN_SERVICES, i); c$known_services_done = T; } } event protocol_confirmation(c: connection, atype: count, aid: count) &priority=-5 { known_services_done(c); } event connection_established(c: connection) { c$known_services_watch=T; } # Handle the connection ending in case no protocol was ever detected. event connection_state_remove(c: connection) &priority=-5 { if ( c$known_services_watch ) known_services_done(c); }