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