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; }