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; 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 0000000000..b5e72d4735 Binary files /dev/null and b/testing/btest/Traces/dhcp/dhcp_ack_subscriber_id_and_agent_remote_id.trace differ 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 0000000000..bfdbb54c01 Binary files /dev/null and b/testing/btest/Traces/dhcp/dhcp_discover_param_req_and_client_id.trace differ 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