Porting Matti's branch to git.

No changes.
This commit is contained in:
Robin Sommer 2011-01-13 14:58:53 -08:00
parent 5d41794034
commit cb64bb6874
14 changed files with 795 additions and 154 deletions

@ -1 +1 @@
Subproject commit a05be1242b4e06dca1bb1a38ed871e7e2d78181b
Subproject commit 0d8b64252f00f147f31f5e8c02a6a710699b67d9

View file

@ -38,11 +38,12 @@ type icmp_context: record {
id: conn_id;
len: count;
proto: count;
frag_offset: count;
bad_hdr_len: bool;
bad_checksum: bool;
MF: bool;
DF: bool;
frag_offset: count &optional; #no frag offset for IPv6
bad_hdr_len: bool &optional;
bad_checksum: bool &optional; #no checksum in IPv6 header
MF: bool &optional; #no MF for IPv6
DF: bool &optional; #no DF for IPv6
ICMP6Flag: bool;
};
type addr_set: set[addr];
@ -534,6 +535,7 @@ const IPPROTO_IGMP = 2; # group mgmt protocol
const IPPROTO_IPIP = 4; # IP encapsulation in IP
const IPPROTO_TCP = 6; # TCP
const IPPROTO_UDP = 17; # user datagram protocol
const IPPROTO_ICMPV6 = 58; # ICMP for IPv6
const IPPROTO_RAW = 255; # raw IP packet
type ip_hdr: record {

View file

@ -1,4 +1,5 @@
# $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 weird
@ -55,8 +56,16 @@ type flow_info: record {
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 = {
[0] = "echo_reply",
[1] = "unreach", #icmpv6
[2] = "too_big", #icmpv6
[3] = "unreach",
[4] = "quench",
[5] = "redirect",
@ -71,6 +80,33 @@ const names: table[count] of string = {
[16] = "info_reply",
[17] = "mask_req",
[18] = "mask_reply",
[128] = "echo_req", #icmpv6
[129] = "echo_reply", #icmpv6
[130] = "group_memb_query", #icmpv6
[131] = "group_memb_report", #icmpv6
[132] = "group_memb_reduct", #icmpv6
[133] = "router_sol", #icmpv6
[134] = "router_ad", #icmpv6
[135] = "neighbor_sol", #icmpv6
[136] = "neighbor_ad", #icmpv6
[137] = "redirect", #icmpv6
[138] = "router_renum", #icmpv6
[139] = "node_info_query", #icmpv6
[140] = "node_info_resp", #icmpv6
[141] = "inv_neigh_disc_sol", #icmpv6
[142] = "inv_neigh_disc_ad", #icmpv6
[143] = "mul_lis_report", #icmpv6
[144] = "home_agent_addr_req", #icmpv6
[145] = "home_agent_addr_reply",#icmpv6
[146] = "mobible_prefx_sol", #icmpv6
[147] = "mobible_prefx_ad", #icmpv6
[148] = "cert_path_sol", #icmpv6
[149] = "cert_path_ad", #icmpv6
[150] = "experimental", #icmpv6
[151] = "mcast_router_ad", #icmpv6
[152] = "mcast_router_sol", #icmpv6
[153] = "mcast_router_term", #icmpv6
[154] = "fmip", #icmpv6
} &default = function(n: count): string { return fmt("icmp-%d", n); };
@ -80,7 +116,8 @@ const IP_proto_name: table[count] of string = {
[2] = "IGMP",
[6] = "TCP",
[17] = "UDP",
[41] = "IPV6",
[41] = "IP6",
[58] = "ICMP6",
} &default = function(n: count): string { return fmt("%s", n); }
&redef;
@ -123,12 +160,13 @@ global flows: table[flow_id] of flow_info
&read_expire = 45 sec
&expire_func = flush_flow;
event icmp_sent(c: connection, icmp: icmp_conn)
event icmp_sent(c: connection, icmp: icmp_conn, ICMP6: bool)
{
print icmp_file, fmt("%.6f %.6f %s %s %s %s %s %s %s %s %s",
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");
icmp$len, "0", "SH", ICMP6);
}
event flow_summary(flow: flow_id, last_time: time)
@ -173,13 +211,64 @@ function update_flow(icmp: icmp_conn, id: count, is_orig: bool, payload: string)
schedule +30sec { flow_summary(fid, fi$last_time) };
}
event icmp_echo_request(c: connection, icmp: icmp_conn, id: count, seq: count, 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
{
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 )
{
# 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);
local orig = icmp$orig_h;
local resp = icmp$resp_h;
# Simple ping scan detector.
if ( detect_scans &&
(orig !in Scan::distinct_peers ||
@ -231,7 +320,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,
seq: count, payload: string)
seq: count, payload: string, ICMP6: bool)
{
# Check payload with the associated flow.
@ -240,6 +329,8 @@ event icmp_echo_reply(c: connection, icmp: icmp_conn, id: count,
fid$resp_h = icmp$orig_h; # it's an echo reply.
fid$id = id;
if ( fid !in flows )
{
# NOTICE([$note=ICMPUnpairedEchoReply,
@ -266,9 +357,12 @@ event icmp_echo_reply(c: connection, icmp: icmp_conn, id: count,
update_flow(icmp, id, F, payload);
}
event icmp_unreachable(c: connection, icmp: icmp_conn, code: count,
context: icmp_context)
{
if ( active_connection(context$id) )
{
# This section allows Bro to act on ICMP-unreachable packets
@ -292,7 +386,7 @@ event icmp_unreachable(c: connection, icmp: icmp_conn, code: count,
# 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",
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:",
@ -301,6 +395,40 @@ event icmp_unreachable(c: connection, icmp: icmp_conn, code: count,
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$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,7 +48,7 @@ const Analyzer::Config Analyzer::analyzer_configs[] = {
{ AnalyzerTag::ICMP, "ICMP", ICMP_Analyzer::InstantiateAnalyzer,
ICMP_Analyzer::Available, 0, false },
{ AnalyzerTag::ICMP_TimeExceeded, "ICMP_TIMEEXCEEDED",
/*{ AnalyzerTag::ICMP_TimeExceeded, "ICMP_TIMEEXCEEDED",
ICMP_TimeExceeded_Analyzer::InstantiateAnalyzer,
ICMP_TimeExceeded_Analyzer::Available, 0, false },
{ AnalyzerTag::ICMP_Unreachable, "ICMP_UNREACHABLE",
@ -56,7 +56,11 @@ const Analyzer::Config Analyzer::analyzer_configs[] = {
ICMP_Unreachable_Analyzer::Available, 0, false },
{ AnalyzerTag::ICMP_Echo, "ICMP_ECHO",
ICMP_Echo_Analyzer::InstantiateAnalyzer,
ICMP_Echo_Analyzer::Available, 0, false },
ICMP_Echo_Analyzer::Available, 0, false },*/
{ AnalyzerTag::TCP, "TCP", TCP_Analyzer::InstantiateAnalyzer,
TCP_Analyzer::Available, 0, false },

View file

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

View file

@ -215,7 +215,10 @@ bool DPM::BuildInitialAnalyzerTree(TransportProto proto, Connection* conn,
case TRANSPORT_ICMP: {
const struct icmp* icmpp = (const struct icmp *) data;
switch ( icmpp->icmp_type ) {
//Old code, moving to having only one ICMP analyzer
/*switch ( icmpp->icmp_type ) {
case ICMP_ECHO:
case ICMP_ECHOREPLY:
@ -241,10 +244,11 @@ bool DPM::BuildInitialAnalyzerTree(TransportProto proto, Connection* conn,
DBG_DPD(conn, "activated ICMP Time Exceeded analyzer");
}
break;
}
}*/
//if ( ! root )
if ( ! root )
root = new ICMP_Analyzer(conn);
root = new ICMP_Analyzer(conn);
DBG_DPD(conn, "activated ICMP analyzer");
analyzed = true;
break;

View file

@ -9,12 +9,17 @@
#include "Event.h"
#include "ICMP.h"
#include <netinet/icmp6.h>
ICMP_Analyzer::ICMP_Analyzer(Connection* c)
: TransportLayerAnalyzer(AnalyzerTag::ICMP, c)
{
icmp_conn_val = 0;
c->SetInactivityTimeout(icmp_inactivity_timeout);
request_len = reply_len = -1;
}
ICMP_Analyzer::ICMP_Analyzer(AnalyzerTag::Tag tag, Connection* c)
@ -45,16 +50,43 @@ void ICMP_Analyzer::DeliverPacket(int arg_len, const u_char* data,
// Subtract off the common part of ICMP header.
PacketContents(data + 8, min(len, caplen) - 8);
const struct icmp* icmpp = (const struct icmp*) data;
len = arg_len;
if ( ! ignore_checksums && caplen >= len &&
icmp_checksum(icmpp, len) != 0xffff )
//We need a separate calculation for ICMP6 checksums, pseudoheader is appended to the
//ICMP6 checksum calculation, which is different from ICMP4
#ifdef BROv6
if (ip->NextProto() == IPPROTO_ICMPV6 && ! ignore_checksums &&
caplen >= len && icmp6_checksum(icmpp,ip->IP6_Hdr(),len )!= 0xffff )
{
Weird("bad_ICMP6_checksum");
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);
if ( rule_matcher )
@ -66,7 +98,7 @@ void ICMP_Analyzer::DeliverPacket(int arg_len, const u_char* data,
type = icmpp->icmp_type;
code = icmpp->icmp_code;
// Move past common portion of ICMP header.
// Move past common portion of ICMP header. //OK for ICMPv6?
data += 8;
caplen -= 8;
len -= 8;
@ -77,33 +109,113 @@ void ICMP_Analyzer::DeliverPacket(int arg_len, const u_char* data,
else
len_stat += len;
NextICMP(current_timestamp, icmpp, len, caplen, data);
NextICMP(current_timestamp, icmpp, len, caplen, data, ip);
if ( rule_matcher )
matcher_state.Match(Rule::PAYLOAD, data, len, is_orig,
false, false, true);
}
void ICMP_Analyzer::NextICMP(double /* t */, const struct icmp* /* icmpp */,
int /* len */, int /* caplen */,
const u_char*& /* data */)
{
ICMPEvent(icmp_sent);
}
void ICMP_Analyzer::ICMPEvent(EventHandlerPtr f)
{
/********************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 )
{
int ICMP6Flag = 0;
//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_ECHOREPLY:
Echo(t, icmpp, len, caplen, data, ip_hdr);
break;
case ICMP_UNREACH:
case ICMP_TIMXCEED:
Context(t, icmpp, len, caplen, data, ip_hdr);
break;
default: ICMPEvent(icmp_sent, ICMP6Flag); break;
}
}
else
Weird("Malformed ip header");
}
void ICMP_Analyzer::ICMPEvent(EventHandlerPtr f, int ICMP6Flag)
{
if ( ! f )
return;
return;
val_list* vl = new val_list;
vl->append(BuildConnVal());
vl->append(BuildICMPVal());
vl->append(BuildICMPVal(ICMP6Flag));
//if ( f == icmp_sent ) //for now, testing purposes
vl->append(new Val(ICMP6Flag, TYPE_BOOL));
ConnectionEvent(f, vl);
}
RecordVal* ICMP_Analyzer::BuildICMPVal()
RecordVal* ICMP_Analyzer::BuildICMPVal(int ICMP6Flag)
{
if ( ! icmp_conn_val )
{
@ -111,7 +223,13 @@ RecordVal* ICMP_Analyzer::BuildICMPVal()
icmp_conn_val->Assign(0, new AddrVal(Conn()->OrigAddr()));
icmp_conn_val->Assign(1, new AddrVal(Conn()->RespAddr()));
icmp_conn_val->Assign(2, new Val(type, TYPE_COUNT));
if ( ICMP6Flag == 1 )
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));
}
@ -121,48 +239,170 @@ RecordVal* ICMP_Analyzer::BuildICMPVal()
return icmp_conn_val;
}
RecordVal* ICMP_Analyzer::ExtractICMPContext(int len, const u_char*& data)
RecordVal* ICMP_Analyzer::ExtractICMP4Context(int len, const u_char*& data)
{
const struct ip* ip = (const struct ip *) data;
uint32 ip_hdr_len = ip->ip_hl * 4;
/**
* 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 = &ip_hdr_data;
int ICMP6Flag = 0;
uint32 ip_hdr_len = ip_hdr->HdrLen();
uint32 ip_len, frag_offset;
TransportProto proto = TRANSPORT_UNKNOWN;
int DF, MF, bad_hdr_len, bad_checksum;
uint32 src_addr, dst_addr;
uint32 src_addr, dst_addr,src_addr2, dst_addr2;
uint32 src_port, dst_port;
if ( ip_hdr_len < sizeof(struct ip) || ip_hdr_len > uint32(len) )
{ // We don't have an entire IP header.
if ( ip_hdr_len < sizeof(struct ip) || ip_hdr_len > uint32(len) )
{ // We don't have an entire IP header.
bad_hdr_len = 1;
ip_len = frag_offset = 0;
DF = MF = bad_checksum = 0;
src_addr = dst_addr = 0;
src_port = dst_port = 0;
}
else
{
bad_hdr_len = 0;
ip_len = ip_hdr->TotalLen();
bad_checksum = ones_complement_checksum((void*) ip_hdr->IP4_Hdr(), ip_hdr_len, 0) != 0xffff;
src_addr = ip_hdr->SrcAddr4();
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();
DF = ip_hdr->DF();
MF = frag_field & 0x2000;
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 ) //what is this value for ipv6?
{
// 4 above is the magic number meaning that both
// port numbers are included in the ICMP.
bad_hdr_len = 1;
src_port = dst_port = 0;
}
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);
}
}
RecordVal* iprec = new RecordVal(icmp_context);
RecordVal* id_val = new RecordVal(conn_id);
id_val->Assign(0, new AddrVal(src_addr));
id_val->Assign(1, new PortVal(src_port, proto));
id_val->Assign(2, new AddrVal(dst_addr));
id_val->Assign(3, new PortVal(dst_port, proto));
iprec->Assign(0, id_val);
iprec->Assign(1, new Val(ip_len, TYPE_COUNT));
iprec->Assign(2, new Val(proto, TYPE_COUNT));
iprec->Assign(3, new Val(frag_offset, TYPE_COUNT));
iprec->Assign(4, new Val(bad_hdr_len, TYPE_BOOL));
iprec->Assign(5, new Val(bad_checksum, TYPE_BOOL));
iprec->Assign(6, new Val(MF, TYPE_BOOL));
iprec->Assign(7, new Val(DF, TYPE_BOOL));
iprec->Assign(8, new Val(ICMP6Flag, TYPE_BOOL));
return iprec;
}
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 = &ip_hdr_data;
int ICMP6Flag = 1;
int DF = 0, MF = 0, bad_hdr_len = 0, bad_checksum = 0;
uint32 ip_hdr_len = ip_hdr->HdrLen(); //should always be 40
uint32* src_addr;
uint32* dst_addr;
uint32 ip_len, frag_offset = 0;
TransportProto proto = TRANSPORT_UNKNOWN;
uint32 src_port, dst_port;
if ( ip_hdr_len < sizeof(struct ip6_hdr) || ip_hdr_len != 40 )
{
bad_hdr_len = 1;
ip_len = frag_offset = 0;
DF = MF = bad_checksum = 0;
ip_len = 0;
src_addr = dst_addr = 0;
src_port = dst_port = 0;
}
else
{
bad_hdr_len = 0;
ip_len = ntohs(ip->ip_len);
bad_checksum = ones_complement_checksum((void*) ip, ip_hdr_len, 0) != 0xffff;
ip_len = ip_hdr->TotalLen();
src_addr = uint32(ip->ip_src.s_addr);
dst_addr = uint32(ip->ip_dst.s_addr);
src_addr = (uint32 *) ip_hdr->SrcAddr();
dst_addr = (uint32 *) ip_hdr->DstAddr();
switch ( ip->ip_p ) {
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; break; //TransportProto Hack
// Default uses TRANSPORT_UNKNOWN, per initialization above.
}
uint32 frag_field = ntohs(ip->ip_off);
DF = frag_field & 0x4000;
MF = frag_field & 0x2000;
frag_offset = frag_field & /* IP_OFFMASK not portable */ 0x1fff;
const u_char* transport_hdr = ((u_char *) ip + ip_hdr_len);
const u_char* transport_hdr = ((u_char *)ip_hdr->IP6_Hdr() + ip_hdr_len);
if ( uint32(len) < ip_hdr_len + 4 )
{
@ -179,7 +419,7 @@ RecordVal* ICMP_Analyzer::ExtractICMPContext(int len, const u_char*& data)
(const struct icmp *) transport_hdr;
bool is_one_way; // dummy
src_port = ntohs(icmpp->icmp_type);
dst_port = ntohs(ICMP_counterpart(icmpp->icmp_type,
dst_port = ntohs(ICMP6_counterpart(icmpp->icmp_type,
icmpp->icmp_code,
is_one_way));
}
@ -215,19 +455,42 @@ RecordVal* ICMP_Analyzer::ExtractICMPContext(int len, const u_char*& data)
id_val->Assign(1, new PortVal(src_port, proto));
id_val->Assign(2, new AddrVal(dst_addr));
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(2, new Val(proto, TYPE_COUNT));
iprec->Assign(3, new Val(frag_offset, TYPE_COUNT));
//TransportProto Hack
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));
}
else
{
iprec->Assign(2, new Val(proto, TYPE_COUNT));
}
iprec->Assign(3, new Val(frag_offset, TYPE_COUNT)); //NA for ip6
iprec->Assign(4, new Val(bad_hdr_len, TYPE_BOOL));
iprec->Assign(5, new Val(bad_checksum, TYPE_BOOL));
iprec->Assign(6, new Val(MF, TYPE_BOOL));
iprec->Assign(7, new Val(DF, TYPE_BOOL));
iprec->Assign(6, new Val(MF, TYPE_BOOL)); //NA for ip6
iprec->Assign(7, new Val(DF, TYPE_BOOL)); //NA for ip6
iprec->Assign(8, new Val(ICMP6Flag, TYPE_BOOL)); //ICMP6Flag
return iprec;
}
bool ICMP_Analyzer::IsReuse(double /* t */, const u_char* /* pkt */)
{
return 0;
@ -277,57 +540,156 @@ unsigned int ICMP_Analyzer::MemoryAllocation() const
+ (icmp_conn_val ? icmp_conn_val->MemoryAllocation() : 0);
}
ICMP_Echo_Analyzer::ICMP_Echo_Analyzer(Connection* c)
: ICMP_Analyzer(AnalyzerTag::ICMP_Echo, c)
{
}
void ICMP_Echo_Analyzer::NextICMP(double t, const struct icmp* icmpp, int len,
int caplen, const u_char*& data)
{
EventHandlerPtr f = type == ICMP_ECHO ? icmp_echo_request : icmp_echo_reply;
void ICMP_Analyzer::Echo(double t, const struct icmp* icmpp, int len,
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;
ICMP6Flag = 1;
}
else
f = type == ICMP_ECHO ? icmp_echo_request : icmp_echo_reply;
if ( ! f )
return;
int iid = ntohs(icmpp->icmp_hun.ih_idseq.icd_id);
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);
val_list* vl = new val_list;
vl->append(BuildConnVal());
vl->append(BuildICMPVal());
vl->append(BuildICMPVal(ICMP6Flag));
vl->append(new Val(iid, TYPE_COUNT));
vl->append(new Val(iseq, TYPE_COUNT));
vl->append(new StringVal(payload));
vl->append(new Val(ICMP6Flag, TYPE_BOOL));
ConnectionEvent(f, vl);
}
void ICMP_Context_Analyzer::NextICMP(double t, const struct icmp* icmpp,
int len, int caplen, const u_char*& data)
void ICMP_Analyzer::Router(double t, const struct icmp* icmpp, int len,
int caplen, const u_char*& data, const IP_Hdr* /*ip_hdr*/)
//For handling router related ICMP messages,
{
EventHandlerPtr f = 0;
switch ( type ) {
case ICMP_UNREACH: f = icmp_unreachable; break;
case ICMP_TIMXCEED: f = icmp_time_exceeded; break;
int ICMP6Flag = 1;
switch ( type )
{
case ND_ROUTER_ADVERT: f = icmp_router_advertisement; break;
case ND_REDIRECT:
case ND_ROUTER_SOLICIT:
case ICMP6_ROUTER_RENUMBERING:
default: ICMPEvent(icmp_sent,ICMP6Flag); return;
}
val_list* vl = new val_list;
vl->append(BuildConnVal());
vl->append(BuildICMPVal(ICMP6Flag));
vl->append(new Val(ICMP6Flag, TYPE_BOOL));
ConnectionEvent(f, vl);
}
if ( f )
{
val_list* vl = new val_list;
vl->append(BuildConnVal());
vl->append(BuildICMPVal());
vl->append(new Val(code, TYPE_COUNT));
vl->append(ExtractICMPContext(caplen, data));
ConnectionEvent(f, vl);
void ICMP_Analyzer::Context(double t, const struct icmp* icmpp,
int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr)
{//For handling the ICMP error messages
EventHandlerPtr f = 0;
int ICMP6Flag = 0;
if ( ip_hdr->NextProto() == IPPROTO_ICMPV6 ) //is ip6
{
ICMP6Flag = 1;
//printf("Executing: Context for ICMPv6\n");
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 )
{
val_list* vl = new val_list;
vl->append(BuildConnVal());
vl->append(BuildICMPVal(ICMP6Flag));
vl->append(new Val(code, TYPE_COUNT));
vl->append(ExtractICMP4Context(caplen, data));
ConnectionEvent(f, vl);
}
}
else
{
Weird("ICMP packet, invalid data\n"); //make this more descriptive
}
}
int ICMP_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;
@ -338,14 +700,77 @@ int ICMP_counterpart(int icmp_type, int icmp_code, bool& is_one_way)
switch ( icmp_type ) {
case ICMP_ECHO: return ICMP_ECHOREPLY;
case ICMP_ECHOREPLY: return ICMP_ECHO;
case ICMP_TSTAMP: return ICMP_TSTAMPREPLY;
case ICMP_TSTAMPREPLY: return ICMP_TSTAMP;
case ICMP_IREQ: return ICMP_IREQREPLY;
case ICMP_IREQREPLY: return ICMP_IREQ;
case ICMP_ROUTERSOLICIT: return ICMP_ROUTERADVERT;
case ICMP_MASKREQ: return ICMP_MASKREPLY;
case ICMP_MASKREPLY: return ICMP_MASKREQ;
default: is_one_way = true; return icmp_code;
}
}
int ICMP6_counterpart(int icmp_type, int icmp_code, bool& is_one_way)
{
is_one_way = false;
/**ICMP6 version of the ICMP4_counterpart, under work**/
//not yet used anywhere, for the context class
switch ( icmp_type ) {
case ICMP6_ECHO_REQUEST: return ICMP6_ECHO_REPLY;
case ICMP6_ECHO_REPLY: return ICMP6_ECHO_REQUEST;
case ND_ROUTER_SOLICIT: return ND_ROUTER_ADVERT;
case ND_ROUTER_ADVERT: return ND_ROUTER_SOLICIT;
case ND_NEIGHBOR_SOLICIT: return ND_NEIGHBOR_ADVERT;
case ND_NEIGHBOR_ADVERT: return ND_NEIGHBOR_SOLICIT;
case MLD_LISTENER_QUERY: return MLD_LISTENER_REPORT;
case MLD_LISTENER_REPORT: return MLD_LISTENER_QUERY;
case 139: return 140; //ICMP node information query and response respectively (not defined in icmp6.h)
case 140: return 139;
case 144: return 145; //Home Agent Address Discovery Request Message and reply
case 145: return 144;
//check the rest of the counterparts
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,15 +34,27 @@ protected:
virtual bool IsReuse(double t, const u_char* pkt);
virtual unsigned int MemoryAllocation() const;
void ICMPEvent(EventHandlerPtr f);
void ICMPEvent(EventHandlerPtr f, int ICMP6Flag);
void Echo(double t, const struct icmp* icmpp, int len,
int caplen, const u_char*& data, const IP_Hdr* ip_hdr);
void Context(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,
int caplen, const u_char*& data, const IP_Hdr* ip_hdr);
void Describe(ODesc* d) const;
RecordVal* BuildICMPVal();
RecordVal* BuildICMPVal(int ICMP6Flag);
virtual void NextICMP(double t, const struct icmp* icmpp,
int len, int caplen, const u_char*& data);
int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr);
RecordVal* ExtractICMP4Context(int len, const u_char*& data);
RecordVal* ExtractICMP6Context(int len, const u_char*& data);
RecordVal* ExtractICMPContext(int len, const u_char*& data);
RecordVal* icmp_conn_val;
int type;
@ -54,65 +66,24 @@ protected:
RuleMatcherState matcher_state;
};
class ICMP_Echo_Analyzer : public ICMP_Analyzer {
public:
ICMP_Echo_Analyzer(Connection* conn);
/*class ICMP4_Analyzer : public ICMP_Analyzer {
static Analyzer* InstantiateAnalyzer(Connection* conn)
{ return new ICMP_Echo_Analyzer(conn); }
static bool Available() { return icmp_echo_request || icmp_echo_reply; }
protected:
ICMP_Echo_Analyzer() { }
virtual void NextICMP(double t, const struct icmp* icmpp,
int len, int caplen, const u_char*& data);
};
class ICMP_Context_Analyzer : public ICMP_Analyzer {
public:
ICMP_Context_Analyzer(AnalyzerTag::Tag tag, Connection* conn)
: ICMP_Analyzer(tag, conn) { }
class ICMP6_Analyzer : public ICMP_Analyzer {
protected:
ICMP_Context_Analyzer() { }
virtual void NextICMP(double t, const struct icmp* icmpp,
int len, int caplen, const u_char*& data);
};
class ICMP_TimeExceeded_Analyzer : public ICMP_Context_Analyzer {
public:
ICMP_TimeExceeded_Analyzer(Connection* conn)
: ICMP_Context_Analyzer(AnalyzerTag::ICMP_TimeExceeded, conn) { }
static Analyzer* InstantiateAnalyzer(Connection* conn)
{ return new ICMP_TimeExceeded_Analyzer(conn); }
static bool Available() { return icmp_time_exceeded; }
protected:
ICMP_TimeExceeded_Analyzer() { }
};
class ICMP_Unreachable_Analyzer : public ICMP_Context_Analyzer {
public:
ICMP_Unreachable_Analyzer(Connection* conn)
: ICMP_Context_Analyzer(AnalyzerTag::ICMP_Unreachable, conn) { }
static Analyzer* InstantiateAnalyzer(Connection* conn)
{ return new ICMP_Unreachable_Analyzer(conn); }
static bool Available() { return icmp_unreachable; }
protected:
ICMP_Unreachable_Analyzer() { }
};
};*/
// Returns the counterpart type to the given type (e.g., the counterpart
// to ICMP_ECHOREPLY is ICMP_ECHO).
extern int ICMP_counterpart(int icmp_type, int icmp_code, bool& is_one_way);
//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 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

View file

@ -299,6 +299,7 @@ void NetSessions::NextPacket(double t, const struct pcap_pkthdr* hdr,
}
const struct ip* ip = (const struct ip*) (pkt + hdr_size);
if ( ip->ip_v == 4 )
{
IP_Hdr ip_hdr(ip);
@ -332,6 +333,8 @@ void NetSessions::NextPacketSecondary(double /* t */, const struct pcap_pkthdr*
++num_packets_processed;
uint32 caplen = hdr->caplen - hdr_size;
if ( caplen < sizeof(struct ip) )
{
@ -459,7 +462,7 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
int proto = ip_hdr->NextProto();
if ( proto != IPPROTO_TCP && proto != IPPROTO_UDP &&
proto != IPPROTO_ICMP )
proto != IPPROTO_ICMP && proto != IPPROTO_ICMPV6) // Added ICMPV6, Matti
{
dump_this_packet = 1;
return;
@ -530,7 +533,7 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
caplen -= ip_hdr_len;
uint32 min_hdr_len = (proto == IPPROTO_TCP) ? sizeof(struct tcphdr) :
(proto == IPPROTO_UDP ? sizeof(struct udphdr) : ICMP_MINLEN);
(proto == IPPROTO_UDP ? sizeof(struct udphdr) : ICMP_MINLEN); //needs checking for ICMPV6?, Matti
if ( len < min_hdr_len )
{
@ -582,7 +585,7 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
const struct icmp* icmpp = (const struct icmp *) data;
id.src_port = icmpp->icmp_type;
id.dst_port = ICMP_counterpart(icmpp->icmp_type,
id.dst_port = ICMP4_counterpart(icmpp->icmp_type,
icmpp->icmp_code,
id.is_one_way);
@ -593,6 +596,23 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
break;
}
case IPPROTO_ICMPV6: // new case, identical to ICMP, is this correct?? Matti
{
const struct icmp* icmpp = (const struct icmp *) data;
id.src_port = icmpp->icmp_type;
//printf("TYPE: %d\n", id.src_port); //testing, Matti
id.dst_port = ICMP6_counterpart(icmpp->icmp_type,
icmpp->icmp_code,
id.is_one_way);
id.src_port = htons(id.src_port);
id.dst_port = htons(id.dst_port);
d = &icmp_conns;
break;
}
default:
Weird(fmt("unknown_protocol %d", proto), hdr, pkt);
return;
@ -611,6 +631,8 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
else
{
conn = (Connection*) d->Lookup(h);
if ( ! conn )
{
conn = NewConn(h, t, &id, data, proto);
@ -620,6 +642,9 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
else
{
// We already know that connection.
int consistent = CheckConnectionTag(conn);
if ( consistent < 0 )
{
@ -773,6 +798,19 @@ Val* NetSessions::BuildHeader(const struct ip* ip)
break;
}
case IPPROTO_ICMPV6: //Added, Matti
{
const struct icmp* icmpp = (const struct icmp *) data;
RecordVal* icmp_hdr = new RecordVal(icmp_hdr_type);
//printf("datalen:%d",data_len); //Testing, Matti
icmp_hdr->Assign(0, new Val(icmpp->icmp_type, TYPE_COUNT));
pkt_hdr->Assign(3, icmp_hdr);
break;
}
default:
{
// This is not a protocol we understand.
@ -968,7 +1006,7 @@ void NetSessions::Remove(Connection* c)
;
else if ( ! tcp_conns.RemoveEntry(k) )
internal_error("connection missing");
internal_error(fmt("connection missing"));
break;
case TRANSPORT_UDP:
@ -1157,6 +1195,9 @@ Connection* NetSessions::NewConn(HashKey* k, double t, const ConnID* id,
case IPPROTO_UDP:
tproto = TRANSPORT_UDP;
break;
case IPPROTO_ICMPV6: //TransportProto Hack
tproto = TRANSPORT_ICMP;
break;
default:
internal_error("unknown transport protocol");
break;
@ -1242,7 +1283,6 @@ bool NetSessions::IsLikelyServerPort(uint32 port, TransportProto proto) const
port |= UDP_PORT_MASK;
else if ( proto == TRANSPORT_ICMP )
port |= ICMP_PORT_MASK;
return port_cache.find(port) != port_cache.end();
}

View file

@ -872,7 +872,6 @@ PortVal::PortVal(uint32 p, TransportProto port_type) : Val(TYPE_PORT)
case TRANSPORT_ICMP:
p |= ICMP_PORT_MASK;
break;
default:
break; // "other"
}

View file

@ -513,9 +513,10 @@ protected:
#define NUM_PORT_SPACES 4
#define PORT_SPACE_MASK 0x30000
#define TCP_PORT_MASK 0x10000
#define UDP_PORT_MASK 0x20000
#define ICMP_PORT_MASK 0x30000
#define TCP_PORT_MASK 0x10000
#define UDP_PORT_MASK 0x20000
#define ICMP_PORT_MASK 0x30000
typedef enum {
TRANSPORT_UNKNOWN, TRANSPORT_TCP, TRANSPORT_UDP, TRANSPORT_ICMP,
@ -537,6 +538,7 @@ public:
int IsUDP() const;
int IsICMP() const;
TransportProto PortType() const
{
if ( IsTCP() )

View file

@ -52,11 +52,21 @@ event udp_request%(u: connection%);
event udp_reply%(u: connection%);
event udp_contents%(u: connection, is_orig: bool, contents: string%);
event udp_session_done%(u: connection%);
event icmp_sent%(c: connection, icmp: icmp_conn%);
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%);
event icmp_sent%(c: connection, icmp: icmp_conn, ICMP6: bool%);
event icmp_echo_request%(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, ICMP6: bool%);
event icmp_unreachable%(c: connection, icmp: icmp_conn, code: count, context: icmp_context%);
event icmp_time_exceeded%(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 icmp6_placeholder%(c: connection, icmp: icmp_conn, ICMP6: bool%);
event net_stats_update%(t: time, ns: net_stats%);
event conn_stats%(c: connection, os: endpoint_stats, rs: endpoint_stats%);
event conn_weird%(name: string, c: connection%);

View file

@ -86,6 +86,14 @@ int udp_checksum(const struct ip* ip, const struct udphdr* up, int len)
#ifdef BROv6
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)
Computed as the 16-bit one's complement of the one's complement sum of a
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;
if ( len % 2 == 1 )
@ -97,19 +105,61 @@ int udp6_checksum(const struct ip6_hdr* ip6, const struct udphdr* up, int len)
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*) &len, 4, sum);
uint32 l = htonl(len);
sum = ones_complement_checksum((void*) &l, 4, sum);
uint32 addl_pseudo = htons(IPPROTO_UDP);
sum = ones_complement_checksum((void*) &addl_pseudo, 4, sum);
sum = ones_complement_checksum((void*) up, len, sum);
//printf("checksum, calculated for UDP6: %d\n",sum);
return sum;
}
int icmp6_checksum(const struct icmp* icmpp, const struct ip6_hdr* ip6, int len)
{
/**From RFC
Checksum that covers the ICMPv6 message. This field contains the 16-bit one's
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;
if ( len % 2 == 1 )
// Add in pad byte.
sum += htons(((const u_char*) icmpp)[len - 1] << 8);
else
sum = 0;
//pseudoheader as in udp6 above
sum = ones_complement_checksum((void*) ip6->ip6_src.s6_addr, 16, sum);
sum = ones_complement_checksum((void*) ip6->ip6_dst.s6_addr, 16, sum);
uint32 l = htonl(len);
sum = ones_complement_checksum((void*) &l, 4, sum);
uint32 addl_pseudo = htons(IPPROTO_ICMPV6);
sum = ones_complement_checksum((void*) &addl_pseudo, 4, sum);
//pseudoheader complete
sum = ones_complement_checksum((void*) icmpp, len, sum);
//printf("checksum, calculated for ICMP6: %d\n",sum);
return sum;
}
#endif
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;
if ( len % 2 == 1 )
// Add in pad byte.
sum = htons(((const u_char*) icmpp)[len - 1] << 8);
@ -118,10 +168,15 @@ int icmp_checksum(const struct icmp* icmpp, int len)
sum = ones_complement_checksum((void*) icmpp, len, sum);
//printf("checksum, calculated for ICMP4: %d\n",sum);
return sum;
}
#define CLASS_A 0x00000000
#define CLASS_B 0x80000000
#define CLASS_C 0xc0000000

View file

@ -91,6 +91,7 @@ extern int udp_checksum(const struct ip* ip, const struct udphdr* up, int len);
#ifdef BROv6
extern int udp6_checksum(const struct ip6_hdr* ip, const struct udphdr* up,
int len);
extern int icmp6_checksum(const struct icmp* icmpp, const struct ip6_hdr* ip6, int len);
#endif
extern int icmp_checksum(const struct icmp* icmpp, int len);