diff --git a/policy.old/conn.bro b/policy.old/conn.bro deleted file mode 100644 index 5c1b06eccc..0000000000 --- a/policy.old/conn.bro +++ /dev/null @@ -1,423 +0,0 @@ -# $Id: conn.bro 6782 2009-06-28 02:19:03Z vern $ - -@load notice -@load hot -@load port-name -@load netstats -@load conn-id - -redef enum Notice += { - SensitiveConnection, # connection marked "hot" -}; - -const conn_closed = { TCP_CLOSED, TCP_RESET }; - -global have_FTP = F; # if true, we've loaded ftp.bro -global have_SMTP = F; # if true, we've loaded smtp.bro -global is_ftp_data_conn: function(c: connection): bool; - -# Whether to include connection state history in the logs generated -# by record_connection. -const record_state_history = F &redef; - -# Whether to translate the local address in SensitiveConnection notices -# to a hostname. Meant as a demonstration of the "when" construct. -const xlate_hot_local_addr = F &redef; - -# Whether to use DPD for generating the service field in the summaries. -# Default off, because it changes the format of conn.log in a way -# potentially incompatible with existing scripts. -const dpd_conn_logs = F &redef; - -# Maps a given port on a given server's address to an RPC service. -# If we haven't loaded portmapper.bro, then it will be empty -# (and, ideally, queries to it would be optimized away ...). -global RPC_server_map: table[addr, port] of string; - -const conn_file = open_log_file("conn") &redef; - -function conn_state(c: connection, trans: transport_proto): string - { - local os = c$orig$state; - local rs = c$resp$state; - - local o_inactive = os == TCP_INACTIVE || os == TCP_PARTIAL; - local r_inactive = rs == TCP_INACTIVE || rs == TCP_PARTIAL; - - if ( trans == tcp ) - { - if ( rs == TCP_RESET ) - { - if ( os == TCP_SYN_SENT || os == TCP_SYN_ACK_SENT || - (os == TCP_RESET && - c$orig$size == 0 && c$resp$size == 0) ) - return "REJ"; - else if ( o_inactive ) - return "RSTRH"; - else - return "RSTR"; - } - else if ( os == TCP_RESET ) - return r_inactive ? "RSTOS0" : "RSTO"; - else if ( rs == TCP_CLOSED && os == TCP_CLOSED ) - return "SF"; - else if ( os == TCP_CLOSED ) - return r_inactive ? "SH" : "S2"; - else if ( rs == TCP_CLOSED ) - return o_inactive ? "SHR" : "S3"; - else if ( os == TCP_SYN_SENT && rs == TCP_INACTIVE ) - return "S0"; - else if ( os == TCP_ESTABLISHED && rs == TCP_ESTABLISHED ) - return "S1"; - else - return "OTH"; - } - - else if ( trans == udp ) - { - if ( os == UDP_ACTIVE ) - return rs == UDP_ACTIVE ? "SF" : "S0"; - else - return rs == UDP_ACTIVE ? "SHR" : "OTH"; - } - - else - return "OTH"; - } - -function conn_size(e: endpoint, trans: transport_proto): string - { - if ( e$size > 0 || (trans == tcp && e$state == TCP_CLOSED) ) - return fmt("%d", e$size); - else - ### should return 0 for TCP_RESET that went through TCP_CLOSED - return "?"; - } - -function service_name(c: connection): string - { - local p = c$id$resp_p; - - if ( p in port_names ) - return port_names[p]; - else - return "other"; - } - -const state_graphic = { - ["OTH"] = "?>?", ["REJ"] = "[", - ["RSTO"] = ">]", ["RSTOS0"] = "}]", ["RSTR"] = ">[", ["RSTRH"] = "<[", - ["S0"] = "}", ["S1"] = ">", ["S2"] = "}2", ["S3"] = "}3", - ["SF"] = ">", ["SH"] = ">h", ["SHR"] = " 0 ) - log_hot_conn(c); - - if ( trans == tcp ) - { - if ( c$orig$state in conn_closed || c$resp$state in conn_closed ) - duration = fmt("%.06f", c$duration); - else - duration = "?"; - } - else - duration = fmt("%.06f", c$duration); - - local addl = c$addl; - -@ifdef ( estimate_flow_size_and_remove ) - # Annotate connection with separately-estimated size, if present. - local orig_est = estimate_flow_size_and_remove(id, T); - local resp_est = estimate_flow_size_and_remove(id, F); - - if ( orig_est$have_est ) - addl = fmt("%s olower=%.0fMB oupper=%.0fMB oincon=%s", addl, - orig_est$lower / 1e6, orig_est$upper / 1e6, - orig_est$num_inconsistent); - - if ( resp_est$have_est ) - addl = fmt("%s rlower=%.0fMB rupper=%.0fMB rincon=%s", addl, - resp_est$lower / 1e6, resp_est$upper / 1e6, - resp_est$num_inconsistent); -@endif - - local service = determine_service(c); - - local log_msg = - fmt("%.6f %s %s %s %s %d %d %s %s %s %s %s", - c$start_time, duration, id$orig_h, id$resp_h, service, - id$orig_p, id$resp_p, trans, - conn_size(c$orig, trans), conn_size(c$resp, trans), - conn_state(c, trans), flags); - - if ( record_state_history ) - log_msg = fmt("%s %s", log_msg, - c$history == "" ? "X" : c$history); - - if ( addl != "" ) - log_msg = fmt("%s %s", log_msg, addl); - - print f, log_msg; - } - -event connection_established(c: connection) - { - Hot::check_hot(c, Hot::CONN_ESTABLISHED); - - if ( c$hot > 0 ) - log_hot_conn(c); - } - -event partial_connection(c: connection) - { - if ( c$orig$state == TCP_PARTIAL && c$resp$state == TCP_INACTIVE ) - # This appears to be a stealth scan. Don't do hot-checking - # as there wasn't an established connection. - ; - else - { - Hot::check_hot(c, Hot::CONN_ESTABLISHED); - Hot::check_hot(c, Hot::APPL_ESTABLISHED); # assume it's been established - } - - if ( c$hot > 0 ) - log_hot_conn(c); - } - -event connection_attempt(c: connection) - { - Hot::check_spoof(c); - Hot::check_hot(c, Hot::CONN_ATTEMPTED); - } - -event connection_finished(c: connection) - { - if ( c$orig$size == 0 || c$resp$size == 0 ) - # Hard to get excited about this - not worth logging again. - c$hot = 0; - else - Hot::check_hot(c, Hot::CONN_FINISHED); - } - -event connection_partial_close(c: connection) - { - if ( c$orig$size == 0 || c$resp$size == 0 ) - # Hard to get excited about this - not worth logging again. - c$hot = 0; - else - Hot::check_hot(c, Hot::CONN_FINISHED); - } - -event connection_half_finished(c: connection) - { - Hot::check_hot(c, Hot::CONN_ATTEMPTED); - } - -event connection_rejected(c: connection) - { - Hot::check_hot(c, Hot::CONN_REJECTED); - } - -event connection_reset(c: connection) - { - Hot::check_hot(c, Hot::CONN_FINISHED); - } - -event connection_pending(c: connection) - { - if ( c$orig$state in conn_closed && - (c$resp$state == TCP_INACTIVE || c$resp$state == TCP_PARTIAL) ) - # This is a stray FIN or RST - don't bother reporting. - return; - - if ( c$orig$state == TCP_RESET || c$resp$state == TCP_RESET ) - # We already reported this connection when the RST - # occurred. - return; - - Hot::check_hot(c, Hot::CONN_FINISHED); - } - -function connection_gone(c: connection, gone_type: string) - { - if ( c$orig$size == 0 || c$resp$size == 0 ) - { - if ( c$orig$state == TCP_RESET && c$resp$state == TCP_INACTIVE) - # A bare RST, no other context. Ignore it. - return; - - # Hard to get excited about this - not worth logging again, - # per connection_finished(). - c$hot = 0; - } - else - Hot::check_hot(c, Hot::CONN_TIMEOUT); - } - -event connection_state_remove(c: connection) &priority = -10 - { - local os = c$orig$state; - local rs = c$resp$state; - - if ( os == TCP_ESTABLISHED && rs == TCP_ESTABLISHED ) - # It was still active, no summary generated. - connection_gone(c, "remove"); - - else if ( (os == TCP_CLOSED || rs == TCP_CLOSED) && - (os == TCP_ESTABLISHED || rs == TCP_ESTABLISHED) ) - # One side has closed, the other hasn't - it's in state S2 - # or S3, hasn't been reported yet. - connection_gone(c, "remove"); - - record_connection(conn_file, c); - - delete hot_conns_reported[c$id]; - } diff --git a/policy.old/ftp.bro b/policy.old/ftp.bro index 4fc86df2c4..4686d2b6ee 100644 --- a/policy.old/ftp.bro +++ b/policy.old/ftp.bro @@ -287,7 +287,7 @@ function is_ftp_data_conn(c: connection): bool else if ( id$orig_p == 20/tcp && [$orig_h = id$resp_h, $orig_p = id$resp_p, - $resp_h = id$orig_h, $resp_p = 21/tcp] in ftp_sessions ) + $resp_h = id$orig_h, $resp_p = 21/tcp] in ftp_sessions ) return T; else return F; diff --git a/policy.old/portmapper.bro b/policy.old/portmapper.bro index 99ce096ee0..be576b3ffe 100644 --- a/policy.old/portmapper.bro +++ b/policy.old/portmapper.bro @@ -133,6 +133,11 @@ export { [NFS_world_servers, NFS_services], [sun-rpc.mcast.net, "ypserv"], # sigh } &redef; + + # Maps a given port on a given server's address to an RPC service. + # If we haven't loaded portmapper.bro, then it will be empty + # (and, ideally, queries to it would be optimized away ...). + global RPC_server_map: table[addr, port] of string; } redef capture_filters += { ["portmapper"] = "port 111" }; @@ -256,7 +261,7 @@ event pm_request_unset(r: connection, m: pm_mapping, success: bool) rpc_prog(m$program), m$p, success ? "ok" : "failed"), T); } -function update_RPC_server_map(server: addr, p: port, prog: string) +function update_RPC_server_map(r: connection, server: addr, p: port, prog: string) { if ( [server, p] in RPC_server_map ) { @@ -268,6 +273,8 @@ function update_RPC_server_map(server: addr, p: port, prog: string) } else RPC_server_map[server, p] = prog; + + add r$service[prog]; } event pm_request_getport(r: connection, pr: pm_port_request, p: port) @@ -275,12 +282,12 @@ event pm_request_getport(r: connection, pr: pm_port_request, p: port) local prog = rpc_prog(pr$program); local log_it = pm_check_getport(r, prog); - update_RPC_server_map(r$id$resp_h, p, prog); + update_RPC_server_map(r, r$id$resp_h, p, prog); pm_request(r, "pm_getport", fmt("%s -> %s", prog, p), log_it); } -function pm_mapping_to_text(server: addr, m: pm_mappings): string +function pm_mapping_to_text(r: connection, server: addr, m: pm_mappings): string { # Used to suppress multiple entries for multiple versions. local mapping_seen: set[count, port]; @@ -297,7 +304,7 @@ function pm_mapping_to_text(server: addr, m: pm_mappings): string add mapping_seen[prog, p]; addls[++num_addls] = fmt("%s -> %s", rpc_prog(prog), p); - update_RPC_server_map(server, p, rpc_prog(prog)); + update_RPC_server_map(r, server, p, rpc_prog(prog)); } } @@ -315,7 +322,7 @@ event pm_request_dump(r: connection, m: pm_mappings) { local log_it = [r$id$orig_h, r$id$resp_h] !in RPC_dump_okay; pm_request(r, "pm_dump", length(m) == 0 ? "(nil)" : "(done)", log_it); - append_addl(r, cat("<", pm_mapping_to_text(r$id$resp_h, m), ">")); + append_addl(r, cat("<", pm_mapping_to_text(r, r$id$resp_h, m), ">")); } event pm_request_callit(r: connection, call: pm_callit_request, p: port) diff --git a/policy/conn.bro b/policy/conn.bro new file mode 100644 index 0000000000..b32bb06637 --- /dev/null +++ b/policy/conn.bro @@ -0,0 +1,150 @@ +@load functions + +module Conn; + +export { + redef enum Log::ID += { CONN }; + type Log: record { + start_time: time; + orig_h: addr; + orig_p: count; + resp_h: addr; + resp_p: count; + proto: transport_proto; + service: string &default="other"; + duration: interval &default=0secs; + orig_bytes: count &default=0; + resp_bytes: count &default=0; + conn_state: string &default=""; + local_orig: bool &default=F; + addl: string &default=""; + history: string &default=""; + }; + + # Only log connections appear successful. + # TODO: implement this as a filter + const only_log_successful = T &redef; + + # Configure if only a certain direction of connection is desired. + # TODO: implement this as a filter + const logging = Enabled &redef; + + # If inbound/outbound connections are to be split into separate files. + # TODO: implement a log splitting option as a filter here too (inbound/outbound) + const split_log = F &redef; + + # This is where users can get access to the active Log record for a + # connection so they can extend and enhance the logged data. + global active_conns: table[conn_id] of Log; +} + +event bro_init() + { + Log::create_stream("CONN", "Conn::Log"); + Log::add_default_filter("CONN"); + } + +function conn_state(c: connection, trans: transport_proto): string + { + local os = c$orig$state; + local rs = c$resp$state; + + local o_inactive = os == TCP_INACTIVE || os == TCP_PARTIAL; + local r_inactive = rs == TCP_INACTIVE || rs == TCP_PARTIAL; + + if ( trans == tcp ) + { + if ( rs == TCP_RESET ) + { + if ( os == TCP_SYN_SENT || os == TCP_SYN_ACK_SENT || + (os == TCP_RESET && + c$orig$size == 0 && c$resp$size == 0) ) + return "REJ"; + else if ( o_inactive ) + return "RSTRH"; + else + return "RSTR"; + } + else if ( os == TCP_RESET ) + return r_inactive ? "RSTOS0" : "RSTO"; + else if ( rs == TCP_CLOSED && os == TCP_CLOSED ) + return "SF"; + else if ( os == TCP_CLOSED ) + return r_inactive ? "SH" : "S2"; + else if ( rs == TCP_CLOSED ) + return o_inactive ? "SHR" : "S3"; + else if ( os == TCP_SYN_SENT && rs == TCP_INACTIVE ) + return "S0"; + else if ( os == TCP_ESTABLISHED && rs == TCP_ESTABLISHED ) + return "S1"; + else + return "OTH"; + } + + else if ( trans == udp ) + { + if ( os == UDP_ACTIVE ) + return rs == UDP_ACTIVE ? "SF" : "S0"; + else + return rs == UDP_ACTIVE ? "SHR" : "OTH"; + } + + else + return "OTH"; + } + +function determine_service(c: connection): string + { + local service = ""; + for ( s in c$service ) + { + if ( sub_bytes(s, 0, 1) != "-" ) + service = service == "" ? s : cat(service, ",", s); + } + + return service == "" ? "other" : to_lower(service); + } + +function get_conn_log(c: connection): Log + { + local id = c$id; + local conn_log: Log; + if ( c$id in active_conns ) + conn_log = active_conns[id]; + else + { + conn_log$start_time=c$start_time; + conn_log$orig_h=id$orig_h; + conn_log$orig_p=port_to_count(id$orig_p); + conn_log$resp_h=id$resp_h; + conn_log$resp_p=port_to_count(id$resp_p); + conn_log$proto=get_port_transport_proto(id$resp_p); + conn_log$local_orig=is_local_addr(id$orig_h); + } + + conn_log$duration=c$duration; + conn_log$service=determine_service(c); + # TODO: these should optionally use Gregor's new + # actual byte counting code if it's enabled. + conn_log$orig_bytes=c$orig$size; + conn_log$resp_bytes=c$resp$size; + conn_log$conn_state=conn_state(c, get_port_transport_proto(c$id$resp_p)); + conn_log$addl=c$addl; + conn_log$history=c$history; + + return conn_log; + } + +event connection_established(c: connection) &priority = 10 + { + active_conns[c$id] = get_conn_log(c); + } + +event connection_state_remove(c: connection) &priority = 10 + { + local conn_log = get_conn_log(c); + Log::write("CONN", conn_log); + + if ( c$id in active_conns ) + delete active_conns[c$id]; + } diff --git a/policy/hot.conn.bro b/policy/hot.conn.bro new file mode 100644 index 0000000000..0ac070832c --- /dev/null +++ b/policy/hot.conn.bro @@ -0,0 +1,200 @@ +@load hot + +redef enum Notice += { + SensitiveConnection, # connection marked "hot" +}; + +# Whether to translate the local address in SensitiveConnection notices +# to a hostname. Meant as a demonstration of the "when" construct. +const xlate_hot_local_addr = F &redef; + +# The sets are indexed by the complete hot messages. +global hot_conns_reported: table[conn_id] of set[string]; + +const conn_closed = { TCP_CLOSED, TCP_RESET }; + +const state_graphic = { + ["OTH"] = "?>?", ["REJ"] = "[", + ["RSTO"] = ">]", ["RSTOS0"] = "}]", ["RSTR"] = ">[", ["RSTRH"] = "<[", + ["S0"] = "}", ["S1"] = ">", ["S2"] = "}2", ["S3"] = "}3", + ["SF"] = ">", ["SH"] = ">h", ["SHR"] = " 0 ) + log_hot_conn(c); + } + +event connection_state_remove(c: connection) &priority = -10 + { + local os = c$orig$state; + local rs = c$resp$state; + + if ( os == TCP_ESTABLISHED && rs == TCP_ESTABLISHED ) + # It was still active, no summary generated. + connection_gone(c, "remove"); + + else if ( (os == TCP_CLOSED || rs == TCP_CLOSED) && + (os == TCP_ESTABLISHED || rs == TCP_ESTABLISHED) ) + # One side has closed, the other hasn't - it's in state S2 + # or S3, hasn't been reported yet. + connection_gone(c, "remove"); + + delete hot_conns_reported[c$id]; + } + + +event partial_connection(c: connection) + { + if ( c$orig$state == TCP_PARTIAL && c$resp$state == TCP_INACTIVE ) + # This appears to be a stealth scan. Don't do hot-checking + # as there wasn't an established connection. + ; + else + { + Hot::check_hot(c, Hot::CONN_ESTABLISHED); + Hot::check_hot(c, Hot::APPL_ESTABLISHED); # assume it's been established + } + + if ( c$hot > 0 ) + log_hot_conn(c); + } + +event connection_attempt(c: connection) + { + Hot::check_spoof(c); + Hot::check_hot(c, Hot::CONN_ATTEMPTED); + } + +event connection_finished(c: connection) + { + if ( c$orig$size == 0 || c$resp$size == 0 ) + # Hard to get excited about this - not worth logging again. + c$hot = 0; + else + Hot::check_hot(c, Hot::CONN_FINISHED); + } + +event connection_partial_close(c: connection) + { + if ( c$orig$size == 0 || c$resp$size == 0 ) + # Hard to get excited about this - not worth logging again. + c$hot = 0; + else + Hot::check_hot(c, Hot::CONN_FINISHED); + } + +event connection_half_finished(c: connection) + { + Hot::check_hot(c, Hot::CONN_ATTEMPTED); + } + +event connection_rejected(c: connection) + { + Hot::check_hot(c, Hot::CONN_REJECTED); + } + +event connection_reset(c: connection) + { + Hot::check_hot(c, Hot::CONN_FINISHED); + } + +event connection_pending(c: connection) + { + if ( c$orig$state in conn_closed && + (c$resp$state == TCP_INACTIVE || c$resp$state == TCP_PARTIAL) ) + # This is a stray FIN or RST - don't bother reporting. + return; + + if ( c$orig$state == TCP_RESET || c$resp$state == TCP_RESET ) + # We already reported this connection when the RST + # occurred. + return; + + Hot::check_hot(c, Hot::CONN_FINISHED); + } + +function connection_gone(c: connection, gone_type: string) + { + if ( c$orig$size == 0 || c$resp$size == 0 ) + { + if ( c$orig$state == TCP_RESET && c$resp$state == TCP_INACTIVE) + # A bare RST, no other context. Ignore it. + return; + + # Hard to get excited about this - not worth logging again, + # per connection_finished(). + c$hot = 0; + } + else + Hot::check_hot(c, Hot::CONN_TIMEOUT); + }