1bf7dd643SShuo Chen#include "faketcp.h" 2bf7dd643SShuo Chen 3bf7dd643SShuo Chen#include <stdio.h> 4bf7dd643SShuo Chen#include <stdlib.h> 5bf7dd643SShuo Chen#include <string.h> 6bf7dd643SShuo Chen#include <unistd.h> 7bf7dd643SShuo Chen#include <netinet/ip.h> 8bf7dd643SShuo Chen#include <netinet/tcp.h> 9bf7dd643SShuo Chen#include <linux/if_ether.h> 10bf7dd643SShuo Chen 11bf7dd643SShuo Chenvoid tcp_input(int fd, const void* input, const void* payload, int tot_len) 12bf7dd643SShuo Chen{ 13bf7dd643SShuo Chen const struct iphdr* iphdr = static_cast<const struct iphdr*>(input); 14bf7dd643SShuo Chen const struct tcphdr* tcphdr = static_cast<const struct tcphdr*>(payload); 15bf7dd643SShuo Chen const int iphdr_len = iphdr->ihl*4; 16bf7dd643SShuo Chen const int tcp_seg_len = tot_len - iphdr_len; 17bf7dd643SShuo Chen const int tcphdr_size = sizeof(*tcphdr); 18bf7dd643SShuo Chen if (tcp_seg_len >= tcphdr_size 19bf7dd643SShuo Chen && tcp_seg_len >= tcphdr->doff*4) 20bf7dd643SShuo Chen { 21bf7dd643SShuo Chen const int tcphdr_len = tcphdr->doff*4; 22bf7dd643SShuo Chen const int payload_len = tot_len - iphdr_len - tcphdr_len; 23bf7dd643SShuo Chen 24bf7dd643SShuo Chen char source[INET_ADDRSTRLEN]; 25bf7dd643SShuo Chen char dest[INET_ADDRSTRLEN]; 26bf7dd643SShuo Chen inet_ntop(AF_INET, &iphdr->saddr, source, INET_ADDRSTRLEN); 27bf7dd643SShuo Chen inet_ntop(AF_INET, &iphdr->daddr, dest, INET_ADDRSTRLEN); 28bf7dd643SShuo Chen printf("IP %s.%d > %s.%d: ", 29bf7dd643SShuo Chen source, ntohs(tcphdr->source), dest, ntohs(tcphdr->dest)); 3061cf49ddSShuo Chen printf("Flags [%c], seq %u, win %d, length %d%s\n", 31bf7dd643SShuo Chen tcphdr->syn ? 'S' : (tcphdr->fin ? 'F' : '.'), 32bf7dd643SShuo Chen ntohl(tcphdr->seq), 33bf7dd643SShuo Chen ntohs(tcphdr->window), 3461cf49ddSShuo Chen payload_len, 3561cf49ddSShuo Chen tcphdr_len > sizeof(struct tcphdr) ? " <>" : ""); 36bf7dd643SShuo Chen 37bf7dd643SShuo Chen union 38bf7dd643SShuo Chen { 39bf7dd643SShuo Chen unsigned char output[ETH_FRAME_LEN]; 40bf7dd643SShuo Chen struct 41bf7dd643SShuo Chen { 42bf7dd643SShuo Chen struct iphdr iphdr; 43bf7dd643SShuo Chen struct tcphdr tcphdr; 44bf7dd643SShuo Chen } out; 45bf7dd643SShuo Chen }; 46bf7dd643SShuo Chen 4761cf49ddSShuo Chen static_assert(sizeof(out) == sizeof(struct iphdr) + sizeof(struct tcphdr), ""); 48bf7dd643SShuo Chen int output_len = sizeof(out); 49bf7dd643SShuo Chen bzero(&out, output_len + 4); 50bf7dd643SShuo Chen memcpy(output, input, sizeof(struct iphdr)); 51bf7dd643SShuo Chen 52bf7dd643SShuo Chen out.tcphdr.source = tcphdr->dest; 53bf7dd643SShuo Chen out.tcphdr.dest = tcphdr->source; 54bf7dd643SShuo Chen out.tcphdr.doff = sizeof(struct tcphdr) / 4; 5561cf49ddSShuo Chen out.tcphdr.window = htons(65000); 56bf7dd643SShuo Chen 57bf7dd643SShuo Chen bool response = false; 5861cf49ddSShuo Chen const uint32_t seq = ntohl(tcphdr->seq); 5961cf49ddSShuo Chen const uint32_t isn = 123456; 60bf7dd643SShuo Chen if (tcphdr->syn) 61bf7dd643SShuo Chen { 6261cf49ddSShuo Chen out.tcphdr.seq = htonl(isn); 6361cf49ddSShuo Chen out.tcphdr.ack_seq = htonl(seq+1); 64bf7dd643SShuo Chen out.tcphdr.syn = 1; 65bf7dd643SShuo Chen out.tcphdr.ack = 1; 6661cf49ddSShuo Chen 6761cf49ddSShuo Chen // set mss=1000 6861cf49ddSShuo Chen unsigned char* mss = output + output_len; 6961cf49ddSShuo Chen *mss++ = 2; 7061cf49ddSShuo Chen *mss++ = 4; 7161cf49ddSShuo Chen *mss++ = 0x03; 7261cf49ddSShuo Chen *mss++ = 0xe8; // 1000 == 0x03e8 7361cf49ddSShuo Chen out.tcphdr.doff += 1; 7461cf49ddSShuo Chen output_len += 4; 7561cf49ddSShuo Chen 76bf7dd643SShuo Chen response = true; 77bf7dd643SShuo Chen } 78bf7dd643SShuo Chen else if (tcphdr->fin) 79bf7dd643SShuo Chen { 8061cf49ddSShuo Chen out.tcphdr.seq = htonl(isn+1); 8161cf49ddSShuo Chen out.tcphdr.ack_seq = htonl(seq+1); 82bf7dd643SShuo Chen out.tcphdr.fin = 1; 83bf7dd643SShuo Chen out.tcphdr.ack = 1; 84bf7dd643SShuo Chen response = true; 85bf7dd643SShuo Chen } 86bf7dd643SShuo Chen else if (payload_len > 0) 87bf7dd643SShuo Chen { 8861cf49ddSShuo Chen out.tcphdr.seq = htonl(isn+1); 8961cf49ddSShuo Chen out.tcphdr.ack_seq = htonl(seq+payload_len); 90bf7dd643SShuo Chen out.tcphdr.ack = 1; 91bf7dd643SShuo Chen response = true; 92bf7dd643SShuo Chen } 93bf7dd643SShuo Chen 9461cf49ddSShuo Chen // build IP header 9561cf49ddSShuo Chen out.iphdr.tot_len = htons(output_len); 9661cf49ddSShuo Chen std::swap(out.iphdr.saddr, out.iphdr.daddr); 9761cf49ddSShuo Chen out.iphdr.check = 0; 9861cf49ddSShuo Chen out.iphdr.check = in_checksum(output, sizeof(struct iphdr)); 9961cf49ddSShuo Chen 100bf7dd643SShuo Chen unsigned char* pseudo = output + output_len; 101bf7dd643SShuo Chen pseudo[0] = 0; 102bf7dd643SShuo Chen pseudo[1] = IPPROTO_TCP; 103bf7dd643SShuo Chen pseudo[2] = 0; 10461cf49ddSShuo Chen pseudo[3] = output_len - sizeof(struct iphdr); 10561cf49ddSShuo Chen out.tcphdr.check = in_checksum(&out.iphdr.saddr, output_len - 8); 106bf7dd643SShuo Chen if (response) 107bf7dd643SShuo Chen { 108bf7dd643SShuo Chen write(fd, output, output_len); 109bf7dd643SShuo Chen } 110bf7dd643SShuo Chen } 111bf7dd643SShuo Chen} 112bf7dd643SShuo Chen 11361cf49ddSShuo Chenint main(int argc, char* argv[]) 114bf7dd643SShuo Chen{ 115bf7dd643SShuo Chen char ifname[IFNAMSIZ] = "tun%d"; 11661cf49ddSShuo Chen bool offload = argc > 1 && strcmp(argv[1], "-K") == 0; 11761cf49ddSShuo Chen int fd = tun_alloc(ifname, offload); 118bf7dd643SShuo Chen 119bf7dd643SShuo Chen if (fd < 0) 120bf7dd643SShuo Chen { 121bf7dd643SShuo Chen fprintf(stderr, "tunnel interface allocation failed\n"); 122bf7dd643SShuo Chen exit(1); 123bf7dd643SShuo Chen } 124bf7dd643SShuo Chen 125bf7dd643SShuo Chen printf("allocted tunnel interface %s\n", ifname); 126bf7dd643SShuo Chen sleep(1); 127bf7dd643SShuo Chen 128bf7dd643SShuo Chen for (;;) 129bf7dd643SShuo Chen { 130b2fec1eaSShuo Chen union 131b2fec1eaSShuo Chen { 13261cf49ddSShuo Chen unsigned char buf[IP_MAXPACKET]; 133b2fec1eaSShuo Chen struct iphdr iphdr; 134b2fec1eaSShuo Chen }; 135b2fec1eaSShuo Chen 136b2fec1eaSShuo Chen const int iphdr_size = sizeof iphdr; 137b2fec1eaSShuo Chen 138bf7dd643SShuo Chen int nread = read(fd, buf, sizeof(buf)); 139bf7dd643SShuo Chen if (nread < 0) 140bf7dd643SShuo Chen { 141bf7dd643SShuo Chen perror("read"); 142bf7dd643SShuo Chen close(fd); 143bf7dd643SShuo Chen exit(1); 144bf7dd643SShuo Chen } 14561cf49ddSShuo Chen else if (nread == sizeof(buf)) 14661cf49ddSShuo Chen { 14761cf49ddSShuo Chen printf("possible message truncated.\n"); 14861cf49ddSShuo Chen } 149bf7dd643SShuo Chen printf("read %d bytes from tunnel interface %s.\n", nread, ifname); 150bf7dd643SShuo Chen 15161cf49ddSShuo Chen const int iphdr_len = iphdr.ihl*4; // FIXME: check nread >= sizeof iphdr before accessing iphdr.ihl. 152bf7dd643SShuo Chen if (nread >= iphdr_size 153bf7dd643SShuo Chen && iphdr.version == 4 154b2fec1eaSShuo Chen && iphdr_len >= iphdr_size 155b2fec1eaSShuo Chen && iphdr_len <= nread 156bf7dd643SShuo Chen && iphdr.tot_len == htons(nread) 157b2fec1eaSShuo Chen && in_checksum(buf, iphdr_len) == 0) 158bf7dd643SShuo Chen { 159b2fec1eaSShuo Chen const void* payload = buf + iphdr_len; 160bf7dd643SShuo Chen if (iphdr.protocol == IPPROTO_ICMP) 161bf7dd643SShuo Chen { 162bf7dd643SShuo Chen icmp_input(fd, buf, payload, nread); 163bf7dd643SShuo Chen } 164bf7dd643SShuo Chen else if (iphdr.protocol == IPPROTO_TCP) 165bf7dd643SShuo Chen { 166bf7dd643SShuo Chen tcp_input(fd, buf, payload, nread); 167bf7dd643SShuo Chen } 168bf7dd643SShuo Chen } 16961cf49ddSShuo Chen else if (iphdr.version == 4) 170bf7dd643SShuo Chen { 171bf7dd643SShuo Chen printf("bad packet\n"); 172bf7dd643SShuo Chen for (int i = 0; i < nread; ++i) 173bf7dd643SShuo Chen { 174bf7dd643SShuo Chen if (i % 4 == 0) printf("\n"); 175bf7dd643SShuo Chen printf("%02x ", buf[i]); 176bf7dd643SShuo Chen } 177bf7dd643SShuo Chen printf("\n"); 178bf7dd643SShuo Chen } 179bf7dd643SShuo Chen } 180bf7dd643SShuo Chen 181bf7dd643SShuo Chen return 0; 182bf7dd643SShuo Chen} 183