From c211a2c91aa006e0a93fe94b34cdf7d8ea4f45e1 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Wed, 10 Dec 2014 15:12:38 -0600 Subject: [PATCH] Fix PIA packet replay to deliver copy of IP header This prevented one from writing a packet-wise analyzer that needs access to IP headers and can be attached to a connection via signature match. None of the analyzers currently shipping are affected. And maybe it's unlikely there will be many that ever would be, but it's awkward for the API to omit IP headers in this special case (i.e. packets buffer for use with DPD signature matching). Addresses BIT-1298 --- src/IP.cc | 71 ++++++++++++++++++++++++++++++++ src/IP.h | 31 ++++++++++++++ src/analyzer/protocol/pia/PIA.cc | 13 +++--- src/analyzer/protocol/pia/PIA.h | 5 ++- 4 files changed, 113 insertions(+), 7 deletions(-) diff --git a/src/IP.cc b/src/IP.cc index 46702f2546..f1a0a80553 100644 --- a/src/IP.cc +++ b/src/IP.cc @@ -4,6 +4,8 @@ #include "Type.h" #include "Val.h" #include "Var.h" +#include +#include static RecordType* ip4_hdr_type = 0; static RecordType* ip6_hdr_type = 0; @@ -636,3 +638,72 @@ VectorVal* IPv6_Hdr_Chain::BuildVal() const return rval; } + +IP_Hdr::IP_Hdr(const IP_Hdr& other) + { + del = true; + + if ( other.ip4 ) + { + char* new_hdr = new char[other.HdrLen()]; + memcpy(new_hdr, other.ip4, other.HdrLen()); + ip4 = (const struct ip*)new_hdr; + ip6 = 0; + ip6_hdrs = 0; + } + else + { + ip4 = 0; + char* new_hdr = new char[other.HdrLen()]; + memcpy(new_hdr, other.ip6, other.HdrLen()); + ip6 = (const struct ip6_hdr*)new_hdr; + ip6_hdrs = other.ip6_hdrs->Copy(ip6); + } + } + +IP_Hdr& IP_Hdr::operator=(IP_Hdr other) + { + swap(*this, other); + return *this; + } + +IPv6_Hdr_Chain* IPv6_Hdr_Chain::Copy(const ip6_hdr* new_hdr) const + { + IPv6_Hdr_Chain* rval = new IPv6_Hdr_Chain; + rval->length = length; + +#ifdef ENABLE_MOBILE_IPV6 + if ( homeAddr ) + rval->homeAddr = new IPAddr(*homeAddr); +#endif + + if ( finalDst ) + rval->finalDst = new IPAddr(*finalDst); + + if ( chain.empty() ) + { + reporter->InternalWarning("empty IPv6 header chain"); + delete rval; + return 0; + } + + const u_char* new_data = (const u_char*)new_hdr; + const u_char* old_data = chain[0]->Data(); + + for ( size_t i = 0; i < chain.size(); ++i ) + { + int off = chain[i]->Data() - old_data; + rval->chain.push_back(new IPv6_Hdr(chain[i]->Type(), new_data + off)); + } + + return rval; + } + +void swap(IP_Hdr& a, IP_Hdr& b) + { + using std::swap; + swap(a.ip4, b.ip4); + swap(a.ip6, b.ip6); + swap(a.del, b.del); + swap(a.ip6_hdrs, b.ip6_hdrs); + } diff --git a/src/IP.h b/src/IP.h index fb936df1bc..c1e80c4aed 100644 --- a/src/IP.h +++ b/src/IP.h @@ -157,6 +157,12 @@ public: delete finalDst; } + /** + * @return a copy of the header chain, but with pointers to individual + * IPv6 headers now pointing within \a new_hdr. + */ + IPv6_Hdr_Chain* Copy(const struct ip6_hdr* new_hdr) const; + /** * Returns the number of headers in the chain. */ @@ -264,6 +270,14 @@ protected: // point to a fragment friend class FragReassembler; + IPv6_Hdr_Chain() : + length(0), +#ifdef ENABLE_MOBILE_IPV6 + homeAddr(0), +#endif + finalDst(0) + {} + /** * Initializes the header chain from an IPv6 header structure, and replaces * the first next protocol pointer field that points to a fragment header. @@ -353,6 +367,20 @@ public: { } + /** + * Copy constructor. The internal buffer of \a other which contains + * the header data must not be truncated. Also not that if that buffer + * points to a full packet payload, only the IP header portion is copied. + */ + IP_Hdr(const IP_Hdr& other); + + /** + * Copy assignment. The internal buffer of \a other which contains + * the header data must not be truncated. Also not that if that buffer + * points to a full packet payload, only the IP header portion is copied. + */ + IP_Hdr& operator=(IP_Hdr other); + /** * Destructor. */ @@ -553,7 +581,10 @@ public: */ RecordVal* BuildPktHdrVal() const; + friend void swap(IP_Hdr& a, IP_Hdr& b); + private: + const struct ip* ip4; const struct ip6_hdr* ip6; bool del; diff --git a/src/analyzer/protocol/pia/PIA.cc b/src/analyzer/protocol/pia/PIA.cc index 24d4565ce1..21c83367e4 100644 --- a/src/analyzer/protocol/pia/PIA.cc +++ b/src/analyzer/protocol/pia/PIA.cc @@ -22,6 +22,7 @@ void PIA::ClearBuffer(Buffer* buffer) for ( DataBlock* b = buffer->head; b; b = next ) { next = b->next; + delete b->ip; delete [] b->data; delete b; } @@ -31,7 +32,7 @@ void PIA::ClearBuffer(Buffer* buffer) } void PIA::AddToBuffer(Buffer* buffer, uint64 seq, int len, const u_char* data, - bool is_orig) + bool is_orig, const IP_Hdr* ip) { u_char* tmp = 0; @@ -42,6 +43,7 @@ void PIA::AddToBuffer(Buffer* buffer, uint64 seq, int len, const u_char* data, } DataBlock* b = new DataBlock; + b->ip = ip ? new IP_Hdr(*ip) : 0; b->data = tmp; b->is_orig = is_orig; b->len = len; @@ -59,9 +61,10 @@ void PIA::AddToBuffer(Buffer* buffer, uint64 seq, int len, const u_char* data, buffer->size += len; } -void PIA::AddToBuffer(Buffer* buffer, int len, const u_char* data, bool is_orig) +void PIA::AddToBuffer(Buffer* buffer, int len, const u_char* data, bool is_orig, + const IP_Hdr* ip) { - AddToBuffer(buffer, -1, len, data, is_orig); + AddToBuffer(buffer, -1, len, data, is_orig, ip); } void PIA::ReplayPacketBuffer(analyzer::Analyzer* analyzer) @@ -69,7 +72,7 @@ void PIA::ReplayPacketBuffer(analyzer::Analyzer* analyzer) DBG_LOG(DBG_ANALYZER, "PIA replaying %d total packet bytes", pkt_buffer.size); for ( DataBlock* b = pkt_buffer.head; b; b = b->next ) - analyzer->DeliverPacket(b->len, b->data, b->is_orig, -1, 0, 0); + analyzer->DeliverPacket(b->len, b->data, b->is_orig, -1, b->ip, 0); } void PIA::PIA_Done() @@ -96,7 +99,7 @@ void PIA::PIA_DeliverPacket(int len, const u_char* data, bool is_orig, uint64 se if ( (pkt_buffer.state == BUFFERING || new_state == BUFFERING) && len > 0 ) { - AddToBuffer(&pkt_buffer, seq, len, data, is_orig); + AddToBuffer(&pkt_buffer, seq, len, data, is_orig, ip); if ( pkt_buffer.size > dpd_buffer_size ) new_state = dpd_match_only_beginning ? SKIPPING : MATCHING_ONLY; diff --git a/src/analyzer/protocol/pia/PIA.h b/src/analyzer/protocol/pia/PIA.h index 1dc7dbb2bc..d6e07f68c3 100644 --- a/src/analyzer/protocol/pia/PIA.h +++ b/src/analyzer/protocol/pia/PIA.h @@ -49,6 +49,7 @@ protected: // Buffers one chunk of data. Used both for packet payload (incl. // sequence numbers for TCP) and chunks of a reassembled stream. struct DataBlock { + IP_Hdr* ip; const u_char* data; bool is_orig; int len; @@ -66,9 +67,9 @@ protected: }; void AddToBuffer(Buffer* buffer, uint64 seq, int len, - const u_char* data, bool is_orig); + const u_char* data, bool is_orig, const IP_Hdr* ip = 0); void AddToBuffer(Buffer* buffer, int len, - const u_char* data, bool is_orig); + const u_char* data, bool is_orig, const IP_Hdr* ip = 0); void ClearBuffer(Buffer* buffer); DataBlock* CurrentPacket() { return ¤t_packet; }