#include #include #include #include #include #include #include #include #include #include "TunDevice.hpp" static const size_t TUN_MTU = 1500; // TODO determine this cleanly TunDevice::TunDevice(const std::string& dev) { struct ifreq ifr; int fd; if( (fd = open("/dev/net/tun", O_RDWR)) < 0 ) { throw TunDevice::InitializationError( "Cannot open /dev/net/tun", errno, true); } 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){ close(fd); throw TunDevice::InitializationError( "Tunnel interface failed [TUNSETIFF]", errno, true); } _dev_name = ifr.ifr_name; _fd = fd; // Bring interface up kdebugf("Bringing interface up...\n"); int sockfd = socket(AF_INET, SOCK_DGRAM, 0); // Any socket will do if(ioctl(sockfd, SIOCGIFFLAGS, (void*) &ifr) < 0) { close(fd); close(sockfd); throw TunDevice::InitializationError( "Could not get tunnel interface flags", errno, true); } ifr.ifr_flags |= IFF_UP | IFF_RUNNING; if(ioctl(sockfd, SIOCSIFFLAGS, (void*) &ifr) < 0) { close(fd); close(sockfd); throw TunDevice::InitializationError( "Could not bring tunnel interface up", errno, true); } close(sockfd); // The device is now fully set up _poll_fd.fd = _fd; _poll_fd.events = POLLIN; } TunDevice::~TunDevice() { close(_fd); } 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; } 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; } 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; }