Add IPv6 fragment reassembly.

This commit is contained in:
Jon Siwek 2012-03-06 16:08:28 -06:00
parent a0e07018f4
commit 9d590456b0
4 changed files with 180 additions and 61 deletions

154
src/IP.h
View file

@ -26,6 +26,16 @@ public:
*/
IPv6_Hdr(const u_char* d) : type(IPPROTO_IPV6), data(d) {}
/**
* Construct the main IPv6 header, but replace the next protocol field
* if it points to a fragment.
*/
IPv6_Hdr(const u_char* d, uint16 nxt) : type(IPPROTO_IPV6), data(d)
{
if ( ((ip6_hdr*)data)->ip6_nxt == IPPROTO_FRAGMENT )
((ip6_hdr*)data)->ip6_nxt = nxt;
}
/**
* Construct an IPv6 header or extension header from assigned type number.
*/
@ -49,6 +59,11 @@ public:
*/
uint8 Type() const { return type; }
/**
* Returns pointer to the start of where header structure resides in memory.
*/
const u_char* Data() const { return data; }
/**
* Returns the script-layer record representation of the header.
*/
@ -59,50 +74,63 @@ protected:
const u_char* data;
};
class IPv6_HopOpts : public IPv6_Hdr {
class IPv6_Ext : public IPv6_Hdr {
public:
IPv6_HopOpts(const u_char* d) : IPv6_Hdr(IPPROTO_HOPOPTS, d) {}
IPv6_Ext(uint16 type, const u_char* d) : IPv6_Hdr(type, d) {}
IPv6_Ext(uint16 type, const u_char* d, uint16 nxt) : IPv6_Hdr(type, d)
{
if ( ((ip6_ext*)data)->ip6e_nxt == IPPROTO_FRAGMENT )
((ip6_ext*)data)->ip6e_nxt = nxt;
}
uint8 NextHdr() const { return ((ip6_ext*)data)->ip6e_nxt; }
virtual uint16 Length() const = 0;
virtual RecordVal* BuildRecordVal() const = 0;
};
class IPv6_HopOpts : public IPv6_Ext {
public:
IPv6_HopOpts(const u_char* d) : IPv6_Ext(IPPROTO_HOPOPTS, d) {}
IPv6_HopOpts(const u_char* d, uint16 n) : IPv6_Ext(IPPROTO_HOPOPTS, d, n) {}
uint16 Length() const { return 8 + 8 * ((ip6_ext*)data)->ip6e_len; }
RecordVal* BuildRecordVal() const;
};
class IPv6_DstOpts : public IPv6_Hdr {
class IPv6_DstOpts : public IPv6_Ext {
public:
IPv6_DstOpts(const u_char* d) : IPv6_Hdr(IPPROTO_DSTOPTS, d) {}
uint8 NextHdr() const { return ((ip6_ext*)data)->ip6e_nxt; }
IPv6_DstOpts(const u_char* d) : IPv6_Ext(IPPROTO_DSTOPTS, d) {}
IPv6_DstOpts(const u_char* d, uint16 n) : IPv6_Ext(IPPROTO_DSTOPTS, d, n) {}
uint16 Length() const { return 8 + 8 * ((ip6_ext*)data)->ip6e_len; }
RecordVal* BuildRecordVal() const;
};
class IPv6_Routing : public IPv6_Hdr {
class IPv6_Routing : public IPv6_Ext {
public:
IPv6_Routing(const u_char* d) : IPv6_Hdr(IPPROTO_ROUTING, d) {}
uint8 NextHdr() const { return ((ip6_ext*)data)->ip6e_nxt; }
IPv6_Routing(const u_char* d) : IPv6_Ext(IPPROTO_ROUTING, d) {}
IPv6_Routing(const u_char* d, uint16 n) : IPv6_Ext(IPPROTO_ROUTING, d, n) {}
uint16 Length() const { return 8 + 8 * ((ip6_ext*)data)->ip6e_len; }
RecordVal* BuildRecordVal() const;
};
class IPv6_Fragment : public IPv6_Hdr {
class IPv6_Fragment : public IPv6_Ext {
public:
IPv6_Fragment(const u_char* d) : IPv6_Hdr(IPPROTO_FRAGMENT, d) {}
uint8 NextHdr() const { return ((ip6_ext*)data)->ip6e_nxt; }
IPv6_Fragment(const u_char* d) : IPv6_Ext(IPPROTO_FRAGMENT, d) {}
IPv6_Fragment(const u_char* d, uint16 n) : IPv6_Ext(IPPROTO_FRAGMENT, d, n)
{}
uint16 Length() const { return 8; }
RecordVal* BuildRecordVal() const;
};
class IPv6_AH : public IPv6_Hdr {
class IPv6_AH : public IPv6_Ext {
public:
IPv6_AH(const u_char* d) : IPv6_Hdr(IPPROTO_AH, d) {}
uint8 NextHdr() const { return ((ip6_ext*)data)->ip6e_nxt; }
IPv6_AH(const u_char* d) : IPv6_Ext(IPPROTO_AH, d) {}
IPv6_AH(const u_char* d, uint16 n) : IPv6_Ext(IPPROTO_AH, d, n) {}
uint16 Length() const { return 8 + 4 * ((ip6_ext*)data)->ip6e_len; }
RecordVal* BuildRecordVal() const;
};
class IPv6_ESP : public IPv6_Hdr {
class IPv6_ESP : public IPv6_Ext {
public:
IPv6_ESP(const u_char* d) : IPv6_Hdr(IPPROTO_ESP, d) {}
uint8 NextHdr() const { return ((ip6_ext*)data)->ip6e_nxt; }
IPv6_ESP(const u_char* d) : IPv6_Ext(IPPROTO_ESP, d) {}
// encrypted payload begins after 8 bytes
uint16 Length() const { return 8; }
RecordVal* BuildRecordVal() const;
@ -113,7 +141,14 @@ public:
/**
* Initializes the header chain from an IPv6 header structure.
*/
IPv6_Hdr_Chain(const struct ip6_hdr* ip6);
IPv6_Hdr_Chain(const struct ip6_hdr* ip6) { Init(ip6, false); }
/**
* Initializes the header chain from an IPv6 header structure, and replaces
* the first next protocol pointer field that points to a fragment header.
*/
IPv6_Hdr_Chain(const struct ip6_hdr* ip6, uint16 next)
{ Init(ip6, true, next); }
~IPv6_Hdr_Chain()
{ for ( size_t i = 0; i < chain.size(); ++i ) delete chain[i]; }
@ -133,22 +168,73 @@ public:
*/
const IPv6_Hdr* operator[](const size_t i) const { return chain[i]; }
/**
* Returns whether the header chain indicates a fragmented packet.
*/
bool IsFragment() const
{ return chain[chain.size()-1]->Type() == IPPROTO_FRAGMENT; }
/**
* Returns pointer to fragment header structure if the chain contains one.
*/
const struct ip6_frag* GetFragHdr() const
{ return IsFragment() ?
(const struct ip6_frag*)chain[chain.size()-1]->Data(): 0; }
/**
* If the header chain is a fragment, returns the offset in number of bytes
* relative to the start of the Fragmentable Part of the original packet.
*/
uint16 FragOffset() const
{ return IsFragment() ?
(ntohs(GetFragHdr()->ip6f_offlg) & 0xfff8) : 0; }
/**
* If the header chain is a fragment, returns the identification field.
*/
uint32 ID() const
{ return IsFragment() ? ntohl(GetFragHdr()->ip6f_ident) : 0; }
/**
* If the header chain is a fragment, returns the M (more fragments) flag.
*/
int MF() const
{ return IsFragment() ?
(ntohs(GetFragHdr()->ip6f_offlg) & 0x0001) != 0 : 0; }
protected:
void Init(const struct ip6_hdr* ip6, bool set_next, uint16 next = 0);
vector<IPv6_Hdr*> chain;
uint16 length; // The summation of all header lengths in the chain in bytes.
};
class IP_Hdr {
public:
IP_Hdr(const u_char* p, bool arg_del)
: ip4(0), ip6(0), del(arg_del), ip6_hdrs(0)
{
if ( ((const struct ip*)p)->ip_v == 4 )
ip4 = (const struct ip*)p;
else if ( ((const struct ip*)p)->ip_v == 6 )
{
ip6 = (const struct ip6_hdr*)p;
ip6_hdrs = new IPv6_Hdr_Chain(ip6);
}
else if ( arg_del )
delete [] p;
}
IP_Hdr(const struct ip* arg_ip4, bool arg_del)
: ip4(arg_ip4), ip6(0), del(arg_del)
: ip4(arg_ip4), ip6(0), del(arg_del), ip6_hdrs(0)
{
}
IP_Hdr(const struct ip6_hdr* arg_ip6, bool arg_del)
: ip4(0), ip6(arg_ip6), del(arg_del)
IP_Hdr(const struct ip6_hdr* arg_ip6, bool arg_del,
const IPv6_Hdr_Chain* c = 0)
: ip4(0), ip6(arg_ip6), del(arg_del),
ip6_hdrs(c ? c : new IPv6_Hdr_Chain(ip6))
{
ip6_hdrs = new IPv6_Hdr_Chain(ip6);
}
~IP_Hdr()
@ -190,7 +276,7 @@ public:
return ntohs(ip6->ip6_plen) - ip6_hdrs->TotalLength();
}
uint16 TotalLen() const
uint32 TotalLen() const
{ return ip4 ? ntohs(ip4->ip_len) : ntohs(ip6->ip6_plen) + 40; }
uint16 HdrLen() const
@ -207,25 +293,19 @@ public:
unsigned char TTL() const
{ 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; }
{ return ip4 ? (ntohs(ip4->ip_off) & 0x3fff) != 0 :
ip6_hdrs->IsFragment(); }
//TODO: check for IPv6 Fragment ext. header
uint16 FragOffset() const
{ return ip4 ? (ntohs(ip4->ip_off) & 0x1fff) * 8 : 0; }
{ return ip4 ? (ntohs(ip4->ip_off) & 0x1fff) * 8 :
ip6_hdrs->FragOffset(); }
//TODO: check for IPv6 Fragment ext. header
uint16 FragField() const
{ return ip4 ? ntohs(ip4->ip_off) : 0; }
uint32 ID() const
{ return ip4 ? ntohs(ip4->ip_id) : ip6_hdrs->ID(); }
//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; }
{ return ip4 ? (ntohs(ip4->ip_off) & 0x2000) != 0 : ip6_hdrs->MF(); }
// IPv6 has no "Don't Fragment" flag.
int DF() const
@ -240,7 +320,7 @@ private:
const struct ip* ip4;
const struct ip6_hdr* ip6;
bool del;
IPv6_Hdr_Chain* ip6_hdrs;
const IPv6_Hdr_Chain* ip6_hdrs;
};
#endif