1cc808594SShuo Chen#include "faketcp.h"
2cc808594SShuo Chen
3cc808594SShuo Chen#include <fcntl.h>
4cc808594SShuo Chen#include <stdio.h>
5cc808594SShuo Chen#include <string.h>
6cc808594SShuo Chen#include <unistd.h>
7cc808594SShuo Chen#include <linux/if_tun.h>
8cc808594SShuo Chen#include <netinet/in.h>
9cc808594SShuo Chen#include <netinet/ip_icmp.h>
10cc808594SShuo Chen#include <sys/ioctl.h>
11cc808594SShuo Chen
12bcb7e916SShuo Chenint sethostaddr(const char* dev)
13bcb7e916SShuo Chen{
14bcb7e916SShuo Chen  struct ifreq ifr;
15bcb7e916SShuo Chen  bzero(&ifr, sizeof(ifr));
16bcb7e916SShuo Chen  strcpy(ifr.ifr_name, dev);
17bcb7e916SShuo Chen  struct sockaddr_in addr;
18bcb7e916SShuo Chen  bzero(&addr, sizeof addr);
19bcb7e916SShuo Chen  addr.sin_family = AF_INET;
20bcb7e916SShuo Chen  inet_pton(AF_INET, "192.168.0.1", &addr.sin_addr);
21bcb7e916SShuo Chen  //addr.sin_addr.s_addr = htonl(0xc0a80001);
22bcb7e916SShuo Chen  bcopy(&addr, &ifr.ifr_addr, sizeof addr);
23bcb7e916SShuo Chen  int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
24bcb7e916SShuo Chen  if (sockfd < 0)
25bcb7e916SShuo Chen    return sockfd;
26bcb7e916SShuo Chen  int err = 0;
27bcb7e916SShuo Chen  // ifconfig tun0 192.168.0.1
28bcb7e916SShuo Chen  if ((err = ioctl(sockfd, SIOCSIFADDR, (void *) &ifr)) < 0)
29bcb7e916SShuo Chen  {
30bcb7e916SShuo Chen    perror("ioctl SIOCSIFADDR");
31bcb7e916SShuo Chen    goto done;
32bcb7e916SShuo Chen  }
33bcb7e916SShuo Chen  // ifup tun0
34bcb7e916SShuo Chen  if ((err = ioctl(sockfd, SIOCGIFFLAGS, (void *) &ifr)) < 0)
35bcb7e916SShuo Chen  {
36bcb7e916SShuo Chen    perror("ioctl SIOCGIFFLAGS");
37bcb7e916SShuo Chen    goto done;
38bcb7e916SShuo Chen  }
39bcb7e916SShuo Chen  ifr.ifr_flags |= IFF_UP;
40bcb7e916SShuo Chen  if ((err = ioctl(sockfd, SIOCSIFFLAGS, (void *) &ifr)) < 0)
41bcb7e916SShuo Chen  {
42bcb7e916SShuo Chen    perror("ioctl SIOCSIFFLAGS");
43bcb7e916SShuo Chen    goto done;
44bcb7e916SShuo Chen  }
45bcb7e916SShuo Chen  // ifconfig tun0 192.168.0.1/24
46bcb7e916SShuo Chen  inet_pton(AF_INET, "255.255.255.0", &addr.sin_addr);
47bcb7e916SShuo Chen  bcopy(&addr, &ifr.ifr_netmask, sizeof addr);
48bcb7e916SShuo Chen  if ((err = ioctl(sockfd, SIOCSIFNETMASK, (void *) &ifr)) < 0)
49bcb7e916SShuo Chen  {
50bcb7e916SShuo Chen    perror("ioctl SIOCSIFNETMASK");
51bcb7e916SShuo Chen    goto done;
52bcb7e916SShuo Chen  }
53bcb7e916SShuo Chendone:
54bcb7e916SShuo Chen  close(sockfd);
55bcb7e916SShuo Chen  return err;
56bcb7e916SShuo Chen}
57bcb7e916SShuo Chen
5861cf49ddSShuo Chenint tun_alloc(char dev[IFNAMSIZ], bool offload)
59cc808594SShuo Chen{
60cc808594SShuo Chen  struct ifreq ifr;
61cc808594SShuo Chen  int fd, err;
62cc808594SShuo Chen
63cc808594SShuo Chen  if ((fd = open("/dev/net/tun", O_RDWR)) < 0)
64cc808594SShuo Chen  {
65cc808594SShuo Chen    perror("open");
66cc808594SShuo Chen    return -1;
67cc808594SShuo Chen  }
68cc808594SShuo Chen
69bcb7e916SShuo Chen  bzero(&ifr, sizeof(ifr));
70cc808594SShuo Chen  ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
71cc808594SShuo Chen
72cc808594SShuo Chen  if (*dev)
73cc808594SShuo Chen  {
74cc808594SShuo Chen    strncpy(ifr.ifr_name, dev, IFNAMSIZ);
75cc808594SShuo Chen  }
76cc808594SShuo Chen
77cc808594SShuo Chen  if ((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0)
78cc808594SShuo Chen  {
79bcb7e916SShuo Chen    perror("ioctl TUNSETIFF");
80cc808594SShuo Chen    close(fd);
81cc808594SShuo Chen    return err;
82cc808594SShuo Chen  }
8361cf49ddSShuo Chen
8461cf49ddSShuo Chen  if (offload) {
8561cf49ddSShuo Chen    const uint32_t offload_flags =
8661cf49ddSShuo Chen        TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 | TUN_F_TSO_ECN;
8761cf49ddSShuo Chen    if (ioctl(fd, TUNSETOFFLOAD, offload_flags) != 0) {
8861cf49ddSShuo Chen      perror("TUNSETOFFLOAD");
8961cf49ddSShuo Chen      return -1;
9061cf49ddSShuo Chen    }
9161cf49ddSShuo Chen  }
9261cf49ddSShuo Chen
93cc808594SShuo Chen  strcpy(dev, ifr.ifr_name);
94bcb7e916SShuo Chen  if ((err = sethostaddr(dev)) < 0)
95bcb7e916SShuo Chen    return err;
96cc808594SShuo Chen
97cc808594SShuo Chen  return fd;
98cc808594SShuo Chen}
99cc808594SShuo Chen
100cc808594SShuo Chenuint16_t in_checksum(const void* buf, int len)
101cc808594SShuo Chen{
102cc808594SShuo Chen  assert(len % 2 == 0);
103cc808594SShuo Chen  const uint16_t* data = static_cast<const uint16_t*>(buf);
104cc808594SShuo Chen  int sum = 0;
105cc808594SShuo Chen  for (int i = 0; i < len; i+=2)
106cc808594SShuo Chen  {
107cc808594SShuo Chen    sum += *data++;
108cc808594SShuo Chen  }
109a4bafd74SShuo Chen  while (sum >> 16)
110a4bafd74SShuo Chen    sum = (sum & 0xFFFF) + (sum >> 16);
111cc808594SShuo Chen  assert(sum <= 0xFFFF);
112cc808594SShuo Chen  return ~sum;
113cc808594SShuo Chen}
114cc808594SShuo Chen
115cc808594SShuo Chenvoid icmp_input(int fd, const void* input, const void* payload, int len)
116cc808594SShuo Chen{
117cc808594SShuo Chen  const struct iphdr* iphdr = static_cast<const struct iphdr*>(input);
118cc808594SShuo Chen  const struct icmphdr* icmphdr = static_cast<const struct icmphdr*>(payload);
119cc808594SShuo Chen  // const int icmphdr_size = sizeof(*icmphdr);
120cc808594SShuo Chen  const int iphdr_len = iphdr->ihl*4;
121cc808594SShuo Chen
122cc808594SShuo Chen  if (icmphdr->type == ICMP_ECHO)
123cc808594SShuo Chen  {
124cc808594SShuo Chen    char source[INET_ADDRSTRLEN];
125cc808594SShuo Chen    char dest[INET_ADDRSTRLEN];
126cc808594SShuo Chen    inet_ntop(AF_INET, &iphdr->saddr, source, INET_ADDRSTRLEN);
127cc808594SShuo Chen    inet_ntop(AF_INET, &iphdr->daddr, dest, INET_ADDRSTRLEN);
128cc808594SShuo Chen    printf("%s > %s: ", source, dest);
129cc808594SShuo Chen    printf("ICMP echo request, id %d, seq %d, length %d\n",
130cc808594SShuo Chen           ntohs(icmphdr->un.echo.id),
131cc808594SShuo Chen           ntohs(icmphdr->un.echo.sequence),
132cc808594SShuo Chen           len - iphdr_len);
133cc808594SShuo Chen
134cc808594SShuo Chen    union
135cc808594SShuo Chen    {
136cc808594SShuo Chen      unsigned char output[ETH_FRAME_LEN];
137cc808594SShuo Chen      struct
138cc808594SShuo Chen      {
139cc808594SShuo Chen        struct iphdr iphdr;
140cc808594SShuo Chen        struct icmphdr icmphdr;
141cc808594SShuo Chen      } out;
142cc808594SShuo Chen    };
143cc808594SShuo Chen
144cc808594SShuo Chen    memcpy(output, input, len);
145cc808594SShuo Chen    out.icmphdr.type = ICMP_ECHOREPLY;
146cc808594SShuo Chen    out.icmphdr.checksum += ICMP_ECHO; // FIXME: not portable
147cc808594SShuo Chen    std::swap(out.iphdr.saddr, out.iphdr.daddr);
148cc808594SShuo Chen    write(fd, output, len);
149cc808594SShuo Chen  }
150cc808594SShuo Chen}
151cc808594SShuo Chen
152