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, bool passive) 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 const int payload_len = tot_len - iphdr_len - tcphdr_len; 23 24 char source[INET_ADDRSTRLEN]; 25 char dest[INET_ADDRSTRLEN]; 26 inet_ntop(AF_INET, &iphdr->saddr, source, INET_ADDRSTRLEN); 27 inet_ntop(AF_INET, &iphdr->daddr, dest, INET_ADDRSTRLEN); 28 printf("IP %s.%d > %s.%d: ", 29 source, ntohs(tcphdr->source), dest, ntohs(tcphdr->dest)); 30 printf("Flags [%c], seq %u, win %d, length %d\n", 31 tcphdr->syn ? 'S' : (tcphdr->fin ? 'F' : '.'), 32 ntohl(tcphdr->seq), 33 ntohs(tcphdr->window), 34 payload_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 56 out.tcphdr.source = tcphdr->dest; 57 out.tcphdr.dest = tcphdr->source; 58 out.tcphdr.doff = sizeof(struct tcphdr) / 4; 59 out.tcphdr.window = htons(5000); 60 61 bool response = false; 62 if (tcphdr->syn) 63 { 64 out.tcphdr.seq = htonl(passive ? 123456 : 123457); 65 out.tcphdr.ack_seq = htonl(ntohl(tcphdr->seq)+1); 66 if (passive) 67 { 68 out.tcphdr.syn = 1; 69 } 70 out.tcphdr.ack = 1; 71 response = true; 72 } 73 else if (tcphdr->fin) 74 { 75 out.tcphdr.seq = htonl(123457); 76 out.tcphdr.ack_seq = htonl(ntohl(tcphdr->seq)+1); 77 out.tcphdr.fin = 1; 78 out.tcphdr.ack = 1; 79 response = true; 80 } 81 else if (payload_len > 0) 82 { 83 out.tcphdr.seq = htonl(123457); 84 out.tcphdr.ack_seq = htonl(ntohl(tcphdr->seq)+payload_len); 85 out.tcphdr.ack = 1; 86 response = true; 87 } 88 89 unsigned char* pseudo = output + output_len; 90 pseudo[0] = 0; 91 pseudo[1] = IPPROTO_TCP; 92 pseudo[2] = 0; 93 pseudo[3] = sizeof(struct tcphdr); 94 out.tcphdr.check = in_checksum(&out.iphdr.saddr, sizeof(struct tcphdr)+12); 95 if (response) 96 { 97 write(fd, output, output_len); 98 } 99 } 100} 101 102 103bool connect_one(int fd, uint32_t daddr, int dport, uint32_t saddr, int sport) 104{ 105 { 106 union 107 { 108 unsigned char output[ETH_FRAME_LEN]; 109 struct 110 { 111 struct iphdr iphdr; 112 struct tcphdr tcphdr; 113 } out; 114 }; 115 116 bzero(&out, (sizeof out)+4); 117 118 out.iphdr.version = IPVERSION; 119 out.iphdr.ihl = sizeof(out.iphdr)/4; 120 out.iphdr.tos = 0; 121 out.iphdr.tot_len = htons(sizeof(out)); 122 out.iphdr.id = 55564; 123 out.iphdr.frag_off |= htons(IP_DF); 124 out.iphdr.ttl = IPDEFTTL; 125 out.iphdr.protocol = IPPROTO_TCP; 126 out.iphdr.saddr = saddr; 127 out.iphdr.daddr = daddr; 128 out.iphdr.check = in_checksum(output, sizeof(struct iphdr)); 129 130 out.tcphdr.source = sport; 131 out.tcphdr.dest = dport; 132 out.tcphdr.seq = htonl(123456); 133 out.tcphdr.ack_seq = 0; 134 out.tcphdr.doff = sizeof(out.tcphdr)/4; 135 out.tcphdr.syn = 1; 136 out.tcphdr.window = htons(4096); 137 138 unsigned char* pseudo = output + sizeof out; 139 pseudo[0] = 0; 140 pseudo[1] = IPPROTO_TCP; 141 pseudo[2] = 0; 142 pseudo[3] = sizeof(struct tcphdr); 143 out.tcphdr.check = in_checksum(&out.iphdr.saddr, sizeof(struct tcphdr)+12); 144 145 write(fd, output, sizeof out); 146 } 147 148 union 149 { 150 unsigned char buf[ETH_FRAME_LEN]; 151 struct iphdr iphdr; 152 }; 153 154 const int iphdr_size = sizeof iphdr; 155 156 int nread = read(fd, buf, sizeof(buf)); 157 if (nread < 0) 158 { 159 perror("read"); 160 close(fd); 161 exit(1); 162 } 163 // printf("read %d bytes from tunnel interface %s.\n", nread, ifname); 164 165 if (nread >= iphdr_size 166 && iphdr.version == 4 167 && iphdr.ihl*4 >= iphdr_size 168 && iphdr.ihl*4 <= nread 169 && iphdr.tot_len == htons(nread) 170 && in_checksum(buf, iphdr.ihl*4) == 0) 171 { 172 const void* payload = buf + iphdr.ihl*4; 173 if (iphdr.protocol == IPPROTO_ICMP) 174 { 175 icmp_input(fd, buf, payload, nread); 176 } 177 else if (iphdr.protocol == IPPROTO_TCP) 178 { 179 tcp_input(fd, buf, payload, nread, false); 180 } 181 } 182 183 return true; 184} 185 186void connect_many(int fd, const char* ipstr, int port, int count) 187{ 188 uint32_t destip; 189 inet_pton(AF_INET, ipstr, &destip); 190 191 uint32_t srcip = ntohl(destip)+1; 192 int srcport = 1024; 193 194 for (int i = 0; i < count; ++i) 195 { 196 connect_one(fd, destip, htons(port), htonl(srcip), htons(srcport)); 197 srcport++; 198 if (srcport > 0xFFFF) 199 { 200 srcport = 1024; 201 srcip++; 202 } 203 } 204} 205 206void usage() 207{ 208} 209 210int main(int argc, char* argv[]) 211{ 212 if (argc < 4) 213 { 214 usage(); 215 return 0; 216 } 217 218 char ifname[IFNAMSIZ] = "tun%d"; 219 int fd = tun_alloc(ifname); 220 221 if (fd < 0) 222 { 223 fprintf(stderr, "tunnel interface allocation failed\n"); 224 exit(1); 225 } 226 227 const char* ip = argv[1]; 228 int port = atoi(argv[2]); 229 int count = atoi(argv[3]); 230 printf("allocted tunnel interface %s\n", ifname); 231 printf("press enter key to start connecting %s:%d\n", ip, port); 232 getchar(); 233 234 connect_many(fd, ip, port, count); 235 236 for (;;) 237 { 238 union 239 { 240 unsigned char buf[ETH_FRAME_LEN]; 241 struct iphdr iphdr; 242 }; 243 244 const int iphdr_size = sizeof iphdr; 245 246 int nread = read(fd, buf, sizeof(buf)); 247 if (nread < 0) 248 { 249 perror("read"); 250 close(fd); 251 exit(1); 252 } 253 printf("read %d bytes from tunnel interface %s.\n", nread, ifname); 254 255 const int iphdr_len = iphdr.ihl*4; 256 if (nread >= iphdr_size 257 && iphdr.version == 4 258 && iphdr_len >= iphdr_size 259 && iphdr_len <= nread 260 && iphdr.tot_len == htons(nread) 261 && in_checksum(buf, iphdr_len) == 0) 262 { 263 const void* payload = buf + iphdr_len; 264 if (iphdr.protocol == IPPROTO_ICMP) 265 { 266 icmp_input(fd, buf, payload, nread); 267 } 268 else if (iphdr.protocol == IPPROTO_TCP) 269 { 270 tcp_input(fd, buf, payload, nread, true); 271 } 272 } 273 else 274 { 275 printf("bad packet\n"); 276 for (int i = 0; i < nread; ++i) 277 { 278 if (i % 4 == 0) printf("\n"); 279 printf("%02x ", buf[i]); 280 } 281 printf("\n"); 282 } 283 } 284 285 return 0; 286} 287