]> git.sesse.net Git - greproxy/blob - tungre.cpp
82bfa347d636ce09ce98cc720d52cc406da1fcc4
[greproxy] / tungre.cpp
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <fcntl.h>
5 #include <unistd.h>
6 #include <sys/ioctl.h>
7 #include <netinet/in.h>
8 #include <arpa/inet.h>
9 #include <linux/if.h>
10 #include <linux/if_tun.h>
11
12 #include <map>
13 #include <string>
14 #include <queue>
15
16 using namespace std;
17
18 struct gre_header {
19         uint8_t reserved0_hi : 4;
20         uint8_t has_seq : 1;
21         uint8_t has_key : 1;
22         uint8_t unused : 1;
23         uint8_t has_checksum : 1;
24
25         uint8_t version : 3;
26         uint8_t reserved0_lo: 5;
27
28         uint16_t protocol_type;
29 };
30
31 int tun_open(const char *name) {
32         struct ifreq ifr;
33
34         int fd = open("/dev/net/tun", O_RDWR);
35         if (fd == -1) {
36                 perror("/dev/net/tun");
37                 exit(1);
38         }
39
40         memset(&ifr, 0, sizeof(ifr));
41         ifr.ifr_flags = IFF_TUN;
42         strncpy(ifr.ifr_name, name, IFNAMSIZ);
43
44         int err = ioctl(fd, TUNSETIFF, &ifr);
45         if (err == -1) {
46                 perror("ioctl(TUNSETIFF)");
47                 exit(-1);
48         }
49
50         return fd;
51 }
52
53 in6_addr get_addr(const char *str) {
54         in6_addr ret;
55         if (inet_pton(AF_INET6, str, &ret) != 1) {
56                 fprintf(stderr, "Could not parse %s\n", str);
57                 exit(1);
58         }
59         return ret;
60 }
61
62 struct GREPacket {
63         int seq;
64         uint16_t proto;
65         string data;
66
67         bool operator> (const GREPacket &other) const {
68                 return seq > other.seq;
69         }
70 };
71
72 class Sender {
73 public:
74         virtual void send_packet(uint16_t proto, const string &data) = 0;
75 };
76
77 class GRESender : public Sender {
78 public:
79         GRESender(int sock, const in6_addr &dst);
80         virtual void send_packet(uint16_t proto, const string &data);
81
82 private:
83         int seq;
84         int sock;
85         sockaddr_in6 dstaddr;
86 };
87
88 class TUNSender : public Sender {
89 public:
90         TUNSender(int tunfd);
91         virtual void send_packet(uint16_t proto, const string &data);
92
93 private:
94         int tunfd;
95 };
96
97 class Reorderer {
98 public:
99         Reorderer(Sender* sender);
100         void handle_packet(uint16_t proto, const string& data, int seq);
101
102 private:
103         void send_packet(uint16_t proto, const string &data, bool silence);
104
105         Sender* sender;
106         int last_seq;
107
108         priority_queue<GREPacket, vector<GREPacket>, greater<GREPacket>> packet_buffer;
109         map<int, int> ccs;
110 };
111
112 GRESender::GRESender(int sock, const in6_addr &dst)
113         : sock(sock), seq(0)
114 {
115         memset(&dstaddr, 0, sizeof(dstaddr));
116         dstaddr.sin6_family = AF_INET6;
117         dstaddr.sin6_addr = dst;
118 }
119
120 void GRESender::send_packet(uint16_t proto, const string &data)
121 {
122         char buf[4096];
123         gre_header *gre = (gre_header *)buf;
124
125         memset(gre, 0, sizeof(*gre));
126         gre->has_seq = 1;
127         gre->version = 0;
128         gre->protocol_type = htons(proto);
129
130         char *ptr = buf + sizeof(*gre);
131         int seq_be = htonl(seq++);
132         memcpy(ptr, &seq_be, sizeof(seq_be));
133         ptr += sizeof(seq_be);
134
135         memcpy(ptr, data.data(), data.size());
136         
137         if (sendto(sock, buf, data.size() + sizeof(seq_be) + sizeof(*gre), 0, (sockaddr *)&dstaddr, sizeof(dstaddr)) == -1) {
138                 perror("sendto");
139                 return;
140         }
141 }
142         
143 TUNSender::TUNSender(int tunfd)
144         : tunfd(tunfd) {}
145
146 void TUNSender::send_packet(uint16_t proto, const string &data)
147 {
148         char buf[4096];
149
150         char *ptr = buf;
151         uint16_t flags = 0;
152         memcpy(ptr, &flags, sizeof(flags));
153         ptr += sizeof(flags);
154
155         proto = htons(proto);
156         memcpy(ptr, &proto, sizeof(proto));
157         ptr += sizeof(proto);
158
159         memcpy(ptr, data.data(), data.size());
160
161         int len = sizeof(flags) + sizeof(proto) + data.size();
162         if (write(tunfd, buf, len) != len) {
163                 perror("write");
164                 return;
165         }
166 }
167
168 Reorderer::Reorderer(Sender* sender)
169         : sender(sender), last_seq(-1)
170 {
171 }
172
173 #define PACKET_BUFFER_SIZE 100
174
175 void Reorderer::handle_packet(uint16_t proto, const string& data, int seq)
176 {
177         bool silence = false;
178         if (packet_buffer.size() >= PACKET_BUFFER_SIZE) {
179                 printf("Gave up waiting for packets [%d,%d>\n",
180                         last_seq + 1, packet_buffer.top().seq);
181                 silence = true;
182                 last_seq = packet_buffer.top().seq - 1;
183         }
184
185         GREPacket packet;
186         packet.seq = seq;
187         packet.proto = proto;
188         packet.data = data;
189         packet_buffer.push(packet);
190
191         while (!packet_buffer.empty() &&
192                (last_seq == -1 || packet_buffer.top().seq <= last_seq + 1)) {
193                 int front_seq = packet_buffer.top().seq;
194                 if (front_seq < last_seq + 1) {
195                         printf("Duplicate packet or way out-of-order: seq=%d front_seq=%d\n",
196                                 front_seq, last_seq + 1);
197                         packet_buffer.pop();
198                         continue;
199                 }
200                 //if (packet_buffer.size() > 1) {
201                 //      printf("seq=%d (REORDER %d)\n", front_seq, int(packet_buffer.size()));
202                 //} else {
203                 //      printf("seq=%d\n", front_seq);
204                 //}
205                 const string &data = packet_buffer.top().data;
206                 send_packet(packet_buffer.top().proto, data, silence);
207                 packet_buffer.pop();
208                 last_seq = front_seq;
209                 if (!silence && !packet_buffer.empty()) {
210                         printf("Reordering with packet buffer size %d: seq=%d new_front_seq=%d\n", int(packet_buffer.size()), front_seq, packet_buffer.top().seq);
211                         silence = true;
212                 }
213         }
214 }
215
216 void Reorderer::send_packet(uint16_t proto, const string &data, bool silence)
217 {
218         if (data.size() == 1344) {
219                 for (int i = 0; i < 7; ++i) {
220                         const char *pkt = &data[i * 188 + 28];
221                         int pid = (ntohl(*(uint32_t *)(pkt)) & 0x1fff00) >> 8;
222                         if (pid == 8191) {
223                                 // stuffing, ignore
224                                 continue;
225                         }
226                         int has_payload = pkt[3] & 0x10;
227                         int cc = pkt[3] & 0xf;
228                         if (has_payload) {
229                                 int last_cc = ccs[pid];
230                                 if (!silence && cc != ((last_cc + 1) & 0xf)) {
231                                         printf("Pid %d discontinuity (expected %d, got %d)\n", pid, (last_cc + 1) & 0xf, cc);
232                                 }
233                                 ccs[pid] = cc;
234                         }
235                 }
236         }
237         sender->send_packet(proto, data);
238 }
239
240 void read_gre_packet(int gresock, const in6_addr &remoteaddr, Reorderer *sender)
241 {
242         struct sockaddr_storage addr;
243         socklen_t addrlen = sizeof(addr);
244         char buf[4096];
245         int ret = recvfrom(gresock, buf, sizeof(buf), 0, (struct sockaddr *)&addr, &addrlen);
246         if (ret == -1) {
247                 perror("recvfrom");
248                 exit(1);
249         }
250         if (addr.ss_family != AF_INET6) {
251                 return;
252         }
253         struct in6_addr *addr6 = &((struct sockaddr_in6 *)&addr)->sin6_addr;
254         if (memcmp(addr6, &remoteaddr, sizeof(*addr6)) != 0) {
255                 // ignore
256                 return;
257         }
258         gre_header* gre = (gre_header *)buf;
259
260         char* ptr = buf + sizeof(gre_header);
261         if (gre->has_checksum) {
262                 ptr += 4;
263         }
264         if (gre->has_key) {
265                 ptr += 4;
266         }
267         uint32_t seq;
268         if (gre->has_seq) {
269                 seq = ntohl(*(uint32_t *)ptr);
270                 ptr += 4;
271         }
272
273         //printf("gre packet: proto=%x\n", ntohs(gre->protocol_type));
274
275         sender->handle_packet(ntohs(gre->protocol_type), string(ptr, buf + ret), seq);
276 }
277
278 void read_tun_packet(int tunfd, Sender *sender)
279 {
280         char buf[4096];
281         int ret = read(tunfd, buf, sizeof(buf));
282         if (ret == -1) {
283                 perror("read");
284                 exit(1);
285         }
286         if (ret == 0) {
287                 fprintf(stderr, "tunfd EOF\n");
288                 exit(1);
289         }
290         
291         char *ptr = buf;
292         uint16_t flags = *(uint16_t *)ptr;
293         ptr += 2;
294         uint16_t proto = ntohs(*(uint16_t *)ptr);
295         ptr += 2;
296         //fprintf(stderr, "tun packet: flags=%x proto=%x len=%d\n",
297         //      flags, proto, ret - 4);
298         sender->send_packet(proto, string(ptr, buf + ret));
299 }
300
301 int main(int argc, char **argv)
302 {
303         int tunfd = tun_open("tungre");
304         int gresock = socket(AF_INET6, SOCK_RAW, IPPROTO_GRE);
305         if (gresock == -1) {
306                 perror("socket");
307                 exit(1);
308         }
309
310         sockaddr_in6 my_addr;
311         memset(&my_addr, 0, sizeof(my_addr));
312         my_addr.sin6_family = AF_INET6;
313         my_addr.sin6_addr = get_addr(argv[1]);
314         if (bind(gresock, (sockaddr *)&my_addr, sizeof(my_addr)) == -1) {
315                 perror("bind");
316                 exit(1);
317         }
318
319         in6_addr remoteaddr = get_addr(argv[2]);
320         GRESender gre_sender(gresock, remoteaddr);
321         TUNSender tun_sender(tunfd);
322
323         Reorderer tun_reorderer(&tun_sender);
324
325         fd_set fds;
326         FD_ZERO(&fds);
327         for ( ;; ) {
328                 FD_SET(gresock, &fds);
329                 FD_SET(tunfd, &fds);
330                 int ret = select(1024, &fds, NULL, NULL, NULL);
331                 if (ret == -1) {
332                         perror("select");
333                         continue;
334                 }
335
336                 if (FD_ISSET(gresock, &fds)) {
337                         read_gre_packet(gresock, remoteaddr, &tun_reorderer);
338                 }
339                 if (FD_ISSET(tunfd, &fds)) {
340                         read_tun_packet(tunfd, &gre_sender);
341                 }
342         }
343 }