12c431f66SShuo Chen#include "faketcp.h"
22c431f66SShuo Chen
32c431f66SShuo Chen#include <map>
42c431f66SShuo Chen
52c431f66SShuo Chen#include <stdio.h>
62c431f66SShuo Chen#include <stdlib.h>
7a4bafd74SShuo Chen#include <sys/time.h>
82c431f66SShuo Chen#include <unistd.h>
92c431f66SShuo Chen#include <netinet/ip.h>
102c431f66SShuo Chen#include <netinet/tcp.h>
112c431f66SShuo Chen#include <linux/if_ether.h>
122c431f66SShuo Chen
132c431f66SShuo Chenstruct TcpState
142c431f66SShuo Chen{
152c431f66SShuo Chen  uint32_t rcv_nxt;
162c431f66SShuo Chen  uint32_t snd_una;
172c431f66SShuo Chen};
182c431f66SShuo Chen
192c431f66SShuo Chenstd::map<SocketAddr, TcpState> expectedSeqs;
202c431f66SShuo Chen
212c431f66SShuo Chenvoid tcp_input(int fd, const void* input, const void* ippayload, int tot_len)
222c431f66SShuo Chen{
232c431f66SShuo Chen  const struct iphdr* iphdr = static_cast<const struct iphdr*>(input);
242c431f66SShuo Chen  const struct tcphdr* tcphdr = static_cast<const struct tcphdr*>(ippayload);
252c431f66SShuo Chen  const int iphdr_len = iphdr->ihl*4;
262c431f66SShuo Chen  const int tcp_seg_len = tot_len - iphdr_len;
272c431f66SShuo Chen  const int tcphdr_size = sizeof(*tcphdr);
282c431f66SShuo Chen  if (tcp_seg_len >= tcphdr_size
292c431f66SShuo Chen      && tcp_seg_len >= tcphdr->doff*4)
302c431f66SShuo Chen  {
312c431f66SShuo Chen    const int tcphdr_len = tcphdr->doff*4;
322c431f66SShuo Chen    const void* payload = ippayload + tcphdr_len;
332c431f66SShuo Chen    const int payload_len = tot_len - iphdr_len - tcphdr_len;
342c431f66SShuo Chen
352c431f66SShuo Chen    char source[INET_ADDRSTRLEN];
362c431f66SShuo Chen    char dest[INET_ADDRSTRLEN];
372c431f66SShuo Chen    inet_ntop(AF_INET, &iphdr->saddr, source, INET_ADDRSTRLEN);
382c431f66SShuo Chen    inet_ntop(AF_INET, &iphdr->daddr, dest, INET_ADDRSTRLEN);
392c431f66SShuo Chen    printf("IP %s.%d > %s.%d: ",
402c431f66SShuo Chen           source, ntohs(tcphdr->source), dest, ntohs(tcphdr->dest));
412c431f66SShuo Chen    printf("Flags [%c], seq %u, win %d, length %d\n",
422c431f66SShuo Chen           tcphdr->syn ? 'S' : (tcphdr->fin ? 'F' : '.'),
432c431f66SShuo Chen           ntohl(tcphdr->seq),
442c431f66SShuo Chen           ntohs(tcphdr->window),
452c431f66SShuo Chen           payload_len);
462c431f66SShuo Chen
472c431f66SShuo Chen    union
482c431f66SShuo Chen    {
492c431f66SShuo Chen      unsigned char output[ETH_FRAME_LEN];
502c431f66SShuo Chen      struct
512c431f66SShuo Chen      {
522c431f66SShuo Chen        struct iphdr iphdr;
532c431f66SShuo Chen        struct tcphdr tcphdr;
542c431f66SShuo Chen      } out;
552c431f66SShuo Chen    };
562c431f66SShuo Chen
572c431f66SShuo Chen    assert(sizeof(out) == sizeof(struct iphdr) + sizeof(struct tcphdr));
582c431f66SShuo Chen    int output_len = sizeof(out);
592c431f66SShuo Chen    bzero(&out, output_len + 4);
602c431f66SShuo Chen    memcpy(output, input, sizeof(struct iphdr));
612c431f66SShuo Chen
622c431f66SShuo Chen    std::swap(out.iphdr.saddr, out.iphdr.daddr);
632c431f66SShuo Chen    out.iphdr.check = 0;
642c431f66SShuo Chen
652c431f66SShuo Chen    out.tcphdr.source = tcphdr->dest;
662c431f66SShuo Chen    out.tcphdr.dest = tcphdr->source;
672c431f66SShuo Chen    out.tcphdr.doff = sizeof(struct tcphdr) / 4;
682c431f66SShuo Chen    out.tcphdr.window = htons(5000);
692c431f66SShuo Chen
702c431f66SShuo Chen    SocketAddr addr = { out.iphdr.saddr, out.iphdr.daddr, out.tcphdr.source, out.tcphdr.dest };
712c431f66SShuo Chen    bool response = false;
722c431f66SShuo Chen    const uint32_t seq = ntohl(tcphdr->seq);
732c431f66SShuo Chen    if (tcphdr->syn)
742c431f66SShuo Chen    {
752c431f66SShuo Chen      out.tcphdr.seq = htonl(seq);
762c431f66SShuo Chen      out.tcphdr.ack_seq = htonl(seq+1);
772c431f66SShuo Chen      out.tcphdr.syn = 1;
782c431f66SShuo Chen      out.tcphdr.ack = 1;
792c431f66SShuo Chen      TcpState s = { seq + 1, seq + 1 };
802c431f66SShuo Chen      expectedSeqs[addr] = s;
812c431f66SShuo Chen      response = true;
822c431f66SShuo Chen    }
832c431f66SShuo Chen    else if (tcphdr->fin)
842c431f66SShuo Chen    {
852c431f66SShuo Chen      out.tcphdr.seq = htonl(seq);
862c431f66SShuo Chen      out.tcphdr.ack_seq = htonl(seq+1);
872c431f66SShuo Chen      out.tcphdr.fin = 1;
882c431f66SShuo Chen      out.tcphdr.ack = 1;
892c431f66SShuo Chen      expectedSeqs.erase(addr);
902c431f66SShuo Chen      response = true;
912c431f66SShuo Chen    }
922c431f66SShuo Chen    else
932c431f66SShuo Chen    {
942c431f66SShuo Chen      out.tcphdr.seq = htonl(seq);
952c431f66SShuo Chen      out.tcphdr.ack_seq = htonl(seq+payload_len);
962c431f66SShuo Chen      out.tcphdr.psh = 1;
972c431f66SShuo Chen      out.tcphdr.ack = 1;
982c431f66SShuo Chen      assert(output + output_len + payload_len < output + sizeof(output));
992c431f66SShuo Chen      memcpy(output + output_len, payload, payload_len);
1002c431f66SShuo Chen      output_len += payload_len;
1012c431f66SShuo Chen      auto it = expectedSeqs.find(addr);
1022c431f66SShuo Chen      if (it != expectedSeqs.end())
1032c431f66SShuo Chen      {
1042c431f66SShuo Chen        const uint32_t ack = ntohl(tcphdr->ack_seq);
1052c431f66SShuo Chen        printf("seq = %u, ack = %u\n", seq, ack);
1062c431f66SShuo Chen        printf("rcv_nxt = %u, snd_una = %u\n", it->second.rcv_nxt, it->second.snd_una);
107a4bafd74SShuo Chen        if (tcphdr->ack && ack == it->second.snd_una)
108a4bafd74SShuo Chen        {
109a4bafd74SShuo Chen          it->second.rcv_nxt = ack;
110a4bafd74SShuo Chen        }
1112c431f66SShuo Chen        if (payload_len > 0 && it->second.rcv_nxt == seq)
1122c431f66SShuo Chen        {
1132c431f66SShuo Chen          it->second.snd_una = seq+payload_len;
1142c431f66SShuo Chen          response = true;
1152c431f66SShuo Chen        }
1162c431f66SShuo Chen        printf("rcv_nxt = %u, snd_una = %u\n", it->second.rcv_nxt, it->second.snd_una);
1172c431f66SShuo Chen      }
1182c431f66SShuo Chen      else
1192c431f66SShuo Chen      {
1202c431f66SShuo Chen        // RST
1212c431f66SShuo Chen      }
1222c431f66SShuo Chen    }
1232c431f66SShuo Chen
1242c431f66SShuo Chen    out.iphdr.tot_len = htons(output_len);
1252c431f66SShuo Chen    out.iphdr.check = in_checksum(output, sizeof(struct iphdr));
1262c431f66SShuo Chen
1272c431f66SShuo Chen    unsigned char* pseudo = output + output_len;
1282c431f66SShuo Chen    if (payload_len % 2 == 1)
1292c431f66SShuo Chen    {
1302c431f66SShuo Chen      *pseudo = 0;
1312c431f66SShuo Chen      ++pseudo;
1322c431f66SShuo Chen    }
1332c431f66SShuo Chen    unsigned int len = sizeof(struct tcphdr)+payload_len;
1342c431f66SShuo Chen    pseudo[0] = 0;
1352c431f66SShuo Chen    pseudo[1] = IPPROTO_TCP;
1362c431f66SShuo Chen    pseudo[2] = len / 256;
1372c431f66SShuo Chen    pseudo[3] = len % 256;
1382c431f66SShuo Chen    out.tcphdr.check = in_checksum(&out.iphdr.saddr, len + 12 + (payload_len % 2));
1392c431f66SShuo Chen    if (response)
1402c431f66SShuo Chen    {
1412c431f66SShuo Chen      write(fd, output, output_len);
1422c431f66SShuo Chen    }
1432c431f66SShuo Chen  }
1442c431f66SShuo Chen}
1452c431f66SShuo Chen
1462c431f66SShuo Chenint main()
1472c431f66SShuo Chen{
1482c431f66SShuo Chen  char ifname[IFNAMSIZ] = "tun%d";
1492c431f66SShuo Chen  int fd = tun_alloc(ifname);
1502c431f66SShuo Chen
1512c431f66SShuo Chen  if (fd < 0)
1522c431f66SShuo Chen  {
1532c431f66SShuo Chen    fprintf(stderr, "tunnel interface allocation failed\n");
1542c431f66SShuo Chen    exit(1);
1552c431f66SShuo Chen  }
1562c431f66SShuo Chen
1572c431f66SShuo Chen  printf("allocted tunnel interface %s\n", ifname);
1582c431f66SShuo Chen  sleep(1);
1592c431f66SShuo Chen
1602c431f66SShuo Chen  for (;;)
1612c431f66SShuo Chen  {
1622c431f66SShuo Chen    union
1632c431f66SShuo Chen    {
1642c431f66SShuo Chen      unsigned char buf[ETH_FRAME_LEN];
1652c431f66SShuo Chen      struct iphdr iphdr;
1662c431f66SShuo Chen    };
1672c431f66SShuo Chen
1682c431f66SShuo Chen    const int iphdr_size = sizeof iphdr;
1692c431f66SShuo Chen
1702c431f66SShuo Chen    int nread = read(fd, buf, sizeof(buf));
1712c431f66SShuo Chen    if (nread < 0)
1722c431f66SShuo Chen    {
1732c431f66SShuo Chen      perror("read");
1742c431f66SShuo Chen      close(fd);
1752c431f66SShuo Chen      exit(1);
1762c431f66SShuo Chen    }
177a4bafd74SShuo Chen    struct timeval tv;
178a4bafd74SShuo Chen    gettimeofday(&tv, NULL);
179a4bafd74SShuo Chen    printf("%ld.%06ld read %d bytes %s.\n", tv.tv_sec, tv.tv_usec, nread, ifname);
1802c431f66SShuo Chen
1812c431f66SShuo Chen    const int iphdr_len = iphdr.ihl*4;
1822c431f66SShuo Chen    if (nread >= iphdr_size
1832c431f66SShuo Chen        && iphdr.version == 4
1842c431f66SShuo Chen        && iphdr_len >= iphdr_size
1852c431f66SShuo Chen        && iphdr_len <= nread
1862c431f66SShuo Chen        && iphdr.tot_len == htons(nread)
1872c431f66SShuo Chen        && in_checksum(buf, iphdr_len) == 0)
1882c431f66SShuo Chen    {
1892c431f66SShuo Chen      const void* payload = buf + iphdr_len;
1902c431f66SShuo Chen      if (iphdr.protocol == IPPROTO_ICMP)
1912c431f66SShuo Chen      {
1922c431f66SShuo Chen        icmp_input(fd, buf, payload, nread);
1932c431f66SShuo Chen      }
1942c431f66SShuo Chen      else if (iphdr.protocol == IPPROTO_TCP)
1952c431f66SShuo Chen      {
1962c431f66SShuo Chen        tcp_input(fd, buf, payload, nread);
1972c431f66SShuo Chen      }
1982c431f66SShuo Chen    }
1992c431f66SShuo Chen    else
2002c431f66SShuo Chen    {
2012c431f66SShuo Chen      printf("bad packet\n");
2022c431f66SShuo Chen      for (int i = 0; i < nread; ++i)
2032c431f66SShuo Chen      {
2042c431f66SShuo Chen        if (i % 4 == 0) printf("\n");
2052c431f66SShuo Chen        printf("%02x ", buf[i]);
2062c431f66SShuo Chen      }
2072c431f66SShuo Chen      printf("\n");
2082c431f66SShuo Chen    }
2092c431f66SShuo Chen  }
2102c431f66SShuo Chen
2112c431f66SShuo Chen  return 0;
2122c431f66SShuo Chen}
213