149f15100SShuo Chen#include "faketcp.h" 249f15100SShuo Chen 349f15100SShuo Chen#include <stdio.h> 449f15100SShuo Chen#include <stdlib.h> 549f15100SShuo Chen#include <string.h> 649f15100SShuo Chen#include <unistd.h> 749f15100SShuo Chen#include <netinet/ip.h> 849f15100SShuo Chen#include <netinet/tcp.h> 949f15100SShuo Chen#include <linux/if_ether.h> 1049f15100SShuo Chen 1149f15100SShuo Chenvoid tcp_input(int fd, const void* input, const void* ippayload, int tot_len) 1249f15100SShuo Chen{ 1349f15100SShuo Chen const struct iphdr* iphdr = static_cast<const struct iphdr*>(input); 1449f15100SShuo Chen const struct tcphdr* tcphdr = static_cast<const struct tcphdr*>(ippayload); 1549f15100SShuo Chen const int iphdr_len = iphdr->ihl*4; 1649f15100SShuo Chen const int tcp_seg_len = tot_len - iphdr_len; 1749f15100SShuo Chen const int tcphdr_size = sizeof(*tcphdr); 1849f15100SShuo Chen if (tcp_seg_len >= tcphdr_size 1949f15100SShuo Chen && tcp_seg_len >= tcphdr->doff*4) 2049f15100SShuo Chen { 2149f15100SShuo Chen const int tcphdr_len = tcphdr->doff*4; 2249f15100SShuo Chen const void* payload = ippayload + tcphdr_len; 2349f15100SShuo Chen const int payload_len = tot_len - iphdr_len - tcphdr_len; 2449f15100SShuo Chen 2549f15100SShuo Chen char source[INET_ADDRSTRLEN]; 2649f15100SShuo Chen char dest[INET_ADDRSTRLEN]; 2749f15100SShuo Chen inet_ntop(AF_INET, &iphdr->saddr, source, INET_ADDRSTRLEN); 2849f15100SShuo Chen inet_ntop(AF_INET, &iphdr->daddr, dest, INET_ADDRSTRLEN); 2949f15100SShuo Chen printf("IP %s.%d > %s.%d: ", 3049f15100SShuo Chen source, ntohs(tcphdr->source), dest, ntohs(tcphdr->dest)); 3149f15100SShuo Chen printf("Flags [%c], seq %u, win %d, length %d\n", 3249f15100SShuo Chen tcphdr->syn ? 'S' : (tcphdr->fin ? 'F' : '.'), 3349f15100SShuo Chen ntohl(tcphdr->seq), 3449f15100SShuo Chen ntohs(tcphdr->window), 3549f15100SShuo Chen payload_len); 3649f15100SShuo Chen 3749f15100SShuo Chen union 3849f15100SShuo Chen { 3949f15100SShuo Chen unsigned char output[ETH_FRAME_LEN]; 4049f15100SShuo Chen struct 4149f15100SShuo Chen { 4249f15100SShuo Chen struct iphdr iphdr; 4349f15100SShuo Chen struct tcphdr tcphdr; 4449f15100SShuo Chen } out; 4549f15100SShuo Chen }; 4649f15100SShuo Chen 4749f15100SShuo Chen assert(sizeof(out) == sizeof(struct iphdr) + sizeof(struct tcphdr)); 4849f15100SShuo Chen int output_len = sizeof(out); 4949f15100SShuo Chen bzero(&out, output_len + 4); 5049f15100SShuo Chen memcpy(output, input, sizeof(struct iphdr)); 5149f15100SShuo Chen 5249f15100SShuo Chen std::swap(out.iphdr.saddr, out.iphdr.daddr); 5349f15100SShuo Chen out.iphdr.check = 0; 5449f15100SShuo Chen 5549f15100SShuo Chen out.tcphdr.source = tcphdr->dest; 5649f15100SShuo Chen out.tcphdr.dest = tcphdr->source; 5749f15100SShuo Chen out.tcphdr.doff = sizeof(struct tcphdr) / 4; 5849f15100SShuo Chen out.tcphdr.window = htons(5000); 5949f15100SShuo Chen 6049f15100SShuo Chen bool response = false; 612c431f66SShuo Chen const uint32_t seq = ntohl(tcphdr->seq); 6249f15100SShuo Chen if (tcphdr->syn) 6349f15100SShuo Chen { 642c431f66SShuo Chen out.tcphdr.seq = htonl(seq); 652c431f66SShuo Chen out.tcphdr.ack_seq = htonl(seq+1); 6649f15100SShuo Chen out.tcphdr.syn = 1; 6749f15100SShuo Chen out.tcphdr.ack = 1; 6849f15100SShuo Chen response = true; 6949f15100SShuo Chen } 7049f15100SShuo Chen else if (tcphdr->fin) 7149f15100SShuo Chen { 722c431f66SShuo Chen out.tcphdr.seq = htonl(seq); 732c431f66SShuo Chen out.tcphdr.ack_seq = htonl(seq+1); 7449f15100SShuo Chen out.tcphdr.fin = 1; 7549f15100SShuo Chen out.tcphdr.ack = 1; 7649f15100SShuo Chen response = true; 7749f15100SShuo Chen } 7849f15100SShuo Chen else if (payload_len > 0) 7949f15100SShuo Chen { 802c431f66SShuo Chen out.tcphdr.seq = htonl(seq); 812c431f66SShuo Chen out.tcphdr.ack_seq = htonl(seq+payload_len); 8249f15100SShuo Chen out.tcphdr.psh = 1; 8349f15100SShuo Chen out.tcphdr.ack = 1; 8449f15100SShuo Chen assert(output + output_len + payload_len < output + sizeof(output)); 8549f15100SShuo Chen memcpy(output + output_len, payload, payload_len); 8649f15100SShuo Chen output_len += payload_len; 8749f15100SShuo Chen response = true; 8849f15100SShuo Chen } 8949f15100SShuo Chen 9049f15100SShuo Chen out.iphdr.tot_len = htons(output_len); 9149f15100SShuo Chen out.iphdr.check = in_checksum(output, sizeof(struct iphdr)); 9249f15100SShuo Chen 9349f15100SShuo Chen unsigned char* pseudo = output + output_len; 9449f15100SShuo Chen if (payload_len % 2 == 1) 9549f15100SShuo Chen { 9649f15100SShuo Chen *pseudo = 0; 9749f15100SShuo Chen ++pseudo; 9849f15100SShuo Chen } 9949f15100SShuo Chen unsigned int len = sizeof(struct tcphdr)+payload_len; 10049f15100SShuo Chen pseudo[0] = 0; 10149f15100SShuo Chen pseudo[1] = IPPROTO_TCP; 10249f15100SShuo Chen pseudo[2] = len / 256; 10349f15100SShuo Chen pseudo[3] = len % 256; 10449f15100SShuo Chen out.tcphdr.check = in_checksum(&out.iphdr.saddr, len + 12 + (payload_len % 2)); 10549f15100SShuo Chen if (response) 10649f15100SShuo Chen { 10749f15100SShuo Chen write(fd, output, output_len); 10849f15100SShuo Chen } 10949f15100SShuo Chen } 11049f15100SShuo Chen} 11149f15100SShuo Chen 11249f15100SShuo Chenint main() 11349f15100SShuo Chen{ 11449f15100SShuo Chen char ifname[IFNAMSIZ] = "tun%d"; 11549f15100SShuo Chen int fd = tun_alloc(ifname); 11649f15100SShuo Chen 11749f15100SShuo Chen if (fd < 0) 11849f15100SShuo Chen { 11949f15100SShuo Chen fprintf(stderr, "tunnel interface allocation failed\n"); 12049f15100SShuo Chen exit(1); 12149f15100SShuo Chen } 12249f15100SShuo Chen 12349f15100SShuo Chen printf("allocted tunnel interface %s\n", ifname); 12449f15100SShuo Chen sleep(1); 12549f15100SShuo Chen 12649f15100SShuo Chen for (;;) 12749f15100SShuo Chen { 12849f15100SShuo Chen union 12949f15100SShuo Chen { 13049f15100SShuo Chen unsigned char buf[ETH_FRAME_LEN]; 13149f15100SShuo Chen struct iphdr iphdr; 13249f15100SShuo Chen }; 13349f15100SShuo Chen 13449f15100SShuo Chen const int iphdr_size = sizeof iphdr; 13549f15100SShuo Chen 13649f15100SShuo Chen int nread = read(fd, buf, sizeof(buf)); 13749f15100SShuo Chen if (nread < 0) 13849f15100SShuo Chen { 13949f15100SShuo Chen perror("read"); 14049f15100SShuo Chen close(fd); 14149f15100SShuo Chen exit(1); 14249f15100SShuo Chen } 14349f15100SShuo Chen printf("read %d bytes from tunnel interface %s.\n", nread, ifname); 14449f15100SShuo Chen 14549f15100SShuo Chen const int iphdr_len = iphdr.ihl*4; 14649f15100SShuo Chen if (nread >= iphdr_size 14749f15100SShuo Chen && iphdr.version == 4 14849f15100SShuo Chen && iphdr_len >= iphdr_size 14949f15100SShuo Chen && iphdr_len <= nread 15049f15100SShuo Chen && iphdr.tot_len == htons(nread) 15149f15100SShuo Chen && in_checksum(buf, iphdr_len) == 0) 15249f15100SShuo Chen { 15349f15100SShuo Chen const void* payload = buf + iphdr_len; 15449f15100SShuo Chen if (iphdr.protocol == IPPROTO_ICMP) 15549f15100SShuo Chen { 15649f15100SShuo Chen icmp_input(fd, buf, payload, nread); 15749f15100SShuo Chen } 15849f15100SShuo Chen else if (iphdr.protocol == IPPROTO_TCP) 15949f15100SShuo Chen { 16049f15100SShuo Chen tcp_input(fd, buf, payload, nread); 16149f15100SShuo Chen } 16249f15100SShuo Chen } 16349f15100SShuo Chen else 16449f15100SShuo Chen { 16549f15100SShuo Chen printf("bad packet\n"); 16649f15100SShuo Chen for (int i = 0; i < nread; ++i) 16749f15100SShuo Chen { 16849f15100SShuo Chen if (i % 4 == 0) printf("\n"); 16949f15100SShuo Chen printf("%02x ", buf[i]); 17049f15100SShuo Chen } 17149f15100SShuo Chen printf("\n"); 17249f15100SShuo Chen } 17349f15100SShuo Chen } 17449f15100SShuo Chen 17549f15100SShuo Chen return 0; 17649f15100SShuo Chen} 177