Significant edit pass over ICMPv6 code.

Matti, more per mail.
This commit is contained in:
Robin Sommer 2011-01-25 17:54:20 -08:00
parent cb64bb6874
commit 50181edd84
10 changed files with 424 additions and 719 deletions

View file

@ -28,6 +28,8 @@ type icmp_conn: record {
itype: count; itype: count;
icode: count; icode: count;
len: count; len: count;
v6: bool; # true if it's an ICMPv6 packet.
}; };
type icmp_hdr: record { type icmp_hdr: record {
@ -38,12 +40,11 @@ type icmp_context: record {
id: conn_id; id: conn_id;
len: count; len: count;
proto: count; proto: count;
frag_offset: count &optional; #no frag offset for IPv6 bad_hdr_len: bool;
bad_hdr_len: bool &optional; bad_checksum: bool; # always true for ICMPv6.
bad_checksum: bool &optional; #no checksum in IPv6 header frag_offset: count; # always 0 for IMCPv6.
MF: bool &optional; #no MF for IPv6 MF: bool; # always false for IMCPv6.
DF: bool &optional; #no DF for IPv6 DF: bool; # always true for ICMPv6.
ICMP6Flag: bool;
}; };
type addr_set: set[addr]; type addr_set: set[addr];

View file

@ -1,5 +1,4 @@
# $Id: icmp.bro 6883 2009-08-19 21:08:09Z vern $ # $Id: icmp.bro 6883 2009-08-19 21:08:09Z vern $
# While using this script, please notice that the last F/T value is the IPv6 Flag
@load hot @load hot
@load weird @load weird
@ -18,6 +17,7 @@ export {
ICMPAsymPayload, # payload in echo req-resp not the same ICMPAsymPayload, # payload in echo req-resp not the same
ICMPConnectionPair, # too many ICMPs between hosts ICMPConnectionPair, # too many ICMPs between hosts
ICMPAddressScan, ICMPAddressScan,
ICMPRogueRouter, # v6 advertisement from unknown router
# The following isn't presently sufficiently useful due # The following isn't presently sufficiently useful due
# to cold start and packet drops. # to cold start and packet drops.
@ -35,6 +35,12 @@ export {
const detect_conn_pairs = F &redef; # switch for connection pair const detect_conn_pairs = F &redef; # switch for connection pair
const detect_payload_asym = F &redef; # switch for echo payload const detect_payload_asym = F &redef; # switch for echo payload
const conn_pair_threshold = 200 &redef; const conn_pair_threshold = 200 &redef;
# If the IPv6 routers in a network are all known, they can be
# whitelisted here. If so, any other router seen sending an
# announcement will be reported. If this set remains empty, no such
# detection will be done.
const router_whitelist: set[addr] &redef;
} }
global conn_pair:table[addr] of set[addr] &create_expire = 1 day; global conn_pair:table[addr] of set[addr] &create_expire = 1 day;
@ -56,16 +62,10 @@ type flow_info: record {
payload: string; payload: string;
}; };
#Insert whitelisted routers here, Router advertisements from other
#routers will be logged as possible rogue router attacks
const routers_whitelist: table[string] of bool = {
#["fe80::260:97ff:fe07:69ea"] = T, #an example
} &redef &default = F;
const names: table[count] of string = { const names: table[count] of string = {
[0] = "echo_reply", [0] = "echo_reply",
[1] = "unreach", #icmpv6 [1] = "unreach", # icmpv6
[2] = "too_big", #icmpv6 [2] = "too_big", # icmpv6
[3] = "unreach", [3] = "unreach",
[4] = "quench", [4] = "quench",
[5] = "redirect", [5] = "redirect",
@ -80,33 +80,33 @@ const names: table[count] of string = {
[16] = "info_reply", [16] = "info_reply",
[17] = "mask_req", [17] = "mask_req",
[18] = "mask_reply", [18] = "mask_reply",
[128] = "echo_req", #icmpv6 [128] = "echo_req", # icmpv6
[129] = "echo_reply", #icmpv6 [129] = "echo_reply", # icmpv6
[130] = "group_memb_query", #icmpv6 [130] = "group_memb_query", # icmpv6
[131] = "group_memb_report", #icmpv6 [131] = "group_memb_report", # icmpv6
[132] = "group_memb_reduct", #icmpv6 [132] = "group_memb_reduct", # icmpv6
[133] = "router_sol", #icmpv6 [133] = "router_sol", # icmpv6
[134] = "router_ad", #icmpv6 [134] = "router_ad", # icmpv6
[135] = "neighbor_sol", #icmpv6 [135] = "neighbor_sol", # icmpv6
[136] = "neighbor_ad", #icmpv6 [136] = "neighbor_ad", # icmpv6
[137] = "redirect", #icmpv6 [137] = "redirect", # icmpv6
[138] = "router_renum", #icmpv6 [138] = "router_renum", # icmpv6
[139] = "node_info_query", #icmpv6 [139] = "node_info_query", # icmpv6
[140] = "node_info_resp", #icmpv6 [140] = "node_info_resp", # icmpv6
[141] = "inv_neigh_disc_sol", #icmpv6 [141] = "inv_neigh_disc_sol", # icmpv6
[142] = "inv_neigh_disc_ad", #icmpv6 [142] = "inv_neigh_disc_ad", # icmpv6
[143] = "mul_lis_report", #icmpv6 [143] = "mul_lis_report", # icmpv6
[144] = "home_agent_addr_req", #icmpv6 [144] = "home_agent_addr_req", # icmpv6
[145] = "home_agent_addr_reply",#icmpv6 [145] = "home_agent_addr_reply",# icmpv6
[146] = "mobible_prefx_sol", #icmpv6 [146] = "mobible_prefx_sol", # icmpv6
[147] = "mobible_prefx_ad", #icmpv6 [147] = "mobible_prefx_ad", # icmpv6
[148] = "cert_path_sol", #icmpv6 [148] = "cert_path_sol", # icmpv6
[149] = "cert_path_ad", #icmpv6 [149] = "cert_path_ad", # icmpv6
[150] = "experimental", #icmpv6 [150] = "experimental", # icmpv6
[151] = "mcast_router_ad", #icmpv6 [151] = "mcast_router_ad", # icmpv6
[152] = "mcast_router_sol", #icmpv6 [152] = "mcast_router_sol", # icmpv6
[153] = "mcast_router_term", #icmpv6 [153] = "mcast_router_term", # icmpv6
[154] = "fmip", #icmpv6 [154] = "fmip", # icmpv6
} &default = function(n: count): string { return fmt("icmp-%d", n); }; } &default = function(n: count): string { return fmt("icmp-%d", n); };
@ -116,8 +116,8 @@ const IP_proto_name: table[count] of string = {
[2] = "IGMP", [2] = "IGMP",
[6] = "TCP", [6] = "TCP",
[17] = "UDP", [17] = "UDP",
[41] = "IP6", [41] = "IPV6",
[58] = "ICMP6", [58] = "ICMPV6",
} &default = function(n: count): string { return fmt("%s", n); } } &default = function(n: count): string { return fmt("%s", n); }
&redef; &redef;
@ -160,13 +160,38 @@ global flows: table[flow_id] of flow_info
&read_expire = 45 sec &read_expire = 45 sec
&expire_func = flush_flow; &expire_func = flush_flow;
event icmp_sent(c: connection, icmp: icmp_conn, ICMP6: bool) function print_log(c: connection, icmp: icmp_conn, addl: string)
{ {
if ( ! log_details )
return;
print icmp_file, fmt("%.6f %.6f %s %s %s %s %s %s %s %s %s %s", print icmp_file, fmt("%.6f %.6f %s %s %s %s %s %s %s %s",
network_time(), 0.0, icmp$orig_h, icmp$resp_h, network_time(), 0.0, icmp$orig_h, icmp$resp_h,
names[icmp$itype], icmp$itype, icmp$icode, "icmp", names[icmp$itype], icmp$itype, icmp$icode,
icmp$len, "0", "SH", ICMP6); icmp$v6 ? "icmp6" : "icmp", icmp$len, addl);
}
function print_log_with_context(c: connection, icmp: icmp_conn, context: icmp_context, addl: string)
{
# Due to the connection data contained *within*
# them, each log line will contain two connections' worth
# of data. The initial ICMP connection info is the same
# as logged for connections.
local ctx = fmt("0 EncapPkt: %s %s %s %s %s %s %s %s %s",
context$id$orig_h, context$id$orig_p,
context$id$resp_h, context$id$resp_p,
context$len, IP_proto_name[context$proto],
context$len, context$bad_hdr_len,
context$bad_checksum);
print_log(c, icmp, ctx);
}
event icmp_sent(c: connection, icmp: icmp_conn)
{
print_log(c, icmp, "0 SH");
} }
event flow_summary(flow: flow_id, last_time: time) event flow_summary(flow: flow_id, last_time: time)
@ -212,63 +237,18 @@ function update_flow(icmp: icmp_conn, id: count, is_orig: bool, payload: string)
} }
event icmp_error_message(c: connection, icmp: icmp_conn, code: count, context: icmp_context) #for other but the unreach types, which is preserved event icmp_error_message(c: connection, icmp: icmp_conn, code: count, context: icmp_context)
{ {
print_log_with_context(c, icmp, context, "");
if ( active_connection(context$id) )
{
# This section allows Bro to act on ICMP error message packets
# that happen in the context of an active connection. It is
# not currently used.
local c2 = connection_record(context$id);
local os = c2$orig$state;
local rs = c2$resp$state;
local is_attempt =
is_tcp_port(c2$id$orig_p) ?
(os == TCP_SYN_SENT && rs == TCP_INACTIVE) :
(os == UDP_ACTIVE && rs == UDP_INACTIVE);
# Insert action here.
} }
if ( log_details ) event icmp_echo_request(c: connection, icmp: icmp_conn, id: count, seq: count, payload: string)
{
# ICMP error message packets are logged here.
# Due to the connection data contained *within*
# them, each log line will contain two connections' worth
# of data. The initial ICMP connection info is the same
# as logged for connections.
print icmp_file, fmt("%.6f %.6f %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s",
network_time(), 0.0, icmp$orig_h, icmp$resp_h,
names[icmp$itype], icmp$itype, icmp$icode, "icmp",
icmp$len, "0", "EncapPkt:",
# This is the encapsulated packet:
context$id$orig_h, context$id$orig_p,
context$id$resp_h, context$id$resp_p,
context$len, IP_proto_name[context$proto],
context$len, context$bad_hdr_len,
context$bad_checksum, context$ICMP6Flag);
}
}
event icmp6_placeholder(c: connection, icmp: icmp_conn, ICMP6: bool) #just for testing
{
print "icmp6_placeholder triggered";
}
event icmp_echo_request(c: connection, icmp: icmp_conn, id: count, seq: count, payload: string, ICMP6: bool)
{ {
update_flow(icmp, id, T, payload); update_flow(icmp, id, T, payload);
local orig = icmp$orig_h; local orig = icmp$orig_h;
local resp = icmp$resp_h; local resp = icmp$resp_h;
# Simple ping scan detector. # Simple ping scan detector.
if ( detect_scans && if ( detect_scans &&
(orig !in Scan::distinct_peers || (orig !in Scan::distinct_peers ||
@ -320,7 +300,7 @@ event icmp_echo_request(c: connection, icmp: icmp_conn, id: count, seq: count, p
} }
event icmp_echo_reply(c: connection, icmp: icmp_conn, id: count, event icmp_echo_reply(c: connection, icmp: icmp_conn, id: count,
seq: count, payload: string, ICMP6: bool) seq: count, payload: string)
{ {
# Check payload with the associated flow. # Check payload with the associated flow.
@ -329,8 +309,6 @@ event icmp_echo_reply(c: connection, icmp: icmp_conn, id: count,
fid$resp_h = icmp$orig_h; # it's an echo reply. fid$resp_h = icmp$orig_h; # it's an echo reply.
fid$id = id; fid$id = id;
if ( fid !in flows ) if ( fid !in flows )
{ {
# NOTICE([$note=ICMPUnpairedEchoReply, # NOTICE([$note=ICMPUnpairedEchoReply,
@ -357,78 +335,19 @@ event icmp_echo_reply(c: connection, icmp: icmp_conn, id: count,
update_flow(icmp, id, F, payload); update_flow(icmp, id, F, payload);
} }
event icmp_unreachable(c: connection, icmp: icmp_conn, code: count, event icmp_unreachable(c: connection, icmp: icmp_conn, code: count,
context: icmp_context) context: icmp_context)
{ {
print_log_with_context(c, icmp, context, "");
}
if ( active_connection(context$id) ) event icmp_router_advertisement(c: connection, icmp: icmp_conn)
{ {
# This section allows Bro to act on ICMP-unreachable packets print_log(c, icmp, "");
# that happen in the context of an active connection. It is
# not currently used.
local c2 = connection_record(context$id);
local os = c2$orig$state;
local rs = c2$resp$state;
local is_attempt =
is_tcp_port(c2$id$orig_p) ?
(os == TCP_SYN_SENT && rs == TCP_INACTIVE) :
(os == UDP_ACTIVE && rs == UDP_INACTIVE);
# Insert action here. if ( |router_whitelist| == 0 || icmp$orig_h in router_whitelist )
return;
NOTICE([$note=ICMPRogueRouter,
$msg=fmt("rouge router advertisement from %s", icmp$orig_h)]);
} }
if ( log_details )
{
# ICMP unreachable packets are the only ones currently
# logged. Due to the connection data contained *within*
# them, each log line will contain two connections' worth
# of data. The initial ICMP connection info is the same
# as logged for connections.
print icmp_file, fmt("%.6f %.6f %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s",
network_time(), 0.0, icmp$orig_h, icmp$resp_h,
names[icmp$itype], icmp$itype, icmp$icode, "icmp",
icmp$len, "0", "EncapPkt:",
# This is the encapsulated packet:
context$id$orig_h, context$id$orig_p,
context$id$resp_h, context$id$resp_p,
context$len, IP_proto_name[context$proto],
context$len, context$bad_hdr_len,
context$bad_checksum, context$ICMP6Flag);
}
}
event icmp_router_advertisement(c: connection, icmp: icmp_conn, ICMP6: bool)
{
if ( routers_whitelist[ fmt("%s",icmp$orig_h) ] )
{
print icmp_file, fmt("%.6f %.6f %s %s %s %s %s %s %s %s %s %s",
network_time(), 0.0, icmp$orig_h, icmp$resp_h,
names[icmp$itype], icmp$itype, icmp$icode, "icmp",
icmp$len, "0", "SH", ICMP6);
}
else
{
print icmp_file, fmt("%.6f %.6f %s %s %s %s %s %s %s %s",
network_time(), 0.0, icmp$orig_h, icmp$resp_h,
names[icmp$itype], "Possible Rogue Router Detected", icmp$itype, icmp$icode,
icmp$len, ICMP6);
}
}

View file

@ -48,20 +48,6 @@ const Analyzer::Config Analyzer::analyzer_configs[] = {
{ AnalyzerTag::ICMP, "ICMP", ICMP_Analyzer::InstantiateAnalyzer, { AnalyzerTag::ICMP, "ICMP", ICMP_Analyzer::InstantiateAnalyzer,
ICMP_Analyzer::Available, 0, false }, ICMP_Analyzer::Available, 0, false },
/*{ AnalyzerTag::ICMP_TimeExceeded, "ICMP_TIMEEXCEEDED",
ICMP_TimeExceeded_Analyzer::InstantiateAnalyzer,
ICMP_TimeExceeded_Analyzer::Available, 0, false },
{ AnalyzerTag::ICMP_Unreachable, "ICMP_UNREACHABLE",
ICMP_Unreachable_Analyzer::InstantiateAnalyzer,
ICMP_Unreachable_Analyzer::Available, 0, false },
{ AnalyzerTag::ICMP_Echo, "ICMP_ECHO",
ICMP_Echo_Analyzer::InstantiateAnalyzer,
ICMP_Echo_Analyzer::Available, 0, false },*/
{ AnalyzerTag::TCP, "TCP", TCP_Analyzer::InstantiateAnalyzer, { AnalyzerTag::TCP, "TCP", TCP_Analyzer::InstantiateAnalyzer,
TCP_Analyzer::Available, 0, false }, TCP_Analyzer::Available, 0, false },
{ AnalyzerTag::UDP, "UDP", UDP_Analyzer::InstantiateAnalyzer, { AnalyzerTag::UDP, "UDP", UDP_Analyzer::InstantiateAnalyzer,

View file

@ -22,7 +22,7 @@ namespace AnalyzerTag {
PIA_TCP, PIA_UDP, PIA_TCP, PIA_UDP,
// Transport-layer analyzers. // Transport-layer analyzers.
ICMP,/* ICMP_TimeExceeded, ICMP_Unreachable, ICMP_Echo*/ TCP, UDP, ICMP, TCP, UDP,
// Application-layer analyzers (hand-written). // Application-layer analyzers (hand-written).
BitTorrent, BitTorrentTracker, BitTorrent, BitTorrentTracker,

View file

@ -214,42 +214,8 @@ bool DPM::BuildInitialAnalyzerTree(TransportProto proto, Connection* conn,
break; break;
case TRANSPORT_ICMP: { case TRANSPORT_ICMP: {
const struct icmp* icmpp = (const struct icmp *) data;
//Old code, moving to having only one ICMP analyzer
/*switch ( icmpp->icmp_type ) {
case ICMP_ECHO:
case ICMP_ECHOREPLY:
if ( ICMP_Echo_Analyzer::Available() )
{
root = new ICMP_Echo_Analyzer(conn);
DBG_DPD(conn, "activated ICMP Echo analyzer");
}
break;
case ICMP_UNREACH:
if ( ICMP_Unreachable_Analyzer::Available() )
{
root = new ICMP_Unreachable_Analyzer(conn);
DBG_DPD(conn, "activated ICMP Unreachable analyzer");
}
break;
case ICMP_TIMXCEED:
if ( ICMP_TimeExceeded_Analyzer::Available() )
{
root = new ICMP_TimeExceeded_Analyzer(conn);
DBG_DPD(conn, "activated ICMP Time Exceeded analyzer");
}
break;
}*/
//if ( ! root )
root = new ICMP_Analyzer(conn); root = new ICMP_Analyzer(conn);
DBG_DPD(conn, "activated ICMP analyzer"); DBG_DPD(conn, "activated ICMP analyzer");
analyzed = true; analyzed = true;
break; break;
} }

View file

@ -11,15 +11,12 @@
#include <netinet/icmp6.h> #include <netinet/icmp6.h>
ICMP_Analyzer::ICMP_Analyzer(Connection* c) ICMP_Analyzer::ICMP_Analyzer(Connection* c)
: TransportLayerAnalyzer(AnalyzerTag::ICMP, c) : TransportLayerAnalyzer(AnalyzerTag::ICMP, c)
{ {
icmp_conn_val = 0; icmp_conn_val = 0;
c->SetInactivityTimeout(icmp_inactivity_timeout); c->SetInactivityTimeout(icmp_inactivity_timeout);
request_len = reply_len = -1; request_len = reply_len = -1;
} }
ICMP_Analyzer::ICMP_Analyzer(AnalyzerTag::Tag tag, Connection* c) ICMP_Analyzer::ICMP_Analyzer(AnalyzerTag::Tag tag, Connection* c)
@ -37,7 +34,7 @@ void ICMP_Analyzer::Done()
matcher_state.FinishEndpointMatcher(); matcher_state.FinishEndpointMatcher();
} }
void ICMP_Analyzer::DeliverPacket(int arg_len, const u_char* data, void ICMP_Analyzer::DeliverPacket(int len, const u_char* data,
bool is_orig, int seq, const IP_Hdr* ip, int caplen) bool is_orig, int seq, const IP_Hdr* ip, int caplen)
{ {
assert(ip); assert(ip);
@ -50,43 +47,40 @@ void ICMP_Analyzer::DeliverPacket(int arg_len, const u_char* data,
// Subtract off the common part of ICMP header. // Subtract off the common part of ICMP header.
PacketContents(data + 8, min(len, caplen) - 8); PacketContents(data + 8, min(len, caplen) - 8);
const struct icmp* icmpp = (const struct icmp*) data; const struct icmp* icmpp = (const struct icmp*) data;
len = arg_len;
assert(caplen >= len); // Should have been caught earlier already.
if ( ! ignore_checksums )
{
int chksum;
//We need a separate calculation for ICMP6 checksums, pseudoheader is appended to the
//ICMP6 checksum calculation, which is different from ICMP4
#ifdef BROv6 #ifdef BROv6
switch ( ip->NextProto() )
{
case IPPROTO_ICMP:
chksum = icmp_checksum(icmpp, len);
break;
case IPPROTO_ICMPV6:
chksum = icmp6_checksum(icmpp, ip->IP6_Hdr(), len);
break;
if (ip->NextProto() == IPPROTO_ICMPV6 && ! ignore_checksums && default:
caplen >= len && icmp6_checksum(icmpp,ip->IP6_Hdr(),len )!= 0xffff ) internal_error("unexpected IP proto in ICMP analyzer");
}
#else
# Classic v4 version.
chksum = icmp_checksum(icmpp, len);
#endif
if ( chksum != 0xffff )
{ {
Weird("bad_ICMP6_checksum"); Weird("bad_ICMP6_checksum");
return; return;
} }
else if (ip->NextProto() != IPPROTO_ICMPV6 && ! ignore_checksums &&
caplen >= len && icmp_checksum(icmpp, len) != 0xffff )
{
Weird("bad_ICMP_checksum");
return;
} }
#else
if ( ! ignore_checksums && caplen >= len &&
icmp_checksum(icmpp, len) != 0xffff )
{
Weird("bad_ICMP_checksum");
return;
}
#endif
Conn()->SetLastTime(current_timestamp); Conn()->SetLastTime(current_timestamp);
if ( rule_matcher ) if ( rule_matcher )
@ -95,89 +89,26 @@ void ICMP_Analyzer::DeliverPacket(int arg_len, const u_char* data,
matcher_state.InitEndpointMatcher(this, ip, len, is_orig, 0); matcher_state.InitEndpointMatcher(this, ip, len, is_orig, 0);
} }
type = icmpp->icmp_type; // Move past common portion of ICMP header.
code = icmpp->icmp_code;
// Move past common portion of ICMP header. //OK for ICMPv6?
data += 8; data += 8;
caplen -= 8; caplen -= 8;
len -= 8; len -= 8;
int& len_stat = is_orig ? request_len : reply_len; if ( ip->NextProto() == IPPROTO_ICMP )
if ( len_stat < 0 ) NextICMP4(current_timestamp, icmpp, len, caplen, data, ip);
len_stat = len;
else else
len_stat += len; NextICMP6(current_timestamp, icmpp, len, caplen, data, ip);
NextICMP(current_timestamp, icmpp, len, caplen, data, ip);
if ( rule_matcher ) if ( rule_matcher )
matcher_state.Match(Rule::PAYLOAD, data, len, is_orig, matcher_state.Match(Rule::PAYLOAD, data, len, is_orig,
false, false, true); false, false, true);
} }
void ICMP_Analyzer::NextICMP4(double t, const struct icmp* icmpp, int len, int caplen,
/********************Generic analyzer for all ICMP4/ICMP6******************************/
void ICMP_Analyzer::NextICMP(double t , const struct icmp* icmpp , int len , int caplen,
const u_char*& data, const IP_Hdr* ip_hdr ) const u_char*& data, const IP_Hdr* ip_hdr )
{ {
int ICMP6Flag = 0; switch ( icmpp->icmp_type )
//printf("Executing: ICMP_Analyzer::NextICMP\n");
//printf("New analyzer structure\n");
if ( ip_hdr->NextProto() == IPPROTO_ICMPV6 )
{
//printf("ICMP6!\n");
ICMP6Flag = 1;
switch (type) //Add new ICMP6 functions here, you can also use codes to narrow the area of single functions.
{
//All the echo stuff here
case ICMP6_ECHO_REQUEST:
case ICMP6_ECHO_REPLY:
Echo(t, icmpp, len, caplen, data, ip_hdr);
break;
//Error messages all have the same structure for their context, and are handled by the same function.
case ICMP6_PARAM_PROB:
case ICMP6_TIME_EXCEEDED:
case ICMP6_PACKET_TOO_BIG:
case ICMP6_DST_UNREACH:
Context(t, icmpp, len, caplen, data, ip_hdr);
break;
//All router related stuff should eventually be handled by the Router()
case ND_REDIRECT:
case ND_ROUTER_SOLICIT:
case ICMP6_ROUTER_RENUMBERING:
case ND_ROUTER_ADVERT:
Router(t, icmpp, len, caplen, data, ip_hdr); //currently only logs the router stuff for other than router_advert
break;
/* listed for convenience
case ICMP6_PARAM_PROB: break;
case MLD_LISTENER_QUERY: break;
case MLD_LISTENER_REPORT: break;
case MLD_LISTENER_REDUCTION: break;
case ND_NEIGHBOR_SOLICIT: break;
case ND_NEIGHBOR_ADVERT: break;
case ND_REDIRECT: break;
case ICMP6_ROUTER_RENUMBERING: break;
case ND_NEIGHBOR_SOLICIT: break;
case ND_NEIGHBOR_ADVERT: break;
case ICMP6_TIME_EXCEEDED: break;
*/
default: ICMPEvent(icmp_sent, ICMP6Flag); break;
}
}
else if ( ip_hdr->NextProto() == IPPROTO_ICMP )
{
switch (type) //Add new ICMP4 functions here
{ {
case ICMP_ECHO: case ICMP_ECHO:
case ICMP_ECHOREPLY: case ICMP_ECHOREPLY:
@ -186,36 +117,76 @@ void ICMP_Analyzer::NextICMP(double t , const struct icmp* icmpp , int len , i
case ICMP_UNREACH: case ICMP_UNREACH:
case ICMP_TIMXCEED: case ICMP_TIMXCEED:
Context(t, icmpp, len, caplen, data, ip_hdr); Context4(t, icmpp, len, caplen, data, ip_hdr);
break; break;
default: ICMPEvent(icmp_sent, ICMP6Flag); break; default:
ICMPEvent(icmp_sent, icmpp, len, 0); break;
}
} }
#ifdef BROv6
void ICMP_Analyzer::NextICMP6(double t, const struct icmp* icmpp, int len, int caplen,
const u_char*& data, const IP_Hdr* ip_hdr )
{
switch ( icmpp->icmp_type )
{
// Echo types.
case ICMP6_ECHO_REQUEST:
case ICMP6_ECHO_REPLY:
Echo(t, icmpp, len, caplen, data, ip_hdr);
break;
// Error messages all have the same structure for their context,
// and are handled by the same function.
case ICMP6_PARAM_PROB:
case ICMP6_TIME_EXCEEDED:
case ICMP6_PACKET_TOO_BIG:
case ICMP6_DST_UNREACH:
Context6(t, icmpp, len, caplen, data, ip_hdr);
break;
// Router related messages.
case ND_REDIRECT:
case ND_ROUTER_SOLICIT:
case ICMP6_ROUTER_RENUMBERING:
case ND_ROUTER_ADVERT:
Router(t, icmpp, len, caplen, data, ip_hdr);
break;
#if 0
// Currently not specifically implemented.
case ICMP6_PARAM_PROB:
case MLD_LISTENER_QUERY:
case MLD_LISTENER_REPORT:
case MLD_LISTENER_REDUCTION:
case ND_NEIGHBOR_SOLICIT:
case ND_NEIGHBOR_ADVERT:
case ND_REDIRECT:
case ICMP6_ROUTER_RENUMBERING:
case ND_NEIGHBOR_SOLICIT:
case ND_NEIGHBOR_ADVERT:
case ICMP6_TIME_EXCEEDED:
#endif
default:
ICMPEvent(icmp_sent, icmpp, len, 1);
break;
} }
else
Weird("Malformed ip header");
} }
#endif
void ICMP_Analyzer::ICMPEvent(EventHandlerPtr f, const struct icmp* icmpp, int len, int icmpv6)
void ICMP_Analyzer::ICMPEvent(EventHandlerPtr f, int ICMP6Flag)
{ {
if ( ! f ) if ( ! f )
return; return;
val_list* vl = new val_list; val_list* vl = new val_list;
vl->append(BuildConnVal()); vl->append(BuildConnVal());
vl->append(BuildICMPVal(ICMP6Flag)); vl->append(BuildICMPVal(icmpp, len, icmpv6));
//if ( f == icmp_sent ) //for now, testing purposes
vl->append(new Val(ICMP6Flag, TYPE_BOOL));
ConnectionEvent(f, vl); ConnectionEvent(f, vl);
} }
RecordVal* ICMP_Analyzer::BuildICMPVal(const struct icmp* icmpp, int len, int icmpv6)
RecordVal* ICMP_Analyzer::BuildICMPVal(int ICMP6Flag)
{ {
if ( ! icmp_conn_val ) if ( ! icmp_conn_val )
{ {
@ -223,15 +194,10 @@ RecordVal* ICMP_Analyzer::BuildICMPVal(int ICMP6Flag)
icmp_conn_val->Assign(0, new AddrVal(Conn()->OrigAddr())); icmp_conn_val->Assign(0, new AddrVal(Conn()->OrigAddr()));
icmp_conn_val->Assign(1, new AddrVal(Conn()->RespAddr())); icmp_conn_val->Assign(1, new AddrVal(Conn()->RespAddr()));
icmp_conn_val->Assign(2, new Val(icmpp->icmp_type, TYPE_COUNT));
if ( ICMP6Flag == 1 ) icmp_conn_val->Assign(3, new Val(icmpp->icmp_code, TYPE_COUNT));
icmp_conn_val->Assign(2, new Val(Type6to4(type), TYPE_COUNT)); //to avoid errors in getting the message type *name* right on the scripting level, type number will be different from true ipv6
else
icmp_conn_val->Assign(2, new Val(type, TYPE_COUNT));
icmp_conn_val->Assign(3, new Val(code, TYPE_COUNT));
icmp_conn_val->Assign(4, new Val(len, TYPE_COUNT)); icmp_conn_val->Assign(4, new Val(len, TYPE_COUNT));
icmp_conn_val->Assign(5, new Val(icmpv6, TYPE_BOOL));
} }
Ref(icmp_conn_val); Ref(icmp_conn_val);
@ -239,15 +205,74 @@ RecordVal* ICMP_Analyzer::BuildICMPVal(int ICMP6Flag)
return icmp_conn_val; return icmp_conn_val;
} }
TransportProto ICMP_Analyzer::GetContextProtocol(const IP_Hdr* ip_hdr, uint32* src_port, uint32* dst_port)
{
const u_char* transport_hdr;
uint32 ip_hdr_len = ip_hdr->HdrLen();
bool ip4 = ip_hdr->IP4_Hdr();
if ( ip4 )
transport_hdr = ((u_char *) ip_hdr->IP4_Hdr() + ip_hdr_len);
else
transport_hdr = ((u_char *) ip_hdr->IP6_Hdr() + ip_hdr_len);
TransportProto proto;
switch ( ip_hdr->NextProto() ) {
case 1: proto = TRANSPORT_ICMP; break;
case 6: proto = TRANSPORT_TCP; break;
case 17: proto = TRANSPORT_UDP; break;
case 58: proto = TRANSPORT_ICMP; //TransportProto Hack // XXX What's this?
default: proto = TRANSPORT_UNKNOWN; break;
}
switch ( proto ) {
case TRANSPORT_ICMP:
{
const struct icmp* icmpp =
(const struct icmp *) transport_hdr;
bool is_one_way; // dummy
*src_port = ntohs(icmpp->icmp_type);
if ( ip4 )
*dst_port = ntohs(ICMP4_counterpart(icmpp->icmp_type,
icmpp->icmp_code, is_one_way));
else
*dst_port = ntohs(ICMP6_counterpart(icmpp->icmp_type,
icmpp->icmp_code, is_one_way));
break;
}
case TRANSPORT_TCP:
{
const struct tcphdr* tp =
(const struct tcphdr *) transport_hdr;
*src_port = ntohs(tp->th_sport);
*dst_port = ntohs(tp->th_dport);
break;
}
case TRANSPORT_UDP:
{
const struct udphdr* up =
(const struct udphdr *) transport_hdr;
*src_port = ntohs(up->uh_sport);
*dst_port = ntohs(up->uh_dport);
break;
}
default:
*src_port = *dst_port = ntohs(0);
}
return proto;
}
RecordVal* ICMP_Analyzer::ExtractICMP4Context(int len, const u_char*& data) RecordVal* ICMP_Analyzer::ExtractICMP4Context(int len, const u_char*& data)
{ {
/**
* For use only with ICMP4, ICMPV6 context extraction is still non-functional
*/
const IP_Hdr ip_hdr_data((const struct ip*) data); const IP_Hdr ip_hdr_data((const struct ip*) data);
const IP_Hdr* ip_hdr = &ip_hdr_data; const IP_Hdr* ip_hdr = &ip_hdr_data;
int ICMP6Flag = 0;
uint32 ip_hdr_len = ip_hdr->HdrLen(); uint32 ip_hdr_len = ip_hdr->HdrLen();
@ -258,7 +283,8 @@ RecordVal* ICMP_Analyzer::ExtractICMP4Context(int len, const u_char*& data)
uint32 src_port, dst_port; uint32 src_port, dst_port;
if ( ip_hdr_len < sizeof(struct ip) || ip_hdr_len > uint32(len) ) if ( ip_hdr_len < sizeof(struct ip) || ip_hdr_len > uint32(len) )
{ // We don't have an entire IP header. {
// We don't have an entire IP header.
bad_hdr_len = 1; bad_hdr_len = 1;
ip_len = frag_offset = 0; ip_len = frag_offset = 0;
DF = MF = bad_checksum = 0; DF = MF = bad_checksum = 0;
@ -275,62 +301,19 @@ RecordVal* ICMP_Analyzer::ExtractICMP4Context(int len, const u_char*& data)
src_addr = ip_hdr->SrcAddr4(); src_addr = ip_hdr->SrcAddr4();
dst_addr = ip_hdr->DstAddr4(); dst_addr = ip_hdr->DstAddr4();
switch ( ip_hdr->NextProto() ) {
case 1: proto = TRANSPORT_ICMP; break;
case 6: proto = TRANSPORT_TCP; break;
case 17: proto = TRANSPORT_UDP; break;
// Default uses TRANSPORT_UNKNOWN, per initialization above.
}
uint32 frag_field = ip_hdr->FragField(); uint32 frag_field = ip_hdr->FragField();
DF = ip_hdr->DF(); DF = ip_hdr->DF();
MF = frag_field & 0x2000; MF = frag_field & 0x2000;
frag_offset = frag_field & /* IP_OFFMASK not portable */ 0x1fff; frag_offset = frag_field & /* IP_OFFMASK not portable */ 0x1fff;
const u_char* transport_hdr = ((u_char *) ip_hdr->IP4_Hdr() + ip_hdr_len); if ( uint32(len) >= ip_hdr_len + 4 )
proto = GetContextProtocol(ip_hdr, &src_port, &dst_port);
if ( uint32(len) < ip_hdr_len + 4 ) //what is this value for ipv6? else
{ {
// 4 above is the magic number meaning that both // 4 above is the magic number meaning that both
// port numbers are included in the ICMP. // port numbers are included in the ICMP.
bad_hdr_len = 1;
src_port = dst_port = 0; src_port = dst_port = 0;
} bad_hdr_len = 1;
switch ( proto ) {
case TRANSPORT_ICMP:
{
const struct icmp* icmpp =
(const struct icmp *) transport_hdr;
bool is_one_way; // dummy
src_port = ntohs(icmpp->icmp_type);
dst_port = ntohs(ICMP4_counterpart(icmpp->icmp_type,
icmpp->icmp_code,
is_one_way));
}
break;
case TRANSPORT_TCP:
{
const struct tcphdr* tp =
(const struct tcphdr *) transport_hdr;
src_port = ntohs(tp->th_sport);
dst_port = ntohs(tp->th_dport);
}
break;
case TRANSPORT_UDP:
{
const struct udphdr* up =
(const struct udphdr *) transport_hdr;
src_port = ntohs(up->uh_sport);
dst_port = ntohs(up->uh_dport);
}
break;
default:
src_port = dst_port = ntohs(0);
} }
} }
@ -341,48 +324,40 @@ RecordVal* ICMP_Analyzer::ExtractICMP4Context(int len, const u_char*& data)
id_val->Assign(1, new PortVal(src_port, proto)); id_val->Assign(1, new PortVal(src_port, proto));
id_val->Assign(2, new AddrVal(dst_addr)); id_val->Assign(2, new AddrVal(dst_addr));
id_val->Assign(3, new PortVal(dst_port, proto)); id_val->Assign(3, new PortVal(dst_port, proto));
iprec->Assign(0, id_val);
iprec->Assign(0, id_val);
iprec->Assign(1, new Val(ip_len, TYPE_COUNT)); iprec->Assign(1, new Val(ip_len, TYPE_COUNT));
iprec->Assign(2, new Val(proto, TYPE_COUNT)); iprec->Assign(2, new Val(proto, TYPE_COUNT));
iprec->Assign(3, new Val(frag_offset, TYPE_COUNT)); iprec->Assign(3, new Val(bad_hdr_len, TYPE_BOOL));
iprec->Assign(4, new Val(bad_hdr_len, TYPE_BOOL)); iprec->Assign(4, new Val(bad_checksum, TYPE_BOOL));
iprec->Assign(5, new Val(bad_checksum, TYPE_BOOL)); iprec->Assign(5, new Val(frag_offset, TYPE_COUNT));
iprec->Assign(6, new Val(MF, TYPE_BOOL)); iprec->Assign(6, new Val(MF, TYPE_BOOL));
iprec->Assign(7, new Val(DF, TYPE_BOOL)); iprec->Assign(7, new Val(DF, TYPE_BOOL));
iprec->Assign(8, new Val(ICMP6Flag, TYPE_BOOL));
return iprec; return iprec;
} }
RecordVal* ICMP_Analyzer::ExtractICMP6Context(int len, const u_char*& data) RecordVal* ICMP_Analyzer::ExtractICMP6Context(int len, const u_char*& data)
{ {
/**
* For use with ICMP6 error message context extraction (possibly very frail function)
*/
const IP_Hdr ip_hdr_data((const struct ip6_hdr*) data); const IP_Hdr ip_hdr_data((const struct ip6_hdr*) data);
const IP_Hdr* ip_hdr = &ip_hdr_data; const IP_Hdr* ip_hdr = &ip_hdr_data;
int ICMP6Flag = 1;
int DF = 0, MF = 0, bad_hdr_len = 0, bad_checksum = 0; int DF = 0, MF = 0, bad_hdr_len = 0, bad_checksum = 0;
TransportProto proto = TRANSPORT_UNKNOWN;
uint32 ip_hdr_len = ip_hdr->HdrLen(); //should always be 40 uint32 ip_hdr_len = ip_hdr->HdrLen(); //should always be 40
uint32* src_addr; uint32* src_addr;
uint32* dst_addr; uint32* dst_addr;
uint32 ip_len, frag_offset = 0; uint32 ip_len, frag_offset = 0;
TransportProto proto = TRANSPORT_UNKNOWN;
uint32 src_port, dst_port; uint32 src_port, dst_port;
if ( ip_hdr_len < sizeof(struct ip6_hdr) || ip_hdr_len != 40 ) if ( ip_hdr_len < sizeof(struct ip6_hdr) || ip_hdr_len != 40 ) // XXX What's the 2nd part doing?
{ {
bad_hdr_len = 1; bad_hdr_len = 1;
ip_len = 0; ip_len = 0;
src_addr = dst_addr = 0; src_addr = dst_addr = 0;
src_port = dst_port = 0; src_port = dst_port = 0;
} }
else else
{ {
ip_len = ip_hdr->TotalLen(); ip_len = ip_hdr->TotalLen();
@ -390,61 +365,14 @@ RecordVal* ICMP_Analyzer::ExtractICMP6Context(int len, const u_char*& data)
src_addr = (uint32 *) ip_hdr->SrcAddr(); src_addr = (uint32 *) ip_hdr->SrcAddr();
dst_addr = (uint32 *) ip_hdr->DstAddr(); dst_addr = (uint32 *) ip_hdr->DstAddr();
if ( uint32(len) >= ip_hdr_len + 4 )
proto = GetContextProtocol(ip_hdr, &src_port, &dst_port);
switch ( ip_hdr->NextProto() ) { else
case 1: proto = TRANSPORT_ICMP; break;
case 6: proto = TRANSPORT_TCP; break;
case 17: proto = TRANSPORT_UDP; break;
case 58: proto = TRANSPORT_ICMP; break; //TransportProto Hack
// Default uses TRANSPORT_UNKNOWN, per initialization above.
}
const u_char* transport_hdr = ((u_char *)ip_hdr->IP6_Hdr() + ip_hdr_len);
if ( uint32(len) < ip_hdr_len + 4 )
{ {
// 4 above is the magic number meaning that both // 4 above is the magic number meaning that both
// port numbers are included in the ICMP. // port numbers are included in the ICMP.
bad_hdr_len = 1;
src_port = dst_port = 0; src_port = dst_port = 0;
} bad_hdr_len = 1;
switch ( proto ) {
case TRANSPORT_ICMP:
{
const struct icmp* icmpp =
(const struct icmp *) transport_hdr;
bool is_one_way; // dummy
src_port = ntohs(icmpp->icmp_type);
dst_port = ntohs(ICMP6_counterpart(icmpp->icmp_type,
icmpp->icmp_code,
is_one_way));
}
break;
case TRANSPORT_TCP:
{
const struct tcphdr* tp =
(const struct tcphdr *) transport_hdr;
src_port = ntohs(tp->th_sport);
dst_port = ntohs(tp->th_dport);
}
break;
case TRANSPORT_UDP:
{
const struct udphdr* up =
(const struct udphdr *) transport_hdr;
src_port = ntohs(up->uh_sport);
dst_port = ntohs(up->uh_dport);
}
break;
default:
src_port = dst_port = ntohs(0);
} }
} }
@ -459,7 +387,7 @@ RecordVal* ICMP_Analyzer::ExtractICMP6Context(int len, const u_char*& data)
iprec->Assign(0, id_val); iprec->Assign(0, id_val);
iprec->Assign(1, new Val(ip_len, TYPE_COUNT)); iprec->Assign(1, new Val(ip_len, TYPE_COUNT));
//TransportProto Hack //TransportProto Hack // XXX Likewise.
if ( ip_hdr->NextProto() == 58 || 17 ) //if the encap packet is ICMPv6 we force this... (cause there is no IGMP (by that name) for ICMPv6), rather ugly hack once more if ( ip_hdr->NextProto() == 58 || 17 ) //if the encap packet is ICMPv6 we force this... (cause there is no IGMP (by that name) for ICMPv6), rather ugly hack once more
{ {
iprec->Assign(2, new Val(58, TYPE_COUNT)); iprec->Assign(2, new Val(58, TYPE_COUNT));
@ -469,28 +397,18 @@ RecordVal* ICMP_Analyzer::ExtractICMP6Context(int len, const u_char*& data)
iprec->Assign(2, new Val(proto, TYPE_COUNT)); iprec->Assign(2, new Val(proto, TYPE_COUNT));
} }
iprec->Assign(3, new Val(frag_offset, TYPE_COUNT)); //NA for ip6 iprec->Assign(3, new Val(bad_hdr_len, TYPE_BOOL));
iprec->Assign(4, new Val(bad_hdr_len, TYPE_BOOL));
iprec->Assign(5, new Val(bad_checksum, TYPE_BOOL)); // The following are not available for IPv6.
iprec->Assign(6, new Val(MF, TYPE_BOOL)); //NA for ip6 iprec->Assign(4, new Val(0, TYPE_BOOL)); // bad_checksum
iprec->Assign(7, new Val(DF, TYPE_BOOL)); //NA for ip6 iprec->Assign(5, new Val(frag_offset, TYPE_COUNT)); // frag_offset
iprec->Assign(8, new Val(ICMP6Flag, TYPE_BOOL)); //ICMP6Flag iprec->Assign(6, new Val(0, TYPE_BOOL)); // MF
iprec->Assign(7, new Val(1, TYPE_BOOL)); // DF
return iprec; return iprec;
} }
bool ICMP_Analyzer::IsReuse(double /* t */, const u_char* /* pkt */) bool ICMP_Analyzer::IsReuse(double /* t */, const u_char* /* pkt */)
{ {
return 0; return 0;
@ -504,10 +422,12 @@ void ICMP_Analyzer::Describe(ODesc* d) const
d->AddSP(")"); d->AddSP(")");
d->Add(dotted_addr(Conn()->OrigAddr())); d->Add(dotted_addr(Conn()->OrigAddr()));
#if 0
d->Add("."); d->Add(".");
d->Add(type); d->Add(type);
d->Add("."); d->Add(".");
d->Add(code); d->Add(code);
#endif
d->SP(); d->SP();
d->AddSP("->"); d->AddSP("->");
@ -543,19 +463,16 @@ unsigned int ICMP_Analyzer::MemoryAllocation() const
void ICMP_Analyzer::Echo(double t, const struct icmp* icmpp, int len, void ICMP_Analyzer::Echo(double t, const struct icmp* icmpp, int len,
int caplen, const u_char*& data, const IP_Hdr* ip_hdr) int caplen, const u_char*& data, const IP_Hdr* ip_hdr)
{ //For handling all Echo related ICMP messages
EventHandlerPtr f = 0;
int ICMP6Flag = 0;
//printf("Executing: Echo, NextProto:%d\n",ip_hdr->NextProto());
if ( ip_hdr->NextProto() == IPPROTO_ICMPV6 )
{ {
f = type == ICMP6_ECHO_REQUEST ? icmp_echo_request : icmp_echo_reply; // For handling all Echo related ICMP messages
ICMP6Flag = 1; EventHandlerPtr f = 0;
}
#ifdef BROv6
if ( ip_hdr->NextProto() == IPPROTO_ICMPV6 )
f = (icmpp->icmp_type == ICMP6_ECHO_REQUEST) ? icmp_echo_request : icmp_echo_reply;
else else
f = type == ICMP_ECHO ? icmp_echo_request : icmp_echo_reply; #endif
f = (icmpp->icmp_type == ICMP_ECHO) ? icmp_echo_request : icmp_echo_reply;
if ( ! f ) if ( ! f )
return; return;
@ -563,137 +480,110 @@ void ICMP_Analyzer::Echo(double t, const struct icmp* icmpp, int len,
int iid = ntohs(icmpp->icmp_hun.ih_idseq.icd_id); int iid = ntohs(icmpp->icmp_hun.ih_idseq.icd_id);
int iseq = ntohs(icmpp->icmp_hun.ih_idseq.icd_seq); int iseq = ntohs(icmpp->icmp_hun.ih_idseq.icd_seq);
//printf("Check these values: iid:[%d] iseq:[%d]\n",iid,iseq);
BroString* payload = new BroString(data, caplen, 0); BroString* payload = new BroString(data, caplen, 0);
val_list* vl = new val_list; val_list* vl = new val_list;
vl->append(BuildConnVal()); vl->append(BuildConnVal());
vl->append(BuildICMPVal(ICMP6Flag)); vl->append(BuildICMPVal(icmpp, len, ip_hdr->NextProto() != IPPROTO_ICMP));
vl->append(new Val(iid, TYPE_COUNT)); vl->append(new Val(iid, TYPE_COUNT));
vl->append(new Val(iseq, TYPE_COUNT)); vl->append(new Val(iseq, TYPE_COUNT));
vl->append(new StringVal(payload)); vl->append(new StringVal(payload));
vl->append(new Val(ICMP6Flag, TYPE_BOOL));
ConnectionEvent(f, vl); ConnectionEvent(f, vl);
} }
void ICMP_Analyzer::Router(double t, const struct icmp* icmpp, int len, void ICMP_Analyzer::Router(double t, const struct icmp* icmpp, int len,
int caplen, const u_char*& data, const IP_Hdr* /*ip_hdr*/) int caplen, const u_char*& data, const IP_Hdr* /*ip_hdr*/)
//For handling router related ICMP messages,
{ {
EventHandlerPtr f = 0; EventHandlerPtr f = 0;
int ICMP6Flag = 1;
switch ( type ) switch ( icmpp->icmp_type )
{ {
case ND_ROUTER_ADVERT: f = icmp_router_advertisement; break; case ND_ROUTER_ADVERT:
f = icmp_router_advertisement;
break;
case ND_REDIRECT: case ND_REDIRECT:
case ND_ROUTER_SOLICIT: case ND_ROUTER_SOLICIT:
case ICMP6_ROUTER_RENUMBERING: case ICMP6_ROUTER_RENUMBERING:
default: ICMPEvent(icmp_sent,ICMP6Flag); return; default:
ICMPEvent(icmp_sent, icmpp, len, 1);
return;
} }
val_list* vl = new val_list; val_list* vl = new val_list;
vl->append(BuildConnVal()); vl->append(BuildConnVal());
vl->append(BuildICMPVal(ICMP6Flag)); vl->append(BuildICMPVal(icmpp, len, 1));
vl->append(new Val(ICMP6Flag, TYPE_BOOL));
ConnectionEvent(f, vl); ConnectionEvent(f, vl);
} }
void ICMP_Analyzer::Context4(double t, const struct icmp* icmpp,
void ICMP_Analyzer::Context(double t, const struct icmp* icmpp,
int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr) int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr)
{//For handling the ICMP error messages {
EventHandlerPtr f = 0; EventHandlerPtr f = 0;
int ICMP6Flag = 0;
switch ( icmpp->icmp_type )
if ( ip_hdr->NextProto() == IPPROTO_ICMPV6 ) //is ip6
{ {
case ICMP_UNREACH:
f = icmp_unreachable;
break;
ICMP6Flag = 1; case ICMP_TIMXCEED:
//printf("Executing: Context for ICMPv6\n"); f = icmp_error_message;
break;
switch ( type )
{
case ICMP6_DST_UNREACH: f = icmp_unreachable; break;
case ICMP6_PARAM_PROB: f = icmp_error_message; break;
case ICMP6_TIME_EXCEEDED: f = icmp_error_message; break;
case ICMP6_PACKET_TOO_BIG: f = icmp_error_message; break;
}
if ( f )
{
val_list* vl = new val_list;
vl->append(BuildConnVal()); //check for ip6 functionality
vl->append(BuildICMPVal(ICMP6Flag)); //check for ip6 functionality
vl->append(new Val(code, TYPE_COUNT));
vl->append(ExtractICMP6Context(caplen, data));
ConnectionEvent(f, vl);
}
}
else if ( ip_hdr->NextProto() == IPPROTO_ICMP )
{
//printf("Executing: Context for ICMP\n");
switch ( type )
{
case ICMP_UNREACH: f = icmp_unreachable; break;
case ICMP_TIMXCEED: f = icmp_error_message; break;
} }
if ( f ) if ( f )
{ {
val_list* vl = new val_list; val_list* vl = new val_list;
vl->append(BuildConnVal()); vl->append(BuildConnVal());
vl->append(BuildICMPVal(ICMP6Flag)); vl->append(BuildICMPVal(icmpp, len, 0));
vl->append(new Val(code, TYPE_COUNT)); vl->append(new Val(icmpp->icmp_code, TYPE_COUNT));
vl->append(ExtractICMP4Context(caplen, data)); vl->append(ExtractICMP4Context(caplen, data));
ConnectionEvent(f, vl); ConnectionEvent(f, vl);
} }
} }
else
#ifdef BROv6
void ICMP_Analyzer::Context6(double t, const struct icmp* icmpp,
int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr)
{ {
Weird("ICMP packet, invalid data\n"); //make this more descriptive EventHandlerPtr f = 0;
}
switch ( icmpp->icmp_type )
{
case ICMP6_DST_UNREACH:
f = icmp_unreachable;
break;
case ICMP6_PARAM_PROB:
case ICMP6_TIME_EXCEEDED:
case ICMP6_PACKET_TOO_BIG:
f = icmp_error_message;
break;
} }
if ( f )
{
val_list* vl = new val_list;
vl->append(BuildConnVal());
vl->append(BuildICMPVal(icmpp, len, 1));
vl->append(new Val(icmpp->icmp_code, TYPE_COUNT));
vl->append(ExtractICMP6Context(caplen, data));
ConnectionEvent(f, vl);
}
}
#endif
int ICMP4_counterpart(int icmp_type, int icmp_code, bool& is_one_way) int ICMP4_counterpart(int icmp_type, int icmp_code, bool& is_one_way)
{ {
is_one_way = false; is_one_way = false;
// return the counterpart type if one exists. This allows us // Return the counterpart type if one exists. This allows us
// to track corresponding ICMP requests/replies. // to track corresponding ICMP requests/replies.
// Note that for the two-way ICMP messages, icmp_code is // Note that for the two-way ICMP messages, icmp_code is
// always 0 (RFC 792). // always 0 (RFC 792).
@ -720,12 +610,7 @@ int ICMP6_counterpart(int icmp_type, int icmp_code, bool& is_one_way)
{ {
is_one_way = false; is_one_way = false;
/**ICMP6 version of the ICMP4_counterpart, under work**/
//not yet used anywhere, for the context class
switch ( icmp_type ) { switch ( icmp_type ) {
case ICMP6_ECHO_REQUEST: return ICMP6_ECHO_REPLY; case ICMP6_ECHO_REQUEST: return ICMP6_ECHO_REPLY;
case ICMP6_ECHO_REPLY: return ICMP6_ECHO_REQUEST; case ICMP6_ECHO_REPLY: return ICMP6_ECHO_REQUEST;
@ -738,39 +623,17 @@ int ICMP6_counterpart(int icmp_type, int icmp_code, bool& is_one_way)
case MLD_LISTENER_QUERY: return MLD_LISTENER_REPORT; case MLD_LISTENER_QUERY: return MLD_LISTENER_REPORT;
case MLD_LISTENER_REPORT: return MLD_LISTENER_QUERY; case MLD_LISTENER_REPORT: return MLD_LISTENER_QUERY;
case 139: return 140; //ICMP node information query and response respectively (not defined in icmp6.h) // ICMP node information query and response respectively (not defined in
// icmp6.h)
case 139: return 140;
case 140: return 139; case 140: return 139;
case 144: return 145; //Home Agent Address Discovery Request Message and reply // Home Agent Address Discovery Request Message and reply
case 144: return 145;
case 145: return 144; case 145: return 144;
//check the rest of the counterparts // TODO: Add further counterparts.
default: is_one_way = true; return icmp_code; default: is_one_way = true; return icmp_code;
} }
} }
//For mapping ICMP types and codes of v6 to v4. Because we are using same events for both icmpv4 and icmpv6 there is some overlap
//in ICMP types. If this function is used, the name (checked from a table in the scripts) will be incorrect for the listed
//types, but the names will be correct for all ICMP types.
int Type6to4(int icmp_type)
{
switch ( icmp_type ) //For these three values, the type number will be wrong if this is used!
{ //easy way to disable this is just to comment all the cases out, and leave only the default.
case ICMP6_DST_UNREACH: return ICMP_UNREACH; break;
case ICMP6_TIME_EXCEEDED: return ICMP_TIMXCEED; break;
case ICMP6_PARAM_PROB: return ICMP_PARAMPROB; break;
default: return icmp_type; break;
}
}
int Code6to4(int icmp_code) //not used yet for anything
{
switch ( icmp_code )
{
default: return icmp_code; break;
}
}

View file

@ -34,7 +34,7 @@ protected:
virtual bool IsReuse(double t, const u_char* pkt); virtual bool IsReuse(double t, const u_char* pkt);
virtual unsigned int MemoryAllocation() const; virtual unsigned int MemoryAllocation() const;
void ICMPEvent(EventHandlerPtr f, int ICMP6Flag); void ICMPEvent(EventHandlerPtr f, const struct icmp* icmpp, int len, int icmpv6);
void Echo(double t, const struct icmp* icmpp, int len, void Echo(double t, const struct icmp* icmpp, int len,
int caplen, const u_char*& data, const IP_Hdr* ip_hdr); int caplen, const u_char*& data, const IP_Hdr* ip_hdr);
@ -43,47 +43,40 @@ protected:
void Router(double t, const struct icmp* icmpp, int len, void Router(double t, const struct icmp* icmpp, int len,
int caplen, const u_char*& data, const IP_Hdr* ip_hdr); int caplen, const u_char*& data, const IP_Hdr* ip_hdr);
void Describe(ODesc* d) const; void Describe(ODesc* d) const;
RecordVal* BuildICMPVal(int ICMP6Flag); RecordVal* BuildICMPVal(const struct icmp* icmpp, int len, int icmpv6);
virtual void NextICMP(double t, const struct icmp* icmpp, void NextICMP4(double t, const struct icmp* icmpp, int len, int caplen,
int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr); const u_char*& data, const IP_Hdr* ip_hdr );
RecordVal* ExtractICMP4Context(int len, const u_char*& data); RecordVal* ExtractICMP4Context(int len, const u_char*& data);
void Context4(double t, const struct icmp* icmpp, int len, int caplen,
const u_char*& data, const IP_Hdr* ip_hdr);
TransportProto GetContextProtocol(const IP_Hdr* ip_hdr, uint32* src_port,
uint32* dst_port);
#ifdef BROv6
void NextICMP6(double t, const struct icmp* icmpp, int len, int caplen,
const u_char*& data, const IP_Hdr* ip_hdr );
RecordVal* ExtractICMP6Context(int len, const u_char*& data); RecordVal* ExtractICMP6Context(int len, const u_char*& data);
void Context6(double t, const struct icmp* icmpp, int len, int caplen,
const u_char*& data, const IP_Hdr* ip_hdr);
#endif
RecordVal* icmp_conn_val; RecordVal* icmp_conn_val;
int type;
int code;
int len;
int request_len, reply_len; int request_len, reply_len;
RuleMatcherState matcher_state; RuleMatcherState matcher_state;
}; };
/*class ICMP4_Analyzer : public ICMP_Analyzer {
};
class ICMP6_Analyzer : public ICMP_Analyzer {
};*/
// Returns the counterpart type to the given type (e.g., the counterpart // Returns the counterpart type to the given type (e.g., the counterpart
// to ICMP_ECHOREPLY is ICMP_ECHO). // to ICMP_ECHOREPLY is ICMP_ECHO).
//extern int ICMP_counterpart(int icmp_type, int icmp_code, bool& is_one_way);
extern int ICMP4_counterpart(int icmp_type, int icmp_code, bool& is_one_way); extern int ICMP4_counterpart(int icmp_type, int icmp_code, bool& is_one_way);
extern int ICMP6_counterpart(int icmp_type, int icmp_code, bool& is_one_way); extern int ICMP6_counterpart(int icmp_type, int icmp_code, bool& is_one_way);
extern int Type6to4(int icmp_type);
extern int Code6to4(int icmp_code);
#endif #endif

View file

@ -53,12 +53,12 @@ event udp_reply%(u: connection%);
event udp_contents%(u: connection, is_orig: bool, contents: string%); event udp_contents%(u: connection, is_orig: bool, contents: string%);
event udp_session_done%(u: connection%); event udp_session_done%(u: connection%);
event icmp_sent%(c: connection, icmp: icmp_conn, ICMP6: bool%); event icmp_sent%(c: connection, icmp: icmp_conn%);
event icmp_echo_request%(c: connection, icmp: icmp_conn, id: count, seq: count, payload: string, ICMP6: bool%); event icmp_echo_request%(c: connection, icmp: icmp_conn, id: count, seq: count, payload: string%);
event icmp_echo_reply%(c: connection, icmp: icmp_conn, id: count, seq: count, payload: string, ICMP6: bool%); event icmp_echo_reply%(c: connection, icmp: icmp_conn, id: count, seq: count, payload: string%);
event icmp_unreachable%(c: connection, icmp: icmp_conn, code: count, context: icmp_context%); event icmp_unreachable%(c: connection, icmp: icmp_conn, code: count, context: icmp_context%);
event icmp_error_message%(c: connection, icmp: icmp_conn, code: count, context: icmp_context%); event icmp_error_message%(c: connection, icmp: icmp_conn, code: count, context: icmp_context%);
event icmp_router_advertisement%(c: connection, icmp: icmp_conn, ICMP6: bool%); event icmp_router_advertisement%(c: connection, icmp: icmp_conn%);

View file

@ -86,14 +86,8 @@ int udp_checksum(const struct ip* ip, const struct udphdr* up, int len)
#ifdef BROv6 #ifdef BROv6
int udp6_checksum(const struct ip6_hdr* ip6, const struct udphdr* up, int len) int udp6_checksum(const struct ip6_hdr* ip6, const struct udphdr* up, int len)
{ {
/**From RFC for udp4 (same for udp6, except for different pseudoheader which is same as for icmp6) // UDP over IPv6 uses the same checksum function as over IPv4 but a
Computed as the 16-bit one's complement of the one's complement sum of a // different pseuod-header over which it is computed.
pseudo header of information from the IP header, the UDP header, and the
data, padded as needed with zero bytes at the end to make a multiple of
two bytes. If the checksum is cleared to zero, then checksuming is
disabled. If the computed checksum is zero, then this field must be set
to 0xFFFF.
**/
uint32 sum; uint32 sum;
if ( len % 2 == 1 ) if ( len % 2 == 1 )
@ -108,23 +102,18 @@ int udp6_checksum(const struct ip6_hdr* ip6, const struct udphdr* up, int len)
uint32 l = htonl(len); uint32 l = htonl(len);
sum = ones_complement_checksum((void*) &l, 4, sum); sum = ones_complement_checksum((void*) &l, 4, sum);
uint32 addl_pseudo = htons(IPPROTO_UDP); uint32 addl_pseudo = htons(IPPROTO_UDP);
sum = ones_complement_checksum((void*) &addl_pseudo, 4, sum); sum = ones_complement_checksum((void*) &addl_pseudo, 4, sum);
sum = ones_complement_checksum((void*) up, len, sum); sum = ones_complement_checksum((void*) up, len, sum);
//printf("checksum, calculated for UDP6: %d\n",sum);
return sum; return sum;
} }
int icmp6_checksum(const struct icmp* icmpp, const struct ip6_hdr* ip6, int len) int icmp6_checksum(const struct icmp* icmpp, const struct ip6_hdr* ip6, int len)
{ {
/**From RFC // ICMP6 uses the same checksum function as over ICMP4 but a different
Checksum that covers the ICMPv6 message. This field contains the 16-bit one's // pseuod-header over which it is computed.
complement of the one's complement sum of the entire ICMPv6 message starting
with the ICMPv6 message type field, prepended with a pseudo-header of IPv6
header fields.
**/
uint32 sum; uint32 sum;
if ( len % 2 == 1 ) if ( len % 2 == 1 )
@ -133,19 +122,17 @@ int icmp6_checksum(const struct icmp* icmpp, const struct ip6_hdr* ip6, int len)
else else
sum = 0; sum = 0;
//pseudoheader as in udp6 above // Pseudo-header as for UDP over IPv6 above.
sum = ones_complement_checksum((void*) ip6->ip6_src.s6_addr, 16, sum); sum = ones_complement_checksum((void*) ip6->ip6_src.s6_addr, 16, sum);
sum = ones_complement_checksum((void*) ip6->ip6_dst.s6_addr, 16, sum); sum = ones_complement_checksum((void*) ip6->ip6_dst.s6_addr, 16, sum);
uint32 l = htonl(len); uint32 l = htonl(len);
sum = ones_complement_checksum((void*) &l, 4, sum); sum = ones_complement_checksum((void*) &l, 4, sum);
uint32 addl_pseudo = htons(IPPROTO_ICMPV6); uint32 addl_pseudo = htons(IPPROTO_ICMPV6);
sum = ones_complement_checksum((void*) &addl_pseudo, 4, sum); sum = ones_complement_checksum((void*) &addl_pseudo, 4, sum);
//pseudoheader complete
sum = ones_complement_checksum((void*) icmpp, len, sum); sum = ones_complement_checksum((void*) icmpp, len, sum);
//printf("checksum, calculated for ICMP6: %d\n",sum);
return sum; return sum;
} }
@ -153,12 +140,6 @@ int icmp6_checksum(const struct icmp* icmpp, const struct ip6_hdr* ip6, int len)
int icmp_checksum(const struct icmp* icmpp, int len) int icmp_checksum(const struct icmp* icmpp, int len)
{ {
/**From RFC
Checksum that covers the ICMP message. This is the 16-bit one's
complement of the one's complement sum of the ICMP message starting
with the Type field. The checksum field should be cleared to zero
before generating the checksum.
**/
uint32 sum; uint32 sum;
if ( len % 2 == 1 ) if ( len % 2 == 1 )
// Add in pad byte. // Add in pad byte.
@ -168,15 +149,9 @@ int icmp_checksum(const struct icmp* icmpp, int len)
sum = ones_complement_checksum((void*) icmpp, len, sum); sum = ones_complement_checksum((void*) icmpp, len, sum);
//printf("checksum, calculated for ICMP4: %d\n",sum);
return sum; return sum;
} }
#define CLASS_A 0x00000000 #define CLASS_A 0x00000000
#define CLASS_B 0x80000000 #define CLASS_B 0x80000000
#define CLASS_C 0xc0000000 #define CLASS_C 0xc0000000

View file

@ -88,12 +88,14 @@ extern int ones_complement_checksum(const void* p, int b, uint32 sum);
extern int tcp_checksum(const struct ip* ip, const struct tcphdr* tp, int len); extern int tcp_checksum(const struct ip* ip, const struct tcphdr* tp, int len);
extern int udp_checksum(const struct ip* ip, const struct udphdr* up, int len); extern int udp_checksum(const struct ip* ip, const struct udphdr* up, int len);
extern int icmp_checksum(const struct icmp* icmpp, int len);
#ifdef BROv6 #ifdef BROv6
extern int udp6_checksum(const struct ip6_hdr* ip, const struct udphdr* up, extern int udp6_checksum(const struct ip6_hdr* ip, const struct udphdr* up,
int len); int len);
extern int icmp6_checksum(const struct icmp* icmpp, const struct ip6_hdr* ip6, int len); extern int icmp6_checksum(const struct icmp* icmpp, const struct ip6_hdr* ip6,
int len);
#endif #endif
extern int icmp_checksum(const struct icmp* icmpp, int len);
// Given an address in host order, returns its "classical network prefix", // Given an address in host order, returns its "classical network prefix",
// also in host order. // also in host order.