# test shell for bro interactive tool (BIT) # # the general form for event request/reply is event_name/event_nameR # event to test for the existance of an address in a table @load notice @load scan @load listen-clear @load notice @load conn redef Remote::destinations += { ["show_cpu"] = [$host = 127.0.0.1, $events = /show_cpu/, $connect=F, $ssl=F], ["show_memory"] = [$host = 127.0.0.1, $events = /show_memory/, $connect=F, $ssl=F], ["null_event"] = [$host = 127.0.0.1, $events = /null_event/, $connect=F, $ssl=F], ["host_drop_check"] = [$host = 127.0.0.1, $events = /host_drop_check/, $connect=F, $ssl=F], ["host_drop"] = [$host = 127.0.0.1, $events = /host_drop/, $connect=F, $ssl=F], ["host_undrop"] = [$host = 127.0.0.1, $events = /host_undrop/, $connect=F, $ssl=F], ["show_scan"] = [$host = 127.0.0.1, $events = /show_scan/, $connect=F, $ssl=F], ["scan_on"] = [$host = 127.0.0.1, $events = /scan_on/, $connect=F, $ssl=F], ["scan_off"] = [$host = 127.0.0.1, $events = /scan_off/, $connect=F, $ssl=F], ["reset_scan"] = [$host = 127.0.0.1, $events = /reset_scan/, $connect=F, $ssl=F], ["show_conn"] = [$host = 127.0.0.1, $events = /show_conn/, $connect=F, $ssl=F], ["drop_on"] = [$host = 127.0.0.1, $events = /drop_on/, $connect=F, $ssl=F], ["drop_off"] = [$host = 127.0.0.1, $events = /drop_off/, $connect=F, $ssl=F], ["show_pcap_filter"] = [$host = 127.0.0.1, $events = /show_pcap_filter/, $connect=F, $ssl=F], ["update_pcap_filter"] = [$host = 127.0.0.1, $events = /update_pcap_filter/, $connect=F, $ssl=F], ["conn_match_load"] = [$host = 127.0.0.1, $events = /conn_match_load/, $connect=F, $ssl=F], ["conn_match"] = [$host = 127.0.0.1, $events = /conn_match/, $connect=F, $ssl=F], ["lookup_on"] = [$host = 127.0.0.1, $events = /lookup_on/, $connect=F, $ssl=F], ["lookup_off"] = [$host = 127.0.0.1, $events = /lookup_off/, $connect=F, $ssl=F], ["lookup"] = [$host = 127.0.0.1, $events = /lookup/, $connect=F, $ssl=F], ["lookup_pair"] = [$host = 127.0.0.1, $events = /lookup_pair/, $connect=F, $ssl=F], }; # this is for looking up active & historical connections # adjust via conn_match_load global process_connection_lookups = T; redef enum Notice += { AddressDroppedShell, # address has been dropped via interactive shell DynamicPolicyChange, # shell used to change policy }; # this is the unit of string return for the callback functions. it is # in the form of a record in case additions need to be made. it is returned # via the return_line() event. type line_return: record { data: string; }; type set_return: record { i: count; data: table[count] of string; }; # this notifys the bro of what is going on - just a wrapper function shellNotify(message: string) { NOTICE([$note=DynamicPolicyChange, $msg=message]); } event null_event() { # this is for a null ping, not overly useful #redef report_outbound_peer_scan = { 100, 1000, }; can_drop_connectivity = T; shellNotify("can drop changed to F"); } event scan_on() { print("HERE!"); suppress_scan_checks = F; shellNotify("suppress_scan_checks = F"); } event scan_off() { suppress_scan_checks = T; shellNotify("suppress_scan_checks = T"); } event reset_scan(a: addr) { # this will reset the scan related table values assosciated with a # given IP address, then remove it from the dropped list. This is # different from the undrop which only removes the address from the # list of dropped hosts. The @ifdef is used in case scan.bro is not loaded @ifdef (num_distinct_peers) if ( a in num_distinct_peers ) num_distinct_peers[a] = 0; if ( a in landmine_address ) delete landmine_address[a]; if ( a in num_distinct_ports ) num_distinct_ports[a] = 0; if ( a in num_distinct_low_ports ) num_distinct_low_ports[a] = 0; if ( a in possible_scan_sources ) delete possible_scan_sources[a]; #if ( a in scan_triples ) # scan_triples[a]= 0; # note that this list is not exclusive, and could be improved... #remove dropped records if they exist if ( a in did_drop_address ) delete did_drop_address[a]; if ( a in connectivity_dropped ) delete connectivity_dropped[a]; shellNotify(fmt("reset_scan called on %s", a)); @endif } event drop_on() { can_drop_connectivity = T; shellNotify("allow drop changed to T"); } event drop_off() { can_drop_connectivity = F; shellNotify("allow drop changed to F"); } event show_cpu() { # return cpu usage information local now = current_time(); local lag = now - network_time(); local lr: line_return; local res = resource_usage(); local total_CPU_time = res$user_time + res$system_time; local CPU_util = (total_CPU_time) / res$real_time; if ( bro_is_terminating() ) # No more stats will be written or scheduled when Bro is # shutting down. return; lr$data = fmt("total CPU time/total clock time: %f", CPU_util); event return_line(lr); } event show_memory() { local res = resource_usage(); local lr: line_return; lr$data = fmt(" total mem (k): %d \n minor faults: %d\n major faults: %d\n num swap: %d\n blocking input: %d\n blocking output: %d\n context changes: %d", res$mem, res$minor_faults, res$major_faults, res$num_swap, res$blocking_input, res$blocking_output, res$num_context); event return_line(lr); } event host_drop_check(a: addr) { local lr: line_return; if ( a in did_drop_address ) lr$data = fmt("Host %s is dropped", a); else lr$data = fmt("Host %s is not dropped", a); event return_line(lr); } event host_drop(a: addr) { # this is taken almost line for line from the drop section # in scan.bro, but with some changes for handeling the # return functionaliity # we assume that scan.bro has been loaded :-( # XXX add ifdef check! local lr: line_return; # quick check to make sure that dropping is in place if ( ! can_drop_connectivity ) { lr$data = "Dropping not allowed via policy"; event return_line(lr); } else { if ( a in never_shut_down || a in never_drop_nets ) { lr$data = fmt("Address %s prohibited from dropping", a); event return_line(lr); } else if ( ++did_drop_address[a] == 1 ) { #system(fmt("%s %s", drop_connectivity_script, a)); lr$data = fmt("Address %s dropped", a); event return_line(lr); NOTICE([$note=AddressDroppedShell, $src=a, $msg=fmt("dropping address %s via interactive shell", a)]); } else { lr$data = fmt("Address %s already dropped", a); event return_line(lr); NOTICE([$note=AddressDropIgnored, $src=a, $msg=fmt("ignoring request to drop address %s again", a)]); } } } event host_undrop(a: addr) { # note that this does *not* remove the statistics for dropping, # just the actual records assosciated with host dropping @ifdef (num_distinct_peers) #remove dropped records if they exist if ( a in did_drop_address ) delete did_drop_address[a]; if ( a in connectivity_dropped ) delete connectivity_dropped[a]; shellNotify(fmt("host_undrop called on %s", a)); @endif } event show_scan(a: addr) { local lss:count; local lr: line_return; # options to gather data about the scaning host if ( a in possible_scan_sources ) lss = 1; else lss = 0; lr$data = fmt("scan data for %s:\n host count: %d\n backscatter count: %d\n possible scan source: %d", a, num_backscatter_peers[a], num_distinct_peers[a], lss); # now return this data to the calling entity event return_line(lr); } event show_conn() { local res = resource_usage(); local lr: line_return; lr$data = fmt("connection data:\n tcp (current/max): %d/%d\n udp (current/max): %d/%d\n icmp (current/max): %d/%d\n fragments (current/max): %d/%d", res$num_TCP_conns, res$max_TCP_conns, res$num_UDP_conns, res$max_UDP_conns, res$num_ICMP_conns, res$max_ICMP_conns, res$num_fragments, res$max_fragments); event return_line(lr); } function go(filter: string) { #capture_filters[filter] = filter; #update_default_pcap_filter(); } event show_pcap_filter() { local lr: line_return; lr$data = fmt("%s", default_pcap_filter); event return_line(lr); } event update_pcap_filter(filter: string) { go(filter); local lr: line_return; lr$data = fmt("%s", default_pcap_filter); event return_line(lr); } event conn_match_load() { local lr: line_return; if ( process_connection_lookups = F ) { process_connection_lookups = T; lr$data = "connection processing activated"; shellNotify("connection processing activated"); } else { #redef process_connection_lookups = F; process_connection_lookups = F; lr$data = "connection processing deactivated"; shellNotify("connection processing deactivated"); } event return_line(lr); } # this is the data struct for individual host-host quads, it is to be # set into a table indexed by source. this is a little gross... # # sh1 - hp11: [port111,port112] # - hp11: [port111,port113] # - hp21 # sh2 - hp21 # - hp22 # - hp23 # type conn_data: record { start_time: time; times_seen: count; }; type host_pair: record { c: table[port, port] of conn_data; }; type source_host: record { sip: table[addr] of host_pair; }; # main lookup table global source_lookup: table[addr] of source_host; # these are the events that control the config and lookup of select IP addresses event lookup_on() { if ( process_connection_lookups == F ) process_connection_lookups = T; local note = fmt("connection lookup toggled to %s", process_connection_lookups); shellNotify(note); } event lookup_off() { if ( process_connection_lookups == T ) process_connection_lookups = F; local note = fmt("connection lookup toggled to %s", process_connection_lookups); shellNotify(note); } event connection_established(c: connection) { # here we use a flag to optionally process connection events and # load them into a single ip indexed table. Not too efficient, but # limiting connections to SF types to begin with will allow for better # experimentation local tmphp: host_pair; local tmpsh: source_host; local tmpconn: conn_data; local orig_h: addr; local orig_p: port; local resp_h: addr; local resp_p: port; local cc: table[port, port] of conn_data; local tmpsip: table[addr] of host_pair; if ( process_connection_lookups ) { orig_h = c$id$orig_h; resp_h = c$id$resp_h; orig_p = c$id$orig_p; resp_p = c$id$resp_p; if ( orig_h !in source_lookup ) { # new orig IP, add record for both it and the resp host tmpconn$start_time = c$start_time; tmpconn$times_seen = 1; cc[orig_p, resp_p] = tmpconn; tmphp$c = cc; # now add the host pair record to the orig host tale tmpsip[resp_h] = tmphp; tmpsh$sip = tmpsip; # now insert the value into the orig lookup table source_lookup[orig_h] = tmpsh; } else { # we have seen the orig IP - now grab that record and see if # the resp IP has been seen as well tmpsh = source_lookup[orig_h]; if ( resp_h !in tmpsh$sip ) { # this is a new resp IP for the org, create the fillins... tmpconn$start_time = c$start_time; tmpconn$times_seen = 1; cc[orig_p, resp_p] = tmpconn; tmphp$c = cc; tmpsh$sip[resp_h] = tmphp; # fill in source lookup table with new value source_lookup[orig_h] = tmpsh; } else { # we have seen this pair of hosts before, like above check pair # values and augment as needed tmphp = tmpsh$sip[resp_h]; if ( [orig_p, resp_p] !in tmphp$c ) { # this is a new set of ports for the orig/resp pair # create the appropriate data and update the tree. tmpconn$start_time = c$start_time; tmpconn$times_seen =1; tmphp$c[orig_p, resp_p] = tmpconn; tmpsh$sip[resp_h] = tmphp; source_lookup[orig_h] = tmpsh; } else { # same ports seen - update the count and timestamp on # the data portion and move along tmpconn$start_time = c$start_time; #tmpconn$times_seen =+ 1; tmphp$c[orig_p, resp_p] = tmpconn; tmpsh$sip[resp_h] = tmphp; source_lookup[orig_h] = tmpsh; } } } } } event lookup_pair(origA: addr, respA: addr) { # here we lookup *any* connection which has 'a' as the source address. this may # be quite inefficient to do so this needs to be tested on a loaded box and look # at droppd packets local t_addr: addr; local t_addr2: addr; local t_orig_p: port; local t_resp_p: port; local tmphp: host_pair; local tmpsh: source_host; local tmpconn: conn_data; local lr: line_return; for ( t_addr in source_lookup ) { if ( t_addr == origA ) { tmpsh = source_lookup[origA]; for ( t_addr2 in tmpsh$sip ) # grab dest IP { # now if destIp ='s provided, print data if ( t_addr2 == respA ) { tmphp = tmpsh$sip[t_addr2]; for ( [t_orig_p, t_resp_p] in tmphp$c ) { lr$data = fmt("%s:%s -> %s:%s", t_addr, t_orig_p, t_addr2, t_resp_p); event return_line(lr); } } } #print fmt("seen %s", t_addr); } } } event lookup(origA: addr) { # here we lookup *any* connection which has 'a' as the source address. this may # be quite inefficient to do so this needs to be tested on a loaded box and look # at droppd packets local t_addr: addr; local t_addr2: addr; local t_orig_p: port; local t_resp_p: port; local tmphp: host_pair; local tmpsh: source_host; local tmpconn: conn_data; local lr: line_return; for ( t_addr in source_lookup ) { if ( t_addr == origA ) { tmpsh = source_lookup[origA]; for ( t_addr2 in tmpsh$sip ) # grab dest IP { tmphp = tmpsh$sip[t_addr2]; for ( [t_orig_p, t_resp_p] in tmphp$c ) { lr$data = fmt("%s:%s -> %s:%s", t_addr, t_orig_p, t_addr2, t_resp_p); event return_line(lr); } } #print fmt("seen %s", t_addr); } } }