diff --git a/src/IpPacketFragmentation.cpp b/src/IpPacketFragmentation.cpp new file mode 100644 index 0000000..3f41248 --- /dev/null +++ b/src/IpPacketFragmentation.cpp @@ -0,0 +1,98 @@ +#include "IpPacketFragmentation.h" +#include +#include + +IpPacketFragmentation::IpPacketFragmentation(const size_t newMtu) : mtu(newMtu), idCounter() +{ +} + + +IpPacketFragmentation::~IpPacketFragmentation() +{ + +} + +void IpPacketFragmentation::addExtensionHeader(IN const uint8_t nextHeader, IN const uint8_t *startPtr, IN Tins::IPv6 & ipFragmentPdu) +{ + Tins::IPv6::ext_header fragmentionHeader(nextHeader, fragmentionHeadersize , startPtr); + ipFragmentPdu.add_ext_header(fragmentionHeader); +} + +void IpPacketFragmentation::initFragmentationHeader(FragmentionHeaderStruct* ptrFragmentionHeaderStruct) +{ + ptrFragmentionHeaderStruct->NextHeader = Tins::IPv6::FRAGMENT; + ptrFragmentionHeaderStruct->Reserved = 0; + ptrFragmentionHeaderStruct->Res = 0; + ptrFragmentionHeaderStruct->MFlag = 1; + ptrFragmentionHeaderStruct->Identification = ++idCounter; +} + +bool IpPacketFragmentation::handle(IN const Tins::PDU & pdu, IN IPacketHandler * callBackHandler) +{ + if (callBackHandler == nullptr || callBackHandler == this) + { + return false; + } + + const size_t originPduSize = pdu.size(); + const size_t fragmentationCount = originPduSize + 1; + if (fragmentationCount < 2) + { + return callBackHandler->handle(pdu, this); + } + + const Tins::IPv6 * ipPdu = pdu.find_pdu(); + if (ipPdu == nullptr) + { + return false; + } + + Tins::PDU * ipDataPdu = ipPdu->inner_pdu(); + if (ipPdu == nullptr) + { + return false; + } + + ByteVector ipPayload = ipDataPdu->serialize(); + const long ipPayloadSize = static_cast(ipPayload.size()); + const long fragmentationSize = static_cast(ipPayload.size() / fragmentationCount); + const long payLoadEndIndicator = ipPayloadSize - fragmentationSize; + ByteVector::iterator fragmentPosIt = ipPayload.begin(); + FragmentionHeaderUnion fragmentionHeaderUnion; + FragmentionHeaderStruct * ptrFragmentionHeaderStruct = &fragmentionHeaderUnion.Structed; + uint8_t * ptrStartFragmentionHeader = &fragmentionHeaderUnion.Bytes[1]; + initFragmentationHeader(ptrFragmentionHeaderStruct); + for (ptrFragmentionHeaderStruct->FragmentOffset = 0; ptrFragmentionHeaderStruct->FragmentOffset < payLoadEndIndicator; ptrFragmentionHeaderStruct->FragmentOffset += fragmentationSize) + { + ByteVector::iterator fragmentStart = fragmentPosIt; + fragmentPosIt = fragmentStart + fragmentationSize; + if (!createAndForwardFragmend(pdu, fragmentStart, fragmentPosIt, ptrFragmentionHeaderStruct, ptrStartFragmentionHeader, callBackHandler)) + { + return false; + } + } + + ptrFragmentionHeaderStruct->MFlag = 0; + return createAndForwardFragmend(pdu, fragmentPosIt, ipPayload.end(), ptrFragmentionHeaderStruct, ptrStartFragmentionHeader, callBackHandler); +} + +bool IpPacketFragmentation::createAndForwardFragmend(IN const Tins::PDU & pdu, IN const ByteVector::iterator & fragmentStart, IN const ByteVector::iterator & fragmentPosIt, IN FragmentionHeaderStruct * ptrFragmentionHeaderStruct, IN uint8_t * ptrStartFragmentionHeader, IN IPacketHandler * callBackHandler) +{ + SPtrByteVector fragmentPayload = std::make_shared(fragmentStart, fragmentPosIt); + Tins::PDU * fragmentPdu = pdu.clone(); + if (fragmentPdu == nullptr) + { + return false; + } + + Tins::IPv6 * ipFragmentPdu = fragmentPdu->find_pdu(); + if (ipFragmentPdu == nullptr) + { + return false; + } + + addExtensionHeader(ptrFragmentionHeaderStruct->NextHeader, ptrStartFragmentionHeader, *ipFragmentPdu); + SPtrRawPDU rawFragmentPdu = std::make_shared(fragmentPayload->data(), static_cast(fragmentPayload->size())); + ipFragmentPdu->inner_pdu(rawFragmentPdu.get()); + return callBackHandler->handle(pdu, this); +} diff --git a/src/IpPacketFragmentation.h b/src/IpPacketFragmentation.h new file mode 100644 index 0000000..445f911 --- /dev/null +++ b/src/IpPacketFragmentation.h @@ -0,0 +1,27 @@ +#ifndef IPPACKETFRAGMENTATION_H +#define IPPACKETFRAGMENTATION_H + +#include "IpPacketFragmentation_t.h" +#include "Ip6Packet_t.h" +#include "AbstractPacketHandler.h" + +class IpPacketFragmentation : public AbstractPacketHandler +{ + +public: + + IpPacketFragmentation(const size_t newMtu); + virtual ~IpPacketFragmentation(); + + virtual bool handle(IN const Tins::PDU & pdu, IN IPacketHandler * callBackHandler = nullptr) override; +private: + const size_t mtu; + uint32_t idCounter; + static const size_t fragmentionHeadersize = sizeof (FragmentionHeaderUnion) - 1; + static void addExtensionHeader(IN const uint8_t NextHeader, IN const uint8_t *startPtr, IN Tins::IPv6 & ipFragmentPdu); + bool createAndForwardFragmend(IN const Tins::PDU & pdu, IN const ByteVector::iterator & fragmentStart, IN const ByteVector::iterator & fragmentPosIt, IN FragmentionHeaderStruct * ptrFragmentionHeaderStruct, IN uint8_t * ptrStartFragmentionHeader, IN IPacketHandler * callBackHandler); + + void initFragmentationHeader(FragmentionHeaderStruct* ptrFragmentionHeaderStruct); +}; + +#endif // IPPACKETFRAGMENTATION_H diff --git a/src/IpPacketFragmentation_t.h b/src/IpPacketFragmentation_t.h new file mode 100644 index 0000000..7154f7e --- /dev/null +++ b/src/IpPacketFragmentation_t.h @@ -0,0 +1,40 @@ +#ifndef IPPACKETFRAGMENTATION_T_H +#define IPPACKETFRAGMENTATION_T_H + +#include + +class IpPacketFragmentation; +typedef IpPacketFragmentation * PtrIpPacketFragmentation; +typedef std::shared_ptr * SPtrIpPacketFragmentation; +typedef std::unique_ptr * UPtrIpPacketFragmentation; +typedef std::weak_ptr * WPtrIpPacketFragmentation; + +namespace Tins +{ + class RawPDU; +} + +typedef std::unique_ptr UPtrRawPDU; +typedef std::weak_ptr WPtrRawPDU; +typedef std::shared_ptr SPtrRawPDU; + +#pragma pack(push) +#pragma pack(1) +struct FragmentionHeaderStruct +{ + uint8_t NextHeader; + uint8_t Reserved; + uint16_t MFlag:1; + uint16_t Res:2; + uint16_t FragmentOffset:13; + uint32_t Identification; +}; + +struct FragmentionHeaderUnion +{ + FragmentionHeaderStruct Structed; + uint8_t Bytes[8]; +}; + +#pragma pack(pop) +#endif // IPPACKETFRAGMENTATION_T_H diff --git a/src/Main_t.h b/src/Main_t.h index 7b367d0..fc5458e 100644 --- a/src/Main_t.h +++ b/src/Main_t.h @@ -29,4 +29,12 @@ namespace std } } +typedef std::vector ByteVector; +typedef std::shared_ptr SPtrByteVector; + +typedef std::vector ByteVectorList; +typedef std::shared_ptr SPtrByteVectorList; +typedef std::unique_ptr UPtrByteVectorList; +typedef std::weak_ptr WPtrByteVectorList; + #endif diff --git a/src/TinsNetworkInterfaceCard_t.h b/src/TinsNetworkInterfaceCard_t.h index 688ac35..8299387 100644 --- a/src/TinsNetworkInterfaceCard_t.h +++ b/src/TinsNetworkInterfaceCard_t.h @@ -2,10 +2,9 @@ #define TINSNETWORKINTERFACECARD_T_H #include -#include #include "Main_t.h" -typedef std::vector ByteVector; + namespace Tins {