1b2fec1eaSShuo Chen#include "faketcp.h"
2b2fec1eaSShuo Chen
3b2fec1eaSShuo Chen#include <stdio.h>
4b2fec1eaSShuo Chen#include <stdlib.h>
5b2fec1eaSShuo Chen#include <string.h>
6b2fec1eaSShuo Chen#include <unistd.h>
7b2fec1eaSShuo Chen#include <netinet/ip.h>
8b2fec1eaSShuo Chen#include <netinet/tcp.h>
9b2fec1eaSShuo Chen#include <linux/if_ether.h>
10b2fec1eaSShuo Chen
11b2fec1eaSShuo Chenvoid tcp_input(int fd, const void* input, const void* payload, int tot_len, bool passive)
12b2fec1eaSShuo Chen{
13b2fec1eaSShuo Chen  const struct iphdr* iphdr = static_cast<const struct iphdr*>(input);
14b2fec1eaSShuo Chen  const struct tcphdr* tcphdr = static_cast<const struct tcphdr*>(payload);
15b2fec1eaSShuo Chen  const int iphdr_len = iphdr->ihl*4;
16b2fec1eaSShuo Chen  const int tcp_seg_len = tot_len - iphdr_len;
17b2fec1eaSShuo Chen  const int tcphdr_size = sizeof(*tcphdr);
18b2fec1eaSShuo Chen  if (tcp_seg_len >= tcphdr_size
19b2fec1eaSShuo Chen      && tcp_seg_len >= tcphdr->doff*4)
20b2fec1eaSShuo Chen  {
21b2fec1eaSShuo Chen    const int tcphdr_len = tcphdr->doff*4;
22b2fec1eaSShuo Chen    const int payload_len = tot_len - iphdr_len - tcphdr_len;
23b2fec1eaSShuo Chen
24b2fec1eaSShuo Chen    char source[INET_ADDRSTRLEN];
25b2fec1eaSShuo Chen    char dest[INET_ADDRSTRLEN];
26b2fec1eaSShuo Chen    inet_ntop(AF_INET, &iphdr->saddr, source, INET_ADDRSTRLEN);
27b2fec1eaSShuo Chen    inet_ntop(AF_INET, &iphdr->daddr, dest, INET_ADDRSTRLEN);
28b2fec1eaSShuo Chen    printf("IP %s.%d > %s.%d: ",
29b2fec1eaSShuo Chen           source, ntohs(tcphdr->source), dest, ntohs(tcphdr->dest));
30b2fec1eaSShuo Chen    printf("Flags [%c], seq %u, win %d, length %d\n",
31b2fec1eaSShuo Chen           tcphdr->syn ? 'S' : (tcphdr->fin ? 'F' : '.'),
32b2fec1eaSShuo Chen           ntohl(tcphdr->seq),
33b2fec1eaSShuo Chen           ntohs(tcphdr->window),
34b2fec1eaSShuo Chen           payload_len);
35b2fec1eaSShuo Chen
36b2fec1eaSShuo Chen    union
37b2fec1eaSShuo Chen    {
38b2fec1eaSShuo Chen      unsigned char output[ETH_FRAME_LEN];
39b2fec1eaSShuo Chen      struct
40b2fec1eaSShuo Chen      {
41b2fec1eaSShuo Chen        struct iphdr iphdr;
42b2fec1eaSShuo Chen        struct tcphdr tcphdr;
43b2fec1eaSShuo Chen      } out;
44b2fec1eaSShuo Chen    };
45b2fec1eaSShuo Chen
46b2fec1eaSShuo Chen    assert(sizeof(out) == sizeof(struct iphdr) + sizeof(struct tcphdr));
47b2fec1eaSShuo Chen    int output_len = sizeof(out);
48b2fec1eaSShuo Chen    bzero(&out, output_len + 4);
49b2fec1eaSShuo Chen    memcpy(output, input, sizeof(struct iphdr));
50b2fec1eaSShuo Chen
51b2fec1eaSShuo Chen    out.iphdr.tot_len = htons(output_len);
52b2fec1eaSShuo Chen    std::swap(out.iphdr.saddr, out.iphdr.daddr);
53b2fec1eaSShuo Chen    out.iphdr.check = 0;
54b2fec1eaSShuo Chen    out.iphdr.check = in_checksum(output, sizeof(struct iphdr));
55b2fec1eaSShuo Chen
56b2fec1eaSShuo Chen    out.tcphdr.source = tcphdr->dest;
57b2fec1eaSShuo Chen    out.tcphdr.dest = tcphdr->source;
58b2fec1eaSShuo Chen    out.tcphdr.doff = sizeof(struct tcphdr) / 4;
59b2fec1eaSShuo Chen    out.tcphdr.window = htons(5000);
60b2fec1eaSShuo Chen
61b2fec1eaSShuo Chen    bool response = false;
62b2fec1eaSShuo Chen    if (tcphdr->syn)
63b2fec1eaSShuo Chen    {
64b2fec1eaSShuo Chen      out.tcphdr.seq = htonl(passive ? 123456 : 123457);
65b2fec1eaSShuo Chen      out.tcphdr.ack_seq = htonl(ntohl(tcphdr->seq)+1);
66b2fec1eaSShuo Chen      if (passive)
67b2fec1eaSShuo Chen      {
68b2fec1eaSShuo Chen        out.tcphdr.syn = 1;
69b2fec1eaSShuo Chen      }
70b2fec1eaSShuo Chen      out.tcphdr.ack = 1;
71b2fec1eaSShuo Chen      response = true;
72b2fec1eaSShuo Chen    }
73b2fec1eaSShuo Chen    else if (tcphdr->fin)
74b2fec1eaSShuo Chen    {
75b2fec1eaSShuo Chen      out.tcphdr.seq = htonl(123457);
76b2fec1eaSShuo Chen      out.tcphdr.ack_seq = htonl(ntohl(tcphdr->seq)+1);
77b2fec1eaSShuo Chen      out.tcphdr.fin = 1;
78b2fec1eaSShuo Chen      out.tcphdr.ack = 1;
79b2fec1eaSShuo Chen      response = true;
80b2fec1eaSShuo Chen    }
81b2fec1eaSShuo Chen    else if (payload_len > 0)
82b2fec1eaSShuo Chen    {
83b2fec1eaSShuo Chen      out.tcphdr.seq = htonl(123457);
84b2fec1eaSShuo Chen      out.tcphdr.ack_seq = htonl(ntohl(tcphdr->seq)+payload_len);
85b2fec1eaSShuo Chen      out.tcphdr.ack = 1;
86b2fec1eaSShuo Chen      response = true;
87b2fec1eaSShuo Chen    }
88b2fec1eaSShuo Chen
89b2fec1eaSShuo Chen    unsigned char* pseudo = output + output_len;
90b2fec1eaSShuo Chen    pseudo[0] = 0;
91b2fec1eaSShuo Chen    pseudo[1] = IPPROTO_TCP;
92b2fec1eaSShuo Chen    pseudo[2] = 0;
93b2fec1eaSShuo Chen    pseudo[3] = sizeof(struct tcphdr);
94b2fec1eaSShuo Chen    out.tcphdr.check = in_checksum(&out.iphdr.saddr, sizeof(struct tcphdr)+12);
95b2fec1eaSShuo Chen    if (response)
96b2fec1eaSShuo Chen    {
97b2fec1eaSShuo Chen      write(fd, output, output_len);
98b2fec1eaSShuo Chen    }
99b2fec1eaSShuo Chen  }
100b2fec1eaSShuo Chen}
101b2fec1eaSShuo Chen
102b2fec1eaSShuo Chen
103b2fec1eaSShuo Chenbool connect_one(int fd, uint32_t daddr, int dport, uint32_t saddr, int sport)
104b2fec1eaSShuo Chen{
105b2fec1eaSShuo Chen  {
106b2fec1eaSShuo Chen    union
107b2fec1eaSShuo Chen    {
108b2fec1eaSShuo Chen      unsigned char output[ETH_FRAME_LEN];
109b2fec1eaSShuo Chen      struct
110b2fec1eaSShuo Chen      {
111b2fec1eaSShuo Chen        struct iphdr iphdr;
112b2fec1eaSShuo Chen        struct tcphdr tcphdr;
113b2fec1eaSShuo Chen      } out;
114b2fec1eaSShuo Chen    };
115b2fec1eaSShuo Chen
116b2fec1eaSShuo Chen    bzero(&out, (sizeof out)+4);
117b2fec1eaSShuo Chen
118b2fec1eaSShuo Chen    out.iphdr.version = IPVERSION;
119b2fec1eaSShuo Chen    out.iphdr.ihl = sizeof(out.iphdr)/4;
120b2fec1eaSShuo Chen    out.iphdr.tos = 0;
121b2fec1eaSShuo Chen    out.iphdr.tot_len = htons(sizeof(out));
122b2fec1eaSShuo Chen    out.iphdr.id = 55564;
123b2fec1eaSShuo Chen    out.iphdr.frag_off |= htons(IP_DF);
124b2fec1eaSShuo Chen    out.iphdr.ttl = IPDEFTTL;
125b2fec1eaSShuo Chen    out.iphdr.protocol = IPPROTO_TCP;
126b2fec1eaSShuo Chen    out.iphdr.saddr = saddr;
127b2fec1eaSShuo Chen    out.iphdr.daddr = daddr;
128b2fec1eaSShuo Chen    out.iphdr.check = in_checksum(output, sizeof(struct iphdr));
129b2fec1eaSShuo Chen
130b2fec1eaSShuo Chen    out.tcphdr.source = sport;
131b2fec1eaSShuo Chen    out.tcphdr.dest = dport;
132b2fec1eaSShuo Chen    out.tcphdr.seq = htonl(123456);
133b2fec1eaSShuo Chen    out.tcphdr.ack_seq = 0;
134b2fec1eaSShuo Chen    out.tcphdr.doff = sizeof(out.tcphdr)/4;
135b2fec1eaSShuo Chen    out.tcphdr.syn = 1;
136b2fec1eaSShuo Chen    out.tcphdr.window = htons(4096);
137b2fec1eaSShuo Chen
138b2fec1eaSShuo Chen    unsigned char* pseudo = output + sizeof out;
139b2fec1eaSShuo Chen    pseudo[0] = 0;
140b2fec1eaSShuo Chen    pseudo[1] = IPPROTO_TCP;
141b2fec1eaSShuo Chen    pseudo[2] = 0;
142b2fec1eaSShuo Chen    pseudo[3] = sizeof(struct tcphdr);
143b2fec1eaSShuo Chen    out.tcphdr.check = in_checksum(&out.iphdr.saddr, sizeof(struct tcphdr)+12);
144b2fec1eaSShuo Chen
145b2fec1eaSShuo Chen    write(fd, output, sizeof out);
146b2fec1eaSShuo Chen  }
147b2fec1eaSShuo Chen
148b2fec1eaSShuo Chen    union
149b2fec1eaSShuo Chen    {
150b2fec1eaSShuo Chen      unsigned char buf[ETH_FRAME_LEN];
151b2fec1eaSShuo Chen      struct iphdr iphdr;
152b2fec1eaSShuo Chen    };
153b2fec1eaSShuo Chen
154b2fec1eaSShuo Chen    const int iphdr_size = sizeof iphdr;
155b2fec1eaSShuo Chen
156b2fec1eaSShuo Chen  int nread = read(fd, buf, sizeof(buf));
157b2fec1eaSShuo Chen  if (nread < 0)
158b2fec1eaSShuo Chen  {
159b2fec1eaSShuo Chen    perror("read");
160b2fec1eaSShuo Chen    close(fd);
161b2fec1eaSShuo Chen    exit(1);
162b2fec1eaSShuo Chen  }
163b2fec1eaSShuo Chen  // printf("read %d bytes from tunnel interface %s.\n", nread, ifname);
164b2fec1eaSShuo Chen
165b2fec1eaSShuo Chen  if (nread >= iphdr_size
166b2fec1eaSShuo Chen      && iphdr.version == 4
167b2fec1eaSShuo Chen      && iphdr.ihl*4 >= iphdr_size
168b2fec1eaSShuo Chen      && iphdr.ihl*4 <= nread
169b2fec1eaSShuo Chen      && iphdr.tot_len == htons(nread)
170b2fec1eaSShuo Chen      && in_checksum(buf, iphdr.ihl*4) == 0)
171b2fec1eaSShuo Chen  {
172b2fec1eaSShuo Chen    const void* payload = buf + iphdr.ihl*4;
173b2fec1eaSShuo Chen    if (iphdr.protocol == IPPROTO_ICMP)
174b2fec1eaSShuo Chen    {
175b2fec1eaSShuo Chen      icmp_input(fd, buf, payload, nread);
176b2fec1eaSShuo Chen    }
177b2fec1eaSShuo Chen    else if (iphdr.protocol == IPPROTO_TCP)
178b2fec1eaSShuo Chen    {
179b2fec1eaSShuo Chen      tcp_input(fd, buf, payload, nread, false);
180b2fec1eaSShuo Chen    }
181b2fec1eaSShuo Chen  }
182b2fec1eaSShuo Chen
183b2fec1eaSShuo Chen  return true;
184b2fec1eaSShuo Chen}
185b2fec1eaSShuo Chen
186b2fec1eaSShuo Chenvoid connect_many(int fd, const char* ipstr, int port, int count)
187b2fec1eaSShuo Chen{
188b2fec1eaSShuo Chen  uint32_t destip;
189b2fec1eaSShuo Chen  inet_pton(AF_INET, ipstr, &destip);
190b2fec1eaSShuo Chen
191b2fec1eaSShuo Chen  uint32_t srcip = ntohl(destip)+1;
192b2fec1eaSShuo Chen  int srcport = 1024;
193b2fec1eaSShuo Chen
194b2fec1eaSShuo Chen  for (int i = 0; i < count; ++i)
195b2fec1eaSShuo Chen  {
196b2fec1eaSShuo Chen    connect_one(fd, destip, htons(port), htonl(srcip), htons(srcport));
197b2fec1eaSShuo Chen    srcport++;
198b2fec1eaSShuo Chen    if (srcport > 0xFFFF)
199b2fec1eaSShuo Chen    {
200b2fec1eaSShuo Chen      srcport = 1024;
201b2fec1eaSShuo Chen      srcip++;
202b2fec1eaSShuo Chen    }
203b2fec1eaSShuo Chen  }
204b2fec1eaSShuo Chen}
205b2fec1eaSShuo Chen
206b2fec1eaSShuo Chenvoid usage()
207b2fec1eaSShuo Chen{
208b2fec1eaSShuo Chen}
209b2fec1eaSShuo Chen
210b2fec1eaSShuo Chenint main(int argc, char* argv[])
211b2fec1eaSShuo Chen{
212b2fec1eaSShuo Chen  if (argc < 4)
213b2fec1eaSShuo Chen  {
214b2fec1eaSShuo Chen    usage();
215b2fec1eaSShuo Chen    return 0;
216b2fec1eaSShuo Chen  }
217b2fec1eaSShuo Chen
218b2fec1eaSShuo Chen  char ifname[IFNAMSIZ] = "tun%d";
219b2fec1eaSShuo Chen  int fd = tun_alloc(ifname);
220b2fec1eaSShuo Chen
221b2fec1eaSShuo Chen  if (fd < 0)
222b2fec1eaSShuo Chen  {
223b2fec1eaSShuo Chen    fprintf(stderr, "tunnel interface allocation failed\n");
224b2fec1eaSShuo Chen    exit(1);
225b2fec1eaSShuo Chen  }
226b2fec1eaSShuo Chen
227b2fec1eaSShuo Chen  const char* ip = argv[1];
228b2fec1eaSShuo Chen  int port = atoi(argv[2]);
229b2fec1eaSShuo Chen  int count = atoi(argv[3]);
230b2fec1eaSShuo Chen  printf("allocted tunnel interface %s\n", ifname);
231b2fec1eaSShuo Chen  printf("press enter key to start connecting %s:%d\n", ip, port);
232b2fec1eaSShuo Chen  getchar();
233b2fec1eaSShuo Chen
234b2fec1eaSShuo Chen  connect_many(fd, ip, port, count);
235b2fec1eaSShuo Chen
236b2fec1eaSShuo Chen  for (;;)
237b2fec1eaSShuo Chen  {
238b2fec1eaSShuo Chen    union
239b2fec1eaSShuo Chen    {
240b2fec1eaSShuo Chen      unsigned char buf[ETH_FRAME_LEN];
241b2fec1eaSShuo Chen      struct iphdr iphdr;
242b2fec1eaSShuo Chen    };
243b2fec1eaSShuo Chen
244b2fec1eaSShuo Chen    const int iphdr_size = sizeof iphdr;
245b2fec1eaSShuo Chen
246b2fec1eaSShuo Chen    int nread = read(fd, buf, sizeof(buf));
247b2fec1eaSShuo Chen    if (nread < 0)
248b2fec1eaSShuo Chen    {
249b2fec1eaSShuo Chen      perror("read");
250b2fec1eaSShuo Chen      close(fd);
251b2fec1eaSShuo Chen      exit(1);
252b2fec1eaSShuo Chen    }
253b2fec1eaSShuo Chen    printf("read %d bytes from tunnel interface %s.\n", nread, ifname);
254b2fec1eaSShuo Chen
255b2fec1eaSShuo Chen    const int iphdr_len = iphdr.ihl*4;
256b2fec1eaSShuo Chen    if (nread >= iphdr_size
257b2fec1eaSShuo Chen        && iphdr.version == 4
258b2fec1eaSShuo Chen        && iphdr_len >= iphdr_size
259b2fec1eaSShuo Chen        && iphdr_len <= nread
260b2fec1eaSShuo Chen        && iphdr.tot_len == htons(nread)
261b2fec1eaSShuo Chen        && in_checksum(buf, iphdr_len) == 0)
262b2fec1eaSShuo Chen    {
263b2fec1eaSShuo Chen      const void* payload = buf + iphdr_len;
264b2fec1eaSShuo Chen      if (iphdr.protocol == IPPROTO_ICMP)
265b2fec1eaSShuo Chen      {
266b2fec1eaSShuo Chen        icmp_input(fd, buf, payload, nread);
267b2fec1eaSShuo Chen      }
268b2fec1eaSShuo Chen      else if (iphdr.protocol == IPPROTO_TCP)
269b2fec1eaSShuo Chen      {
270b2fec1eaSShuo Chen        tcp_input(fd, buf, payload, nread, true);
271b2fec1eaSShuo Chen      }
272b2fec1eaSShuo Chen    }
273b2fec1eaSShuo Chen    else
274b2fec1eaSShuo Chen    {
275b2fec1eaSShuo Chen      printf("bad packet\n");
276b2fec1eaSShuo Chen      for (int i = 0; i < nread; ++i)
277b2fec1eaSShuo Chen      {
278b2fec1eaSShuo Chen        if (i % 4 == 0) printf("\n");
279b2fec1eaSShuo Chen        printf("%02x ", buf[i]);
280b2fec1eaSShuo Chen      }
281b2fec1eaSShuo Chen      printf("\n");
282b2fec1eaSShuo Chen    }
283b2fec1eaSShuo Chen  }
284b2fec1eaSShuo Chen
285b2fec1eaSShuo Chen  return 0;
286b2fec1eaSShuo Chen}
287