Redefine VpnPackets as TLV containers
This commit is contained in:
parent
20d0d3fc59
commit
324d156cf3
2 changed files with 206 additions and 7 deletions
|
@ -2,8 +2,10 @@
|
||||||
#include "VpnPeer.hpp"
|
#include "VpnPeer.hpp"
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
const size_t VpnPacket::VPN_HEADER_BYTES = 8;
|
const size_t VpnPacket::VPN_HEADER_BYTES = 8;
|
||||||
|
const size_t VpnPacket::TLV_HEADER_BYTES = 3;
|
||||||
uint32_t VpnPacket::_next_general_seqno = 0;
|
uint32_t VpnPacket::_next_general_seqno = 0;
|
||||||
|
|
||||||
static const size_t OUTER_HEADERS_BYTES =
|
static const size_t OUTER_HEADERS_BYTES =
|
||||||
|
@ -15,8 +17,8 @@ static const int
|
||||||
DATA_TIMESTAMP_POS = 4;
|
DATA_TIMESTAMP_POS = 4;
|
||||||
|
|
||||||
VpnPacket::VpnPacket(size_t mtu)
|
VpnPacket::VpnPacket(size_t mtu)
|
||||||
: _peer(nullptr), _data_space(mtu-OUTER_HEADERS_BYTES), _data_size(0),
|
: _peer(nullptr), _data_space(mtu-OUTER_HEADERS_BYTES),
|
||||||
_reception_timestamp(0)
|
_data_size(VPN_HEADER_BYTES), _reception_timestamp(0)
|
||||||
{
|
{
|
||||||
_data = new char[mtu - OUTER_HEADERS_BYTES];
|
_data = new char[mtu - OUTER_HEADERS_BYTES];
|
||||||
}
|
}
|
||||||
|
@ -25,6 +27,13 @@ VpnPacket::~VpnPacket() {
|
||||||
delete[] _data;
|
delete[] _data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VpnPacket::iterator VpnPacket::begin() {
|
||||||
|
return iterator(VpnPacketTLV(*this, 0));
|
||||||
|
}
|
||||||
|
VpnPacket::iterator VpnPacket::end() {
|
||||||
|
return iterator(VpnPacketTLV(*this, get_payload_size()));
|
||||||
|
}
|
||||||
|
|
||||||
bool VpnPacket::parse_as_ipv6() {
|
bool VpnPacket::parse_as_ipv6() {
|
||||||
return parse_ipv6_header(get_payload(), get_payload_size(), _ipv6_header);
|
return parse_ipv6_header(get_payload(), get_payload_size(), _ipv6_header);
|
||||||
}
|
}
|
||||||
|
@ -55,3 +64,50 @@ uint32_t VpnPacket::next_seqno() {
|
||||||
return _peer->next_seqno();
|
return _peer->next_seqno();
|
||||||
return _next_general_seqno++;
|
return _next_general_seqno++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VpnPacketTLV::VpnPacketTLV(VpnPacket& packet, size_t payload_offset)
|
||||||
|
: _packet(packet), _tlv_pos(payload_offset)
|
||||||
|
{}
|
||||||
|
|
||||||
|
VpnPacketTLV VpnPacketTLV::create(
|
||||||
|
VpnPacket& packet, VpnPacket::PayloadType type)
|
||||||
|
{
|
||||||
|
VpnPacketTLV tlv = VpnPacketTLV(packet, packet.get_payload_size());
|
||||||
|
packet.increase_payload_size(VpnPacket::TLV_HEADER_BYTES);
|
||||||
|
|
||||||
|
char* data = tlv.get_data();
|
||||||
|
data[0] = type;
|
||||||
|
*(uint16_t*)(data+1) = 0; // Set len to 0
|
||||||
|
|
||||||
|
return tlv;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t VpnPacketTLV::get_payload_size() const {
|
||||||
|
return *(uint16_t*)(get_data() + 1);
|
||||||
|
}
|
||||||
|
void VpnPacketTLV::set_payload_size(uint16_t size) {
|
||||||
|
uint16_t* data_size_ptr = (uint16_t*)(get_data() + 1);
|
||||||
|
uint16_t old_size = *data_size_ptr;
|
||||||
|
*data_size_ptr = size;
|
||||||
|
_packet.increase_payload_size(size - old_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
VpnPacket::PayloadType VpnPacketTLV::get_type() const {
|
||||||
|
return (VpnPacket::PayloadType)(*(uint8_t*)(get_data()));
|
||||||
|
}
|
||||||
|
void VpnPacketTLV::set_type(VpnPacket::PayloadType type) {
|
||||||
|
*(uint8_t*)(get_data()) = (uint8_t) type;
|
||||||
|
}
|
||||||
|
|
||||||
|
TunnelledPacket::TunnelledPacket(VpnPacket& packet, size_t payload_offset)
|
||||||
|
: VpnPacketTLV(packet, payload_offset)
|
||||||
|
{}
|
||||||
|
|
||||||
|
TunnelledPacket::TunnelledPacket(const VpnPacketTLV& copy)
|
||||||
|
: VpnPacketTLV(copy._packet, copy._tlv_pos)
|
||||||
|
{}
|
||||||
|
|
||||||
|
TunnelledPacket TunnelledPacket::create(VpnPacket& packet) {
|
||||||
|
return VpnPacketTLV::create(packet, VpnPacket::PAYLOAD_TYPE_TUNNELLED);
|
||||||
|
}
|
||||||
|
|
153
VpnPacket.hpp
153
VpnPacket.hpp
|
@ -9,24 +9,53 @@
|
||||||
|
|
||||||
/** VPN packet layout:
|
/** VPN packet layout:
|
||||||
*
|
*
|
||||||
* +-------+-------+-------+-------+-------+-------+-------+-------+
|
* 0 1 2 3
|
||||||
* | 1B | 1B | 1B | 1B | 1B | 1B | 1B | 1B |
|
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
* +-------+-------+-------+-------+-------+-------+-------+-------+
|
* +---------------+---------------+---------------+---------------+
|
||||||
* | Sequence number [4B] | Sending timestamp (μs) [4B] |
|
* | Sequence number [4B] |
|
||||||
* +---------------------------------------------------------------+
|
* +---------------------------------------------------------------+
|
||||||
* | Nested packet (payload) |
|
* | Sending timestamp (μs) [4B] |
|
||||||
|
* +---------------+-----------------------------------------------+
|
||||||
|
* | Type [1B] | First payload size (B) [2B] | Payload |
|
||||||
|
* +---------------+-----------------------------------------------+
|
||||||
|
* | Payload (cont.) |
|
||||||
|
* +---------------+-----------------------------------------------+
|
||||||
|
* | Type [1B] | Second payload size (B) [2B] | Payload |
|
||||||
|
* +---------------+-----------------------------------------------+
|
||||||
|
* | Payload (cont.) |
|
||||||
* +---------------------------------------------------------------+
|
* +---------------------------------------------------------------+
|
||||||
|
* | ... |
|
||||||
|
* +---------------------------------------------------------------+
|
||||||
|
*
|
||||||
|
* Where
|
||||||
|
* - Type is one of the values from PayloadType below;
|
||||||
|
* - Payload size is the size of the payload (excluding headers), in bytes;
|
||||||
|
* - Payload is an arbitrary value, defined by Type
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class VpnPeer;
|
class VpnPeer;
|
||||||
|
class VpnPacketTLVIterator;
|
||||||
|
|
||||||
class VpnPacket {
|
class VpnPacket {
|
||||||
public:
|
public:
|
||||||
static const size_t VPN_HEADER_BYTES;
|
static const size_t VPN_HEADER_BYTES;
|
||||||
|
static const size_t TLV_HEADER_BYTES;
|
||||||
|
|
||||||
|
typedef VpnPacketTLVIterator iterator;
|
||||||
|
|
||||||
|
enum PayloadType {
|
||||||
|
PAYLOAD_TYPE_UNDEF, ///< Undefined packet type
|
||||||
|
PAYLOAD_TYPE_TUNNELLED, ///< A tunnelled packet
|
||||||
|
PAYLOAD_TYPE_RR, ///< Receiver report
|
||||||
|
PAYLOAD_TYPE_REMB, ///< Receiver Estimated Maximum Bitrate
|
||||||
|
};
|
||||||
|
|
||||||
VpnPacket(size_t mtu);
|
VpnPacket(size_t mtu);
|
||||||
~VpnPacket();
|
~VpnPacket();
|
||||||
|
|
||||||
|
iterator begin();
|
||||||
|
iterator end();
|
||||||
|
|
||||||
/// Set packet peer -- used for sequence numbers
|
/// Set packet peer -- used for sequence numbers
|
||||||
void set_peer(std::shared_ptr<VpnPeer> peer) { _peer = peer; }
|
void set_peer(std::shared_ptr<VpnPeer> peer) { _peer = peer; }
|
||||||
|
|
||||||
|
@ -35,23 +64,42 @@ class VpnPacket {
|
||||||
bool ipv6_parsed() const { return _ipv6_parsed; }
|
bool ipv6_parsed() const { return _ipv6_parsed; }
|
||||||
const IPv6Header& get_ipv6_header() const { return _ipv6_header; }
|
const IPv6Header& get_ipv6_header() const { return _ipv6_header; }
|
||||||
|
|
||||||
|
/// Get a pointer to the packet payload (const version)
|
||||||
const char* get_payload() const { return _data + VPN_HEADER_BYTES; }
|
const char* get_payload() const { return _data + VPN_HEADER_BYTES; }
|
||||||
|
/// Get a pointer to the packet payload
|
||||||
char* get_payload() { return _data + VPN_HEADER_BYTES; }
|
char* get_payload() { return _data + VPN_HEADER_BYTES; }
|
||||||
|
/// Get a pointer to the first free byte of the packet payload
|
||||||
|
char* get_next_payload() { return get_payload() + get_payload_size(); }
|
||||||
|
/// Get the space allocated for the packet payload
|
||||||
size_t get_payload_space() const {
|
size_t get_payload_space() const {
|
||||||
return _data_space - VPN_HEADER_BYTES; }
|
return _data_space - VPN_HEADER_BYTES; }
|
||||||
|
/// Get the current size filled by the payload
|
||||||
size_t get_payload_size() const {
|
size_t get_payload_size() const {
|
||||||
return _data_size - VPN_HEADER_BYTES; }
|
return _data_size - VPN_HEADER_BYTES; }
|
||||||
|
/// Set current size filled by the packet payload
|
||||||
void set_payload_size(size_t payload_size) {
|
void set_payload_size(size_t payload_size) {
|
||||||
_data_size = payload_size + VPN_HEADER_BYTES; }
|
_data_size = payload_size + VPN_HEADER_BYTES; }
|
||||||
|
/// Increase the current size filled by the packet payload (size may be
|
||||||
|
/// negative).
|
||||||
|
void increase_payload_size(ssize_t payload_size_increment) {
|
||||||
|
_data_size += payload_size_increment; }
|
||||||
|
|
||||||
|
/// Get a pointer to the full packet data (const version)
|
||||||
const char* get_data() const { return _data; }
|
const char* get_data() const { return _data; }
|
||||||
|
/// Get a pointer to the full packet data
|
||||||
char* get_data() { return _data; }
|
char* get_data() { return _data; }
|
||||||
|
/// Get the space allocated for the packet
|
||||||
size_t get_data_space() const { return _data_space; }
|
size_t get_data_space() const { return _data_space; }
|
||||||
|
/// Get the total current size of the packet
|
||||||
size_t get_data_size() const { return _data_size; }
|
size_t get_data_size() const { return _data_size; }
|
||||||
|
/// Set the total current size of the packet
|
||||||
void set_data_size(size_t data_size) { _data_size = data_size; }
|
void set_data_size(size_t data_size) { _data_size = data_size; }
|
||||||
|
|
||||||
|
/// Get this packet's seqno
|
||||||
uint32_t get_seqno() const;
|
uint32_t get_seqno() const;
|
||||||
|
/// Get this packet's sending timestamp
|
||||||
uint32_t get_sending_timestamp() const;
|
uint32_t get_sending_timestamp() const;
|
||||||
|
/// Get this packet's reception timestamp
|
||||||
uint32_t get_reception_timestamp() const { return _reception_timestamp; }
|
uint32_t get_reception_timestamp() const { return _reception_timestamp; }
|
||||||
|
|
||||||
/** Fill the headers of the packet. This method must be called as close
|
/** Fill the headers of the packet. This method must be called as close
|
||||||
|
@ -81,3 +129,98 @@ class VpnPacket {
|
||||||
|
|
||||||
static uint32_t _next_general_seqno;
|
static uint32_t _next_general_seqno;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Base class for a TLV contained in a VpnPacket */
|
||||||
|
class VpnPacketTLV {
|
||||||
|
public:
|
||||||
|
VpnPacketTLV(VpnPacket& packet, size_t payload_offset);
|
||||||
|
|
||||||
|
static VpnPacketTLV create(
|
||||||
|
VpnPacket& packet,
|
||||||
|
VpnPacket::PayloadType type=VpnPacket::PAYLOAD_TYPE_UNDEF);
|
||||||
|
|
||||||
|
const VpnPacket& get_packet() const { return _packet; }
|
||||||
|
VpnPacket& get_packet() { return _packet; }
|
||||||
|
|
||||||
|
/// Get the offset in the packet
|
||||||
|
size_t get_offset() const { return _tlv_pos; }
|
||||||
|
|
||||||
|
/// Get a pointer to the payload (const version)
|
||||||
|
const char* get_payload() const {
|
||||||
|
return _packet.get_payload() + _tlv_pos + VpnPacket::TLV_HEADER_BYTES; }
|
||||||
|
/// Get a pointer to the payload
|
||||||
|
char* get_payload() {
|
||||||
|
return _packet.get_payload() + _tlv_pos + VpnPacket::TLV_HEADER_BYTES; }
|
||||||
|
/// Get the current payload size
|
||||||
|
uint16_t get_payload_size() const;
|
||||||
|
/// Set the current payload size
|
||||||
|
void set_payload_size(uint16_t size);
|
||||||
|
|
||||||
|
/// Get a pointer to the raw data (const version)
|
||||||
|
const char* get_data() const {
|
||||||
|
return _packet.get_payload() + _tlv_pos; }
|
||||||
|
/// Get a pointer to the raw data
|
||||||
|
char* get_data() { return _packet.get_payload() + _tlv_pos; }
|
||||||
|
/// Get the current raw data size
|
||||||
|
uint16_t get_data_size() const {
|
||||||
|
return get_payload_size() + VpnPacket::TLV_HEADER_BYTES; }
|
||||||
|
/// Set the current raw data size
|
||||||
|
void set_data_size(uint16_t size) {
|
||||||
|
set_payload_size(size + VpnPacket::TLV_HEADER_BYTES); }
|
||||||
|
|
||||||
|
/// Get this TLV's type
|
||||||
|
VpnPacket::PayloadType get_type() const;
|
||||||
|
|
||||||
|
bool operator==(const VpnPacketTLV& other) const {
|
||||||
|
return &_packet == &other._packet && _tlv_pos == other._tlv_pos; }
|
||||||
|
|
||||||
|
protected: // meth
|
||||||
|
/// Set this TLV's type
|
||||||
|
void set_type(VpnPacket::PayloadType type);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
VpnPacket& _packet;
|
||||||
|
size_t _tlv_pos;
|
||||||
|
|
||||||
|
friend class TunnelledPacket;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** An iterator over the VpnPacketTLVs of a VpnPacket */
|
||||||
|
class VpnPacketTLVIterator {
|
||||||
|
public:
|
||||||
|
using iterator_category = std::input_iterator_tag;
|
||||||
|
using value_type = VpnPacketTLV;
|
||||||
|
using difference_type = ptrdiff_t;
|
||||||
|
using pointer = VpnPacketTLV*;
|
||||||
|
using reference = VpnPacketTLV&;
|
||||||
|
|
||||||
|
VpnPacketTLVIterator(const VpnPacketTLV& tlv) : _tlv(tlv) {}
|
||||||
|
|
||||||
|
VpnPacketTLVIterator& operator++();
|
||||||
|
VpnPacketTLVIterator operator++(int) {
|
||||||
|
VpnPacketTLVIterator tmp(*this);
|
||||||
|
operator++();
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const VpnPacketTLVIterator& other) {
|
||||||
|
return _tlv == other._tlv; }
|
||||||
|
bool operator!=(const VpnPacketTLVIterator& other) {
|
||||||
|
return !(operator==(other)); }
|
||||||
|
bool past_the_end() const {
|
||||||
|
return _tlv.get_offset() >= _tlv.get_packet().get_payload_size(); }
|
||||||
|
reference operator*() { return _tlv; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
VpnPacketTLV _tlv;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** A packet sent through the VPN tunnel.
|
||||||
|
*
|
||||||
|
* This must instantiated just before filling it with data. */
|
||||||
|
class TunnelledPacket: public VpnPacketTLV {
|
||||||
|
public:
|
||||||
|
TunnelledPacket(VpnPacket& packet, size_t payload_offset);
|
||||||
|
TunnelledPacket(const VpnPacketTLV& copy);
|
||||||
|
static TunnelledPacket create(VpnPacket& packet);
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in a new issue