faketcp.cc revision bcb7e916
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
58bcb7e916SShuo Chen
59bcb7e916SShuo Chenint tun_alloc(char dev[IFNAMSIZ])
60cc808594SShuo Chen{
61cc808594SShuo Chen  struct ifreq ifr;
62cc808594SShuo Chen  int fd, err;
63cc808594SShuo Chen
64cc808594SShuo Chen  if ((fd = open("/dev/net/tun", O_RDWR)) < 0)
65cc808594SShuo Chen  {
66cc808594SShuo Chen    perror("open");
67cc808594SShuo Chen    return -1;
68cc808594SShuo Chen  }
69cc808594SShuo Chen
70bcb7e916SShuo Chen  bzero(&ifr, sizeof(ifr));
71cc808594SShuo Chen  ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
72cc808594SShuo Chen
73cc808594SShuo Chen  if (*dev)
74cc808594SShuo Chen  {
75cc808594SShuo Chen    strncpy(ifr.ifr_name, dev, IFNAMSIZ);
76cc808594SShuo Chen  }
77cc808594SShuo Chen
78cc808594SShuo Chen  if ((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0)
79cc808594SShuo Chen  {
80bcb7e916SShuo Chen    perror("ioctl TUNSETIFF");
81cc808594SShuo Chen    close(fd);
82cc808594SShuo Chen    return err;
83cc808594SShuo Chen  }
84cc808594SShuo Chen  strcpy(dev, ifr.ifr_name);
85bcb7e916SShuo Chen  if ((err = sethostaddr(dev)) < 0)
86bcb7e916SShuo Chen    return err;
87cc808594SShuo Chen
88cc808594SShuo Chen  return fd;
89cc808594SShuo Chen}
90cc808594SShuo Chen
91cc808594SShuo Chenuint16_t in_checksum(const void* buf, int len)
92cc808594SShuo Chen{
93cc808594SShuo Chen  assert(len % 2 == 0);
94cc808594SShuo Chen  const uint16_t* data = static_cast<const uint16_t*>(buf);
95cc808594SShuo Chen  int sum = 0;
96cc808594SShuo Chen  for (int i = 0; i < len; i+=2)
97cc808594SShuo Chen  {
98cc808594SShuo Chen    sum += *data++;
99cc808594SShuo Chen  }
100a4bafd74SShuo Chen  while (sum >> 16)
101a4bafd74SShuo Chen    sum = (sum & 0xFFFF) + (sum >> 16);
102cc808594SShuo Chen  assert(sum <= 0xFFFF);
103cc808594SShuo Chen  return ~sum;
104cc808594SShuo Chen}
105cc808594SShuo Chen
106cc808594SShuo Chenvoid icmp_input(int fd, const void* input, const void* payload, int len)
107cc808594SShuo Chen{
108cc808594SShuo Chen  const struct iphdr* iphdr = static_cast<const struct iphdr*>(input);
109cc808594SShuo Chen  const struct icmphdr* icmphdr = static_cast<const struct icmphdr*>(payload);
110cc808594SShuo Chen  // const int icmphdr_size = sizeof(*icmphdr);
111cc808594SShuo Chen  const int iphdr_len = iphdr->ihl*4;
112cc808594SShuo Chen
113cc808594SShuo Chen  if (icmphdr->type == ICMP_ECHO)
114cc808594SShuo Chen  {
115cc808594SShuo Chen    char source[INET_ADDRSTRLEN];
116cc808594SShuo Chen    char dest[INET_ADDRSTRLEN];
117cc808594SShuo Chen    inet_ntop(AF_INET, &iphdr->saddr, source, INET_ADDRSTRLEN);
118cc808594SShuo Chen    inet_ntop(AF_INET, &iphdr->daddr, dest, INET_ADDRSTRLEN);
119cc808594SShuo Chen    printf("%s > %s: ", source, dest);
120cc808594SShuo Chen    printf("ICMP echo request, id %d, seq %d, length %d\n",
121cc808594SShuo Chen           ntohs(icmphdr->un.echo.id),
122cc808594SShuo Chen           ntohs(icmphdr->un.echo.sequence),
123cc808594SShuo Chen           len - iphdr_len);
124cc808594SShuo Chen
125cc808594SShuo Chen    union
126cc808594SShuo Chen    {
127cc808594SShuo Chen      unsigned char output[ETH_FRAME_LEN];
128cc808594SShuo Chen      struct
129cc808594SShuo Chen      {
130cc808594SShuo Chen        struct iphdr iphdr;
131cc808594SShuo Chen        struct icmphdr icmphdr;
132cc808594SShuo Chen      } out;
133cc808594SShuo Chen    };
134cc808594SShuo Chen
135cc808594SShuo Chen    memcpy(output, input, len);
136cc808594SShuo Chen    out.icmphdr.type = ICMP_ECHOREPLY;
137cc808594SShuo Chen    out.icmphdr.checksum += ICMP_ECHO; // FIXME: not portable
138cc808594SShuo Chen    std::swap(out.iphdr.saddr, out.iphdr.daddr);
139cc808594SShuo Chen    write(fd, output, len);
140cc808594SShuo Chen  }
141cc808594SShuo Chen}
142cc808594SShuo Chen
143