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