diff --git a/aux/broctl b/aux/broctl index a05be1242b..0d8b64252f 160000 --- a/aux/broctl +++ b/aux/broctl @@ -1 +1 @@ -Subproject commit a05be1242b4e06dca1bb1a38ed871e7e2d78181b +Subproject commit 0d8b64252f00f147f31f5e8c02a6a710699b67d9 diff --git a/policy/bro.init b/policy/bro.init index 1ba8f59b4d..e812db0075 100644 --- a/policy/bro.init +++ b/policy/bro.init @@ -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 { diff --git a/policy/icmp.bro b/policy/icmp.bro index c6c3c87d44..d75b2a3731 100644 --- a/policy/icmp.bro +++ b/policy/icmp.bro @@ -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); + } + + } + + + + + + + + + + + + + + diff --git a/src/Analyzer.cc b/src/Analyzer.cc index c323f99e23..a3f6bbfc2c 100644 --- a/src/Analyzer.cc +++ b/src/Analyzer.cc @@ -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 }, diff --git a/src/AnalyzerTags.h b/src/AnalyzerTags.h index 9bf3efbd3c..eb18a03a73 100644 --- a/src/AnalyzerTags.h +++ b/src/AnalyzerTags.h @@ -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, diff --git a/src/DPM.cc b/src/DPM.cc index 35111a38fa..7be9376b9f 100644 --- a/src/DPM.cc +++ b/src/DPM.cc @@ -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; diff --git a/src/ICMP.cc b/src/ICMP.cc index d73a9a781e..b83cf76a40 100644 --- a/src/ICMP.cc +++ b/src/ICMP.cc @@ -9,12 +9,17 @@ #include "Event.h" #include "ICMP.h" +#include + + + 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; + } + } + + diff --git a/src/ICMP.h b/src/ICMP.h index 43921f1aac..14f6971915 100644 --- a/src/ICMP.h +++ b/src/ICMP.h @@ -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 diff --git a/src/Sessions.cc b/src/Sessions.cc index fd443d4dcc..de0a1cb488 100644 --- a/src/Sessions.cc +++ b/src/Sessions.cc @@ -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(); } diff --git a/src/Val.cc b/src/Val.cc index 9a1ee700ff..66770cbdb1 100644 --- a/src/Val.cc +++ b/src/Val.cc @@ -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" } diff --git a/src/Val.h b/src/Val.h index 5a2faee9d7..b6effcb9e9 100644 --- a/src/Val.h +++ b/src/Val.h @@ -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() ) diff --git a/src/event.bif b/src/event.bif index 3171b02dde..ffee9244b7 100644 --- a/src/event.bif +++ b/src/event.bif @@ -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%); diff --git a/src/net_util.cc b/src/net_util.cc index e49d575fa0..4c57f12213 100644 --- a/src/net_util.cc +++ b/src/net_util.cc @@ -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 diff --git a/src/net_util.h b/src/net_util.h index 25b6b293fc..4c17104573 100644 --- a/src/net_util.h +++ b/src/net_util.h @@ -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);