2020-06-05 17:30:35 +02:00
|
|
|
#include "VpnPacket.hpp"
|
2020-06-10 18:49:36 +02:00
|
|
|
#include "VpnPeer.hpp"
|
2020-06-05 17:30:35 +02:00
|
|
|
|
2020-07-22 15:52:55 +02:00
|
|
|
#include <string.h>
|
2020-07-22 19:38:14 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <utility>
|
2020-06-05 17:30:35 +02:00
|
|
|
|
2020-06-10 18:49:36 +02:00
|
|
|
const size_t VpnPacket::VPN_HEADER_BYTES = 8;
|
2020-06-26 19:41:55 +02:00
|
|
|
const size_t VpnControlPacket::TLV_HEADER_BYTES = 3;
|
2020-06-10 18:49:36 +02:00
|
|
|
|
|
|
|
static const size_t OUTER_HEADERS_BYTES =
|
2020-06-05 17:30:35 +02:00
|
|
|
40 /* IPv6 header */ + 8 /* UDP header */;
|
|
|
|
// We use a TUN device, hence we don't have a layer 2 header.
|
|
|
|
|
2020-06-10 18:49:36 +02:00
|
|
|
static const int
|
|
|
|
DATA_SEQNO_POS = 0,
|
2020-06-26 19:41:55 +02:00
|
|
|
DATA_CTRLBIT_POS = 4,
|
2020-06-10 18:49:36 +02:00
|
|
|
DATA_TIMESTAMP_POS = 4;
|
|
|
|
|
2020-06-26 19:41:55 +02:00
|
|
|
VpnPacket::VpnPacket(size_t mtu, bool inbound)
|
|
|
|
: _peer(nullptr), _inbound(inbound), _data_space(mtu-OUTER_HEADERS_BYTES),
|
2020-06-12 17:36:55 +02:00
|
|
|
_data_size(VPN_HEADER_BYTES), _reception_timestamp(0)
|
2020-06-05 17:30:35 +02:00
|
|
|
{
|
2020-07-22 17:04:22 +02:00
|
|
|
_data = (char*) malloc(sizeof(char) * (mtu - OUTER_HEADERS_BYTES));
|
2020-06-05 17:30:35 +02:00
|
|
|
}
|
|
|
|
|
2020-07-22 17:04:22 +02:00
|
|
|
VpnPacket::~VpnPacket() {
|
|
|
|
free(_data);
|
|
|
|
}
|
2020-06-05 17:30:35 +02:00
|
|
|
|
2020-06-26 19:41:55 +02:00
|
|
|
VpnPacket::VpnPacket(VpnPacket&& move_from) :
|
|
|
|
_peer(move_from._peer),
|
|
|
|
_inbound(move_from._inbound),
|
|
|
|
_data(std::move(move_from._data)),
|
|
|
|
_data_space(move_from._data_space),
|
|
|
|
_data_size(move_from._data_size),
|
|
|
|
_reception_timestamp(move_from._reception_timestamp)
|
|
|
|
{}
|
2020-06-10 18:49:36 +02:00
|
|
|
|
2020-06-16 18:57:08 +02:00
|
|
|
size_t VpnPacket::get_tunnelled_mtu(size_t udp_mtu) {
|
2020-06-26 19:41:55 +02:00
|
|
|
return udp_mtu - OUTER_HEADERS_BYTES - VPN_HEADER_BYTES;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VpnPacket::set_peer(VpnPeer* peer) {
|
|
|
|
_peer = peer;
|
|
|
|
if(_peer && _inbound)
|
|
|
|
_peer->got_inbound_packet(*this);
|
2020-06-16 18:57:08 +02:00
|
|
|
}
|
|
|
|
|
2020-06-10 18:49:36 +02:00
|
|
|
uint32_t VpnPacket::get_seqno() const {
|
2020-07-22 17:04:22 +02:00
|
|
|
return ntohl(*(uint32_t*)(_data + DATA_SEQNO_POS));
|
2020-06-10 18:49:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t VpnPacket::get_sending_timestamp() const {
|
2020-06-26 19:41:55 +02:00
|
|
|
return ntohl(
|
2020-07-22 17:04:22 +02:00
|
|
|
*(uint32_t*)(_data + DATA_TIMESTAMP_POS) & 0x7fffffffUL
|
2020-06-26 19:41:55 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool VpnPacket::is_control() const {
|
2020-07-22 17:04:22 +02:00
|
|
|
return *(unsigned char*)(_data + DATA_CTRLBIT_POS) & 0x80;
|
2020-06-26 19:41:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void VpnPacket::set_control(bool is_control) {
|
|
|
|
unsigned char* ctrl_field =
|
2020-07-22 17:04:22 +02:00
|
|
|
(unsigned char*) (_data + DATA_CTRLBIT_POS);
|
2020-06-26 19:41:55 +02:00
|
|
|
*ctrl_field &= 0x7f;
|
|
|
|
if(is_control)
|
|
|
|
*ctrl_field |= 0x80;
|
2020-06-10 18:49:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void VpnPacket::prepare_for_sending() {
|
2020-07-22 17:04:22 +02:00
|
|
|
uint32_t* ts_field = (uint32_t*) (_data + DATA_TIMESTAMP_POS);
|
2020-06-28 23:29:39 +02:00
|
|
|
*ts_field &= htonl(0x80000000UL);
|
2020-07-22 17:04:22 +02:00
|
|
|
*(uint32_t*)(_data + DATA_SEQNO_POS) = htonl(next_seqno());
|
2020-07-22 15:45:16 +02:00
|
|
|
*ts_field |= htonl(to_us_timestamp(current_us_timestamp()));
|
2020-06-10 18:49:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void VpnPacket::upon_reception() {
|
2020-07-22 15:45:16 +02:00
|
|
|
_reception_timestamp = to_us_timestamp(current_us_timestamp());
|
2020-06-10 18:49:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t VpnPacket::next_seqno() {
|
2020-07-22 19:09:27 +02:00
|
|
|
if(!_peer) {
|
|
|
|
fprintf(stderr, "ERROR: trying to get seqno without peer.\n");
|
|
|
|
return 0;
|
|
|
|
}
|
2020-06-15 20:21:07 +02:00
|
|
|
return _peer->next_seqno();
|
2020-06-10 18:49:36 +02:00
|
|
|
}
|
2020-06-12 17:36:55 +02:00
|
|
|
|
2020-06-26 19:41:55 +02:00
|
|
|
VpnControlPacket::VpnControlPacket(size_t mtu, bool inbound)
|
|
|
|
: VpnPacket(mtu, inbound)
|
|
|
|
{
|
|
|
|
set_control(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
VpnControlPacket::VpnControlPacket(VpnPacket&& move_from)
|
|
|
|
: VpnPacket(std::move(move_from))
|
|
|
|
{}
|
|
|
|
|
|
|
|
VpnPacketTLV VpnControlPacket::first_tlv() {
|
|
|
|
return VpnPacketTLV(*this, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
VpnDataPacket::VpnDataPacket(size_t mtu, bool inbound)
|
|
|
|
: VpnPacket(mtu, inbound), _ipv6_parsed(false)
|
|
|
|
{
|
|
|
|
set_control(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
VpnDataPacket::VpnDataPacket(VpnPacket&& move_from)
|
|
|
|
: VpnPacket(std::move(move_from)), _ipv6_parsed(false)
|
|
|
|
{}
|
|
|
|
|
2020-06-28 23:29:39 +02:00
|
|
|
bool VpnDataPacket::parse_as_ipv6(bool reparse) {
|
|
|
|
if(_ipv6_parsed && !reparse)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
_ipv6_parsed =
|
|
|
|
parse_ipv6_header(get_payload(), get_payload_size(), _ipv6_header);
|
|
|
|
return _ipv6_parsed;
|
2020-06-26 19:41:55 +02:00
|
|
|
}
|
2020-06-12 17:36:55 +02:00
|
|
|
|
2020-06-26 19:41:55 +02:00
|
|
|
VpnPacketTLV::VpnPacketTLV(VpnControlPacket& packet, size_t payload_offset)
|
2020-06-12 17:36:55 +02:00
|
|
|
: _packet(packet), _tlv_pos(payload_offset)
|
|
|
|
{}
|
|
|
|
|
2020-06-15 20:21:07 +02:00
|
|
|
VpnPacketTLV::VpnPacketTLV(const VpnPacketTLV& other) :
|
|
|
|
_packet(other._packet), _tlv_pos(other._tlv_pos)
|
|
|
|
{}
|
|
|
|
|
2020-06-12 17:36:55 +02:00
|
|
|
VpnPacketTLV VpnPacketTLV::create(
|
2020-06-26 19:41:55 +02:00
|
|
|
VpnControlPacket& packet, VpnPacketTLV::PayloadType type)
|
2020-06-12 17:36:55 +02:00
|
|
|
{
|
|
|
|
VpnPacketTLV tlv = VpnPacketTLV(packet, packet.get_payload_size());
|
2020-06-26 19:41:55 +02:00
|
|
|
packet.increase_payload_size(VpnControlPacket::TLV_HEADER_BYTES);
|
2020-06-12 17:36:55 +02:00
|
|
|
|
|
|
|
char* data = tlv.get_data();
|
|
|
|
data[0] = type;
|
|
|
|
*(uint16_t*)(data+1) = 0; // Set len to 0
|
|
|
|
|
|
|
|
return tlv;
|
|
|
|
}
|
|
|
|
|
2020-06-15 20:21:07 +02:00
|
|
|
VpnPacketTLV VpnPacketTLV::next_tlv() {
|
|
|
|
size_t next_offset = _tlv_pos + get_payload_size();
|
|
|
|
return VpnPacketTLV(_packet, next_offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
void VpnPacketTLV::seek_next_tlv() {
|
2020-06-26 19:41:55 +02:00
|
|
|
_tlv_pos =
|
|
|
|
_tlv_pos + VpnControlPacket::TLV_HEADER_BYTES + get_payload_size();
|
2020-06-15 20:21:07 +02:00
|
|
|
}
|
|
|
|
|
2020-06-12 17:36:55 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2020-06-16 20:24:59 +02:00
|
|
|
uint16_t VpnPacketTLV::get_payload_space() const {
|
|
|
|
return _packet.get_payload_space()
|
|
|
|
- _packet.get_payload_size()
|
|
|
|
+ get_payload_size();
|
|
|
|
}
|
|
|
|
|
2020-06-26 19:41:55 +02:00
|
|
|
VpnPacketTLV::PayloadType VpnPacketTLV::get_type() const {
|
|
|
|
return (PayloadType)(*(uint8_t*)(get_data()));
|
2020-06-12 17:36:55 +02:00
|
|
|
}
|
2020-06-26 19:41:55 +02:00
|
|
|
void VpnPacketTLV::set_type(VpnPacketTLV::PayloadType type) {
|
2020-06-12 17:36:55 +02:00
|
|
|
*(uint8_t*)(get_data()) = (uint8_t) type;
|
|
|
|
}
|
2020-06-28 23:29:39 +02:00
|
|
|
|
2020-07-03 16:13:47 +02:00
|
|
|
/* ========== VpnTlvLossReport ========== */
|
|
|
|
const uint32_t VpnTlvLossReport::REP_SEQNO_POS = 0,
|
|
|
|
VpnTlvLossReport::REP_LOSS_POS = 4;
|
|
|
|
|
|
|
|
VpnTlvLossReport::VpnTlvLossReport(
|
|
|
|
VpnControlPacket& packet, size_t payload_offset)
|
|
|
|
: VpnPacketTLV(packet, payload_offset) {}
|
|
|
|
VpnTlvLossReport::VpnTlvLossReport(const VpnPacketTLV& other)
|
|
|
|
: VpnPacketTLV(other) {}
|
|
|
|
|
|
|
|
VpnTlvLossReport VpnTlvLossReport::create(VpnControlPacket& packet) {
|
|
|
|
VpnTlvLossReport tlv =
|
|
|
|
VpnPacketTLV::create(packet, VpnPacketTLV::PAYLOAD_TYPE_LOSS_REPORT);
|
|
|
|
tlv.set_payload_size(8);
|
|
|
|
memset(tlv.get_payload(), 0, 8);
|
|
|
|
return tlv;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t VpnTlvLossReport::get_report_seqno() const {
|
|
|
|
return ntohl(*(uint32_t*)(get_payload() + REP_SEQNO_POS));
|
|
|
|
}
|
|
|
|
void VpnTlvLossReport::set_report_seqno(uint32_t seqno) {
|
|
|
|
*(uint32_t*)(get_payload() + REP_SEQNO_POS) = htonl(seqno);
|
|
|
|
}
|
|
|
|
uint32_t VpnTlvLossReport::get_losses() const {
|
|
|
|
return ntohl(*(uint32_t*)(get_payload() + REP_LOSS_POS));
|
|
|
|
}
|
|
|
|
void VpnTlvLossReport::set_losses(uint32_t losses) {
|
|
|
|
*(uint32_t*)(get_payload() + REP_LOSS_POS) = htonl(losses);
|
|
|
|
}
|
2020-06-28 23:29:39 +02:00
|
|
|
|
|
|
|
/* ========== VpnTlvRTTQ ========== */
|
|
|
|
VpnTlvRTTQ::VpnTlvRTTQ(VpnControlPacket& packet, size_t payload_offset)
|
|
|
|
: VpnPacketTLV(packet, payload_offset) {}
|
|
|
|
VpnTlvRTTQ::VpnTlvRTTQ(const VpnPacketTLV& other)
|
|
|
|
: VpnPacketTLV(other) {}
|
|
|
|
|
|
|
|
VpnTlvRTTQ VpnTlvRTTQ::create(VpnControlPacket& packet) {
|
|
|
|
return VpnPacketTLV::create(packet, VpnPacketTLV::PAYLOAD_TYPE_RTTQ);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ========== VpnTlvRTTA ========== */
|
|
|
|
const uint32_t VpnTlvRTTA::EXP_TS_POS = 0, VpnTlvRTTA::RECV_TS_POS = 4;
|
|
|
|
|
|
|
|
VpnTlvRTTA::VpnTlvRTTA(VpnControlPacket& packet, size_t payload_offset)
|
|
|
|
: VpnPacketTLV(packet, payload_offset) {}
|
|
|
|
VpnTlvRTTA::VpnTlvRTTA(const VpnPacketTLV& other)
|
|
|
|
: VpnPacketTLV(other) {}
|
|
|
|
|
|
|
|
VpnTlvRTTA VpnTlvRTTA::create(VpnControlPacket& packet) {
|
|
|
|
VpnTlvRTTA tlv =
|
|
|
|
VpnPacketTLV::create(packet, VpnPacketTLV::PAYLOAD_TYPE_RTTA);
|
|
|
|
tlv.set_payload_size(8);
|
|
|
|
memset(tlv.get_payload(), 0, 8);
|
|
|
|
return tlv;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t VpnTlvRTTA::get_exp_ts() const {
|
|
|
|
return ntohl(*(uint32_t*)(get_payload() + EXP_TS_POS));
|
|
|
|
}
|
|
|
|
void VpnTlvRTTA::set_exp_ts(uint32_t ts) {
|
|
|
|
*(uint32_t*)(get_payload() + EXP_TS_POS) = htonl(ts);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t VpnTlvRTTA::get_recv_ts() const {
|
|
|
|
return ntohl(*(uint32_t*)(get_payload() + RECV_TS_POS));
|
|
|
|
}
|
|
|
|
void VpnTlvRTTA::set_recv_ts(uint32_t ts) {
|
|
|
|
*(uint32_t*)(get_payload() + RECV_TS_POS) = htonl(ts);
|
|
|
|
}
|
|
|
|
|