From 1f96a34a376da7e9da39967b8c6d2a3aa428a4f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophile=20Bastian?= Date: Tue, 2 Jun 2020 13:08:23 +0200 Subject: [PATCH] Setup tun device --- .gitignore | 2 ++ Makefile | 19 +++++++++++++++++++ TunDevice.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++++++ TunDevice.hpp | 22 ++++++++++++++++++++++ main.cpp | 17 +++++++++++++++++ util.cpp | 15 +++++++++++++++ util.hpp | 17 +++++++++++++++++ 7 files changed, 138 insertions(+) create mode 100644 Makefile create mode 100644 TunDevice.cpp create mode 100644 TunDevice.hpp create mode 100644 main.cpp create mode 100644 util.cpp create mode 100644 util.hpp diff --git a/.gitignore b/.gitignore index 84f59bd..012f190 100644 --- a/.gitignore +++ b/.gitignore @@ -88,3 +88,5 @@ docs/_build/ # PyBuilder target/ +# ---> Local ignores +congestvpn diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ba03f38 --- /dev/null +++ b/Makefile @@ -0,0 +1,19 @@ +CXX=g++ +CXXFLAGS=-O2 -g -Wall -Wextra -std=c++17 +CXXLIBS= + +OBJS=TunDevice.o util.o main.o +TARGET=congestvpn + +all: $(TARGET) + +$(TARGET): $(OBJS) + $(CXX) $(CXXFLAGS) $(CXXLIBS) -o $@ $^ + +%.o: %.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< + +clean: + rm -f $(OBJS) $(TARGET) + +.PHONY: all clean diff --git a/TunDevice.cpp b/TunDevice.cpp new file mode 100644 index 0000000..4b69a46 --- /dev/null +++ b/TunDevice.cpp @@ -0,0 +1,46 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "TunDevice.hpp" + +TunDevice::TunDevice(const std::string& dev) +{ + struct ifreq ifr; + int fd, err; + + if( (fd = open("/dev/net/tun", O_RDWR)) < 0 ) + throw TunDevice::InitializationError("Cannot open /dev/net/tun", fd); + + 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( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ){ + close(fd); + throw TunDevice::InitializationError( + "Tunnel interface failed [TUNSETIFF]", err + ); + } + _dev_name = ifr.ifr_name; + _fd = fd; +} + +TunDevice::~TunDevice() { + close(_fd); +} diff --git a/TunDevice.hpp b/TunDevice.hpp new file mode 100644 index 0000000..9b1fd89 --- /dev/null +++ b/TunDevice.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include +#include "util.hpp" + +class TunDevice { + public: + class InitializationError : public MsgException { + public: + InitializationError(const std::string& msg, int code=0) + : MsgException(msg, code) {} + }; + + TunDevice(const std::string& dev); + ~TunDevice(); + + const std::string& get_dev_name() const { return _dev_name; } + int get_fd() const { return _fd; } + private: + int _fd; + std::string _dev_name; +}; diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..469b0cb --- /dev/null +++ b/main.cpp @@ -0,0 +1,17 @@ +#include +#include + +#include "TunDevice.hpp" + +int main(void) { + try { + TunDevice tun_dev("cvpn%d"); + printf("Tunnel device opened: <%s>, fd <%d>.\nSleeping 10 seconds.\n", + tun_dev.get_dev_name().c_str(), tun_dev.get_fd()); + sleep(10); + printf("Shutting down.\n"); + } catch(const TunDevice::InitializationError& exn) { + fprintf(stderr, "ERROR: %s\n", exn.what()); + } + return 0; +} diff --git a/util.cpp b/util.cpp new file mode 100644 index 0000000..41b4258 --- /dev/null +++ b/util.cpp @@ -0,0 +1,15 @@ +#include + +#include "util.hpp" + +MsgException::MsgException(const std::string& msg, int code) + : _msg(msg), _code(code) +{ + _what = _msg; + + if(_code != 0) { + char remainder[20]; + sprintf(remainder, " (code %d)", _code); + _what += remainder; + } +} diff --git a/util.hpp b/util.hpp new file mode 100644 index 0000000..2c97ab3 --- /dev/null +++ b/util.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +// MsgException -- an exception bearing a passed explanation message +class MsgException : public std::exception { + public: + MsgException(const std::string& msg, int code=0); + int errcode() const noexcept { return _code; } + const char* what() const noexcept { return _what.c_str(); }; + + private: + std::string _msg; + int _code; + std::string _what; +};