1
0
mirror of https://github.com/mfontanini/libtins synced 2026-01-23 18:55:58 +01:00
Files
libtins/src/ip_reassembler.cpp
2014-11-12 21:11:01 -08:00

154 lines
4.8 KiB
C++

/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "ip.h"
#include "rawpdu.h"
#include "constants.h"
#include "internals.h"
#include "ip_reassembler.h"
namespace Tins {
namespace Internals {
IPv4Stream::IPv4Stream()
: received_end(false), received_size(), total_size()
{
}
void IPv4Stream::add_fragment(IP *ip) {
fragments_type::iterator it = fragments.begin();
uint16_t offset = extract_offset(ip);
while(it != fragments.end() && offset > it->offset()) {
++it;
}
// No duplicates plx
if(it != fragments.end() && it->offset() == offset)
return;
fragments.insert(it, IPv4Fragment(ip->inner_pdu(), offset));
received_size += ip->inner_pdu()->size();
if(!extract_more_frag(ip)) {
total_size = offset + ip->inner_pdu()->size();
received_end = true;
}
if(offset == 0)
transport_proto = ip->protocol();
}
bool IPv4Stream::is_complete() const {
return received_end && received_size == total_size;
}
PDU *IPv4Stream::allocate_pdu() const {
PDU::serialization_type buffer;
buffer.reserve(total_size);
// Check if we actually have all the data we need. Otherwise return nullptr;
uint16_t expected = 0;
for(fragments_type::const_iterator it = fragments.begin(); it != fragments.end(); ++it) {
if(expected != it->offset())
return 0;
expected = it->offset() + it->payload().size();
buffer.insert(buffer.end(), it->payload().begin(), it->payload().end());
}
return Internals::pdu_from_flag(
static_cast<Constants::IP::e>(transport_proto),
buffer.empty() ? 0 : &buffer[0],
buffer.size()
);
}
uint16_t IPv4Stream::extract_offset(const IP *ip) {
return (ip->frag_off() & 0x1fff) * 8;
}
bool IPv4Stream::extract_more_frag(const IP *ip) {
return ip->frag_off() & 0x2000;
}
} // namespace Internals
IPv4Reassembler::IPv4Reassembler(overlapping_technique technique)
: technique(technique)
{
}
IPv4Reassembler::packet_status IPv4Reassembler::process(PDU &pdu) {
IP *ip = pdu.find_pdu<IP>();
if(ip && ip->inner_pdu()) {
// There's fragmentation
if(ip->is_fragmented()) {
// Create it or look it up, it's the same
Internals::IPv4Stream &stream = streams[make_key(ip)];
stream.add_fragment(ip);
if(stream.is_complete()) {
PDU *pdu = stream.allocate_pdu();
// The packet is corrupt
if(!pdu) {
streams.erase(make_key(ip));
return FRAGMENTED;
}
ip->inner_pdu(pdu);
ip->frag_off(0);
return REASSEMBLED;
}
else
return FRAGMENTED;
}
}
return NOT_FRAGMENTED;
}
IPv4Reassembler::key_type IPv4Reassembler::make_key(const IP *ip) const {
return std::make_pair(
ip->id(),
make_address_pair(ip->src_addr(), ip->dst_addr())
);
}
IPv4Reassembler::address_pair IPv4Reassembler::make_address_pair(IPv4Address addr1, IPv4Address addr2) const {
if(addr1 < addr2)
return std::make_pair(addr1, addr2);
else
return std::make_pair(addr2, addr1);
}
void IPv4Reassembler::clear_streams() {
streams.clear();
}
void IPv4Reassembler::remove_stream(uint16_t id, IPv4Address addr1, IPv4Address addr2) {
streams.erase(
std::make_pair(
id,
make_address_pair(addr1, addr2)
)
);
}
} // namespace Tins