Théophile Bastian
0b8cf0edc1
Those packets are probably packets truncated because the buffer is not large enough.
210 lines
8.2 KiB
C++
210 lines
8.2 KiB
C++
#pragma once
|
|
|
|
/** A packet to be transmitted or received over the VPN socket */
|
|
|
|
#include <cstdlib>
|
|
#include <memory>
|
|
|
|
#include "ip_header.hpp"
|
|
|
|
/** VPN packet layout:
|
|
*
|
|
* 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] |
|
|
* +---------------------------------------------------------------+
|
|
* | 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;
|
|
* - Sender ID is an arbitrary value, recommended to be randomly chosen
|
|
* - Payload size is the size of the payload (excluding headers), in bytes;
|
|
* - Payload is an arbitrary value, defined by Type
|
|
*/
|
|
|
|
class VpnPeer;
|
|
class VpnPacketTLV;
|
|
|
|
class VpnPacket {
|
|
public:
|
|
static const size_t VPN_HEADER_BYTES;
|
|
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
|
|
};
|
|
|
|
class PeerNotSet: public std::exception {};
|
|
|
|
VpnPacket(size_t mtu);
|
|
~VpnPacket();
|
|
|
|
VpnPacketTLV first_tlv();
|
|
|
|
/// Get the maximal payload space for a given tunnel MTU
|
|
static size_t get_tunnelled_mtu(size_t udp_mtu);
|
|
|
|
/// Set packet peer -- used for sequence numbers
|
|
void set_peer(VpnPeer* peer) { _peer = peer; }
|
|
|
|
/// 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
|
|
* 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();
|
|
|
|
private:
|
|
VpnPeer* _peer; // raw pointer: we do not own the peer in any way
|
|
|
|
char* _data;
|
|
size_t _data_space, _data_size;
|
|
|
|
uint32_t _reception_timestamp;
|
|
};
|
|
|
|
/** Base class for a TLV contained in a VpnPacket */
|
|
class VpnPacketTLV {
|
|
public:
|
|
VpnPacketTLV(VpnPacket& packet, size_t payload_offset);
|
|
VpnPacketTLV(const VpnPacketTLV& other);
|
|
|
|
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(); }
|
|
|
|
/// 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;
|
|
|
|
/// 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;
|
|
};
|