congestvpn/VpnPacket.hpp

211 lines
8.2 KiB
C++
Raw Permalink Normal View History

2020-06-05 17:30:35 +02:00
#pragma once
/** A packet to be transmitted or received over the VPN socket */
#include <cstdlib>
2020-06-10 18:49:36 +02:00
#include <memory>
2020-06-05 17:30:35 +02:00
#include "ip_header.hpp"
2020-06-10 18:49:36 +02:00
/** VPN packet layout:
*
2020-06-12 17:36:55 +02:00
* 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] |
2020-06-10 18:49:36 +02:00
* +---------------------------------------------------------------+
2020-06-12 17:36:55 +02:00
* | Sending timestamp (μs) [4B] |
* +---------------+-----------------------------------------------+
* | Type [1B] | First payload size (B) [2B] | Payload |
* +---------------+-----------------------------------------------+
* | Payload (cont.) |
* +---------------+-----------------------------------------------+
* | Type [1B] | Second payload size (B) [2B] | Payload |
* +---------------+-----------------------------------------------+
* | Payload (cont.) |
2020-06-10 18:49:36 +02:00
* +---------------------------------------------------------------+
2020-06-12 17:36:55 +02:00
* | ... |
* +---------------------------------------------------------------+
*
* Where
* - Type is one of the values from PayloadType below;
* - Sender ID is an arbitrary value, recommended to be randomly chosen
2020-06-12 17:36:55 +02:00
* - Payload size is the size of the payload (excluding headers), in bytes;
* - Payload is an arbitrary value, defined by Type
2020-06-10 18:49:36 +02:00
*/
class VpnPeer;
class VpnPacketTLV;
2020-06-10 18:49:36 +02:00
2020-06-05 17:30:35 +02:00
class VpnPacket {
public:
2020-06-10 18:49:36 +02:00
static const size_t VPN_HEADER_BYTES;
2020-06-12 17:36:55 +02:00
static const size_t TLV_HEADER_BYTES;
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
};
2020-06-05 17:30:35 +02:00
class PeerNotSet: public std::exception {};
2020-06-05 17:30:35 +02:00
VpnPacket(size_t mtu);
~VpnPacket();
VpnPacketTLV first_tlv();
2020-06-12 17:36:55 +02:00
/// Get the maximal payload space for a given tunnel MTU
static size_t get_tunnelled_mtu(size_t udp_mtu);
2020-06-10 18:49:36 +02:00
/// Set packet peer -- used for sequence numbers
void set_peer(VpnPeer* peer) { _peer = peer; }
2020-06-05 17:30:35 +02:00
2020-06-12 17:36:55 +02:00
/// Get a pointer to the packet payload (const version)
2020-06-10 18:49:36 +02:00
const char* get_payload() const { return _data + VPN_HEADER_BYTES; }
2020-06-12 17:36:55 +02:00
/// Get a pointer to the packet payload
2020-06-10 18:49:36 +02:00
char* get_payload() { return _data + VPN_HEADER_BYTES; }
2020-06-12 17:36:55 +02:00
/// 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
2020-06-05 17:30:35 +02:00
size_t get_payload_space() const {
2020-06-10 18:49:36 +02:00
return _data_space - VPN_HEADER_BYTES; }
2020-06-12 17:36:55 +02:00
/// Get the current size filled by the payload
2020-06-05 17:30:35 +02:00
size_t get_payload_size() const {
2020-06-10 18:49:36 +02:00
return _data_size - VPN_HEADER_BYTES; }
2020-06-12 17:36:55 +02:00
/// Set current size filled by the packet payload
2020-06-05 17:30:35 +02:00
void set_payload_size(size_t payload_size) {
2020-06-10 18:49:36 +02:00
_data_size = payload_size + VPN_HEADER_BYTES; }
2020-06-12 17:36:55 +02:00
/// 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; }
2020-06-05 17:30:35 +02:00
2020-06-12 17:36:55 +02:00
/// Get a pointer to the full packet data (const version)
2020-06-05 17:30:35 +02:00
const char* get_data() const { return _data; }
2020-06-12 17:36:55 +02:00
/// Get a pointer to the full packet data
2020-06-05 17:30:35 +02:00
char* get_data() { return _data; }
2020-06-12 17:36:55 +02:00
/// Get the space allocated for the packet
2020-06-05 17:30:35 +02:00
size_t get_data_space() const { return _data_space; }
2020-06-12 17:36:55 +02:00
/// Get the total current size of the packet
2020-06-05 17:30:35 +02:00
size_t get_data_size() const { return _data_size; }
2020-06-12 17:36:55 +02:00
/// Set the total current size of the packet
2020-06-05 17:30:35 +02:00
void set_data_size(size_t data_size) { _data_size = data_size; }
2020-06-12 17:36:55 +02:00
/// Get this packet's seqno
2020-06-10 18:49:36 +02:00
uint32_t get_seqno() const;
2020-06-12 17:36:55 +02:00
/// Get this packet's sending timestamp
2020-06-10 18:49:36 +02:00
uint32_t get_sending_timestamp() const;
2020-06-12 17:36:55 +02:00
/// Get this packet's reception timestamp
2020-06-10 18:49:36 +02:00
uint32_t get_reception_timestamp() const { return _reception_timestamp; }
/** Fill the headers of the packet. This method must be called as close
* to the time the packet is actually sent as possible, as it handles
* timestamps. */
void prepare_for_sending();
/** Do what must be done at reception, eg. keep the reception
* timestamp. This method must be called as close to the time the
* packet is actually received as possible, as it handles timestamps.
*/
void upon_reception();
private: // methods
inline uint32_t next_seqno();
2020-06-05 17:30:35 +02:00
private:
VpnPeer* _peer; // raw pointer: we do not own the peer in any way
2020-06-10 18:49:36 +02:00
2020-06-05 17:30:35 +02:00
char* _data;
size_t _data_space, _data_size;
2020-06-10 18:49:36 +02:00
uint32_t _reception_timestamp;
2020-06-05 17:30:35 +02:00
};
2020-06-12 17:36:55 +02:00
/** Base class for a TLV contained in a VpnPacket */
class VpnPacketTLV {
public:
VpnPacketTLV(VpnPacket& packet, size_t payload_offset);
VpnPacketTLV(const VpnPacketTLV& other);
2020-06-12 17:36:55 +02:00
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 next TLV in this packet.
VpnPacketTLV next_tlv();
/// Point this object to the next TLV (ie. `next_tlv` in place)
void seek_next_tlv();
/// Check whether the current TLV is past the packet's end
bool past_the_end() const {
return _tlv_pos >= _packet.get_payload_size(); }
2020-06-12 17:36:55 +02:00
/// 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 the total available raw data space
uint16_t get_payload_space() const;
2020-06-12 17:36:55 +02:00
/// 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;
};
/** 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);
/// Try to parse the packet as IPv6, return `false` upon failure.
bool parse_as_ipv6();
bool ipv6_parsed() const { return _ipv6_parsed; }
const IPv6Header& get_ipv6_header() const { return _ipv6_header; }
private:
bool _ipv6_parsed;
IPv6Header _ipv6_header;
2020-06-12 17:36:55 +02:00
};