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