Rework the DHCP analyzer to make it compatible again.

This commit is contained in:
Vlad Grigorescu 2013-07-18 21:17:06 -04:00
parent 7838113dc2
commit deeb5ec38e
14 changed files with 623 additions and 275 deletions

View file

@ -36,6 +36,7 @@
@load base/frameworks/tunnels @load base/frameworks/tunnels
@load base/protocols/conn @load base/protocols/conn
@load base/protocols/dhcp
@load base/protocols/dns @load base/protocols/dns
@load base/protocols/ftp @load base/protocols/ftp
@load base/protocols/http @load base/protocols/http

View file

@ -0,0 +1,2 @@
@load ./consts
@load ./main

View file

@ -0,0 +1,20 @@
##! Types, errors, and fields for analyzing DHCP data. A helper file
##! for DHCP analysis scripts.
module DHCP;
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",
} &default = function(n: count): string { return fmt("unknown-message-type-%d", n); };
}

View file

@ -0,0 +1,74 @@
##! 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.
##!
##! To enable further analysis and log output for DHCP, see the optional
##! scripts in the policy/protocols/dhcp directory.
@load ./utils.bro
module DHCP;
export {
redef enum Log::ID += { LOG };
## The record type which contains the column fields of the DHCP log.
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
## occuring.
uid: string &log;
## The connection's 4-tuple of endpoint addresses/ports.
id: conn_id &log;
## Client's hardware address.
mac: string &log &optional;
## Client's actual assigned IP address.
assigned_ip: addr &log &optional;
## IP address lease interval.
lease_time: interval &log &optional;
## A random number choosen by the client for this transaction.
trans_id: count &log;
};
## 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);
}
# Add the dhcp info to the connection record
redef record connection += {
dhcp: Info &optional;
};
const ports = { 67/udp, 68/udp };
redef likely_server_ports += { 67/udp };
event bro_init() &priority=5
{
Log::create_stream(DHCP::LOG, [$columns=Info, $ev=log_dhcp]);
Analyzer::register_for_ports(Analyzer::ANALYZER_DHCP, ports);
}
event dhcp_ack(c: connection, msg: dhcp_msg, mask: addr, router: dhcp_router_list, lease: interval, serv_addr: addr, host_name: string) &priority=5
{
local info: Info;
info$ts = network_time();
info$id = c$id;
info$uid = c$uid;
info$assigned_ip = reverse_ip(msg$yiaddr);
info$lease_time = lease;
info$trans_id = msg$xid;
if ( msg$h_addr != "" )
info$mac = msg$h_addr;
c$dhcp = info;
}
# We let policy scripts add stuff too, so we run this at a lower priority
event dhcp_ack(c: connection, msg: dhcp_msg, mask: addr, router: dhcp_router_list, lease: interval, serv_addr: addr, host_name: string) &priority=1
{
Log::write(DHCP::LOG, c$dhcp);
}

View file

@ -0,0 +1,21 @@
##! Utilities specific for DHCP processing.
@load ./main
module DHCP;
export {
## Reverse the octets of an IPv4 IP.
##
## ip: An :bro:type:`addr` IPv4 address.
##
## Returns: A reversed addr.
global reverse_ip: function(ip: addr): addr;
}
function reverse_ip(ip: addr): addr
{
local octets = split(cat(ip), /\./);
return to_addr(cat(octets[4], ".", octets[3], ".", octets[2], ".", octets[1]));
}

View file

