]> git.sesse.net Git - greproxy/blob - tunprotocol.cpp
Merge branch 'master' of /srv/git.sesse.net/www/greproxy
[greproxy] / tunprotocol.cpp
1 #include <fcntl.h>
2 #include <netinet/in.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <sys/ioctl.h>
7 #include <unistd.h>
8 #include <linux/if.h>
9 #include <linux/if_tun.h>
10
11 #include "tunprotocol.h"
12
13 using namespace std;
14
15 namespace {
16
17 int tun_open(const char *name) {
18         struct ifreq ifr;
19
20         int fd = open("/dev/net/tun", O_RDWR);
21         if (fd == -1) {
22                 perror("/dev/net/tun");
23                 exit(1);
24         }
25
26         memset(&ifr, 0, sizeof(ifr));
27         ifr.ifr_flags = IFF_TUN;
28         strncpy(ifr.ifr_name, name, IFNAMSIZ);
29
30         int err = ioctl(fd, TUNSETIFF, &ifr);
31         if (err == -1) {
32                 perror("ioctl(TUNSETIFF)");
33                 exit(-1);
34         }
35
36         return fd;
37 }
38
39 }  // namespace
40
41 TUNProtocol::TUNProtocol(const char *devname)
42         : tunfd(tun_open(devname)), seq(0) {
43 }
44
45 void TUNProtocol::send_packet(uint16_t proto, const string &data, uint32_t incoming_seq)
46 {
47         char buf[4096];
48
49         char *ptr = buf;
50         uint16_t flags = 0;
51         memcpy(ptr, &flags, sizeof(flags));
52         ptr += sizeof(flags);
53
54         proto = htons(proto);
55         memcpy(ptr, &proto, sizeof(proto));
56         ptr += sizeof(proto);
57
58         memcpy(ptr, data.data(), data.size());
59
60         int len = sizeof(flags) + sizeof(proto) + data.size();
61         if (write(tunfd, buf, len) != len) {
62                 perror("write");
63                 return;
64         }
65
66         ++sent_packets;
67 }
68
69 int TUNProtocol::fd() const
70 {
71         return tunfd;
72 }
73
74 void TUNProtocol::read_packet(Sender *sender)
75 {
76         char buf[4096];
77         int ret = read(tunfd, buf, sizeof(buf));
78         if (ret == -1) {
79                 perror("read");
80                 exit(1);
81         }
82         if (ret == 0) {
83                 fprintf(stderr, "tunfd EOF\n");
84                 exit(1);
85         }
86         
87         char *ptr = buf;
88         uint16_t flags = *(uint16_t *)ptr;
89         ptr += 2;
90         uint16_t proto = ntohs(*(uint16_t *)ptr);
91         ptr += 2;
92         //fprintf(stderr, "tun packet: flags=%x proto=%x len=%d\n",
93         //      flags, proto, ret - 4);
94         ++received_packets;
95         sender->send_packet(proto, string(ptr, buf + ret), seq++);
96 }
97