]> git.sesse.net Git - greproxy/commitdiff
Move GREProtocol into its own files, and Reorderer into a .h file.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Sat, 7 Feb 2015 00:11:37 +0000 (01:11 +0100)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Sat, 7 Feb 2015 00:11:37 +0000 (01:11 +0100)
greprotocol.cpp [new file with mode: 0644]
greprotocol.h [new file with mode: 0644]
reorderer.h [new file with mode: 0644]

diff --git a/greprotocol.cpp b/greprotocol.cpp
new file mode 100644 (file)
index 0000000..b826a52
--- /dev/null
@@ -0,0 +1,112 @@
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "greprotocol.h"
+#include "reorderer.h"
+
+using namespace std;
+
+struct gre_header {
+       uint8_t reserved0_hi : 4;
+       uint8_t has_seq : 1;
+       uint8_t has_key : 1;
+       uint8_t unused : 1;
+       uint8_t has_checksum : 1;
+
+       uint8_t version : 3;
+       uint8_t reserved0_lo: 5;
+
+       uint16_t protocol_type;
+};
+
+
+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;
+}
+
+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);
+}
+
diff --git a/greprotocol.h b/greprotocol.h
new file mode 100644 (file)
index 0000000..6930f20
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef _GREPROTOCOL_H
+#define _GREPROTOCOL_H
+
+#include "protocol.h"
+
+#include <arpa/inet.h>
+#include <stdint.h>
+#include <string>
+
+class Reorderer;
+
+class GREProtocol : public Protocol {
+public:
+       GREProtocol(const in6_addr &myaddr, const in6_addr &dst);
+       virtual void send_packet(uint16_t proto, const std::string &data);
+       virtual int fd() const;
+       void read_packet(Reorderer* sender);
+
+private:
+       int seq;
+       int sock;
+       sockaddr_in6 dstaddr;
+};
+
+#endif  // !defined(_GREPROTOCOL_H)
diff --git a/reorderer.h b/reorderer.h
new file mode 100644 (file)
index 0000000..476093f
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef _REORDERER_H
+#define _REORDERER_H 1
+
+#include <stdint.h>
+
+#include <algorithm>
+#include <map>
+#include <queue>
+#include <string>
+#include <vector>
+
+class Protocol;
+
+struct GREPacket {
+       int seq;
+       uint16_t proto;
+       std::string data;
+
+       bool operator> (const GREPacket &other) const {
+               return seq > other.seq;
+       }
+};
+
+class Reorderer {
+public:
+       Reorderer(Protocol* sender);
+       void handle_packet(uint16_t proto, const std::string& data, int seq);
+
+private:
+       void send_packet(uint16_t proto, const std::string &data, bool silence);
+
+       Protocol* sender;
+       int last_seq;
+
+       std::priority_queue<GREPacket, std::vector<GREPacket>, std::greater<GREPacket>> packet_buffer;
+       std::map<int, int> ccs;
+};
+
+#endif  // !defined(_REORDERER_H)