@ -0,0 +1,256 @@
##! Handlers for DHCP message types other than DHCPACK, which is handled in base/protocols/dhcp.
##! For networks that wish to get more details from their DHCP logs, at the expense
##! of a significantly higher log rate.
@load base/protocols/dhcp
module DHCP;
export {
redef record Info += {
## The value of the host name option, if seen
host_name: string &log &optional;
## The IP requested by the client, if any
requested_ip: addr &log &optional;
## The type of the DHCP message (DHCPOFFER, DHCPRELEASE, etc.)
msg_type: string &log &optional;
};
#### Enabled by default
## A boolean value to determine if DHCPREQUEST messages are logged.
## Often useful to see client activity, and because host_name is often available.
const log_dhcprequest = T &redef;
## A boolean value to determine if DHCPDECLINE messages are logged.
## A client declines a lease if it detects that the IP is already in use (usually via ARP).
const log_dhcpdecline = T &redef;
## A boolean value to determine if DHCPNAK messages are logged.
## A server issues a DHCPNAK if a client DHCPREQUEST is invalid.
const log_dhcpnak = T &redef;
## A boolean value to determine if DHCPRELEASE messages are logged.
## A client issues a DHCPRELEASE when it no longer needs the lease (e.g. it's shutting down).
const log_dhcprelease = T &redef;
#### Not enabled by default
## A boolean value to determine if DHCPOFFER messages are logged.
## Used to profile server -> client communication.
const log_dhcpoffer = F &redef;
## A boolean value to determine if DHCPDISCOVER messages are logged.
## Used to profile broadcast client discovery requests.
const log_dhcpdiscover = F &redef;
## A boolean value to determine if DHCPINFORM messages are logged.
## Used to profile clients attempting to request/renew specific IPs.
const log_dhcpinform = F &redef;
}
event dhcp_offer(c: connection, msg: dhcp_msg, mask: addr, router: dhcp_router_list, lease: interval, serv_addr: addr, host_name: string) &priority=5
{
if ( ! log_dhcpoffer )
return;
local info: Info;
info$ts = network_time();
info$id = c$id;
info$uid = c$uid;
info$assigned_ip = reverse_ip(msg$yiaddr);
info$lease_time = lease;
info$trans_id = msg$xid;
info$msg_type = "DHCPOFFER";
if ( msg$h_addr != "" )
info$mac = msg$h_addr;
if ( host_name != "" )
info$host_name = host_name;
c$dhcp = info;
}
event dhcp_discover(c: connection, msg: dhcp_msg, req_addr: addr, host_name: string) &priority=5
{
if ( ! log_dhcpdiscover )
return;
local info: Info;
info$ts = network_time();
info$id = c$id;
info$uid = c$uid;
info$requested_ip = req_addr;
info$trans_id = msg$xid;
info$msg_type = "DHCPDISCOVER";
if ( msg$h_addr != "" )
info$mac = msg$h_addr;
if ( host_name != "" )
info$host_name = host_name;
c$dhcp = info;
}
event dhcp_request(c: connection, msg: dhcp_msg, req_addr: addr, serv_addr: addr, host_name: string) &priority=5
{
if ( ! log_dhcprequest )
return;
local info: Info;
info$ts = network_time();
info$id = c$id;
info$uid = c$uid;
info$requested_ip = req_addr;
info$trans_id = msg$xid;
info$msg_type = "DHCPREQUEST";
if ( msg$h_addr != "" )
info$mac = msg$h_addr;
if ( host_name != "" )
info$host_name = host_name;
c$dhcp = info;
}
event dhcp_decline(c: connection, msg: dhcp_msg, host_name: string) &priority=5
{
if ( ! log_dhcpdecline )
return;
local info: Info;
info$ts = network_time();
info$id = c$id;
info$uid = c$uid;
info$trans_id = msg$xid;
info$msg_type = "DHCPDECLINE";
if ( msg$h_addr != "" )
info$mac = msg$h_addr;
if ( host_name != "" )
info$host_name = host_name;
c$dhcp = info;
}
event dhcp_nak(c: connection, msg: dhcp_msg, host_name: string) &priority=5
{
if ( ! log_dhcpnak )
return;
local info: Info;
info$ts = network_time();
info$id = c$id;
info$uid = c$uid;
info$trans_id = msg$xid;
info$msg_type = "DHCPNAK";
if ( msg$h_addr != "" )
info$mac = msg$h_addr;
if ( host_name != "" )
info$host_name = host_name;
c$dhcp = info;
}
event dhcp_release(c: connection, msg: dhcp_msg, host_name: string) &priority=5
{
if ( ! log_dhcprelease )
return;
local info: Info;
info$ts = network_time();
info$id = c$id;
info$uid = c$uid;
info$trans_id = msg$xid;
info$msg_type = "DHCPRELEASE";
if ( msg$h_addr != "" )
info$mac = msg$h_addr;
if ( host_name != "" )
info$host_name = host_name;
c$dhcp = info;
}
event dhcp_inform(c: connection, msg: dhcp_msg, host_name: string) &priority=5
{
if ( ! log_dhcpinform )
return;
local info: Info;
info$ts = network_time();
info$id = c$id;
info$uid = c$uid;
info$trans_id = msg$xid;
info$msg_type = "DHCPINFORM";
if ( msg$h_addr != "" )
info$mac = msg$h_addr;
if ( host_name != "" )
info$host_name = host_name;
c$dhcp = info;
}
event dhcp_ack(c: connection, msg: dhcp_msg, mask: addr, router: dhcp_router_list, lease: interval, serv_addr: addr, host_name: string) &priority=4
{
## For the sake of consistency, let's add msg_type to DHCPACK as well.
c$dhcp$msg_type = "DHCPACK";
## host_name is generally not in ACKs, but let's check anyway.
if ( host_name != "" )
c$dhcp$host_name = host_name;
}
#### We log stuff at a lower priority, in case any other scripts would like to extend the Info record first.
event dhcp_offer(c: connection, msg: dhcp_msg, mask: addr, router: dhcp_router_list, lease: interval, serv_addr: addr, host_name: string) &priority=1
{
if ( log_dhcpoffer )
Log::write(DHCP::LOG, c$dhcp);
}
event dhcp_discover(c: connection, msg: dhcp_msg, req_addr: addr, host_name: string) &priority=1
{
if ( log_dhcpdiscover )
Log::write(DHCP::LOG, c$dhcp);
}
event dhcp_request(c: connection, msg: dhcp_msg, req_addr: addr, serv_addr: addr, host_name: string) &priority=1
{
if ( log_dhcprequest )
Log::write(DHCP::LOG, c$dhcp);
}
event dhcp_decline(c: connection, msg: dhcp_msg, host_name: string) &priority=1
{
if ( log_dhcpdecline )
Log::write(DHCP::LOG, c$dhcp);
}
event dhcp_nak(c: connection, msg: dhcp_msg, host_name: string) &priority=1
{
if ( log_dhcpnak )
Log::write(DHCP::LOG, c$dhcp);
}
event dhcp_release(c: connection, msg: dhcp_msg, host_name: string) &priority=1
{
if ( log_dhcprelease )
Log::write(DHCP::LOG, c$dhcp);
}
event dhcp_inform(c: connection, msg: dhcp_msg, host_name: string) &priority=1
{
if ( log_dhcpinform )
Log::write(DHCP::LOG, c$dhcp);
}

