1#include "faketcp.h"
2
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6#include <unistd.h>
7#include <netinet/ip.h>
8#include <netinet/tcp.h>
9#include <linux/if_ether.h>
10
11void tcp_input(int fd, const void* input, const void* payload, int tot_len)
12{
13  const struct iphdr* iphdr = static_cast<const struct iphdr*>(input);
14  const struct tcphdr* tcphdr = static_cast<const struct tcphdr*>(payload);
15  const int iphdr_len = iphdr->ihl*4;
16  const int tcp_seg_len = tot_len - iphdr_len;
17  const int tcphdr_size = sizeof(*tcphdr);
18  if (tcp_seg_len >= tcphdr_size
19      && tcp_seg_len >= tcphdr->doff*4)
20  {
21    const int tcphdr_len = tcphdr->doff*4;
22
23    if (tcphdr->syn)
24    {
25      char source[INET_ADDRSTRLEN];
26      char dest[INET_ADDRSTRLEN];
27      inet_ntop(AF_INET, &iphdr->saddr, source, INET_ADDRSTRLEN);
28      inet_ntop(AF_INET, &iphdr->daddr, dest, INET_ADDRSTRLEN);
29      printf("IP %s.%d > %s.%d: ",
30             source, ntohs(tcphdr->source), dest, ntohs(tcphdr->dest));
31      printf("Flags [S], seq %u, win %d, length %d\n",
32             ntohl(tcphdr->seq),
33             ntohs(tcphdr->window),
34             tot_len - iphdr_len - tcphdr_len);
35
36      union
37      {
38        unsigned char output[ETH_FRAME_LEN];
39        struct
40        {
41          struct iphdr iphdr;
42          struct tcphdr tcphdr;
43        } out;
44      };
45
46      assert(sizeof(out) == sizeof(struct iphdr) + sizeof(struct tcphdr));
47      int output_len = sizeof(out);
48      bzero(&out, output_len + 4);
49      memcpy(output, input, sizeof(struct iphdr));
50
51      out.iphdr.tot_len = htons(output_len);
52      std::swap(out.iphdr.saddr, out.iphdr.daddr);
53      out.iphdr.check = 0;
54      out.iphdr.check = in_checksum(output, sizeof(struct iphdr));
55      out.tcphdr.source = tcphdr->dest;
56      out.tcphdr.dest = tcphdr->source;
57      out.tcphdr.seq = 0;
58      out.tcphdr.ack_seq = htonl(ntohl(tcphdr->seq)+1);
59      out.tcphdr.doff = sizeof(struct tcphdr) / 4;
60      out.tcphdr.ack = 1;
61      out.tcphdr.rst = 1;
62      out.tcphdr.window = 0;
63      unsigned char* pseudo = output + output_len;
64      pseudo[0] = 0;
65      pseudo[1] = IPPROTO_TCP;
66      pseudo[2] = 0;
67      pseudo[3] = sizeof(struct tcphdr);
68      out.tcphdr.check = in_checksum(&out.iphdr.saddr, sizeof(struct tcphdr)+12);
69      write(fd, output, output_len);
70    }
71  }
72}
73
74int main()
75{
76  char ifname[IFNAMSIZ] = "tun%d";
77  int fd = tun_alloc(ifname);
78
79  if (fd < 0)
80  {
81    fprintf(stderr, "tunnel interface allocation failed\n");
82    exit(1);
83  }
84
85  printf("allocted tunnel interface %s\n", ifname);
86  sleep(1);
87
88  for (;;)
89  {
90    union
91    {
92      unsigned char buf[ETH_FRAME_LEN];
93      struct iphdr iphdr;
94    };
95
96    const int iphdr_size = sizeof iphdr;
97
98    int nread = read(fd, buf, sizeof(buf));
99    if (nread < 0)
100    {
101      perror("read");
102      close(fd);
103      exit(1);
104    }
105    printf("read %d bytes from tunnel interface %s.\n", nread, ifname);
106
107    const int iphdr_len = iphdr.ihl*4;
108    if (nread >= iphdr_size
109        && iphdr.version == 4
110        && iphdr_len >= iphdr_size
111        && iphdr_len <= nread
112        && iphdr.tot_len == htons(nread)
113        && in_checksum(buf, iphdr_len) == 0)
114    {
115      const void* payload = buf + iphdr_len;
116      if (iphdr.protocol == IPPROTO_ICMP)
117      {
118        icmp_input(fd, buf, payload, nread);
119      }
120      else if (iphdr.protocol == IPPROTO_TCP)
121      {
122        tcp_input(fd, buf, payload, nread);
123      }
124    }
125    else
126    {
127      printf("bad packet\n");
128      for (int i = 0; i < nread; ++i)
129      {
130        if (i % 4 == 0) printf("\n");
131        printf("%02x ", buf[i]);
132      }
133      printf("\n");
134    }
135  }
136
137  return 0;
138}
139