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