icmpecho.cc revision b9400f6c
1b9400f6cSShuo Chen#include <algorithm>
2b9400f6cSShuo Chen
3b9400f6cSShuo Chen#include <stdio.h>
4b9400f6cSShuo Chen#include <string.h>
5b9400f6cSShuo Chen#include <fcntl.h>
6b9400f6cSShuo Chen#include <sys/ioctl.h>
7b9400f6cSShuo Chen#include <stdlib.h>
8b9400f6cSShuo Chen#include <unistd.h>
9b9400f6cSShuo Chen#include <arpa/inet.h>
10b9400f6cSShuo Chen#include <net/if.h>
11b9400f6cSShuo Chen#include <netinet/ip.h>
12b9400f6cSShuo Chen#include <netinet/ip_icmp.h>
13b9400f6cSShuo Chen#include <linux/if_tun.h>
14b9400f6cSShuo Chen
15b9400f6cSShuo Chen#define PACKET_SIZE 1514
16b9400f6cSShuo Chen
17b9400f6cSShuo Chenint tun_alloc(char *dev)
18b9400f6cSShuo Chen{
19b9400f6cSShuo Chen  struct ifreq ifr;
20b9400f6cSShuo Chen  int fd, err;
21b9400f6cSShuo Chen
22b9400f6cSShuo Chen  if ((fd = open("/dev/net/tun", O_RDWR)) < 0)
23b9400f6cSShuo Chen  {
24b9400f6cSShuo Chen    perror("open");
25b9400f6cSShuo Chen    return -1;
26b9400f6cSShuo Chen  }
27b9400f6cSShuo Chen
28b9400f6cSShuo Chen  memset(&ifr, 0, sizeof(ifr));
29b9400f6cSShuo Chen  ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
30b9400f6cSShuo Chen
31b9400f6cSShuo Chen  if (*dev)
32b9400f6cSShuo Chen  {
33b9400f6cSShuo Chen    strncpy(ifr.ifr_name, dev, IFNAMSIZ);
34b9400f6cSShuo Chen  }
35b9400f6cSShuo Chen
36b9400f6cSShuo Chen  if ((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0)
37b9400f6cSShuo Chen  {
38b9400f6cSShuo Chen    perror("ioctl");
39b9400f6cSShuo Chen    close(fd);
40b9400f6cSShuo Chen    return err;
41b9400f6cSShuo Chen  }
42b9400f6cSShuo Chen  strcpy(dev, ifr.ifr_name);
43b9400f6cSShuo Chen
44b9400f6cSShuo Chen  return fd;
45b9400f6cSShuo Chen}
46b9400f6cSShuo Chen
47b9400f6cSShuo Chenvoid icmp_echo(int fd, const void* input, const void* payload, int len)
48b9400f6cSShuo Chen{
49b9400f6cSShuo Chen  const struct iphdr* iphdr = static_cast<const struct iphdr*>(input);
50b9400f6cSShuo Chen  const struct icmphdr* icmphdr = static_cast<const struct icmphdr*>(payload);
51b9400f6cSShuo Chen  const int icmphdr_size = sizeof(*icmphdr);
52b9400f6cSShuo Chen
53b9400f6cSShuo Chen  if (icmphdr->type == ICMP_ECHO)
54b9400f6cSShuo Chen  {
55b9400f6cSShuo Chen    char source[INET_ADDRSTRLEN];
56b9400f6cSShuo Chen    char dest[INET_ADDRSTRLEN];
57b9400f6cSShuo Chen    inet_ntop(AF_INET, &iphdr->saddr, source, INET_ADDRSTRLEN);
58b9400f6cSShuo Chen    inet_ntop(AF_INET, &iphdr->daddr, dest, INET_ADDRSTRLEN);
59b9400f6cSShuo Chen    printf("%s > %s: ", source, dest);
60b9400f6cSShuo Chen    printf("ICMP echo request, id %d, seq %d, length %d\n",
61b9400f6cSShuo Chen           ntohs(icmphdr->un.echo.id),
62b9400f6cSShuo Chen           ntohs(icmphdr->un.echo.sequence),
63b9400f6cSShuo Chen           len - iphdr->ihl*4);
64b9400f6cSShuo Chen  }
65b9400f6cSShuo Chen
66b9400f6cSShuo Chen  union
67b9400f6cSShuo Chen  {
68b9400f6cSShuo Chen    unsigned char output[PACKET_SIZE];
69b9400f6cSShuo Chen    struct
70b9400f6cSShuo Chen    {
71b9400f6cSShuo Chen      struct iphdr iphdr;
72b9400f6cSShuo Chen      struct icmphdr icmphdr;
73b9400f6cSShuo Chen    } out;
74b9400f6cSShuo Chen  };
75b9400f6cSShuo Chen
76b9400f6cSShuo Chen  memcpy(output, input, len);
77b9400f6cSShuo Chen  out.icmphdr.type = ICMP_ECHOREPLY;
78b9400f6cSShuo Chen  out.icmphdr.checksum += ICMP_ECHO; // FIXME: not portable
79b9400f6cSShuo Chen  std::swap(out.iphdr.saddr, out.iphdr.daddr);
80b9400f6cSShuo Chen  write(fd, output, len);
81b9400f6cSShuo Chen}
82b9400f6cSShuo Chen
83b9400f6cSShuo Chenuint16_t iphdr_checksum(const void* buf, int len)
84b9400f6cSShuo Chen{
85b9400f6cSShuo Chen  const uint16_t* data = static_cast<const uint16_t*>(buf);
86b9400f6cSShuo Chen  int sum = 0;
87b9400f6cSShuo Chen  for (int i = 0; i < len; i+=2)
88b9400f6cSShuo Chen  {
89b9400f6cSShuo Chen    sum += *data++;
90b9400f6cSShuo Chen  }
91b9400f6cSShuo Chen  // while (sum >> 16)
92b9400f6cSShuo Chen  sum = (sum & 0xFFFF) + (sum >> 16);
93b9400f6cSShuo Chen  return ~sum;
94b9400f6cSShuo Chen}
95b9400f6cSShuo Chen
96b9400f6cSShuo Chenint main()
97b9400f6cSShuo Chen{
98b9400f6cSShuo Chen  union
99b9400f6cSShuo Chen  {
100b9400f6cSShuo Chen    unsigned char buf[PACKET_SIZE];
101b9400f6cSShuo Chen    struct iphdr iphdr;
102b9400f6cSShuo Chen  };
103b9400f6cSShuo Chen
104b9400f6cSShuo Chen  const int iphdr_size = sizeof iphdr;
105b9400f6cSShuo Chen
106b9400f6cSShuo Chen  char ifname[IFNAMSIZ] = "tun%d";
107b9400f6cSShuo Chen  int fd = tun_alloc(ifname);
108b9400f6cSShuo Chen
109b9400f6cSShuo Chen  if (fd < 0)
110b9400f6cSShuo Chen  {
111b9400f6cSShuo Chen    fprintf(stderr, "tunnel interface allocation failed\n");
112b9400f6cSShuo Chen    exit(1);
113b9400f6cSShuo Chen  }
114b9400f6cSShuo Chen
115b9400f6cSShuo Chen  printf("allocted tunnel interface %s\n", ifname);
116b9400f6cSShuo Chen  sleep(1);
117b9400f6cSShuo Chen
118b9400f6cSShuo Chen  for (;;)
119b9400f6cSShuo Chen  {
120b9400f6cSShuo Chen    int nread = read(fd, buf, sizeof(buf));
121b9400f6cSShuo Chen    if (nread < 0)
122b9400f6cSShuo Chen    {
123b9400f6cSShuo Chen      perror("read");
124b9400f6cSShuo Chen      close(fd);
125b9400f6cSShuo Chen      exit(1);
126b9400f6cSShuo Chen    }
127b9400f6cSShuo Chen    printf("read %d bytes from tunnel interface %s.\n", nread, ifname);
128b9400f6cSShuo Chen
129b9400f6cSShuo Chen    if (nread >= iphdr_size
130b9400f6cSShuo Chen        && iphdr.version == 4
131b9400f6cSShuo Chen        && iphdr.ihl*4 >= iphdr_size
132b9400f6cSShuo Chen        && iphdr.ihl*4 <= nread
133b9400f6cSShuo Chen        && iphdr.tot_len == htons(nread)
134b9400f6cSShuo Chen        && iphdr_checksum(buf, iphdr.ihl*4) == 0)
135b9400f6cSShuo Chen    {
136b9400f6cSShuo Chen      const void* payload = buf + iphdr.ihl*4;
137b9400f6cSShuo Chen      if (iphdr.protocol == 1)
138b9400f6cSShuo Chen      {
139b9400f6cSShuo Chen        icmp_echo(fd, buf, payload, nread);
140b9400f6cSShuo Chen      }
141b9400f6cSShuo Chen    }
142b9400f6cSShuo Chen    else
143b9400f6cSShuo Chen    {
144b9400f6cSShuo Chen      printf("bad packet\n");
145b9400f6cSShuo Chen      for (int i = 0; i < nread; ++i)
146b9400f6cSShuo Chen      {
147b9400f6cSShuo Chen        if (i % 4 == 0) printf("\n");
148b9400f6cSShuo Chen        printf("%02x ", buf[i]);
149b9400f6cSShuo Chen      }
150b9400f6cSShuo Chen      printf("\n");
151b9400f6cSShuo Chen    }
152b9400f6cSShuo Chen  }
153b9400f6cSShuo Chen
154b9400f6cSShuo Chen  return 0;
155b9400f6cSShuo Chen}
156