From 18499fd7d926051e7be850d5e932e950844ba5b7 Mon Sep 17 00:00:00 2001 From: Valerio G Date: Sun, 31 Dec 2017 17:36:30 +0100 Subject: [PATCH 1/4] Extend DHCP protocol analyzer with new options. Add the folowing option types: - 55 Parameters Request List; - 58 Renewal time; - 59 Rebinding time; - 61 Client Identifier; - 82 Relay Agent Information. Extend the following events with new parameters, specifically: - dhcp_discover exports client identifier and parameters request list; - dhcp_request exports client_identifier and parameters request list; - dhcp_ack exports rebinding time, renewal time and list of suboptions value of dhcp relay agent information option; - dhcp_inform exports parameters request list. Add option type specific variables within the scope of DHCP module (see src/analyzer/protocol/dhcp/types.bif). Move protocol specific variables "dhcp_msg" and "dhcp_router_list" from scope Global to DHCP:: and adapt inet_net_var in src/NetVar.cc consequently. Extend src/analyzer/protocols/dhcp/main.bro to handle the new events and to log dhcp_ack, dhcp_request and dhcp_discover. Modify scripts/policy/protocols/dhcp/known-devices-and-hostnames.bro to include new events' variables. --- scripts/base/init-bare.bro | 51 +++++--- scripts/base/protocols/dhcp/main.bro | 90 ++++++++++++-- .../dhcp/known-devices-and-hostnames.bro | 4 +- src/NetVar.cc | 4 +- src/analyzer/protocol/dhcp/CMakeLists.txt | 1 + src/analyzer/protocol/dhcp/DHCP.cc | 1 + src/analyzer/protocol/dhcp/dhcp-analyzer.pac | 90 +++++++++++--- src/analyzer/protocol/dhcp/dhcp-protocol.pac | 114 +++++++++--------- src/analyzer/protocol/dhcp/dhcp.pac | 1 + src/analyzer/protocol/dhcp/events.bif | 37 ++++-- src/analyzer/protocol/dhcp/types.bif | 10 ++ 11 files changed, 291 insertions(+), 112 deletions(-) create mode 100644 src/analyzer/protocol/dhcp/types.bif diff --git a/scripts/base/init-bare.bro b/scripts/base/init-bare.bro index f2ea2ed29a..a7047d4cfc 100644 --- a/scripts/base/init-bare.bro +++ b/scripts/base/init-bare.bro @@ -3058,24 +3058,43 @@ export { module GLOBAL; -## A list of router addresses offered by a DHCP server. -## -## .. bro:see:: dhcp_ack dhcp_offer -type dhcp_router_list: table[count] of addr; +module DHCP; -## A DHCP message. -## -## .. bro:see:: dhcp_ack dhcp_decline dhcp_discover dhcp_inform dhcp_nak -## dhcp_offer dhcp_release dhcp_request -type dhcp_msg: record { - op: count; ##< Message OP code. 1 = BOOTREQUEST, 2 = BOOTREPLY - m_type: count; ##< The type of DHCP message. - xid: count; ##< Transaction ID of a DHCP session. - h_addr: string; ##< Hardware address of the client. - ciaddr: addr; ##< Original IP address of the client. - yiaddr: addr; ##< IP address assigned to the client. -}; +export { + ## A list of router addresses offered by a DHCP server. + ## + ## .. bro:see:: dhcp_ack dhcp_offer + type DHCP::dhcp_router_list: table[count] of addr; + ## A DHCP message. + ## .. bro:see:: dhcp_ack dhcp_decline dhcp_discover dhcp_inform dhcp_nak + ## dhcp_offer dhcp_release dhcp_request + type DHCP::dhcp_msg: record { + op: count; ##< Message OP code. 1 = BOOTREQUEST, 2 = BOOTREPLY + m_type: count; ##< The type of DHCP message. + xid: count; ##< Transaction ID of a DHCP session. + h_addr: string; ##< Hardware address of the client. + ciaddr: addr; ##< Original IP address of the client. + yiaddr: addr; ##< IP address assigned to the client. + }; + ## DHCP Paremeter Reuqest list (Option 55) + ## .. bro:see:: dhcp_request dhcp_discover + type DHCP::dhcp_params_list: table[count] of count; + ## DHCP Relay Agent Information Option (Option 82) + ## .. bro:see:: dhcp_ack + type DHCP::dhcp_sub_opt: record { + code: count; + value: string; + }; + ## DHCP Client Identifier (Option 61) + ## .. bro:see:: dhcp_request dhcp_discover + type DHCP::dhcp_client_id: record { + hwtype: count; + hwaddr: string; + }; + type DHCP::dhcp_sub_opt_list: table[count] of DHCP::dhcp_sub_opt; +} +module GLOBAL; ## A DNS message. ## ## .. bro:see:: dns_AAAA_reply dns_A_reply dns_CNAME_reply dns_EDNS_addl diff --git a/scripts/base/protocols/dhcp/main.bro b/scripts/base/protocols/dhcp/main.bro index bfc3d98117..92b61697fe 100644 --- a/scripts/base/protocols/dhcp/main.bro +++ b/scripts/base/protocols/dhcp/main.bro @@ -17,20 +17,32 @@ export { type Info: record { ## The earliest time at which a DHCP message over the ## associated connection is observed. - ts: time &log; + ts: time &log; ## A unique identifier of the connection over which DHCP is ## occurring. - uid: string &log; + uid: string &log; ## The connection's 4-tuple of endpoint addresses/ports. - id: conn_id &log; + id: conn_id &log; ## Client's hardware address. - mac: string &log &optional; + mac: string &log &optional; ## Client's actual assigned IP address. - assigned_ip: addr &log &optional; + assigned_ip: addr &log &optional; ## IP address lease interval. - lease_time: interval &log &optional; + lease_time: interval &log &optional; ## A random number chosen by the client for this transaction. - trans_id: count &log; + trans_id: count &log; + ## the message type + msg_type: string &log &optional; + ## client ID + client_id: string &log &optional; + ## the server ID + server_id: addr &log &optional; + ## the host name + host_name: string &log &optional; + ## the subscriber id (if present) + subscriber_id: string &log &optional; + ## the agent remote id (if present) + agent_remote_id: string &log &optional; }; ## Event that can be handled to access the DHCP @@ -47,20 +59,26 @@ redef record connection += { const ports = { 67/udp, 68/udp }; redef likely_server_ports += { 67/udp }; +global info: Info; + event bro_init() &priority=5 { Log::create_stream(DHCP::LOG, [$columns=Info, $ev=log_dhcp, $path="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, reb_time: count, ren_time: count, sub_opt: dhcp_sub_opt_list) &priority=5 { - local info: Info; + #local info: Info; info$ts = network_time(); info$id = c$id; info$uid = c$uid; info$lease_time = lease; info$trans_id = msg$xid; + info$msg_type = message_types[msg$m_type]; + + info$server_id = serv_addr; + info$host_name = host_name; if ( msg$h_addr != "" ) info$mac = msg$h_addr; @@ -70,10 +88,62 @@ event dhcp_ack(c: connection, msg: dhcp_msg, mask: addr, router: dhcp_router_lis else info$assigned_ip = c$id$orig_h; + for (param in sub_opt) + { + #if ( sub_opt[param]$code == 1 ) + #{ + #print fmt("Relay Agent Information:"); + #print fmt( "sub option: code=%d circuit id=%s",sub_opt[param]$code,sub_opt[param]$value ); + #} + if ( sub_opt[param]$code == 2 ) + info$agent_remote_id = bytestring_to_hexstr(sub_opt[param]$value); + + if ( sub_opt[param]$code == 6 ) + info$subscriber_id = (sub_opt[param]$value); + } + 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=-5 +event dhcp_ack(c: connection, msg: dhcp_msg, mask: addr, router: dhcp_router_list, lease: interval, serv_addr: addr, host_name: string, reb_time: count, ren_time: count, sub_opt: dhcp_sub_opt_list) &priority=-5 { Log::write(DHCP::LOG, c$dhcp); } + +event dhcp_request(c: connection, msg: dhcp_msg, req_addr: addr, serv_addr: addr, host_name: string, c_id: dhcp_client_id, req_params: table[count] of count) &priority=5 + { + info$ts = network_time(); + info$id = c$id; + info$uid = c$uid; + info$trans_id = msg$xid; + info$msg_type = message_types[msg$m_type]; + info$server_id = serv_addr; + info$host_name = host_name; + info$client_id = c_id$hwaddr; + + c$dhcp = info; + } + +event dhcp_request(c: connection, msg: dhcp_msg, req_addr: addr, serv_addr: addr, host_name: string, c_id: dhcp_client_id, req_params: table[count] of count) &priority=-5 + { + Log::write(DHCP::LOG, c$dhcp); + } + +event dhcp_discover(c: connection, msg: dhcp_msg, req_addr: addr, host_name: string, c_id: dhcp_client_id, req_params: table[count] of count) &priority=5 + { + info$ts = network_time(); + info$id = c$id; + info$uid = c$uid; + info$trans_id = msg$xid; + info$msg_type = message_types[msg$m_type]; + info$host_name = host_name; + info$client_id = c_id$hwaddr; + + c$dhcp = info; + } + +event dhcp_discover(c: connection, msg: dhcp_msg, req_addr: addr, host_name: string, c_id: dhcp_client_id, req_params: table[count] of count) &priority=-5 + { + 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 index 63b794cb9f..39ea02c759 100644 --- a/scripts/policy/protocols/dhcp/known-devices-and-hostnames.bro +++ b/scripts/policy/protocols/dhcp/known-devices-and-hostnames.bro @@ -12,7 +12,7 @@ export { }; } -event dhcp_request(c: connection, msg: dhcp_msg, req_addr: addr, serv_addr: addr, host_name: string) +event dhcp_request(c: connection, msg: DHCP::dhcp_msg, req_addr: addr, serv_addr: addr, host_name: string, client_id: DHCP::dhcp_client_id, req_params: DHCP::dhcp_params_list) { if ( msg$h_addr == "" ) return; @@ -24,7 +24,7 @@ event dhcp_request(c: connection, msg: dhcp_msg, req_addr: addr, serv_addr: addr } } -event dhcp_inform(c: connection, msg: dhcp_msg, host_name: string) +event dhcp_inform(c: connection, msg: DHCP::dhcp_msg, host_name: string, req_params: DHCP::dhcp_params_list) { if ( msg$h_addr == "" ) return; diff --git a/src/NetVar.cc b/src/NetVar.cc index 75613364e2..3f0967dbc4 100644 --- a/src/NetVar.cc +++ b/src/NetVar.cc @@ -426,8 +426,8 @@ void init_net_var() entropy_test_result = internal_type("entropy_test_result")->AsRecordType(); - dhcp_router_list = internal_type("dhcp_router_list")->AsTableType(); - dhcp_msg = internal_type("dhcp_msg")->AsRecordType(); + dhcp_router_list = internal_type("DHCP::dhcp_router_list")->AsTableType(); + dhcp_msg = internal_type("DHCP::dhcp_msg")->AsRecordType(); dns_msg = internal_type("dns_msg")->AsRecordType(); dns_answer = internal_type("dns_answer")->AsRecordType(); diff --git a/src/analyzer/protocol/dhcp/CMakeLists.txt b/src/analyzer/protocol/dhcp/CMakeLists.txt index 646a11f9ab..ece07e3a7e 100644 --- a/src/analyzer/protocol/dhcp/CMakeLists.txt +++ b/src/analyzer/protocol/dhcp/CMakeLists.txt @@ -6,5 +6,6 @@ include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DI bro_plugin_begin(Bro DHCP) bro_plugin_cc(DHCP.cc Plugin.cc) bro_plugin_bif(events.bif) +bro_plugin_bif(types.bif) bro_plugin_pac(dhcp.pac dhcp-protocol.pac dhcp-analyzer.pac) bro_plugin_end() diff --git a/src/analyzer/protocol/dhcp/DHCP.cc b/src/analyzer/protocol/dhcp/DHCP.cc index 78b1c6be69..4ab77c09a4 100644 --- a/src/analyzer/protocol/dhcp/DHCP.cc +++ b/src/analyzer/protocol/dhcp/DHCP.cc @@ -1,6 +1,7 @@ #include "DHCP.h" #include "events.bif.h" +#include "types.bif.h" using namespace analyzer::dhcp; diff --git a/src/analyzer/protocol/dhcp/dhcp-analyzer.pac b/src/analyzer/protocol/dhcp/dhcp-analyzer.pac index a11412ce96..f9b195088e 100644 --- a/src/analyzer/protocol/dhcp/dhcp-analyzer.pac +++ b/src/analyzer/protocol/dhcp/dhcp-analyzer.pac @@ -8,17 +8,26 @@ flow DHCP_Flow(is_orig: bool) { %member{ BroVal dhcp_msg_val_; + uint8 sum_len; %} %init{ dhcp_msg_val_ = 0; + sum_len = 0; %} %cleanup{ Unref(dhcp_msg_val_); dhcp_msg_val_ = 0; + sum_len = 0; %} + function get_dhcp_sumlen(len: uint8): uint8 + %{ + sum_len = len + sum_len; + return sum_len; + %} + function get_dhcp_msgtype(options: DHCP_Option[]): uint8 %{ vector::const_iterator ptr; @@ -54,7 +63,12 @@ flow DHCP_Flow(is_orig: bool) { // Requested IP address to the server. ::uint32 req_addr = 0, serv_addr = 0; - StringVal* host_name = 0; + StringVal* host_name = new StringVal(""); + + TableVal* params_list = 0; + RecordVal* client_id = new RecordVal(BifType::Record::DHCP::dhcp_client_id); + client_id->Assign(0,0); + client_id->Assign(1,new StringVal("")); for ( ptr = options->begin(); ptr != options->end() && ! (*ptr)->last(); ++ptr ) { @@ -69,29 +83,42 @@ flow DHCP_Flow(is_orig: bool) { break; case HOST_NAME_OPTION: - Unref(host_name); host_name = new StringVal((*ptr)->info()->host_name().length(), (const char*) (*ptr)->info()->host_name().begin()); break; + case CLIENT_ID_OPTION: + client_id->Assign(0, new Val((*ptr)->info()->client_id()->hwtype(), TYPE_COUNT)); + client_id->Assign(1, new StringVal(fmt_mac((*ptr)->info()->client_id()->hwaddr().begin(), (*ptr)->info()->client_id()->hwaddr().length()))); + break; + case PAR_REQ_LIST: + params_list = new TableVal(BifType::Table::DHCP::dhcp_params_list); + int num_parms = (*ptr)->info()->par_req_list()->size(); + for (int i=0; i < num_parms; ++i) + { + vector* plist = (*ptr)->info()->par_req_list(); + uint8 param = (*plist)[i]; + Val* index = new Val(i+1, TYPE_COUNT); + params_list->Assign(index, new Val(param, TYPE_COUNT)); + Unref(index); + } + break; } } - if ( host_name == 0 ) - host_name = new StringVal(""); - switch ( type ) { case DHCPDISCOVER: BifEvent::generate_dhcp_discover(connection()->bro_analyzer(), connection()->bro_analyzer()->Conn(), - dhcp_msg_val_->Ref(), new AddrVal(req_addr), host_name); + dhcp_msg_val_->Ref(), new AddrVal(req_addr), + host_name, client_id, params_list); break; case DHCPREQUEST: BifEvent::generate_dhcp_request(connection()->bro_analyzer(), connection()->bro_analyzer()->Conn(), dhcp_msg_val_->Ref(), new AddrVal(req_addr), - new AddrVal(serv_addr), host_name); + new AddrVal(serv_addr), host_name, client_id, params_list); break; case DHCPDECLINE: @@ -109,7 +136,7 @@ flow DHCP_Flow(is_orig: bool) { case DHCPINFORM: BifEvent::generate_dhcp_inform(connection()->bro_analyzer(), connection()->bro_analyzer()->Conn(), - dhcp_msg_val_->Ref(), host_name); + dhcp_msg_val_->Ref(), host_name, params_list); break; default: @@ -123,6 +150,7 @@ flow DHCP_Flow(is_orig: bool) { function parse_reply(options: DHCP_Option[], type: uint8): bool %{ vector::const_iterator ptr; + vector::const_iterator ptrsubopt; // RFC 1533 allows a list of router addresses. TableVal* router_list = 0; @@ -132,6 +160,13 @@ flow DHCP_Flow(is_orig: bool) { uint32 lease = 0; StringVal* host_name = 0; + uint32 reb_time = 0; + uint32 ren_time = 0; + StringVal* agent_cir = 0; + StringVal* agent_rem = 0; + StringVal* agent_sub_opt = 0; + TableVal* relay_agent_sub_opt = new TableVal(BifType::Table::DHCP::dhcp_sub_opt_list); + for ( ptr = options->begin(); ptr != options->end() && ! (*ptr)->last(); ++ptr ) { @@ -144,7 +179,7 @@ flow DHCP_Flow(is_orig: bool) { case ROUTER_OPTION: // Let's hope there aren't multiple // such options. - Unref(router_list); + //Unref(router_list); router_list = new TableVal(dhcp_router_list); { @@ -175,10 +210,32 @@ flow DHCP_Flow(is_orig: bool) { break; case HOST_NAME_OPTION: - Unref(host_name); host_name = new StringVal((*ptr)->info()->host_name().length(), (const char*) (*ptr)->info()->host_name().begin()); break; + + case REB_TIME_OPTION: + reb_time = (*ptr)->info()->reb_time(); + break; + + case REN_TIME_OPTION: + ren_time = (*ptr)->info()->ren_time(); + break; + + case RELAY_AGENT_INF: + RecordVal* r = new RecordVal(BifType::Record::DHCP::dhcp_sub_opt); + uint i = 0; + for( ptrsubopt = (*ptr)->info()->relay_agent_inf()->begin(); ptrsubopt != (*ptr)->info()->relay_agent_inf()->end(); ++ptrsubopt) + { + r = new RecordVal(BifType::Record::DHCP::dhcp_sub_opt); + Val* index = new Val(i + 1, TYPE_COUNT); + r->Assign(0, new Val((*ptrsubopt)->code(), TYPE_COUNT)); + r->Assign(1, bytestring_to_val((*ptrsubopt)->value())); + relay_agent_sub_opt->Assign(index, r); + Unref(index); + ++i; + } + break; } } @@ -204,19 +261,19 @@ flow DHCP_Flow(is_orig: bool) { BifEvent::generate_dhcp_ack(connection()->bro_analyzer(), connection()->bro_analyzer()->Conn(), dhcp_msg_val_->Ref(), new AddrVal(subnet_mask), - router_list, lease, new AddrVal(serv_addr), host_name); + router_list, lease, new AddrVal(serv_addr), host_name, reb_time, ren_time, relay_agent_sub_opt); break; case DHCPNAK: - Unref(router_list); + //Unref(router_list); BifEvent::generate_dhcp_nak(connection()->bro_analyzer(), connection()->bro_analyzer()->Conn(), dhcp_msg_val_->Ref(), host_name); break; default: - Unref(router_list); - Unref(host_name); + //Unref(router_list); + //Unref(host_name); break; } @@ -266,7 +323,10 @@ flow DHCP_Flow(is_orig: bool) { case BOOTREPLY: // presumably from server to client if ( ${msg.type} == DHCPOFFER || ${msg.type} == DHCPACK || - ${msg.type} == DHCPNAK ) + ${msg.type} == DHCPNAK || + ${msg.type} == DHCPLEASEUNASSIGNED || + ${msg.type} == DHCPLEASEUNKNOWN || + ${msg.type} == DHCPLEASEACTIVE ) parse_reply(${msg.options}, ${msg.type}); else connection()->bro_analyzer()->ProtocolViolation(fmt("unknown DHCP message type option for BOOTREPLY (%d)", diff --git a/src/analyzer/protocol/dhcp/dhcp-protocol.pac b/src/analyzer/protocol/dhcp/dhcp-protocol.pac index cf8cf69b26..ebc1fd946a 100644 --- a/src/analyzer/protocol/dhcp/dhcp-protocol.pac +++ b/src/analyzer/protocol/dhcp/dhcp-protocol.pac @@ -3,7 +3,7 @@ # Refer to RFC 2131 for op types. enum OP_type { BOOTREQUEST = 1, - BOOTREPLY = 2, + BOOTREPLY = 2 }; # Refer to RFC 1533 for option types. @@ -16,33 +16,67 @@ enum OPTION_type { REQ_IP_OPTION = 50, LEASE_OPTION = 51, MSG_TYPE_OPTION = 53, - SERV_ID_OPTION = 54, # Server address, actually :) - END_OPTION = 255, + SERV_ID_OPTION = 54, # Server address, actually :) + PAR_REQ_LIST = 55, # Parameters Request List - NEW + REN_TIME_OPTION = 58, # Renewal time - NEW + REB_TIME_OPTION = 59, # Rebinding time - NEW + CLIENT_ID_OPTION = 61, # Client Identifier - NEW + RELAY_AGENT_INF = 82, # Relay Agent Information - NEW + END_OPTION = 255 }; -# Refer to RFC 1533 for message types (with option = 53). enum DHCP_message_type { - DHCPDISCOVER = 1, - DHCPOFFER = 2, - DHCPREQUEST = 3, - DHCPDECLINE = 4, - DHCPACK = 5, - DHCPNAK = 6, - DHCPRELEASE = 7, - DHCPINFORM = 8, + DHCPDISCOVER = 1, + DHCPOFFER = 2, + DHCPREQUEST = 3, + DHCPDECLINE = 4, + DHCPACK = 5, + DHCPNAK = 6, + DHCPRELEASE = 7, + DHCPINFORM = 8, + DHCPFORCERENEW = 9, # RFC 2132 + DHCPLEASEQUERY = 10, # RFC 4388 + DHCPLEASEUNASSIGNED = 11, # RFC 4388 + DHCPLEASEUNKNOWN = 12, # RFC 4388 + DHCPLEASEACTIVE = 13 # RFC 4388 +}; + +type Relay_Agent_SubOption(tot_len: uint8) = record { + code : uint8; + length : uint8; + value : bytestring &length = length; +} &let { + sum_len: uint8 = $context.flow.get_dhcp_sumlen(length + 2); + last: bool = (sum_len == tot_len); +}; + +type Client_Identifier(length: uint8) = record { + hwtype : uint8; + hwaddr : bytestring &length = length -1; +}; + +enum DHCP_hardware_type +{ + ETHERNET = 1, + EXPERIMENTAL_ETHERNET = 2 }; type Option_Info(code: uint8) = record { length : uint8; value : case code of { - SUBNET_OPTION -> mask : uint32; - ROUTER_OPTION -> router_list : uint32[length/4]; - REQ_IP_OPTION -> req_addr : uint32; - LEASE_OPTION -> lease : uint32; - MSG_TYPE_OPTION -> msg_type : uint8; - SERV_ID_OPTION -> serv_addr : uint32; - HOST_NAME_OPTION-> host_name : bytestring &length = length; - default -> other : bytestring &length = length; + SUBNET_OPTION -> mask : uint32; + ROUTER_OPTION -> router_list : uint32[length/4]; + REQ_IP_OPTION -> req_addr : uint32; + LEASE_OPTION -> lease : uint32; + MSG_TYPE_OPTION -> msg_type : uint8; + SERV_ID_OPTION -> serv_addr : uint32; + HOST_NAME_OPTION -> host_name : bytestring &length = length; + PAR_REQ_LIST -> par_req_list : uint8[length]; + REB_TIME_OPTION -> reb_time : uint32; + REN_TIME_OPTION -> ren_time : uint32; + CLIENT_ID_OPTION -> client_id : Client_Identifier(length); + RELAY_AGENT_INF -> relay_agent_inf : Relay_Agent_SubOption(length)[] &until($element.last); + default -> other : bytestring &length = length; }; }; @@ -53,45 +87,9 @@ type DHCP_Option = record { default -> info : Option_Info(code); }; } &let { - last: bool = (code == 255); # Mark the end of a list of options + last: bool = (code == END_OPTION); # Mark the end of a list of options }; -# Message format according to RFC 2131 -# -# 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 -# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 -# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -# | op (1) | htype (1) | hlen (1) | hops (1) | -# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -# | xid (4) | -# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -# | secs (2) | flags (2) | -# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -# | ciaddr (4) | -# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -# | yiaddr (4) | -# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -# | siaddr (4) | -# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -# | giaddr (4) | -# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -# | | -# | chaddr (16) | -# / / -# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -# | | -# | sname (64) | -# / / -# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -# | | -# | file (128) | -# / / -# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -# | | -# | options (variable) | -# / / -# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - type DHCP_Message = record { op : uint8; htype : uint8; @@ -107,11 +105,9 @@ type DHCP_Message = record { chaddr : bytestring &length = 16; sname : bytestring &length = 64; file : bytestring &length = 128; - # Cookie belongs to options in RFC 2131, but we separate # them here for easy parsing. cookie : uint32; - options : DHCP_Option[] &until($element.last); } &let { type : uint8 = $context.flow.get_dhcp_msgtype(options); diff --git a/src/analyzer/protocol/dhcp/dhcp.pac b/src/analyzer/protocol/dhcp/dhcp.pac index 706be31e10..18439cf341 100644 --- a/src/analyzer/protocol/dhcp/dhcp.pac +++ b/src/analyzer/protocol/dhcp/dhcp.pac @@ -2,6 +2,7 @@ %include bro.pac %extern{ +#include "types.bif.h" #include "events.bif.h" %} diff --git a/src/analyzer/protocol/dhcp/events.bif b/src/analyzer/protocol/dhcp/events.bif index bbd27c71f7..057db36aff 100644 --- a/src/analyzer/protocol/dhcp/events.bif +++ b/src/analyzer/protocol/dhcp/events.bif @@ -9,6 +9,10 @@ ## ## host_name: The value of the host name option, if specified by the client. ## +## client_id: The value of the client id (usually the MAC ADDRESS). +## +## req_params: The Parameters Request List. +## ## .. bro:see:: dhcp_discover dhcp_offer dhcp_request dhcp_decline dhcp_ack dhcp_nak ## dhcp_release dhcp_inform ## @@ -16,7 +20,7 @@ ## protocol). It treats broadcast addresses just like any other and ## associates packets into transport-level flows in the same way as usual. ## -event dhcp_discover%(c: connection, msg: dhcp_msg, req_addr: addr, host_name: string%); +event dhcp_discover%(c: connection, msg: DHCP::dhcp_msg, req_addr: addr, host_name: string, client_id: DHCP::dhcp_client_id, req_params: DHCP::dhcp_params_list%); ## Generated for DHCP messages of type *DHCPOFFER* (server to client in response ## to DHCPDISCOVER with offer of configuration parameters). @@ -43,7 +47,7 @@ event dhcp_discover%(c: connection, msg: dhcp_msg, req_addr: addr, host_name: st ## protocol). It treats broadcast addresses just like any other and ## associates packets into transport-level flows in the same way as usual. ## -event dhcp_offer%(c: connection, msg: dhcp_msg, mask: addr, router: dhcp_router_list, lease: interval, serv_addr: addr, host_name: string%); +event dhcp_offer%(c: connection, msg: DHCP::dhcp_msg, mask: addr, router: DHCP::dhcp_router_list, lease: interval, serv_addr: addr, host_name: string%); ## Generated for DHCP messages of type *DHCPREQUEST* (Client message to servers either ## (a) requesting offered parameters from one server and implicitly declining offers @@ -60,6 +64,10 @@ event dhcp_offer%(c: connection, msg: dhcp_msg, mask: addr, router: dhcp_router_ ## ## host_name: The value of the host name option, if specified by the client. ## +## client_id: The client id. +## +## req_parms: The Parameters Request List. +## ## .. bro:see:: dhcp_discover dhcp_offer dhcp_decline dhcp_ack dhcp_nak ## dhcp_release dhcp_inform ## @@ -67,7 +75,7 @@ event dhcp_offer%(c: connection, msg: dhcp_msg, mask: addr, router: dhcp_router_ ## protocol). It treats broadcast addresses just like any other and ## associates packets into transport-level flows in the same way as usual. ## -event dhcp_request%(c: connection, msg: dhcp_msg, req_addr: addr, serv_addr: addr, host_name: string%); +event dhcp_request%(c: connection, msg: DHCP::dhcp_msg, req_addr: addr, serv_addr: addr, host_name: string, client_id: DHCP::dhcp_client_id, req_params: DHCP::dhcp_params_list%); ## Generated for DHCP messages of type *DHCPDECLINE* (Client to server indicating ## network address is already in use). @@ -85,7 +93,7 @@ event dhcp_request%(c: connection, msg: dhcp_msg, req_addr: addr, serv_addr: add ## protocol). It treats broadcast addresses just like any other and ## associates packets into transport-level flows in the same way as usual. ## -event dhcp_decline%(c: connection, msg: dhcp_msg, host_name: string%); +event dhcp_decline%(c: connection, msg: DHCP::dhcp_msg, host_name: string%); ## Generated for DHCP messages of type *DHCPACK* (Server to client with configuration ## parameters, including committed network address). @@ -105,10 +113,21 @@ event dhcp_decline%(c: connection, msg: dhcp_msg, host_name: string%); ## host_name: Optional host name value. May differ from the host name requested ## from the client. ## +## reb_time: A 32-bit unsigned integer indicating the number of seconds before +## the cilent enters the rebinding state if it has not renewed its +## current address lease with the DHCP server. +## +## ren_time: A 32-bit unsigned integer indicating the number of seconds before +## the client begins to renew its address lease with the DHCP server. +## +## sub_opt: DHCP relay agent information option list of suboption values +## (see http://slaptijack.com/networking/what-is-dhcp-option-82/ or +## http://www.juniper.net/documentation/en_US/junose14.3/topics/concept/dhcp-relay-option-82-suboptions-overview.html) +## ## .. bro:see:: dhcp_discover dhcp_offer dhcp_request dhcp_decline dhcp_nak ## dhcp_release dhcp_inform ## -event dhcp_ack%(c: connection, msg: dhcp_msg, mask: addr, router: dhcp_router_list, lease: interval, serv_addr: addr, host_name: string%); +event dhcp_ack%(c: connection, msg: DHCP::dhcp_msg, mask: addr, router: DHCP::dhcp_router_list, lease: interval, serv_addr: addr, host_name: string, reb_time: count, ren_time: count, sub_opt: DHCP::dhcp_sub_opt_list%); ## Generated for DHCP messages of type *DHCPNAK* (Server to client indicating client's ## notion of network address is incorrect (e.g., client has moved to new subnet) or @@ -127,7 +146,7 @@ event dhcp_ack%(c: connection, msg: dhcp_msg, mask: addr, router: dhcp_router_li ## protocol). It treats broadcast addresses just like any other and ## associates packets into transport-level flows in the same way as usual. ## -event dhcp_nak%(c: connection, msg: dhcp_msg, host_name: string%); +event dhcp_nak%(c: connection, msg: DHCP::dhcp_msg, host_name: string%); ## Generated for DHCP messages of type *DHCPRELEASE* (Client to server relinquishing ## network address and cancelling remaining lease). @@ -141,7 +160,7 @@ event dhcp_nak%(c: connection, msg: dhcp_msg, host_name: string%); ## .. bro:see:: dhcp_discover dhcp_offer dhcp_request dhcp_decline dhcp_ack dhcp_nak ## dhcp_inform ## -event dhcp_release%(c: connection, msg: dhcp_msg, host_name: string%); +event dhcp_release%(c: connection, msg: DHCP::dhcp_msg, host_name: string%); ## Generated for DHCP messages of type *DHCPINFORM* (Client to server, asking only for ## local configuration parameters; client already has externally configured network @@ -153,6 +172,8 @@ event dhcp_release%(c: connection, msg: dhcp_msg, host_name: string%); ## ## host_name: The value of the host name option, if specified by the client. ## +## req_parms: The Parameters Request List. +## ## .. bro:see:: dhcp_discover dhcp_offer dhcp_request dhcp_decline dhcp_ack dhcp_nak ## dhcp_release ## @@ -160,5 +181,5 @@ event dhcp_release%(c: connection, msg: dhcp_msg, host_name: string%); ## protocol). It treats broadcast addresses just like any other and ## associates packets into transport-level flows in the same way as usual. ## -event dhcp_inform%(c: connection, msg: dhcp_msg, host_name: string%); +event dhcp_inform%(c: connection, msg: DHCP::dhcp_msg, host_name: string, req_params: DHCP::dhcp_params_list%); diff --git a/src/analyzer/protocol/dhcp/types.bif b/src/analyzer/protocol/dhcp/types.bif new file mode 100644 index 0000000000..8f501fc7fd --- /dev/null +++ b/src/analyzer/protocol/dhcp/types.bif @@ -0,0 +1,10 @@ +module DHCP; + +type dhcp_msg: record; +type dhcp_router_list: table; +type dhcp_params_list: table; +type dhcp_sub_opt_list: table; +type dhcp_sub_opt: record; +type dhcp_client_id: record; + +module GLOBAL; From 928e33a7b8019a178ed6ca6dc819b350aefcef16 Mon Sep 17 00:00:00 2001 From: Valerio G Date: Mon, 8 Jan 2018 21:39:11 +0100 Subject: [PATCH 2/4] Add .btest scripts for dhck_ack and dhcp_discover messages verifying that new options are correctly reported in dhcp.log records. --- .../dhcp.log | 10 ++++++++++ .../dhcp.log | 10 ++++++++++ ...cp_ack_subscriber_id_and_agent_remote_id.trace | Bin 0 -> 419 bytes .../dhcp_discover_param_req_and_client_id.trace | Bin 0 -> 363 bytes .../base/protocols/dhcp/dhcp-ack-msg-types.btest | 6 ++++++ .../protocols/dhcp/dhcp-discover-msg-types.btest | 6 ++++++ 6 files changed, 32 insertions(+) create mode 100644 testing/btest/Baseline/scripts.base.protocols.dhcp.dhcp-ack-msg-types/dhcp.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.dhcp.dhcp-discover-msg-types/dhcp.log create mode 100644 testing/btest/Traces/dhcp/dhcp_ack_subscriber_id_and_agent_remote_id.trace create mode 100644 testing/btest/Traces/dhcp/dhcp_discover_param_req_and_client_id.trace create mode 100644 testing/btest/scripts/base/protocols/dhcp/dhcp-ack-msg-types.btest create mode 100644 testing/btest/scripts/base/protocols/dhcp/dhcp-discover-msg-types.btest diff --git a/testing/btest/Baseline/scripts.base.protocols.dhcp.dhcp-ack-msg-types/dhcp.log b/testing/btest/Baseline/scripts.base.protocols.dhcp.dhcp-ack-msg-types/dhcp.log new file mode 100644 index 0000000000..1edaec49ee --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.dhcp.dhcp-ack-msg-types/dhcp.log @@ -0,0 +1,10 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path dhcp +#open 2018-01-08-17-58-31 +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p mac assigned_ip lease_time trans_id msg_type client_id server_id host_name subscriber_id agent_remote_id +#types time string addr port addr port string addr interval count string string addr string string string +1102274184.387798 CHhAvVGS1DHFjwGM9 10.10.0.10 68 10.10.0.1 67 00:0a:28:00:fa:42 192.168.0.10 3600.000000 15633 DHCP_ACK - 10.10.0.1 (empty) -subID- 13 +#close 2018-01-08-17-58-31 diff --git a/testing/btest/Baseline/scripts.base.protocols.dhcp.dhcp-discover-msg-types/dhcp.log b/testing/btest/Baseline/scripts.base.protocols.dhcp.dhcp-discover-msg-types/dhcp.log new file mode 100644 index 0000000000..13e87b3855 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.dhcp.dhcp-discover-msg-types/dhcp.log @@ -0,0 +1,10 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path dhcp +#open 2018-01-08-17-58-41 +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p mac assigned_ip lease_time trans_id msg_type client_id server_id host_name subscriber_id agent_remote_id +#types time string addr port addr port string addr interval count string string addr string string string +1102274184.317453 CHhAvVGS1DHFjwGM9 0.0.0.0 68 255.255.255.255 67 - - - 15633 DHCP_DISCOVER 00:0b:82:01:fc:42 - test0000 - - +#close 2018-01-08-17-58-41 diff --git a/testing/btest/Traces/dhcp/dhcp_ack_subscriber_id_and_agent_remote_id.trace b/testing/btest/Traces/dhcp/dhcp_ack_subscriber_id_and_agent_remote_id.trace new file mode 100644 index 0000000000000000000000000000000000000000..b5e72d473576c32fbc99cf0775860ff4e1860f4f GIT binary patch literal 419 zcmca|c+)~A1{MYw`2U}Qff2~*h}-OV?G-CSHIM_s3|txvzns9NBL{;k17j|W8v{dw zprQ;H7Xu>@b1^tGxG+Xal`%200hQYd!c07{0w@Oq5K~~hAx|ea1t*&_vRVPdkDbFB zNb=|z14%vsGZs*=FtYpyhG&opqgY8sX0ZYg<>%#8DkLhDq!yRx>FF^s3bV267MCV@ Ly66JK9R~maz#k;D literal 0 HcmV?d00001 diff --git a/testing/btest/Traces/dhcp/dhcp_discover_param_req_and_client_id.trace b/testing/btest/Traces/dhcp/dhcp_discover_param_req_and_client_id.trace new file mode 100644 index 0000000000000000000000000000000000000000..bfdbb54c01dd71276c37f881c1dd3d8198cc5691 GIT binary patch literal 363 zcmca|c+)~A1{MYw`2U}Qff2~*h}-PQdxM3+8OQDAV?eoa5pjjal#NCvI5CX!O5nKjJE8I3}Bxbv0QMz Ych8)Kk(o`4hodC5xWoVmfI$iZ0FO;2VE_OC literal 0 HcmV?d00001 diff --git a/testing/btest/scripts/base/protocols/dhcp/dhcp-ack-msg-types.btest b/testing/btest/scripts/base/protocols/dhcp/dhcp-ack-msg-types.btest new file mode 100644 index 0000000000..8f192b7aa4 --- /dev/null +++ b/testing/btest/scripts/base/protocols/dhcp/dhcp-ack-msg-types.btest @@ -0,0 +1,6 @@ +# This tests that DHCP leases are logged in dhcp.log +# The trace has a message of each DHCP message type, +# but only one lease should show up in the logs. + +# @TEST-EXEC: bro -r $TRACES/dhcp/dhcp_ack_subscriber_id_and_agent_remote_id.trace %INPUT +# @TEST-EXEC: btest-diff dhcp.log diff --git a/testing/btest/scripts/base/protocols/dhcp/dhcp-discover-msg-types.btest b/testing/btest/scripts/base/protocols/dhcp/dhcp-discover-msg-types.btest new file mode 100644 index 0000000000..1952682e61 --- /dev/null +++ b/testing/btest/scripts/base/protocols/dhcp/dhcp-discover-msg-types.btest @@ -0,0 +1,6 @@ +# This tests that DHCP leases are logged in dhcp.log +# The trace has a message of each DHCP message type, +# but only one lease should show up in the logs. + +# @TEST-EXEC: bro -r $TRACES/dhcp/dhcp_discover_param_req_and_client_id.trace %INPUT +# @TEST-EXEC: btest-diff dhcp.log From c2f35920fd1a045c893713557b2838fd38471c4d Mon Sep 17 00:00:00 2001 From: Seth Hall Date: Fri, 2 Feb 2018 10:14:15 -0500 Subject: [PATCH 3/4] First step of DHCP analyzer rearchitecture. Old event prototypes have changed and the events are broken right now and may be removed in favor of the new generic "dhcp_message" event. DHCP option parsing is abstracted from the main code base of the protocol parser and are all now located in their own file. Documentation, tests, and final code cleanup are still pending. --- scripts/base/init-bare.bro | 48 +- scripts/base/protocols/dhcp/consts.bro | 26 +- scripts/base/protocols/dhcp/main.bro | 113 ++--- src/NetVar.cc | 6 - src/NetVar.h | 3 - src/analyzer/protocol/dhcp/CMakeLists.txt | 2 +- src/analyzer/protocol/dhcp/DHCP.cc | 11 +- src/analyzer/protocol/dhcp/DHCP.h | 8 +- src/analyzer/protocol/dhcp/dhcp-analyzer.pac | 493 +++++++------------ src/analyzer/protocol/dhcp/dhcp-options.pac | 327 ++++++++++++ src/analyzer/protocol/dhcp/dhcp-protocol.pac | 145 +++--- src/analyzer/protocol/dhcp/dhcp.pac | 10 + src/analyzer/protocol/dhcp/events.bif | 19 +- src/analyzer/protocol/dhcp/types.bif | 15 +- 14 files changed, 728 insertions(+), 498 deletions(-) create mode 100644 src/analyzer/protocol/dhcp/dhcp-options.pac diff --git a/scripts/base/init-bare.bro b/scripts/base/init-bare.bro index a7047d4cfc..9ea7a4ce00 100644 --- a/scripts/base/init-bare.bro +++ b/scripts/base/init-bare.bro @@ -3064,11 +3064,12 @@ export { ## A list of router addresses offered by a DHCP server. ## ## .. bro:see:: dhcp_ack dhcp_offer - type DHCP::dhcp_router_list: table[count] of addr; + type DHCP::RouterList: table[count] of addr; + ## A DHCP message. ## .. bro:see:: dhcp_ack dhcp_decline dhcp_discover dhcp_inform dhcp_nak ## dhcp_offer dhcp_release dhcp_request - type DHCP::dhcp_msg: record { + type DHCP::Msg: record { op: count; ##< Message OP code. 1 = BOOTREQUEST, 2 = BOOTREPLY m_type: count; ##< The type of DHCP message. xid: count; ##< Transaction ID of a DHCP session. @@ -3076,22 +3077,55 @@ export { ciaddr: addr; ##< Original IP address of the client. yiaddr: addr; ##< IP address assigned to the client. }; - ## DHCP Paremeter Reuqest list (Option 55) + + ## DHCP Parameter Request list (Option 55) ## .. bro:see:: dhcp_request dhcp_discover - type DHCP::dhcp_params_list: table[count] of count; + type DHCP::ParamsList: table[count] of count; + ## DHCP Relay Agent Information Option (Option 82) ## .. bro:see:: dhcp_ack - type DHCP::dhcp_sub_opt: record { + type DHCP::SubOpt: record { code: count; value: string; }; + ## DHCP Client Identifier (Option 61) ## .. bro:see:: dhcp_request dhcp_discover - type DHCP::dhcp_client_id: record { + type DHCP::ClientID: record { hwtype: count; hwaddr: string; }; - type DHCP::dhcp_sub_opt_list: table[count] of DHCP::dhcp_sub_opt; + + type DHCP::SubOptList: table[count] of DHCP::SubOpt; + + type DHCP::Options: record { + subnet_mask: addr &optional; + + host_name: string &optional; + + req_addr: addr &optional; + + router_list: DHCP::RouterList &optional; + + lease: interval &optional; + + serv_addr: addr &optional; + + ## DHCP Parameter Request list (Option 55) + param_list: DHCP::ParamsList &optional; + + ren_time: interval &optional; + + reb_time: interval &optional; + + ## DHCP Client Identifier (Option 61) + client_id: DHCP::ClientID &optional; + + ## DHCP Relay Agent Information Option (Option 82) + sub_opt: DHCP::SubOptList &optional; + }; + + } module GLOBAL; diff --git a/scripts/base/protocols/dhcp/consts.bro b/scripts/base/protocols/dhcp/consts.bro index 5afdfc9415..1ca47ac36f 100644 --- a/scripts/base/protocols/dhcp/consts.bro +++ b/scripts/base/protocols/dhcp/consts.bro @@ -7,14 +7,24 @@ export { ## Types of DHCP messages. See :rfc:`1533`. const message_types = { - [1] = "DHCP_DISCOVER", - [2] = "DHCP_OFFER", - [3] = "DHCP_REQUEST", - [4] = "DHCP_DECLINE", - [5] = "DHCP_ACK", - [6] = "DHCP_NAK", - [7] = "DHCP_RELEASE", - [8] = "DHCP_INFORM", + [1] = "DHCP_DISCOVER", + [2] = "DHCP_OFFER", + [3] = "DHCP_REQUEST", + [4] = "DHCP_DECLINE", + [5] = "DHCP_ACK", + [6] = "DHCP_NAK", + [7] = "DHCP_RELEASE", + [8] = "DHCP_INFORM", + [9] = "DHCP_FORCERENEW", + [10] = "DHCP_LEASEQUERY", + [11] = "DHCP_LEASEUNASSIGNED", + [12] = "DHCP_DHCPLEASEUNKNOWN", + [13] = "DHCP_LEASEACTIVE", + [14] = "DHCP_BULKLEASEQUERY", + [15] = "DHCP_LEASEQUERYDONE", + [16] = "DHCP_ACTIVELEASEQUERY", + [17] = "DHCP_LEASEQUERYSTATUS", + [18] = "DHCP_TLS", } &default = function(n: count): string { return fmt("unknown-message-type-%d", n); }; } diff --git a/scripts/base/protocols/dhcp/main.bro b/scripts/base/protocols/dhcp/main.bro index 92b61697fe..0b45d69a4b 100644 --- a/scripts/base/protocols/dhcp/main.bro +++ b/scripts/base/protocols/dhcp/main.bro @@ -59,91 +59,60 @@ redef record connection += { const ports = { 67/udp, 68/udp }; redef likely_server_ports += { 67/udp }; -global info: Info; - event bro_init() &priority=5 { Log::create_stream(DHCP::LOG, [$columns=Info, $ev=log_dhcp, $path="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, reb_time: count, ren_time: count, sub_opt: dhcp_sub_opt_list) &priority=5 +event dhcp_message(c: connection, is_orig: bool, msg: DHCP::Msg, options: DHCP::Options) &priority=-5 { - #local info: Info; - info$ts = network_time(); - info$id = c$id; - info$uid = c$uid; - info$lease_time = lease; - info$trans_id = msg$xid; - info$msg_type = message_types[msg$m_type]; + if ( msg$m_type == 5 ) # DHCP_ACK + { + local info = Info($ts = network_time(), + $id = c$id, + $uid = c$uid, + $trans_id = msg$xid); - info$server_id = serv_addr; - info$host_name = host_name; + if ( msg$h_addr != "" ) + info$mac = msg$h_addr; - if ( msg$h_addr != "" ) - info$mac = msg$h_addr; + if ( reverse_ip(msg$yiaddr) != 0.0.0.0 ) + info$assigned_ip = reverse_ip(msg$yiaddr); + else + info$assigned_ip = c$id$orig_h; - if ( reverse_ip(msg$yiaddr) != 0.0.0.0 ) - info$assigned_ip = reverse_ip(msg$yiaddr); - else - info$assigned_ip = c$id$orig_h; + if ( options?$lease ) + info$lease_time = options$lease; - for (param in sub_opt) - { - #if ( sub_opt[param]$code == 1 ) - #{ - #print fmt("Relay Agent Information:"); - #print fmt( "sub option: code=%d circuit id=%s",sub_opt[param]$code,sub_opt[param]$value ); - #} - if ( sub_opt[param]$code == 2 ) - info$agent_remote_id = bytestring_to_hexstr(sub_opt[param]$value); + if ( options?$sub_opt ) + { + for ( param in options$sub_opt ) + { + local sub_opt = options$sub_opt[param]; - if ( sub_opt[param]$code == 6 ) - info$subscriber_id = (sub_opt[param]$value); + #if ( sub_opt$code == 1 ) + # { + # print fmt("Relay Agent Information:"); + # print fmt( "sub option: code=%d circuit id=%s",sub_opt$code,sub_opt$value ); + # } + + if ( sub_opt$code == 2 ) + info$agent_remote_id = bytestring_to_hexstr(sub_opt$value); + + if ( sub_opt$code == 6 ) + info$subscriber_id = (sub_opt$value); + } + } + + c$dhcp = info; + } } - 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, reb_time: count, ren_time: count, sub_opt: dhcp_sub_opt_list) &priority=-5 +event dhcp_message(c: connection, is_orig: bool, msg: DHCP::Msg, options: DHCP::Options) &priority=-5 { - Log::write(DHCP::LOG, c$dhcp); + if ( msg$m_type == 5 ) # DHCP_ACK + { + Log::write(DHCP::LOG, c$dhcp); + } } - -event dhcp_request(c: connection, msg: dhcp_msg, req_addr: addr, serv_addr: addr, host_name: string, c_id: dhcp_client_id, req_params: table[count] of count) &priority=5 - { - info$ts = network_time(); - info$id = c$id; - info$uid = c$uid; - info$trans_id = msg$xid; - info$msg_type = message_types[msg$m_type]; - info$server_id = serv_addr; - info$host_name = host_name; - info$client_id = c_id$hwaddr; - - c$dhcp = info; - } - -event dhcp_request(c: connection, msg: dhcp_msg, req_addr: addr, serv_addr: addr, host_name: string, c_id: dhcp_client_id, req_params: table[count] of count) &priority=-5 - { - Log::write(DHCP::LOG, c$dhcp); - } - -event dhcp_discover(c: connection, msg: dhcp_msg, req_addr: addr, host_name: string, c_id: dhcp_client_id, req_params: table[count] of count) &priority=5 - { - info$ts = network_time(); - info$id = c$id; - info$uid = c$uid; - info$trans_id = msg$xid; - info$msg_type = message_types[msg$m_type]; - info$host_name = host_name; - info$client_id = c_id$hwaddr; - - c$dhcp = info; - } - -event dhcp_discover(c: connection, msg: dhcp_msg, req_addr: addr, host_name: string, c_id: dhcp_client_id, req_params: table[count] of count) &priority=-5 - { - Log::write(DHCP::LOG, c$dhcp); - } - diff --git a/src/NetVar.cc b/src/NetVar.cc index 3f0967dbc4..93533b9627 100644 --- a/src/NetVar.cc +++ b/src/NetVar.cc @@ -110,9 +110,6 @@ RecordType* geo_location; RecordType* entropy_test_result; -TableType* dhcp_router_list; -RecordType* dhcp_msg; - RecordType* dns_msg; RecordType* dns_answer; RecordType* dns_soa; @@ -426,9 +423,6 @@ void init_net_var() entropy_test_result = internal_type("entropy_test_result")->AsRecordType(); - dhcp_router_list = internal_type("DHCP::dhcp_router_list")->AsTableType(); - dhcp_msg = internal_type("DHCP::dhcp_msg")->AsRecordType(); - dns_msg = internal_type("dns_msg")->AsRecordType(); dns_answer = internal_type("dns_answer")->AsRecordType(); dns_soa = internal_type("dns_soa")->AsRecordType(); diff --git a/src/NetVar.h b/src/NetVar.h index 2b8ebd69c2..023be18867 100644 --- a/src/NetVar.h +++ b/src/NetVar.h @@ -113,9 +113,6 @@ extern RecordType* geo_location; extern RecordType* entropy_test_result; -extern TableType* dhcp_router_list; -extern RecordType* dhcp_msg; - extern RecordType* dns_msg; extern RecordType* dns_answer; extern RecordType* dns_soa; diff --git a/src/analyzer/protocol/dhcp/CMakeLists.txt b/src/analyzer/protocol/dhcp/CMakeLists.txt index ece07e3a7e..6077adfeb6 100644 --- a/src/analyzer/protocol/dhcp/CMakeLists.txt +++ b/src/analyzer/protocol/dhcp/CMakeLists.txt @@ -7,5 +7,5 @@ bro_plugin_begin(Bro DHCP) bro_plugin_cc(DHCP.cc Plugin.cc) bro_plugin_bif(events.bif) bro_plugin_bif(types.bif) -bro_plugin_pac(dhcp.pac dhcp-protocol.pac dhcp-analyzer.pac) +bro_plugin_pac(dhcp.pac dhcp-protocol.pac dhcp-analyzer.pac dhcp-options.pac) bro_plugin_end() diff --git a/src/analyzer/protocol/dhcp/DHCP.cc b/src/analyzer/protocol/dhcp/DHCP.cc index 4ab77c09a4..11ecb91107 100644 --- a/src/analyzer/protocol/dhcp/DHCP.cc +++ b/src/analyzer/protocol/dhcp/DHCP.cc @@ -25,5 +25,14 @@ void DHCP_Analyzer::DeliverPacket(int len, const u_char* data, bool orig, uint64 seq, const IP_Hdr* ip, int caplen) { Analyzer::DeliverPacket(len, data, orig, seq, ip, caplen); - interp->NewData(orig, data, data + len); + + try + { + interp->NewData(orig, data, data + len); + } + catch ( const binpac::Exception& e ) + { + ProtocolViolation(fmt("Binpac exception: %s", e.c_msg())); + } + } diff --git a/src/analyzer/protocol/dhcp/DHCP.h b/src/analyzer/protocol/dhcp/DHCP.h index f8f0449878..7d0f88724d 100644 --- a/src/analyzer/protocol/dhcp/DHCP.h +++ b/src/analyzer/protocol/dhcp/DHCP.h @@ -10,11 +10,11 @@ namespace analyzer { namespace dhcp { class DHCP_Analyzer : public analyzer::Analyzer { public: DHCP_Analyzer(Connection* conn); - virtual ~DHCP_Analyzer(); + ~DHCP_Analyzer() override; - virtual void Done(); - virtual void DeliverPacket(int len, const u_char* data, bool orig, - uint64 seq, const IP_Hdr* ip, int caplen); + void Done() override; + void DeliverPacket(int len, const u_char* data, bool orig, + uint64 seq, const IP_Hdr* ip, int caplen) override; static analyzer::Analyzer* Instantiate(Connection* conn) { return new DHCP_Analyzer(conn); } diff --git a/src/analyzer/protocol/dhcp/dhcp-analyzer.pac b/src/analyzer/protocol/dhcp/dhcp-analyzer.pac index f9b195088e..6c43cb07e8 100644 --- a/src/analyzer/protocol/dhcp/dhcp-analyzer.pac +++ b/src/analyzer/protocol/dhcp/dhcp-analyzer.pac @@ -1,284 +1,140 @@ -connection DHCP_Conn(bro_analyzer: BroAnalyzer) { - upflow = DHCP_Flow(true); - downflow = DHCP_Flow(false); -}; - -flow DHCP_Flow(is_orig: bool) { - datagram = DHCP_Message withcontext(connection, this); +refine flow DHCP_Flow += { %member{ - BroVal dhcp_msg_val_; - uint8 sum_len; + RecordVal *dhcp_msg_val; + RecordVal *options; %} %init{ - dhcp_msg_val_ = 0; - sum_len = 0; + dhcp_msg_val = 0; + options = 0; %} %cleanup{ - Unref(dhcp_msg_val_); - dhcp_msg_val_ = 0; - sum_len = 0; + Unref(dhcp_msg_val); + dhcp_msg_val = 0; + + Unref(options); + options = 0; %} - function get_dhcp_sumlen(len: uint8): uint8 + function parse_request(options: Option[], type: uint8): bool %{ - sum_len = len + sum_len; - return sum_len; - %} - - function get_dhcp_msgtype(options: DHCP_Option[]): uint8 - %{ - vector::const_iterator ptr; - uint8 type = 0; - - // Leave the for loop if the message type is found. - bool parsed = false; - - for ( ptr = options->begin(); - ptr != options->end() && ! (*ptr)->last(); ++ptr ) - { - // We use a switch for future expandability. - switch ( (*ptr)->code() ) { - case MSG_TYPE_OPTION: - type = (*ptr)->info()->msg_type(); - parsed = true; - break; - } - - if ( parsed ) - break; - } - - if ( type == 0 ) - connection()->bro_analyzer()->ProtocolViolation("no DHCP message type option"); - - return type; - %} - - function parse_request(options: DHCP_Option[], type: uint8): bool - %{ - vector::const_iterator ptr; - - // Requested IP address to the server. - ::uint32 req_addr = 0, serv_addr = 0; - StringVal* host_name = new StringVal(""); - - TableVal* params_list = 0; - RecordVal* client_id = new RecordVal(BifType::Record::DHCP::dhcp_client_id); - client_id->Assign(0,0); - client_id->Assign(1,new StringVal("")); - - for ( ptr = options->begin(); ptr != options->end() && ! (*ptr)->last(); ++ptr ) - { - switch ( (*ptr)->code() ) - { - case REQ_IP_OPTION: - req_addr = htonl((*ptr)->info()->req_addr()); - break; - - case SERV_ID_OPTION: - serv_addr = htonl((*ptr)->info()->serv_addr()); - break; - - case HOST_NAME_OPTION: - host_name = new StringVal((*ptr)->info()->host_name().length(), - (const char*) (*ptr)->info()->host_name().begin()); - break; - case CLIENT_ID_OPTION: - client_id->Assign(0, new Val((*ptr)->info()->client_id()->hwtype(), TYPE_COUNT)); - client_id->Assign(1, new StringVal(fmt_mac((*ptr)->info()->client_id()->hwaddr().begin(), (*ptr)->info()->client_id()->hwaddr().length()))); - break; - case PAR_REQ_LIST: - params_list = new TableVal(BifType::Table::DHCP::dhcp_params_list); - int num_parms = (*ptr)->info()->par_req_list()->size(); - for (int i=0; i < num_parms; ++i) - { - vector* plist = (*ptr)->info()->par_req_list(); - uint8 param = (*plist)[i]; - Val* index = new Val(i+1, TYPE_COUNT); - params_list->Assign(index, new Val(param, TYPE_COUNT)); - Unref(index); - } - break; - } - } - - switch ( type ) - { - case DHCPDISCOVER: - BifEvent::generate_dhcp_discover(connection()->bro_analyzer(), - connection()->bro_analyzer()->Conn(), - dhcp_msg_val_->Ref(), new AddrVal(req_addr), - host_name, client_id, params_list); - break; - - case DHCPREQUEST: - BifEvent::generate_dhcp_request(connection()->bro_analyzer(), - connection()->bro_analyzer()->Conn(), - dhcp_msg_val_->Ref(), new AddrVal(req_addr), - new AddrVal(serv_addr), host_name, client_id, params_list); - break; - - case DHCPDECLINE: - BifEvent::generate_dhcp_decline(connection()->bro_analyzer(), - connection()->bro_analyzer()->Conn(), - dhcp_msg_val_->Ref(), host_name); - break; - - case DHCPRELEASE: - BifEvent::generate_dhcp_release(connection()->bro_analyzer(), - connection()->bro_analyzer()->Conn(), - dhcp_msg_val_->Ref(), host_name); - break; - - case DHCPINFORM: - BifEvent::generate_dhcp_inform(connection()->bro_analyzer(), - connection()->bro_analyzer()->Conn(), - dhcp_msg_val_->Ref(), host_name, params_list); - break; - - default: - Unref(host_name); - break; - } +// // Requested IP address to the server. +// ::uint32 req_addr = 0, serv_addr = 0; +// StringVal* host_name = new StringVal(""); +// +// TableVal* params_list = 0; +// RecordVal* client_id = new RecordVal(BifType::Record::DHCP::ClientID); +// client_id->Assign(0,0); +// client_id->Assign(1,new StringVal("")); +// +// switch ( type ) +// { +// case DHCPDISCOVER: +// BifEvent::generate_dhcp_discover(connection()->bro_analyzer(), +// connection()->bro_analyzer()->Conn(), +// dhcp_msg_val->Ref(), new AddrVal(req_addr), +// host_name, client_id, params_list); +// break; +// +// case DHCPREQUEST: +// BifEvent::generate_dhcp_request(connection()->bro_analyzer(), +// connection()->bro_analyzer()->Conn(), +// dhcp_msg_val->Ref(), new AddrVal(req_addr), +// new AddrVal(serv_addr), host_name, client_id, params_list); +// break; +// +// case DHCPDECLINE: +// BifEvent::generate_dhcp_decline(connection()->bro_analyzer(), +// connection()->bro_analyzer()->Conn(), +// dhcp_msg_val->Ref(), host_name); +// break; +// +// case DHCPRELEASE: +// BifEvent::generate_dhcp_release(connection()->bro_analyzer(), +// connection()->bro_analyzer()->Conn(), +// dhcp_msg_val->Ref(), host_name); +// break; +// +// case DHCPINFORM: +// BifEvent::generate_dhcp_inform(connection()->bro_analyzer(), +// connection()->bro_analyzer()->Conn(), +// dhcp_msg_val->Ref(), host_name, params_list); +// break; +// +// default: +// Unref(host_name); +// break; +// } return true; %} - function parse_reply(options: DHCP_Option[], type: uint8): bool + function parse_reply(options: Option[], type: uint8): bool %{ - vector::const_iterator ptr; - vector::const_iterator ptrsubopt; +// // RFC 1533 allows a list of router addresses. +// TableVal* router_list = 0; +// +// ::uint32 subnet_mask = 0, serv_addr = 0; +// +// uint32 lease = 0; +// StringVal* host_name = 0; +// +// uint32 reb_time = 0; +// uint32 ren_time = 0; +// StringVal* agent_cir = 0; +// StringVal* agent_rem = 0; +// StringVal* agent_sub_opt = 0; +// TableVal* relay_agent_sub_opt = new TableVal(BifType::Table::DHCP::SubOptList); +// +// if ( host_name == nullptr ) +// host_name = new StringVal(""); +// +// switch ( type ) +// { +// case DHCPOFFER: +// if ( ! router_list ) +// router_list = new TableVal(BifType::Table::DHCP::RouterList); +// +// BifEvent::generate_dhcp_offer(connection()->bro_analyzer(), +// connection()->bro_analyzer()->Conn(), +// dhcp_msg_val->Ref(), new AddrVal(subnet_mask), +// router_list, lease, new AddrVal(serv_addr), host_name); +// break; +// +// case DHCPACK: +// if ( ! router_list ) +// router_list = new TableVal(BifType::Table::DHCP::RouterList); +// +// BifEvent::generate_dhcp_ack(connection()->bro_analyzer(), +// connection()->bro_analyzer()->Conn(), +// dhcp_msg_val->Ref(), new AddrVal(subnet_mask), +// router_list, lease, new AddrVal(serv_addr), host_name, reb_time, ren_time, relay_agent_sub_opt); +// break; +// +// case DHCPNAK: +// //Unref(router_list); +// BifEvent::generate_dhcp_nak(connection()->bro_analyzer(), +// connection()->bro_analyzer()->Conn(), +// dhcp_msg_val->Ref(), host_name); +// break; +// +// default: +// //Unref(router_list); +// //Unref(host_name); +// break; +// } +// + return true; + %} - // RFC 1533 allows a list of router addresses. - TableVal* router_list = 0; - - ::uint32 subnet_mask = 0, serv_addr = 0; - - uint32 lease = 0; - StringVal* host_name = 0; - - uint32 reb_time = 0; - uint32 ren_time = 0; - StringVal* agent_cir = 0; - StringVal* agent_rem = 0; - StringVal* agent_sub_opt = 0; - TableVal* relay_agent_sub_opt = new TableVal(BifType::Table::DHCP::dhcp_sub_opt_list); - - for ( ptr = options->begin(); - ptr != options->end() && ! (*ptr)->last(); ++ptr ) - { - switch ( (*ptr)->code() ) - { - case SUBNET_OPTION: - subnet_mask = htonl((*ptr)->info()->mask()); - break; - - case ROUTER_OPTION: - // Let's hope there aren't multiple - // such options. - //Unref(router_list); - router_list = new TableVal(dhcp_router_list); - - { - int num_routers = (*ptr)->info()->router_list()->size(); - - for ( int i = 0; i < num_routers; ++i ) - { - vector* rlist = (*ptr)->info()->router_list(); - - uint32 raddr = (*rlist)[i]; - ::uint32 tmp_addr; - tmp_addr = htonl(raddr); - - // index starting from 1 - Val* index = new Val(i + 1, TYPE_COUNT); - router_list->Assign(index, new AddrVal(tmp_addr)); - Unref(index); - } - } - break; - - case LEASE_OPTION: - lease = (*ptr)->info()->lease(); - break; - - case SERV_ID_OPTION: - serv_addr = htonl((*ptr)->info()->serv_addr()); - break; - - case HOST_NAME_OPTION: - host_name = new StringVal((*ptr)->info()->host_name().length(), - (const char*) (*ptr)->info()->host_name().begin()); - break; - - case REB_TIME_OPTION: - reb_time = (*ptr)->info()->reb_time(); - break; - - case REN_TIME_OPTION: - ren_time = (*ptr)->info()->ren_time(); - break; - - case RELAY_AGENT_INF: - RecordVal* r = new RecordVal(BifType::Record::DHCP::dhcp_sub_opt); - uint i = 0; - for( ptrsubopt = (*ptr)->info()->relay_agent_inf()->begin(); ptrsubopt != (*ptr)->info()->relay_agent_inf()->end(); ++ptrsubopt) - { - r = new RecordVal(BifType::Record::DHCP::dhcp_sub_opt); - Val* index = new Val(i + 1, TYPE_COUNT); - r->Assign(0, new Val((*ptrsubopt)->code(), TYPE_COUNT)); - r->Assign(1, bytestring_to_val((*ptrsubopt)->value())); - relay_agent_sub_opt->Assign(index, r); - Unref(index); - ++i; - } - break; - } - } - - if ( host_name == 0 ) - host_name = new StringVal(""); - - switch ( type ) - { - case DHCPOFFER: - if ( ! router_list ) - router_list = new TableVal(dhcp_router_list); - - BifEvent::generate_dhcp_offer(connection()->bro_analyzer(), - connection()->bro_analyzer()->Conn(), - dhcp_msg_val_->Ref(), new AddrVal(subnet_mask), - router_list, lease, new AddrVal(serv_addr), host_name); - break; - - case DHCPACK: - if ( ! router_list ) - router_list = new TableVal(dhcp_router_list); - - BifEvent::generate_dhcp_ack(connection()->bro_analyzer(), - connection()->bro_analyzer()->Conn(), - dhcp_msg_val_->Ref(), new AddrVal(subnet_mask), - router_list, lease, new AddrVal(serv_addr), host_name, reb_time, ren_time, relay_agent_sub_opt); - break; - - case DHCPNAK: - //Unref(router_list); - BifEvent::generate_dhcp_nak(connection()->bro_analyzer(), - connection()->bro_analyzer()->Conn(), - dhcp_msg_val_->Ref(), host_name); - break; - - default: - //Unref(router_list); - //Unref(host_name); - break; - } + function create_options(): bool + %{ + if ( options == nullptr ) + options = new RecordVal(BifType::Record::DHCP::Options); return true; - %} function process_dhcp_message(msg: DHCP_Message): bool @@ -292,55 +148,81 @@ flow DHCP_Flow(is_orig: bool) { return false; } - Unref(dhcp_msg_val_); + Unref(dhcp_msg_val); std::string mac_str = fmt_mac(${msg.chaddr}.data(), ${msg.chaddr}.length()); - RecordVal* r = new RecordVal(dhcp_msg); - r->Assign(0, new Val(${msg.op}, TYPE_COUNT)); - r->Assign(1, new Val(${msg.type}, TYPE_COUNT)); - r->Assign(2, new Val(${msg.xid}, TYPE_COUNT)); - r->Assign(3, new StringVal(mac_str)); - r->Assign(4, new AddrVal(${msg.ciaddr})); - r->Assign(5, new AddrVal(${msg.yiaddr})); + dhcp_msg_val = new RecordVal(BifType::Record::DHCP::Msg); + dhcp_msg_val->Assign(0, new Val(${msg.op}, TYPE_COUNT)); + dhcp_msg_val->Assign(1, new Val(${msg.type}, TYPE_COUNT)); + dhcp_msg_val->Assign(2, new Val(${msg.xid}, TYPE_COUNT)); + dhcp_msg_val->Assign(3, new StringVal(mac_str)); + dhcp_msg_val->Assign(4, new AddrVal(${msg.ciaddr})); + dhcp_msg_val->Assign(5, new AddrVal(${msg.yiaddr})); - dhcp_msg_val_ = r; + if ( dhcp_message ) + BifEvent::generate_dhcp_message(connection()->bro_analyzer(), + connection()->bro_analyzer()->Conn(), + ${msg.is_orig}, + dhcp_msg_val->Ref(), + options->Ref()); - switch ( ${msg.op} ) - { - case BOOTREQUEST: // presumably from client to server - if ( ${msg.type} == DHCPDISCOVER || - ${msg.type} == DHCPREQUEST || - ${msg.type} == DHCPDECLINE || - ${msg.type} == DHCPRELEASE || - ${msg.type} == DHCPINFORM ) - parse_request(${msg.options}, ${msg.type}); - else - connection()->bro_analyzer()->ProtocolViolation(fmt("unknown DHCP message type option for BOOTREQUEST (%d)", - ${msg.type})); - break; + Unref(dhcp_msg_val); + dhcp_msg_val = 0; + Unref(options); + options = 0; - case BOOTREPLY: // presumably from server to client - if ( ${msg.type} == DHCPOFFER || - ${msg.type} == DHCPACK || - ${msg.type} == DHCPNAK || - ${msg.type} == DHCPLEASEUNASSIGNED || - ${msg.type} == DHCPLEASEUNKNOWN || - ${msg.type} == DHCPLEASEACTIVE ) - parse_reply(${msg.options}, ${msg.type}); - else - connection()->bro_analyzer()->ProtocolViolation(fmt("unknown DHCP message type option for BOOTREPLY (%d)", - ${msg.type})); - - break; - - default: - connection()->bro_analyzer()->ProtocolViolation(fmt("unknown DHCP message op code (%d). Known codes: 1=BOOTREQUEST, 2=BOOTREPLY", - ${msg.op})); - break; - } + //switch ( ${msg.op} ) + // { + // case BOOTREQUEST: // presumably from client to server + // if ( ${msg.type} == DHCPDISCOVER || + // ${msg.type} == DHCPREQUEST || + // ${msg.type} == DHCPDECLINE || + // ${msg.type} == DHCPRELEASE || + // ${msg.type} == DHCPINFORM ) + // { + // parse_request(${msg.options}, ${msg.type}); + // } + // else + // { + // connection()->bro_analyzer()->ProtocolViolation(fmt("unknown DHCP message type option for BOOTREQUEST (%d)", + // ${msg.type})); + // } + // break; + // + // case BOOTREPLY: // presumably from server to client + // if ( ${msg.type} == DHCPOFFER || + // ${msg.type} == DHCPACK || + // ${msg.type} == DHCPNAK || + // ${msg.type} == DHCPLEASEUNASSIGNED || + // ${msg.type} == DHCPLEASEUNKNOWN || + // ${msg.type} == DHCPLEASEACTIVE ) + // { + // parse_reply(${msg.options}, ${msg.type}); + // } + // else + // { + // connection()->bro_analyzer()->ProtocolViolation(fmt("unknown DHCP message type option for BOOTREPLY (%d)", + // ${msg.type})); + // } + // + // break; + // + // default: + // // Removing this because I've seen some packets with weird values + // // but they still parse fine. + // //connection()->bro_analyzer()->ProtocolViolation(fmt("unknown DHCP message op code (%d). Known codes: 1=BOOTREQUEST, 2=BOOTREPLY", + // // ${msg.op})); + // break; + // } + // A single message reaching this point is enough to confirm the protocol + // because it's not uncommon to see a single DHCP message + // on a "connection". + // The binpac analyzer would have thrown an error before this point + // if there was a problem too (and subsequently called ProtocolViolation). connection()->bro_analyzer()->ProtocolConfirmation(); + return true; %} }; @@ -348,3 +230,8 @@ flow DHCP_Flow(is_orig: bool) { refine typeattr DHCP_Message += &let { proc_dhcp_message = $context.flow.process_dhcp_message(this); }; + +refine typeattr Option += &let { + proc_create_options = $context.flow.create_options(); +}; + diff --git a/src/analyzer/protocol/dhcp/dhcp-options.pac b/src/analyzer/protocol/dhcp/dhcp-options.pac new file mode 100644 index 0000000000..d39484ba96 --- /dev/null +++ b/src/analyzer/protocol/dhcp/dhcp-options.pac @@ -0,0 +1,327 @@ + +############################## +# SUBNET OPTION +############################## +let SUBNET_OPTION = 1; + +# Parse the option +refine casetype OptionValue += { + SUBNET_OPTION -> mask : uint32; +}; + +refine flow DHCP_Flow += { + function process_subnet_option(v: OptionValue): bool + %{ + ${context.flow}->options->Assign(0, new AddrVal(htonl(${v.mask}))); + return true; + %} +}; + +refine typeattr Option += &let { + proc_subnet_option = $context.flow.process_subnet_option(info) &if(code==SUBNET_OPTION); +}; + + +############################## +# HOST NAME OPTION +############################## +let HOST_NAME_OPTION = 12; + +# Parse the option +refine casetype OptionValue += { + HOST_NAME_OPTION -> host_name : bytestring &length=length; +}; + +refine flow DHCP_Flow += { + function process_host_name_option(v: OptionValue): bool + %{ + ${context.flow}->options->Assign(1, new StringVal(${v.host_name}.length(), (const char*) ${v.host_name}.begin())); + + return true; + %} +}; + +refine typeattr Option += &let { + proc_host_name_option = $context.flow.process_host_name_option(info) &if(code==HOST_NAME_OPTION); +}; + + +############################## +# REQ IP OPTION +############################## +let REQ_IP_OPTION = 50; + +# Parse the option +refine casetype OptionValue += { + REQ_IP_OPTION -> req_addr : uint32; +}; + +refine flow DHCP_Flow += { + function process_req_ip_option(v: OptionValue): bool + %{ + ${context.flow}->options->Assign(2, new AddrVal(htonl(${v.req_addr}))); + + return true; + %} +}; + +refine typeattr Option += &let { + proc_req_ip_option = $context.flow.process_req_ip_option(info) &if(code==REQ_IP_OPTION); +}; + +############################## +# ROUTER OPTION +############################## +let ROUTER_OPTION = 3; + +# Parse the option +refine casetype OptionValue += { + ROUTER_OPTION -> router_list : uint32[length/4]; +}; + +refine flow DHCP_Flow += { + function process_router_option(v: OptionValue): bool + %{ + TableVal* router_list = new TableVal(BifType::Table::DHCP::RouterList); + int num_routers = ${v.router_list}->size(); + vector* rlist = ${v.router_list}; + + for ( int i = 0; i < num_routers; ++i ) + { + uint32 raddr = (*rlist)[i]; + ::uint32 tmp_addr; + tmp_addr = htonl(raddr); + // index starting from 1 + Val* index = new Val(i + 1, TYPE_COUNT); + router_list->Assign(index, new AddrVal(tmp_addr)); + Unref(index); + } + + ${context.flow}->options->Assign(3, router_list); + + return true; + %} +}; + +refine typeattr Option += &let { + proc_router_option = $context.flow.process_router_option(info) &if(code==ROUTER_OPTION); +}; + + +############################## +# LEASE_OPTION OPTION +############################## +let LEASE_OPTION = 51; + +# Parse the option +refine casetype OptionValue += { + LEASE_OPTION -> lease : uint32; +}; + +refine flow DHCP_Flow += { + function process_lease_option(v: OptionValue): bool + %{ + double lease = static_cast(${v.lease}); + ${context.flow}->options->Assign(4, new Val(lease, TYPE_INTERVAL)); + + return true; + %} +}; + +refine typeattr Option += &let { + proc_lease_option = $context.flow.process_lease_option(info) &if(code==LEASE_OPTION); +}; + +############################## +# SERV_ID_OPTION OPTION +############################## +let SERV_ID_OPTION = 54; + +# Parse the option +refine casetype OptionValue += { + SERV_ID_OPTION -> serv_addr : uint32; +}; + +refine flow DHCP_Flow += { + function process_serv_id_option(v: OptionValue): bool + %{ + ${context.flow}->options->Assign(5, new AddrVal(htonl(${v.serv_addr}))); + + return true; + %} +}; + +refine typeattr Option += &let { + proc_serv_id_option = $context.flow.process_serv_id_option(info) &if(code==SERV_ID_OPTION); +}; + + +############################## +# PAR_REQ_LIST OPTION +############################## +let PAR_REQ_LIST_OPTION = 55; + +# Parse the option +refine casetype OptionValue += { + PAR_REQ_LIST_OPTION -> par_req_list : uint8[length]; +}; + +refine flow DHCP_Flow += { + function process_par_req_list_option(v: OptionValue): bool + %{ + TableVal* params_list = new TableVal(BifType::Table::DHCP::ParamsList); + int num_parms = ${v.par_req_list}->size(); + vector* plist = ${v.par_req_list}; + + for (int i=0; i < num_parms; ++i) + { + uint8 param = (*plist)[i]; + Val* index = new Val(i+1, TYPE_COUNT); + params_list->Assign(index, new Val(param, TYPE_COUNT)); + Unref(index); + } + + ${context.flow}->options->Assign(6, params_list); + + return true; + %} +}; + +refine typeattr Option += &let { + proc_par_req_list_option = $context.flow.process_par_req_list_option(info) &if(code==PAR_REQ_LIST_OPTION); +}; + + +############################## +# REN_TIME_OPTION OPTION +############################## +let REN_TIME_OPTION = 58; + +# Parse the option +refine casetype OptionValue += { + REN_TIME_OPTION -> ren_time : uint32; +}; + +refine flow DHCP_Flow += { + function process_ren_time_option(v: OptionValue): bool + %{ + double ren_time = static_cast(${v.ren_time}); + ${context.flow}->options->Assign(7, new Val(ren_time, TYPE_INTERVAL)); + + return true; + %} +}; + +refine typeattr Option += &let { + proc_ren_time_option = $context.flow.process_ren_time_option(info) &if(code==REN_TIME_OPTION); +}; + + +############################## +# REB_TIME_OPTION OPTION +############################## +let REB_TIME_OPTION = 59; + +# Parse the option +refine casetype OptionValue += { + REB_TIME_OPTION -> reb_time : uint32; +}; + +refine flow DHCP_Flow += { + function process_reb_time_option(v: OptionValue): bool + %{ + double reb_time = static_cast(${v.reb_time}); + ${context.flow}->options->Assign(8, new Val(reb_time, TYPE_INTERVAL)); + + return true; + %} +}; + +refine typeattr Option += &let { + proc_reb_time_option = $context.flow.process_reb_time_option(info) &if(code==REB_TIME_OPTION); +}; + + +############################## +# CLIENT_ID_OPTION OPTION +############################## +let CLIENT_ID_OPTION = 61; + +type Client_Identifier(length: uint8) = record { + hwtype : uint8; + hwaddr : bytestring &length = length - 1; +}; + +# Parse the option +refine casetype OptionValue += { + CLIENT_ID_OPTION -> client_id : Client_Identifier(length); +}; + +refine flow DHCP_Flow += { + function process_client_id_option(v: OptionValue): bool + %{ + RecordVal* client_id = new RecordVal(BifType::Record::DHCP::ClientID); + client_id->Assign(0, new Val(${v.client_id.hwtype}, TYPE_COUNT)); + client_id->Assign(1, new StringVal(fmt_mac(${v.client_id.hwaddr}.begin(), ${v.client_id.hwaddr}.length()))); + + ${context.flow}->options->Assign(9, client_id); + + return true; + %} +}; + +refine typeattr Option += &let { + proc_client_id_option = $context.flow.process_client_id_option(info) &if(code==CLIENT_ID_OPTION); +}; + + + +############################## +# RELAY_AGENT_INF OPTION +############################## +let RELAY_AGENT_INF_OPTION = 82; + +type Relay_Agent_SubOption(tot_len: uint8) = record { + code : uint8; + length : uint8; + value : bytestring &length = length; +} &let { + sum_len: uint8 = $context.flow.get_dhcp_sumlen(length + 2); + last: bool = (sum_len == tot_len); +}; + +# Parse the option +refine casetype OptionValue += { + RELAY_AGENT_INF_OPTION -> relay_agent_inf : Relay_Agent_SubOption(length)[] &until($element.last); +}; + +refine flow DHCP_Flow += { + function process_relay_agent_inf_option(v: OptionValue): bool + %{ + TableVal* relay_agent_sub_opt = new TableVal(BifType::Table::DHCP::SubOptList); + RecordVal* r = new RecordVal(BifType::Record::DHCP::SubOpt); + uint i = 1; + for ( auto ptrsubopt = ${v.relay_agent_inf}->begin(); + ptrsubopt != ${v.relay_agent_inf}->end(); ++ptrsubopt ) + { + r = new RecordVal(BifType::Record::DHCP::SubOpt); + r->Assign(0, new Val((*ptrsubopt)->code(), TYPE_COUNT)); + r->Assign(1, bytestring_to_val((*ptrsubopt)->value())); + + Val* index = new Val(i, TYPE_COUNT); + relay_agent_sub_opt->Assign(index, r); + Unref(index); + ++i; + } + + ${context.flow}->options->Assign(10, relay_agent_sub_opt); + return true; + %} +}; + +refine typeattr Option += &let { + proc_relay_agent_info_option = $context.flow.process_relay_agent_inf_option(info) &if(code==RELAY_AGENT_INF_OPTION); +}; + + + diff --git a/src/analyzer/protocol/dhcp/dhcp-protocol.pac b/src/analyzer/protocol/dhcp/dhcp-protocol.pac index ebc1fd946a..43dade5989 100644 --- a/src/analyzer/protocol/dhcp/dhcp-protocol.pac +++ b/src/analyzer/protocol/dhcp/dhcp-protocol.pac @@ -6,24 +6,7 @@ enum OP_type { BOOTREPLY = 2 }; -# Refer to RFC 1533 for option types. -# The option types are by no means complete. -# Anyone can add a new option type in RFC 1533 to be parsed here. -enum OPTION_type { - SUBNET_OPTION = 1, - ROUTER_OPTION = 3, - HOST_NAME_OPTION = 12, - REQ_IP_OPTION = 50, - LEASE_OPTION = 51, - MSG_TYPE_OPTION = 53, - SERV_ID_OPTION = 54, # Server address, actually :) - PAR_REQ_LIST = 55, # Parameters Request List - NEW - REN_TIME_OPTION = 58, # Renewal time - NEW - REB_TIME_OPTION = 59, # Rebinding time - NEW - CLIENT_ID_OPTION = 61, # Client Identifier - NEW - RELAY_AGENT_INF = 82, # Relay Agent Information - NEW - END_OPTION = 255 -}; +let MSG_TYPE_OPTION = 53; enum DHCP_message_type { DHCPDISCOVER = 1, @@ -41,74 +24,82 @@ enum DHCP_message_type { DHCPLEASEACTIVE = 13 # RFC 4388 }; -type Relay_Agent_SubOption(tot_len: uint8) = record { - code : uint8; - length : uint8; - value : bytestring &length = length; -} &let { - sum_len: uint8 = $context.flow.get_dhcp_sumlen(length + 2); - last: bool = (sum_len == tot_len); +type OptionValue(code: uint8, length: uint8) = case code of { + # This is extended in dhcp-options.pac + MSG_TYPE_OPTION -> msg_type : uint8; + default -> other : bytestring &length = length; }; -type Client_Identifier(length: uint8) = record { - hwtype : uint8; - hwaddr : bytestring &length = length -1; -}; - -enum DHCP_hardware_type -{ - ETHERNET = 1, - EXPERIMENTAL_ETHERNET = 2 -}; - -type Option_Info(code: uint8) = record { - length : uint8; - value : case code of { - SUBNET_OPTION -> mask : uint32; - ROUTER_OPTION -> router_list : uint32[length/4]; - REQ_IP_OPTION -> req_addr : uint32; - LEASE_OPTION -> lease : uint32; - MSG_TYPE_OPTION -> msg_type : uint8; - SERV_ID_OPTION -> serv_addr : uint32; - HOST_NAME_OPTION -> host_name : bytestring &length = length; - PAR_REQ_LIST -> par_req_list : uint8[length]; - REB_TIME_OPTION -> reb_time : uint32; - REN_TIME_OPTION -> ren_time : uint32; - CLIENT_ID_OPTION -> client_id : Client_Identifier(length); - RELAY_AGENT_INF -> relay_agent_inf : Relay_Agent_SubOption(length)[] &until($element.last); - default -> other : bytestring &length = length; - }; -}; - -type DHCP_Option = record { - code : uint8; - data : case code of { - 0, 255 -> none : empty; - default -> info : Option_Info(code); +type Option = record { + code : uint8; + length : uint8; + data : case code of { + 0, 255 -> none : empty; + default -> info : OptionValue(code, length); }; } &let { - last: bool = (code == END_OPTION); # Mark the end of a list of options + last = (code == 255); # Mark the end of a list of options }; -type DHCP_Message = record { - op : uint8; - htype : uint8; - hlen : uint8; - hops : uint8; - xid : uint32; - secs : uint16; - flags : uint16; - ciaddr : uint32; - yiaddr : uint32; - siaddr : uint32; - giaddr : uint32; +type DHCP_Message(is_orig: bool) = record { + op : uint8; + htype : uint8; + hlen : uint8; + hops : uint8; + xid : uint32; + secs : uint16; + flags : uint16; + ciaddr : uint32; + yiaddr : uint32; + siaddr : uint32; + giaddr : uint32; chaddr : bytestring &length = 16; - sname : bytestring &length = 64; - file : bytestring &length = 128; + sname : bytestring &length = 64; + file : bytestring &length = 128; # Cookie belongs to options in RFC 2131, but we separate # them here for easy parsing. cookie : uint32; - options : DHCP_Option[] &until($element.last); + options : Option[] &until($element.last); } &let { - type : uint8 = $context.flow.get_dhcp_msgtype(options); + type = $context.flow.get_dhcp_msgtype(options); } &byteorder = bigendian; + +refine flow DHCP_Flow += { + %member{ + uint8 sum_len; + %} + + %init{ + sum_len = 0; + %} + + %cleanup{ + sum_len = 0; + %} + + function get_dhcp_sumlen(len: uint8): uint8 + %{ + sum_len = len + sum_len; + return sum_len; + %} + + function get_dhcp_msgtype(options: Option[]): uint8 + %{ + uint8 type = 0; + for ( auto ptr = options->begin(); + ptr != options->end() && ! (*ptr)->last(); ++ptr ) + { + if ( (*ptr)->code() == MSG_TYPE_OPTION ) + { + type = (*ptr)->info()->msg_type(); + break; + } + } + + if ( type == 0 ) + connection()->bro_analyzer()->ProtocolViolation("no DHCP message type option"); + + return type; + %} +}; + diff --git a/src/analyzer/protocol/dhcp/dhcp.pac b/src/analyzer/protocol/dhcp/dhcp.pac index 18439cf341..ac88726b3c 100644 --- a/src/analyzer/protocol/dhcp/dhcp.pac +++ b/src/analyzer/protocol/dhcp/dhcp.pac @@ -11,5 +11,15 @@ analyzer DHCP withcontext { flow: DHCP_Flow; }; +connection DHCP_Conn(bro_analyzer: BroAnalyzer) { + upflow = DHCP_Flow(true); + downflow = DHCP_Flow(false); +}; + +flow DHCP_Flow(is_orig: bool) { + datagram = DHCP_Message(is_orig) withcontext(connection, this); +}; + %include dhcp-protocol.pac %include dhcp-analyzer.pac +%include dhcp-options.pac diff --git a/src/analyzer/protocol/dhcp/events.bif b/src/analyzer/protocol/dhcp/events.bif index 057db36aff..663ba3c319 100644 --- a/src/analyzer/protocol/dhcp/events.bif +++ b/src/analyzer/protocol/dhcp/events.bif @@ -1,3 +1,6 @@ + +event dhcp_message%(c: connection, is_orig: bool, msg: DHCP::Msg, options: DHCP::Options%); + ## Generated for DHCP messages of type *DHCPDISCOVER* (client broadcast to locate ## available servers). ## @@ -20,7 +23,7 @@ ## protocol). It treats broadcast addresses just like any other and ## associates packets into transport-level flows in the same way as usual. ## -event dhcp_discover%(c: connection, msg: DHCP::dhcp_msg, req_addr: addr, host_name: string, client_id: DHCP::dhcp_client_id, req_params: DHCP::dhcp_params_list%); +event dhcp_discover%(c: connection, msg: DHCP::Msg, req_addr: addr, host_name: string, client_id: DHCP::ClientID, req_params: DHCP::ParamsList%); ## Generated for DHCP messages of type *DHCPOFFER* (server to client in response ## to DHCPDISCOVER with offer of configuration parameters). @@ -47,7 +50,7 @@ event dhcp_discover%(c: connection, msg: DHCP::dhcp_msg, req_addr: addr, host_na ## protocol). It treats broadcast addresses just like any other and ## associates packets into transport-level flows in the same way as usual. ## -event dhcp_offer%(c: connection, msg: DHCP::dhcp_msg, mask: addr, router: DHCP::dhcp_router_list, lease: interval, serv_addr: addr, host_name: string%); +event dhcp_offer%(c: connection, msg: DHCP::Msg, mask: addr, router: DHCP::RouterList, lease: interval, serv_addr: addr, host_name: string%); ## Generated for DHCP messages of type *DHCPREQUEST* (Client message to servers either ## (a) requesting offered parameters from one server and implicitly declining offers @@ -75,7 +78,7 @@ event dhcp_offer%(c: connection, msg: DHCP::dhcp_msg, mask: addr, router: DHCP:: ## protocol). It treats broadcast addresses just like any other and ## associates packets into transport-level flows in the same way as usual. ## -event dhcp_request%(c: connection, msg: DHCP::dhcp_msg, req_addr: addr, serv_addr: addr, host_name: string, client_id: DHCP::dhcp_client_id, req_params: DHCP::dhcp_params_list%); +event dhcp_request%(c: connection, msg: DHCP::Msg, req_addr: addr, serv_addr: addr, host_name: string, client_id: DHCP::ClientID, req_params: DHCP::ParamsList%); ## Generated for DHCP messages of type *DHCPDECLINE* (Client to server indicating ## network address is already in use). @@ -93,7 +96,7 @@ event dhcp_request%(c: connection, msg: DHCP::dhcp_msg, req_addr: addr, serv_add ## protocol). It treats broadcast addresses just like any other and ## associates packets into transport-level flows in the same way as usual. ## -event dhcp_decline%(c: connection, msg: DHCP::dhcp_msg, host_name: string%); +event dhcp_decline%(c: connection, msg: DHCP::Msg, host_name: string%); ## Generated for DHCP messages of type *DHCPACK* (Server to client with configuration ## parameters, including committed network address). @@ -127,7 +130,7 @@ event dhcp_decline%(c: connection, msg: DHCP::dhcp_msg, host_name: string%); ## .. bro:see:: dhcp_discover dhcp_offer dhcp_request dhcp_decline dhcp_nak ## dhcp_release dhcp_inform ## -event dhcp_ack%(c: connection, msg: DHCP::dhcp_msg, mask: addr, router: DHCP::dhcp_router_list, lease: interval, serv_addr: addr, host_name: string, reb_time: count, ren_time: count, sub_opt: DHCP::dhcp_sub_opt_list%); +event dhcp_ack%(c: connection, msg: DHCP::Msg, mask: addr, router: DHCP::RouterList, lease: interval, serv_addr: addr, host_name: string%); ## Generated for DHCP messages of type *DHCPNAK* (Server to client indicating client's ## notion of network address is incorrect (e.g., client has moved to new subnet) or @@ -146,7 +149,7 @@ event dhcp_ack%(c: connection, msg: DHCP::dhcp_msg, mask: addr, router: DHCP::dh ## protocol). It treats broadcast addresses just like any other and ## associates packets into transport-level flows in the same way as usual. ## -event dhcp_nak%(c: connection, msg: DHCP::dhcp_msg, host_name: string%); +event dhcp_nak%(c: connection, msg: DHCP::Msg, host_name: string%); ## Generated for DHCP messages of type *DHCPRELEASE* (Client to server relinquishing ## network address and cancelling remaining lease). @@ -160,7 +163,7 @@ event dhcp_nak%(c: connection, msg: DHCP::dhcp_msg, host_name: string%); ## .. bro:see:: dhcp_discover dhcp_offer dhcp_request dhcp_decline dhcp_ack dhcp_nak ## dhcp_inform ## -event dhcp_release%(c: connection, msg: DHCP::dhcp_msg, host_name: string%); +event dhcp_release%(c: connection, msg: DHCP::Msg, host_name: string%); ## Generated for DHCP messages of type *DHCPINFORM* (Client to server, asking only for ## local configuration parameters; client already has externally configured network @@ -181,5 +184,5 @@ event dhcp_release%(c: connection, msg: DHCP::dhcp_msg, host_name: string%); ## protocol). It treats broadcast addresses just like any other and ## associates packets into transport-level flows in the same way as usual. ## -event dhcp_inform%(c: connection, msg: DHCP::dhcp_msg, host_name: string, req_params: DHCP::dhcp_params_list%); +event dhcp_inform%(c: connection, msg: DHCP::Msg, host_name: string%); diff --git a/src/analyzer/protocol/dhcp/types.bif b/src/analyzer/protocol/dhcp/types.bif index 8f501fc7fd..bf55018b00 100644 --- a/src/analyzer/protocol/dhcp/types.bif +++ b/src/analyzer/protocol/dhcp/types.bif @@ -1,10 +1,9 @@ module DHCP; -type dhcp_msg: record; -type dhcp_router_list: table; -type dhcp_params_list: table; -type dhcp_sub_opt_list: table; -type dhcp_sub_opt: record; -type dhcp_client_id: record; - -module GLOBAL; +type Msg: record; +type RouterList: table; +type ParamsList: table; +type SubOptList: table; +type SubOpt: record; +type ClientID: record; +type Options: record; From e76b56ce530aff67422ab24c66c4de2ed8b467d7 Mon Sep 17 00:00:00 2001 From: Seth Hall Date: Thu, 1 Mar 2018 08:36:32 -0800 Subject: [PATCH 4/4] Rework to the DHCP analyzer. Highlights: - Reduced all DHCP events into a single dhcp_message event. (removed legacy events since they weren't widely used anyway) - Support many more DHCP options. - DHCP log is completely reworked and now represents DHCP sessions based on the transaction ID (and works on clusters). - Removed the known-devices-and-hostnames script since it's generally less relevant now with the updated log. --- scripts/base/init-bare.bro | 157 ++++-- scripts/base/protocols/dhcp/consts.bro | 199 ++++++- scripts/base/protocols/dhcp/dpd.sig | 4 +- scripts/base/protocols/dhcp/main.bro | 277 ++++++--- scripts/base/protocols/dhcp/utils.bro | 19 - scripts/policy/misc/known-devices.bro | 6 - .../dhcp/known-devices-and-hostnames.bro | 37 -- scripts/policy/protocols/dhcp/msg-orig.bro | 21 + scripts/policy/protocols/dhcp/software.bro | 63 +++ scripts/policy/protocols/dhcp/sub-opts.bro | 45 ++ scripts/test-all-policy.bro | 4 +- src/analyzer/protocol/dhcp/dhcp-analyzer.pac | 234 ++------ src/analyzer/protocol/dhcp/dhcp-options.pac | 530 +++++++++++++++--- src/analyzer/protocol/dhcp/dhcp-protocol.pac | 50 +- src/analyzer/protocol/dhcp/events.bif | 198 +------ src/analyzer/protocol/dhcp/types.bif | 6 +- .../Baseline/core.print-bpf-filters/output2 | 9 +- .../canonified_loaded_scripts.log | 5 +- .../canonified_loaded_scripts.log | 6 +- testing/btest/Baseline/plugins.hooks/output | 23 +- .../dhcp.log | 10 +- .../dhcp.log | 12 +- .../dhcp.log | 10 +- .../dhcp.log | 10 + .../dhcp.log | 10 +- .../known_devices.log | 11 - .../base/protocols/dhcp/dhcp-sub-opts.btest | 2 + .../known-devices-and-hostnames/basic.test | 8 - 28 files changed, 1234 insertions(+), 732 deletions(-) delete mode 100644 scripts/base/protocols/dhcp/utils.bro delete mode 100644 scripts/policy/protocols/dhcp/known-devices-and-hostnames.bro create mode 100644 scripts/policy/protocols/dhcp/msg-orig.bro create mode 100644 scripts/policy/protocols/dhcp/software.bro create mode 100644 scripts/policy/protocols/dhcp/sub-opts.bro create mode 100644 testing/btest/Baseline/scripts.base.protocols.dhcp.dhcp-sub-opts/dhcp.log delete mode 100644 testing/btest/Baseline/scripts.policy.protocols.dhcp.known-devices-and-hostnames.basic/known_devices.log create mode 100644 testing/btest/scripts/base/protocols/dhcp/dhcp-sub-opts.btest delete mode 100644 testing/btest/scripts/policy/protocols/dhcp/known-devices-and-hostnames/basic.test diff --git a/scripts/base/init-bare.bro b/scripts/base/init-bare.bro index 9ea7a4ce00..cfffdc4af5 100644 --- a/scripts/base/init-bare.bro +++ b/scripts/base/init-bare.bro @@ -3061,10 +3061,11 @@ module GLOBAL; module DHCP; export { - ## A list of router addresses offered by a DHCP server. + ## A list of addresses offered by a DHCP server. Could be routers, + ## DNS servers, or other. ## ## .. bro:see:: dhcp_ack dhcp_offer - type DHCP::RouterList: table[count] of addr; + type DHCP::Addrs: vector of addr; ## A DHCP message. ## .. bro:see:: dhcp_ack dhcp_decline dhcp_discover dhcp_inform dhcp_nak @@ -3073,20 +3074,17 @@ export { op: count; ##< Message OP code. 1 = BOOTREQUEST, 2 = BOOTREPLY m_type: count; ##< The type of DHCP message. xid: count; ##< Transaction ID of a DHCP session. - h_addr: string; ##< Hardware address of the client. + ## Number of seconds since client began address acquisition + ## or renewal process + secs: interval; + flags: count; ciaddr: addr; ##< Original IP address of the client. yiaddr: addr; ##< IP address assigned to the client. - }; - - ## DHCP Parameter Request list (Option 55) - ## .. bro:see:: dhcp_request dhcp_discover - type DHCP::ParamsList: table[count] of count; - - ## DHCP Relay Agent Information Option (Option 82) - ## .. bro:see:: dhcp_ack - type DHCP::SubOpt: record { - code: count; - value: string; + siaddr: addr; ##< IP address of the server. + giaddr: addr; ##< IP address of the relaying gateway. + chaddr: string; ##< Client hardware address. + sname: string &default=""; ##< Server host name. + file_n: string &default=""; ##< Boot file name. }; ## DHCP Client Identifier (Option 61) @@ -3096,36 +3094,113 @@ export { hwaddr: string; }; - type DHCP::SubOptList: table[count] of DHCP::SubOpt; - - type DHCP::Options: record { - subnet_mask: addr &optional; - - host_name: string &optional; - - req_addr: addr &optional; - - router_list: DHCP::RouterList &optional; - - lease: interval &optional; - - serv_addr: addr &optional; - - ## DHCP Parameter Request list (Option 55) - param_list: DHCP::ParamsList &optional; - - ren_time: interval &optional; - - reb_time: interval &optional; - - ## DHCP Client Identifier (Option 61) - client_id: DHCP::ClientID &optional; - - ## DHCP Relay Agent Information Option (Option 82) - sub_opt: DHCP::SubOptList &optional; + ## DHCP Client FQDN Option information (Option 81) + type DHCP::ClientFQDN: record { + ## An unparsed bitfield of flags (refer to RFC 4702). + flags: count; + ## This field is deprecated in the standard. + rcode1: count; + ## This field is deprecated in the standard. + rcode2: count; + ## The Domain Name part of the option carries all or part of the FQDN of + ## a DHCP client. + domain_name: string; }; + ## DHCP Relay Agent Information Option (Option 82) + ## .. bro:see:: dhcp_ack + type DHCP::SubOpt: record { + code: count; + value: string; + }; + type DHCP::SubOpts: vector of DHCP::SubOpt; + + type DHCP::Options: record { + ## The ordered list of DHCP all DHCP options numbers. + options: index_vec &optional; + + ## Subnet Mask Value (option 1) + subnet_mask: addr &optional; + + ## Router addresses (option 3) + routers: DHCP::Addrs &optional; + + ## DNS Server addresses (option 6) + dns_servers: DHCP::Addrs &optional; + + ## The Hostname of the client (option 12) + host_name: string &optional; + + ## The DNS domain name of the client (option 15) + domain_name: string &optional; + + ## Enable/Disable IP Forwarding (option 19) + forwarding: bool &optional; + + ## Broadcast Address (option 28) + broadcast: addr &optional; + + ## Vendor specific data. This can frequently + ## be unparsed binary data. (option 43) + vendor: string &optional; + + ## NETBIOS name server list (option 44) + nbns: DHCP::Addrs &optional; + + ## Address requested by the client (option 50) + addr_request: addr &optional; + + ## Lease time offered by the server. (option 51) + lease: interval &optional; + + ## Server address to allow clients to distinguish + ## between lease offers. (option 54) + serv_addr: addr &optional; + + ## DHCP Parameter Request list (option 55) + param_list: index_vec &optional; + + ## Textual error message (option 56) + message: string &optional; + + ## Maximum Message Size (option 57) + max_msg_size: count &optional; + + ## This option specifies the time interval from address + ## assignment until the client transitions to the + ## RENEWING state. (option 58) + renewal_time: interval &optional; + + ## This option specifies the time interval from address + ## assignment until the client transitions to the + ## REBINDING state. (option 59) + rebinding_time: interval &optional; + + ## This option is used by DHCP clients to optionally + ## identify the vendor type and configuration of a DHCP + ## client. (option 60) + vendor_class: string &optional; + + ## DHCP Client Identifier (Option 61) + client_id: DHCP::ClientID &optional; + + ## User Class opaque value (Option 77) + user_class: string &optional; + + ## DHCP Client FQDN (Option 81) + client_fqdn: DHCP::ClientFQDN &optional; + + ## DHCP Relay Agent Information Option (Option 82) + sub_opt: DHCP::SubOpts &optional; + + ## Auto Config option to let host know if it's allowed to + ## auto assign an IP address. (Option 116) + auto_config: bool &optional; + + ## URL to find a proxy.pac for auto proxy config (Option 252) + auto_proxy_config: string &optional; + }; } module GLOBAL; diff --git a/scripts/base/protocols/dhcp/consts.bro b/scripts/base/protocols/dhcp/consts.bro index 1ca47ac36f..6a7c1cea6c 100644 --- a/scripts/base/protocols/dhcp/consts.bro +++ b/scripts/base/protocols/dhcp/consts.bro @@ -4,27 +4,186 @@ module DHCP; export { - - ## Types of DHCP messages. See :rfc:`1533`. + ## Types of DHCP messages. See :rfc:`1533`, :rfc:`3203`, + ## :rfc:`4388`, :rfc:`6926`, and :rfc:`7724`. const message_types = { - [1] = "DHCP_DISCOVER", - [2] = "DHCP_OFFER", - [3] = "DHCP_REQUEST", - [4] = "DHCP_DECLINE", - [5] = "DHCP_ACK", - [6] = "DHCP_NAK", - [7] = "DHCP_RELEASE", - [8] = "DHCP_INFORM", - [9] = "DHCP_FORCERENEW", - [10] = "DHCP_LEASEQUERY", - [11] = "DHCP_LEASEUNASSIGNED", - [12] = "DHCP_DHCPLEASEUNKNOWN", - [13] = "DHCP_LEASEACTIVE", - [14] = "DHCP_BULKLEASEQUERY", - [15] = "DHCP_LEASEQUERYDONE", - [16] = "DHCP_ACTIVELEASEQUERY", - [17] = "DHCP_LEASEQUERYSTATUS", - [18] = "DHCP_TLS", + [1] = "DISCOVER", + [2] = "OFFER", + [3] = "REQUEST", + [4] = "DECLINE", + [5] = "ACK", + [6] = "NAK", + [7] = "RELEASE", + [8] = "INFORM", + [9] = "FORCERENEW", # RFC3203 + [10] = "LEASEQUERY", # RFC4388 + [11] = "LEASEUNASSIGNED", # RFC4388 + [12] = "LEASEUNKNOWN", # RFC4388 + [13] = "LEASEACTIVE", # RFC4388 + [14] = "BULKLEASEQUERY", # RFC6926 + [15] = "LEASEQUERYDONE", # RFC6926 + [16] = "ACTIVELEASEQUERY", # RFC7724 + [17] = "LEASEQUERYSTATUS", # RFC7724 + [18] = "TLS", # RFC7724 } &default = function(n: count): string { return fmt("unknown-message-type-%d", n); }; + ## Option types mapped to their names. + const option_types: table[int] of string = { + [0] = "Pad", + [1] = "Subnet Mask", + [2] = "Time Offset", + [3] = "Router", + [4] = "Time Server", + [5] = "Name Server", + [6] = "Domain Server", + [7] = "Log Server", + [8] = "Quotes Server", + [9] = "LPR Server", + [10] = "Impress Server", + [11] = "RLP Server", + [12] = "Hostname", + [13] = "Boot File Size", + [14] = "Merit Dump File", + [15] = "Domain Name", + [16] = "Swap Server", + [17] = "Root Path", + [18] = "Extension File", + [19] = "Forward On/Off", + [20] = "SrcRte On/Off", + [21] = "Policy Filter", + [22] = "Max DG Assembly", + [23] = "Default IP TTL", + [24] = "MTU Timeout", + [25] = "MTU Plateau", + [26] = "MTU Interface", + [27] = "MTU Subnet", + [28] = "Broadcast Address", + [29] = "Mask Discovery", + [30] = "Mask Supplier", + [31] = "Router Discovery", + [32] = "Router Request", + [33] = "Static Route", + [34] = "Trailers", + [35] = "ARP Timeout", + [36] = "Ethernet", + [37] = "Default TCP TTL", + [38] = "Keepalive Time", + [39] = "Keepalive Data", + [40] = "NIS Domain", + [41] = "NIS Servers", + [42] = "NTP Servers", + [43] = "Vendor Specific", + [44] = "NETBIOS Name Srv", + [45] = "NETBIOS Dist Srv", + [46] = "NETBIOS Node Type", + [47] = "NETBIOS Scope", + [48] = "X Window Font", + [49] = "X Window Manager", + [50] = "Address Request", + [51] = "Address Time", + [52] = "Overload", + [53] = "DHCP Msg Type", + [54] = "DHCP Server Id", + [55] = "Parameter List", + [56] = "DHCP Message", + [57] = "DHCP Max Msg Size", + [58] = "Renewal Time", + [59] = "Rebinding Time", + [60] = "Class Id", + [61] = "Client Id", + [62] = "NetWare/IP Domain", + [63] = "NetWare/IP Option", + [64] = "NIS-Domain-Name", + [65] = "NIS-Server-Addr", + [66] = "Server-Name", + [67] = "Bootfile-Name", + [68] = "Home-Agent-Addrs", + [69] = "SMTP-Server", + [70] = "POP3-Server", + [71] = "NNTP-Server", + [72] = "WWW-Server", + [73] = "Finger-Server", + [74] = "IRC-Server", + [75] = "StreetTalk-Server", + [76] = "STDA-Server", + [77] = "User-Class", + [78] = "Directory Agent", + [79] = "Service Scope", + [80] = "Rapid Commit", + [81] = "Client FQDN", + [82] = "Relay Agent Information", + [83] = "iSNS", + [85] = "NDS Servers", + [86] = "NDS Tree Name", + [87] = "NDS Context", + [88] = "BCMCS Controller Domain Name list", + [89] = "BCMCS Controller IPv4 address option", + [90] = "Authentication", + [91] = "client-last-transaction-time option", + [92] = "associated-ip option", + [93] = "Client System", + [94] = "Client NDI", + [95] = "LDAP", + [97] = "UUID/GUID", + [98] = "User-Auth", + [99] = "GEOCONF_CIVIC", + [100] = "PCode", + [101] = "TCode", + [112] = "Netinfo Address", + [113] = "Netinfo Tag", + [114] = "URL", + [116] = "Auto-Config", + [117] = "Name Service Search", + [118] = "Subnet Selection Option", + [119] = "Domain Search", + [120] = "SIP Servers DHCP Option", + [121] = "Classless Static Route Option", + [122] = "CCC", + [123] = "GeoConf Option", + [124] = "V-I Vendor Class", + [125] = "V-I Vendor-Specific Information", + [128] = "PXE - undefined (vendor specific)", + [129] = "PXE - undefined (vendor specific)", + [130] = "PXE - undefined (vendor specific)", + [131] = "PXE - undefined (vendor specific)", + [132] = "IEEE 802.1Q VLAN ID", + [133] = "IEEE 802.1D/p Layer 2 Priority", + [134] = "Diffserv Code Point (DSCP) for VoIP signalling and media streams", + [135] = "HTTP Proxy for phone-specific applications", + [136] = "OPTION_PANA_AGENT", + [137] = "OPTION_V4_LOST", + [138] = "OPTION_CAPWAP_AC_V4", + [139] = "OPTION-IPv4_Address-MoS", + [140] = "OPTION-IPv4_FQDN-MoS", + [141] = "SIP UA Configuration Service Domains", + [142] = "OPTION-IPv4_Address-ANDSF", + [144] = "GeoLoc", + [145] = "FORCERENEW_NONCE_CAPABLE", + [146] = "RDNSS Selection", + [150] = "TFTP server address", + [151] = "status-code", + [152] = "base-time", + [153] = "start-time-of-state", + [154] = "query-start-time", + [155] = "query-end-time", + [156] = "dhcp-state", + [157] = "data-source", + [158] = "OPTION_V4_PCP_SERVER", + [159] = "OPTION_V4_PORTPARAMS", + [160] = "DHCP Captive-Portal", + [161] = "OPTION_MUD_URL_V4 (TEMPORARY - registered 2016-11-17)", + [175] = "Etherboot (Tentatively Assigned - 2005-06-23)", + [176] = "IP Telephone (Tentatively Assigned - 2005-06-23)", + [177] = "PacketCable and CableHome (replaced by 122)", + [208] = "PXELINUX Magic", + [209] = "Configuration File", + [210] = "Path Prefix", + [211] = "Reboot Time", + [212] = "OPTION_6RD", + [213] = "OPTION_V4_ACCESS_DOMAIN", + [220] = "Subnet Allocation Option", + [221] = "Virtual Subnet Selection (VSS) Option", + [252] = "auto-proxy-config", + [255] = "End", + } &default = function(n: int): string { return fmt("unknown-option-type-%d", n); }; } diff --git a/scripts/base/protocols/dhcp/dpd.sig b/scripts/base/protocols/dhcp/dpd.sig index 010920e2d8..85aa23ea16 100644 --- a/scripts/base/protocols/dhcp/dpd.sig +++ b/scripts/base/protocols/dhcp/dpd.sig @@ -1,5 +1,5 @@ signature dhcp_cookie { ip-proto == udp - payload /^.*\x63\x82\x53\x63/ + payload /^.{236}\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 0b45d69a4b..01ca96225c 100644 --- a/scripts/base/protocols/dhcp/main.bro +++ b/scripts/base/protocols/dhcp/main.bro @@ -1,12 +1,11 @@ -##! Analyzes DHCP traffic in order to log DHCP leases given to clients. -##! This script ignores large swaths of the protocol, since it is rather -##! noisy on most networks, and focuses on the end-result: assigned leases. -##! -##! If you'd like to track known DHCP devices and to log the hostname -##! supplied by the client, see -##! :doc:`/scripts/policy/protocols/dhcp/known-devices-and-hostnames.bro`. +##! Analyze DHCP traffic and provide a log that is organized around +##! the idea of a DHCP "conversation" defined by messaes exchanged within +##! a relatively short period of time using the same transaction ID. +##! The log will have information from clients and servers to give a more +##! complete picture of what happened. -@load ./utils.bro +@load base/frameworks/cluster +@load ./consts module DHCP; @@ -17,34 +16,81 @@ export { type Info: record { ## The earliest time at which a DHCP message over the ## associated connection is observed. - ts: time &log; - ## A unique identifier of the connection over which DHCP is - ## occurring. - uid: string &log; - ## The connection's 4-tuple of endpoint addresses/ports. - id: conn_id &log; + ts: time &log; + + ## A series of unique identifiers of the connections over which + ## DHCP is occurring. This behavior with multiple connections is + ## unique to DHCP because of the way it uses broadcast packets + ## on local networks. + uids: set[string] &log; + + ## IP address of the client. If a transaction + ## is only a client sending INFORM messages then + ## there is no lease information exchanged so this + ## is helpful to know who sent the messages. + ## Getting an address in this field does require + ## that the client sources at least one DHCP message + ## using a non-broadcast address. + client_addr: addr &log &optional; + ## IP address of the server involved in actually + ## handing out the lease. There could be other + ## servers replying with OFFER messages which won't + ## be represented here. Getting an address in this + ## field also requires that the server handing out + ## the lease also sources packets from a non-broadcast + ## IP address. + server_addr: addr &log &optional; + ## Client's hardware address. - mac: string &log &optional; - ## Client's actual assigned IP address. - assigned_ip: addr &log &optional; + mac: string &log &optional; + + ## Name given by client in Hostname option 12. + host_name: string &log &optional; + ## FQDN given by client in Client FQDN option 81. + client_fqdn: string &log &optional; + ## Domain given by the server in option 15. + domain: string &log &optional; + + ## IP address requested by the client. + requested_addr: addr &log &optional; + ## IP address assigned by the server. + assigned_addr: addr &log &optional; ## IP address lease interval. - lease_time: interval &log &optional; - ## A random number chosen by the client for this transaction. - trans_id: count &log; - ## the message type - msg_type: string &log &optional; - ## client ID - client_id: string &log &optional; - ## the server ID - server_id: addr &log &optional; - ## the host name - host_name: string &log &optional; - ## the subscriber id (if present) - subscriber_id: string &log &optional; - ## the agent remote id (if present) - agent_remote_id: string &log &optional; + lease_time: interval &log &optional; + + ## Message typically accompanied with a DHCP_DECLINE + ## so the client can tell the server why it rejected + ## an address. + client_message: string &log &optional; + ## Message typically accompanied with a DHCP_NAK to let + ## the client know why it rejected the request. + server_message: string &log &optional; + + ## The DHCP message types seen by this DHCP transaction + msg_types: vector of string &log &default=string_vec(); + + ## Duration of the DHCP "session" representing the + ## time from the first message to the last. + duration: interval &log &default=0secs; }; + ## The maximum amount of time that a transation ID will be watched + ## for to try and tie messages together into a single DHCP + ## transaction narrative. + const DHCP::max_txid_watch_time = 30secs &redef; + + ## This event is used internally to distribute data around clusters + ## since DHCP doesn't follow the normal "connection" model used by + ## most protocols. It can also be handled to extend the DHCP log. + ## bro:see::`DHCP::log_info`. + global DHCP::aggregate_msgs: event(ts: time, id: conn_id, uid: string, is_orig: bool, msg: DHCP::Msg, options: DHCP::Options); + + ## This is a global variable that is only to be used in the + ## :bro::see::`DHCP::aggregate_msgs` event. It can be used to avoid + ## looking up the info record for a transaction ID in every event handler + ## for :bro:see::`DHCP::aggregate_msgs`. + global DHCP::log_info: Info; + ## Event that can be handled to access the DHCP ## record as it is sent on to the logging framework. global log_dhcp: event(rec: Info); @@ -55,8 +101,13 @@ redef record connection += { dhcp: Info &optional; }; +redef record Info += { + last_message_ts: time &optional; +}; + # 67/udp is the server's port, 68/udp the client. -const ports = { 67/udp, 68/udp }; +# 4011/udp seems to be some proxyDHCP thing. +const ports = { 67/udp, 68/udp, 4011/udp }; redef likely_server_ports += { 67/udp }; event bro_init() &priority=5 @@ -65,54 +116,144 @@ event bro_init() &priority=5 Analyzer::register_for_ports(Analyzer::ANALYZER_DHCP, ports); } -event dhcp_message(c: connection, is_orig: bool, msg: DHCP::Msg, options: DHCP::Options) &priority=-5 +# Setup the clusterized config that is needed to tie messages together on a cluster. +redef Cluster::worker2manager_events += /DHCP::aggregate_msgs/; + +function join_data_expiration(t: table[count] of Info, idx: count): interval { - if ( msg$m_type == 5 ) # DHCP_ACK + local info = t[idx]; + + local now = network_time(); + # If a message hasn't been seen in the past 5 seconds or the + # total time watching has been more than the maximum time + # allowed by the configuration then log this data and expire it. + # Also, if Bro is shutting down. + if ( (now - info$last_message_ts) > 5sec || + (now - info$ts) > max_txid_watch_time || + bro_is_terminating() ) { - local info = Info($ts = network_time(), - $id = c$id, - $uid = c$uid, - $trans_id = msg$xid); + Log::write(LOG, info); - if ( msg$h_addr != "" ) - info$mac = msg$h_addr; + # Go ahead and expire the data now that the log + # entry has been written. + return 0secs; + } + else + { + return 5secs; + } + } - if ( reverse_ip(msg$yiaddr) != 0.0.0.0 ) - info$assigned_ip = reverse_ip(msg$yiaddr); +# This is where the data is stored as it's centralized. All data for a log must +# arrive within the expiration interval if it's to be logged fully. On a cluster, +# this data is only maintained on the manager. +global join_data: table[count] of Info = table() + &create_expire=10secs &expire_func=join_data_expiration; + + + +@if ( ! Cluster::is_enabled() || Cluster::local_node_type() == Cluster::MANAGER ) +# We are handling this event at priority 1000 because we really want +# the DHCP::log_info global to be set correctly before a user might try +# to access it. +event DHCP::aggregate_msgs(ts: time, id: conn_id, uid: string, is_orig: bool, msg: DHCP::Msg, options: DHCP::Options) &priority=1000 + { + if ( msg$xid !in join_data ) + { + join_data[msg$xid] = Info($ts=ts, + $uids=set(uid)); + } + + log_info = join_data[msg$xid]; + } + +event DHCP::aggregate_msgs(ts: time, id: conn_id, uid: string, is_orig: bool, msg: DHCP::Msg, options: DHCP::Options) &priority=5 + { + log_info$duration = ts - log_info$ts; + + if ( uid !in log_info$uids ) + add log_info$uids[uid]; + + log_info$msg_types[|log_info$msg_types|] = DHCP::message_types[msg$m_type]; + + # Let's watch for messages in any DHCP message type + # and split them out based on client and server. + if ( options?$message ) + { + if ( is_orig ) + log_info$client_message = options$message; else - info$assigned_ip = c$id$orig_h; + log_info$server_message = options$message; + } - if ( options?$lease ) - info$lease_time = options$lease; + # Update the last message time so that we can do some data + # expiration handling. + log_info$last_message_ts = ts; - if ( options?$sub_opt ) + if ( is_orig ) # client requests + { + # Assign the client addr in case this is a session + # of only INFORM messages (no lease handed out). + # This also works if a normal lease handout uses + # unicast. + if ( id$orig_h != 0.0.0.0 && id$orig_h != 255.255.255.255 ) + log_info$client_addr = id$orig_h; + + if ( options?$host_name ) + log_info$host_name = options$host_name; + + if ( options?$client_fqdn ) + log_info$client_fqdn = options$client_fqdn$domain_name; + + if ( options?$client_id && + options$client_id$hwtype == 1 ) # ETHERNET + log_info$mac = options$client_id$hwaddr; + + if ( options?$addr_request ) + log_info$requested_addr = options$addr_request; + } + else # server reply messages + { + # Only log the address of the server if it handed out + # an IP address. + if ( msg$yiaddr != 0.0.0.0 && + id$resp_h != 255.255.255.255 ) { - for ( param in options$sub_opt ) - { - local sub_opt = options$sub_opt[param]; - - #if ( sub_opt$code == 1 ) - # { - # print fmt("Relay Agent Information:"); - # print fmt( "sub option: code=%d circuit id=%s",sub_opt$code,sub_opt$value ); - # } - - if ( sub_opt$code == 2 ) - info$agent_remote_id = bytestring_to_hexstr(sub_opt$value); - - if ( sub_opt$code == 6 ) - info$subscriber_id = (sub_opt$value); - } + log_info$server_addr = id$resp_h; } - c$dhcp = info; + # Only use the client hardware address from the server + # if we didn't already pick one up from the client. + if ( msg$chaddr != "" && !log_info?$mac ) + log_info$mac = msg$chaddr; + + if ( msg$yiaddr != 0.0.0.0 ) + log_info$assigned_addr = msg$yiaddr; + + # If no client address has been seen yet, let's use the assigned addr. + if ( ! log_info?$client_addr && log_info?$assigned_addr ) + log_info$client_addr = log_info$assigned_addr; + + if ( options?$domain_name ) + log_info$domain = options$domain_name; + + if ( options?$lease ) + log_info$lease_time = options$lease; } } +@endif + + +# Aggregate DHCP messages to the manager. event dhcp_message(c: connection, is_orig: bool, msg: DHCP::Msg, options: DHCP::Options) &priority=-5 { - if ( msg$m_type == 5 ) # DHCP_ACK - { - Log::write(DHCP::LOG, c$dhcp); - } + event DHCP::aggregate_msgs(network_time(), c$id, c$uid, is_orig, msg, options); + } + +event bro_done() &priority=-5 + { + # Log any remaining data that hasn't already been logged! + for ( i in DHCP::join_data ) + join_data_expiration(DHCP::join_data, i); } diff --git a/scripts/base/protocols/dhcp/utils.bro b/scripts/base/protocols/dhcp/utils.bro deleted file mode 100644 index 9d5a422128..0000000000 --- a/scripts/base/protocols/dhcp/utils.bro +++ /dev/null @@ -1,19 +0,0 @@ -##! Utilities specific for DHCP processing. - -module DHCP; - -export { - ## Reverse the octets of an IPv4 address. - ## - ## ip: An IPv4 address. - ## - ## Returns: A reversed IPv4 address. - global reverse_ip: function(ip: addr): addr; -} - -function reverse_ip(ip: addr): addr - { - local octets = split_string(cat(ip), /\./); - return to_addr(cat(octets[3], ".", octets[2], ".", octets[1], ".", octets[0])); - } - diff --git a/scripts/policy/misc/known-devices.bro b/scripts/policy/misc/known-devices.bro index 2f1f81524f..35ea9bff8b 100644 --- a/scripts/policy/misc/known-devices.bro +++ b/scripts/policy/misc/known-devices.bro @@ -2,12 +2,6 @@ ##! been able to determine the MAC address, and it logs them 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 on its own, it needs to be -##! supplied with information from elsewhere, such as -##! :doc:`/scripts/policy/protocols/dhcp/known-devices-and-hostnames.bro`. module Known; diff --git a/scripts/policy/protocols/dhcp/known-devices-and-hostnames.bro b/scripts/policy/protocols/dhcp/known-devices-and-hostnames.bro deleted file mode 100644 index 39ea02c759..0000000000 --- a/scripts/policy/protocols/dhcp/known-devices-and-hostnames.bro +++ /dev/null @@ -1,37 +0,0 @@ -##! Tracks MAC address with hostnames seen in DHCP traffic. They are logged into -##! ``devices.log``. - -@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::dhcp_msg, req_addr: addr, serv_addr: addr, host_name: string, client_id: DHCP::dhcp_client_id, req_params: DHCP::dhcp_params_list) - { - 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]); - } - } - -event dhcp_inform(c: connection, msg: DHCP::dhcp_msg, host_name: string, req_params: DHCP::dhcp_params_list) - { - 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]); - } - } diff --git a/scripts/policy/protocols/dhcp/msg-orig.bro b/scripts/policy/protocols/dhcp/msg-orig.bro new file mode 100644 index 0000000000..56a0e8c66e --- /dev/null +++ b/scripts/policy/protocols/dhcp/msg-orig.bro @@ -0,0 +1,21 @@ +##! Add a field that logs the order of hosts sending messages +##! using the same DHCP transaction ID. This information is +##! occasionally needed on some networks to fully explain the +##! DHCP sequence. + +@load base/protocols/dhcp + +module DHCP; + +export { + redef record DHCP::Info += { + ## The address that originated each message from the + ## `msg_types` field. + msg_orig: vector of addr &log &default=addr_vec(); + }; +} + +event DHCP::aggregate_msgs(ts: time, id: conn_id, uid: string, is_orig: bool, msg: DHCP::Msg, options: DHCP::Options) &priority=3 + { + log_info$msg_orig[|log_info$msg_orig|] = is_orig ? id$orig_h : id$resp_h; + } diff --git a/scripts/policy/protocols/dhcp/software.bro b/scripts/policy/protocols/dhcp/software.bro new file mode 100644 index 0000000000..4aa4bdd7ff --- /dev/null +++ b/scripts/policy/protocols/dhcp/software.bro @@ -0,0 +1,63 @@ +##! Software identification and extraction for DHCP traffic. + +@load base/protocols/dhcp +@load base/frameworks/software + +module DHCP; + +export { + redef enum Software::Type += { + ## Identifier for web servers in the software framework. + DHCP::SERVER, + ## Identifier for web browsers in the software framework. + DHCP::CLIENT, + }; + + redef record DHCP::Info += { + ## Software reported by the client in the `vendor_class` option. + client_software: string &log &optional; + ## Software reported by the server in the `vendor_class` option. + server_software: string &log &optional; + }; +} + +event DHCP::aggregate_msgs(ts: time, id: conn_id, uid: string, is_orig: bool, msg: DHCP::Msg, options: DHCP::Options) &priority=5 + { + if ( options?$vendor_class ) + { + if ( is_orig ) + log_info$client_software = options$vendor_class; + else + { + log_info$server_software = options$vendor_class; + Software::found(id, [$unparsed_version=options$vendor_class, + $host=id$resp_h, + $software_type=DHCP::SERVER]); + } + } + } + +event DHCP::log_dhcp(rec: DHCP::Info) + { + if ( rec?$assigned_addr && rec?$server_addr && + (rec?$client_software || rec?$server_software) ) + { + # Not quite right to just blindly use 67 and 68 as the ports + local id: conn_id = [$orig_h=rec$assigned_addr, $orig_p=68/udp, + $resp_h=rec$server_addr, $resp_p=67/udp]; + + if ( rec?$client_software && rec$assigned_addr != 255.255.255.255 ) + { + Software::found(id, [$unparsed_version=rec$client_software, + $host=rec$assigned_addr, + $software_type=DHCP::CLIENT]); + } + + if ( rec?$server_software ) + { + Software::found(id, [$unparsed_version=rec$server_software, + $host=rec$server_addr, + $software_type=DHCP::SERVER]); + } + } + } diff --git a/scripts/policy/protocols/dhcp/sub-opts.bro b/scripts/policy/protocols/dhcp/sub-opts.bro new file mode 100644 index 0000000000..af5056bf39 --- /dev/null +++ b/scripts/policy/protocols/dhcp/sub-opts.bro @@ -0,0 +1,45 @@ + +@load base/protocols/dhcp + +module DHCP; + +export { + redef record DHCP::Info += { + ## Added by DHCP relay agents which terminate switched or + ## permanent circuits. It encodes an agent-local identifier + ## of the circuit from which a DHCP client-to-server packet was + ## received. Typically it should represent a router or switch + ## interface number. + circuit_id: string &log &optional; + + ## A globally unique identifier added by relay agents to identify + ## the remote host end of the circuit. + agent_remote_id: string &log &optional; + + ## The subscriber ID is a value independent of the physical + ## network configuration so that a customer's DHCP configuration + ## can be given to them correctly no matter where they are + ## physically connected. + subscriber_id: string &log &optional; + }; +} + +event DHCP::aggregate_msgs(ts: time, id: conn_id, uid: string, is_orig: bool, msg: DHCP::Msg, options: DHCP::Options) + { + if ( options?$sub_opt ) + { + for ( i in options$sub_opt ) + { + local sub_opt = options$sub_opt[i]; + + if ( sub_opt$code == 1 ) + DHCP::log_info$circuit_id = sub_opt$value; + + if ( sub_opt$code == 2 ) + DHCP::log_info$agent_remote_id = sub_opt$value; + + if ( sub_opt$code == 6 ) + DHCP::log_info$subscriber_id = sub_opt$value; + } + } + } diff --git a/scripts/test-all-policy.bro b/scripts/test-all-policy.bro index 7c828241d0..26eb6b8d9e 100644 --- a/scripts/test-all-policy.bro +++ b/scripts/test-all-policy.bro @@ -60,7 +60,9 @@ @load protocols/conn/mac-logging.bro @load protocols/conn/vlan-logging.bro @load protocols/conn/weirds.bro -@load protocols/dhcp/known-devices-and-hostnames.bro +@load protocols/dhcp/msg-orig.bro +@load protocols/dhcp/software.bro +@load protocols/dhcp/sub-opts.bro @load protocols/dns/auth-addl.bro @load protocols/dns/detect-external-names.bro @load protocols/ftp/detect-bruteforcing.bro diff --git a/src/analyzer/protocol/dhcp/dhcp-analyzer.pac b/src/analyzer/protocol/dhcp/dhcp-analyzer.pac index 6c43cb07e8..df9223f0a6 100644 --- a/src/analyzer/protocol/dhcp/dhcp-analyzer.pac +++ b/src/analyzer/protocol/dhcp/dhcp-analyzer.pac @@ -3,11 +3,13 @@ refine flow DHCP_Flow += { %member{ RecordVal *dhcp_msg_val; RecordVal *options; + VectorVal* all_options; %} %init{ dhcp_msg_val = 0; options = 0; + all_options = 0; %} %cleanup{ @@ -16,123 +18,22 @@ refine flow DHCP_Flow += { Unref(options); options = 0; + + Unref(all_options); + all_options = 0; %} - function parse_request(options: Option[], type: uint8): bool - %{ -// // Requested IP address to the server. -// ::uint32 req_addr = 0, serv_addr = 0; -// StringVal* host_name = new StringVal(""); -// -// TableVal* params_list = 0; -// RecordVal* client_id = new RecordVal(BifType::Record::DHCP::ClientID); -// client_id->Assign(0,0); -// client_id->Assign(1,new StringVal("")); -// -// switch ( type ) -// { -// case DHCPDISCOVER: -// BifEvent::generate_dhcp_discover(connection()->bro_analyzer(), -// connection()->bro_analyzer()->Conn(), -// dhcp_msg_val->Ref(), new AddrVal(req_addr), -// host_name, client_id, params_list); -// break; -// -// case DHCPREQUEST: -// BifEvent::generate_dhcp_request(connection()->bro_analyzer(), -// connection()->bro_analyzer()->Conn(), -// dhcp_msg_val->Ref(), new AddrVal(req_addr), -// new AddrVal(serv_addr), host_name, client_id, params_list); -// break; -// -// case DHCPDECLINE: -// BifEvent::generate_dhcp_decline(connection()->bro_analyzer(), -// connection()->bro_analyzer()->Conn(), -// dhcp_msg_val->Ref(), host_name); -// break; -// -// case DHCPRELEASE: -// BifEvent::generate_dhcp_release(connection()->bro_analyzer(), -// connection()->bro_analyzer()->Conn(), -// dhcp_msg_val->Ref(), host_name); -// break; -// -// case DHCPINFORM: -// BifEvent::generate_dhcp_inform(connection()->bro_analyzer(), -// connection()->bro_analyzer()->Conn(), -// dhcp_msg_val->Ref(), host_name, params_list); -// break; -// -// default: -// Unref(host_name); -// break; -// } - - return true; - %} - - function parse_reply(options: Option[], type: uint8): bool - %{ -// // RFC 1533 allows a list of router addresses. -// TableVal* router_list = 0; -// -// ::uint32 subnet_mask = 0, serv_addr = 0; -// -// uint32 lease = 0; -// StringVal* host_name = 0; -// -// uint32 reb_time = 0; -// uint32 ren_time = 0; -// StringVal* agent_cir = 0; -// StringVal* agent_rem = 0; -// StringVal* agent_sub_opt = 0; -// TableVal* relay_agent_sub_opt = new TableVal(BifType::Table::DHCP::SubOptList); -// -// if ( host_name == nullptr ) -// host_name = new StringVal(""); -// -// switch ( type ) -// { -// case DHCPOFFER: -// if ( ! router_list ) -// router_list = new TableVal(BifType::Table::DHCP::RouterList); -// -// BifEvent::generate_dhcp_offer(connection()->bro_analyzer(), -// connection()->bro_analyzer()->Conn(), -// dhcp_msg_val->Ref(), new AddrVal(subnet_mask), -// router_list, lease, new AddrVal(serv_addr), host_name); -// break; -// -// case DHCPACK: -// if ( ! router_list ) -// router_list = new TableVal(BifType::Table::DHCP::RouterList); -// -// BifEvent::generate_dhcp_ack(connection()->bro_analyzer(), -// connection()->bro_analyzer()->Conn(), -// dhcp_msg_val->Ref(), new AddrVal(subnet_mask), -// router_list, lease, new AddrVal(serv_addr), host_name, reb_time, ren_time, relay_agent_sub_opt); -// break; -// -// case DHCPNAK: -// //Unref(router_list); -// BifEvent::generate_dhcp_nak(connection()->bro_analyzer(), -// connection()->bro_analyzer()->Conn(), -// dhcp_msg_val->Ref(), host_name); -// break; -// -// default: -// //Unref(router_list); -// //Unref(host_name); -// break; -// } -// - return true; - %} - - function create_options(): bool + function create_options(code: uint8): bool %{ if ( options == nullptr ) + { options = new RecordVal(BifType::Record::DHCP::Options); + all_options = new VectorVal(index_vec); + options->Assign(0, all_options->Ref()); + } + + if ( code != 255 ) + all_options->Assign(all_options->Size(), new Val(code, TYPE_COUNT)); return true; %} @@ -148,73 +49,60 @@ refine flow DHCP_Flow += { return false; } - Unref(dhcp_msg_val); - - std::string mac_str = fmt_mac(${msg.chaddr}.data(), ${msg.chaddr}.length()); - - dhcp_msg_val = new RecordVal(BifType::Record::DHCP::Msg); - dhcp_msg_val->Assign(0, new Val(${msg.op}, TYPE_COUNT)); - dhcp_msg_val->Assign(1, new Val(${msg.type}, TYPE_COUNT)); - dhcp_msg_val->Assign(2, new Val(${msg.xid}, TYPE_COUNT)); - dhcp_msg_val->Assign(3, new StringVal(mac_str)); - dhcp_msg_val->Assign(4, new AddrVal(${msg.ciaddr})); - dhcp_msg_val->Assign(5, new AddrVal(${msg.yiaddr})); - if ( dhcp_message ) + { + // Since this is a new message, let's make sure an old + // one is gone. + Unref(dhcp_msg_val); + + std::string mac_str = fmt_mac(${msg.chaddr}.data(), ${msg.chaddr}.length()); + double secs = static_cast(${msg.secs}); + + dhcp_msg_val = new RecordVal(BifType::Record::DHCP::Msg); + dhcp_msg_val->Assign(0, new Val(${msg.op}, TYPE_COUNT)); + dhcp_msg_val->Assign(1, new Val(${msg.type}, TYPE_COUNT)); + dhcp_msg_val->Assign(2, new Val(${msg.xid}, TYPE_COUNT)); + dhcp_msg_val->Assign(3, new Val(secs, TYPE_INTERVAL)); + dhcp_msg_val->Assign(4, new Val(${msg.flags}, TYPE_COUNT)); + dhcp_msg_val->Assign(5, new AddrVal(htonl(${msg.ciaddr}))); + dhcp_msg_val->Assign(6, new AddrVal(htonl(${msg.yiaddr}))); + dhcp_msg_val->Assign(7, new AddrVal(htonl(${msg.siaddr}))); + dhcp_msg_val->Assign(8, new AddrVal(htonl(${msg.giaddr}))); + dhcp_msg_val->Assign(9, new StringVal(mac_str)); + + int last_non_null = 0; + for ( int i=0; i < ${msg.sname}.length(); i++ ) + { + if ( *(${msg.sname}.begin()+i) != 0 ) + last_non_null = i; + } + if ( last_non_null > 0 ) + dhcp_msg_val->Assign(10, new StringVal(last_non_null+1, + reinterpret_cast(${msg.sname}.begin()))); + + last_non_null = 0; + for ( int i=0; i < ${msg.file_n}.length(); i++ ) + { + if ( *(${msg.file_n}.begin()+i) != 0 ) + last_non_null = i; + } + if ( last_non_null > 0 ) + dhcp_msg_val->Assign(11, new StringVal(last_non_null+1, + reinterpret_cast(${msg.file_n}.begin()))); + BifEvent::generate_dhcp_message(connection()->bro_analyzer(), connection()->bro_analyzer()->Conn(), ${msg.is_orig}, dhcp_msg_val->Ref(), options->Ref()); - Unref(dhcp_msg_val); - dhcp_msg_val = 0; - Unref(options); - options = 0; - - //switch ( ${msg.op} ) - // { - // case BOOTREQUEST: // presumably from client to server - // if ( ${msg.type} == DHCPDISCOVER || - // ${msg.type} == DHCPREQUEST || - // ${msg.type} == DHCPDECLINE || - // ${msg.type} == DHCPRELEASE || - // ${msg.type} == DHCPINFORM ) - // { - // parse_request(${msg.options}, ${msg.type}); - // } - // else - // { - // connection()->bro_analyzer()->ProtocolViolation(fmt("unknown DHCP message type option for BOOTREQUEST (%d)", - // ${msg.type})); - // } - // break; - // - // case BOOTREPLY: // presumably from server to client - // if ( ${msg.type} == DHCPOFFER || - // ${msg.type} == DHCPACK || - // ${msg.type} == DHCPNAK || - // ${msg.type} == DHCPLEASEUNASSIGNED || - // ${msg.type} == DHCPLEASEUNKNOWN || - // ${msg.type} == DHCPLEASEACTIVE ) - // { - // parse_reply(${msg.options}, ${msg.type}); - // } - // else - // { - // connection()->bro_analyzer()->ProtocolViolation(fmt("unknown DHCP message type option for BOOTREPLY (%d)", - // ${msg.type})); - // } - // - // break; - // - // default: - // // Removing this because I've seen some packets with weird values - // // but they still parse fine. - // //connection()->bro_analyzer()->ProtocolViolation(fmt("unknown DHCP message op code (%d). Known codes: 1=BOOTREQUEST, 2=BOOTREPLY", - // // ${msg.op})); - // break; - // } + Unref(dhcp_msg_val); + dhcp_msg_val = 0; + Unref(options); + options = 0; + Unref(all_options); + all_options = 0; + } // A single message reaching this point is enough to confirm the protocol // because it's not uncommon to see a single DHCP message @@ -232,6 +120,6 @@ refine typeattr DHCP_Message += &let { }; refine typeattr Option += &let { - proc_create_options = $context.flow.create_options(); + proc_create_options = $context.flow.create_options(code); }; diff --git a/src/analyzer/protocol/dhcp/dhcp-options.pac b/src/analyzer/protocol/dhcp/dhcp-options.pac index d39484ba96..fcc7cf32aa 100644 --- a/src/analyzer/protocol/dhcp/dhcp-options.pac +++ b/src/analyzer/protocol/dhcp/dhcp-options.pac @@ -1,4 +1,3 @@ - ############################## # SUBNET OPTION ############################## @@ -6,19 +5,86 @@ let SUBNET_OPTION = 1; # Parse the option refine casetype OptionValue += { - SUBNET_OPTION -> mask : uint32; + SUBNET_OPTION -> subnet : uint32; }; refine flow DHCP_Flow += { function process_subnet_option(v: OptionValue): bool %{ - ${context.flow}->options->Assign(0, new AddrVal(htonl(${v.mask}))); + ${context.flow}->options->Assign(1, new AddrVal(htonl(${v.subnet}))); return true; %} }; refine typeattr Option += &let { - proc_subnet_option = $context.flow.process_subnet_option(info) &if(code==SUBNET_OPTION); + proc_subnet_option = $context.flow.process_subnet_option(info.value) &if(code==SUBNET_OPTION); +}; + + +############################## +# ROUTER OPTION +############################## +let ROUTER_OPTION = 3; + +# Parse the option +refine casetype OptionValue += { + ROUTER_OPTION -> router_list : uint32[length/4]; +}; + +refine flow DHCP_Flow += { + function process_router_option(v: OptionValue): bool + %{ + VectorVal* router_list = new VectorVal(BifType::Vector::DHCP::Addrs); + int num_routers = ${v.router_list}->size(); + vector* rlist = ${v.router_list}; + + for ( int i = 0; i < num_routers; ++i ) + { + uint32 raddr = (*rlist)[i]; + router_list->Assign(i, new AddrVal(htonl(raddr))); + } + + ${context.flow}->options->Assign(2, router_list); + + return true; + %} +}; + +refine typeattr Option += &let { + proc_router_option = $context.flow.process_router_option(info.value) &if(code==ROUTER_OPTION); +}; + + +############################## +# DNS SERVER OPTION +############################## +let DNS_SERVER_OPTION = 6; + +# Parse the option +refine casetype OptionValue += { + DNS_SERVER_OPTION -> dns_server_list : uint32[length/4]; +}; + +refine flow DHCP_Flow += { + function process_dns_server_option(v: OptionValue): bool + %{ + VectorVal* server_list = new VectorVal(BifType::Vector::DHCP::Addrs); + int num_servers = ${v.dns_server_list}->size(); + vector* rlist = ${v.dns_server_list}; + + for ( int i = 0; i < num_servers; ++i ) + { + uint32 raddr = (*rlist)[i]; + server_list->Assign(i, new AddrVal(htonl(raddr))); + } + + ${context.flow}->options->Assign(3, server_list); + return true; + %} +}; + +refine typeattr Option += &let { + proc_dns_server_option = $context.flow.process_dns_server_option(info.value) &if(code==DNS_SERVER_OPTION); }; @@ -35,76 +101,177 @@ refine casetype OptionValue += { refine flow DHCP_Flow += { function process_host_name_option(v: OptionValue): bool %{ - ${context.flow}->options->Assign(1, new StringVal(${v.host_name}.length(), (const char*) ${v.host_name}.begin())); + ${context.flow}->options->Assign(4, new StringVal(${v.host_name}.length(), + reinterpret_cast(${v.host_name}.begin()))); return true; %} }; refine typeattr Option += &let { - proc_host_name_option = $context.flow.process_host_name_option(info) &if(code==HOST_NAME_OPTION); + proc_host_name_option = $context.flow.process_host_name_option(info.value) &if(code==HOST_NAME_OPTION); }; ############################## -# REQ IP OPTION +# DOMAIN NAME OPTION ############################## -let REQ_IP_OPTION = 50; +let DOMAIN_NAME_OPTION = 15; # Parse the option refine casetype OptionValue += { - REQ_IP_OPTION -> req_addr : uint32; + DOMAIN_NAME_OPTION -> domain_name : bytestring &length=length; }; refine flow DHCP_Flow += { - function process_req_ip_option(v: OptionValue): bool + function process_domain_name_option(v: OptionValue): bool %{ - ${context.flow}->options->Assign(2, new AddrVal(htonl(${v.req_addr}))); - - return true; - %} -}; - -refine typeattr Option += &let { - proc_req_ip_option = $context.flow.process_req_ip_option(info) &if(code==REQ_IP_OPTION); -}; - -############################## -# ROUTER OPTION -############################## -let ROUTER_OPTION = 3; - -# Parse the option -refine casetype OptionValue += { - ROUTER_OPTION -> router_list : uint32[length/4]; -}; - -refine flow DHCP_Flow += { - function process_router_option(v: OptionValue): bool - %{ - TableVal* router_list = new TableVal(BifType::Table::DHCP::RouterList); - int num_routers = ${v.router_list}->size(); - vector* rlist = ${v.router_list}; - - for ( int i = 0; i < num_routers; ++i ) + int last_non_null = 0; + for ( int i=0; i < ${v.domain_name}.length(); i++) { - uint32 raddr = (*rlist)[i]; - ::uint32 tmp_addr; - tmp_addr = htonl(raddr); - // index starting from 1 - Val* index = new Val(i + 1, TYPE_COUNT); - router_list->Assign(index, new AddrVal(tmp_addr)); - Unref(index); + if ( *(${v.domain_name}.begin()+i) != 0 ) + last_non_null = i; } - ${context.flow}->options->Assign(3, router_list); + ${context.flow}->options->Assign(5, new StringVal(last_non_null == 0 ? 0 : last_non_null+1, + reinterpret_cast(${v.domain_name}.begin()))); return true; %} }; refine typeattr Option += &let { - proc_router_option = $context.flow.process_router_option(info) &if(code==ROUTER_OPTION); + proc_domain_name_option = $context.flow.process_domain_name_option(info.value) &if(code==DOMAIN_NAME_OPTION); +}; + + +############################## +# FORWARDING OPTION +############################## +let FORWARDING_OPTION = 19; + +# Parse the option +refine casetype OptionValue += { + FORWARDING_OPTION -> forwarding : uint8; +}; + +refine flow DHCP_Flow += { + function process_forwarding_option(v: OptionValue): bool + %{ + ${context.flow}->options->Assign(6, new Val(${v.forwarding} == 0 ? false : true, TYPE_BOOL)); + + return true; + %} +}; + +refine typeattr Option += &let { + proc_forwarding_option = $context.flow.process_forwarding_option(info.value) &if(code==FORWARDING_OPTION); +}; + + +############################## +# BROADCAST ADDRESS OPTION +############################## +let BROADCAST_ADDRESS_OPTION = 28; + +# Parse the option +refine casetype OptionValue += { + BROADCAST_ADDRESS_OPTION -> broadcast_address : uint32; +}; + +refine flow DHCP_Flow += { + function process_broadcast_address_option(v: OptionValue): bool + %{ + ${context.flow}->options->Assign(7, new AddrVal(htonl(${v.broadcast_address}))); + + return true; + %} +}; + +refine typeattr Option += &let { + proc_broadcast_address_option = $context.flow.process_broadcast_address_option(info.value) &if(code==BROADCAST_ADDRESS_OPTION); +}; + + +############################## +# VENDOR SPECIFIC OPTION +############################## +let VENDOR_SPECIFIC_OPTION = 43; + +# Parse the option +refine casetype OptionValue += { + VENDOR_SPECIFIC_OPTION -> vendor_specific : bytestring &length=length; +}; + +refine flow DHCP_Flow += { + function process_vendor_specific_option(v: OptionValue): bool + %{ + ${context.flow}->options->Assign(8, new StringVal(${v.vendor_specific}.length(), + reinterpret_cast(${v.vendor_specific}.begin()))); + + return true; + %} +}; + +refine typeattr Option += &let { + proc_vendor_specific_option = $context.flow.process_vendor_specific_option(info.value) &if(code==VENDOR_SPECIFIC_OPTION); +}; + + +############################## +# NETBIOS NAME SERVER OPTION +############################## +let NBNS_OPTION = 44; + +# Parse the option +refine casetype OptionValue += { + NBNS_OPTION -> nbns : uint32[length/4]; +}; + +refine flow DHCP_Flow += { + function process_nbns_option(v: OptionValue): bool + %{ + VectorVal* server_list = new VectorVal(BifType::Vector::DHCP::Addrs); + int num_servers = ${v.nbns}->size(); + vector* rlist = ${v.nbns}; + + for ( int i = 0; i < num_servers; ++i ) + { + uint32 raddr = (*rlist)[i]; + server_list->Assign(i, new AddrVal(htonl(raddr))); + } + + ${context.flow}->options->Assign(9, server_list); + return true; + %} +}; + +refine typeattr Option += &let { + proc_nbns_option = $context.flow.process_nbns_option(info.value) &if(code==NBNS_OPTION); +}; + + +############################## +# ADDR REQUEST OPTION +############################## +let ADDR_REQUEST_OPTION = 50; + +# Parse the option +refine casetype OptionValue += { + ADDR_REQUEST_OPTION -> addr_request : uint32; +}; + +refine flow DHCP_Flow += { + function process_addr_request_option(v: OptionValue): bool + %{ + ${context.flow}->options->Assign(10, new AddrVal(htonl(${v.addr_request}))); + + return true; + %} +}; + +refine typeattr Option += &let { + proc_addr_request_option = $context.flow.process_addr_request_option(info.value) &if(code==ADDR_REQUEST_OPTION); }; @@ -122,16 +289,17 @@ refine flow DHCP_Flow += { function process_lease_option(v: OptionValue): bool %{ double lease = static_cast(${v.lease}); - ${context.flow}->options->Assign(4, new Val(lease, TYPE_INTERVAL)); + ${context.flow}->options->Assign(11, new Val(lease, TYPE_INTERVAL)); return true; %} }; refine typeattr Option += &let { - proc_lease_option = $context.flow.process_lease_option(info) &if(code==LEASE_OPTION); + proc_lease_option = $context.flow.process_lease_option(info.value) &if(code==LEASE_OPTION); }; + ############################## # SERV_ID_OPTION OPTION ############################## @@ -145,14 +313,14 @@ refine casetype OptionValue += { refine flow DHCP_Flow += { function process_serv_id_option(v: OptionValue): bool %{ - ${context.flow}->options->Assign(5, new AddrVal(htonl(${v.serv_addr}))); + ${context.flow}->options->Assign(12, new AddrVal(htonl(${v.serv_addr}))); return true; %} }; refine typeattr Option += &let { - proc_serv_id_option = $context.flow.process_serv_id_option(info) &if(code==SERV_ID_OPTION); + proc_serv_id_option = $context.flow.process_serv_id_option(info.value) &if(code==SERV_ID_OPTION); }; @@ -169,76 +337,148 @@ refine casetype OptionValue += { refine flow DHCP_Flow += { function process_par_req_list_option(v: OptionValue): bool %{ - TableVal* params_list = new TableVal(BifType::Table::DHCP::ParamsList); + VectorVal* params = new VectorVal(index_vec); int num_parms = ${v.par_req_list}->size(); vector* plist = ${v.par_req_list}; for (int i=0; i < num_parms; ++i) { uint8 param = (*plist)[i]; - Val* index = new Val(i+1, TYPE_COUNT); - params_list->Assign(index, new Val(param, TYPE_COUNT)); - Unref(index); + params->Assign(i, new Val(param, TYPE_COUNT)); } - ${context.flow}->options->Assign(6, params_list); + ${context.flow}->options->Assign(13, params); return true; %} }; refine typeattr Option += &let { - proc_par_req_list_option = $context.flow.process_par_req_list_option(info) &if(code==PAR_REQ_LIST_OPTION); + proc_par_req_list_option = $context.flow.process_par_req_list_option(info.value) &if(code==PAR_REQ_LIST_OPTION); }; ############################## -# REN_TIME_OPTION OPTION +# MESSAGE OPTION ############################## -let REN_TIME_OPTION = 58; +let MESSAGE_OPTION = 56; # Parse the option refine casetype OptionValue += { - REN_TIME_OPTION -> ren_time : uint32; + MESSAGE_OPTION -> message : bytestring &length=length; }; refine flow DHCP_Flow += { - function process_ren_time_option(v: OptionValue): bool + function process_message_option(v: OptionValue): bool %{ - double ren_time = static_cast(${v.ren_time}); - ${context.flow}->options->Assign(7, new Val(ren_time, TYPE_INTERVAL)); + ${context.flow}->options->Assign(14, new StringVal(${v.message}.length(), + reinterpret_cast(${v.message}.begin()))); return true; %} }; refine typeattr Option += &let { - proc_ren_time_option = $context.flow.process_ren_time_option(info) &if(code==REN_TIME_OPTION); + proc_message_option = $context.flow.process_message_option(info.value) &if(code==MESSAGE_OPTION); }; ############################## -# REB_TIME_OPTION OPTION +# MAX MESSAGE SIZE OPTION ############################## -let REB_TIME_OPTION = 59; +let MAX_MESSAGE_SIZE_OPTION = 57; # Parse the option refine casetype OptionValue += { - REB_TIME_OPTION -> reb_time : uint32; + MAX_MESSAGE_SIZE_OPTION -> max_msg_size : uint16; }; refine flow DHCP_Flow += { - function process_reb_time_option(v: OptionValue): bool + function process_max_message_size_option(v: OptionValue): bool %{ - double reb_time = static_cast(${v.reb_time}); - ${context.flow}->options->Assign(8, new Val(reb_time, TYPE_INTERVAL)); + ${context.flow}->options->Assign(15, new Val(${v.max_msg_size}, TYPE_COUNT)); return true; %} }; refine typeattr Option += &let { - proc_reb_time_option = $context.flow.process_reb_time_option(info) &if(code==REB_TIME_OPTION); + proc_max_message_size_option = $context.flow.process_max_message_size_option(info.value) &if(code==MAX_MESSAGE_SIZE_OPTION); +}; + + +############################## +# RENEWAL_TIME_OPTION OPTION +############################## +let RENEWAL_TIME_OPTION = 58; + +# Parse the option +refine casetype OptionValue += { + RENEWAL_TIME_OPTION -> renewal_time : uint32; +}; + +refine flow DHCP_Flow += { + function process_renewal_time_option(v: OptionValue): bool + %{ + double renewal_time = static_cast(${v.renewal_time}); + ${context.flow}->options->Assign(16, new Val(renewal_time, TYPE_INTERVAL)); + + return true; + %} +}; + +refine typeattr Option += &let { + proc_renewal_time_option = $context.flow.process_renewal_time_option(info.value) &if(code==RENEWAL_TIME_OPTION); +}; + + +############################## +# REBINDING_TIME_OPTION OPTION +############################## +let REBINDING_TIME_OPTION = 59; + +# Parse the option +refine casetype OptionValue += { + REBINDING_TIME_OPTION -> rebinding_time : uint32; +}; + +refine flow DHCP_Flow += { + function process_rebinding_time_option(v: OptionValue): bool + %{ + double rebinding_time = static_cast(${v.rebinding_time}); + ${context.flow}->options->Assign(17, new Val(rebinding_time, TYPE_INTERVAL)); + + return true; + %} +}; + +refine typeattr Option += &let { + proc_rebinding_time_option = $context.flow.process_rebinding_time_option(info.value) &if(code==REBINDING_TIME_OPTION); +}; + + +############################## +# VENDOR CLASS OPTION +############################## +let VENDOR_CLASS_OPTION = 60; + +# Parse the option +refine casetype OptionValue += { + VENDOR_CLASS_OPTION -> vendor_class : bytestring &length=length; +}; + +refine flow DHCP_Flow += { + function process_vendor_class_option(v: OptionValue): bool + %{ + ${context.flow}->options->Assign(18, new StringVal(${v.vendor_class}.length(), + reinterpret_cast(${v.vendor_class}.begin()))); + + return true; + %} +}; + +refine typeattr Option += &let { + proc_vendor_class_option = $context.flow.process_vendor_class_option(info.value) &if(code==VENDOR_CLASS_OPTION); }; @@ -264,17 +504,79 @@ refine flow DHCP_Flow += { client_id->Assign(0, new Val(${v.client_id.hwtype}, TYPE_COUNT)); client_id->Assign(1, new StringVal(fmt_mac(${v.client_id.hwaddr}.begin(), ${v.client_id.hwaddr}.length()))); - ${context.flow}->options->Assign(9, client_id); + ${context.flow}->options->Assign(19, client_id); return true; %} }; refine typeattr Option += &let { - proc_client_id_option = $context.flow.process_client_id_option(info) &if(code==CLIENT_ID_OPTION); + proc_client_id_option = $context.flow.process_client_id_option(info.value) &if(code==CLIENT_ID_OPTION); }; +############################## +# USER CLASS OPTION +############################## +let USER_CLASS_OPTION = 77; + +# Parse the option +refine casetype OptionValue += { + USER_CLASS_OPTION -> user_class : bytestring &length=length; +}; + +refine flow DHCP_Flow += { + function process_user_class_option(v: OptionValue): bool + %{ + ${context.flow}->options->Assign(20, new StringVal(${v.user_class}.length(), + reinterpret_cast(${v.user_class}.begin()))); + + return true; + %} +}; + +refine typeattr Option += &let { + proc_user_class_option = $context.flow.process_user_class_option(info.value) &if(code==USER_CLASS_OPTION); +}; + + +############################## +# CLIENT FQDN OPTION +############################## +let CLIENT_FQDN_OPTION = 81; + +type Client_FQDN(length: uint8) = record { + flags : uint8; + rcode1 : uint8; + rcode2 : uint8; + domain_name : bytestring &length=length-3; +}; + +# Parse the option +refine casetype OptionValue += { + CLIENT_FQDN_OPTION -> client_fqdn : Client_FQDN(length); +}; + +refine flow DHCP_Flow += { + function process_client_fqdn_option(v: OptionValue): bool + %{ + RecordVal* client_fqdn = new RecordVal(BifType::Record::DHCP::ClientFQDN); + client_fqdn->Assign(0, new Val(${v.client_fqdn.flags}, TYPE_COUNT)); + client_fqdn->Assign(1, new Val(${v.client_fqdn.rcode1}, TYPE_COUNT)); + client_fqdn->Assign(2, new Val(${v.client_fqdn.rcode2}, TYPE_COUNT)); + const char* domain_name = reinterpret_cast(${v.client_fqdn.domain_name}.begin()); + client_fqdn->Assign(3, new StringVal(${v.client_fqdn.domain_name}.length(), domain_name)); + + ${context.flow}->options->Assign(21, client_fqdn); + + return true; + %} +}; + +refine typeattr Option += &let { + proc_client_fqdn_option = $context.flow.process_client_fqdn_option(info.value) &if(code==CLIENT_FQDN_OPTION); +}; + ############################## # RELAY_AGENT_INF OPTION @@ -296,11 +598,30 @@ refine casetype OptionValue += { }; refine flow DHCP_Flow += { + %member{ + uint8 sum_len; + %} + + %init{ + sum_len = 0; + %} + + %cleanup{ + sum_len = 0; + %} + + function get_dhcp_sumlen(len: uint8): uint8 + %{ + sum_len = len + sum_len; + return sum_len; + %} + function process_relay_agent_inf_option(v: OptionValue): bool %{ - TableVal* relay_agent_sub_opt = new TableVal(BifType::Table::DHCP::SubOptList); + VectorVal* relay_agent_sub_opt = new VectorVal(BifType::Vector::DHCP::SubOpts); RecordVal* r = new RecordVal(BifType::Record::DHCP::SubOpt); - uint i = 1; + + uint16 i = 0; for ( auto ptrsubopt = ${v.relay_agent_inf}->begin(); ptrsubopt != ${v.relay_agent_inf}->end(); ++ptrsubopt ) { @@ -308,20 +629,69 @@ refine flow DHCP_Flow += { r->Assign(0, new Val((*ptrsubopt)->code(), TYPE_COUNT)); r->Assign(1, bytestring_to_val((*ptrsubopt)->value())); - Val* index = new Val(i, TYPE_COUNT); - relay_agent_sub_opt->Assign(index, r); - Unref(index); + relay_agent_sub_opt->Assign(i, r); ++i; } - ${context.flow}->options->Assign(10, relay_agent_sub_opt); + ${context.flow}->options->Assign(22, relay_agent_sub_opt); return true; %} }; refine typeattr Option += &let { - proc_relay_agent_info_option = $context.flow.process_relay_agent_inf_option(info) &if(code==RELAY_AGENT_INF_OPTION); + proc_relay_agent_info_option = $context.flow.process_relay_agent_inf_option(info.value) &if(code==RELAY_AGENT_INF_OPTION); }; +############################## +# AUTO_CONFIG OPTION +############################## +let AUTO_CONFIG_OPTION = 116; + +# Parse the option +refine casetype OptionValue += { + AUTO_CONFIG_OPTION -> auto_config : uint8; +}; + +refine flow DHCP_Flow += { + function process_auto_config_option(v: OptionValue): bool + %{ + ${context.flow}->options->Assign(23, new Val(${v.auto_config} == 0 ? false : true, TYPE_BOOL)); + + return true; + %} +}; + +refine typeattr Option += &let { + proc_auto_config_option = $context.flow.process_auto_config_option(info.value) &if(code==AUTO_CONFIG_OPTION); +}; + + +############################## +# AUTO PROXY CONFIG OPTION +############################## +let AUTO_PROXY_CONFIG_OPTION = 252; + +# Parse the option +refine casetype OptionValue += { + AUTO_PROXY_CONFIG_OPTION -> auto_proxy_config : bytestring &length=length; +}; + +refine flow DHCP_Flow += { + function process_auto_proxy_config_option(v: OptionValue): bool + %{ + int string_len = ${v.auto_proxy_config}.length(); + const char* last_char = reinterpret_cast(${v.auto_proxy_config}.begin()+${v.auto_proxy_config}.length()); + bool has_newline = strncmp(last_char, "\x0a", 1); + ${context.flow}->options->Assign(24, new StringVal(string_len - (has_newline ? 1 : 0), + reinterpret_cast(${v.auto_proxy_config}.begin()))); + + return true; + %} +}; + +refine typeattr Option += &let { + proc_auto_proxy_config_option = $context.flow.process_auto_proxy_config_option(info.value) &if(code==AUTO_PROXY_CONFIG_OPTION); +}; + diff --git a/src/analyzer/protocol/dhcp/dhcp-protocol.pac b/src/analyzer/protocol/dhcp/dhcp-protocol.pac index 43dade5989..af48a416c4 100644 --- a/src/analyzer/protocol/dhcp/dhcp-protocol.pac +++ b/src/analyzer/protocol/dhcp/dhcp-protocol.pac @@ -8,34 +8,22 @@ enum OP_type { let MSG_TYPE_OPTION = 53; -enum DHCP_message_type { - DHCPDISCOVER = 1, - DHCPOFFER = 2, - DHCPREQUEST = 3, - DHCPDECLINE = 4, - DHCPACK = 5, - DHCPNAK = 6, - DHCPRELEASE = 7, - DHCPINFORM = 8, - DHCPFORCERENEW = 9, # RFC 2132 - DHCPLEASEQUERY = 10, # RFC 4388 - DHCPLEASEUNASSIGNED = 11, # RFC 4388 - DHCPLEASEUNKNOWN = 12, # RFC 4388 - DHCPLEASEACTIVE = 13 # RFC 4388 -}; - type OptionValue(code: uint8, length: uint8) = case code of { # This is extended in dhcp-options.pac - MSG_TYPE_OPTION -> msg_type : uint8; - default -> other : bytestring &length = length; + MSG_TYPE_OPTION -> msg_type : uint8; + default -> other : bytestring &length = length; +}; + +type OptionValueWrapper(code: uint8) = record { + length : uint8; + value : OptionValue(code, length); }; type Option = record { code : uint8; - length : uint8; data : case code of { 0, 255 -> none : empty; - default -> info : OptionValue(code, length); + default -> info : OptionValueWrapper(code); }; } &let { last = (code == 255); # Mark the end of a list of options @@ -55,7 +43,7 @@ type DHCP_Message(is_orig: bool) = record { giaddr : uint32; chaddr : bytestring &length = 16; sname : bytestring &length = 64; - file : bytestring &length = 128; + file_n : bytestring &length = 128; # Cookie belongs to options in RFC 2131, but we separate # them here for easy parsing. cookie : uint32; @@ -65,24 +53,6 @@ type DHCP_Message(is_orig: bool) = record { } &byteorder = bigendian; refine flow DHCP_Flow += { - %member{ - uint8 sum_len; - %} - - %init{ - sum_len = 0; - %} - - %cleanup{ - sum_len = 0; - %} - - function get_dhcp_sumlen(len: uint8): uint8 - %{ - sum_len = len + sum_len; - return sum_len; - %} - function get_dhcp_msgtype(options: Option[]): uint8 %{ uint8 type = 0; @@ -91,7 +61,7 @@ refine flow DHCP_Flow += { { if ( (*ptr)->code() == MSG_TYPE_OPTION ) { - type = (*ptr)->info()->msg_type(); + type = (*ptr)->info()->value()->msg_type(); break; } } diff --git a/src/analyzer/protocol/dhcp/events.bif b/src/analyzer/protocol/dhcp/events.bif index 663ba3c319..3b2e6366a8 100644 --- a/src/analyzer/protocol/dhcp/events.bif +++ b/src/analyzer/protocol/dhcp/events.bif @@ -1,188 +1,12 @@ - +## Generated for all DHCP messages. +## +## c: The connection record describing the underlying UDP flow. +## +## is_orig: Indicate if the message came in a packet from the originator/client +## of the udp flow or the responder/server. +## +## msg: The parsed type-independent part of the DHCP message. The message type +## is indicated in this record. +## +## options: The full set of supported and parsed DHCP options. event dhcp_message%(c: connection, is_orig: bool, msg: DHCP::Msg, options: DHCP::Options%); - -## Generated for DHCP messages of type *DHCPDISCOVER* (client broadcast to locate -## available servers). -## -## c: The connection record describing the underlying UDP flow. -## -## msg: The parsed type-independent part of the DHCP message. -## -## req_addr: The specific address requested by the client. -## -## host_name: The value of the host name option, if specified by the client. -## -## client_id: The value of the client id (usually the MAC ADDRESS). -## -## req_params: The Parameters Request List. -## -## .. bro:see:: dhcp_discover dhcp_offer dhcp_request dhcp_decline dhcp_ack dhcp_nak -## dhcp_release dhcp_inform -## -## .. note:: Bro does not support broadcast packets (as used by the DHCP -## protocol). It treats broadcast addresses just like any other and -## associates packets into transport-level flows in the same way as usual. -## -event dhcp_discover%(c: connection, msg: DHCP::Msg, req_addr: addr, host_name: string, client_id: DHCP::ClientID, req_params: DHCP::ParamsList%); - -## Generated for DHCP messages of type *DHCPOFFER* (server to client in response -## to DHCPDISCOVER with offer of configuration parameters). -## -## c: The connection record describing the underlying UDP flow. -## -## msg: The parsed type-independent part of the DHCP message. -## -## mask: The subnet mask specified by the message. -## -## router: The list of routers specified by the message. -## -## lease: The least interval specified by the message. -## -## serv_addr: The server address specified by the message. -## -## host_name: Optional host name value. May differ from the host name requested -## from the client. -## -## .. bro:see:: dhcp_discover dhcp_request dhcp_decline dhcp_ack dhcp_nak -## dhcp_release dhcp_inform -## -## .. note:: Bro does not support broadcast packets (as used by the DHCP -## protocol). It treats broadcast addresses just like any other and -## associates packets into transport-level flows in the same way as usual. -## -event dhcp_offer%(c: connection, msg: DHCP::Msg, mask: addr, router: DHCP::RouterList, lease: interval, serv_addr: addr, host_name: string%); - -## Generated for DHCP messages of type *DHCPREQUEST* (Client message to servers either -## (a) requesting offered parameters from one server and implicitly declining offers -## from all others, (b) confirming correctness of previously allocated address after, -## e.g., system reboot, or (c) extending the lease on a particular network address.) -## -## c: The connection record describing the underlying UDP flow. -## -## msg: The parsed type-independent part of the DHCP message. -## -## req_addr: The client address specified by the message. -## -## serv_addr: The server address specified by the message. -## -## host_name: The value of the host name option, if specified by the client. -## -## client_id: The client id. -## -## req_parms: The Parameters Request List. -## -## .. bro:see:: dhcp_discover dhcp_offer dhcp_decline dhcp_ack dhcp_nak -## dhcp_release dhcp_inform -## -## .. note:: Bro does not support broadcast packets (as used by the DHCP -## protocol). It treats broadcast addresses just like any other and -## associates packets into transport-level flows in the same way as usual. -## -event dhcp_request%(c: connection, msg: DHCP::Msg, req_addr: addr, serv_addr: addr, host_name: string, client_id: DHCP::ClientID, req_params: DHCP::ParamsList%); - -## Generated for DHCP messages of type *DHCPDECLINE* (Client to server indicating -## network address is already in use). -## -## c: The connection record describing the underlying UDP flow. -## -## msg: The parsed type-independent part of the DHCP message. -## -## host_name: Optional host name value. -## -## .. bro:see:: dhcp_discover dhcp_offer dhcp_request dhcp_ack dhcp_nak -## dhcp_release dhcp_inform -## -## .. note:: Bro does not support broadcast packets (as used by the DHCP -## protocol). It treats broadcast addresses just like any other and -## associates packets into transport-level flows in the same way as usual. -## -event dhcp_decline%(c: connection, msg: DHCP::Msg, host_name: string%); - -## Generated for DHCP messages of type *DHCPACK* (Server to client with configuration -## parameters, including committed network address). -## -## c: The connection record describing the underlying UDP flow. -## -## msg: The parsed type-independent part of the DHCP message. -## -## mask: The subnet mask specified by the message. -## -## router: The list of routers specified by the message. -## -## lease: The least interval specified by the message. -## -## serv_addr: The server address specified by the message. -## -## host_name: Optional host name value. May differ from the host name requested -## from the client. -## -## reb_time: A 32-bit unsigned integer indicating the number of seconds before -## the cilent enters the rebinding state if it has not renewed its -## current address lease with the DHCP server. -## -## ren_time: A 32-bit unsigned integer indicating the number of seconds before -## the client begins to renew its address lease with the DHCP server. -## -## sub_opt: DHCP relay agent information option list of suboption values -## (see http://slaptijack.com/networking/what-is-dhcp-option-82/ or -## http://www.juniper.net/documentation/en_US/junose14.3/topics/concept/dhcp-relay-option-82-suboptions-overview.html) -## -## .. bro:see:: dhcp_discover dhcp_offer dhcp_request dhcp_decline dhcp_nak -## dhcp_release dhcp_inform -## -event dhcp_ack%(c: connection, msg: DHCP::Msg, mask: addr, router: DHCP::RouterList, lease: interval, serv_addr: addr, host_name: string%); - -## Generated for DHCP messages of type *DHCPNAK* (Server to client indicating client's -## notion of network address is incorrect (e.g., client has moved to new subnet) or -## client's lease has expired). -## -## c: The connection record describing the underlying UDP flow. -## -## msg: The parsed type-independent part of the DHCP message. -## -## host_name: Optional host name value. -## -## .. bro:see:: dhcp_discover dhcp_offer dhcp_request dhcp_decline dhcp_ack dhcp_release -## dhcp_inform -## -## .. note:: Bro does not support broadcast packets (as used by the DHCP -## protocol). It treats broadcast addresses just like any other and -## associates packets into transport-level flows in the same way as usual. -## -event dhcp_nak%(c: connection, msg: DHCP::Msg, host_name: string%); - -## Generated for DHCP messages of type *DHCPRELEASE* (Client to server relinquishing -## network address and cancelling remaining lease). -## -## c: The connection record describing the underlying UDP flow. -## -## msg: The parsed type-independent part of the DHCP message. -## -## host_name: The value of the host name option, if specified by the client. -## -## .. bro:see:: dhcp_discover dhcp_offer dhcp_request dhcp_decline dhcp_ack dhcp_nak -## dhcp_inform -## -event dhcp_release%(c: connection, msg: DHCP::Msg, host_name: string%); - -## Generated for DHCP messages of type *DHCPINFORM* (Client to server, asking only for -## local configuration parameters; client already has externally configured network -## address). -## -## c: The connection record describing the underlying UDP flow. -## -## msg: The parsed type-independent part of the DHCP message. -## -## host_name: The value of the host name option, if specified by the client. -## -## req_parms: The Parameters Request List. -## -## .. bro:see:: dhcp_discover dhcp_offer dhcp_request dhcp_decline dhcp_ack dhcp_nak -## dhcp_release -## -## .. note:: Bro does not support broadcast packets (as used by the DHCP -## protocol). It treats broadcast addresses just like any other and -## associates packets into transport-level flows in the same way as usual. -## -event dhcp_inform%(c: connection, msg: DHCP::Msg, host_name: string%); - diff --git a/src/analyzer/protocol/dhcp/types.bif b/src/analyzer/protocol/dhcp/types.bif index bf55018b00..d0062e312c 100644 --- a/src/analyzer/protocol/dhcp/types.bif +++ b/src/analyzer/protocol/dhcp/types.bif @@ -1,9 +1,9 @@ module DHCP; type Msg: record; -type RouterList: table; -type ParamsList: table; -type SubOptList: table; +type Addrs: vector; type SubOpt: record; +type SubOpts: vector; +type ClientFQDN: record; type ClientID: record; type Options: record; diff --git a/testing/btest/Baseline/core.print-bpf-filters/output2 b/testing/btest/Baseline/core.print-bpf-filters/output2 index 53d4189bf7..af9ccda1ae 100644 --- a/testing/btest/Baseline/core.print-bpf-filters/output2 +++ b/testing/btest/Baseline/core.print-bpf-filters/output2 @@ -17,6 +17,7 @@ 1 3306 1 3389 1 3544 +1 4011 2 443 1 502 1 5060 @@ -51,8 +52,8 @@ 1 992 1 993 1 995 -58 and -57 or -58 port +59 and +58 or +59 port 40 tcp -18 udp +19 udp diff --git a/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log b/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log index 52a660261c..c55bb605ae 100644 --- a/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log +++ b/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log @@ -3,7 +3,7 @@ #empty_field (empty) #unset_field - #path loaded_scripts -#open 2017-05-02-20-38-47 +#open 2018-03-01-16-07-03 #fields name #types string scripts/base/init-bare.bro @@ -66,6 +66,7 @@ scripts/base/init-bare.bro build/scripts/base/bif/plugins/Bro_DCE_RPC.types.bif.bro build/scripts/base/bif/plugins/Bro_DCE_RPC.events.bif.bro build/scripts/base/bif/plugins/Bro_DHCP.events.bif.bro + build/scripts/base/bif/plugins/Bro_DHCP.types.bif.bro build/scripts/base/bif/plugins/Bro_DNP3.events.bif.bro build/scripts/base/bif/plugins/Bro_DNS.events.bif.bro build/scripts/base/bif/plugins/Bro_File.events.bif.bro @@ -168,4 +169,4 @@ scripts/base/init-bare.bro build/scripts/base/bif/plugins/Bro_SQLiteWriter.sqlite.bif.bro scripts/policy/misc/loaded-scripts.bro scripts/base/utils/paths.bro -#close 2017-05-02-20-38-47 +#close 2018-03-01-16-07-03 diff --git a/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log b/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log index 75ef872a95..7259566568 100644 --- a/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log +++ b/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log @@ -3,7 +3,7 @@ #empty_field (empty) #unset_field - #path loaded_scripts -#open 2017-05-02-20-39-05 +#open 2018-03-01-16-09-46 #fields name #types string scripts/base/init-bare.bro @@ -66,6 +66,7 @@ scripts/base/init-bare.bro build/scripts/base/bif/plugins/Bro_DCE_RPC.types.bif.bro build/scripts/base/bif/plugins/Bro_DCE_RPC.events.bif.bro build/scripts/base/bif/plugins/Bro_DHCP.events.bif.bro + build/scripts/base/bif/plugins/Bro_DHCP.types.bif.bro build/scripts/base/bif/plugins/Bro_DNP3.events.bif.bro build/scripts/base/bif/plugins/Bro_DNS.events.bif.bro build/scripts/base/bif/plugins/Bro_File.events.bif.bro @@ -267,7 +268,6 @@ scripts/base/init-default.bro scripts/base/protocols/dhcp/__load__.bro scripts/base/protocols/dhcp/consts.bro scripts/base/protocols/dhcp/main.bro - scripts/base/protocols/dhcp/utils.bro scripts/base/protocols/dnp3/__load__.bro scripts/base/protocols/dnp3/main.bro scripts/base/protocols/dnp3/consts.bro @@ -357,4 +357,4 @@ scripts/base/init-default.bro scripts/base/misc/find-filtered-trace.bro scripts/base/misc/version.bro scripts/policy/misc/loaded-scripts.bro -#close 2017-05-02-20-39-05 +#close 2018-03-01-16-09-46 diff --git a/testing/btest/Baseline/plugins.hooks/output b/testing/btest/Baseline/plugins.hooks/output index f6a5c4ad37..07364ecbd3 100644 --- a/testing/btest/Baseline/plugins.hooks/output +++ b/testing/btest/Baseline/plugins.hooks/output @@ -4,6 +4,7 @@ 0.000000 MetaHookPost CallFunction(Analyzer::__disable_analyzer, , (Analyzer::ANALYZER_TCPSTATS)) -> 0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_AYIYA, 5072/udp)) -> 0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_DCE_RPC, 135/tcp)) -> +0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_DHCP, 4011/udp)) -> 0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_DHCP, 67/udp)) -> 0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_DHCP, 68/udp)) -> 0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_DNP3_TCP, 20000/tcp)) -> @@ -66,6 +67,7 @@ 0.000000 MetaHookPost CallFunction(Analyzer::disable_analyzer, , (Analyzer::ANALYZER_TCPSTATS)) -> 0.000000 MetaHookPost CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_AYIYA, 5072/udp)) -> 0.000000 MetaHookPost CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_DCE_RPC, 135/tcp)) -> +0.000000 MetaHookPost CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_DHCP, 4011/udp)) -> 0.000000 MetaHookPost CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_DHCP, 67/udp)) -> 0.000000 MetaHookPost CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_DHCP, 68/udp)) -> 0.000000 MetaHookPost CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_DNP3_TCP, 20000/tcp)) -> @@ -256,7 +258,7 @@ 0.000000 MetaHookPost CallFunction(Log::__create_stream, , (Weird::LOG, [columns=, ev=Weird::log_weird, path=weird])) -> 0.000000 MetaHookPost CallFunction(Log::__create_stream, , (X509::LOG, [columns=, ev=X509::log_x509, path=x509])) -> 0.000000 MetaHookPost CallFunction(Log::__create_stream, , (mysql::LOG, [columns=, ev=MySQL::log_mysql, path=mysql])) -> -0.000000 MetaHookPost CallFunction(Log::__write, , (PacketFilter::LOG, [ts=1516211213.330468, node=bro, filter=ip or not ip, init=T, success=T])) -> +0.000000 MetaHookPost CallFunction(Log::__write, , (PacketFilter::LOG, [ts=1519920860.516463, node=bro, filter=ip or not ip, init=T, success=T])) -> 0.000000 MetaHookPost CallFunction(Log::add_default_filter, , (Cluster::LOG)) -> 0.000000 MetaHookPost CallFunction(Log::add_default_filter, , (Communication::LOG)) -> 0.000000 MetaHookPost CallFunction(Log::add_default_filter, , (Conn::LOG)) -> @@ -429,7 +431,7 @@ 0.000000 MetaHookPost CallFunction(Log::create_stream, , (Weird::LOG, [columns=, ev=Weird::log_weird, path=weird])) -> 0.000000 MetaHookPost CallFunction(Log::create_stream, , (X509::LOG, [columns=, ev=X509::log_x509, path=x509])) -> 0.000000 MetaHookPost CallFunction(Log::create_stream, , (mysql::LOG, [columns=, ev=MySQL::log_mysql, path=mysql])) -> -0.000000 MetaHookPost CallFunction(Log::write, , (PacketFilter::LOG, [ts=1516211213.330468, node=bro, filter=ip or not ip, init=T, success=T])) -> +0.000000 MetaHookPost CallFunction(Log::write, , (PacketFilter::LOG, [ts=1519920860.516463, node=bro, filter=ip or not ip, init=T, success=T])) -> 0.000000 MetaHookPost CallFunction(NetControl::check_plugins, , ()) -> 0.000000 MetaHookPost CallFunction(NetControl::init, , ()) -> 0.000000 MetaHookPost CallFunction(Notice::want_pp, , ()) -> @@ -480,6 +482,7 @@ 0.000000 MetaHookPost LoadFile(0, .<...>/Bro_DCE_RPC.events.bif.bro) -> -1 0.000000 MetaHookPost LoadFile(0, .<...>/Bro_DCE_RPC.types.bif.bro) -> -1 0.000000 MetaHookPost LoadFile(0, .<...>/Bro_DHCP.events.bif.bro) -> -1 +0.000000 MetaHookPost LoadFile(0, .<...>/Bro_DHCP.types.bif.bro) -> -1 0.000000 MetaHookPost LoadFile(0, .<...>/Bro_DNP3.events.bif.bro) -> -1 0.000000 MetaHookPost LoadFile(0, .<...>/Bro_DNS.events.bif.bro) -> -1 0.000000 MetaHookPost LoadFile(0, .<...>/Bro_FTP.events.bif.bro) -> -1 @@ -782,6 +785,7 @@ 0.000000 MetaHookPre CallFunction(Analyzer::__disable_analyzer, , (Analyzer::ANALYZER_TCPSTATS)) 0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_AYIYA, 5072/udp)) 0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_DCE_RPC, 135/tcp)) +0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_DHCP, 4011/udp)) 0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_DHCP, 67/udp)) 0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_DHCP, 68/udp)) 0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_DNP3_TCP, 20000/tcp)) @@ -844,6 +848,7 @@ 0.000000 MetaHookPre CallFunction(Analyzer::disable_analyzer, , (Analyzer::ANALYZER_TCPSTATS)) 0.000000 MetaHookPre CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_AYIYA, 5072/udp)) 0.000000 MetaHookPre CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_DCE_RPC, 135/tcp)) +0.000000 MetaHookPre CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_DHCP, 4011/udp)) 0.000000 MetaHookPre CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_DHCP, 67/udp)) 0.000000 MetaHookPre CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_DHCP, 68/udp)) 0.000000 MetaHookPre CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_DNP3_TCP, 20000/tcp)) @@ -1034,7 +1039,7 @@ 0.000000 MetaHookPre CallFunction(Log::__create_stream, , (Weird::LOG, [columns=, ev=Weird::log_weird, path=weird])) 0.000000 MetaHookPre CallFunction(Log::__create_stream, , (X509::LOG, [columns=, ev=X509::log_x509, path=x509])) 0.000000 MetaHookPre CallFunction(Log::__create_stream, , (mysql::LOG, [columns=, ev=MySQL::log_mysql, path=mysql])) -0.000000 MetaHookPre CallFunction(Log::__write, , (PacketFilter::LOG, [ts=1516211213.330468, node=bro, filter=ip or not ip, init=T, success=T])) +0.000000 MetaHookPre CallFunction(Log::__write, , (PacketFilter::LOG, [ts=1519920860.516463, node=bro, filter=ip or not ip, init=T, success=T])) 0.000000 MetaHookPre CallFunction(Log::add_default_filter, , (Cluster::LOG)) 0.000000 MetaHookPre CallFunction(Log::add_default_filter, , (Communication::LOG)) 0.000000 MetaHookPre CallFunction(Log::add_default_filter, , (Conn::LOG)) @@ -1207,7 +1212,7 @@ 0.000000 MetaHookPre CallFunction(Log::create_stream, , (Weird::LOG, [columns=, ev=Weird::log_weird, path=weird])) 0.000000 MetaHookPre CallFunction(Log::create_stream, , (X509::LOG, [columns=, ev=X509::log_x509, path=x509])) 0.000000 MetaHookPre CallFunction(Log::create_stream, , (mysql::LOG, [columns=, ev=MySQL::log_mysql, path=mysql])) -0.000000 MetaHookPre CallFunction(Log::write, , (PacketFilter::LOG, [ts=1516211213.330468, node=bro, filter=ip or not ip, init=T, success=T])) +0.000000 MetaHookPre CallFunction(Log::write, , (PacketFilter::LOG, [ts=1519920860.516463, node=bro, filter=ip or not ip, init=T, success=T])) 0.000000 MetaHookPre CallFunction(NetControl::check_plugins, , ()) 0.000000 MetaHookPre CallFunction(NetControl::init, , ()) 0.000000 MetaHookPre CallFunction(Notice::want_pp, , ()) @@ -1258,6 +1263,7 @@ 0.000000 MetaHookPre LoadFile(0, .<...>/Bro_DCE_RPC.events.bif.bro) 0.000000 MetaHookPre LoadFile(0, .<...>/Bro_DCE_RPC.types.bif.bro) 0.000000 MetaHookPre LoadFile(0, .<...>/Bro_DHCP.events.bif.bro) +0.000000 MetaHookPre LoadFile(0, .<...>/Bro_DHCP.types.bif.bro) 0.000000 MetaHookPre LoadFile(0, .<...>/Bro_DNP3.events.bif.bro) 0.000000 MetaHookPre LoadFile(0, .<...>/Bro_DNS.events.bif.bro) 0.000000 MetaHookPre LoadFile(0, .<...>/Bro_FTP.events.bif.bro) @@ -1560,6 +1566,7 @@ 0.000000 | HookCallFunction Analyzer::__disable_analyzer(Analyzer::ANALYZER_TCPSTATS) 0.000000 | HookCallFunction Analyzer::__register_for_port(Analyzer::ANALYZER_AYIYA, 5072/udp) 0.000000 | HookCallFunction Analyzer::__register_for_port(Analyzer::ANALYZER_DCE_RPC, 135/tcp) +0.000000 | HookCallFunction Analyzer::__register_for_port(Analyzer::ANALYZER_DHCP, 4011/udp) 0.000000 | HookCallFunction Analyzer::__register_for_port(Analyzer::ANALYZER_DHCP, 67/udp) 0.000000 | HookCallFunction Analyzer::__register_for_port(Analyzer::ANALYZER_DHCP, 68/udp) 0.000000 | HookCallFunction Analyzer::__register_for_port(Analyzer::ANALYZER_DNP3_TCP, 20000/tcp) @@ -1622,6 +1629,7 @@ 0.000000 | HookCallFunction Analyzer::disable_analyzer(Analyzer::ANALYZER_TCPSTATS) 0.000000 | HookCallFunction Analyzer::register_for_port(Analyzer::ANALYZER_AYIYA, 5072/udp) 0.000000 | HookCallFunction Analyzer::register_for_port(Analyzer::ANALYZER_DCE_RPC, 135/tcp) +0.000000 | HookCallFunction Analyzer::register_for_port(Analyzer::ANALYZER_DHCP, 4011/udp) 0.000000 | HookCallFunction Analyzer::register_for_port(Analyzer::ANALYZER_DHCP, 67/udp) 0.000000 | HookCallFunction Analyzer::register_for_port(Analyzer::ANALYZER_DHCP, 68/udp) 0.000000 | HookCallFunction Analyzer::register_for_port(Analyzer::ANALYZER_DNP3_TCP, 20000/tcp) @@ -1811,7 +1819,7 @@ 0.000000 | HookCallFunction Log::__create_stream(Weird::LOG, [columns=, ev=Weird::log_weird, path=weird]) 0.000000 | HookCallFunction Log::__create_stream(X509::LOG, [columns=, ev=X509::log_x509, path=x509]) 0.000000 | HookCallFunction Log::__create_stream(mysql::LOG, [columns=, ev=MySQL::log_mysql, path=mysql]) -0.000000 | HookCallFunction Log::__write(PacketFilter::LOG, [ts=1516211213.330468, node=bro, filter=ip or not ip, init=T, success=T]) +0.000000 | HookCallFunction Log::__write(PacketFilter::LOG, [ts=1519920860.516463, node=bro, filter=ip or not ip, init=T, success=T]) 0.000000 | HookCallFunction Log::add_default_filter(Cluster::LOG) 0.000000 | HookCallFunction Log::add_default_filter(Communication::LOG) 0.000000 | HookCallFunction Log::add_default_filter(Conn::LOG) @@ -1984,7 +1992,7 @@ 0.000000 | HookCallFunction Log::create_stream(Weird::LOG, [columns=, ev=Weird::log_weird, path=weird]) 0.000000 | HookCallFunction Log::create_stream(X509::LOG, [columns=, ev=X509::log_x509, path=x509]) 0.000000 | HookCallFunction Log::create_stream(mysql::LOG, [columns=, ev=MySQL::log_mysql, path=mysql]) -0.000000 | HookCallFunction Log::write(PacketFilter::LOG, [ts=1516211213.330468, node=bro, filter=ip or not ip, init=T, success=T]) +0.000000 | HookCallFunction Log::write(PacketFilter::LOG, [ts=1519920860.516463, node=bro, filter=ip or not ip, init=T, success=T]) 0.000000 | HookCallFunction NetControl::check_plugins() 0.000000 | HookCallFunction NetControl::init() 0.000000 | HookCallFunction Notice::want_pp() @@ -2035,6 +2043,7 @@ 0.000000 | HookLoadFile .<...>/Bro_DCE_RPC.events.bif.bro 0.000000 | HookLoadFile .<...>/Bro_DCE_RPC.types.bif.bro 0.000000 | HookLoadFile .<...>/Bro_DHCP.events.bif.bro +0.000000 | HookLoadFile .<...>/Bro_DHCP.types.bif.bro 0.000000 | HookLoadFile .<...>/Bro_DNP3.events.bif.bro 0.000000 | HookLoadFile .<...>/Bro_DNS.events.bif.bro 0.000000 | HookLoadFile .<...>/Bro_FTP.events.bif.bro @@ -2327,7 +2336,7 @@ 0.000000 | HookLoadFile base<...>/x509 0.000000 | HookLoadFile base<...>/xmpp 0.000000 | HookLogInit packet_filter 1/1 {ts (time), node (string), filter (string), init (bool), success (bool)} -0.000000 | HookLogWrite packet_filter [ts=1516211213.330468, node=bro, filter=ip or not ip, init=T, success=T] +0.000000 | HookLogWrite packet_filter [ts=1519920860.516463, node=bro, filter=ip or not ip, init=T, success=T] 0.000000 | HookQueueEvent NetControl::init() 0.000000 | HookQueueEvent bro_init() 0.000000 | HookQueueEvent filter_change_tracking() diff --git a/testing/btest/Baseline/scripts.base.protocols.dhcp.dhcp-ack-msg-types/dhcp.log b/testing/btest/Baseline/scripts.base.protocols.dhcp.dhcp-ack-msg-types/dhcp.log index 1edaec49ee..7131010acb 100644 --- a/testing/btest/Baseline/scripts.base.protocols.dhcp.dhcp-ack-msg-types/dhcp.log +++ b/testing/btest/Baseline/scripts.base.protocols.dhcp.dhcp-ack-msg-types/dhcp.log @@ -3,8 +3,8 @@ #empty_field (empty) #unset_field - #path dhcp -#open 2018-01-08-17-58-31 -#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p mac assigned_ip lease_time trans_id msg_type client_id server_id host_name subscriber_id agent_remote_id -#types time string addr port addr port string addr interval count string string addr string string string -1102274184.387798 CHhAvVGS1DHFjwGM9 10.10.0.10 68 10.10.0.1 67 00:0a:28:00:fa:42 192.168.0.10 3600.000000 15633 DHCP_ACK - 10.10.0.1 (empty) -subID- 13 -#close 2018-01-08-17-58-31 +#open 2018-03-01-15-18-30 +#fields ts uids client_addr server_addr mac host_name client_fqdn domain requested_addr assigned_addr lease_time client_message server_message msg_types duration +#types time set[string] addr addr string string string string addr addr interval string string vector[string] interval +1102274184.387798 CHhAvVGS1DHFjwGM9 192.168.0.10 10.10.0.1 00:0a:28:00:fa:42 - - - - 192.168.0.10 3600.000000 - - ACK 0.000000 +#close 2018-03-01-15-18-30 diff --git a/testing/btest/Baseline/scripts.base.protocols.dhcp.dhcp-all-msg-types/dhcp.log b/testing/btest/Baseline/scripts.base.protocols.dhcp.dhcp-all-msg-types/dhcp.log index 5f7aeee659..cf36777c6d 100644 --- a/testing/btest/Baseline/scripts.base.protocols.dhcp.dhcp-all-msg-types/dhcp.log +++ b/testing/btest/Baseline/scripts.base.protocols.dhcp.dhcp-all-msg-types/dhcp.log @@ -3,8 +3,10 @@ #empty_field (empty) #unset_field - #path dhcp -#open 2016-07-13-16-15-58 -#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p mac assigned_ip lease_time trans_id -#types time string addr port addr port string addr interval count -1370200444.371332 CtPZjS20MLrsMUOJi2 128.2.6.189 68 128.2.6.152 67 90:b1:1c:99:49:29 128.2.6.189 900.000000 1984 -#close 2016-07-13-16-15-58 +#open 2018-03-01-15-19-24 +#fields ts uids client_addr server_addr mac host_name client_fqdn domain requested_addr assigned_addr lease_time client_message server_message msg_types duration +#types time set[string] addr addr string string string string addr addr interval string string vector[string] interval +1370200447.422207 CHhAvVGS1DHFjwGM9 - - - btest.is.cool - - 128.2.6.189 - - - - INFORM 0.000000 +1370200442.323173 CtPZjS20MLrsMUOJi2,CHhAvVGS1DHFjwGM9,C4J4Th3PJpwUYZZ6gc,ClEkJM2Vm5giqnMf4h 128.2.6.97 128.2.6.152 90:b1:1c:99:49:29 btest.is.cool - cmu.edu 128.2.6.189 128.2.6.189 900.000000 - requested address not available DISCOVER,OFFER,REQUEST,NAK,REQUEST,ACK,DECLINE 3.058797 +1370200446.402928 CHhAvVGS1DHFjwGM9 - - - - - - - - - - - RELEASE 0.000000 +#close 2018-03-01-15-19-24 diff --git a/testing/btest/Baseline/scripts.base.protocols.dhcp.dhcp-discover-msg-types/dhcp.log b/testing/btest/Baseline/scripts.base.protocols.dhcp.dhcp-discover-msg-types/dhcp.log index 13e87b3855..48c6f36cf1 100644 --- a/testing/btest/Baseline/scripts.base.protocols.dhcp.dhcp-discover-msg-types/dhcp.log +++ b/testing/btest/Baseline/scripts.base.protocols.dhcp.dhcp-discover-msg-types/dhcp.log @@ -3,8 +3,8 @@ #empty_field (empty) #unset_field - #path dhcp -#open 2018-01-08-17-58-41 -#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p mac assigned_ip lease_time trans_id msg_type client_id server_id host_name subscriber_id agent_remote_id -#types time string addr port addr port string addr interval count string string addr string string string -1102274184.317453 CHhAvVGS1DHFjwGM9 0.0.0.0 68 255.255.255.255 67 - - - 15633 DHCP_DISCOVER 00:0b:82:01:fc:42 - test0000 - - -#close 2018-01-08-17-58-41 +#open 2018-03-01-15-30-31 +#fields ts uids client_addr server_addr mac host_name client_fqdn domain requested_addr assigned_addr lease_time client_message server_message msg_types duration +#types time set[string] addr addr string string string string addr addr interval string string vector[string] interval +1102274184.317453 CHhAvVGS1DHFjwGM9 - - 00:0b:82:01:fc:42 test0000 - - 208.67.222.222 - - - - DISCOVER 0.000000 +#close 2018-03-01-15-30-31 diff --git a/testing/btest/Baseline/scripts.base.protocols.dhcp.dhcp-sub-opts/dhcp.log b/testing/btest/Baseline/scripts.base.protocols.dhcp.dhcp-sub-opts/dhcp.log new file mode 100644 index 0000000000..5534459dd2 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.dhcp.dhcp-sub-opts/dhcp.log @@ -0,0 +1,10 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path dhcp +#open 2018-03-01-15-30-58 +#fields ts uids client_addr server_addr mac host_name client_fqdn domain requested_addr assigned_addr lease_time client_message server_message msg_types duration circuit_id agent_remote_id subscriber_id +#types time set[string] addr addr string string string string addr addr interval string string vector[string] interval string string string +1102274184.387798 CHhAvVGS1DHFjwGM9 192.168.0.10 10.10.0.1 00:0a:28:00:fa:42 - - - - 192.168.0.10 3600.000000 - - ACK 0.000000 this is only a test... \x13 -subID- +#close 2018-03-01-15-30-58 diff --git a/testing/btest/Baseline/scripts.base.protocols.dhcp.inform/dhcp.log b/testing/btest/Baseline/scripts.base.protocols.dhcp.inform/dhcp.log index 0a92c6c32d..ef1f5483ce 100644 --- a/testing/btest/Baseline/scripts.base.protocols.dhcp.inform/dhcp.log +++ b/testing/btest/Baseline/scripts.base.protocols.dhcp.inform/dhcp.log @@ -3,8 +3,8 @@ #empty_field (empty) #unset_field - #path dhcp -#open 2016-07-13-16-15-59 -#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p mac assigned_ip lease_time trans_id -#types time string addr port addr port string addr interval count -1374432420.191205 CHhAvVGS1DHFjwGM9 128.2.6.122 68 128.2.6.152 67 90:b1:1c:99:49:29 128.2.6.122 0.000000 2754407505 -#close 2016-07-13-16-15-59 +#open 2018-03-01-15-32-52 +#fields ts uids client_addr server_addr mac host_name client_fqdn domain requested_addr assigned_addr lease_time client_message server_message msg_types duration +#types time set[string] addr addr string string string string addr addr interval string string vector[string] interval +1374432420.186878 CHhAvVGS1DHFjwGM9 128.2.6.122 - 90:b1:1c:99:49:29 - - - - - - - - INFORM,ACK 0.004327 +#close 2018-03-01-15-32-52 diff --git a/testing/btest/Baseline/scripts.policy.protocols.dhcp.known-devices-and-hostnames.basic/known_devices.log b/testing/btest/Baseline/scripts.policy.protocols.dhcp.known-devices-and-hostnames.basic/known_devices.log deleted file mode 100644 index 91d37f8950..0000000000 --- a/testing/btest/Baseline/scripts.policy.protocols.dhcp.known-devices-and-hostnames.basic/known_devices.log +++ /dev/null @@ -1,11 +0,0 @@ -#separator \x09 -#set_separator , -#empty_field (empty) -#unset_field - -#path known_devices -#open 2013-07-31-21-27-41 -#fields ts mac dhcp_host_name -#types time string string -1370200443.344965 90:b1:1c:99:49:29 btest.is.cool -1374432420.186878 90:b1:1c:99:49:29 (empty) -#close 2013-07-31-21-27-41 diff --git a/testing/btest/scripts/base/protocols/dhcp/dhcp-sub-opts.btest b/testing/btest/scripts/base/protocols/dhcp/dhcp-sub-opts.btest new file mode 100644 index 0000000000..3bd37a996b --- /dev/null +++ b/testing/btest/scripts/base/protocols/dhcp/dhcp-sub-opts.btest @@ -0,0 +1,2 @@ +# @TEST-EXEC: bro -r $TRACES/dhcp/dhcp_ack_subscriber_id_and_agent_remote_id.trace %INPUT protocols/dhcp/sub-opts +# @TEST-EXEC: btest-diff dhcp.log diff --git a/testing/btest/scripts/policy/protocols/dhcp/known-devices-and-hostnames/basic.test b/testing/btest/scripts/policy/protocols/dhcp/known-devices-and-hostnames/basic.test deleted file mode 100644 index 1144ae1377..0000000000 --- a/testing/btest/scripts/policy/protocols/dhcp/known-devices-and-hostnames/basic.test +++ /dev/null @@ -1,8 +0,0 @@ -# This tests that the known_devices log is created, -# that devices are logged by MAC address, and that -# the DHCP hostname is added, if available. - -# @TEST-EXEC: bro -r $TRACES/dhcp/dhcp.trace -r $TRACES/dhcp/dhcp_inform.trace %INPUT -# @TEST-EXEC: btest-diff known_devices.log - -@load policy/protocols/dhcp/known-devices-and-hostnames