mirror of
https://github.com/mfontanini/libtins
synced 2026-01-23 02:35:57 +01:00
Add VXLAN support (#501)
This patch adds a new PDU class to support VXLAN. Several VXLAN-related tests have also been added. Signed-off-by: James Raphael Tiovalen <jamestiotio@gmail.com>
This commit is contained in:
@@ -180,6 +180,7 @@ public:
|
|||||||
PKTAP,
|
PKTAP,
|
||||||
MPLS,
|
MPLS,
|
||||||
DOT11_CONTROL_TA,
|
DOT11_CONTROL_TA,
|
||||||
|
VXLAN,
|
||||||
UNKNOWN = 999,
|
UNKNOWN = 999,
|
||||||
USER_DEFINED_PDU = 1000
|
USER_DEFINED_PDU = 1000
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -78,7 +78,7 @@
|
|||||||
#include <tins/pdu_allocator.h>
|
#include <tins/pdu_allocator.h>
|
||||||
#include <tins/ipsec.h>
|
#include <tins/ipsec.h>
|
||||||
#include <tins/ip_reassembler.h>
|
#include <tins/ip_reassembler.h>
|
||||||
|
|
||||||
#include <tins/pdu_iterator.h>
|
#include <tins/pdu_iterator.h>
|
||||||
|
#include <tins/vxlan.h>
|
||||||
|
|
||||||
#endif // TINS_TINS_H
|
#endif // TINS_TINS_H
|
||||||
|
|||||||
98
include/tins/vxlan.h
Normal file
98
include/tins/vxlan.h
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
#ifndef TINS_VXLAN_H
|
||||||
|
#define TINS_VXLAN_H
|
||||||
|
|
||||||
|
#include <tins/pdu.h>
|
||||||
|
#include <tins/small_uint.h>
|
||||||
|
|
||||||
|
namespace Tins {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class VXLAN
|
||||||
|
* \brief Represents a VXLAN PDU.
|
||||||
|
*
|
||||||
|
* This class represents a VXLAN PDU.
|
||||||
|
*
|
||||||
|
* \sa RawPDU
|
||||||
|
*/
|
||||||
|
class TINS_API VXLAN : public PDU {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* \brief This PDU's flag.
|
||||||
|
*/
|
||||||
|
static const PDU::PDUType pdu_flag = PDU::VXLAN;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Constructs a VXLAN PDU.
|
||||||
|
*
|
||||||
|
* \param vni VXLAN Network Identifier.
|
||||||
|
*/
|
||||||
|
VXLAN(const small_uint<24> vni = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Constructs a VXLAN object from a buffer and adds
|
||||||
|
* the Ethernet II PDU.
|
||||||
|
*
|
||||||
|
* \param buffer The buffer from which this PDU will be constructed.
|
||||||
|
* \param total_sz The total size of the buffer.
|
||||||
|
*/
|
||||||
|
VXLAN(const uint8_t* buffer, uint32_t total_sz);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Getter for the flags.
|
||||||
|
*/
|
||||||
|
uint8_t get_flags() const { return Endian::be_to_host(header_.flags) >> 24; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Getter for the VNI.
|
||||||
|
*/
|
||||||
|
small_uint<24> get_vni() const { return Endian::be_to_host(header_.vni) >> 8; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Setter for the flags.
|
||||||
|
* \param new_flags The new flags.
|
||||||
|
*/
|
||||||
|
void set_flags(uint8_t new_flags) { header_.flags = Endian::host_to_be(new_flags << 24); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Setter for the VNI.
|
||||||
|
* \param new_vni The new VNI.
|
||||||
|
*/
|
||||||
|
void set_vni(small_uint<24> new_vni) { header_.vni = Endian::host_to_be(new_vni << 8); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Returns the VXLAN frame's header length.
|
||||||
|
*
|
||||||
|
* This method overrides PDU::header_size. This size includes the
|
||||||
|
* payload and options size.
|
||||||
|
*
|
||||||
|
* \return An uint32_t with the header's size.
|
||||||
|
* \sa PDU::header_size
|
||||||
|
*/
|
||||||
|
uint32_t header_size() const { return sizeof(header_); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Getter for the PDU's type.
|
||||||
|
* \sa PDU::pdu_type
|
||||||
|
*/
|
||||||
|
PDUType pdu_type() const { return pdu_flag; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \sa PDU::clone
|
||||||
|
*/
|
||||||
|
VXLAN *clone() const { return new VXLAN(*this); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
TINS_BEGIN_PACK
|
||||||
|
struct vxlan_header {
|
||||||
|
uint32_t flags;
|
||||||
|
uint32_t vni;
|
||||||
|
} TINS_END_PACK;
|
||||||
|
|
||||||
|
void write_serialization(uint8_t* buffer, uint32_t total_sz);
|
||||||
|
|
||||||
|
vxlan_header header_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // Tins
|
||||||
|
|
||||||
|
#endif // TINS_VXLAN_H
|
||||||
@@ -73,6 +73,7 @@ set(SOURCES
|
|||||||
utils/routing_utils.cpp
|
utils/routing_utils.cpp
|
||||||
utils/resolve_utils.cpp
|
utils/resolve_utils.cpp
|
||||||
utils/pdu_utils.cpp
|
utils/pdu_utils.cpp
|
||||||
|
vxlan.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(HEADERS
|
set(HEADERS
|
||||||
|
|||||||
36
src/vxlan.cpp
Normal file
36
src/vxlan.cpp
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#include <tins/internals.h>
|
||||||
|
#include <tins/memory_helpers.h>
|
||||||
|
#include <tins/small_uint.h>
|
||||||
|
#include <tins/vxlan.h>
|
||||||
|
|
||||||
|
using Tins::Memory::InputMemoryStream;
|
||||||
|
using Tins::Memory::OutputMemoryStream;
|
||||||
|
|
||||||
|
namespace Tins {
|
||||||
|
|
||||||
|
VXLAN::VXLAN(const small_uint<24> vni) {
|
||||||
|
set_flags(8);
|
||||||
|
set_vni(vni);
|
||||||
|
}
|
||||||
|
|
||||||
|
VXLAN::VXLAN(const uint8_t* buffer, uint32_t total_sz) {
|
||||||
|
InputMemoryStream stream(buffer, total_sz);
|
||||||
|
stream.read(header_);
|
||||||
|
// If there is any size left
|
||||||
|
if (stream) {
|
||||||
|
inner_pdu(
|
||||||
|
Internals::pdu_from_flag(
|
||||||
|
PDU::ETHERNET_II,
|
||||||
|
stream.pointer(),
|
||||||
|
stream.size()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VXLAN::write_serialization(uint8_t* buffer, uint32_t total_sz) {
|
||||||
|
OutputMemoryStream stream(buffer, total_sz);
|
||||||
|
stream.write(header_);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // Tins
|
||||||
@@ -70,6 +70,7 @@ CREATE_TEST(tcp)
|
|||||||
CREATE_TEST(tcp_ip)
|
CREATE_TEST(tcp_ip)
|
||||||
CREATE_TEST(udp)
|
CREATE_TEST(udp)
|
||||||
CREATE_TEST(utils)
|
CREATE_TEST(utils)
|
||||||
|
CREATE_TEST(vxlan)
|
||||||
|
|
||||||
IF(LIBTINS_ENABLE_PCAP)
|
IF(LIBTINS_ENABLE_PCAP)
|
||||||
CREATE_TEST(offline_packet_filter)
|
CREATE_TEST(offline_packet_filter)
|
||||||
|
|||||||
90
tests/src/vxlan_test.cpp
Normal file
90
tests/src/vxlan_test.cpp
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <string>
|
||||||
|
#include <tins/ethernetII.h>
|
||||||
|
#include <tins/ip.h>
|
||||||
|
#include <tins/tcp.h>
|
||||||
|
#include <tins/udp.h>
|
||||||
|
#include <tins/pdu.h>
|
||||||
|
#include <tins/small_uint.h>
|
||||||
|
#include <tins/vxlan.h>
|
||||||
|
|
||||||
|
#define PACKET_SIZE 68ul
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace Tins;
|
||||||
|
|
||||||
|
class VXLANTest : public testing::Test {
|
||||||
|
public:
|
||||||
|
static const uint8_t expected_packet[PACKET_SIZE];
|
||||||
|
static const uint8_t flags;
|
||||||
|
static const uint16_t dport, sport, p_type;
|
||||||
|
static const small_uint<24> vni;
|
||||||
|
static const IP::address_type dst_ip, src_ip;
|
||||||
|
static const EthernetII::address_type dst_addr, src_addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t VXLANTest::expected_packet[PACKET_SIZE] = {
|
||||||
|
0x08, 0x00, 0x00, 0x00,
|
||||||
|
0xff, 0xff, 0xff, 0x00,
|
||||||
|
0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
|
||||||
|
0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t VXLANTest::flags = 8;
|
||||||
|
const uint16_t VXLANTest::dport = 19627;
|
||||||
|
const uint16_t VXLANTest::sport = 4789;
|
||||||
|
const uint16_t VXLANTest::p_type = 0xd0ab;
|
||||||
|
const small_uint<24> VXLANTest::vni = 0xffffff;
|
||||||
|
const IP::address_type VXLANTest::dst_ip = IP::address_type{"2.2.2.2"};
|
||||||
|
const IP::address_type VXLANTest::src_ip = IP::address_type{"1.1.1.1"};
|
||||||
|
const EthernetII::address_type VXLANTest::dst_addr = EthernetII::address_type{"aa:bb:cc:dd:ee:ff"};
|
||||||
|
const EthernetII::address_type VXLANTest::src_addr = EthernetII::address_type{"8a:8b:8c:8d:8e:8f"};
|
||||||
|
|
||||||
|
TEST_F(VXLANTest, Flags) {
|
||||||
|
auto const vxlan = VXLAN{};
|
||||||
|
EXPECT_EQ(vxlan.get_flags(), flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(VXLANTest, VNI) {
|
||||||
|
auto const vxlan = VXLAN{vni};
|
||||||
|
EXPECT_EQ(vxlan.get_vni(), vni);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(VXLANTest, Find) {
|
||||||
|
auto const pdu = VXLAN{} / EthernetII{dst_addr, src_addr};
|
||||||
|
auto const eth = pdu.find_pdu<EthernetII>();
|
||||||
|
ASSERT_TRUE(eth != nullptr);
|
||||||
|
EXPECT_EQ(eth->dst_addr(), dst_addr);
|
||||||
|
EXPECT_EQ(eth->src_addr(), src_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(VXLANTest, Serialize) {
|
||||||
|
auto eth = EthernetII{dst_addr, src_addr};
|
||||||
|
eth.payload_type(p_type);
|
||||||
|
auto vxlan = VXLAN{vni};
|
||||||
|
vxlan.inner_pdu(eth);
|
||||||
|
auto serialized = vxlan.serialize();
|
||||||
|
ASSERT_EQ(serialized.size(), PACKET_SIZE);
|
||||||
|
EXPECT_TRUE(std::equal(serialized.begin(), serialized.end(), expected_packet));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(VXLANTest, ConstructorFromBuffer) {
|
||||||
|
auto vxlan = VXLAN{expected_packet, PACKET_SIZE};
|
||||||
|
EXPECT_EQ(vxlan.get_vni(), vni);
|
||||||
|
EXPECT_EQ(vxlan.get_flags(), flags);
|
||||||
|
auto const eth = vxlan.find_pdu<EthernetII>();
|
||||||
|
ASSERT_TRUE(eth != nullptr);
|
||||||
|
EXPECT_EQ(eth->dst_addr(), dst_addr);
|
||||||
|
EXPECT_EQ(eth->src_addr(), src_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(VXLANTest, OuterUDP) {
|
||||||
|
auto pkt = IP{dst_ip, src_ip} / UDP{dport, sport} / VXLAN{expected_packet, PACKET_SIZE};
|
||||||
|
auto const vxlan = pkt.find_pdu<VXLAN>();
|
||||||
|
ASSERT_TRUE(vxlan != nullptr);
|
||||||
|
EXPECT_EQ(vxlan->get_flags(), flags);
|
||||||
|
EXPECT_EQ(vxlan->get_vni(), vni);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user