1
0
mirror of https://github.com/mfontanini/libtins synced 2026-01-23 02:35:57 +01:00

Added PDUAllocator class, which makes extending PDUs easier.

This commit is contained in:
Matias Fontanini
2013-08-29 23:31:10 -03:00
parent 4ca21bdad7
commit 5f2c923c48
10 changed files with 438 additions and 20 deletions

View File

@@ -110,7 +110,8 @@ libtins_HEADERS = include/internals.h \
include/stp.h \
include/exceptions.h \
include/config.h \
include/address_range.h
include/address_range.h \
include/pdu_allocator.h
libtins_dot11_HEADERS = include/dot11/dot11_base.h \
include/dot11/dot11_beacon.h \

View File

@@ -397,7 +397,8 @@ libtins_HEADERS = include/internals.h \
include/stp.h \
include/exceptions.h \
include/config.h \
include/address_range.h
include/address_range.h \
include/pdu_allocator.h
libtins_dot11_HEADERS = include/dot11/dot11_base.h \
include/dot11/dot11_beacon.h \

View File

@@ -84,7 +84,7 @@ public:
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return PDU::IP; }
PDUType pdu_type() const { return pdu_flag; }
/**
* \sa PDU::clone

182
include/pdu_allocator.h Normal file
View File

@@ -0,0 +1,182 @@
/*
* Copyright (c) 2012, 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.
*
*/
#ifndef TINS_PDU_ALLOCATOR_H
#define TINS_PDU_ALLOCATOR_H
#include <map>
#include "pdu.h"
namespace Tins {
/**
* \cond
*/
class EthernetII;
class SNAP;
class Dot1Q;
class SLL;
class IP;
class IPv6;
namespace Internals {
template<typename PDUType>
PDU *default_allocator(const uint8_t *buffer, uint32_t size)
{
return new PDUType(buffer, size);
}
template<typename Tag>
class PDUAllocator {
public:
typedef typename Tag::identifier_type id_type;
typedef PDU *(*allocator_type)(const uint8_t *, uint32_t);
template<typename PDUType>
static void register_allocator(id_type identifier)
{
allocators[identifier] = &default_allocator<PDUType>;
pdu_types[PDUType::pdu_flag] = identifier;
}
static PDU *allocate(id_type identifier, const uint8_t *buffer, uint32_t size)
{
typename allocators_type::const_iterator it = allocators.find(identifier);
return (it == allocators.end()) ? 0 : (*it->second)(buffer, size);
}
static bool pdu_type_registered(PDU::PDUType type)
{
return pdu_types.count(type) != 0;
}
static id_type pdu_type_to_id(PDU::PDUType type)
{
typename pdu_map_types::const_iterator it = pdu_types.find(type);
return it->second;
}
private:
typedef std::map<id_type, allocator_type> allocators_type;
typedef std::map<PDU::PDUType, id_type> pdu_map_types;
static allocators_type allocators;
static pdu_map_types pdu_types;
};
template<typename Tag>
typename PDUAllocator<Tag>::allocators_type PDUAllocator<Tag>::allocators;
template<typename Tag>
typename PDUAllocator<Tag>::pdu_map_types PDUAllocator<Tag>::pdu_types;
template<typename IDType>
struct pdu_tag {
typedef IDType identifier_type;
};
template<typename PDUType>
struct pdu_tag_mapper;
#define TINS_GENERATE_TAG_MAPPER(pdu, id_type) \
template<> \
struct pdu_tag_mapper<pdu> { \
typedef pdu_tag<id_type> type; \
};
TINS_GENERATE_TAG_MAPPER(EthernetII, uint16_t)
TINS_GENERATE_TAG_MAPPER(SNAP, uint16_t)
TINS_GENERATE_TAG_MAPPER(SLL, uint16_t)
TINS_GENERATE_TAG_MAPPER(Dot1Q, uint16_t)
TINS_GENERATE_TAG_MAPPER(IP, uint8_t)
TINS_GENERATE_TAG_MAPPER(IPv6, uint8_t)
#undef TINS_GENERATE_TAG_MAPPER
template<typename PDUType>
PDU* allocate(
typename pdu_tag_mapper<PDUType>::type::identifier_type id,
const uint8_t *buffer,
uint32_t size)
{
return PDUAllocator<typename pdu_tag_mapper<PDUType>::type>::allocate(id, buffer, size);
}
template<typename PDUType>
bool pdu_type_registered(PDU::PDUType type)
{
return PDUAllocator<typename pdu_tag_mapper<PDUType>::type>::pdu_type_registered(type);
}
template<typename PDUType>
typename pdu_tag_mapper<PDUType>::type::identifier_type pdu_type_to_id(PDU::PDUType type)
{
return PDUAllocator<typename pdu_tag_mapper<PDUType>::type>::pdu_type_to_id(type);
}
} // namespace Interals
/**
* \endcond
*/
/**
* \brief Defines inner PDU allocators.
*/
namespace Allocators {
/**
* \brief Registers an allocator for the provided PDU type.
*
* Registering a certain allocator for a PDU type is useful for
* extending the library. Once an allocator is registered, it will
* be taken into account while constructing a PDU from a buffer.
*
* If PDU finds that it cannot define which is the protocol
* that should be allocated based on its protocol identifier, it
* will try using the registered allocators if any.
*
* \code
* // Register the 0x666 identifer. Now if EthernetII finds a
* // network layer identifier field whose value is 0x666, it will
* // use SomePDUType as its inner PDU type.
* Allocators::register_allocator<EthernetII, SomePDUType>(0x666);
* \endcode
*
* Note that some PDU types are grouped together. For example,
* registering an allocator for EthernetII will make it work for
* the rest of the link layer protocols, sine they should all work
* the same way.
*/
template<typename PDUType, typename AllocatedType>
void register_allocator(typename Internals::pdu_tag_mapper<PDUType>::type::identifier_type id)
{
Internals::PDUAllocator<
typename Internals::pdu_tag_mapper<PDUType>::type
>::template register_allocator<AllocatedType>(id);
}
} // namespace Allocators
} // namespace Tins
#endif // TINS_PDU_ALLOCATOR_H

View File

@@ -69,5 +69,6 @@
#include "stp.h"
#include "handshake_capturer.h"
#include "address_range.h"
#include "pdu_allocator.h"
#endif // TINS_TINS_H

View File

@@ -41,6 +41,7 @@
#include "pppoe.h"
#include "ip_address.h"
#include "ipv6_address.h"
#include "pdu_allocator.h"
using std::string;
@@ -74,18 +75,27 @@ Tins::PDU *pdu_from_flag(Constants::Ethernet::e flag, const uint8_t *buffer,
{
switch(flag) {
case Tins::Constants::Ethernet::IP:
return new Tins::IP(buffer, size);
return new IP(buffer, size);
case Constants::Ethernet::IPV6:
return new Tins::IPv6(buffer, size);
return new IPv6(buffer, size);
case Tins::Constants::Ethernet::ARP:
return new Tins::ARP(buffer, size);
return new ARP(buffer, size);
case Tins::Constants::Ethernet::PPPOED:
return new Tins::PPPoE(buffer, size);
return new PPPoE(buffer, size);
case Tins::Constants::Ethernet::EAPOL:
return Tins::EAPOL::from_bytes(buffer, size);
return EAPOL::from_bytes(buffer, size);
case Tins::Constants::Ethernet::VLAN:
return new Tins::Dot1Q(buffer, size);
return new Dot1Q(buffer, size);
default:
{
PDU *pdu = Internals::allocate<EthernetII>(
static_cast<uint16_t>(flag),
buffer,
size
);
if(pdu)
return pdu;
}
return rawpdu_on_no_match ? new RawPDU(buffer, size) : 0;
};
}
@@ -148,6 +158,10 @@ Constants::Ethernet::e pdu_flag_to_ether_type(PDU::PDUType flag) {
case PDU::PPPOE:
return Constants::Ethernet::PPPOED;
default:
if(Internals::pdu_type_registered<EthernetII>(flag))
return static_cast<Constants::Ethernet::e>(
Internals::pdu_type_to_id<EthernetII>(flag)
);
return Constants::Ethernet::UNKNOWN;
}
}

View File

@@ -52,6 +52,7 @@
#include "constants.h"
#include "network_interface.h"
#include "exceptions.h"
#include "pdu_allocator.h"
using std::list;
@@ -134,7 +135,15 @@ IP::IP(const uint8_t *buffer, uint32_t total_sz)
inner_pdu(new Tins::IPv6(buffer, total_sz));
break;
default:
inner_pdu(new Tins::RawPDU(buffer, total_sz));
inner_pdu(
Internals::allocate<IP>(
_ip.protocol,
buffer,
total_sz
)
);
if(!inner_pdu())
inner_pdu(new RawPDU(buffer, total_sz));
break;
}
}
@@ -397,8 +406,13 @@ void IP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU* pare
new_flag = Constants::IP::PROTO_ICMP;
break;
default:
// check for other protos
new_flag = 0xff;
if(Internals::pdu_type_registered<IP>(inner_pdu()->pdu_type()))
new_flag = static_cast<Constants::IP::e>(
Internals::pdu_type_to_id<IP>(inner_pdu()->pdu_type())
);
else
// check for other protos
new_flag = 0xff;
};
protocol(new_flag);
//flag(new_flag);

View File

@@ -48,6 +48,7 @@
#include "icmpv6.h"
#include "rawpdu.h"
#include "exceptions.h"
#include "pdu_allocator.h"
namespace Tins {
@@ -101,7 +102,15 @@ IPv6::IPv6(const uint8_t *buffer, uint32_t total_sz)
inner_pdu(new Tins::ICMPv6(buffer, total_sz));
break;
default:
inner_pdu(new Tins::RawPDU(buffer, total_sz));
inner_pdu(
Internals::allocate<IPv6>(
current_header,
buffer,
total_sz
)
);
if(!inner_pdu())
inner_pdu(new Tins::RawPDU(buffer, total_sz));
break;
}
total_sz = 0;
@@ -214,10 +223,13 @@ void IPv6::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *pa
new_flag = Constants::IP::PROTO_ICMPV6;
break;
default:
if(Internals::pdu_type_registered<IPv6>(inner_pdu()->pdu_type()))
new_flag = static_cast<Constants::IP::e>(
Internals::pdu_type_to_id<IPv6>(inner_pdu()->pdu_type())
);
break;
};
if(new_flag != 0xff)
set_last_next_header(new_flag);
set_last_next_header(new_flag);
}
payload_length(total_sz - sizeof(_header));
std::memcpy(buffer, &_header, sizeof(_header));

View File

@@ -874,7 +874,8 @@
../include/dot11/../cxxstd.h ../include/dot11/../macros.h \
../include/ipv6.h ../include/ipv6_address.h ../include/arp.h \
../include/eapol.h ../include/rawpdu.h ../include/dot1q.h \
../include/pppoe.h ../include/ip_address.h ../include/ipv6_address.h
../include/pppoe.h ../include/ip_address.h ../include/ipv6_address.h \
../include/pdu_allocator.h
../include/internals.h:
@@ -941,6 +942,8 @@
../include/ip_address.h:
../include/ipv6_address.h:
../include/pdu_allocator.h:
../src/ip.o: ../src/ip.cpp ../include/ip.h ../include/pdu.h \
../include/macros.h ../include/cxxstd.h ../include/exceptions.h \
../include/small_uint.h ../include/endianness.h ../include/ip_address.h \
@@ -949,7 +952,8 @@
../include/utils.h ../include/hw_address.h ../include/internals.h \
../include/constants.h ../include/packet_sender.h \
../include/network_interface.h ../include/constants.h \
../include/network_interface.h ../include/exceptions.h
../include/network_interface.h ../include/exceptions.h \
../include/pdu_allocator.h
../include/ip.h:
@@ -998,6 +1002,8 @@
../include/network_interface.h:
../include/exceptions.h:
../include/pdu_allocator.h:
../src/ip_address.o: ../src/ip_address.cpp ../include/ip_address.h \
../include/cxxstd.h ../include/endianness.h ../include/macros.h \
../include/address_range.h ../include/ip_address.h \
@@ -1034,7 +1040,7 @@
../include/packet_sender.h ../include/network_interface.h \
../include/hw_address.h ../include/ip_address.h ../include/ip.h \
../include/tcp.h ../include/udp.h ../include/icmp.h ../include/icmpv6.h \
../include/rawpdu.h ../include/exceptions.h
../include/rawpdu.h ../include/exceptions.h ../include/pdu_allocator.h
../include/ipv6.h:
@@ -1077,14 +1083,37 @@
../include/rawpdu.h:
../include/exceptions.h:
../include/pdu_allocator.h:
../src/ipv6_address.o: ../src/ipv6_address.cpp ../include/macros.h \
../include/ipv6_address.h ../include/cxxstd.h
../include/ipv6_address.h ../include/cxxstd.h ../include/address_range.h \
../include/ip_address.h ../include/ipv6_address.h \
../include/endianness.h ../include/macros.h ../include/internals.h \
../include/constants.h ../include/pdu.h ../include/exceptions.h
../include/macros.h:
../include/ipv6_address.h:
../include/cxxstd.h:
../include/address_range.h:
../include/ip_address.h:
../include/ipv6_address.h:
../include/endianness.h:
../include/macros.h:
../include/internals.h:
../include/constants.h:
../include/pdu.h:
../include/exceptions.h:
../src/llc.o: ../src/llc.cpp ../include/llc.h ../include/macros.h \
../include/pdu.h ../include/cxxstd.h ../include/exceptions.h \
../include/endianness.h ../include/stp.h ../include/hw_address.h \
@@ -1800,6 +1829,47 @@ src/address_range.o: src/address_range.cpp ../include/address_range.h \
../include/ip_address.h:
../include/ipv6_address.h:
src/allocators.o: src/allocators.cpp ../include/pdu_allocator.h \
../include/pdu.h ../include/macros.h ../include/cxxstd.h \
../include/exceptions.h ../include/ethernetII.h ../include/endianness.h \
../include/hw_address.h ../include/snap.h ../include/small_uint.h \
../include/sll.h ../include/dot1q.h ../include/ip.h \
../include/ip_address.h ../include/pdu_option.h ../include/ipv6.h \
../include/ipv6_address.h
../include/pdu_allocator.h:
../include/pdu.h:
../include/macros.h:
../include/cxxstd.h:
../include/exceptions.h:
../include/ethernetII.h:
../include/endianness.h:
../include/hw_address.h:
../include/snap.h:
../include/small_uint.h:
../include/sll.h:
../include/dot1q.h:
../include/ip.h:
../include/ip_address.h:
../include/pdu_option.h:
../include/ipv6.h:
../include/ipv6_address.h:
src/arp.o: src/arp.cpp ../include/arp.h ../include/macros.h \
../include/pdu.h ../include/cxxstd.h ../include/exceptions.h \
@@ -2778,7 +2848,7 @@ src/ethernetII.o: src/ethernetII.cpp ../include/ethernetII.h \
../include/utils.h ../include/ip_address.h ../include/ipv6_address.h \
../include/internals.h ../include/constants.h ../include/macros.h \
../include/ipv6.h ../include/small_uint.h ../include/pdu_option.h \
../include/ip.h
../include/ip.h ../include/tcp.h ../include/rawpdu.h
../include/ethernetII.h:
@@ -2813,6 +2883,10 @@ src/ethernetII.o: src/ethernetII.cpp ../include/ethernetII.h \
../include/pdu_option.h:
../include/ip.h:
../include/tcp.h:
../include/rawpdu.h:
src/hwaddress.o: src/hwaddress.cpp ../include/hw_address.h \
../include/cxxstd.h

119
tests/src/allocators.cpp Normal file
View File

