1#include "faketcp.h" 2 3#include <stdio.h> 4#include <stdlib.h> 5#include <string.h> 6#include <unistd.h> 7#include <netinet/ip.h> 8#include <netinet/tcp.h> 9#include <linux/if_ether.h> 10 11void tcp_input(int fd, const void* input, const void* payload, int tot_len) 12{ 13 const struct iphdr* iphdr = static_cast<const struct iphdr*>(input); 14 const struct tcphdr* tcphdr = static_cast<const struct tcphdr*>(payload); 15 const int iphdr_len = iphdr->ihl*4; 16 const int tcp_seg_len = tot_len - iphdr_len; 17 const int tcphdr_size = sizeof(*tcphdr); 18 if (tcp_seg_len >= tcphdr_size 19 && tcp_seg_len >= tcphdr->doff*4) 20 { 21 const int tcphdr_len = tcphdr->doff*4; 22 23 if (tcphdr->syn) 24 { 25 char source[INET_ADDRSTRLEN]; 26 char dest[INET_ADDRSTRLEN]; 27 inet_ntop(AF_INET, &iphdr->saddr, source, INET_ADDRSTRLEN); 28 inet_ntop(AF_INET, &iphdr->daddr, dest, INET_ADDRSTRLEN); 29 printf("IP %s.%d > %s.%d: ", 30 source, ntohs(tcphdr->source), dest, ntohs(tcphdr->dest)); 31 printf("Flags [S], seq %u, win %d, length %d\n", 32 ntohl(tcphdr->seq), 33 ntohs(tcphdr->window), 34 tot_len - iphdr_len - tcphdr_len); 35 36 union 37 { 38 unsigned char output[ETH_FRAME_LEN]; 39 struct 40 { 41 struct iphdr iphdr; 42 struct tcphdr tcphdr; 43 } out; 44 }; 45 46 assert(sizeof(out) == sizeof(struct iphdr) + sizeof(struct tcphdr)); 47 int output_len = sizeof(out); 48 bzero(&out, output_len + 4); 49 memcpy(output, input, sizeof(struct iphdr)); 50 51 out.iphdr.tot_len = htons(output_len); 52 std::swap(out.iphdr.saddr, out.iphdr.daddr); 53 out.iphdr.check = 0; 54 out.iphdr.check = in_checksum(output, sizeof(struct iphdr)); 55 out.tcphdr.source = tcphdr->dest; 56 out.tcphdr.dest = tcphdr->source; 57 out.tcphdr.seq = 0; 58 out.tcphdr.ack_seq = htonl(ntohl(tcphdr->seq)+1); 59 out.tcphdr.doff = sizeof(struct tcphdr) / 4; 60 out.tcphdr.ack = 1; 61 out.tcphdr.rst = 1; 62 out.tcphdr.window = 0; 63 unsigned char* pseudo = output + output_len; 64 pseudo[0] = 0; 65 pseudo[1] = IPPROTO_TCP; 66 pseudo[2] = 0; 67 pseudo[3] = sizeof(struct tcphdr); 68 out.tcphdr.check = in_checksum(&out.iphdr.saddr, sizeof(struct tcphdr)+12); 69 write(fd, output, output_len); 70 } 71 } 72} 73 74int main() 75{ 76 char ifname[IFNAMSIZ] = "tun%d"; 77 int fd = tun_alloc(ifname); 78 79 if (fd < 0) 80 { 81 fprintf(stderr, "tunnel interface allocation failed\n"); 82 exit(1); 83 } 84 85 printf("allocted tunnel interface %s\n", ifname); 86 sleep(1); 87 88 for (;;) 89 { 90 union 91 { 92 unsigned char buf[ETH_FRAME_LEN]; 93 struct iphdr iphdr; 94 }; 95 96 const int iphdr_size = sizeof iphdr; 97 98 int nread = read(fd, buf, sizeof(buf)); 99 if (nread < 0) 100 { 101 perror("read"); 102 close(fd); 103 exit(1); 104 } 105 printf("read %d bytes from tunnel interface %s.\n", nread, ifname); 106 107 const int iphdr_len = iphdr.ihl*4; 108 if (nread >= iphdr_size 109 && iphdr.version == 4 110 && iphdr_len >= iphdr_size 111 && iphdr_len <= nread 112 && iphdr.tot_len == htons(nread) 113 && in_checksum(buf, iphdr_len) == 0) 114 { 115 const void* payload = buf + iphdr_len; 116 if (iphdr.protocol == IPPROTO_ICMP) 117 { 118 icmp_input(fd, buf, payload, nread); 119 } 120 else if (iphdr.protocol == IPPROTO_TCP) 121 { 122 tcp_input(fd, buf, payload, nread); 123 } 124 } 125 else 126 { 127 printf("bad packet\n"); 128 for (int i = 0; i < nread; ++i) 129 { 130 if (i % 4 == 0) printf("\n"); 131 printf("%02x ", buf[i]); 132 } 133 printf("\n"); 134 } 135 } 136 137 return 0; 138} 139