mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
Improve handling of IPv6 routing type 0 extension headers.
- flow_weird event with name argument value of "routing0_hdr" is raised for packets containing an IPv6 routing type 0 header because this type of header is now deprecated according to RFC 5095. - packets with a routing type 0 header and non-zero segments left now use the last address in that header in order to associate with a connection/flow and for calculating TCP/UDP checksums. - added a set of IPv4/IPv6 TCP/UDP checksum unit tests
This commit is contained in:
parent
d889f14638
commit
f4101b5265
39 changed files with 171 additions and 121 deletions
|
@ -7,7 +7,6 @@
|
||||||
|
|
||||||
#include "List.h"
|
#include "List.h"
|
||||||
#include "BroList.h"
|
#include "BroList.h"
|
||||||
#include "net_util.h"
|
|
||||||
|
|
||||||
class Func;
|
class Func;
|
||||||
class FuncType;
|
class FuncType;
|
||||||
|
|
|
@ -28,7 +28,7 @@ void FragTimer::Dispatch(double t, int /* is_expire */)
|
||||||
FragReassembler::FragReassembler(NetSessions* arg_s,
|
FragReassembler::FragReassembler(NetSessions* arg_s,
|
||||||
const IP_Hdr* ip, const u_char* pkt,
|
const IP_Hdr* ip, const u_char* pkt,
|
||||||
HashKey* k, double t)
|
HashKey* k, double t)
|
||||||
: Reassembler(0, ip->DstAddr(), REASSEM_IP)
|
: Reassembler(0, REASSEM_IP)
|
||||||
{
|
{
|
||||||
s = arg_s;
|
s = arg_s;
|
||||||
key = k;
|
key = k;
|
||||||
|
|
14
src/IP.cc
14
src/IP.cc
|
@ -305,6 +305,20 @@ void IPv6_Hdr_Chain::Init(const struct ip6_hdr* ip6, bool set_next, uint16 next)
|
||||||
|
|
||||||
chain.push_back(p);
|
chain.push_back(p);
|
||||||
|
|
||||||
|
// Check for routing type 0 header.
|
||||||
|
if ( current_type == IPPROTO_ROUTING &&
|
||||||
|
((const struct ip6_rthdr*)hdrs)->ip6r_type == 0 )
|
||||||
|
{
|
||||||
|
if ( ((const struct ip6_rthdr*)hdrs)->ip6r_segleft > 0 )
|
||||||
|
// Remember the index for later so we can determine the final
|
||||||
|
// destination of the packet.
|
||||||
|
route0_hdr_idx = chain.size() - 1;
|
||||||
|
|
||||||
|
// RFC 5095 deprecates routing type 0 headers, so raise weirds
|
||||||
|
IPAddr src(((const struct ip6_hdr*)(chain[0]->Data()))->ip6_src);
|
||||||
|
reporter->Weird(src, FinalDst(), "routing0_hdr");
|
||||||
|
}
|
||||||
|
|
||||||
hdrs += len;
|
hdrs += len;
|
||||||
length += len;
|
length += len;
|
||||||
} while ( current_type != IPPROTO_FRAGMENT &&
|
} while ( current_type != IPPROTO_FRAGMENT &&
|
||||||
|
|
56
src/IP.h
56
src/IP.h
|
@ -117,7 +117,8 @@ public:
|
||||||
/**
|
/**
|
||||||
* Initializes the header chain from an IPv6 header structure.
|
* Initializes the header chain from an IPv6 header structure.
|
||||||
*/
|
*/
|
||||||
IPv6_Hdr_Chain(const struct ip6_hdr* ip6) { Init(ip6, false); }
|
IPv6_Hdr_Chain(const struct ip6_hdr* ip6) : route0_hdr_idx(0)
|
||||||
|
{ Init(ip6, false); }
|
||||||
|
|
||||||
~IPv6_Hdr_Chain()
|
~IPv6_Hdr_Chain()
|
||||||
{ for ( size_t i = 0; i < chain.size(); ++i ) delete chain[i]; }
|
{ for ( size_t i = 0; i < chain.size(); ++i ) delete chain[i]; }
|
||||||
|
@ -171,6 +172,27 @@ public:
|
||||||
{ return IsFragment() ?
|
{ return IsFragment() ?
|
||||||
(ntohs(GetFragHdr()->ip6f_offlg) & 0x0001) != 0 : 0; }
|
(ntohs(GetFragHdr()->ip6f_offlg) & 0x0001) != 0 : 0; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the final destination of the packet this chain belongs to.
|
||||||
|
* If the chain doesn't contain any routing type 0 header with non-zero
|
||||||
|
* segments left, this is the destination in the main IP header, else
|
||||||
|
* it's the last address in the routing header. (If there were to be
|
||||||
|
* more than one routing type 0 header with non-zero segments left, the
|
||||||
|
* last one would be the one referenced).
|
||||||
|
*/
|
||||||
|
IPAddr FinalDst() const
|
||||||
|
{
|
||||||
|
if ( route0_hdr_idx )
|
||||||
|
{
|
||||||
|
const struct in6_addr* a = (const struct in6_addr*)
|
||||||
|
(chain[route0_hdr_idx]->Data() +
|
||||||
|
chain[route0_hdr_idx]->Length() - 16);
|
||||||
|
return IPAddr(*a);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return IPAddr(((const struct ip6_hdr*)(chain[0]->Data()))->ip6_dst);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a vector of ip6_ext_hdr RecordVals that includes script-layer
|
* Returns a vector of ip6_ext_hdr RecordVals that includes script-layer
|
||||||
* representation of all extension headers in the chain.
|
* representation of all extension headers in the chain.
|
||||||
|
@ -186,13 +208,24 @@ protected:
|
||||||
* Initializes the header chain from an IPv6 header structure, and replaces
|
* Initializes the header chain from an IPv6 header structure, and replaces
|
||||||
* the first next protocol pointer field that points to a fragment header.
|
* the first next protocol pointer field that points to a fragment header.
|
||||||
*/
|
*/
|
||||||
IPv6_Hdr_Chain(const struct ip6_hdr* ip6, uint16 next)
|
IPv6_Hdr_Chain(const struct ip6_hdr* ip6, uint16 next) : route0_hdr_idx(0)
|
||||||
{ Init(ip6, true, next); }
|
{ Init(ip6, true, next); }
|
||||||
|
|
||||||
void Init(const struct ip6_hdr* ip6, bool set_next, uint16 next = 0);
|
void Init(const struct ip6_hdr* ip6, bool set_next, uint16 next = 0);
|
||||||
|
|
||||||
vector<IPv6_Hdr*> chain;
|
vector<IPv6_Hdr*> chain;
|
||||||
uint16 length; // The summation of all header lengths in the chain in bytes.
|
|
||||||
|
/**
|
||||||
|
* The summation of all header lengths in the chain in bytes.
|
||||||
|
*/
|
||||||
|
uint16 length;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Index of routing type 0 header with non-zero segments left in the header
|
||||||
|
* chain or zero if none exists (it's fine since the main IP header must
|
||||||
|
* always be at index zero).
|
||||||
|
*/
|
||||||
|
uint8 route0_hdr_idx;
|
||||||
};
|
};
|
||||||
|
|
||||||
class IP_Hdr {
|
class IP_Hdr {
|
||||||
|
@ -248,7 +281,22 @@ public:
|
||||||
IPAddr SrcAddr() const
|
IPAddr SrcAddr() const
|
||||||
{ return ip4 ? IPAddr(ip4->ip_src) : IPAddr(ip6->ip6_src); }
|
{ return ip4 ? IPAddr(ip4->ip_src) : IPAddr(ip6->ip6_src); }
|
||||||
|
|
||||||
IPAddr DstAddr() const
|
/**
|
||||||
|
* Returns the final destination address of the header's packet, which
|
||||||
|
* for IPv6 packets without a routing type 0 extension header and IPv4
|
||||||
|
* packets is the destination address in the IP header. For IPv6 packets
|
||||||
|
* with a routing type 0 extension header and a non-zero number of
|
||||||
|
* segments left, the final destination is the last address in the routing
|
||||||
|
* header. If the segments left of a routing type 0 header were zero,
|
||||||
|
* then the final destination is in the IP header itself.
|
||||||
|
*/
|
||||||
|
IPAddr FinalDstAddr() const
|
||||||
|
{ return ip4 ? IPAddr(ip4->ip_dst) : ip6_hdrs->FinalDst(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the destination address held in the IP header.
|
||||||
|
*/
|
||||||
|
IPAddr IPHeaderDstAddr() const
|
||||||
{ return ip4 ? IPAddr(ip4->ip_dst) : IPAddr(ip6->ip6_dst); }
|
{ return ip4 ? IPAddr(ip4->ip_dst) : IPAddr(ip6->ip6_dst); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -58,7 +58,7 @@ bool PacketFilter::Match(const IP_Hdr* ip, int len, int caplen)
|
||||||
if ( f )
|
if ( f )
|
||||||
return MatchFilter(*f, *ip, len, caplen);
|
return MatchFilter(*f, *ip, len, caplen);
|
||||||
|
|
||||||
f = (Filter*) dst_filter.Lookup(ip->DstAddr(), 128);
|
f = (Filter*) dst_filter.Lookup(ip->FinalDstAddr(), 128);
|
||||||
if ( f )
|
if ( f )
|
||||||
return MatchFilter(*f, *ip, len, caplen);
|
return MatchFilter(*f, *ip, len, caplen);
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ PacketSortElement::PacketSortElement(PktSrc* arg_src,
|
||||||
(pkt + tcp_offset);
|
(pkt + tcp_offset);
|
||||||
|
|
||||||
id.src_addr = ip_hdr->SrcAddr();
|
id.src_addr = ip_hdr->SrcAddr();
|
||||||
id.dst_addr = ip_hdr->DstAddr();
|
id.dst_addr = ip_hdr->FinalDstAddr();
|
||||||
id.src_port = tp->th_sport;
|
id.src_port = tp->th_sport;
|
||||||
id.dst_port = tp->th_dport;
|
id.dst_port = tp->th_dport;
|
||||||
id.is_one_way = 0;
|
id.is_one_way = 0;
|
||||||
|
|
|
@ -43,8 +43,7 @@ DataBlock::DataBlock(const u_char* data, int size, int arg_seq,
|
||||||
|
|
||||||
unsigned int Reassembler::total_size = 0;
|
unsigned int Reassembler::total_size = 0;
|
||||||
|
|
||||||
Reassembler::Reassembler(int init_seq, const IPAddr& ip_addr,
|
Reassembler::Reassembler(int init_seq, ReassemblerType arg_type)
|
||||||
ReassemblerType arg_type)
|
|
||||||
{
|
{
|
||||||
blocks = last_block = 0;
|
blocks = last_block = 0;
|
||||||
trim_seq = last_reassem_seq = init_seq;
|
trim_seq = last_reassem_seq = init_seq;
|
||||||
|
|
|
@ -26,8 +26,7 @@ enum ReassemblerType { REASSEM_IP, REASSEM_TCP };
|
||||||
|
|
||||||
class Reassembler : public BroObj {
|
class Reassembler : public BroObj {
|
||||||
public:
|
public:
|
||||||
Reassembler(int init_seq, const IPAddr& ip_addr,
|
Reassembler(int init_seq, ReassemblerType arg_type);
|
||||||
ReassemblerType arg_type);
|
|
||||||
virtual ~Reassembler();
|
virtual ~Reassembler();
|
||||||
|
|
||||||
void NewBlock(double t, int seq, int len, const u_char* data);
|
void NewBlock(double t, int seq, int len, const u_char* data);
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "net_util.h"
|
|
||||||
#include "EventHandler.h"
|
#include "EventHandler.h"
|
||||||
#include "IPAddr.h"
|
#include "IPAddr.h"
|
||||||
|
|
||||||
|
|
|
@ -1105,7 +1105,7 @@ void Packet::Describe(ODesc* d) const
|
||||||
const IP_Hdr ip = IP();
|
const IP_Hdr ip = IP();
|
||||||
d->Add(ip.SrcAddr());
|
d->Add(ip.SrcAddr());
|
||||||
d->Add("->");
|
d->Add("->");
|
||||||
d->Add(ip.DstAddr());
|
d->Add(ip.FinalDstAddr());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Packet::Serialize(SerialInfo* info) const
|
bool Packet::Serialize(SerialInfo* info) const
|
||||||
|
|
|
@ -493,7 +493,7 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
|
||||||
|
|
||||||
ConnID id;
|
ConnID id;
|
||||||
id.src_addr = ip_hdr->SrcAddr();
|
id.src_addr = ip_hdr->SrcAddr();
|
||||||
id.dst_addr = ip_hdr->DstAddr();
|
id.dst_addr = ip_hdr->FinalDstAddr();
|
||||||
Dictionary* d = 0;
|
Dictionary* d = 0;
|
||||||
|
|
||||||
switch ( proto ) {
|
switch ( proto ) {
|
||||||
|
@ -667,7 +667,7 @@ FragReassembler* NetSessions::NextFragment(double t, const IP_Hdr* ip,
|
||||||
|
|
||||||
ListVal* key = new ListVal(TYPE_ANY);
|
ListVal* key = new ListVal(TYPE_ANY);
|
||||||
key->Append(new AddrVal(ip->SrcAddr()));
|
key->Append(new AddrVal(ip->SrcAddr()));
|
||||||
key->Append(new AddrVal(ip->DstAddr()));
|
key->Append(new AddrVal(ip->FinalDstAddr()));
|
||||||
key->Append(new Val(frag_id, TYPE_COUNT));
|
key->Append(new Val(frag_id, TYPE_COUNT));
|
||||||
|
|
||||||
HashKey* h = ch->ComputeHash(key, 1);
|
HashKey* h = ch->ComputeHash(key, 1);
|
||||||
|
@ -1177,7 +1177,7 @@ void NetSessions::Weird(const char* name,
|
||||||
|
|
||||||
void NetSessions::Weird(const char* name, const IP_Hdr* ip)
|
void NetSessions::Weird(const char* name, const IP_Hdr* ip)
|
||||||
{
|
{
|
||||||
reporter->Weird(ip->SrcAddr(), ip->DstAddr(), name);
|
reporter->Weird(ip->SrcAddr(), ip->FinalDstAddr(), name);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int NetSessions::ConnectionMemoryUsage()
|
unsigned int NetSessions::ConnectionMemoryUsage()
|
||||||
|
|
|
@ -31,14 +31,6 @@ TCP_Endpoint::TCP_Endpoint(TCP_Analyzer* arg_analyzer, int arg_is_orig)
|
||||||
tcp_analyzer->Conn()->OrigAddr();
|
tcp_analyzer->Conn()->OrigAddr();
|
||||||
dst_addr = is_orig ? tcp_analyzer->Conn()->OrigAddr() :
|
dst_addr = is_orig ? tcp_analyzer->Conn()->OrigAddr() :
|
||||||
tcp_analyzer->Conn()->RespAddr();
|
tcp_analyzer->Conn()->RespAddr();
|
||||||
|
|
||||||
checksum_base = ones_complement_checksum(src_addr, 0);
|
|
||||||
checksum_base = ones_complement_checksum(dst_addr, checksum_base);
|
|
||||||
// Note, for IPv6, strictly speaking this field is 32 bits
|
|
||||||
// rather than 16 bits. But because the upper bits are all zero,
|
|
||||||
// we get the same checksum either way. The same applies to
|
|
||||||
// later when we add in the data length in ValidChecksum().
|
|
||||||
checksum_base += htons(IPPROTO_TCP);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TCP_Endpoint::~TCP_Endpoint()
|
TCP_Endpoint::~TCP_Endpoint()
|
||||||
|
@ -108,13 +100,21 @@ void TCP_Endpoint::SizeBufferedData(int& waiting_on_hole, int& waiting_on_ack)
|
||||||
|
|
||||||
int TCP_Endpoint::ValidChecksum(const struct tcphdr* tp, int len) const
|
int TCP_Endpoint::ValidChecksum(const struct tcphdr* tp, int len) const
|
||||||
{
|
{
|
||||||
uint32 sum = checksum_base;
|
uint32 sum;
|
||||||
int tcp_len = tp->th_off * 4 + len;
|
int tcp_len = tp->th_off * 4 + len;
|
||||||
|
|
||||||
if ( len % 2 == 1 )
|
if ( len % 2 == 1 )
|
||||||
// Add in pad byte.
|
// Add in pad byte.
|
||||||
sum += htons(((const u_char*) tp)[tcp_len - 1] << 8);
|
sum = htons(((const u_char*) tp)[tcp_len - 1] << 8);
|
||||||
|
else
|
||||||
|
sum = 0;
|
||||||
|
|
||||||
|
sum = ones_complement_checksum(src_addr, sum);
|
||||||
|
sum = ones_complement_checksum(dst_addr, sum);
|
||||||
|
// Note, for IPv6, strictly speaking the protocol and length fields are
|
||||||
|
// 32 bits rather than 16 bits. But because the upper bits are all zero,
|
||||||
|
// we get the same checksum either way.
|
||||||
|
sum += htons(IPPROTO_TCP);
|
||||||
sum += htons((unsigned short) tcp_len); // fill out pseudo header
|
sum += htons((unsigned short) tcp_len); // fill out pseudo header
|
||||||
sum = ones_complement_checksum((void*) tp, tcp_len, sum);
|
sum = ones_complement_checksum((void*) tp, tcp_len, sum);
|
||||||
|
|
||||||
|
|
|
@ -127,7 +127,6 @@ public:
|
||||||
TCP_Reassembler* contents_processor;
|
TCP_Reassembler* contents_processor;
|
||||||
TCP_Analyzer* tcp_analyzer;
|
TCP_Analyzer* tcp_analyzer;
|
||||||
BroFile* contents_file;
|
BroFile* contents_file;
|
||||||
uint32 checksum_base;
|
|
||||||
|
|
||||||
double start_time, last_time;
|
double start_time, last_time;
|
||||||
IPAddr src_addr; // the other endpoint
|
IPAddr src_addr; // the other endpoint
|
||||||
|
|
|
@ -29,7 +29,7 @@ TCP_Reassembler::TCP_Reassembler(Analyzer* arg_dst_analyzer,
|
||||||
TCP_Analyzer* arg_tcp_analyzer,
|
TCP_Analyzer* arg_tcp_analyzer,
|
||||||
TCP_Reassembler::Type arg_type,
|
TCP_Reassembler::Type arg_type,
|
||||||
bool arg_is_orig, TCP_Endpoint* arg_endp)
|
bool arg_is_orig, TCP_Endpoint* arg_endp)
|
||||||
: Reassembler(1, arg_endp->dst_addr, REASSEM_TCP)
|
: Reassembler(1, REASSEM_TCP)
|
||||||
{
|
{
|
||||||
dst_analyzer = arg_dst_analyzer;
|
dst_analyzer = arg_dst_analyzer;
|
||||||
tcp_analyzer = arg_tcp_analyzer;
|
tcp_analyzer = arg_tcp_analyzer;
|
||||||
|
|
32
src/UDP.cc
32
src/UDP.cc
|
@ -57,12 +57,14 @@ void UDP_Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig,
|
||||||
{
|
{
|
||||||
bool bad = false;
|
bool bad = false;
|
||||||
|
|
||||||
if ( ip->IP4_Hdr() && chksum &&
|
if ( ip->IP4_Hdr() )
|
||||||
udp_checksum(ip->IP4_Hdr(), up, len) != 0xffff )
|
{
|
||||||
bad = true;
|
if ( chksum && ! ValidateChecksum(ip, up, len) )
|
||||||
|
bad = true;
|
||||||
|
}
|
||||||
|
|
||||||
if ( ip->IP6_Hdr() && /* checksum is not optional for IPv6 */
|
/* checksum is not optional for IPv6 */
|
||||||
udp6_checksum(ip->IP6_Hdr(), up, len) != 0xffff )
|
else if ( ! ValidateChecksum(ip, up, len) )
|
||||||
bad = true;
|
bad = true;
|
||||||
|
|
||||||
if ( bad )
|
if ( bad )
|
||||||
|
@ -204,4 +206,24 @@ unsigned int UDP_Analyzer::MemoryAllocation() const
|
||||||
return Analyzer::MemoryAllocation() + padded_sizeof(*this) - 24;
|
return Analyzer::MemoryAllocation() + padded_sizeof(*this) - 24;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool UDP_Analyzer::ValidateChecksum(const IP_Hdr* ip, const udphdr* up, int len)
|
||||||
|
{
|
||||||
|
uint32 sum;
|
||||||
|
|
||||||
|
if ( len % 2 == 1 )
|
||||||
|
// Add in pad byte.
|
||||||
|
sum = htons(((const u_char*) up)[len - 1] << 8);
|
||||||
|
else
|
||||||
|
sum = 0;
|
||||||
|
|
||||||
|
sum = ones_complement_checksum(ip->SrcAddr(), sum);
|
||||||
|
sum = ones_complement_checksum(ip->FinalDstAddr(), sum);
|
||||||
|
// Note, for IPv6, strictly speaking the protocol and length fields are
|
||||||
|
// 32 bits rather than 16 bits. But because the upper bits are all zero,
|
||||||
|
// we get the same checksum either way.
|
||||||
|
sum += htons(IPPROTO_UDP);
|
||||||
|
sum += htons((unsigned short) len);
|
||||||
|
sum = ones_complement_checksum((void*) up, len, sum);
|
||||||
|
|
||||||
|
return sum == 0xffff;
|
||||||
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#define udp_h
|
#define udp_h
|
||||||
|
|
||||||
#include "Analyzer.h"
|
#include "Analyzer.h"
|
||||||
|
#include <netinet/udp.h>
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
UDP_INACTIVE, // no packet seen
|
UDP_INACTIVE, // no packet seen
|
||||||
|
@ -31,6 +32,10 @@ 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;
|
||||||
|
|
||||||
|
// Returns true if the checksum is valid, false if not
|
||||||
|
static bool ValidateChecksum(const IP_Hdr* ip, const struct udphdr* up,
|
||||||
|
int len);
|
||||||
|
|
||||||
bro_int_t request_len, reply_len;
|
bro_int_t request_len, reply_len;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -4798,6 +4798,9 @@ function uninstall_src_net_filter%(snet: subnet%) : bool
|
||||||
|
|
||||||
## Installs a filter to drop packets destined to a given IP address with
|
## Installs a filter to drop packets destined to a given IP address with
|
||||||
## a certain probability if none of a given set of TCP flags are set.
|
## a certain probability if none of a given set of TCP flags are set.
|
||||||
|
## Note that for IPv6 packets with a routing type 0 header and non-zero
|
||||||
|
## segments left, this filters out against the final destination of the
|
||||||
|
## packet according to the routing extension header.
|
||||||
##
|
##
|
||||||
## ip: Drop packets to this IP address.
|
## ip: Drop packets to this IP address.
|
||||||
##
|
##
|
||||||
|
|
|
@ -31,85 +31,6 @@ int ones_complement_checksum(const void* p, int b, uint32 sum)
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ones_complement_checksum(const IPAddr& a, uint32 sum)
|
|
||||||
{
|
|
||||||
const uint32* bytes;
|
|
||||||
int len = a.GetBytes(&bytes);
|
|
||||||
return ones_complement_checksum(bytes, len*4, sum);
|
|
||||||
}
|
|
||||||
|
|
||||||
int tcp_checksum(const struct ip* ip, const struct tcphdr* tp, int len)
|
|
||||||
{
|
|
||||||
// ### Note, this is only correct for IPv4. This routine is only
|
|
||||||
// used by the connection compressor (which we turn off for IPv6
|
|
||||||
// traffic).
|
|
||||||
|
|
||||||
int tcp_len = tp->th_off * 4 + len;
|
|
||||||
uint32 sum;
|
|
||||||
|
|
||||||
if ( len % 2 == 1 )
|
|
||||||
// Add in pad byte.
|
|
||||||
sum = htons(((const u_char*) tp)[tcp_len - 1] << 8);
|
|
||||||
else
|
|
||||||
sum = 0;
|
|
||||||
|
|
||||||
sum = ones_complement_checksum((void*) &ip->ip_src.s_addr, 4, sum);
|
|
||||||
sum = ones_complement_checksum((void*) &ip->ip_dst.s_addr, 4, sum);
|
|
||||||
|
|
||||||
uint32 addl_pseudo =
|
|
||||||
(htons(IPPROTO_TCP) << 16) | htons((unsigned short) tcp_len);
|
|
||||||
|
|
||||||
sum = ones_complement_checksum((void*) &addl_pseudo, 4, sum);
|
|
||||||
sum = ones_complement_checksum((void*) tp, tcp_len, sum);
|
|
||||||
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
int udp_checksum(const struct ip* ip, const struct udphdr* up, int len)
|
|
||||||
{
|
|
||||||
uint32 sum;
|
|
||||||
|
|
||||||
if ( len % 2 == 1 )
|
|
||||||
// Add in pad byte.
|
|
||||||
sum = htons(((const u_char*) up)[len - 1] << 8);
|
|
||||||
else
|
|
||||||
sum = 0;
|
|
||||||
|
|
||||||
sum = ones_complement_checksum((void*) &ip->ip_src.s_addr, 4, sum);
|
|
||||||
sum = ones_complement_checksum((void*) &ip->ip_dst.s_addr, 4, sum);
|
|
||||||
|
|
||||||
uint32 addl_pseudo =
|
|
||||||
(htons(IPPROTO_UDP) << 16) | htons((unsigned short) len);
|
|
||||||
|
|
||||||
sum = ones_complement_checksum((void*) &addl_pseudo, 4, sum);
|
|
||||||
sum = ones_complement_checksum((void*) up, len, sum);
|
|
||||||
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
int udp6_checksum(const struct ip6_hdr* ip6, const struct udphdr* up, int len)
|
|
||||||
{
|
|
||||||
uint32 sum;
|
|
||||||
|
|
||||||
if ( len % 2 == 1 )
|
|
||||||
// Add in pad byte.
|
|
||||||
sum = htons(((const u_char*) up)[len - 1] << 8);
|
|
||||||
else
|
|
||||||
sum = 0;
|
|
||||||
|
|
||||||
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_UDP);
|
|
||||||
sum = ones_complement_checksum((void*) &addl_pseudo, 4, sum);
|
|
||||||
sum = ones_complement_checksum((void*) up, len, sum);
|
|
||||||
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
int icmp_checksum(const struct icmp* icmpp, int len)
|
int icmp_checksum(const struct icmp* icmpp, int len)
|
||||||
{
|
{
|
||||||
uint32 sum;
|
uint32 sum;
|
||||||
|
|
|
@ -60,12 +60,14 @@ inline int seq_delta(uint32 a, uint32 b)
|
||||||
|
|
||||||
// Returns the ones-complement checksum of a chunk of b short-aligned bytes.
|
// Returns the ones-complement checksum of a chunk of b short-aligned bytes.
|
||||||
extern int ones_complement_checksum(const void* p, int b, uint32 sum);
|
extern int ones_complement_checksum(const void* p, int b, uint32 sum);
|
||||||
extern int ones_complement_checksum(const IPAddr& a, uint32 sum);
|
|
||||||
|
|
||||||
extern int tcp_checksum(const struct ip* ip, const struct tcphdr* tp, int len);
|
inline int ones_complement_checksum(const IPAddr& a, uint32 sum)
|
||||||
extern int udp_checksum(const struct ip* ip, const struct udphdr* up, int len);
|
{
|
||||||
extern int udp6_checksum(const struct ip6_hdr* ip, const struct udphdr* up,
|
const uint32* bytes;
|
||||||
int len);
|
int len = a.GetBytes(&bytes);
|
||||||
|
return ones_complement_checksum(bytes, len*4, sum);
|
||||||
|
}
|
||||||
|
|
||||||
extern int icmp_checksum(const struct icmp* icmpp, int len);
|
extern int icmp_checksum(const struct icmp* icmpp, int len);
|
||||||
|
|
||||||
// Returns 'A', 'B', 'C' or 'D'
|
// Returns 'A', 'B', 'C' or 'D'
|
||||||
|
|
9
testing/btest/Baseline/core.checksums/bad.out
Normal file
9
testing/btest/Baseline/core.checksums/bad.out
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
1332784981.078396 weird: bad_IP_checksum
|
||||||
|
1332784885.686428 weird: bad_TCP_checksum
|
||||||
|
1332784933.501023 weird: bad_UDP_checksum
|
||||||
|
1332785210.013051 weird: routing0_hdr
|
||||||
|
1332785210.013051 weird: bad_TCP_checksum
|
||||||
|
1332782580.798420 weird: routing0_hdr
|
||||||
|
1332782580.798420 weird: bad_UDP_checksum
|
||||||
|
1332785250.469132 weird: bad_TCP_checksum
|
||||||
|
1332781342.923813 weird: bad_UDP_checksum
|
2
testing/btest/Baseline/core.checksums/good.out
Normal file
2
testing/btest/Baseline/core.checksums/good.out
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
1332785125.596793 weird: routing0_hdr
|
||||||
|
1332782508.592037 weird: routing0_hdr
|
|
@ -1 +1,3 @@
|
||||||
|
weird routing0_hdr from 2001:4f8:4:7:2e0:81ff:fe52:ffff to 2001:78:1:32::2
|
||||||
|
[orig_h=2001:4f8:4:7:2e0:81ff:fe52:ffff, orig_p=53/udp, resp_h=2001:78:1:32::2, resp_p=53/udp]
|
||||||
[ip=<uninitialized>, ip6=[class=0, flow=0, len=59, nxt=0, hlim=64, src=2001:4f8:4:7:2e0:81ff:fe52:ffff, dst=2001:4f8:4:7:2e0:81ff:fe52:9a6b, exts=[[id=0, hopopts=[nxt=43, len=0, options=[[otype=1, len=4, data=\0\0\0\0]]], dstopts=<uninitialized>, routing=<uninitialized>, fragment=<uninitialized>, ah=<uninitialized>, esp=<uninitialized>], [id=43, hopopts=<uninitialized>, dstopts=<uninitialized>, routing=[nxt=17, len=4, rtype=0, segleft=2, data=\0\0\0\0 ^A\0x\0^A\02\0\0\0\0\0\0\0^A ^A\0x\0^A\02\0\0\0\0\0\0\0^B], fragment=<uninitialized>, ah=<uninitialized>, esp=<uninitialized>]]], tcp=<uninitialized>, udp=[sport=53/udp, dport=53/udp, ulen=11], icmp=<uninitialized>]
|
[ip=<uninitialized>, ip6=[class=0, flow=0, len=59, nxt=0, hlim=64, src=2001:4f8:4:7:2e0:81ff:fe52:ffff, dst=2001:4f8:4:7:2e0:81ff:fe52:9a6b, exts=[[id=0, hopopts=[nxt=43, len=0, options=[[otype=1, len=4, data=\0\0\0\0]]], dstopts=<uninitialized>, routing=<uninitialized>, fragment=<uninitialized>, ah=<uninitialized>, esp=<uninitialized>], [id=43, hopopts=<uninitialized>, dstopts=<uninitialized>, routing=[nxt=17, len=4, rtype=0, segleft=2, data=\0\0\0\0 ^A\0x\0^A\02\0\0\0\0\0\0\0^A ^A\0x\0^A\02\0\0\0\0\0\0\0^B], fragment=<uninitialized>, ah=<uninitialized>, esp=<uninitialized>]]], tcp=<uninitialized>, udp=[sport=53/udp, dport=53/udp, ulen=11], icmp=<uninitialized>]
|
||||||
|
|
BIN
testing/btest/Traces/chksums/ip4-bad-chksum.pcap
Normal file
BIN
testing/btest/Traces/chksums/ip4-bad-chksum.pcap
Normal file
Binary file not shown.
BIN
testing/btest/Traces/chksums/ip4-tcp-bad-chksum.pcap
Normal file
BIN
testing/btest/Traces/chksums/ip4-tcp-bad-chksum.pcap
Normal file
Binary file not shown.
BIN
testing/btest/Traces/chksums/ip4-tcp-good-chksum.pcap
Normal file
BIN
testing/btest/Traces/chksums/ip4-tcp-good-chksum.pcap
Normal file
Binary file not shown.
BIN
testing/btest/Traces/chksums/ip4-udp-bad-chksum.pcap
Normal file
BIN
testing/btest/Traces/chksums/ip4-udp-bad-chksum.pcap
Normal file
Binary file not shown.
BIN
testing/btest/Traces/chksums/ip4-udp-good-chksum.pcap
Normal file
BIN
testing/btest/Traces/chksums/ip4-udp-good-chksum.pcap
Normal file
Binary file not shown.
BIN
testing/btest/Traces/chksums/ip6-route0-tcp-bad-chksum.pcap
Normal file
BIN
testing/btest/Traces/chksums/ip6-route0-tcp-bad-chksum.pcap
Normal file
Binary file not shown.
BIN
testing/btest/Traces/chksums/ip6-route0-tcp-good-chksum.pcap
Normal file
BIN
testing/btest/Traces/chksums/ip6-route0-tcp-good-chksum.pcap
Normal file
Binary file not shown.
BIN
testing/btest/Traces/chksums/ip6-route0-udp-bad-chksum.pcap
Normal file
BIN
testing/btest/Traces/chksums/ip6-route0-udp-bad-chksum.pcap
Normal file
Binary file not shown.
BIN
testing/btest/Traces/chksums/ip6-route0-udp-good-chksum.pcap
Normal file
BIN
testing/btest/Traces/chksums/ip6-route0-udp-good-chksum.pcap
Normal file
Binary file not shown.
BIN
testing/btest/Traces/chksums/ip6-tcp-bad-chksum.pcap
Normal file
BIN
testing/btest/Traces/chksums/ip6-tcp-bad-chksum.pcap
Normal file
Binary file not shown.
BIN
testing/btest/Traces/chksums/ip6-tcp-good-chksum.pcap
Normal file
BIN
testing/btest/Traces/chksums/ip6-tcp-good-chksum.pcap
Normal file
Binary file not shown.
BIN
testing/btest/Traces/chksums/ip6-udp-bad-chksum.pcap
Normal file
BIN
testing/btest/Traces/chksums/ip6-udp-bad-chksum.pcap
Normal file
Binary file not shown.
BIN
testing/btest/Traces/chksums/ip6-udp-good-chksum.pcap
Normal file
BIN
testing/btest/Traces/chksums/ip6-udp-good-chksum.pcap
Normal file
Binary file not shown.
|
@ -1,4 +1,4 @@
|
||||||
# @TEST-EXEC: bro -C -b -r $TRACES/ext_hdr_hbh_routing.trace %INPUT >output
|
# @TEST-EXEC: bro -b -r $TRACES/ipv6-hbh-routing0.trace %INPUT >output
|
||||||
# @TEST-EXEC: btest-diff output
|
# @TEST-EXEC: btest-diff output
|
||||||
|
|
||||||
event ipv6_ext_headers(c: connection, p: pkt_hdr)
|
event ipv6_ext_headers(c: connection, p: pkt_hdr)
|
||||||
|
|
15
testing/btest/core/checksums.test
Normal file
15
testing/btest/core/checksums.test
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
# @TEST-EXEC: bro -b -r $TRACES/chksums/ip4-bad-chksum.pcap >>bad.out 2>&1
|
||||||
|
# @TEST-EXEC: bro -b -r $TRACES/chksums/ip4-tcp-bad-chksum.pcap >>bad.out 2>&1
|
||||||
|
# @TEST-EXEC: bro -b -r $TRACES/chksums/ip4-udp-bad-chksum.pcap >>bad.out 2>&1
|
||||||
|
# @TEST-EXEC: bro -b -r $TRACES/chksums/ip6-route0-tcp-bad-chksum.pcap >>bad.out 2>&1
|
||||||
|
# @TEST-EXEC: bro -b -r $TRACES/chksums/ip6-route0-udp-bad-chksum.pcap >>bad.out 2>&1
|
||||||
|
# @TEST-EXEC: bro -b -r $TRACES/chksums/ip6-tcp-bad-chksum.pcap >>bad.out 2>&1
|
||||||
|
# @TEST-EXEC: bro -b -r $TRACES/chksums/ip6-udp-bad-chksum.pcap >>bad.out 2>&1
|
||||||
|
# @TEST-EXEC: bro -b -r $TRACES/chksums/ip4-tcp-good-chksum.pcap >>good.out 2>&1
|
||||||
|
# @TEST-EXEC: bro -b -r $TRACES/chksums/ip4-udp-good-chksum.pcap >>good.out 2>&1
|
||||||
|
# @TEST-EXEC: bro -b -r $TRACES/chksums/ip6-route0-tcp-good-chksum.pcap >>good.out 2>&1
|
||||||
|
# @TEST-EXEC: bro -b -r $TRACES/chksums/ip6-route0-udp-good-chksum.pcap >>good.out 2>&1
|
||||||
|
# @TEST-EXEC: bro -b -r $TRACES/chksums/ip6-tcp-good-chksum.pcap >>good.out 2>&1
|
||||||
|
# @TEST-EXEC: bro -b -r $TRACES/chksums/ip6-udp-good-chksum.pcap >>good.out 2>&1
|
||||||
|
# @TEST-EXEC: btest-diff bad.out
|
||||||
|
# @TEST-EXEC: btest-diff good.out
|
|
@ -1,10 +1,22 @@
|
||||||
# @TEST-EXEC: bro -C -b -r $TRACES/ext_hdr_hbh_routing.trace %INPUT >output
|
# @TEST-EXEC: bro -b -r $TRACES/ipv6-hbh-routing0.trace %INPUT >output
|
||||||
# @TEST-EXEC: btest-diff output
|
# @TEST-EXEC: btest-diff output
|
||||||
|
|
||||||
# Just check that the event is raised correctly for a packet containing
|
# Just check that the event is raised correctly for a packet containing
|
||||||
# extension headers.
|
# extension headers.
|
||||||
|
|
||||||
event ipv6_ext_headers(c: connection, p: pkt_hdr)
|
event ipv6_ext_headers(c: connection, p: pkt_hdr)
|
||||||
{
|
{
|
||||||
print p;
|
print p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Also check the weird for routing type 0 extensions headers
|
||||||
|
event flow_weird(name: string, src: addr, dst: addr)
|
||||||
|
{
|
||||||
|
print fmt("weird %s from %s to %s", name, src, dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
# And the connection for routing type 0 packets with non-zero segments left
|
||||||
|
# should use the last address in that extension header.
|
||||||
|
event new_connection(c: connection)
|
||||||
|
{
|
||||||
|
print c$id;
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue