Add handling for IPv6 extension header chains (addresses #531)

- The script-layer 'pkt_hdr' type is extended with a new 'ip6' field
  representing the full IPv6 header chain.

- The 'new_packet' event is now raised for IPv6 packets (addresses #523)

- A new event called 'ipv6_ext_header' is raised for any IPv6 packet
  containing extension headers.

- A new event called 'esp_packet' is raised for any packets using ESP
  ('new_packet' and 'ipv6_ext_header' events provide connection info,
  but that info can't be provided here since the upper-layer payload
  is encrypted).

- The 'unknown_protocol' weird is now raised more reliably when Bro
  sees a transport protocol or IPv6 extension header it can't handle.
  (addresses #522)

Still need to do IPv6 fragment reassembly and needs more testing.
This commit is contained in:
Jon Siwek 2012-03-02 20:01:01 -06:00
parent 0639487aad
commit eb9f686bb2
11 changed files with 724 additions and 110 deletions

View file

@ -939,11 +939,154 @@ const IPPROTO_IGMP = 2; ##< Group management protocol.
const IPPROTO_IPIP = 4; ##< IP encapsulation in IP. const IPPROTO_IPIP = 4; ##< IP encapsulation in IP.
const IPPROTO_TCP = 6; ##< TCP. const IPPROTO_TCP = 6; ##< TCP.
const IPPROTO_UDP = 17; ##< User datagram protocol. const IPPROTO_UDP = 17; ##< User datagram protocol.
const IPPROTO_IPV6 = 41; ##< IPv6 header.
const IPPROTO_RAW = 255; ##< Raw IP packet. const IPPROTO_RAW = 255; ##< Raw IP packet.
## Values extracted from an IP header. # Definitions for IPv6 extension headers.
const IPPROTO_HOPOPTS = 0; ##< IPv6 hop-by-hop-options header.
const IPPROTO_ROUTING = 43; ##< IPv6 routing header.
const IPPROTO_FRAGMENT = 44; ##< IPv6 fragment header.
const IPPROTO_ESP = 50; ##< IPv6 encapsulating security payload header.
const IPPROTO_AH = 51; ##< IPv6 authentication header.
const IPPROTO_NONE = 59; ##< IPv6 no next header.
const IPPROTO_DSTOPTS = 60; ##< IPv6 destination options header.
## Values extracted from an IPv6 header.
## ##
## .. bro:see:: pkt_hdr discarder_check_ip ## .. bro:see:: pkt_hdr ip_hdr ip6_hdr_chain ip6_hopopts ip6_dstopts ip6_routing
## ip6_fragment ip6_ah ip6_esp
type ip6_hdr: record {
class: count; ##< Traffic class.
flow: count; ##< Flow label.
len: count; ##< Payload length.
nxt: count; ##< Next header (RFC 1700 assigned number).
hlim: count; ##< Hop limit.
src: addr; ##< Source address.
dst: addr; ##< Destination address.
};
## Values extracted from an IPv6 extension header's (e.g. hop-by-hop or
## destination option headers) option field.
##
## .. bro:see:: ip6_hdr ip6_hdr_chain ip6_hopopts ip6_dstopts
type ip6_option: record {
otype: count; ##< Option type.
len: count; ##< Option data length.
data: string; ##< Option data.
};
## Values extracted from an IPv6 Hop-by-Hop options extension header.
##
## .. bro:see:: pkt_hdr ip_hdr ip6_hdr ip6_hdr_chain ip6_option
type ip6_hopopts: record {
## Next header (RFC 1700 assigned number).
nxt: count;
## Length of header in 8-octet units, excluding first unit.
len: count;
## The TLV encoded options;
options: vector of ip6_option;
};
## Values extracted from an IPv6 Destination options extension header.
##
## .. bro:see:: pkt_hdr ip_hdr ip6_hdr ip6_hdr_chain ip6_option
type ip6_dstopts: record {
## Next header (RFC 1700 assigned number).
nxt: count;
## Length of header in 8-octet units, excluding first unit.
len: count;
## The TLV encoded options;
options: vector of ip6_option;
};
## Values extracted from an IPv6 Routing extension header.
##
## .. bro:see:: pkt_hdr ip_hdr ip6_hdr ip6_hdr_chain
type ip6_routing: record {
## Next header (RFC 1700 assigned number).
nxt: count;
## Length of header in 8-octet units, excluding first unit.
len: count;
## Routing type.
rtype: count;
## Segments left.
segleft: count;
## Type-specific data.
data: string;
};
## Values extracted from an IPv6 Fragment extension header.
##
## .. bro:see:: pkt_hdr ip_hdr ip6_hdr ip6_hdr_chain
type ip6_fragment: record {
## Next header (RFC 1700 assigned number).
nxt: count;
## 8-bit reserved field.
rsv1: count;
## Fragmentation offset.
offset: count;
## 2-bit reserved field.
rsv2: count;
## More fragments.
more: bool;
## Fragment identification.
id: count;
};
## Values extracted from an IPv6 Authentication extension header.
##
## .. bro:see:: pkt_hdr ip_hdr ip6_hdr ip6_hdr_chain
type ip6_ah: record {
## Next header (RFC 1700 assigned number).
nxt: count;
## Length of header in 4-octet units, excluding first two units.
len: count;
## Reserved field.
rsv: count;
## Security Parameter Index.
spi: count;
## Sequence number.
seq: count;
## Authentication data.
data: string;
};
## Values extracted from an IPv6 ESP extension header.
##
## .. bro:see:: pkt_hdr ip_hdr ip6_hdr ip6_hdr_chain
type ip6_esp: record {
## Security Parameters Index.
spi: count;
## Sequence number.
seq: count;
};
## An IPv6 header chain.
##
## .. bro:see:: pkt_hdr ip_hdr
type ip6_hdr_chain: record {
## The main IPv6 header.
hdr: ip6_hdr;
## Hop-by-hop option extension header.
hopopts: vector of ip6_hopopts;
## Destination option extension headers.
dstopts: vector of ip6_dstopts;
## Routing extension headers.
routing: vector of ip6_routing;
## Fragment headers.
fragment: vector of ip6_fragment;
## Authentication extension headers.
ah: vector of ip6_ah;
## Encapsulating security payload headers.
esp: vector of ip6_esp;
## Order of extension headers identified by RFC 1700 assigned numbers.
ext_order: vector of count;
};
## Values extracted from an IPv4 header.
##
## .. bro:see:: pkt_hdr ip6_hdr discarder_check_ip
type ip_hdr: record { type ip_hdr: record {
hl: count; ##< Header length in bytes. hl: count; ##< Header length in bytes.
tos: count; ##< Type of service. tos: count; ##< Type of service.
@ -1000,10 +1143,11 @@ type icmp_hdr: record {
## ##
## .. bro:see:: new_packet ## .. bro:see:: new_packet
type pkt_hdr: record { type pkt_hdr: record {
ip: ip_hdr; ##< The IP header. ip: ip_hdr &optional; ##< The IPv4 header if an IPv4 packet.
tcp: tcp_hdr &optional; ##< The TCP header if a TCP packet. ip6: ip6_hdr_chain &optional; ##< The IPv6 header chain if an IPv6 packet.
udp: udp_hdr &optional; ##< The UDP header if a UDP packet. tcp: tcp_hdr &optional; ##< The TCP header if a TCP packet.
icmp: icmp_hdr &optional; ##< The ICMP header if an ICMP packet. udp: udp_hdr &optional; ##< The UDP header if a UDP packet.
icmp: icmp_hdr &optional; ##< The ICMP header if an ICMP packet.
}; };
## Definition of "secondary filters". A secondary filter is a BPF filter given as ## Definition of "secondary filters". A secondary filter is a BPF filter given as

View file

@ -330,6 +330,7 @@ set(bro_SRCS
IntSet.cc IntSet.cc
InterConn.cc InterConn.cc
IOSource.cc IOSource.cc
IP.cc
IPAddr.cc IPAddr.cc
IRC.cc IRC.cc
List.cc List.cc

View file

@ -27,7 +27,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,
uint32 frag_field, HashKey* k, double t) HashKey* k, double t)
: Reassembler(0, ip->DstAddr(), REASSEM_IP) : Reassembler(0, ip->DstAddr(), REASSEM_IP)
{ {
s = arg_s; s = arg_s;
@ -41,7 +41,7 @@ FragReassembler::FragReassembler(NetSessions* arg_s,
reassembled_pkt = 0; reassembled_pkt = 0;
frag_size = 0; // flag meaning "not known" frag_size = 0; // flag meaning "not known"
AddFragment(t, ip, pkt, frag_field); AddFragment(t, ip, pkt);
if ( frag_timeout != 0.0 ) if ( frag_timeout != 0.0 )
{ {
@ -60,8 +60,7 @@ FragReassembler::~FragReassembler()
delete key; delete key;
} }
void FragReassembler::AddFragment(double t, const IP_Hdr* ip, const u_char* pkt, void FragReassembler::AddFragment(double t, const IP_Hdr* ip, const u_char* pkt)
uint32 frag_field)
{ {
const struct ip* ip4 = ip->IP4_Hdr(); const struct ip* ip4 = ip->IP4_Hdr();
@ -72,16 +71,16 @@ void FragReassembler::AddFragment(double t, const IP_Hdr* ip, const u_char* pkt,
// attack. // attack.
s->Weird("fragment_protocol_inconsistency", ip); s->Weird("fragment_protocol_inconsistency", ip);
if ( frag_field & 0x4000 ) if ( ip->DF() )
// Linux MTU discovery for UDP can do this, for example. // Linux MTU discovery for UDP can do this, for example.
s->Weird("fragment_with_DF", ip); s->Weird("fragment_with_DF", ip);
int offset = (ntohs(ip4->ip_off) & 0x1fff) * 8; int offset = ip->FragOffset();
int len = ntohs(ip4->ip_len); int len = ntohs(ip4->ip_len);
int hdr_len = proto_hdr->ip_hl * 4; int hdr_len = proto_hdr->ip_hl * 4;
int upper_seq = offset + len - hdr_len; int upper_seq = offset + len - hdr_len;
if ( (frag_field & 0x2000) == 0 ) if ( ! ip->MF() )
{ {
// Last fragment. // Last fragment.
if ( frag_size == 0 ) if ( frag_size == 0 )

View file

@ -20,11 +20,10 @@ typedef void (FragReassembler::*frag_timer_func)(double t);
class FragReassembler : public Reassembler { class FragReassembler : public Reassembler {
public: public:
FragReassembler(NetSessions* s, const IP_Hdr* ip, const u_char* pkt, FragReassembler(NetSessions* s, const IP_Hdr* ip, const u_char* pkt,
uint32 frag_field, HashKey* k, double t); HashKey* k, double t);
~FragReassembler(); ~FragReassembler();
void AddFragment(double t, const IP_Hdr* ip, const u_char* pkt, void AddFragment(double t, const IP_Hdr* ip, const u_char* pkt);
uint32 frag_field);
void Expire(double t); void Expire(double t);
void DeleteTimer(); void DeleteTimer();

273
src/IP.cc Normal file
View file

@ -0,0 +1,273 @@
// See the file "COPYING" in the main distribution directory for copyright.
#include "IP.h"
#include "Type.h"
#include "Val.h"
#include "Var.h"
static RecordType* ip_hdr_type = 0;
static RecordType* ip6_hdr_type = 0;
static RecordType* ip6_hdr_chain_type = 0;
static RecordType* ip6_option_type = 0;
static RecordType* ip6_hopopts_type = 0;
static RecordType* ip6_dstopts_type = 0;
static RecordType* ip6_routing_type = 0;
static RecordType* ip6_fragment_type = 0;
static RecordType* ip6_ah_type = 0;
static RecordType* ip6_esp_type = 0;
static inline RecordType* hdrType(RecordType*& type, const char* name)
{
if ( ! type ) type = internal_type(name)->AsRecordType();
return type;
}
RecordVal* IPv6_Hdr::BuildRecordVal() const
{
RecordVal* rv = new RecordVal(hdrType(ip6_hdr_type, "ip6_hdr"));
const struct ip6_hdr* ip6 = (const struct ip6_hdr*)data;
rv->Assign(0, new Val(ntohl(ip6->ip6_flow) & 0x0ff00000, TYPE_COUNT));
rv->Assign(1, new Val(ntohl(ip6->ip6_flow) & 0x000fffff, TYPE_COUNT));
rv->Assign(2, new Val(ntohs(ip6->ip6_plen), TYPE_COUNT));
rv->Assign(3, new Val(ip6->ip6_nxt, TYPE_COUNT));
rv->Assign(4, new Val(ip6->ip6_hlim, TYPE_COUNT));
rv->Assign(5, new AddrVal(ip6->ip6_src));
rv->Assign(6, new AddrVal(ip6->ip6_dst));
return rv;
}
static VectorVal* BuildOptionsVal(const u_char* data, uint16 len)
{
VectorVal* vv = new VectorVal(new VectorType(ip6_option_type->Ref()));
while ( len > 0 )
{
const struct ip6_opt* opt = (const struct ip6_opt*) data;
RecordVal* rv = new RecordVal(hdrType(ip6_option_type, "ip6_option"));
rv->Assign(0, new Val(opt->ip6o_type, TYPE_COUNT));
rv->Assign(1, new Val(opt->ip6o_len, TYPE_COUNT));
uint16 off = 2 * sizeof(uint8);
rv->Assign(2, new StringVal(
new BroString(data + off, opt->ip6o_len - off, 1)));
data += opt->ip6o_len + off;
len -= opt->ip6o_len + off;
vv->Assign(vv->Size(), rv, 0);
}
return vv;
}
RecordVal* IPv6_HopOpts::BuildRecordVal() const
{
RecordVal* rv = new RecordVal(hdrType(ip6_hopopts_type, "ip6_hopopts"));
const struct ip6_hbh* hbh = (const struct ip6_hbh*)data;
rv->Assign(0, new Val(hbh->ip6h_nxt, TYPE_COUNT));
rv->Assign(1, new Val(hbh->ip6h_len, TYPE_COUNT));
uint16 off = 2 * sizeof(uint8);
rv->Assign(2, BuildOptionsVal(data + off, Length() - off));
return rv;
}
RecordVal* IPv6_DstOpts::BuildRecordVal() const
{
RecordVal* rv = new RecordVal(hdrType(ip6_dstopts_type, "ip6_dstopts"));
const struct ip6_dest* dst = (const struct ip6_dest*)data;
rv->Assign(0, new Val(dst->ip6d_nxt, TYPE_COUNT));
rv->Assign(1, new Val(dst->ip6d_len, TYPE_COUNT));
uint16 off = 2 * sizeof(uint8);
rv->Assign(2, BuildOptionsVal(data + off, Length() - off));
return rv;
}
RecordVal* IPv6_Routing::BuildRecordVal() const
{
RecordVal* rv = new RecordVal(hdrType(ip6_routing_type, "ip6_routing"));
const struct ip6_rthdr* rt = (const struct ip6_rthdr*)data;
rv->Assign(0, new Val(rt->ip6r_nxt, TYPE_COUNT));
rv->Assign(1, new Val(rt->ip6r_len, TYPE_COUNT));
rv->Assign(2, new Val(rt->ip6r_type, TYPE_COUNT));
rv->Assign(3, new Val(rt->ip6r_segleft, TYPE_COUNT));
uint16 off = 4 * sizeof(uint8);
rv->Assign(4, new StringVal(new BroString(data + off, Length() - off, 1)));
return rv;
}
RecordVal* IPv6_Fragment::BuildRecordVal() const
{
RecordVal* rv = new RecordVal(hdrType(ip6_fragment_type, "ip6_fragment"));
const struct ip6_frag* frag = (const struct ip6_frag*)data;
rv->Assign(0, new Val(frag->ip6f_nxt, TYPE_COUNT));
rv->Assign(1, new Val(frag->ip6f_reserved, TYPE_COUNT));
rv->Assign(2, new Val(ntohs(frag->ip6f_offlg) & 0xfff8, TYPE_COUNT));
rv->Assign(3, new Val(ntohs(frag->ip6f_offlg) & 0x0006, TYPE_COUNT));
rv->Assign(4, new Val(ntohs(frag->ip6f_offlg) & 0x0001, TYPE_BOOL));
rv->Assign(5, new Val(ntohl(frag->ip6f_ident), TYPE_COUNT));
return rv;
}
RecordVal* IPv6_AH::BuildRecordVal() const
{
RecordVal* rv = new RecordVal(hdrType(ip6_ah_type, "ip6_ah"));
rv->Assign(0, new Val(((ip6_ext*)data)->ip6e_nxt, TYPE_COUNT));
rv->Assign(1, new Val(((ip6_ext*)data)->ip6e_len, TYPE_COUNT));
rv->Assign(2, new Val(ntohs(((uint16*)data)[1]), TYPE_COUNT));
rv->Assign(3, new Val(ntohl(((uint32*)data)[1]), TYPE_COUNT));
rv->Assign(4, new Val(ntohl(((uint32*)data)[2]), TYPE_COUNT));
uint16 off = 3 * sizeof(uint32);
rv->Assign(5, new StringVal(new BroString(data + off, Length() - off, 1)));
return rv;
}
RecordVal* IPv6_ESP::BuildRecordVal() const
{
RecordVal* rv = new RecordVal(hdrType(ip6_esp_type, "ip6_esp"));
const uint32* esp = (const uint32*)data;
rv->Assign(0, new Val(ntohl(esp[0]), TYPE_COUNT));
rv->Assign(1, new Val(ntohl(esp[1]), TYPE_COUNT));
return rv;
}
RecordVal* IP_Hdr::BuildRecordVal() const
{
RecordVal* rval = 0;
if ( ! ip_hdr_type )
{
ip_hdr_type = internal_type("ip_hdr")->AsRecordType();
ip6_hdr_type = internal_type("ip6_hdr")->AsRecordType();
ip6_hdr_chain_type = internal_type("ip6_hdr_chain")->AsRecordType();
ip6_hopopts_type = internal_type("ip6_hopopts")->AsRecordType();
ip6_dstopts_type = internal_type("ip6_dstopts")->AsRecordType();
ip6_routing_type = internal_type("ip6_routing")->AsRecordType();
ip6_fragment_type = internal_type("ip6_fragment")->AsRecordType();
ip6_ah_type = internal_type("ip6_ah")->AsRecordType();
ip6_esp_type = internal_type("ip6_esp")->AsRecordType();
}
if ( ip4 )
{
rval = new RecordVal(ip_hdr_type);
rval->Assign(0, new Val(ip4->ip_hl * 4, TYPE_COUNT));
rval->Assign(1, new Val(ip4->ip_tos, TYPE_COUNT));
rval->Assign(2, new Val(ntohs(ip4->ip_len), TYPE_COUNT));
rval->Assign(3, new Val(ntohs(ip4->ip_id), TYPE_COUNT));
rval->Assign(4, new Val(ip4->ip_ttl, TYPE_COUNT));
rval->Assign(5, new Val(ip4->ip_p, TYPE_COUNT));
rval->Assign(6, new AddrVal(ip4->ip_src.s_addr));
rval->Assign(7, new AddrVal(ip4->ip_dst.s_addr));
}
else
{
rval = new RecordVal(ip6_hdr_chain_type);
VectorVal* hopopts = new VectorVal(new VectorType(ip6_hopopts_type->Ref()));
VectorVal* dstopts = new VectorVal(new VectorType(ip6_dstopts_type->Ref()));
VectorVal* routing = new VectorVal(new VectorType(ip6_routing_type->Ref()));
VectorVal* fragment = new VectorVal(new VectorType(ip6_fragment_type->Ref()));
VectorVal* ah = new VectorVal(new VectorType(ip6_ah_type->Ref()));
VectorVal* esp = new VectorVal(new VectorType(ip6_esp_type->Ref()));
VectorVal* order = new VectorVal(new VectorType(base_type(TYPE_COUNT)));
for ( size_t i = 1; i < ip6_hdrs->Size(); ++i )
{
RecordVal* v = ((*ip6_hdrs)[i])->BuildRecordVal();
uint8 type = ((*ip6_hdrs)[i])->Type();
switch (type) {
case IPPROTO_HOPOPTS:
hopopts->Assign(hopopts->Size(), v, 0);
break;
case IPPROTO_ROUTING:
routing->Assign(routing->Size(), v, 0);
break;
case IPPROTO_DSTOPTS:
dstopts->Assign(dstopts->Size(), v, 0);
break;
case IPPROTO_FRAGMENT:
fragment->Assign(fragment->Size(), v, 0);
break;
case IPPROTO_AH:
ah->Assign(ah->Size(), v, 0);
break;
case IPPROTO_ESP:
esp->Assign(esp->Size(), v, 0);
break;
case IPPROTO_IPV6:
default:
reporter->InternalError("pkt_hdr assigned bad header %d", type);
break;
}
order->Assign(i, new Val(type, TYPE_COUNT), 0);
}
rval->Assign(0, ((*ip6_hdrs)[0])->BuildRecordVal());
rval->Assign(1, hopopts);
rval->Assign(2, dstopts);
rval->Assign(3, routing);
rval->Assign(4, fragment);
rval->Assign(5, ah);
rval->Assign(6, esp);
rval->Assign(7, order);
}
return rval;
}
static inline IPv6_Hdr* getIPv6Header(uint8 type, const u_char* d)
{
switch (type) {
case IPPROTO_IPV6:
return new IPv6_Hdr(d);
case IPPROTO_HOPOPTS:
return new IPv6_HopOpts(d);
case IPPROTO_ROUTING:
return new IPv6_Routing(d);
case IPPROTO_DSTOPTS:
return new IPv6_DstOpts(d);
case IPPROTO_FRAGMENT:
return new IPv6_Fragment(d);
case IPPROTO_AH:
return new IPv6_AH(d);
case IPPROTO_ESP:
return new IPv6_ESP(d);
default:
// should never get here if calls are protected by isIPv6ExtHeader()
reporter->InternalError("Unknown IPv6 header type: %d", type);
break;
}
// can't be reached
assert(false);
return 0;
}
static inline bool isIPv6ExtHeader(uint8 type)
{
switch (type) {
case IPPROTO_HOPOPTS:
case IPPROTO_ROUTING:
case IPPROTO_DSTOPTS:
case IPPROTO_FRAGMENT:
case IPPROTO_AH:
case IPPROTO_ESP:
return true;
default:
return false;
}
}
IPv6_Hdr_Chain::IPv6_Hdr_Chain(const struct ip6_hdr* ip6)
{
length = 0;
uint8 current_type, next_type;
next_type = IPPROTO_IPV6;
const u_char* hdrs = (const u_char*) ip6;
do
{
current_type = next_type;
chain.push_back(getIPv6Header(current_type, hdrs));
next_type = chain[chain.size()-1]->NextHdr();
uint16 len = chain[chain.size()-1]->Length();
hdrs += len;
length += len;
} while ( current_type != IPPROTO_FRAGMENT &&
current_type != IPPROTO_ESP &&
isIPv6ExtHeader(next_type) );
}

196
src/IP.h
View file

@ -4,8 +4,139 @@
#define ip_h #define ip_h
#include "config.h" #include "config.h"
#include "net_util.h"
#include "IPAddr.h" #include "IPAddr.h"
#include <net_util.h> #include "Reporter.h"
#include "Val.h"
#include "Type.h"
#include <vector>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
/**
* Base class for IPv6 header/extensions.
*/
class IPv6_Hdr {
public:
IPv6_Hdr() : type(0), data(0) {}
/**
* Construct the main IPv6 header.
*/
IPv6_Hdr(const u_char* d) : type(IPPROTO_IPV6), data(d) {}
/**
* Construct an IPv6 header or extension header from assigned type number.
*/
IPv6_Hdr(uint8 t, const u_char* d) : type(t), data(d) {}
virtual ~IPv6_Hdr() {}
/**
* Returns the assigned IPv6 extension header type number of the header
* that immediately follows this one.
*/
virtual uint8 NextHdr() const { return ((ip6_hdr*)data)->ip6_nxt; }
/**
* Returns the length of the header in bytes.
*/
virtual uint16 Length() const { return 40; }
/**
* Returns the RFC 1700 assigned number indicating the header type.
*/
uint8 Type() const { return type; }
/**
* Returns the script-layer record representation of the header.
*/
virtual RecordVal* BuildRecordVal() const;
protected:
uint8 type;
const u_char* data;
};
class IPv6_HopOpts : public IPv6_Hdr {
public:
IPv6_HopOpts(const u_char* d) : IPv6_Hdr(IPPROTO_HOPOPTS, d) {}
uint8 NextHdr() const { return ((ip6_ext*)data)->ip6e_nxt; }
uint16 Length() const { return 8 + 8 * ((ip6_ext*)data)->ip6e_len; }
RecordVal* BuildRecordVal() const;
};
class IPv6_DstOpts : public IPv6_Hdr {
public:
IPv6_DstOpts(const u_char* d) : IPv6_Hdr(IPPROTO_DSTOPTS, d) {}
uint8 NextHdr() const { return ((ip6_ext*)data)->ip6e_nxt; }
uint16 Length() const { return 8 + 8 * ((ip6_ext*)data)->ip6e_len; }
RecordVal* BuildRecordVal() const;
};
class IPv6_Routing : public IPv6_Hdr {
public:
IPv6_Routing(const u_char* d) : IPv6_Hdr(IPPROTO_ROUTING, d) {}
uint8 NextHdr() const { return ((ip6_ext*)data)->ip6e_nxt; }
uint16 Length() const { return 8 + 8 * ((ip6_ext*)data)->ip6e_len; }
RecordVal* BuildRecordVal() const;
};
class IPv6_Fragment : public IPv6_Hdr {
public:
IPv6_Fragment(const u_char* d) : IPv6_Hdr(IPPROTO_FRAGMENT, d) {}
uint8 NextHdr() const { return ((ip6_ext*)data)->ip6e_nxt; }
uint16 Length() const { return 8; }
RecordVal* BuildRecordVal() const;
};
class IPv6_AH : public IPv6_Hdr {
public:
IPv6_AH(const u_char* d) : IPv6_Hdr(IPPROTO_AH, d) {}
uint8 NextHdr() const { return ((ip6_ext*)data)->ip6e_nxt; }
uint16 Length() const { return 8 + 4 * ((ip6_ext*)data)->ip6e_len; }
RecordVal* BuildRecordVal() const;
};
class IPv6_ESP : public IPv6_Hdr {
public:
IPv6_ESP(const u_char* d) : IPv6_Hdr(IPPROTO_ESP, d) {}
uint8 NextHdr() const { return ((ip6_ext*)data)->ip6e_nxt; }
// encrypted payload begins after 8 bytes
uint16 Length() const { return 8; }
RecordVal* BuildRecordVal() const;
};
class IPv6_Hdr_Chain {
public:
/**
* Initializes the header chain from an IPv6 header structure.
*/
IPv6_Hdr_Chain(const struct ip6_hdr* ip6);
~IPv6_Hdr_Chain()
{ for ( size_t i = 0; i < chain.size(); ++i ) delete chain[i]; }
/**
* Returns the number of headers in the chain.
*/
size_t Size() const { return chain.size(); }
/**
* Returns the sum of the length of all headers in the chain in bytes.
*/
uint16 TotalLength() const { return length; }
/**
* Accesses the header at the given location in the chain.
*/
const IPv6_Hdr* operator[](const size_t i) const { return chain[i]; }
protected:
vector<IPv6_Hdr*> chain;
uint16 length; // The summation of all header lengths in the chain in bytes.
};
class IP_Hdr { class IP_Hdr {
public: public:
@ -17,10 +148,12 @@ public:
IP_Hdr(const struct ip6_hdr* arg_ip6, bool arg_del) IP_Hdr(const struct ip6_hdr* arg_ip6, bool arg_del)
: ip4(0), ip6(arg_ip6), del(arg_del) : ip4(0), ip6(arg_ip6), del(arg_del)
{ {
ip6_hdrs = new IPv6_Hdr_Chain(ip6);
} }
~IP_Hdr() ~IP_Hdr()
{ {
if ( ip6 ) delete ip6_hdrs;
if ( del ) if ( del )
{ {
if ( ip4 ) if ( ip4 )
@ -30,23 +163,23 @@ public:
} }
} }
//TODO: audit usages of this for correct IPv6 support or IPv4 assumptions
const struct ip* IP4_Hdr() const { return ip4; } const struct ip* IP4_Hdr() const { return ip4; }
const struct ip6_hdr* IP6_Hdr() const { return ip6; } const struct ip6_hdr* IP6_Hdr() const { return ip6; }
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 IPAddr DstAddr() const
{ return ip4 ? IPAddr(ip4->ip_dst) : IPAddr(ip6->ip6_dst); } { return ip4 ? IPAddr(ip4->ip_dst) : IPAddr(ip6->ip6_dst); }
//TODO: needs adapting/replacement for IPv6 support
uint16 ID4() const { return ip4 ? ip4->ip_id : 0; }
const u_char* Payload() const const u_char* Payload() const
{ {
if ( ip4 ) if ( ip4 )
return ((const u_char*) ip4) + ip4->ip_hl * 4; return ((const u_char*) ip4) + ip4->ip_hl * 4;
else else
return ((const u_char*) ip6) + 40; return ((const u_char*) ip6) + ip6_hdrs->TotalLength();
} }
uint16 PayloadLen() const uint16 PayloadLen() const
@ -54,33 +187,60 @@ public:
if ( ip4 ) if ( ip4 )
return ntohs(ip4->ip_len) - ip4->ip_hl * 4; return ntohs(ip4->ip_len) - ip4->ip_hl * 4;
else else
return ntohs(ip6->ip6_plen); return ntohs(ip6->ip6_plen) - ip6_hdrs->TotalLength();
} }
uint16 TotalLen() const uint16 TotalLen() const
{ { return ip4 ? ntohs(ip4->ip_len) : ntohs(ip6->ip6_plen) + 40; }
if ( ip4 )
return ntohs(ip4->ip_len); uint16 HdrLen() const
else { return ip4 ? ip4->ip_hl * 4 : ip6_hdrs->TotalLength(); }
return ntohs(ip6->ip6_plen) + 40;
} uint8 LastHeader() const
{ return ip4 ? IPPROTO_RAW :
((*ip6_hdrs)[ip6_hdrs->Size()-1])->Type(); }
uint16 HdrLen() const { return ip4 ? ip4->ip_hl * 4 : 40; }
unsigned char NextProto() const unsigned char NextProto() const
{ return ip4 ? ip4->ip_p : ip6->ip6_nxt; } { return ip4 ? ip4->ip_p :
((*ip6_hdrs)[ip6_hdrs->Size()-1])->NextHdr(); }
unsigned char TTL() const unsigned char TTL() const
{ return ip4 ? ip4->ip_ttl : ip6->ip6_hlim; } { return ip4 ? ip4->ip_ttl : ip6->ip6_hlim; }
//TODO: check for IPv6 Fragment ext. header
bool IsFragment() const
{ return ip4 ? (ntohs(ip4->ip_off) & 0x3fff) != 0 : false; }
//TODO: check for IPv6 Fragment ext. header
uint16 FragOffset() const
{ return ip4 ? (ntohs(ip4->ip_off) & 0x1fff) * 8 : 0; }
//TODO: check for IPv6 Fragment ext. header
uint16 FragField() const uint16 FragField() const
{ return ntohs(ip4 ? ip4->ip_off : 0); } { return ip4 ? ntohs(ip4->ip_off) : 0; }
//TODO: check for IPv6 Fragment ext. header
uint16 ID() const
{ return ip4 ? ntohs(ip4->ip_id) : 0; }
//TODO: check for IPv6 Fragment ext. header
int MF() const
{ return ip4 ? (ntohs(ip4->ip_off) & 0x2000) != 0 : 0; }
// IPv6 has no "Don't Fragment" flag.
int DF() const int DF() const
{ return ip4 ? ((ntohs(ip4->ip_off) & IP_DF) != 0) : 0; } { return ip4 ? ((ntohs(ip4->ip_off) & 0x4000) != 0) : 0; }
uint16 IP_ID() const
{ return ip4 ? (ntohs(ip4->ip_id)) : 0; } size_t NumHeaders() const
{ return ip4 ? 1 : ip6_hdrs->Size(); }
RecordVal* BuildRecordVal() const;
private: private:
const struct ip* ip4; const struct ip* ip4;
const struct ip6_hdr* ip6; const struct ip6_hdr* ip6;
bool del; bool del;
IPv6_Hdr_Chain* ip6_hdrs;
}; };
#endif #endif

View file

@ -33,7 +33,7 @@ PacketSortElement::PacketSortElement(PktSrc* arg_src,
if ( ip_hdr->NextProto() == IPPROTO_TCP && if ( ip_hdr->NextProto() == IPPROTO_TCP &&
// Note: can't sort fragmented packets // Note: can't sort fragmented packets
(ip_hdr->FragField() & 0x3fff) == 0 ) ( ! ip_hdr->IsFragment() ) )
{ {
tcp_offset = hdr_size + ip_hdr->HdrLen(); tcp_offset = hdr_size + ip_hdr->HdrLen();
if ( caplen >= tcp_offset + sizeof(struct tcphdr) ) if ( caplen >= tcp_offset + sizeof(struct tcphdr) )

View file

@ -332,7 +332,8 @@ void NetSessions::NextPacketSecondary(double /* t */, const struct pcap_pkthdr*
StringVal* cmd_val = StringVal* cmd_val =
new StringVal(sp->Event()->Filter()); new StringVal(sp->Event()->Filter());
args->append(cmd_val); args->append(cmd_val);
args->append(BuildHeader(ip)); IP_Hdr ip_hdr(ip, false);
args->append(BuildHeader(&ip_hdr));
// ### Need to queue event here. // ### Need to queue event here.
try try
{ {
@ -400,18 +401,6 @@ int NetSessions::CheckConnectionTag(Connection* conn)
return 1; return 1;
} }
static bool looks_like_IPv4_packet(int len, const struct ip* ip_hdr)
{
if ( (unsigned int) len < sizeof(struct ip) )
return false;
if ( ip_hdr->ip_v == 4 && ntohs(ip_hdr->ip_len) == len )
return true;
else
return false;
}
void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
const IP_Hdr* ip_hdr, const u_char* const pkt, const IP_Hdr* ip_hdr, const u_char* const pkt,
int hdr_size) int hdr_size)
@ -441,18 +430,9 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
if ( discarder && discarder->NextPacket(ip_hdr, len, caplen) ) if ( discarder && discarder->NextPacket(ip_hdr, len, caplen) )
return; return;
int proto = ip_hdr->NextProto();
if ( proto != IPPROTO_TCP && proto != IPPROTO_UDP &&
proto != IPPROTO_ICMP )
{
dump_this_packet = 1;
return;
}
FragReassembler* f = 0; FragReassembler* f = 0;
uint32 frag_field = ip_hdr->FragField();
if ( (frag_field & 0x3fff) != 0 ) if ( ip_hdr->IsFragment() )
{ {
dump_this_packet = 1; // always record fragments dump_this_packet = 1; // always record fragments
@ -463,12 +443,12 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
// Don't try to reassemble, that's doomed. // Don't try to reassemble, that's doomed.
// Discard all except the first fragment (which // Discard all except the first fragment (which
// is useful in analyzing header-only traces) // is useful in analyzing header-only traces)
if ( (frag_field & 0x1fff) != 0 ) if ( ip_hdr->FragOffset() != 0 )
return; return;
} }
else else
{ {
f = NextFragment(t, ip_hdr, pkt + hdr_size, frag_field); f = NextFragment(t, ip_hdr, pkt + hdr_size);
const IP_Hdr* ih = f->ReassembledPkt(); const IP_Hdr* ih = f->ReassembledPkt();
if ( ! ih ) if ( ! ih )
// It didn't reassemble into anything yet. // It didn't reassemble into anything yet.
@ -485,21 +465,24 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
len -= ip_hdr_len; // remove IP header len -= ip_hdr_len; // remove IP header
caplen -= ip_hdr_len; caplen -= ip_hdr_len;
uint32 min_hdr_len = (proto == IPPROTO_TCP) ? sizeof(struct tcphdr) : if ( ip_hdr->LastHeader() == IPPROTO_ESP )
(proto == IPPROTO_UDP ? sizeof(struct udphdr) : ICMP_MINLEN);
if ( len < min_hdr_len )
{ {
Weird("truncated_header", hdr, pkt); if ( esp_packet )
if ( f ) {
Remove(f); // ### val_list* vl = new val_list();
vl->append(ip_hdr->BuildRecordVal());
mgr.QueueEvent(esp_packet, vl);
}
Remove(f);
// Can't do more since upper-layer payloads are going to be encrypted
return; return;
} }
if ( caplen < min_hdr_len )
int proto = ip_hdr->NextProto();
if ( CheckHeaderTrunc(proto, len, caplen, hdr, pkt) )
{ {
Weird("internally_truncated_header", hdr, pkt); Remove(f);
if ( f )
Remove(f); // ###
return; return;
} }
@ -549,6 +532,7 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
default: default:
Weird(fmt("unknown_protocol %d", proto), hdr, pkt); Weird(fmt("unknown_protocol %d", proto), hdr, pkt);
Remove(f);
return; return;
} }
@ -574,6 +558,7 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
if ( consistent < 0 ) if ( consistent < 0 )
{ {
delete h; delete h;
Remove(f);
return; return;
} }
@ -592,10 +577,11 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
} }
if ( ! conn ) if ( ! conn )
{
delete h; delete h;
Remove(f);
if ( ! conn )
return; return;
}
int record_packet = 1; // whether to record the packet at all int record_packet = 1; // whether to record the packet at all
int record_content = 1; // whether to record its data int record_content = 1; // whether to record its data
@ -603,8 +589,17 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
int is_orig = (id.src_addr == conn->OrigAddr()) && int is_orig = (id.src_addr == conn->OrigAddr()) &&
(id.src_port == conn->OrigPort()); (id.src_port == conn->OrigPort());
if ( new_packet && ip4 ) Val* pkt_hdr_val = 0;
conn->Event(new_packet, 0, BuildHeader(ip4));
if ( ipv6_ext_headers && ip_hdr->NumHeaders() > 1 )
{
pkt_hdr_val = BuildHeader(ip_hdr);
conn->Event(new_packet, 0, pkt_hdr_val);
}
if ( new_packet )
conn->Event(new_packet, 0,
pkt_hdr_val ? pkt_hdr_val->Ref() : BuildHeader(ip_hdr));
conn->NextPacket(t, is_orig, ip_hdr, len, caplen, data, conn->NextPacket(t, is_orig, ip_hdr, len, caplen, data,
record_packet, record_content, record_packet, record_content,
@ -614,7 +609,7 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
{ {
// Above we already recorded the fragment in its entirety. // Above we already recorded the fragment in its entirety.
f->DeleteTimer(); f->DeleteTimer();
Remove(f); // ### Remove(f);
} }
else if ( record_packet ) else if ( record_packet )
@ -630,10 +625,39 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
} }
} }
Val* NetSessions::BuildHeader(const struct ip* ip) bool NetSessions::CheckHeaderTrunc(int proto, uint32 len, uint32 caplen,
const struct pcap_pkthdr* h, const u_char* p)
{
uint32 min_hdr_len = 0;
switch ( proto ) {
case IPPROTO_TCP:
min_hdr_len = sizeof(struct tcphdr);
break;
case IPPROTO_UDP:
min_hdr_len = sizeof(struct udphdr);
break;
case IPPROTO_ICMP:
default:
min_hdr_len = ICMP_MINLEN;
break;
}
if ( len < min_hdr_len )
{
Weird("truncated_header", h, p);
return true;
}
if ( caplen < min_hdr_len )
{
Weird("internally_truncated_header", h, p);
return true;
}
return false;
}
Val* NetSessions::BuildHeader(const IP_Hdr* ip)
{ {
static RecordType* pkt_hdr_type = 0; static RecordType* pkt_hdr_type = 0;
static RecordType* ip_hdr_type = 0;
static RecordType* tcp_hdr_type = 0; static RecordType* tcp_hdr_type = 0;
static RecordType* udp_hdr_type = 0; static RecordType* udp_hdr_type = 0;
static RecordType* icmp_hdr_type; static RecordType* icmp_hdr_type;
@ -641,7 +665,6 @@ Val* NetSessions::BuildHeader(const struct ip* ip)
if ( ! pkt_hdr_type ) if ( ! pkt_hdr_type )
{ {
pkt_hdr_type = internal_type("pkt_hdr")->AsRecordType(); pkt_hdr_type = internal_type("pkt_hdr")->AsRecordType();
ip_hdr_type = internal_type("ip_hdr")->AsRecordType();
tcp_hdr_type = internal_type("tcp_hdr")->AsRecordType(); tcp_hdr_type = internal_type("tcp_hdr")->AsRecordType();
udp_hdr_type = internal_type("udp_hdr")->AsRecordType(); udp_hdr_type = internal_type("udp_hdr")->AsRecordType();
icmp_hdr_type = internal_type("icmp_hdr")->AsRecordType(); icmp_hdr_type = internal_type("icmp_hdr")->AsRecordType();
@ -649,26 +672,15 @@ Val* NetSessions::BuildHeader(const struct ip* ip)
RecordVal* pkt_hdr = new RecordVal(pkt_hdr_type); RecordVal* pkt_hdr = new RecordVal(pkt_hdr_type);
RecordVal* ip_hdr = new RecordVal(ip_hdr_type); if ( ip->IP4_Hdr() )
pkt_hdr->Assign(0, ip->BuildRecordVal());
int ip_hdr_len = ip->ip_hl * 4; else
int ip_pkt_len = ntohs(ip->ip_len); pkt_hdr->Assign(1, ip->BuildRecordVal());
ip_hdr->Assign(0, new Val(ip->ip_hl * 4, TYPE_COUNT));
ip_hdr->Assign(1, new Val(ip->ip_tos, TYPE_COUNT));
ip_hdr->Assign(2, new Val(ip_pkt_len, TYPE_COUNT));
ip_hdr->Assign(3, new Val(ntohs(ip->ip_id), TYPE_COUNT));
ip_hdr->Assign(4, new Val(ip->ip_ttl, TYPE_COUNT));
ip_hdr->Assign(5, new Val(ip->ip_p, TYPE_COUNT));
ip_hdr->Assign(6, new AddrVal(ip->ip_src.s_addr));
ip_hdr->Assign(7, new AddrVal(ip->ip_dst.s_addr));
pkt_hdr->Assign(0, ip_hdr);
// L4 header. // L4 header.
const u_char* data = ((const u_char*) ip) + ip_hdr_len; const u_char* data = ip->Payload();
int proto = ip->ip_p; int proto = ip->NextProto();
switch ( proto ) { switch ( proto ) {
case IPPROTO_TCP: case IPPROTO_TCP:
{ {
@ -676,7 +688,7 @@ Val* NetSessions::BuildHeader(const struct ip* ip)
RecordVal* tcp_hdr = new RecordVal(tcp_hdr_type); RecordVal* tcp_hdr = new RecordVal(tcp_hdr_type);
int tcp_hdr_len = tp->th_off * 4; int tcp_hdr_len = tp->th_off * 4;
int data_len = ip_pkt_len - ip_hdr_len - tcp_hdr_len; int data_len = ip->PayloadLen() - tcp_hdr_len;
tcp_hdr->Assign(0, new PortVal(ntohs(tp->th_sport), TRANSPORT_TCP)); tcp_hdr->Assign(0, new PortVal(ntohs(tp->th_sport), TRANSPORT_TCP));
tcp_hdr->Assign(1, new PortVal(ntohs(tp->th_dport), TRANSPORT_TCP)); tcp_hdr->Assign(1, new PortVal(ntohs(tp->th_dport), TRANSPORT_TCP));
@ -687,7 +699,7 @@ Val* NetSessions::BuildHeader(const struct ip* ip)
tcp_hdr->Assign(6, new Val(tp->th_flags, TYPE_COUNT)); tcp_hdr->Assign(6, new Val(tp->th_flags, TYPE_COUNT));
tcp_hdr->Assign(7, new Val(ntohs(tp->th_win), TYPE_COUNT)); tcp_hdr->Assign(7, new Val(ntohs(tp->th_win), TYPE_COUNT));
pkt_hdr->Assign(1, tcp_hdr); pkt_hdr->Assign(2, tcp_hdr);
break; break;
} }
@ -700,7 +712,7 @@ Val* NetSessions::BuildHeader(const struct ip* ip)
udp_hdr->Assign(1, new PortVal(ntohs(up->uh_dport), TRANSPORT_UDP)); udp_hdr->Assign(1, new PortVal(ntohs(up->uh_dport), TRANSPORT_UDP));
udp_hdr->Assign(2, new Val(ntohs(up->uh_ulen), TYPE_COUNT)); udp_hdr->Assign(2, new Val(ntohs(up->uh_ulen), TYPE_COUNT));
pkt_hdr->Assign(2, udp_hdr); pkt_hdr->Assign(3, udp_hdr);
break; break;
} }
@ -711,7 +723,7 @@ Val* NetSessions::BuildHeader(const struct ip* ip)
icmp_hdr->Assign(0, new Val(icmpp->icmp_type, TYPE_COUNT)); icmp_hdr->Assign(0, new Val(icmpp->icmp_type, TYPE_COUNT));
pkt_hdr->Assign(3, icmp_hdr); pkt_hdr->Assign(4, icmp_hdr);
break; break;
} }
@ -725,9 +737,9 @@ Val* NetSessions::BuildHeader(const struct ip* ip)
} }
FragReassembler* NetSessions::NextFragment(double t, const IP_Hdr* ip, FragReassembler* NetSessions::NextFragment(double t, const IP_Hdr* ip,
const u_char* pkt, uint32 frag_field) const u_char* pkt)
{ {
uint32 frag_id = ntohs(ip->ID4()); // we actually could skip conv. uint32 frag_id = ip->ID();
ListVal* key = new ListVal(TYPE_ANY); ListVal* key = new ListVal(TYPE_ANY);
key->Append(new AddrVal(ip->SrcAddr())); key->Append(new AddrVal(ip->SrcAddr()));
@ -741,7 +753,7 @@ FragReassembler* NetSessions::NextFragment(double t, const IP_Hdr* ip,
FragReassembler* f = fragments.Lookup(h); FragReassembler* f = fragments.Lookup(h);
if ( ! f ) if ( ! f )
{ {
f = new FragReassembler(this, ip, pkt, frag_field, h, t); f = new FragReassembler(this, ip, pkt, h, t);
fragments.Insert(h, f); fragments.Insert(h, f);
Unref(key); Unref(key);
return f; return f;
@ -750,7 +762,7 @@ FragReassembler* NetSessions::NextFragment(double t, const IP_Hdr* ip,
delete h; delete h;
Unref(key); Unref(key);
f->AddFragment(t, ip, pkt, frag_field); f->AddFragment(t, ip, pkt);
return f; return f;
} }
@ -909,6 +921,7 @@ void NetSessions::Remove(Connection* c)
void NetSessions::Remove(FragReassembler* f) void NetSessions::Remove(FragReassembler* f)
{ {
if ( ! f ) return;
HashKey* k = f->Key(); HashKey* k = f->Key();
if ( ! k ) if ( ! k )
reporter->InternalError("fragment block not in dictionary"); reporter->InternalError("fragment block not in dictionary");

View file

@ -79,7 +79,7 @@ public:
// Returns a reassembled packet, or nil if there are still // Returns a reassembled packet, or nil if there are still
// some missing fragments. // some missing fragments.
FragReassembler* NextFragment(double t, const IP_Hdr* ip, FragReassembler* NextFragment(double t, const IP_Hdr* ip,
const u_char* pkt, uint32 frag_field); const u_char* pkt);
int Get_OS_From_SYN(struct os_type* retval, int Get_OS_From_SYN(struct os_type* retval,
uint16 tot, uint8 DF_flag, uint8 TTL, uint16 WSS, uint16 tot, uint8 DF_flag, uint8 TTL, uint16 WSS,
@ -193,7 +193,13 @@ protected:
// Builds a record encapsulating a packet. This should be more // Builds a record encapsulating a packet. This should be more
// general, including the equivalent of a union of tcp/udp/icmp // general, including the equivalent of a union of tcp/udp/icmp
// headers . // headers .
Val* BuildHeader(const struct ip* ip); Val* BuildHeader(const IP_Hdr* ip);
// For a given protocol, checks whether the header's length as derived
// from lower-level headers or the length actually captured is less
// than that protocol's minimum header size.
bool CheckHeaderTrunc(int proto, uint32 len, uint32 caplen,
const struct pcap_pkthdr* hdr, const u_char* pkt);
CompositeHash* ch; CompositeHash* ch;
PDict(Connection) tcp_conns; PDict(Connection) tcp_conns;

View file

@ -1203,7 +1203,7 @@ RecordVal* TCP_Analyzer::BuildOSVal(int is_orig, const IP_Hdr* ip,
if ( ip->HdrLen() > 20 ) if ( ip->HdrLen() > 20 )
quirks |= QUIRK_IPOPT; quirks |= QUIRK_IPOPT;
if ( ip->IP_ID() == 0 ) if ( ip->ID() == 0 )
quirks |= QUIRK_ZEROID; quirks |= QUIRK_ZEROID;
if ( tcp->th_seq == 0 ) if ( tcp->th_seq == 0 )
@ -1942,11 +1942,11 @@ int TCPStats_Endpoint::DataSent(double /* t */, int seq, int len, int caplen,
{ {
if ( ++num_pkts == 1 ) if ( ++num_pkts == 1 )
{ // First packet. { // First packet.
last_id = ntohs(ip->ID4()); last_id = ip->ID();
return 0; return 0;
} }
int id = ntohs(ip->ID4()); int id = ip->ID();
if ( id == last_id ) if ( id == last_id )
{ {

View file

@ -454,11 +454,30 @@ event expected_connection_seen%(c: connection, a: count%);
## ##
## c: The connection the packet is part of. ## c: The connection the packet is part of.
## ##
## p: Informattion from the header of the packet that triggered the event. ## p: Information from the header of the packet that triggered the event.
## ##
## .. bro:see:: tcp_packet packet_contents ## .. bro:see:: tcp_packet packet_contents
event new_packet%(c: connection, p: pkt_hdr%); event new_packet%(c: connection, p: pkt_hdr%);
## Generated for every IPv6 packet that contains extension headers.
## This is potentially an expensive event to handle if analysiing IPv6 traffic
## that happens to utilize extension headers frequently.
##
## c: The connection the packet is part of.
##
## p: Information from the header of the packet that triggered the event.
##
## .. bro:see:: new_packet tcp_packet packet_contents esp_packet
event ipv6_ext_headers%(c: connection, p: pkt_hdr%);
## Generated for any packets using the IPv6 Encapsulating Security Payload (ESP)
## extension header.
##
## p: Information from the header of the packet that triggered the event.
##
## .. bro:see:: new_packet tcp_packet ipv6_ext_headers
event esp_packet%(p: pkt_hdr%);
## Generated for every packet that has non-empty transport-layer payload. This is a ## Generated for every packet that has non-empty transport-layer payload. This is a
## very low-level and expensive event that should be avoided when at all possible. ## very low-level and expensive event that should be avoided when at all possible.
## It's usually infeasible to handle when processing even medium volumes of ## It's usually infeasible to handle when processing even medium volumes of