149f15100SShuo Chen#include "faketcp.h"
249f15100SShuo Chen
349f15100SShuo Chen#include <stdio.h>
449f15100SShuo Chen#include <stdlib.h>
549f15100SShuo Chen#include <string.h>
649f15100SShuo Chen#include <unistd.h>
749f15100SShuo Chen#include <netinet/ip.h>
849f15100SShuo Chen#include <netinet/tcp.h>
949f15100SShuo Chen#include <linux/if_ether.h>
1049f15100SShuo Chen
1149f15100SShuo Chenvoid tcp_input(int fd, const void* input, const void* ippayload, int tot_len)
1249f15100SShuo Chen{
1349f15100SShuo Chen  const struct iphdr* iphdr = static_cast<const struct iphdr*>(input);
1449f15100SShuo Chen  const struct tcphdr* tcphdr = static_cast<const struct tcphdr*>(ippayload);
1549f15100SShuo Chen  const int iphdr_len = iphdr->ihl*4;
1649f15100SShuo Chen  const int tcp_seg_len = tot_len - iphdr_len;
1749f15100SShuo Chen  const int tcphdr_size = sizeof(*tcphdr);
1849f15100SShuo Chen  if (tcp_seg_len >= tcphdr_size
1949f15100SShuo Chen      && tcp_seg_len >= tcphdr->doff*4)
2049f15100SShuo Chen  {
2149f15100SShuo Chen    const int tcphdr_len = tcphdr->doff*4;
2249f15100SShuo Chen    const void* payload = ippayload + tcphdr_len;
2349f15100SShuo Chen    const int payload_len = tot_len - iphdr_len - tcphdr_len;
2449f15100SShuo Chen
2549f15100SShuo Chen    char source[INET_ADDRSTRLEN];
2649f15100SShuo Chen    char dest[INET_ADDRSTRLEN];
2749f15100SShuo Chen    inet_ntop(AF_INET, &iphdr->saddr, source, INET_ADDRSTRLEN);
2849f15100SShuo Chen    inet_ntop(AF_INET, &iphdr->daddr, dest, INET_ADDRSTRLEN);
2949f15100SShuo Chen    printf("IP %s.%d > %s.%d: ",
3049f15100SShuo Chen           source, ntohs(tcphdr->source), dest, ntohs(tcphdr->dest));
3149f15100SShuo Chen    printf("Flags [%c], seq %u, win %d, length %d\n",
3249f15100SShuo Chen           tcphdr->syn ? 'S' : (tcphdr->fin ? 'F' : '.'),
3349f15100SShuo Chen           ntohl(tcphdr->seq),
3449f15100SShuo Chen           ntohs(tcphdr->window),
3549f15100SShuo Chen           payload_len);
3649f15100SShuo Chen
3749f15100SShuo Chen    union
3849f15100SShuo Chen    {
3949f15100SShuo Chen      unsigned char output[ETH_FRAME_LEN];
4049f15100SShuo Chen      struct
4149f15100SShuo Chen      {
4249f15100SShuo Chen        struct iphdr iphdr;
4349f15100SShuo Chen        struct tcphdr tcphdr;
4449f15100SShuo Chen      } out;
4549f15100SShuo Chen    };
4649f15100SShuo Chen
4749f15100SShuo Chen    assert(sizeof(out) == sizeof(struct iphdr) + sizeof(struct tcphdr));
4849f15100SShuo Chen    int output_len = sizeof(out);
4949f15100SShuo Chen    bzero(&out, output_len + 4);
5049f15100SShuo Chen    memcpy(output, input, sizeof(struct iphdr));
5149f15100SShuo Chen
5249f15100SShuo Chen    std::swap(out.iphdr.saddr, out.iphdr.daddr);
5349f15100SShuo Chen    out.iphdr.check = 0;
5449f15100SShuo Chen
5549f15100SShuo Chen    out.tcphdr.source = tcphdr->dest;
5649f15100SShuo Chen    out.tcphdr.dest = tcphdr->source;
5749f15100SShuo Chen    out.tcphdr.doff = sizeof(struct tcphdr) / 4;
5849f15100SShuo Chen    out.tcphdr.window = htons(5000);
5949f15100SShuo Chen
6049f15100SShuo Chen    bool response = false;
612c431f66SShuo Chen    const uint32_t seq = ntohl(tcphdr->seq);
6249f15100SShuo Chen    if (tcphdr->syn)
6349f15100SShuo Chen    {
642c431f66SShuo Chen      out.tcphdr.seq = htonl(seq);
652c431f66SShuo Chen      out.tcphdr.ack_seq = htonl(seq+1);
6649f15100SShuo Chen      out.tcphdr.syn = 1;
6749f15100SShuo Chen      out.tcphdr.ack = 1;
6849f15100SShuo Chen      response = true;
6949f15100SShuo Chen    }
7049f15100SShuo Chen    else if (tcphdr->fin)
7149f15100SShuo Chen    {
722c431f66SShuo Chen      out.tcphdr.seq = htonl(seq);
732c431f66SShuo Chen      out.tcphdr.ack_seq = htonl(seq+1);
7449f15100SShuo Chen      out.tcphdr.fin = 1;
7549f15100SShuo Chen      out.tcphdr.ack = 1;
7649f15100SShuo Chen      response = true;
7749f15100SShuo Chen    }
7849f15100SShuo Chen    else if (payload_len > 0)
7949f15100SShuo Chen    {
802c431f66SShuo Chen      out.tcphdr.seq = htonl(seq);
812c431f66SShuo Chen      out.tcphdr.ack_seq = htonl(seq+payload_len);
8249f15100SShuo Chen      out.tcphdr.psh = 1;
8349f15100SShuo Chen      out.tcphdr.ack = 1;
8449f15100SShuo Chen      assert(output + output_len + payload_len < output + sizeof(output));
8549f15100SShuo Chen      memcpy(output + output_len, payload, payload_len);
8649f15100SShuo Chen      output_len += payload_len;
8749f15100SShuo Chen      response = true;
8849f15100SShuo Chen    }
8949f15100SShuo Chen
9049f15100SShuo Chen    out.iphdr.tot_len = htons(output_len);
9149f15100SShuo Chen    out.iphdr.check = in_checksum(output, sizeof(struct iphdr));
9249f15100SShuo Chen
9349f15100SShuo Chen    unsigned char* pseudo = output + output_len;
9449f15100SShuo Chen    if (payload_len % 2 == 1)
9549f15100SShuo Chen    {
9649f15100SShuo Chen      *pseudo = 0;
9749f15100SShuo Chen      ++pseudo;
9849f15100SShuo Chen    }
9949f15100SShuo Chen    unsigned int len = sizeof(struct tcphdr)+payload_len;
10049f15100SShuo Chen    pseudo[0] = 0;
10149f15100SShuo Chen    pseudo[1] = IPPROTO_TCP;
10249f15100SShuo Chen    pseudo[2] = len / 256;
10349f15100SShuo Chen    pseudo[3] = len % 256;
10449f15100SShuo Chen    out.tcphdr.check = in_checksum(&out.iphdr.saddr, len + 12 + (payload_len % 2));
10549f15100SShuo Chen    if (response)
10649f15100SShuo Chen    {
10749f15100SShuo Chen      write(fd, output, output_len);
10849f15100SShuo Chen    }
10949f15100SShuo Chen  }
11049f15100SShuo Chen}
11149f15100SShuo Chen
11249f15100SShuo Chenint main()
11349f15100SShuo Chen{
11449f15100SShuo Chen  char ifname[IFNAMSIZ] = "tun%d";
11549f15100SShuo Chen  int fd = tun_alloc(ifname);
11649f15100SShuo Chen
11749f15100SShuo Chen  if (fd < 0)
11849f15100SShuo Chen  {
11949f15100SShuo Chen    fprintf(stderr, "tunnel interface allocation failed\n");
12049f15100SShuo Chen    exit(1);
12149f15100SShuo Chen  }
12249f15100SShuo Chen
12349f15100SShuo Chen  printf("allocted tunnel interface %s\n", ifname);
12449f15100SShuo Chen  sleep(1);
12549f15100SShuo Chen
12649f15100SShuo Chen  for (;;)
12749f15100SShuo Chen  {
12849f15100SShuo Chen    union
12949f15100SShuo Chen    {
13049f15100SShuo Chen      unsigned char buf[ETH_FRAME_LEN];
13149f15100SShuo Chen      struct iphdr iphdr;
13249f15100SShuo Chen    };
13349f15100SShuo Chen
13449f15100SShuo Chen    const int iphdr_size = sizeof iphdr;
13549f15100SShuo Chen
13649f15100SShuo Chen    int nread = read(fd, buf, sizeof(buf));
13749f15100SShuo Chen    if (nread < 0)
13849f15100SShuo Chen    {
13949f15100SShuo Chen      perror("read");
14049f15100SShuo Chen      close(fd);
14149f15100SShuo Chen      exit(1);
14249f15100SShuo Chen    }
14349f15100SShuo Chen    printf("read %d bytes from tunnel interface %s.\n", nread, ifname);
14449f15100SShuo Chen
14549f15100SShuo Chen    const int iphdr_len = iphdr.ihl*4;
14649f15100SShuo Chen    if (nread >= iphdr_size
14749f15100SShuo Chen        && iphdr.version == 4
14849f15100SShuo Chen        && iphdr_len >= iphdr_size
14949f15100SShuo Chen        && iphdr_len <= nread
15049f15100SShuo Chen        && iphdr.tot_len == htons(nread)
15149f15100SShuo Chen        && in_checksum(buf, iphdr_len) == 0)
15249f15100SShuo Chen    {
15349f15100SShuo Chen      const void* payload = buf + iphdr_len;
15449f15100SShuo Chen      if (iphdr.protocol == IPPROTO_ICMP)
15549f15100SShuo Chen      {
15649f15100SShuo Chen        icmp_input(fd, buf, payload, nread);
15749f15100SShuo Chen      }
15849f15100SShuo Chen      else if (iphdr.protocol == IPPROTO_TCP)
15949f15100SShuo Chen      {
16049f15100SShuo Chen        tcp_input(fd, buf, payload, nread);
16149f15100SShuo Chen      }
16249f15100SShuo Chen    }
16349f15100SShuo Chen    else
16449f15100SShuo Chen    {
16549f15100SShuo Chen      printf("bad packet\n");
16649f15100SShuo Chen      for (int i = 0; i < nread; ++i)
16749f15100SShuo Chen      {
16849f15100SShuo Chen        if (i % 4 == 0) printf("\n");
16949f15100SShuo Chen        printf("%02x ", buf[i]);
17049f15100SShuo Chen      }
17149f15100SShuo Chen      printf("\n");
17249f15100SShuo Chen    }
17349f15100SShuo Chen  }
17449f15100SShuo Chen
17549f15100SShuo Chen  return 0;
17649f15100SShuo Chen}
177