--- /dev/null
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
+
+#include "tunprotocol.h"
+
+using namespace std;
+
+namespace {
+
+int tun_open(const char *name) {
+ struct ifreq ifr;
+
+ int fd = open("/dev/net/tun", O_RDWR);
+ if (fd == -1) {
+ perror("/dev/net/tun");
+ exit(1);
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_flags = IFF_TUN;
+ strncpy(ifr.ifr_name, name, IFNAMSIZ);
+
+ int err = ioctl(fd, TUNSETIFF, &ifr);
+ if (err == -1) {
+ perror("ioctl(TUNSETIFF)");
+ exit(-1);
+ }
+
+ return fd;
+}
+
+} // namespace
+
+TUNProtocol::TUNProtocol(const char *devname)
+ : tunfd(tun_open(devname)) {
+}
+
+void TUNProtocol::send_packet(uint16_t proto, const string &data)
+{
+ char buf[4096];
+
+ char *ptr = buf;
+ uint16_t flags = 0;
+ memcpy(ptr, &flags, sizeof(flags));
+ ptr += sizeof(flags);
+
+ proto = htons(proto);
+ memcpy(ptr, &proto, sizeof(proto));
+ ptr += sizeof(proto);
+
+ memcpy(ptr, data.data(), data.size());
+
+ int len = sizeof(flags) + sizeof(proto) + data.size();
+ if (write(tunfd, buf, len) != len) {
+ perror("write");
+ return;
+ }
+}
+
+int TUNProtocol::fd() const
+{
+ return tunfd;
+}
+
+void TUNProtocol::read_packet(Protocol *sender)
+{
+ char buf[4096];
+ int ret = read(tunfd, buf, sizeof(buf));
+ if (ret == -1) {
+ perror("read");
+ exit(1);
+ }
+ if (ret == 0) {
+ fprintf(stderr, "tunfd EOF\n");
+ exit(1);
+ }
+
+ char *ptr = buf;
+ uint16_t flags = *(uint16_t *)ptr;
+ ptr += 2;
+ uint16_t proto = ntohs(*(uint16_t *)ptr);
+ ptr += 2;
+ //fprintf(stderr, "tun packet: flags=%x proto=%x len=%d\n",
+ // flags, proto, ret - 4);
+ sender->send_packet(proto, string(ptr, buf + ret));
+}
+