congestvpn/UdpVpn.cpp

128 lines
3.3 KiB
C++
Raw Normal View History

2020-06-04 11:47:00 +02:00
#include "UdpVpn.hpp"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <poll.h>
#include <errno.h>
#include "ip_header.hpp"
2020-06-10 16:24:26 +02:00
static const size_t VPN_MTU = 1460; // TODO determine this -- issue #3
2020-06-05 17:31:02 +02:00
2020-06-04 11:47:00 +02:00
UdpVpn::UdpVpn()
2020-06-05 17:31:02 +02:00
: _stopped(false), _vpn_mtu(VPN_MTU), _tun_dev("cvpn%d")
2020-06-04 11:47:00 +02:00
{
_socket = socket(AF_INET6, SOCK_DGRAM, 0);
if(_socket < 0)
throw UdpVpn::InitializationError("Cannot create socket", errno, true);
}
UdpVpn::~UdpVpn() {
close(_socket);
}
void UdpVpn::run() {
int rc;
int start_at_fd = 0; // read from polled fds in round-robin fashion
int cur_fd;
int nfds = 2;
struct pollfd poll_fds[2];
// poll_fds[0]: tun device
poll_fds[0].fd = _tun_dev.get_fd();
poll_fds[0].events = POLLIN;
// poll_fds[1]: UDP socket device
poll_fds[1].fd = _socket;
poll_fds[1].events = POLLIN;
while(!_stopped) {
rc = poll(poll_fds, nfds, -1);
if(rc < 0) {
if(errno == EINTR) // Interrupt.
continue;
throw UdpVpn::NetError(
"Error polling from interface", errno, true);
}
else if(rc == 0) // Nothing to read
continue;
cur_fd = start_at_fd;
do {
if(poll_fds[cur_fd].revents & POLLIN) {
if(cur_fd == 0)
receive_from_tun();
else if(cur_fd == 1)
receive_from_udp();
break;
}
cur_fd = (cur_fd + 1) % nfds;
} while(cur_fd != start_at_fd);
start_at_fd = (start_at_fd + 1) % nfds;
}
}
size_t UdpVpn::read_from_tun(char* buffer, size_t len) {
2020-06-04 11:47:00 +02:00
// We know that there is data available -- use `read()`
2020-06-05 17:31:02 +02:00
return _tun_dev.read(buffer, len);
}
2020-06-04 11:47:00 +02:00
2020-06-05 17:31:02 +02:00
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;
2020-06-05 17:31:02 +02:00
}
return nread;
2020-06-04 11:47:00 +02:00
}
size_t UdpVpn::read_from_udp(char* buffer, size_t len,
sockaddr_in6& peer_addr)
{
2020-06-04 11:47:00 +02:00
ssize_t nread;
socklen_t peer_addr_len = sizeof(peer_addr);
2020-06-10 18:49:36 +02:00
nread = recvfrom(_socket, buffer, len, 0,
2020-06-04 11:47:00 +02:00
(struct sockaddr*) &peer_addr, &peer_addr_len);
if(nread < 0)
throw UdpVpn::NetError("Cannot receive datagram", errno, true);
if(nread == 0)
return 0;
2020-06-04 11:47:00 +02:00
if(peer_addr.sin6_family != AF_INET6) {
debugf("WARNING: Received non-ipv6 family datagram %d. Ignoring.\n",
peer_addr.sin6_family);
return 0;
2020-06-04 11:47:00 +02:00
}
if(peer_addr_len != sizeof(peer_addr)) {
debugf("WARNING: received unexpected source address length %u."
"Ignoring.\n",
peer_addr_len);
return 0;
}
return nread;
2020-06-04 11:47:00 +02:00
}
2020-06-05 17:31:02 +02:00
size_t UdpVpn::read_from_udp(VpnPacket& packet, sockaddr_in6& peer_addr) {
2020-06-10 18:49:36 +02:00
packet.upon_reception(); // The packet is not read yet, but it has arrived
2020-06-05 17:31:02 +02:00
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;
}