@@ -0,0 +1,119 @@
#include <gtest/gtest.h>
#include <vector>
#include <algorithm>
#include <stdint.h>
#include "pdu_allocator.h"
#include "ethernetII.h"
#include "snap.h"
#include "sll.h"
#include "dot1q.h"
#include "ip.h"
#include "ipv6.h"
using namespace Tins;
class AllocatorsTest : public testing::Test {
public:
static const uint8_t link_layer_data_buffer[], ipv4_data_buffer[], ipv6_data_buffer[];
};
const uint8_t AllocatorsTest::link_layer_data_buffer[] = {
0, 27, 17, 210, 243, 22, 0, 25, 209, 22, 248, 43, 6, 102, 65, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65, 65, 65, 65, 65, 65
};
const uint8_t AllocatorsTest::ipv4_data_buffer[] = {
255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 8, 0, 69, 0, 0, 60,
0, 1, 0, 0, 64, 255, 123, 192, 127, 0, 0, 1, 127, 0, 0, 1, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65, 65, 65, 65
};
const uint8_t AllocatorsTest::ipv6_data_buffer[] = {
255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 134, 221, 96, 0, 0,
0, 0, 40, 250, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 65, 65, 65, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65
};
class DummyPDU : public PDU {
public:
static const PDU::PDUType pdu_flag;
DummyPDU(const uint8_t* data, uint32_t sz) : buffer(data, data + sz) { }
DummyPDU *clone() const { return new DummyPDU(*this); }
uint32_t header_size() const { return buffer.size(); }
PDUType pdu_type() const { return pdu_flag; }
void write_serialization(uint8_t *data, uint32_t, const PDU *)
{
std::copy(buffer.begin(), buffer.end(), data);
}
std::vector<uint8_t> buffer;
};
const PDU::PDUType DummyPDU::pdu_flag = static_cast<PDU::PDUType>(0xefff);
TEST_F(AllocatorsTest, LinkLayerPDUs) {
Allocators::register_allocator<EthernetII, DummyPDU>(1638);
Allocators::register_allocator<SNAP, DummyPDU>(25);
Allocators::register_allocator<Dot1Q, DummyPDU>(4562);
Allocators::register_allocator<SLL, DummyPDU>(16705);
std::vector<uint8_t> link_layer_data(
link_layer_data_buffer,
link_layer_data_buffer + sizeof(link_layer_data_buffer)
);
{
EthernetII pkt(&link_layer_data[0], link_layer_data.size());
EXPECT_TRUE(pkt.find_pdu<DummyPDU>());
EXPECT_EQ(pkt.serialize(), link_layer_data);
}
{
SNAP pkt(&link_layer_data[0], link_layer_data.size());
EXPECT_TRUE(pkt.find_pdu<DummyPDU>());
EXPECT_EQ(pkt.serialize(), link_layer_data);
}
{
SLL pkt(&link_layer_data[0], link_layer_data.size());
EXPECT_TRUE(pkt.find_pdu<DummyPDU>());
EXPECT_EQ(pkt.serialize(), link_layer_data);
}
{
Dot1Q pkt(&link_layer_data[0], link_layer_data.size());
EXPECT_TRUE(pkt.find_pdu<DummyPDU>());
EXPECT_EQ(pkt.serialize(), link_layer_data);
}
}
TEST_F(AllocatorsTest, IP) {
std::vector<uint8_t> ipv4_data(
ipv4_data_buffer,
ipv4_data_buffer + sizeof(ipv4_data_buffer)
);
Allocators::register_allocator<IP, DummyPDU>(255);
EthernetII pkt(&ipv4_data[0], ipv4_data.size());
EXPECT_TRUE(pkt.find_pdu<IP>());
EXPECT_TRUE(pkt.find_pdu<DummyPDU>());
EXPECT_EQ(pkt.serialize(), ipv4_data);
}
TEST_F(AllocatorsTest, IPv6) {
std::vector<uint8_t> ipv6_data(
ipv6_data_buffer,
ipv6_data_buffer + sizeof(ipv6_data_buffer)
);
Allocators::register_allocator<IPv6, DummyPDU>(250);
{
EthernetII pkt(&ipv6_data[0], ipv6_data.size());
EXPECT_TRUE(pkt.find_pdu<IPv6>());
EXPECT_TRUE(pkt.find_pdu<DummyPDU>());
EXPECT_EQ(pkt.serialize(), ipv6_data);
}
}