Compare commits

...

3 commits

10 changed files with 136 additions and 63 deletions

View file

@ -5,6 +5,7 @@ CXXLIBS=
OBJS= \
UdpVpn.o UdpVpnClient.o UdpVpnServer.o \
VpnPeer.o \
VpnPacket.o \
TunDevice.o \
ip_header.o util.o main.o
TARGET=congestvpn

View file

@ -11,8 +11,10 @@
#include "ip_header.hpp"
static const size_t VPN_MTU = 1460; // TODO determine this -- issue #3
UdpVpn::UdpVpn()
: _stopped(false), _tun_dev("cvpn%d")
: _stopped(false), _vpn_mtu(VPN_MTU), _tun_dev("cvpn%d")
{
_socket = socket(AF_INET6, SOCK_DGRAM, 0);
if(_socket < 0)
@ -69,11 +71,17 @@ void UdpVpn::run() {
size_t UdpVpn::read_from_tun(char* buffer, size_t len) {
// We know that there is data available -- use `read()`
size_t nread = _tun_dev.read(buffer, len);
return _tun_dev.read(buffer, len);
}
if(nread == 0)
size_t UdpVpn::read_from_tun(VpnPacket& packet) {
size_t nread =
read_from_tun(packet.get_payload(), packet.get_payload_space());
packet.set_payload_size(nread);
if(!packet.parse_as_ipv6()) {
debugf("Ignoring packet with invalid header\n");
return 0;
}
return nread;
}
@ -104,3 +112,15 @@ size_t UdpVpn::read_from_udp(char* buffer, size_t len,
return nread;
}
size_t UdpVpn::read_from_udp(VpnPacket& packet, sockaddr_in6& peer_addr) {
size_t nread =
read_from_udp(packet.get_data(), packet.get_data_space(), peer_addr);
packet.set_data_size(nread);
if(!packet.parse_as_ipv6()) {
debugf("Ignoring packet with invalid header\n");
return 0;
}
return nread;
}

View file

@ -6,6 +6,7 @@
#include "util.hpp"
#include "TunDevice.hpp"
#include "VpnPeer.hpp"
#include "VpnPacket.hpp"
/** Handles UDP communication */
@ -45,10 +46,14 @@ class UdpVpn {
virtual void receive_from_udp() = 0;
size_t read_from_tun(char* buffer, size_t len);
size_t read_from_tun(VpnPacket& packet);
size_t read_from_udp(char* buffer, size_t len, sockaddr_in6& peer_addr);
size_t read_from_udp(VpnPacket& packet, sockaddr_in6& peer_addr);
int _socket;
bool _stopped;
size_t _vpn_mtu;
TunDevice _tun_dev;
};

View file

@ -16,49 +16,38 @@ void UdpVpnClient::set_server(const struct sockaddr_in6& server_addr) {
}
void UdpVpnClient::receive_from_tun() {
char buffer[1500];
size_t nread = read_from_tun(buffer, 1500);
VpnPacket packet(_vpn_mtu);
size_t nread = read_from_tun(packet);
if(nread == 0)
return;
// Parse inner packet header -- assume IPv6 for now [FIXME]
IPv6Header inner_header;
if(!parse_ipv6_header(buffer, nread, inner_header)) {
// Not a valid header -- ignore the packet
debugf("Ignoring outgoing packet with invalid header\n");
return;
}
kdebugf("Transmitting %s -> %s, size %d\n",
format_address(inner_header.source.s6_addr),
format_address(inner_header.dest.s6_addr),
format_address(packet.get_ipv6_header().source.s6_addr),
format_address(packet.get_ipv6_header().dest.s6_addr),
nread);
write_to_server(buffer, nread);
write_to_server(packet);
}
void UdpVpnClient::receive_from_udp() {
char buffer[1500];
VpnPacket packet(_vpn_mtu);
sockaddr_in6 peer_addr;
size_t nread = read_from_udp(buffer, 1500, peer_addr);
// Parse inner packet header -- assume IPv6 for now [FIXME]
IPv6Header inner_header;
if(!parse_ipv6_header(buffer, nread, inner_header)) {
// Not a valid header -- ignore the packet
debugf("Ignoring packet with invalid header\n");
size_t nread = read_from_udp(packet, peer_addr);
if(nread == 0)
return;
}
// Reinject into tun
kdebugf("Receiving packet of size %d from peer\n", nread);
_tun_dev.write(buffer, nread);
kdebugf("Receiving packet of size %d from %s\n",
nread,
format_address(packet.get_ipv6_header().source.s6_addr));
_tun_dev.write(packet.get_payload(), packet.get_payload_size());
}
size_t UdpVpnClient::write_to_server(const char* data, size_t len) {
size_t UdpVpnClient::write_to_server(const VpnPacket& packet) {
ssize_t nsent;
nsent = sendto(_socket, data, len, MSG_CONFIRM,
nsent = sendto(_socket, packet.get_data(), packet.get_data_size(),
MSG_CONFIRM,
(const struct sockaddr*) &_server_addr, sizeof(_server_addr));
if(nsent < 0)
throw NetError("Could not send UDP packet", errno, true);

View file

@ -12,7 +12,7 @@ class UdpVpnClient: public UdpVpn {
virtual void receive_from_tun();
virtual void receive_from_udp();
size_t write_to_server(const char* data, size_t len);
size_t write_to_server(const VpnPacket& packet);
struct sockaddr_in6 _server_addr;
};

View file

@ -42,63 +42,52 @@ std::shared_ptr<VpnPeer> UdpVpnServer::get_peer_for_ip(
}
void UdpVpnServer::receive_from_tun() {
char buffer[1500];
size_t nread = read_from_tun(buffer, 1500);
VpnPacket packet(_vpn_mtu);
size_t nread = read_from_tun(packet);
if(nread == 0)
return;
// Parse inner packet header -- assume IPv6 for now [FIXME]
IPv6Header inner_header;
if(!parse_ipv6_header(buffer, nread, inner_header)) {
// Not a valid header -- ignore the packet
debugf("Ignoring outgoing packet with invalid header\n");
return;
}
// Recover VpnPeer -- or drop if new
std::shared_ptr<VpnPeer> peer = get_peer_for_ip(inner_header.dest);
const in6_addr& peer_inner_addr = packet.get_ipv6_header().dest;
std::shared_ptr<VpnPeer> peer = get_peer_for_ip(peer_inner_addr);
if(!peer) {
debugf("Dropping packet for destination %s -- unknown peer.\n",
format_address(inner_header.dest.s6_addr));
format_address(peer_inner_addr.s6_addr));
return;
}
kdebugf("Transmitting %s -> %s, size %d\n",
format_address(inner_header.source.s6_addr),
format_address(inner_header.dest.s6_addr),
format_address(packet.get_ipv6_header().source.s6_addr),
format_address(packet.get_ipv6_header().dest.s6_addr),
nread);
peer->write(buffer, nread);
peer->write(packet);
}
void UdpVpnServer::receive_from_udp() {
char buffer[1500];
VpnPacket packet(_vpn_mtu);
sockaddr_in6 peer_addr;
size_t nread = read_from_udp(buffer, 1500, peer_addr);
// Parse inner packet header -- assume IPv6 for now [FIXME]
IPv6Header inner_header;
if(!parse_ipv6_header(buffer, nread, inner_header)) {
// Not a valid header -- ignore the packet
debugf("Ignoring packet with invalid header\n");
size_t nread = read_from_udp(packet, peer_addr);
if(nread == 0)
return;
}
// Recover VpnPeer -- or create if new
std::shared_ptr<VpnPeer> peer = get_peer_for_ip(inner_header.source);
const in6_addr& peer_inner_addr = packet.get_ipv6_header().source;
std::shared_ptr<VpnPeer> peer = get_peer_for_ip(peer_inner_addr);
if(!peer) {
peer = std::make_shared<VpnPeer>(this, peer_addr, inner_header.source);
auto insert_result = _peers.insert({inner_header.source, peer});
peer = std::make_shared<VpnPeer>(this, peer_addr, peer_inner_addr);
_peers.insert({peer_inner_addr, peer});
debugf("Got new peer %s:%d -- %s [really inserted=%d]\n",
debugf("Got new peer %s:%d -- %s\n",
format_address(peer_addr.sin6_addr.s6_addr),
htons(peer_addr.sin6_port),
format_address(inner_header.source.s6_addr),
insert_result.second);
format_address(peer_inner_addr.s6_addr));
}
// VpnPeer* peer = (peer_iter->second);
// TODO -- pass the packet to `peer` for a cleaner flow
// Reinject into tun
kdebugf("Receiving packet of size %d from peer\n", nread);
_tun_dev.write(buffer, nread);
kdebugf("Receiving packet of size %d from %s\n",
nread,
format_address(packet.get_ipv6_header().source.s6_addr));
_tun_dev.write(packet.get_payload(), packet.get_payload_size());
}

21
VpnPacket.cpp Normal file
View file

@ -0,0 +1,21 @@
#include "VpnPacket.hpp"
const size_t VpnPacket::VPN_HEADER_SIZE = 0;
static const size_t OUTER_HEADERS_SIZE =
40 /* IPv6 header */ + 8 /* UDP header */;
// We use a TUN device, hence we don't have a layer 2 header.
VpnPacket::VpnPacket(size_t mtu)
: _data_space(mtu-OUTER_HEADERS_SIZE), _data_size(0)
{
_data = new char[mtu - OUTER_HEADERS_SIZE];
}
VpnPacket::~VpnPacket() {
delete[] _data;
}
bool VpnPacket::parse_as_ipv6() {
return parse_ipv6_header(get_payload(), get_payload_size(), _ipv6_header);
}

42
VpnPacket.hpp Normal file
View file

@ -0,0 +1,42 @@
#pragma once
/** A packet to be transmitted or received over the VPN socket */
#include <cstdlib>
#include "ip_header.hpp"
class VpnPacket {
public:
static const size_t VPN_HEADER_SIZE;
VpnPacket(size_t mtu);
~VpnPacket();
/// 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; }
const char* get_payload() const { return _data + VPN_HEADER_SIZE; }
char* get_payload() { return _data + VPN_HEADER_SIZE; }
size_t get_payload_space() const {
return _data_space - VPN_HEADER_SIZE; }
size_t get_payload_size() const {
return _data_size - VPN_HEADER_SIZE; }
void set_payload_size(size_t payload_size) {
_data_size = payload_size + VPN_HEADER_SIZE; }
const char* get_data() const { return _data; }
char* get_data() { return _data; }
size_t get_data_space() const { return _data_space; }
size_t get_data_size() const { return _data_size; }
void set_data_size(size_t data_size) { _data_size = data_size; }
private:
char* _data;
size_t _data_space, _data_size;
bool _ipv6_parsed;
IPv6Header _ipv6_header;
};

View file

@ -21,3 +21,7 @@ size_t VpnPeer::write(const char* data, size_t len) {
return (size_t) nsent;
}
size_t VpnPeer::write(const VpnPacket& packet) {
return write(packet.get_data(), packet.get_data_size());
}

View file

@ -4,6 +4,7 @@
#include <netinet/in.h>
#include "util.hpp"
#include "VpnPacket.hpp"
class UdpVpn;
@ -25,6 +26,7 @@ class VpnPeer {
const in6_addr& get_int_addr() const { return _int_addr; }
size_t write(const char* data, size_t len);
size_t write(const VpnPacket& packet);
private:
UdpVpn* _vpn;