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 <chrono>
|
||||
#include <cstring>
|
||||
|
||||
const size_t VpnPacket::VPN_HEADER_BYTES = 8;
|
||||
const size_t VpnPacket::TLV_HEADER_BYTES = 3;
|
||||
uint32_t VpnPacket::_next_general_seqno = 0;
|
||||
|
||||
static const size_t OUTER_HEADERS_BYTES =
|
||||
|
@ -15,8 +17,8 @@ static const int
|
|||
DATA_TIMESTAMP_POS = 4;
|
||||
|
||||
VpnPacket::VpnPacket(size_t mtu)
|
||||
: _peer(nullptr), _data_space(mtu-OUTER_HEADERS_BYTES), _data_size(0),
|
||||
_reception_timestamp(0)
|
||||
: _peer(nullptr), _data_space(mtu-OUTER_HEADERS_BYTES),
|
||||
_data_size(VPN_HEADER_BYTES), _reception_timestamp(0)
|
||||
{
|
||||
_data = new char[mtu - OUTER_HEADERS_BYTES];
|
||||
}
|
||||
|
@ -25,6 +27,13 @@ VpnPacket::~VpnPacket() {
|
|||
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() {
|
||||
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 _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:
|
||||
*
|
||||
* +-------+-------+-------+-------+-------+-------+-------+-------+
|
||||
* | 1B | 1B | 1B | 1B | 1B | 1B | 1B | 1B |
|
||||
* +-------+-------+-------+-------+-------+-------+-------+-------+
|
||||
* | Sequence number [4B] | Sending timestamp (μs) [4B] |
|
||||
* 0 1 2 3
|
||||
* 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] |
|
||||
* +---------------------------------------------------------------+
|
||||
* | 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 VpnPacketTLVIterator;
|
||||
|
||||
class VpnPacket {
|
||||
public:
|
||||
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();
|
||||
|
||||
iterator begin();
|
||||
iterator end();
|
||||
|
||||
/// Set packet peer -- used for sequence numbers
|
||||
void set_peer(std::shared_ptr<VpnPeer> peer) { _peer = peer; }
|
||||
|
||||
|
@ -35,23 +64,42 @@ class VpnPacket {
|
|||
bool ipv6_parsed() const { return _ipv6_parsed; }
|
||||
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; }
|
||||
/// Get a pointer to the packet payload
|
||||
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 {
|
||||
return _data_space - VPN_HEADER_BYTES; }
|
||||
/// Get the current size filled by the payload
|
||||
size_t get_payload_size() const {
|
||||
return _data_size - VPN_HEADER_BYTES; }
|
||||
/// Set current size filled by the packet payload
|
||||
void set_payload_size(size_t payload_size) {
|
||||
_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; }
|
||||
/// Get a pointer to the full packet data
|
||||
char* get_data() { return _data; }
|
||||
/// Get the space allocated for the packet
|
||||
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; }
|
||||
/// Set the total current size of the packet
|
||||
void set_data_size(size_t data_size) { _data_size = data_size; }
|
||||
|
||||
/// Get this packet's seqno
|
||||
uint32_t get_seqno() const;
|
||||
/// Get this packet's sending timestamp
|
||||
uint32_t get_sending_timestamp() const;
|
||||
/// Get this packet's reception timestamp
|
||||
uint32_t get_reception_timestamp() const { return _reception_timestamp; }
|
||||
|
||||
/** 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;
|
||||
};
|
||||
|
||||
/** 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