Extract ICMPv6 NDP options and include in ICMP events (addresses #833).

This adds a new parameter of type "icmp6_nd_options" to the ICMPv6
neighbor discovery events (icmp_redirect, icmp_router_solicitation,
icmp_router_advertisement, icmp_neighbor_solicitation,
icmp_neighbor_advertisement) which includes data extracted from
all neighbor discovery options (RFC 4861) that are present in the
ICMPv6 message.
This commit is contained in:
Jon Siwek 2012-06-26 16:59:56 -05:00
parent c3b9a2a29c
commit 9ae9b2aa4d
10 changed files with 321 additions and 39 deletions

View file

@ -169,8 +169,10 @@ void ICMP_Analyzer::NextICMP6(double t, const struct icmp* icmpp, int len, int c
NeighborSolicit(t, icmpp, len, caplen, data, ip_hdr);
break;
case ND_ROUTER_SOLICIT:
RouterSolicit(t, icmpp, len, caplen, data, ip_hdr);
break;
case ICMP6_ROUTER_RENUMBERING:
Router(t, icmpp, len, caplen, data, ip_hdr);
ICMPEvent(icmp_sent, icmpp, len, 1, ip_hdr);
break;
#if 0
@ -515,10 +517,12 @@ void ICMP_Analyzer::RouterAdvert(double t, const struct icmp* icmpp, int len,
int caplen, const u_char*& data, const IP_Hdr* ip_hdr)
{
EventHandlerPtr f = icmp_router_advertisement;
uint32 reachable, retrans;
uint32 reachable = 0, retrans = 0;
memcpy(&reachable, data, sizeof(reachable));
memcpy(&retrans, data + sizeof(reachable), sizeof(retrans));
if ( caplen >= (int)sizeof(reachable) )
memcpy(&reachable, data, sizeof(reachable));
if ( caplen >= (int)sizeof(reachable) + (int)sizeof(retrans) )
memcpy(&retrans, data + sizeof(reachable), sizeof(retrans));
val_list* vl = new val_list;
vl->append(BuildConnVal());
@ -534,6 +538,9 @@ void ICMP_Analyzer::RouterAdvert(double t, const struct icmp* icmpp, int len,
vl->append(new IntervalVal((double)ntohl(reachable), Milliseconds));
vl->append(new IntervalVal((double)ntohl(retrans), Milliseconds));
int opt_offset = sizeof(reachable) + sizeof(retrans);
vl->append(BuildNDOptionsVal(caplen - opt_offset, data + opt_offset));
ConnectionEvent(f, vl);
}
@ -542,9 +549,10 @@ void ICMP_Analyzer::NeighborAdvert(double t, const struct icmp* icmpp, int len,
int caplen, const u_char*& data, const IP_Hdr* ip_hdr)
{
EventHandlerPtr f = icmp_neighbor_advertisement;
in6_addr tgtaddr;
IPAddr tgtaddr;
memcpy(&tgtaddr.s6_addr, data, sizeof(tgtaddr.s6_addr));
if ( caplen >= (int)sizeof(in6_addr) )
tgtaddr = IPAddr(*((const in6_addr*)data));
val_list* vl = new val_list;
vl->append(BuildConnVal());
@ -552,7 +560,10 @@ void ICMP_Analyzer::NeighborAdvert(double t, const struct icmp* icmpp, int len,
vl->append(new Val(icmpp->icmp_num_addrs & 0x80, TYPE_BOOL)); // Router
vl->append(new Val(icmpp->icmp_num_addrs & 0x40, TYPE_BOOL)); // Solicited
vl->append(new Val(icmpp->icmp_num_addrs & 0x20, TYPE_BOOL)); // Override
vl->append(new AddrVal(IPAddr(tgtaddr)));
vl->append(new AddrVal(tgtaddr));
int opt_offset = sizeof(in6_addr);
vl->append(BuildNDOptionsVal(caplen - opt_offset, data + opt_offset));
ConnectionEvent(f, vl);
}
@ -562,14 +573,18 @@ void ICMP_Analyzer::NeighborSolicit(double t, const struct icmp* icmpp, int len,
int caplen, const u_char*& data, const IP_Hdr* ip_hdr)
{
EventHandlerPtr f = icmp_neighbor_solicitation;
in6_addr tgtaddr;
IPAddr tgtaddr;
memcpy(&tgtaddr.s6_addr, data, sizeof(tgtaddr.s6_addr));
if ( caplen >= (int)sizeof(in6_addr) )
tgtaddr = IPAddr(*((const in6_addr*)data));
val_list* vl = new val_list;
vl->append(BuildConnVal());
vl->append(BuildICMPVal(icmpp, len, 1, ip_hdr));
vl->append(new AddrVal(IPAddr(tgtaddr)));
vl->append(new AddrVal(tgtaddr));
int opt_offset = sizeof(in6_addr);
vl->append(BuildNDOptionsVal(caplen - opt_offset, data + opt_offset));
ConnectionEvent(f, vl);
}
@ -579,40 +594,35 @@ void ICMP_Analyzer::Redirect(double t, const struct icmp* icmpp, int len,
int caplen, const u_char*& data, const IP_Hdr* ip_hdr)
{
EventHandlerPtr f = icmp_redirect;
in6_addr tgtaddr, dstaddr;
IPAddr tgtaddr, dstaddr;
memcpy(&tgtaddr.s6_addr, data, sizeof(tgtaddr.s6_addr));
memcpy(&dstaddr.s6_addr, data + sizeof(tgtaddr.s6_addr), sizeof(dstaddr.s6_addr));
if ( caplen >= (int)sizeof(in6_addr) )
tgtaddr = IPAddr(*((const in6_addr*)data));
if ( caplen >= 2 * (int)sizeof(in6_addr) )
dstaddr = IPAddr(*((const in6_addr*)(data + sizeof(in6_addr))));
val_list* vl = new val_list;
vl->append(BuildConnVal());
vl->append(BuildICMPVal(icmpp, len, 1, ip_hdr));
vl->append(new AddrVal(IPAddr(tgtaddr)));
vl->append(new AddrVal(IPAddr(dstaddr)));
vl->append(new AddrVal(tgtaddr));
vl->append(new AddrVal(dstaddr));
int opt_offset = 2 * sizeof(in6_addr);
vl->append(BuildNDOptionsVal(caplen - opt_offset, data + opt_offset));
ConnectionEvent(f, vl);
}
void ICMP_Analyzer::Router(double t, const struct icmp* icmpp, int len,
void ICMP_Analyzer::RouterSolicit(double t, const struct icmp* icmpp, int len,
int caplen, const u_char*& data, const IP_Hdr* ip_hdr)
{
EventHandlerPtr f = 0;
switch ( icmpp->icmp_type )
{
case ND_ROUTER_SOLICIT:
f = icmp_router_solicitation;
break;
case ICMP6_ROUTER_RENUMBERING:
default:
ICMPEvent(icmp_sent, icmpp, len, 1, ip_hdr);
return;
}
EventHandlerPtr f = icmp_router_solicitation;
val_list* vl = new val_list;
vl->append(BuildConnVal());
vl->append(BuildICMPVal(icmpp, len, 1, ip_hdr));
vl->append(BuildNDOptionsVal(caplen, data));
ConnectionEvent(f, vl);
}
@ -685,6 +695,137 @@ void ICMP_Analyzer::Context6(double t, const struct icmp* icmpp,
}
}
VectorVal* ICMP_Analyzer::BuildNDOptionsVal(int caplen, const u_char* data)
{
static RecordType* icmp6_nd_option_type = 0;
static RecordType* icmp6_nd_prefix_info_type = 0;
if ( ! icmp6_nd_option_type )
{
icmp6_nd_option_type = internal_type("icmp6_nd_option")->AsRecordType();
icmp6_nd_prefix_info_type =
internal_type("icmp6_nd_prefix_info")->AsRecordType();
}
VectorVal* vv = new VectorVal(
internal_type("icmp6_nd_options")->AsVectorType());
while ( caplen > 0 )
{
// Must have at least type & length to continue parsing options.
if ( caplen < 2 )
{
Weird("truncated_ICMPv6_ND_options");
break;
}
uint8 type = *((const uint8*)data);
uint8 length = *((const uint8*)(data + 1));
if ( length == 0 )
{
Weird("zero_length_ICMPv6_ND_option");
break;
}
RecordVal* rv = new RecordVal(icmp6_nd_option_type);
rv->Assign(0, new Val(type, TYPE_COUNT));
rv->Assign(1, new Val(length, TYPE_COUNT));
// adjust length to be in units of bytes, exclude type/length fields
length = length * 8 - 2;
data += 2;
caplen -= 2;
bool set_payload_field = false;
// Only parse out known options that are there in full.
switch ( type ) {
case 1:
case 2:
// Source/Target Link-layer Address option
{
if ( caplen >= length )
{
BroString* link_addr = new BroString(data, length, 0);
rv->Assign(2, new StringVal(link_addr));
}
else
set_payload_field = true;
}
break;
case 3:
// Prefix Information option
{
if ( caplen >= 30 )
{
RecordVal* info = new RecordVal(icmp6_nd_prefix_info_type);
uint8 prefix_len = *((const uint8*)(data));
bool L_flag = (*((const uint8*)(data + 1)) & 0x80) != 0;
bool A_flag = (*((const uint8*)(data + 1)) & 0x40) != 0;
uint32 valid_life = *((const uint32*)(data + 2));
uint32 prefer_life = *((const uint32*)(data + 6));
in6_addr prefix = *((const in6_addr*)(data + 14));
info->Assign(0, new Val(prefix_len, TYPE_COUNT));
info->Assign(1, new Val(L_flag, TYPE_BOOL));
info->Assign(2, new Val(A_flag, TYPE_BOOL));
info->Assign(3, new IntervalVal((double)ntohl(valid_life), Seconds));
info->Assign(4, new IntervalVal((double)ntohl(prefer_life), Seconds));
info->Assign(5, new AddrVal(IPAddr(prefix)));
rv->Assign(3, info);
}
else
set_payload_field = true;
}
break;
case 4:
// Redirected Header option
{
if ( caplen >= length )
{
const u_char* hdr = data + 6;
rv->Assign(4, ExtractICMP6Context(length - 6, hdr));
}
else
set_payload_field = true;
}
break;
case 5:
// MTU option
{
if ( caplen >= 6 )
rv->Assign(5, new Val(ntohl(*((const uint32*)(data + 2))),
TYPE_COUNT));
else
set_payload_field = true;
}
break;
default:
{
set_payload_field = true;
}
break;
}
if ( set_payload_field )
{
BroString* payload =
new BroString(data, min((int)length, caplen), 0);
rv->Assign(6, new StringVal(payload));
}
data += length;
caplen -= length;
vv->Assign(vv->Size(), rv, 0);
}
return vv;
}
int ICMP4_counterpart(int icmp_type, int icmp_code, bool& is_one_way)
{
is_one_way = false;

View file

@ -48,7 +48,7 @@ protected:
int caplen, const u_char*& data, const IP_Hdr* ip_hdr);
void NeighborSolicit(double t, const struct icmp* icmpp, int len,
int caplen, const u_char*& data, const IP_Hdr* ip_hdr);
void Router(double t, const struct icmp* icmpp, int len,
void RouterSolicit(double t, const struct icmp* icmpp, int len,
int caplen, const u_char*& data, const IP_Hdr* ip_hdr);
void Describe(ODesc* d) const;
@ -75,6 +75,9 @@ protected:
void Context6(double t, const struct icmp* icmpp, int len, int caplen,
const u_char*& data, const IP_Hdr* ip_hdr);
// RFC 4861 Neighbor Discover message options
VectorVal* BuildNDOptionsVal(int caplen, const u_char* data);
RecordVal* icmp_conn_val;
int type;
int code;

View file

@ -1054,9 +1054,11 @@ event icmp_parameter_problem%(c: connection, icmp: icmp_conn, code: count, conte
## icmp: Additional ICMP-specific information augmenting the standard connection
## record *c*.
##
## options: Any Neighbor Discovery options included with message (:rfc:`4861`).
##
## .. bro:see:: icmp_router_advertisement
## icmp_neighbor_solicitation icmp_neighbor_advertisement icmp_redirect
event icmp_router_solicitation%(c: connection, icmp: icmp_conn%);
event icmp_router_solicitation%(c: connection, icmp: icmp_conn, options: icmp6_nd_options%);
## Generated for ICMP *router advertisement* messages.
##
@ -1090,9 +1092,11 @@ event icmp_router_solicitation%(c: connection, icmp: icmp_conn%);
##
## retrans_timer: How long a host should wait before retransmitting.
##
## options: Any Neighbor Discovery options included with message (:rfc:`4861`).
##
## .. bro:see:: icmp_router_solicitation
## icmp_neighbor_solicitation icmp_neighbor_advertisement icmp_redirect
event icmp_router_advertisement%(c: connection, icmp: icmp_conn, cur_hop_limit: count, managed: bool, other: bool, home_agent: bool, pref: count, proxy: bool, rsv: count, router_lifetime: interval, reachable_time: interval, retrans_timer: interval%);
event icmp_router_advertisement%(c: connection, icmp: icmp_conn, cur_hop_limit: count, managed: bool, other: bool, home_agent: bool, pref: count, proxy: bool, rsv: count, router_lifetime: interval, reachable_time: interval, retrans_timer: interval, options: icmp6_nd_options%);
## Generated for ICMP *neighbor solicitation* messages.
##
@ -1107,9 +1111,11 @@ event icmp_router_advertisement%(c: connection, icmp: icmp_conn, cur_hop_limit:
##
## tgt: The IP address of the target of the solicitation.
##
## options: Any Neighbor Discovery options included with message (:rfc:`4861`).
##
## .. bro:see:: icmp_router_solicitation icmp_router_advertisement
## icmp_neighbor_advertisement icmp_redirect
event icmp_neighbor_solicitation%(c: connection, icmp: icmp_conn, tgt:addr%);
event icmp_neighbor_solicitation%(c: connection, icmp: icmp_conn, tgt: addr, options: icmp6_nd_options%);
## Generated for ICMP *neighbor advertisement* messages.
##
@ -1131,9 +1137,11 @@ event icmp_neighbor_solicitation%(c: connection, icmp: icmp_conn, tgt:addr%);
## tgt: the Target Address in the soliciting message or the address whose
## link-layer address has changed for unsolicited adverts.
##
## options: Any Neighbor Discovery options included with message (:rfc:`4861`).
##
## .. bro:see:: icmp_router_solicitation icmp_router_advertisement
## icmp_neighbor_solicitation icmp_redirect
event icmp_neighbor_advertisement%(c: connection, icmp: icmp_conn, router: bool, solicited: bool, override: bool, tgt:addr%);
event icmp_neighbor_advertisement%(c: connection, icmp: icmp_conn, router: bool, solicited: bool, override: bool, tgt: addr, options: icmp6_nd_options%);
## Generated for ICMP *redirect* messages.
##
@ -1151,9 +1159,11 @@ event icmp_neighbor_advertisement%(c: connection, icmp: icmp_conn, router: bool,
##
## dest: The address of the destination which is redirected to the target.
##
## options: Any Neighbor Discovery options included with message (:rfc:`4861`).
##
## .. bro:see:: icmp_router_solicitation icmp_router_advertisement
## icmp_neighbor_solicitation icmp_neighbor_advertisement
event icmp_redirect%(c: connection, icmp: icmp_conn, tgt: addr, dest: addr%);
event icmp_redirect%(c: connection, icmp: icmp_conn, tgt: addr, dest: addr, options: icmp6_nd_options%);
## Generated when a TCP connection terminated, passing on statistics about the
## two endpoints. This event is always generated when Bro flushes the internal