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.
This commit is contained in:
Seth Hall 2018-02-02 10:14:15 -05:00
parent ba49ab8201
commit c2f35920fd
14 changed files with 728 additions and 498 deletions

View file

@ -3064,11 +3064,12 @@ export {
## A list of router addresses offered by a DHCP server. ## A list of router addresses offered by a DHCP server.
## ##
## .. bro:see:: dhcp_ack dhcp_offer ## .. 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. ## A DHCP message.
## .. bro:see:: dhcp_ack dhcp_decline dhcp_discover dhcp_inform dhcp_nak ## .. bro:see:: dhcp_ack dhcp_decline dhcp_discover dhcp_inform dhcp_nak
## dhcp_offer dhcp_release dhcp_request ## dhcp_offer dhcp_release dhcp_request
type DHCP::dhcp_msg: record { type DHCP::Msg: record {
op: count; ##< Message OP code. 1 = BOOTREQUEST, 2 = BOOTREPLY op: count; ##< Message OP code. 1 = BOOTREQUEST, 2 = BOOTREPLY
m_type: count; ##< The type of DHCP message. m_type: count; ##< The type of DHCP message.
xid: count; ##< Transaction ID of a DHCP session. xid: count; ##< Transaction ID of a DHCP session.
@ -3076,22 +3077,55 @@ export {
ciaddr: addr; ##< Original IP address of the client. ciaddr: addr; ##< Original IP address of the client.
yiaddr: addr; ##< IP address assigned to 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 ## .. 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) ## DHCP Relay Agent Information Option (Option 82)
## .. bro:see:: dhcp_ack ## .. bro:see:: dhcp_ack
type DHCP::dhcp_sub_opt: record { type DHCP::SubOpt: record {
code: count; code: count;
value: string; value: string;
}; };
## DHCP Client Identifier (Option 61) ## DHCP Client Identifier (Option 61)
## .. bro:see:: dhcp_request dhcp_discover ## .. bro:see:: dhcp_request dhcp_discover
type DHCP::dhcp_client_id: record { type DHCP::ClientID: record {
hwtype: count; hwtype: count;
hwaddr: string; 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; module GLOBAL;

View file

@ -15,6 +15,16 @@ export {
[6] = "DHCP_NAK", [6] = "DHCP_NAK",
[7] = "DHCP_RELEASE", [7] = "DHCP_RELEASE",
[8] = "DHCP_INFORM", [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); }; } &default = function(n: count): string { return fmt("unknown-message-type-%d", n); };
} }

View file

@ -59,26 +59,20 @@ redef record connection += {
const ports = { 67/udp, 68/udp }; const ports = { 67/udp, 68/udp };
redef likely_server_ports += { 67/udp }; redef likely_server_ports += { 67/udp };
global info: Info;
event bro_init() &priority=5 event bro_init() &priority=5
{ {
Log::create_stream(DHCP::LOG, [$columns=Info, $ev=log_dhcp, $path="dhcp"]); Log::create_stream(DHCP::LOG, [$columns=Info, $ev=log_dhcp, $path="dhcp"]);
Analyzer::register_for_ports(Analyzer::ANALYZER_DHCP, ports); 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; if ( msg$m_type == 5 ) # DHCP_ACK
info$ts = network_time(); {
info$id = c$id; local info = Info($ts = network_time(),
info$uid = c$uid; $id = c$id,
info$lease_time = lease; $uid = c$uid,
info$trans_id = msg$xid; $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 != "" ) if ( msg$h_addr != "" )
info$mac = msg$h_addr; info$mac = msg$h_addr;
@ -88,62 +82,37 @@ event dhcp_ack(c: connection, msg: dhcp_msg, mask: addr, router: dhcp_router_lis
else else
info$assigned_ip = c$id$orig_h; info$assigned_ip = c$id$orig_h;
for (param in sub_opt) if ( options?$lease )
info$lease_time = options$lease;
if ( options?$sub_opt )
{ {
#if ( sub_opt[param]$code == 1 ) 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("Relay Agent Information:");
#print fmt( "sub option: code=%d circuit id=%s",sub_opt[param]$code,sub_opt[param]$value ); # print fmt( "sub option: code=%d circuit id=%s",sub_opt$code,sub_opt$value );
# } # }
if ( sub_opt[param]$code == 2 )
info$agent_remote_id = bytestring_to_hexstr(sub_opt[param]$value);
if ( sub_opt[param]$code == 6 ) if ( sub_opt$code == 2 )
info$subscriber_id = (sub_opt[param]$value); 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
{
if ( msg$m_type == 5 ) # DHCP_ACK
{ {
Log::write(DHCP::LOG, c$dhcp); 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);
}

View file

@ -110,9 +110,6 @@ RecordType* geo_location;
RecordType* entropy_test_result; RecordType* entropy_test_result;
TableType* dhcp_router_list;
RecordType* dhcp_msg;
RecordType* dns_msg; RecordType* dns_msg;
RecordType* dns_answer; RecordType* dns_answer;
RecordType* dns_soa; RecordType* dns_soa;
@ -426,9 +423,6 @@ void init_net_var()
entropy_test_result = internal_type("entropy_test_result")->AsRecordType(); 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_msg = internal_type("dns_msg")->AsRecordType();
dns_answer = internal_type("dns_answer")->AsRecordType(); dns_answer = internal_type("dns_answer")->AsRecordType();
dns_soa = internal_type("dns_soa")->AsRecordType(); dns_soa = internal_type("dns_soa")->AsRecordType();

View file

@ -113,9 +113,6 @@ extern RecordType* geo_location;
extern RecordType* entropy_test_result; extern RecordType* entropy_test_result;
extern TableType* dhcp_router_list;
extern RecordType* dhcp_msg;
extern RecordType* dns_msg; extern RecordType* dns_msg;
extern RecordType* dns_answer; extern RecordType* dns_answer;
extern RecordType* dns_soa; extern RecordType* dns_soa;

View file

@ -7,5 +7,5 @@ bro_plugin_begin(Bro DHCP)
bro_plugin_cc(DHCP.cc Plugin.cc) bro_plugin_cc(DHCP.cc Plugin.cc)
bro_plugin_bif(events.bif) bro_plugin_bif(events.bif)
bro_plugin_bif(types.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() bro_plugin_end()

View file

@ -25,5 +25,14 @@ void DHCP_Analyzer::DeliverPacket(int len, const u_char* data,
bool orig, uint64 seq, const IP_Hdr* ip, int caplen) bool orig, uint64 seq, const IP_Hdr* ip, int caplen)
{ {
Analyzer::DeliverPacket(len, data, orig, seq, ip, caplen); Analyzer::DeliverPacket(len, data, orig, seq, ip, caplen);
try
{
interp->NewData(orig, data, data + len); interp->NewData(orig, data, data + len);
} }
catch ( const binpac::Exception& e )
{
ProtocolViolation(fmt("Binpac exception: %s", e.c_msg()));
}
}

View file

@ -10,11 +10,11 @@ namespace analyzer { namespace dhcp {
class DHCP_Analyzer : public analyzer::Analyzer { class DHCP_Analyzer : public analyzer::Analyzer {
public: public:
DHCP_Analyzer(Connection* conn); DHCP_Analyzer(Connection* conn);
virtual ~DHCP_Analyzer(); ~DHCP_Analyzer() override;
virtual void Done(); void Done() override;
virtual void DeliverPacket(int len, const u_char* data, bool orig, void DeliverPacket(int len, const u_char* data, bool orig,
uint64 seq, const IP_Hdr* ip, int caplen); uint64 seq, const IP_Hdr* ip, int caplen) override;
static analyzer::Analyzer* Instantiate(Connection* conn) static analyzer::Analyzer* Instantiate(Connection* conn)
{ return new DHCP_Analyzer(conn); } { return new DHCP_Analyzer(conn); }

View file

@ -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{ %member{
BroVal dhcp_msg_val_; RecordVal *dhcp_msg_val;
uint8 sum_len; RecordVal *options;
%} %}
%init{ %init{
dhcp_msg_val_ = 0; dhcp_msg_val = 0;
sum_len = 0; options = 0;
%} %}
%cleanup{ %cleanup{
Unref(dhcp_msg_val_); Unref(dhcp_msg_val);
dhcp_msg_val_ = 0; dhcp_msg_val = 0;
sum_len = 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; // // Requested IP address to the server.
return sum_len; // ::uint32 req_addr = 0, serv_addr = 0;
%} // StringVal* host_name = new StringVal("");
//
function get_dhcp_msgtype(options: DHCP_Option[]): uint8 // TableVal* params_list = 0;
%{ // RecordVal* client_id = new RecordVal(BifType::Record::DHCP::ClientID);
vector<DHCP_Option*>::const_iterator ptr; // client_id->Assign(0,0);
uint8 type = 0; // client_id->Assign(1,new StringVal(""));
//
// Leave the for loop if the message type is found. // switch ( type )
bool parsed = false; // {
// case DHCPDISCOVER:
for ( ptr = options->begin(); // BifEvent::generate_dhcp_discover(connection()->bro_analyzer(),
ptr != options->end() && ! (*ptr)->last(); ++ptr ) // connection()->bro_analyzer()->Conn(),
{ // dhcp_msg_val->Ref(), new AddrVal(req_addr),
// We use a switch for future expandability. // host_name, client_id, params_list);
switch ( (*ptr)->code() ) { // break;
case MSG_TYPE_OPTION: //
type = (*ptr)->info()->msg_type(); // case DHCPREQUEST:
parsed = true; // BifEvent::generate_dhcp_request(connection()->bro_analyzer(),
break; // connection()->bro_analyzer()->Conn(),
} // dhcp_msg_val->Ref(), new AddrVal(req_addr),
// new AddrVal(serv_addr), host_name, client_id, params_list);
if ( parsed ) // break;
break; //
} // case DHCPDECLINE:
// BifEvent::generate_dhcp_decline(connection()->bro_analyzer(),
if ( type == 0 ) // connection()->bro_analyzer()->Conn(),
connection()->bro_analyzer()->ProtocolViolation("no DHCP message type option"); // dhcp_msg_val->Ref(), host_name);
// break;
return type; //
%} // case DHCPRELEASE:
// BifEvent::generate_dhcp_release(connection()->bro_analyzer(),
function parse_request(options: DHCP_Option[], type: uint8): bool // connection()->bro_analyzer()->Conn(),
%{ // dhcp_msg_val->Ref(), host_name);
vector<DHCP_Option*>::const_iterator ptr; // break;
//
// Requested IP address to the server. // case DHCPINFORM:
::uint32 req_addr = 0, serv_addr = 0; // BifEvent::generate_dhcp_inform(connection()->bro_analyzer(),
StringVal* host_name = new StringVal(""); // connection()->bro_analyzer()->Conn(),
// dhcp_msg_val->Ref(), host_name, params_list);
TableVal* params_list = 0; // break;
RecordVal* client_id = new RecordVal(BifType::Record::DHCP::dhcp_client_id); //
client_id->Assign(0,0); // default:
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<uint8>* 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;
}
return true;
%}
function parse_reply(options: DHCP_Option[], type: uint8): bool
%{
vector<DHCP_Option*>::const_iterator ptr;
vector<Relay_Agent_SubOption*>::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::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<uint32>* 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); // Unref(host_name);
break; // break;
} // }
return true; 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
%{
if ( options == nullptr )
options = new RecordVal(BifType::Record::DHCP::Options);
return true;
%} %}
function process_dhcp_message(msg: DHCP_Message): bool function process_dhcp_message(msg: DHCP_Message): bool
@ -292,55 +148,81 @@ flow DHCP_Flow(is_orig: bool) {
return false; return false;
} }
Unref(dhcp_msg_val_); Unref(dhcp_msg_val);
std::string mac_str = fmt_mac(${msg.chaddr}.data(), ${msg.chaddr}.length()); std::string mac_str = fmt_mac(${msg.chaddr}.data(), ${msg.chaddr}.length());
RecordVal* r = new RecordVal(dhcp_msg); dhcp_msg_val = new RecordVal(BifType::Record::DHCP::Msg);
r->Assign(0, new Val(${msg.op}, TYPE_COUNT)); dhcp_msg_val->Assign(0, new Val(${msg.op}, TYPE_COUNT));
r->Assign(1, new Val(${msg.type}, TYPE_COUNT)); dhcp_msg_val->Assign(1, new Val(${msg.type}, TYPE_COUNT));
r->Assign(2, new Val(${msg.xid}, TYPE_COUNT)); dhcp_msg_val->Assign(2, new Val(${msg.xid}, TYPE_COUNT));
r->Assign(3, new StringVal(mac_str)); dhcp_msg_val->Assign(3, new StringVal(mac_str));
r->Assign(4, new AddrVal(${msg.ciaddr})); dhcp_msg_val->Assign(4, new AddrVal(${msg.ciaddr}));
r->Assign(5, new AddrVal(${msg.yiaddr})); 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} ) Unref(dhcp_msg_val);
{ dhcp_msg_val = 0;
case BOOTREQUEST: // presumably from client to server Unref(options);
if ( ${msg.type} == DHCPDISCOVER || options = 0;
${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 //switch ( ${msg.op} )
if ( ${msg.type} == DHCPOFFER || // {
${msg.type} == DHCPACK || // case BOOTREQUEST: // presumably from client to server
${msg.type} == DHCPNAK || // if ( ${msg.type} == DHCPDISCOVER ||
${msg.type} == DHCPLEASEUNASSIGNED || // ${msg.type} == DHCPREQUEST ||
${msg.type} == DHCPLEASEUNKNOWN || // ${msg.type} == DHCPDECLINE ||
${msg.type} == DHCPLEASEACTIVE ) // ${msg.type} == DHCPRELEASE ||
parse_reply(${msg.options}, ${msg.type}); // ${msg.type} == DHCPINFORM )
else // {
connection()->bro_analyzer()->ProtocolViolation(fmt("unknown DHCP message type option for BOOTREPLY (%d)", // parse_request(${msg.options}, ${msg.type});
${msg.type})); // }
// else
break; // {
// connection()->bro_analyzer()->ProtocolViolation(fmt("unknown DHCP message type option for BOOTREQUEST (%d)",
default: // ${msg.type}));
connection()->bro_analyzer()->ProtocolViolation(fmt("unknown DHCP message op code (%d). Known codes: 1=BOOTREQUEST, 2=BOOTREPLY", // }
${msg.op})); // break;
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(); connection()->bro_analyzer()->ProtocolConfirmation();
return true; return true;
%} %}
}; };
@ -348,3 +230,8 @@ flow DHCP_Flow(is_orig: bool) {
refine typeattr DHCP_Message += &let { refine typeattr DHCP_Message += &let {
proc_dhcp_message = $context.flow.process_dhcp_message(this); proc_dhcp_message = $context.flow.process_dhcp_message(this);
}; };
refine typeattr Option += &let {
proc_create_options = $context.flow.create_options();
};

View file

@ -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<uint32>* 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<double>(${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<uint8>* 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<double>(${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<double>(${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);
};

View file

@ -6,24 +6,7 @@ enum OP_type {
BOOTREPLY = 2 BOOTREPLY = 2
}; };
# Refer to RFC 1533 for option types. let MSG_TYPE_OPTION = 53;
# 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
};
enum DHCP_message_type { enum DHCP_message_type {
DHCPDISCOVER = 1, DHCPDISCOVER = 1,
@ -41,56 +24,24 @@ enum DHCP_message_type {
DHCPLEASEACTIVE = 13 # RFC 4388 DHCPLEASEACTIVE = 13 # RFC 4388
}; };
type Relay_Agent_SubOption(tot_len: uint8) = record { type OptionValue(code: uint8, length: uint8) = case code of {
code : uint8; # This is extended in dhcp-options.pac
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; 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; default -> other : bytestring &length = length;
}; };
};
type DHCP_Option = record { type Option = record {
code : uint8; code : uint8;
length : uint8;
data : case code of { data : case code of {
0, 255 -> none : empty; 0, 255 -> none : empty;
default -> info : Option_Info(code); default -> info : OptionValue(code, length);
}; };
} &let { } &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 { type DHCP_Message(is_orig: bool) = record {
op : uint8; op : uint8;
htype : uint8; htype : uint8;
hlen : uint8; hlen : uint8;
@ -108,7 +59,47 @@ type DHCP_Message = record {
# Cookie belongs to options in RFC 2131, but we separate # Cookie belongs to options in RFC 2131, but we separate
# them here for easy parsing. # them here for easy parsing.
cookie : uint32; cookie : uint32;
options : DHCP_Option[] &until($element.last); options : Option[] &until($element.last);
} &let { } &let {
type : uint8 = $context.flow.get_dhcp_msgtype(options); type = $context.flow.get_dhcp_msgtype(options);
} &byteorder = bigendian; } &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;
%}
};

View file

@ -11,5 +11,15 @@ analyzer DHCP withcontext {
flow: DHCP_Flow; 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-protocol.pac
%include dhcp-analyzer.pac %include dhcp-analyzer.pac
%include dhcp-options.pac

View file

@ -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 ## Generated for DHCP messages of type *DHCPDISCOVER* (client broadcast to locate
## available servers). ## available servers).
## ##
@ -20,7 +23,7 @@
## protocol). It treats broadcast addresses just like any other and ## protocol). It treats broadcast addresses just like any other and
## associates packets into transport-level flows in the same way as usual. ## 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 ## Generated for DHCP messages of type *DHCPOFFER* (server to client in response
## to DHCPDISCOVER with offer of configuration parameters). ## 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 ## protocol). It treats broadcast addresses just like any other and
## associates packets into transport-level flows in the same way as usual. ## 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 ## Generated for DHCP messages of type *DHCPREQUEST* (Client message to servers either
## (a) requesting offered parameters from one server and implicitly declining offers ## (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 ## protocol). It treats broadcast addresses just like any other and
## associates packets into transport-level flows in the same way as usual. ## 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 ## Generated for DHCP messages of type *DHCPDECLINE* (Client to server indicating
## network address is already in use). ## 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 ## protocol). It treats broadcast addresses just like any other and
## associates packets into transport-level flows in the same way as usual. ## 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 ## Generated for DHCP messages of type *DHCPACK* (Server to client with configuration
## parameters, including committed network address). ## 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 ## .. bro:see:: dhcp_discover dhcp_offer dhcp_request dhcp_decline dhcp_nak
## dhcp_release dhcp_inform ## 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 ## 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 ## 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 ## protocol). It treats broadcast addresses just like any other and
## associates packets into transport-level flows in the same way as usual. ## 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 ## Generated for DHCP messages of type *DHCPRELEASE* (Client to server relinquishing
## network address and cancelling remaining lease). ## 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 ## .. bro:see:: dhcp_discover dhcp_offer dhcp_request dhcp_decline dhcp_ack dhcp_nak
## dhcp_inform ## 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 ## Generated for DHCP messages of type *DHCPINFORM* (Client to server, asking only for
## local configuration parameters; client already has externally configured network ## 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 ## protocol). It treats broadcast addresses just like any other and
## associates packets into transport-level flows in the same way as usual. ## 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%);

View file

@ -1,10 +1,9 @@
module DHCP; module DHCP;
type dhcp_msg: record; type Msg: record;
type dhcp_router_list: table; type RouterList: table;
type dhcp_params_list: table; type ParamsList: table;
type dhcp_sub_opt_list: table; type SubOptList: table;
type dhcp_sub_opt: record; type SubOpt: record;
type dhcp_client_id: record; type ClientID: record;
type Options: record;
module GLOBAL;