congestvpn/TunDevice.cpp

90 lines
2.3 KiB
C++
Raw Normal View History

2020-06-02 13:08:23 +02:00
#include <linux/if.h>
#include <linux/if_tun.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
2020-06-02 13:08:23 +02:00
#include <cstdlib>
#include <cstring>
#include "TunDevice.hpp"
static const size_t TUN_MTU = 1500; // TODO determine this cleanly
2020-06-02 13:08:23 +02:00
TunDevice::TunDevice(const std::string& dev)
{
struct ifreq ifr;
int fd;
2020-06-02 13:08:23 +02:00
if( (fd = open("/dev/net/tun", O_RDWR)) < 0 ) {
throw TunDevice::InitializationError(
"Cannot open /dev/net/tun", errno, true);
}
2020-06-02 13:08:23 +02:00
memset(&ifr, 0, sizeof(ifr));
/* Flags: IFF_TUN - TUN device (no Ethernet headers)
* IFF_TAP - TAP device
*
* IFF_NO_PI - Do not provide packet information
*/
ifr.ifr_flags = IFF_TUN;
if(!dev.empty()) {
if(dev.size() >= IFNAMSIZ - 2)
throw TunDevice::InitializationError("Device name is too long.");
strncpy(ifr.ifr_name, dev.c_str(), IFNAMSIZ-1);
}
if(ioctl(fd, TUNSETIFF, (void *) &ifr) < 0){
2020-06-02 13:08:23 +02:00
close(fd);
throw TunDevice::InitializationError(
"Tunnel interface failed [TUNSETIFF]", errno, true);
2020-06-02 13:08:23 +02:00
}
_dev_name = ifr.ifr_name;
_fd = fd;
// The device is now fully set up
_poll_fd.fd = _fd;
_poll_fd.events = POLLIN;
2020-06-02 13:08:23 +02:00
}
TunDevice::~TunDevice() {
close(_fd);
}
2020-06-04 11:46:09 +02:00
size_t TunDevice::poll_packet(char* read_buffer, size_t buf_size, int timeout) {
int poll_rc = poll(&_poll_fd, 1, timeout);
if(poll_rc < 0) {
if(errno == EINTR) // Interrupt.
return 0;
throw TunDevice::NetError(
"Error polling from interface", errno, true);
}
else if(poll_rc == 0 || (_poll_fd.revents & POLLIN) == 0) {
// Nothing to read
return 0;
}
2020-06-04 11:46:09 +02:00
return this->read(read_buffer, buf_size);
}
size_t TunDevice::read(char* read_buffer, size_t buf_size) {
int nread = ::read(_fd, read_buffer, buf_size);
if(nread < 0) {
throw TunDevice::NetError(
"Error reading from interface", errno, true);
}
_last_read_size = nread;
return _last_read_size;
}
2020-06-04 11:46:09 +02:00
size_t TunDevice::write(const char* data, size_t len) {
int nwritten = ::write(_fd, data, len);
if(nwritten < 0) {
throw TunDevice::NetError(
"Error writing to interface: ", errno, true);
}
return nwritten;
}