View file

@ -1,4 +1,3 @@
#include "DHCP.h" #include "DHCP.h"
#include "events.bif.h" #include "events.bif.h"

View file

@ -19,6 +19,9 @@ public:
static analyzer::Analyzer* InstantiateAnalyzer(Connection* conn) static analyzer::Analyzer* InstantiateAnalyzer(Connection* conn)
{ return new DHCP_Analyzer(conn); } { return new DHCP_Analyzer(conn); }
static bool Available()
{ return dhcp_discover || dhcp_offer || dhcp_request || dhcp_decline || dhcp_ack || dhcp_nak || dhcp_release || dhcp_inform; }
protected: protected:
binpac::DHCP::DHCP_Conn* interp; binpac::DHCP::DHCP_Conn* interp;
}; };

View file

@ -8,12 +8,10 @@ flow DHCP_Flow(is_orig: bool) {
%member{ %member{
BroVal dhcp_msg_val_; BroVal dhcp_msg_val_;
BroAnalyzer interp;
%} %}
%init{ %init{
dhcp_msg_val_ = 0; dhcp_msg_val_ = 0;
interp = connection->bro_analyzer();
%} %}
%cleanup{ %cleanup{
@ -45,7 +43,7 @@ flow DHCP_Flow(is_orig: bool) {
} }
if ( type == 0 ) if ( type == 0 )
interp->Weird("DHCP_no_type_option"); connection()->bro_analyzer()->ProtocolViolation("no DHCP message type option");
return type; return type;
%} %}
@ -56,54 +54,63 @@ flow DHCP_Flow(is_orig: bool) {
// Requested IP address to the server. // Requested IP address to the server.
::uint32 req_addr = 0, serv_addr = 0; ::uint32 req_addr = 0, serv_addr = 0;
StringVal* host_name = 0;
for ( ptr = options->begin(); for ( ptr = options->begin(); ptr != options->end() && ! (*ptr)->last(); ++ptr )
ptr != options->end() && ! (*ptr)->last(); ++ptr )
{ {
switch ( (*ptr)->code() ) { switch ( (*ptr)->code() )
case REQ_IP_OPTION: {
req_addr = htonl((*ptr)->info()->req_addr()); case REQ_IP_OPTION:
break; req_addr = htonl((*ptr)->info()->req_addr());
break;
case SERV_ID_OPTION: case SERV_ID_OPTION:
serv_addr = htonl((*ptr)->info()->serv_addr()); serv_addr = htonl((*ptr)->info()->serv_addr());
break; break;
}
case HOST_NAME_OPTION:
host_name = new StringVal((*ptr)->info()->host_name().length(),
(const char*) (*ptr)->info()->host_name().begin());
break;
}
} }
if ( host_name == 0 )
host_name = new StringVal("");
switch ( type ) switch ( type )
{ {
case DHCPDISCOVER: case DHCPDISCOVER:
BifEvent::generate_dhcp_discover(connection()->bro_analyzer(), BifEvent::generate_dhcp_discover(connection()->bro_analyzer(),
connection()->bro_analyzer()->Conn(), connection()->bro_analyzer()->Conn(),
dhcp_msg_val_->Ref(), new AddrVal(req_addr)); dhcp_msg_val_->Ref(), new AddrVal(req_addr), host_name);
break; break;
case DHCPREQUEST: case DHCPREQUEST:
BifEvent::generate_dhcp_request(connection()->bro_analyzer(), BifEvent::generate_dhcp_request(connection()->bro_analyzer(),
connection()->bro_analyzer()->Conn(), connection()->bro_analyzer()->Conn(),
dhcp_msg_val_->Ref(), new AddrVal(req_addr), dhcp_msg_val_->Ref(), new AddrVal(req_addr),
new AddrVal(serv_addr)); new AddrVal(serv_addr), host_name);
break; break;
case DHCPDECLINE: case DHCPDECLINE:
BifEvent::generate_dhcp_decline(connection()->bro_analyzer(), BifEvent::generate_dhcp_decline(connection()->bro_analyzer(),
connection()->bro_analyzer()->Conn(), connection()->bro_analyzer()->Conn(),
dhcp_msg_val_->Ref()); dhcp_msg_val_->Ref(), host_name);
break; break;
case DHCPRELEASE: case DHCPRELEASE:
BifEvent::generate_dhcp_release(connection()->bro_analyzer(), BifEvent::generate_dhcp_release(connection()->bro_analyzer(),
connection()->bro_analyzer()->Conn(), connection()->bro_analyzer()->Conn(),
dhcp_msg_val_->Ref()); dhcp_msg_val_->Ref(), host_name);
break; break;
case DHCPINFORM: case DHCPINFORM:
BifEvent::generate_dhcp_inform(connection()->bro_analyzer(), BifEvent::generate_dhcp_inform(connection()->bro_analyzer(),
connection()->bro_analyzer()->Conn(), connection()->bro_analyzer()->Conn(),
dhcp_msg_val_->Ref()); dhcp_msg_val_->Ref(), host_name);
break; break;
} }
return true; return true;
%} %}
@ -118,72 +125,83 @@ flow DHCP_Flow(is_orig: bool) {
::uint32 subnet_mask = 0, serv_addr = 0; ::uint32 subnet_mask = 0, serv_addr = 0;
uint32 lease = 0; uint32 lease = 0;
StringVal* host_name = 0;
for ( ptr = options->begin(); for ( ptr = options->begin();
ptr != options->end() && ! (*ptr)->last(); ++ptr ) ptr != options->end() && ! (*ptr)->last(); ++ptr )
{ {
switch ( (*ptr)->code() ) { 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 = case SUBNET_OPTION:
(*ptr)->info()->router_list()->size(); subnet_mask = htonl((*ptr)->info()->mask());
break;
for ( int i = 0; i < num_routers; ++i ) case ROUTER_OPTION:
{ // Let's hope there aren't multiple
vector<uint32>* rlist = // such options.
(*ptr)->info()->router_list(); Unref(router_list);
uint32 raddr = (*rlist)[i]; router_list = new TableVal(dhcp_router_list);
::uint32 tmp_addr;
tmp_addr = htonl(raddr); {
// index starting from 1 int num_routers = (*ptr)->info()->router_list()->size();
Val* index = new Val(i + 1, TYPE_COUNT);
router_list->Assign(index, new AddrVal(tmp_addr)); for ( int i = 0; i < num_routers; ++i )
Unref(index); {
} 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;
} }
break;
case LEASE_OPTION:
lease = (*ptr)->info()->lease();
break;
case SERV_ID_OPTION:
serv_addr = htonl((*ptr)->info()->serv_addr());
break;
}
} }
switch ( type ) { if ( host_name == 0 )
case DHCPOFFER: host_name = new StringVal("");
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));
break;
case DHCPACK: switch ( type )
BifEvent::generate_dhcp_ack(connection()->bro_analyzer(), {
connection()->bro_analyzer()->Conn(), case DHCPOFFER:
dhcp_msg_val_->Ref(), new AddrVal(subnet_mask), BifEvent::generate_dhcp_offer(connection()->bro_analyzer(),
router_list, lease, new AddrVal(serv_addr)); connection()->bro_analyzer()->Conn(),
break; dhcp_msg_val_->Ref(), new AddrVal(subnet_mask),
router_list, lease, new AddrVal(serv_addr), host_name);
break;
case DHCPNAK: case DHCPACK:
BifEvent::generate_dhcp_nak(connection()->bro_analyzer(), BifEvent::generate_dhcp_ack(connection()->bro_analyzer(),
connection()->bro_analyzer()->Conn(), connection()->bro_analyzer()->Conn(),
dhcp_msg_val_->Ref()); dhcp_msg_val_->Ref(), new AddrVal(subnet_mask),
break; router_list, lease, new AddrVal(serv_addr), host_name);
break;
} case DHCPNAK:
BifEvent::generate_dhcp_nak(connection()->bro_analyzer(),
connection()->bro_analyzer()->Conn(),
dhcp_msg_val_->Ref(), host_name);
break;
}
return true; return true;
@ -195,7 +213,10 @@ flow DHCP_Flow(is_orig: bool) {
// DHCP or BOOTP. If not, we are unable to interpret // DHCP or BOOTP. If not, we are unable to interpret
// the message options. // the message options.
if ( ${msg.cookie} != 0x63825363 ) if ( ${msg.cookie} != 0x63825363 )
{
connection()->bro_analyzer()->ProtocolViolation(fmt("bad cookie (%d)", ${msg.cookie}));
return false; return false;
}
Unref(dhcp_msg_val_); Unref(dhcp_msg_val_);
RecordVal* r = new RecordVal(dhcp_msg); RecordVal* r = new RecordVal(dhcp_msg);
@ -203,40 +224,44 @@ flow DHCP_Flow(is_orig: bool) {
r->Assign(0, new Val(${msg.op}, TYPE_COUNT)); r->Assign(0, new Val(${msg.op}, TYPE_COUNT));
r->Assign(1, new Val(${msg.type}, TYPE_COUNT)); r->Assign(1, new Val(${msg.type}, TYPE_COUNT));
r->Assign(2, new Val(${msg.xid}, TYPE_COUNT)); r->Assign(2, new Val(${msg.xid}, TYPE_COUNT));
r->Assign(3, new StringVal(format_mac(${msg.chaddr}.data())));
// We want only 6 bytes for Ethernet address.
r->Assign(3, new StringVal(6, (const char*) ${msg.chaddr}.begin()));
r->Assign(4, new AddrVal(${msg.ciaddr})); r->Assign(4, new AddrVal(${msg.ciaddr}));
r->Assign(5, new AddrVal(${msg.yiaddr})); r->Assign(5, new AddrVal(${msg.yiaddr}));
dhcp_msg_val_ = r; dhcp_msg_val_ = r;
switch ( ${msg.op} ) { switch ( ${msg.op} )
case BOOTREQUEST: // presumablye from client to server {
if ( ${msg.type} == DHCPDISCOVER || case BOOTREQUEST: // presumably from client to server
${msg.type} == DHCPREQUEST || if ( ${msg.type} == DHCPDISCOVER ||
${msg.type} == DHCPDECLINE || ${msg.type} == DHCPREQUEST ||
${msg.type} == DHCPRELEASE || ${msg.type} == DHCPDECLINE ||
${msg.type} == DHCPINFORM ) ${msg.type} == DHCPRELEASE ||
parse_request(${msg.options}, ${msg.type}); ${msg.type} == DHCPINFORM )
else parse_request(${msg.options}, ${msg.type});
interp->Weird("DHCP_wrong_msg_type"); else
break; connection()->bro_analyzer()->ProtocolViolation(fmt("unknown DHCP message type option for BOOTREQUEST (%d)",
${msg.type}));
break;
case BOOTREPLY: // presumably from server to client case BOOTREPLY: // presumably from server to client
if ( ${msg.type} == DHCPOFFER || if ( ${msg.type} == DHCPOFFER ||
${msg.type} == DHCPACK || ${msg.type} == DHCPNAK ) ${msg.type} == DHCPACK ||
parse_reply(${msg.options}, ${msg.type}); ${msg.type} == DHCPNAK )
else parse_reply(${msg.options}, ${msg.type});
interp->Weird("DHCP_wrong_msg_type"); else
break; connection()->bro_analyzer()->ProtocolViolation(fmt("unknown DHCP message type option for BOOTREPLY (%d)",
${msg.type}));
default:
interp->Weird("DHCP_wrong_op_type"); break;
break;
}
default:
connection()->bro_analyzer()->ProtocolViolation(fmt("unknown DHCP message op code (%d). Known codes: 1=BOOTREQUEST, 2=BOOTREPLY",
${msg.op}));
break;
}
connection()->bro_analyzer()->ProtocolConfirmation();
return true; return true;
%} %}
}; };

