diff --git a/scripts/base/protocols/dhcp/__load__.bro b/scripts/base/protocols/dhcp/__load__.bro index 0098b81a7a..c04423a855 100644 --- a/scripts/base/protocols/dhcp/__load__.bro +++ b/scripts/base/protocols/dhcp/__load__.bro @@ -1,2 +1,4 @@ @load ./consts -@load ./main \ No newline at end of file +@load ./main + +@load-sigs ./dpd.sig diff --git a/scripts/base/protocols/dhcp/dpd.sig b/scripts/base/protocols/dhcp/dpd.sig new file mode 100644 index 0000000000..010920e2d8 --- /dev/null +++ b/scripts/base/protocols/dhcp/dpd.sig @@ -0,0 +1,5 @@ +signature dhcp_cookie { + ip-proto == udp + payload /^.*\x63\x82\x53\x63/ + enable "dhcp" +} \ No newline at end of file diff --git a/scripts/base/protocols/dhcp/main.bro b/scripts/base/protocols/dhcp/main.bro index 9fc63df152..05491361ff 100644 --- a/scripts/base/protocols/dhcp/main.bro +++ b/scripts/base/protocols/dhcp/main.bro @@ -2,8 +2,8 @@ ##! This script ignores large swaths of the protocol, since it is rather ##! noisy on most networks, and focuses on the end-result: assigned leases. ##! -##! To enable further analysis and log output for DHCP, see the optional -##! scripts in the policy/protocols/dhcp directory. +##! If you'd like to track known DHCP devices and to log the hostname +##! supplied by the client, see policy/protocols/dhcp/known-devices.bro @load ./utils.bro @@ -45,13 +45,13 @@ redef record connection += { const ports = { 67/udp, 68/udp }; redef likely_server_ports += { 67/udp }; -event bro_init() &priority=5 +event bro_init() { Log::create_stream(DHCP::LOG, [$columns=Info, $ev=log_dhcp]); Analyzer::register_for_ports(Analyzer::ANALYZER_DHCP, ports); } -event dhcp_ack(c: connection, msg: dhcp_msg, mask: addr, router: dhcp_router_list, lease: interval, serv_addr: addr, host_name: string) &priority=5 +event dhcp_ack(c: connection, msg: dhcp_msg, mask: addr, router: dhcp_router_list, lease: interval, serv_addr: addr, host_name: string) { local info: Info; info$ts = network_time(); @@ -65,10 +65,6 @@ event dhcp_ack(c: connection, msg: dhcp_msg, mask: addr, router: dhcp_router_lis info$mac = msg$h_addr; c$dhcp = info; - } -# We let policy scripts add stuff too, so we run this at a lower priority -event dhcp_ack(c: connection, msg: dhcp_msg, mask: addr, router: dhcp_router_list, lease: interval, serv_addr: addr, host_name: string) &priority=1 - { Log::write(DHCP::LOG, c$dhcp); } diff --git a/scripts/policy/misc/known-devices.bro b/scripts/policy/misc/known-devices.bro new file mode 100644 index 0000000000..4c3ed9009c --- /dev/null +++ b/scripts/policy/misc/known-devices.bro @@ -0,0 +1,37 @@ +##! This script logs devices for which Bro has been able to determine the MAC +##! address and logs the MAC address once per day (by default). The log that +##! is output provides an easy way to determine a count of the devices in use +##! on a network per day. + +##! NOTE: This script will not generate any logs. Scripts such as +##! policy/protocols/dhcp/known-devices-and-hostnames are needed. +module Known; + +export { + ## The known-hosts logging stream identifier. + redef enum Log::ID += { DEVICES_LOG }; + + ## The record type which contains the column fields of the known-devices log. + type DevicesInfo: record { + ## The timestamp at which the host was detected. + ts: time &log; + ## The MAC address that was detected. + mac: string &log; + }; + + ## The set of all known MAC addresses to store for preventing duplicate + ## logging of addresses. It can also be used from other scripts to + ## inspect if an address has been seen in use. + ## Maintain the list of known devices for 24 hours so that the existence + ## of each individual address is logged each day. + global known_devices: set[string] &create_expire=1day &synchronized &redef; + + ## An event that can be handled to access the :bro:type:`Known::DevicesInfo` + ## record as it is sent on to the logging framework. + global log_known_devices: event(rec: DevicesInfo); +} + +event bro_init() + { + Log::create_stream(Known::DEVICES_LOG, [$columns=DevicesInfo, $ev=log_known_devices]); + } diff --git a/scripts/policy/protocols/dhcp/handle_extra_msg_types.bro b/scripts/policy/protocols/dhcp/handle_extra_msg_types.bro deleted file mode 100644 index e5fa713da4..0000000000 --- a/scripts/policy/protocols/dhcp/handle_extra_msg_types.bro +++ /dev/null @@ -1,256 +0,0 @@ -##! Handlers for DHCP message types other than DHCPACK, which is handled in base/protocols/dhcp. -##! For networks that wish to get more details from their DHCP logs, at the expense -##! of a significantly higher log rate. - -@load base/protocols/dhcp - -module DHCP; - -export { - redef record Info += { - ## The value of the host name option, if seen - host_name: string &log &optional; - ## The IP requested by the client, if any - requested_ip: addr &log &optional; - ## The type of the DHCP message (DHCPOFFER, DHCPRELEASE, etc.) - msg_type: string &log &optional; - }; - - #### Enabled by default - - ## A boolean value to determine if DHCPREQUEST messages are logged. - ## Often useful to see client activity, and because host_name is often available. - const log_dhcprequest = T &redef; - - ## A boolean value to determine if DHCPDECLINE messages are logged. - ## A client declines a lease if it detects that the IP is already in use (usually via ARP). - const log_dhcpdecline = T &redef; - - ## A boolean value to determine if DHCPNAK messages are logged. - ## A server issues a DHCPNAK if a client DHCPREQUEST is invalid. - const log_dhcpnak = T &redef; - - ## A boolean value to determine if DHCPRELEASE messages are logged. - ## A client issues a DHCPRELEASE when it no longer needs the lease (e.g. it's shutting down). - const log_dhcprelease = T &redef; - - #### Not enabled by default - - ## A boolean value to determine if DHCPOFFER messages are logged. - ## Used to profile server -> client communication. - const log_dhcpoffer = F &redef; - - ## A boolean value to determine if DHCPDISCOVER messages are logged. - ## Used to profile broadcast client discovery requests. - const log_dhcpdiscover = F &redef; - - ## A boolean value to determine if DHCPINFORM messages are logged. - ## Used to profile clients attempting to request/renew specific IPs. - const log_dhcpinform = F &redef; - -} - -event dhcp_offer(c: connection, msg: dhcp_msg, mask: addr, router: dhcp_router_list, lease: interval, serv_addr: addr, host_name: string) &priority=5 - { - if ( ! log_dhcpoffer ) - return; - - local info: Info; - info$ts = network_time(); - info$id = c$id; - info$uid = c$uid; - info$assigned_ip = reverse_ip(msg$yiaddr); - info$lease_time = lease; - info$trans_id = msg$xid; - info$msg_type = "DHCPOFFER"; - - if ( msg$h_addr != "" ) - info$mac = msg$h_addr; - - if ( host_name != "" ) - info$host_name = host_name; - - c$dhcp = info; - } - -event dhcp_discover(c: connection, msg: dhcp_msg, req_addr: addr, host_name: string) &priority=5 - { - if ( ! log_dhcpdiscover ) - return; - - local info: Info; - info$ts = network_time(); - info$id = c$id; - info$uid = c$uid; - info$requested_ip = req_addr; - info$trans_id = msg$xid; - info$msg_type = "DHCPDISCOVER"; - - if ( msg$h_addr != "" ) - info$mac = msg$h_addr; - - if ( host_name != "" ) - info$host_name = host_name; - - c$dhcp = info; - } - -event dhcp_request(c: connection, msg: dhcp_msg, req_addr: addr, serv_addr: addr, host_name: string) &priority=5 - { - if ( ! log_dhcprequest ) - return; - - local info: Info; - info$ts = network_time(); - info$id = c$id; - info$uid = c$uid; - info$requested_ip = req_addr; - info$trans_id = msg$xid; - info$msg_type = "DHCPREQUEST"; - - if ( msg$h_addr != "" ) - info$mac = msg$h_addr; - - if ( host_name != "" ) - info$host_name = host_name; - - c$dhcp = info; - } - -event dhcp_decline(c: connection, msg: dhcp_msg, host_name: string) &priority=5 - { - if ( ! log_dhcpdecline ) - return; - - local info: Info; - info$ts = network_time(); - info$id = c$id; - info$uid = c$uid; - info$trans_id = msg$xid; - info$msg_type = "DHCPDECLINE"; - - if ( msg$h_addr != "" ) - info$mac = msg$h_addr; - - if ( host_name != "" ) - info$host_name = host_name; - - c$dhcp = info; - } - -event dhcp_nak(c: connection, msg: dhcp_msg, host_name: string) &priority=5 - { - if ( ! log_dhcpnak ) - return; - - local info: Info; - info$ts = network_time(); - info$id = c$id; - info$uid = c$uid; - info$trans_id = msg$xid; - info$msg_type = "DHCPNAK"; - - if ( msg$h_addr != "" ) - info$mac = msg$h_addr; - - if ( host_name != "" ) - info$host_name = host_name; - - c$dhcp = info; - } - -event dhcp_release(c: connection, msg: dhcp_msg, host_name: string) &priority=5 - { - if ( ! log_dhcprelease ) - return; - - local info: Info; - info$ts = network_time(); - info$id = c$id; - info$uid = c$uid; - info$trans_id = msg$xid; - info$msg_type = "DHCPRELEASE"; - - if ( msg$h_addr != "" ) - info$mac = msg$h_addr; - - if ( host_name != "" ) - info$host_name = host_name; - - c$dhcp = info; - } - -event dhcp_inform(c: connection, msg: dhcp_msg, host_name: string) &priority=5 - { - if ( ! log_dhcpinform ) - return; - - local info: Info; - info$ts = network_time(); - info$id = c$id; - info$uid = c$uid; - info$trans_id = msg$xid; - info$msg_type = "DHCPINFORM"; - - if ( msg$h_addr != "" ) - info$mac = msg$h_addr; - - if ( host_name != "" ) - info$host_name = host_name; - - c$dhcp = info; - } - -event dhcp_ack(c: connection, msg: dhcp_msg, mask: addr, router: dhcp_router_list, lease: interval, serv_addr: addr, host_name: string) &priority=4 - { - ## For the sake of consistency, let's add msg_type to DHCPACK as well. - c$dhcp$msg_type = "DHCPACK"; - ## host_name is generally not in ACKs, but let's check anyway. - if ( host_name != "" ) - c$dhcp$host_name = host_name; - } - -#### We log stuff at a lower priority, in case any other scripts would like to extend the Info record first. - -event dhcp_offer(c: connection, msg: dhcp_msg, mask: addr, router: dhcp_router_list, lease: interval, serv_addr: addr, host_name: string) &priority=1 - { - if ( log_dhcpoffer ) - Log::write(DHCP::LOG, c$dhcp); - } - -event dhcp_discover(c: connection, msg: dhcp_msg, req_addr: addr, host_name: string) &priority=1 - { - if ( log_dhcpdiscover ) - Log::write(DHCP::LOG, c$dhcp); - } - -event dhcp_request(c: connection, msg: dhcp_msg, req_addr: addr, serv_addr: addr, host_name: string) &priority=1 - { - if ( log_dhcprequest ) - Log::write(DHCP::LOG, c$dhcp); - } - -event dhcp_decline(c: connection, msg: dhcp_msg, host_name: string) &priority=1 - { - if ( log_dhcpdecline ) - Log::write(DHCP::LOG, c$dhcp); - } - -event dhcp_nak(c: connection, msg: dhcp_msg, host_name: string) &priority=1 - { - if ( log_dhcpnak ) - Log::write(DHCP::LOG, c$dhcp); - } - -event dhcp_release(c: connection, msg: dhcp_msg, host_name: string) &priority=1 - { - if ( log_dhcprelease ) - Log::write(DHCP::LOG, c$dhcp); - } - -event dhcp_inform(c: connection, msg: dhcp_msg, host_name: string) &priority=1 - { - if ( log_dhcpinform ) - Log::write(DHCP::LOG, c$dhcp); - } - diff --git a/scripts/policy/protocols/dhcp/known-devices-and-hostnames.bro b/scripts/policy/protocols/dhcp/known-devices-and-hostnames.bro new file mode 100644 index 0000000000..95770ce273 --- /dev/null +++ b/scripts/policy/protocols/dhcp/known-devices-and-hostnames.bro @@ -0,0 +1,22 @@ +@load policy/misc/known-devices + +module Known; + +export { + redef record DevicesInfo += { + ## The value of the DHCP host name option, if seen + dhcp_host_name: string &log &optional; + }; +} + +event dhcp_request(c: connection, msg: dhcp_msg, req_addr: addr, serv_addr: addr, host_name: string) + { + if ( msg$h_addr == "" ) + return; + + if ( msg$h_addr !in known_devices ) + { + add known_devices[msg$h_addr]; + Log::write(Known::DEVICES_LOG, [$ts=network_time(), $mac=msg$h_addr, $dhcp_host_name=host_name]); + } + }