-struct GREPacket {
- int seq;
- uint16_t proto;
- string data;
-
- bool operator> (const GREPacket &other) const {
- return seq > other.seq;
- }
-};
-
-class Protocol {
-public:
- virtual void send_packet(uint16_t proto, const string &data) = 0;
- virtual int fd() const = 0;
-};
-
-class Reorderer;
-class Protocol;
-
-class GREProtocol : public Protocol {
-public:
- GREProtocol(const in6_addr &myaddr, const in6_addr &dst);
- virtual void send_packet(uint16_t proto, const string &data);
- virtual int fd() const;
- void read_packet(Reorderer* sender);
-
-private:
- int seq;
- int sock;
- sockaddr_in6 dstaddr;
-};
-
-class TUNProtocol : public Protocol {
-public:
- TUNProtocol(const char *devname);
- virtual void send_packet(uint16_t proto, const string &data);
- virtual int fd() const;
- void read_packet(Protocol* sender);
-
-private:
- int tunfd;
-};
-
-class Reorderer {
-public:
- Reorderer(Protocol* sender);
- void handle_packet(uint16_t proto, const string& data, int seq);
-
-private:
- void send_packet(uint16_t proto, const string &data, bool silence);
-
- Protocol* sender;
- int last_seq;
-
- priority_queue<GREPacket, vector<GREPacket>, greater<GREPacket>> packet_buffer;
- map<int, int> ccs;
-};
-
-GREProtocol::GREProtocol(const in6_addr &src, const in6_addr &dst)
- : seq(0)
-{
- memset(&dstaddr, 0, sizeof(dstaddr));
- dstaddr.sin6_family = AF_INET6;
- dstaddr.sin6_addr = dst;
-
- sock = socket(AF_INET6, SOCK_RAW, IPPROTO_GRE);
- if (sock == -1) {
- perror("socket");
- exit(1);
- }
-
- sockaddr_in6 my_addr;
- memset(&my_addr, 0, sizeof(my_addr));
- my_addr.sin6_family = AF_INET6;
- my_addr.sin6_addr = src;
- if (bind(sock, (sockaddr *)&my_addr, sizeof(my_addr)) == -1) {
- perror("bind");
- exit(1);
- }
-}
-
-void GREProtocol::send_packet(uint16_t proto, const string &data)
-{
- char buf[4096];
- gre_header *gre = (gre_header *)buf;
-
- memset(gre, 0, sizeof(*gre));
- gre->has_seq = 1;
- gre->version = 0;
- gre->protocol_type = htons(proto);
-
- char *ptr = buf + sizeof(*gre);
- int seq_be = htonl(seq++);
- memcpy(ptr, &seq_be, sizeof(seq_be));
- ptr += sizeof(seq_be);
-
- memcpy(ptr, data.data(), data.size());
-
- if (sendto(sock, buf, data.size() + sizeof(seq_be) + sizeof(*gre), 0, (sockaddr *)&dstaddr, sizeof(dstaddr)) == -1) {
- perror("sendto");
- return;
- }
-}
-
-int GREProtocol::fd() const
-{
- return sock;
-}
-
-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;
-}
-
-Reorderer::Reorderer(Protocol* sender)
- : sender(sender), last_seq(-1)
-{
-}
-
-#define PACKET_BUFFER_SIZE 100
-
-void Reorderer::handle_packet(uint16_t proto, const string& data, int seq)
-{
- bool silence = false;
- if (packet_buffer.size() >= PACKET_BUFFER_SIZE) {
- printf("Gave up waiting for packets [%d,%d>\n",
- last_seq + 1, packet_buffer.top().seq);
- silence = true;
- last_seq = packet_buffer.top().seq - 1;
- }
-
- GREPacket packet;
- packet.seq = seq;
- packet.proto = proto;
- packet.data = data;
- packet_buffer.push(packet);
-
- while (!packet_buffer.empty() &&
- (last_seq == -1 || packet_buffer.top().seq <= last_seq + 1)) {
- int front_seq = packet_buffer.top().seq;
- if (front_seq < last_seq + 1) {
- printf("Duplicate packet or way out-of-order: seq=%d front_seq=%d\n",
- front_seq, last_seq + 1);
- packet_buffer.pop();
- continue;
- }
- //if (packet_buffer.size() > 1) {
- // printf("seq=%d (REORDER %d)\n", front_seq, int(packet_buffer.size()));
- //} else {
- // printf("seq=%d\n", front_seq);
- //}
- const string &data = packet_buffer.top().data;
- send_packet(packet_buffer.top().proto, data, silence);
- packet_buffer.pop();
- last_seq = front_seq;
- if (!silence && !packet_buffer.empty()) {
- printf("Reordering with packet buffer size %d: seq=%d new_front_seq=%d\n", int(packet_buffer.size()), front_seq, packet_buffer.top().seq);
- silence = true;
- }
- }
-}
-
-void Reorderer::send_packet(uint16_t proto, const string &data, bool silence)
-{
- if (data.size() == 1344) {
- for (int i = 0; i < 7; ++i) {
- const char *pkt = &data[i * 188 + 28];
- int pid = (ntohl(*(uint32_t *)(pkt)) & 0x1fff00) >> 8;
- if (pid == 8191) {
- // stuffing, ignore
- continue;
- }
- int has_payload = pkt[3] & 0x10;
- int cc = pkt[3] & 0xf;
- if (has_payload) {
- int last_cc = ccs[pid];
- if (!silence && cc != ((last_cc + 1) & 0xf)) {
- printf("Pid %d discontinuity (expected %d, got %d)\n", pid, (last_cc + 1) & 0xf, cc);
- }
- ccs[pid] = cc;
- }
- }
- }
- sender->send_packet(proto, data);
-}
-
-void GREProtocol::read_packet(Reorderer *sender)
-{
- struct sockaddr_storage addr;
- socklen_t addrlen = sizeof(addr);
- char buf[4096];
- int ret = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *)&addr, &addrlen);
- if (ret == -1) {
- perror("recvfrom");
- exit(1);
- }
- if (addr.ss_family != AF_INET6) {
- return;
- }
- struct in6_addr *addr6 = &((struct sockaddr_in6 *)&addr)->sin6_addr;
- if (memcmp(addr6, &dstaddr.sin6_addr, sizeof(*addr6)) != 0) {
- // ignore
- return;
- }
- gre_header* gre = (gre_header *)buf;
-
- char* ptr = buf + sizeof(gre_header);
- if (gre->has_checksum) {
- ptr += 4;
- }
- if (gre->has_key) {
- ptr += 4;
- }
- uint32_t seq;
- if (gre->has_seq) {
- seq = ntohl(*(uint32_t *)ptr);
- ptr += 4;
- }
-
- //printf("gre packet: proto=%x\n", ntohs(gre->protocol_type));
-
- sender->handle_packet(ntohs(gre->protocol_type), string(ptr, buf + ret), seq);
-}
-
-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));
-}
-