View file

@ -10,13 +10,14 @@ enum OP_type {
# The option types are by no means complete. # The option types are by no means complete.
# Anyone can add a new option type in RFC 1533 to be parsed here. # Anyone can add a new option type in RFC 1533 to be parsed here.
enum OPTION_type { enum OPTION_type {
SUBNET_OPTION = 1, SUBNET_OPTION = 1,
ROUTER_OPTION = 3, ROUTER_OPTION = 3,
REQ_IP_OPTION = 50, HOST_NAME_OPTION = 12,
LEASE_OPTION = 51, REQ_IP_OPTION = 50,
MSG_TYPE_OPTION = 53, LEASE_OPTION = 51,
SERV_ID_OPTION = 54, # Server address, actually :) MSG_TYPE_OPTION = 53,
END_OPTION = 255, SERV_ID_OPTION = 54, # Server address, actually :)
END_OPTION = 255,
}; };
# Refer to RFC 1533 for message types (with option = 53). # Refer to RFC 1533 for message types (with option = 53).
@ -34,21 +35,22 @@ enum DHCP_message_type {
type Option_Info(code: uint8) = record { type Option_Info(code: uint8) = record {
length : uint8; length : uint8;
value : case code of { value : case code of {
SUBNET_OPTION -> mask : uint32; SUBNET_OPTION -> mask : uint32;
ROUTER_OPTION -> router_list: uint32[length/4]; ROUTER_OPTION -> router_list : uint32[length/4];
REQ_IP_OPTION -> req_addr : uint32; REQ_IP_OPTION -> req_addr : uint32;
LEASE_OPTION -> lease : uint32; LEASE_OPTION -> lease : uint32;
MSG_TYPE_OPTION -> msg_type : uint8; MSG_TYPE_OPTION -> msg_type : uint8;
SERV_ID_OPTION -> serv_addr: uint32; SERV_ID_OPTION -> serv_addr : uint32;
default -> other: bytestring &length = length; HOST_NAME_OPTION -> host_name : bytestring &length = length;
default -> other : bytestring &length = length;
}; };
}; };
type DHCP_Option = record { type DHCP_Option = record {
code : uint8; code : uint8;
data : case code of { data : case code of {
0, 255 -> none : empty; 0, 255 -> none : empty;
default -> info : Option_Info(code); default -> info : Option_Info(code);
}; };
} &let { } &let {
last: bool = (code == 255); # Mark the end of a list of options last: bool = (code == 255); # Mark the end of a list of options

View file

@ -1,3 +1,4 @@
%include binpac.pac
%include bro.pac %include bro.pac
%extern{ %extern{

View file

@ -1,8 +1,5 @@
## Generated for DHCP messages of type *discover*. ## Generated for DHCP messages of type *DHCPDISCOVER* (client broadcast to locate
## ## available servers).
## See `Wikipedia
## <http://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol>`__ for
## more information about the DHCP protocol.
## ##
## c: The connection record describing the underlying UDP flow. ## c: The connection record describing the underlying UDP flow.
## ##
@ -10,33 +7,23 @@
## ##
## req_addr: The specific address requested by the client. ## req_addr: The specific address requested by the client.
## ##
## .. bro:see:: dns_AAAA_reply dns_A_reply dns_CNAME_reply dns_EDNS_addl ## host_name: The value of the host name option, if specified by the client.
## dns_HINFO_reply dns_MX_reply dns_NS_reply dns_PTR_reply dns_SOA_reply ##
## dns_SRV_reply dns_TSIG_addl dns_TXT_reply dns_WKS_reply dns_end ## .. bro:see:: dhcp_discover dhcp_offer dhcp_request dhcp_decline dhcp_ack dhcp_nak
## dns_full_request dns_mapping_altered dns_mapping_lost_name dns_mapping_new_name ## dhcp_release dhcp_inform
## dns_mapping_unverified dns_mapping_valid dns_message dns_query_reply
## dns_rejected dns_request non_dns_request dns_max_queries dns_session_timeout
## dns_skip_addl dns_skip_all_addl dns_skip_all_auth dns_skip_auth
## ##
## .. note:: Bro does not support broadcast packets (as used by the DHCP ## .. note:: Bro does not support broadcast packets (as used by the 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.
## ##
## .. todo:: Bro's current default configuration does not activate the protocol event dhcp_discover%(c: connection, msg: dhcp_msg, req_addr: addr, host_name: string%);
## analyzer that generates this event; the corresponding script has not yet
## been ported to Bro 2.x. To still enable this event, one needs to
## register a port for it or add a DPD payload signature.
event dhcp_discover%(c: connection, msg: dhcp_msg, req_addr: addr%);
## Generated for DHCP messages of type *offer*. ## Generated for DHCP messages of type *DHCPOFFER* (server to client in response to
## ## DHCPDISCOVER with offer of configuration parameters).
## See `Wikipedia
## <http://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol>`__ for
## more information about the DHCP protocol.
## ##
## c: The connection record describing the underlying UDP flow. ## c: The connection record describing the underlying UDP flow.
## ##
## msg: TODO. ## msg: The parsed type-independent part of the DHCP message.
## ##
## mask: The subnet mask specified by the message. ## mask: The subnet mask specified by the message.
## ##
@ -46,28 +33,21 @@ event dhcp_discover%(c: connection, msg: dhcp_msg, req_addr: addr%);
## ##
## serv_addr: The server address specified by the message. ## serv_addr: The server address specified by the message.
## ##
## .. bro:see:: dns_AAAA_reply dns_A_reply dns_CNAME_reply dns_EDNS_addl ## host_name: The value of the host name option, if specified by the client.
## dns_HINFO_reply dns_MX_reply dns_NS_reply dns_PTR_reply dns_SOA_reply ##
## dns_SRV_reply dns_TSIG_addl dns_TXT_reply dns_WKS_reply dns_end ## .. bro:see:: dhcp_discover dhcp_request dhcp_decline dhcp_ack dhcp_nak
## dns_full_request dns_mapping_altered dns_mapping_lost_name dns_mapping_new_name ## dhcp_release dhcp_inform
## dns_mapping_unverified dns_mapping_valid dns_message dns_query_reply
## dns_rejected dns_request non_dns_request
## ##
## .. note:: Bro does not support broadcast packets (as used by the DHCP ## .. note:: Bro does not support broadcast packets (as used by the 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.
## ##
## .. todo:: Bro's current default configuration does not activate the protocol event dhcp_offer%(c: connection, msg: dhcp_msg, mask: addr, router: dhcp_router_list, lease: interval, serv_addr: addr, host_name: string%);
## analyzer that generates this event; the corresponding script has not yet
## been ported to Bro 2.x. To still enable this event, one needs to
## register a port for it or add a DPD payload signature.
event dhcp_offer%(c: connection, msg: dhcp_msg, mask: addr, router: dhcp_router_list, lease: interval, serv_addr: addr%);
## Generated for DHCP messages of type *request*. ## Generated for DHCP messages of type *DHCPREQUEST* (Client message to servers either
## ## (a) requesting offered parameters from one server and implicitly declining offers
## See `Wikipedia ## from all others, (b) confirming correctness of previously allocated address after,
## <http://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol>`__ for ## e.g., system reboot, or (c) extending the lease on a particular network address.)
## more information about the DHCP protocol.
## ##
## c: The connection record describing the underlying UDP flow. ## c: The connection record describing the underlying UDP flow.
## ##
@ -77,55 +57,37 @@ event dhcp_offer%(c: connection, msg: dhcp_msg, mask: addr, router: dhcp_router_
## ##
## serv_addr: The server address specified by the message. ## serv_addr: The server address specified by the message.
## ##
## .. bro:see:: dns_AAAA_reply dns_A_reply dns_CNAME_reply dns_EDNS_addl ## host_name: The value of the host name option, if specified by the client.
## dns_HINFO_reply dns_MX_reply dns_NS_reply dns_PTR_reply dns_SOA_reply ##
## dns_SRV_reply dns_TSIG_addl dns_TXT_reply dns_WKS_reply dns_end ## .. bro:see:: dhcp_discover dhcp_offer dhcp_decline dhcp_ack dhcp_nak
## dns_full_request dns_mapping_altered dns_mapping_lost_name dns_mapping_new_name ## dhcp_release dhcp_inform
## dns_mapping_unverified dns_mapping_valid dns_message dns_query_reply
## dns_rejected dns_request non_dns_request
## ##
## .. note:: Bro does not support broadcast packets (as used by the DHCP ## .. note:: Bro does not support broadcast packets (as used by the 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.
## ##
## .. todo:: Bro's current default configuration does not activate the protocol event dhcp_request%(c: connection, msg: dhcp_msg, req_addr: addr, serv_addr: addr, host_name: string%);
## analyzer that generates this event; the corresponding script has not yet
## been ported to Bro 2.x. To still enable this event, one needs to
## register a port for it or add a DPD payload signature.
event dhcp_request%(c: connection, msg: dhcp_msg, req_addr: addr, serv_addr: addr%);
## Generated for DHCP messages of type *decline*. ## Generated for DHCP messages of type *DHCPDECLINE* (Client to server indicating
## ## network address is already in use).
## See `Wikipedia
## <http://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol>`__ for
## more information about the DHCP protocol.
## ##
## c: The connection record describing the underlying UDP flow. ## c: The connection record describing the underlying UDP flow.
## ##
## msg: The parsed type-independent part of the DHCP message. ## msg: The parsed type-independent part of the DHCP message.
## ##
## .. bro:see:: dns_AAAA_reply dns_A_reply dns_CNAME_reply dns_EDNS_addl ## host_name: The value of the host name option, if specified by the client.
## dns_HINFO_reply dns_MX_reply dns_NS_reply dns_PTR_reply dns_SOA_reply ##
## dns_SRV_reply dns_TSIG_addl dns_TXT_reply dns_WKS_reply dns_end ## .. bro:see:: dhcp_discover dhcp_offer dhcp_request dhcp_ack dhcp_nak
## dns_full_request dns_mapping_altered dns_mapping_lost_name dns_mapping_new_name ## dhcp_release dhcp_inform
## dns_mapping_unverified dns_mapping_valid dns_message dns_query_reply
## dns_rejected dns_request non_dns_request
## ##
## .. note:: Bro does not support broadcast packets (as used by the DHCP ## .. note:: Bro does not support broadcast packets (as used by the 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.
## ##
## .. todo:: Bro's current default configuration does not activate the protocol event dhcp_decline%(c: connection, msg: dhcp_msg, host_name: string%);
## analyzer that generates this event; the corresponding script has not yet
## been ported to Bro 2.x. To still enable this event, one needs to
## register a port for it or add a DPD payload signature.
event dhcp_decline%(c: connection, msg: dhcp_msg%);
## Generated for DHCP messages of type *acknowledgment*. ## Generated for DHCP messages of type *DHCPACK* (Server to client with configuration
## ## parameters, including committed network address).
## See `Wikipedia
## <http://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol>`__ for
## more information about the DHCP protocol.
## ##
## c: The connection record describing the underlying UDP flow. ## c: The connection record describing the underlying UDP flow.
## ##
@ -139,101 +101,62 @@ event dhcp_decline%(c: connection, msg: dhcp_msg%);
## ##
## serv_addr: The server address specified by the message. ## serv_addr: The server address specified by the message.
## ##
## .. bro:see:: dns_AAAA_reply dns_A_reply dns_CNAME_reply dns_EDNS_addl ## host_name: The value of the host name option, if specified by the client.
## dns_HINFO_reply dns_MX_reply dns_NS_reply dns_PTR_reply dns_SOA_reply
## dns_SRV_reply dns_TSIG_addl dns_TXT_reply dns_WKS_reply dns_end
## dns_full_request dns_mapping_altered dns_mapping_lost_name dns_mapping_new_name
## dns_mapping_unverified dns_mapping_valid dns_message dns_query_reply
## dns_rejected dns_request non_dns_request
## ##
## .. note:: Bro does not support broadcast packets (as used by the DHCP ## .. bro:see:: dhcp_discover dhcp_offer dhcp_request dhcp_decline dhcp_nak
## protocol). It treats broadcast addresses just like any other and ## dhcp_release dhcp_inform
## associates packets into transport-level flows in the same way as usual.
## ##
## .. todo:: Bro's current default configuration does not activate the protocol event dhcp_ack%(c: connection, msg: dhcp_msg, mask: addr, router: dhcp_router_list, lease: interval, serv_addr: addr, host_name: string%);
## analyzer that generates this event; the corresponding script has not yet
## been ported to Bro 2.x. To still enable this event, one needs to
## register a port for it or add a DPD payload signature.
event dhcp_ack%(c: connection, msg: dhcp_msg, mask: addr, router: dhcp_router_list, lease: interval, serv_addr: addr%);
## Generated for DHCP messages of type *negative acknowledgment*. ## 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
## See `Wikipedia ## client's lease has expired).
## <http://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol>`__ for
## more information about the DHCP protocol.
## ##
## c: The connection record describing the underlying UDP flow. ## c: The connection record describing the underlying UDP flow.
## ##
## msg: The parsed type-independent part of the DHCP message. ## msg: The parsed type-independent part of the DHCP message.
## ##
## .. bro:see:: dns_AAAA_reply dns_A_reply dns_CNAME_reply dns_EDNS_addl ## host_name: The value of the host name option, if specified by the client.
## dns_HINFO_reply dns_MX_reply dns_NS_reply dns_PTR_reply dns_SOA_reply ##
## dns_SRV_reply dns_TSIG_addl dns_TXT_reply dns_WKS_reply dns_end ## .. bro:see:: dhcp_discover dhcp_offer dhcp_request dhcp_decline dhcp_ack dhcp_release
## dns_full_request dns_mapping_altered dns_mapping_lost_name dns_mapping_new_name ## dhcp_inform
## dns_mapping_unverified dns_mapping_valid dns_message dns_query_reply
## dns_rejected dns_request non_dns_request
## ##
## .. note:: Bro does not support broadcast packets (as used by the DHCP ## .. note:: Bro does not support broadcast packets (as used by the 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.
## ##
## .. todo:: Bro's current default configuration does not activate the protocol event dhcp_nak%(c: connection, msg: dhcp_msg, host_name: string%);
## analyzer that generates this event; the corresponding script has not yet
## been ported to Bro 2.x. To still enable this event, one needs to
## register a port for it or add a DPD payload signature.
event dhcp_nak%(c: connection, msg: dhcp_msg%);
## Generated for DHCP messages of type *release*. ## Generated for DHCP messages of type *DHCPRELEASE* (Client to server relinquishing
## ## network address and cancelling remaining lease).
## See `Wikipedia
## <http://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol>`__ for
## more information about the DHCP protocol.
## ##
## c: The connection record describing the underlying UDP flow. ## c: The connection record describing the underlying UDP flow.
## ##
## msg: The parsed type-independent part of the DHCP message. ## msg: The parsed type-independent part of the DHCP message.
## ##
## .. bro:see:: dns_AAAA_reply dns_A_reply dns_CNAME_reply dns_EDNS_addl ## host_name: The value of the host name option, if specified by the client.
## dns_HINFO_reply dns_MX_reply dns_NS_reply dns_PTR_reply dns_SOA_reply
## dns_SRV_reply dns_TSIG_addl dns_TXT_reply dns_WKS_reply dns_end
## dns_full_request dns_mapping_altered dns_mapping_lost_name dns_mapping_new_name
## dns_mapping_unverified dns_mapping_valid dns_message dns_query_reply
## dns_rejected dns_request non_dns_request
## ##
## .. note:: Bro does not support broadcast packets (as used by the DHCP ## .. bro:see:: dhcp_discover dhcp_offer dhcp_request dhcp_decline dhcp_ack dhcp_nak
## protocol). It treats broadcast addresses just like any other and ## dhcp_inform
## associates packets into transport-level flows in the same way as usual.
## ##
## .. todo:: Bro's current default configuration does not activate the protocol event dhcp_release%(c: connection, msg: dhcp_msg, host_name: string%);
## analyzer that generates this event; the corresponding script has not yet
## been ported to Bro 2.x. To still enable this event, one needs to
## register a port for it or add a DPD payload signature.
event dhcp_release%(c: connection, msg: dhcp_msg%);
## Generated for DHCP messages of type *inform*. ## Generated for DHCP messages of type *DHCPINFORM* (Client to server, asking only for
## ## local configuration parameters; client already has externally configured network
## See `Wikipedia ## address).
## <http://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol>`__ for
## more information about the DHCP protocol.
## ##
## c: The connection record describing the underlying UDP flow. ## c: The connection record describing the underlying UDP flow.
## ##
## msg: The parsed type-independent part of the DHCP message. ## msg: The parsed type-independent part of the DHCP message.
## ##
## .. bro:see:: dns_AAAA_reply dns_A_reply dns_CNAME_reply dns_EDNS_addl ## host_name: The value of the host name option, if specified by the client.
## dns_HINFO_reply dns_MX_reply dns_NS_reply dns_PTR_reply dns_SOA_reply ##
## dns_SRV_reply dns_TSIG_addl dns_TXT_reply dns_WKS_reply dns_end ## .. bro:see:: dhcp_discover dhcp_offer dhcp_request dhcp_decline dhcp_ack dhcp_nak
## dns_full_request dns_mapping_altered dns_mapping_lost_name dns_mapping_new_name ## dhcp_release
## dns_mapping_unverified dns_mapping_valid dns_message dns_query_reply
## dns_rejected dns_request non_dns_request
## ##
## .. note:: Bro does not support broadcast packets (as used by the DHCP ## .. note:: Bro does not support broadcast packets (as used by the 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.
## ##
## .. todo:: Bro's current default configuration does not activate the protocol event dhcp_inform%(c: connection, msg: dhcp_msg, host_name: string%);
## analyzer that generates this event; the corresponding script has not yet
## been ported to Bro 2.x. To still enable this event, one needs to
## register a port for it or add a DPD payload signature.
event dhcp_inform%(c: connection, msg: dhcp_msg%);

View file

@ -78,6 +78,26 @@ std::string extract_ip_and_len(const std::string& i, int* len)
return extract_ip(i.substr(0, pos)); return extract_ip(i.substr(0, pos));
} }
/**
* Given a MAC address, formats it as 00:de:ad:be:ef
* Supports both EUI-48 and EUI-64. If it's neither, returns
* an empty string.
*
* @param m EUI-48 or EUI-64 MAC address to format, as a char array
* @return A string of the formatted MAC
*/
char* format_mac(const unsigned char* m)
{
char* buf = new char[24];
if (m[6] == 0 && m[7] == 0) // EUI-48
snprintf(buf, 18, "%02x:%02x:%02x:%02x:%02x:%02x",
m[0], m[1], m[2], m[3], m[4], m[5]);
else
snprintf(buf, 24, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7]);
return buf;
}
/** /**
* Takes a string, unescapes all characters that are escaped as hex codes * Takes a string, unescapes all characters that are escaped as hex codes
* (\x##) and turns them into the equivalent ascii-codes. Returns a string * (\x##) and turns them into the equivalent ascii-codes. Returns a string

View file

@ -106,6 +106,7 @@ std::string get_escaped_string(const std::string& str, bool escape_all);
extern char* copy_string(const char* s); extern char* copy_string(const char* s);
extern int streq(const char* s1, const char* s2); extern int streq(const char* s1, const char* s2);
extern char* format_mac(const unsigned char* m);
// Returns the character corresponding to the given escape sequence (s points // Returns the character corresponding to the given escape sequence (s points
// just past the '\'), and updates s to point just beyond the last character // just past the '\'), and updates s to point just beyond the last character