1bf7dd643SShuo Chen#include "faketcp.h"
2bf7dd643SShuo Chen
3bf7dd643SShuo Chen#include <stdio.h>
4bf7dd643SShuo Chen#include <stdlib.h>
5bf7dd643SShuo Chen#include <string.h>
6bf7dd643SShuo Chen#include <unistd.h>
7bf7dd643SShuo Chen#include <netinet/ip.h>
8bf7dd643SShuo Chen#include <netinet/tcp.h>
9bf7dd643SShuo Chen#include <linux/if_ether.h>
10bf7dd643SShuo Chen
11bf7dd643SShuo Chenvoid tcp_input(int fd, const void* input, const void* payload, int tot_len)
12bf7dd643SShuo Chen{
13bf7dd643SShuo Chen  const struct iphdr* iphdr = static_cast<const struct iphdr*>(input);
14bf7dd643SShuo Chen  const struct tcphdr* tcphdr = static_cast<const struct tcphdr*>(payload);
15bf7dd643SShuo Chen  const int iphdr_len = iphdr->ihl*4;
16bf7dd643SShuo Chen  const int tcp_seg_len = tot_len - iphdr_len;
17bf7dd643SShuo Chen  const int tcphdr_size = sizeof(*tcphdr);
18bf7dd643SShuo Chen  if (tcp_seg_len >= tcphdr_size
19bf7dd643SShuo Chen      && tcp_seg_len >= tcphdr->doff*4)
20bf7dd643SShuo Chen  {
21bf7dd643SShuo Chen    const int tcphdr_len = tcphdr->doff*4;
22bf7dd643SShuo Chen    const int payload_len = tot_len - iphdr_len - tcphdr_len;
23bf7dd643SShuo Chen
24bf7dd643SShuo Chen    char source[INET_ADDRSTRLEN];
25bf7dd643SShuo Chen    char dest[INET_ADDRSTRLEN];
26bf7dd643SShuo Chen    inet_ntop(AF_INET, &iphdr->saddr, source, INET_ADDRSTRLEN);
27bf7dd643SShuo Chen    inet_ntop(AF_INET, &iphdr->daddr, dest, INET_ADDRSTRLEN);
28bf7dd643SShuo Chen    printf("IP %s.%d > %s.%d: ",
29bf7dd643SShuo Chen           source, ntohs(tcphdr->source), dest, ntohs(tcphdr->dest));
3061cf49ddSShuo Chen    printf("Flags [%c], seq %u, win %d, length %d%s\n",
31bf7dd643SShuo Chen           tcphdr->syn ? 'S' : (tcphdr->fin ? 'F' : '.'),
32bf7dd643SShuo Chen           ntohl(tcphdr->seq),
33bf7dd643SShuo Chen           ntohs(tcphdr->window),
3461cf49ddSShuo Chen           payload_len,
3561cf49ddSShuo Chen           tcphdr_len > sizeof(struct tcphdr) ? " <>" : "");
36bf7dd643SShuo Chen
37bf7dd643SShuo Chen    union
38bf7dd643SShuo Chen    {
39bf7dd643SShuo Chen      unsigned char output[ETH_FRAME_LEN];
40bf7dd643SShuo Chen      struct
41bf7dd643SShuo Chen      {
42bf7dd643SShuo Chen        struct iphdr iphdr;
43bf7dd643SShuo Chen        struct tcphdr tcphdr;
44bf7dd643SShuo Chen      } out;
45bf7dd643SShuo Chen    };
46bf7dd643SShuo Chen
4761cf49ddSShuo Chen    static_assert(sizeof(out) == sizeof(struct iphdr) + sizeof(struct tcphdr), "");
48bf7dd643SShuo Chen    int output_len = sizeof(out);
49bf7dd643SShuo Chen    bzero(&out, output_len + 4);
50bf7dd643SShuo Chen    memcpy(output, input, sizeof(struct iphdr));
51bf7dd643SShuo Chen
52bf7dd643SShuo Chen    out.tcphdr.source = tcphdr->dest;
53bf7dd643SShuo Chen    out.tcphdr.dest = tcphdr->source;
54bf7dd643SShuo Chen    out.tcphdr.doff = sizeof(struct tcphdr) / 4;
5561cf49ddSShuo Chen    out.tcphdr.window = htons(65000);
56bf7dd643SShuo Chen
57bf7dd643SShuo Chen    bool response = false;
5861cf49ddSShuo Chen    const uint32_t seq = ntohl(tcphdr->seq);
5961cf49ddSShuo Chen    const uint32_t isn = 123456;
60bf7dd643SShuo Chen    if (tcphdr->syn)
61bf7dd643SShuo Chen    {
6261cf49ddSShuo Chen      out.tcphdr.seq = htonl(isn);
6361cf49ddSShuo Chen      out.tcphdr.ack_seq = htonl(seq+1);
64bf7dd643SShuo Chen      out.tcphdr.syn = 1;
65bf7dd643SShuo Chen      out.tcphdr.ack = 1;
6661cf49ddSShuo Chen
6761cf49ddSShuo Chen      // set mss=1000
6861cf49ddSShuo Chen      unsigned char* mss = output + output_len;
6961cf49ddSShuo Chen      *mss++ = 2;
7061cf49ddSShuo Chen      *mss++ = 4;
7161cf49ddSShuo Chen      *mss++ = 0x03;
7261cf49ddSShuo Chen      *mss++ = 0xe8;  // 1000 == 0x03e8
7361cf49ddSShuo Chen      out.tcphdr.doff += 1;
7461cf49ddSShuo Chen      output_len += 4;
7561cf49ddSShuo Chen
76bf7dd643SShuo Chen      response = true;
77bf7dd643SShuo Chen    }
78bf7dd643SShuo Chen    else if (tcphdr->fin)
79bf7dd643SShuo Chen    {
8061cf49ddSShuo Chen      out.tcphdr.seq = htonl(isn+1);
8161cf49ddSShuo Chen      out.tcphdr.ack_seq = htonl(seq+1);
82bf7dd643SShuo Chen      out.tcphdr.fin = 1;
83bf7dd643SShuo Chen      out.tcphdr.ack = 1;
84bf7dd643SShuo Chen      response = true;
85bf7dd643SShuo Chen    }
86bf7dd643SShuo Chen    else if (payload_len > 0)
87bf7dd643SShuo Chen    {
8861cf49ddSShuo Chen      out.tcphdr.seq = htonl(isn+1);
8961cf49ddSShuo Chen      out.tcphdr.ack_seq = htonl(seq+payload_len);
90bf7dd643SShuo Chen      out.tcphdr.ack = 1;
91bf7dd643SShuo Chen      response = true;
92bf7dd643SShuo Chen    }
93bf7dd643SShuo Chen
9461cf49ddSShuo Chen    // build IP header
9561cf49ddSShuo Chen    out.iphdr.tot_len = htons(output_len);
9661cf49ddSShuo Chen    std::swap(out.iphdr.saddr, out.iphdr.daddr);
9761cf49ddSShuo Chen    out.iphdr.check = 0;
9861cf49ddSShuo Chen    out.iphdr.check = in_checksum(output, sizeof(struct iphdr));
9961cf49ddSShuo Chen
100bf7dd643SShuo Chen    unsigned char* pseudo = output + output_len;
101bf7dd643SShuo Chen    pseudo[0] = 0;
102bf7dd643SShuo Chen    pseudo[1] = IPPROTO_TCP;
103bf7dd643SShuo Chen    pseudo[2] = 0;
10461cf49ddSShuo Chen    pseudo[3] = output_len - sizeof(struct iphdr);
10561cf49ddSShuo Chen    out.tcphdr.check = in_checksum(&out.iphdr.saddr, output_len - 8);
106bf7dd643SShuo Chen    if (response)
107bf7dd643SShuo Chen    {
108bf7dd643SShuo Chen      write(fd, output, output_len);
109bf7dd643SShuo Chen    }
110bf7dd643SShuo Chen  }
111bf7dd643SShuo Chen}
112bf7dd643SShuo Chen
11361cf49ddSShuo Chenint main(int argc, char* argv[])
114bf7dd643SShuo Chen{
115bf7dd643SShuo Chen  char ifname[IFNAMSIZ] = "tun%d";
11661cf49ddSShuo Chen  bool offload = argc > 1 && strcmp(argv[1], "-K") == 0;
11761cf49ddSShuo Chen  int fd = tun_alloc(ifname, offload);
118bf7dd643SShuo Chen
119bf7dd643SShuo Chen  if (fd < 0)
120bf7dd643SShuo Chen  {
121bf7dd643SShuo Chen    fprintf(stderr, "tunnel interface allocation failed\n");
122bf7dd643SShuo Chen    exit(1);
123bf7dd643SShuo Chen  }
124bf7dd643SShuo Chen
125bf7dd643SShuo Chen  printf("allocted tunnel interface %s\n", ifname);
126bf7dd643SShuo Chen  sleep(1);
127bf7dd643SShuo Chen
128bf7dd643SShuo Chen  for (;;)
129bf7dd643SShuo Chen  {
130b2fec1eaSShuo Chen    union
131b2fec1eaSShuo Chen    {
13261cf49ddSShuo Chen      unsigned char buf[IP_MAXPACKET];
133b2fec1eaSShuo Chen      struct iphdr iphdr;
134b2fec1eaSShuo Chen    };
135b2fec1eaSShuo Chen
136b2fec1eaSShuo Chen    const int iphdr_size = sizeof iphdr;
137b2fec1eaSShuo Chen
138bf7dd643SShuo Chen    int nread = read(fd, buf, sizeof(buf));
139bf7dd643SShuo Chen    if (nread < 0)
140bf7dd643SShuo Chen    {
141bf7dd643SShuo Chen      perror("read");
142bf7dd643SShuo Chen      close(fd);
143bf7dd643SShuo Chen      exit(1);
144bf7dd643SShuo Chen    }
14561cf49ddSShuo Chen    else if (nread == sizeof(buf))
14661cf49ddSShuo Chen    {
14761cf49ddSShuo Chen      printf("possible message truncated.\n");
14861cf49ddSShuo Chen    }
149bf7dd643SShuo Chen    printf("read %d bytes from tunnel interface %s.\n", nread, ifname);
150bf7dd643SShuo Chen
15161cf49ddSShuo Chen    const int iphdr_len = iphdr.ihl*4;  // FIXME: check nread >= sizeof iphdr before accessing iphdr.ihl.
152bf7dd643SShuo Chen    if (nread >= iphdr_size
153bf7dd643SShuo Chen        && iphdr.version == 4
154b2fec1eaSShuo Chen        && iphdr_len >= iphdr_size
155b2fec1eaSShuo Chen        && iphdr_len <= nread
156bf7dd643SShuo Chen        && iphdr.tot_len == htons(nread)
157b2fec1eaSShuo Chen        && in_checksum(buf, iphdr_len) == 0)
158bf7dd643SShuo Chen    {
159b2fec1eaSShuo Chen      const void* payload = buf + iphdr_len;
160bf7dd643SShuo Chen      if (iphdr.protocol == IPPROTO_ICMP)
161bf7dd643SShuo Chen      {
162bf7dd643SShuo Chen        icmp_input(fd, buf, payload, nread);
163bf7dd643SShuo Chen      }
164bf7dd643SShuo Chen      else if (iphdr.protocol == IPPROTO_TCP)
165bf7dd643SShuo Chen      {
166bf7dd643SShuo Chen        tcp_input(fd, buf, payload, nread);
167bf7dd643SShuo Chen      }
168bf7dd643SShuo Chen    }
16961cf49ddSShuo Chen    else if (iphdr.version == 4)
170bf7dd643SShuo Chen    {
171bf7dd643SShuo Chen      printf("bad packet\n");
172bf7dd643SShuo Chen      for (int i = 0; i < nread; ++i)
173bf7dd643SShuo Chen      {
174bf7dd643SShuo Chen        if (i % 4 == 0) printf("\n");
175bf7dd643SShuo Chen        printf("%02x ", buf[i]);
176bf7dd643SShuo Chen      }
177bf7dd643SShuo Chen      printf("\n");
178bf7dd643SShuo Chen    }
179bf7dd643SShuo Chen  }
180bf7dd643SShuo Chen
181bf7dd643SShuo Chen  return 0;
182bf7dd643SShuo Chen}
183