Last active
August 29, 2015 14:07
-
-
Save ytakano/55f78e1b335646457936 to your computer and use it in GitHub Desktop.
TCP Session Generator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <pcap.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <unistd.h> | |
| #include <math.h> | |
| #include <net/ethernet.h> | |
| #include <netinet/ip.h> | |
| #define __FAVOR_BSD | |
| #include <netinet/tcp.h> | |
| #include <unordered_map> | |
| #include <string> | |
| #include <iostream> | |
| using namespace std; | |
| extern char *optarg; | |
| extern int optind, opterr, optopt; | |
| // Ether Header: 14 bytes | |
| // IP Header: 20 bytes | |
| // TCP Header: 20 bytes | |
| char p_pkt[1540]; | |
| ether_header *p_ethdr = (ether_header*)p_pkt; | |
| ip *p_iphdr = (ip*)&p_pkt[14]; | |
| tcphdr *p_tcphdr = (tcphdr*)&p_pkt[14 + 20]; | |
| uint32_t *p_nullhdr = (uint32_t*)&p_pkt[10]; | |
| uint32_t min_addr = 0x0a010000; // 10.1.10.0 | |
| uint32_t max_addr = 0x0aff0000; // 10.255.0.0 | |
| uint16_t min_port = 10000; | |
| uint16_t max_port = 10010; | |
| uint8_t src_ether[6] = {0, 0x25, 0x90, 0xf9, 0x4a, 0xdd}; | |
| uint8_t dst_ether[6] = {0, 0x25, 0x90, 0xf9, 0x4a, 0xe7}; | |
| uint32_t src_addr; | |
| uint32_t dst_addr; | |
| uint16_t src_port; | |
| uint16_t dst_port; | |
| int limit = 10000000; | |
| int persec = 10000; // 10000 sessions per second | |
| string dev; | |
| pcap_t *handler; | |
| bool is_null = false; | |
| static inline uint16_t | |
| checksum(const uint8_t* buf, size_t size, uint32_t adjust) | |
| { | |
| uint32_t sum = 0; | |
| uint16_t element = 0; | |
| while (size>0) { | |
| element = (*buf)<<8; | |
| buf++; | |
| size--; | |
| if (size>0) { | |
| element |= *buf; | |
| buf++; | |
| size--; | |
| } | |
| sum += element; | |
| } | |
| sum += adjust; | |
| while (sum>0xFFFF) { | |
| sum = (sum>>16) + (sum&0xFFFF); | |
| } | |
| return (~sum) & 0xFFFF; | |
| } | |
| static inline void | |
| checksum_transport(struct ip* iphdr, size_t size) | |
| { | |
| uint32_t pseudoSum = 0; | |
| uint8_t protocol; | |
| uint8_t* l3_buf = (uint8_t*)iphdr; | |
| uint8_t* l4_buf = (uint8_t*)iphdr+(iphdr->ip_hl<<2); | |
| // Src Address ipv4 | |
| pseudoSum += (l3_buf[12]<<8) | l3_buf[13]; | |
| pseudoSum += (l3_buf[14]<<8) | l3_buf[15]; | |
| // Dst Address ipv4 | |
| pseudoSum += (l3_buf[16]<<8) | l3_buf[17]; | |
| pseudoSum += (l3_buf[18]<<8) | l3_buf[19]; | |
| // Protocol Number | |
| pseudoSum += protocol = iphdr->ip_p; | |
| size_t segment_size = size - (iphdr->ip_hl<<2); | |
| pseudoSum += segment_size; | |
| // protocol check !! | |
| if (protocol == IPPROTO_TCP) { | |
| //pseudoSum += (uint8_t)IPPROTO_TCP; | |
| struct tcphdr* tcphdr = (struct tcphdr*)l4_buf; | |
| tcphdr->th_sum = 0x0000; | |
| tcphdr->th_sum = htons(checksum(l4_buf, segment_size, pseudoSum)); | |
| } | |
| return; | |
| } | |
| void | |
| init_tcpkt() | |
| { | |
| memset(p_pkt, 0, sizeof(p_pkt)); | |
| p_ethdr->ether_type = htons(ETHERTYPE_IP); | |
| if (is_null) { | |
| *p_nullhdr = 2; | |
| } else { | |
| memcpy(p_ethdr->ether_dhost, dst_ether, sizeof(dst_ether)); | |
| memcpy(p_ethdr->ether_shost, src_ether, sizeof(src_ether)); | |
| } | |
| p_iphdr->ip_v = 4; | |
| p_iphdr->ip_hl = 5; | |
| p_iphdr->ip_len = htons(40); | |
| p_iphdr->ip_ttl = 8; | |
| p_iphdr->ip_p = IPPROTO_TCP; | |
| p_tcphdr->th_off = 5; | |
| p_tcphdr->th_win = 0xffff; | |
| src_addr = min_addr; | |
| dst_addr = min_addr; | |
| src_port = min_port; | |
| dst_port = min_port; | |
| } | |
| uint16_t | |
| cksum(uint16_t *buffer, int size) | |
| { | |
| uint32_t sum = 0; | |
| while (size > 1) | |
| { | |
| sum += *buffer++; | |
| size -= sizeof(uint16_t); | |
| } | |
| if(size) | |
| sum += *(uint8_t*)buffer; | |
| sum = (sum >> 16) + (sum & 0xffff); | |
| sum += (sum >> 16); | |
| return (uint16_t)(~sum); | |
| } | |
| void | |
| gen_pkt() | |
| { | |
| int i = 0; | |
| double interval = 1 / (double)persec; | |
| timeval stime; | |
| gettimeofday(&stime, NULL); | |
| for (src_addr = min_addr; src_addr < max_addr; src_addr++) { | |
| for (dst_addr = min_addr; dst_addr < max_addr; dst_addr++) { | |
| if (src_addr == dst_addr) | |
| continue; | |
| for (src_port = min_port; src_port < max_port; src_port++) { | |
| for (dst_port = min_port; dst_port < max_port; dst_port++) { | |
| int result; | |
| timeval t0, t1; | |
| gettimeofday(&t0, NULL); | |
| // generate SYN packet | |
| p_iphdr->ip_src.s_addr = htonl(src_addr); | |
| p_iphdr->ip_dst.s_addr = htonl(dst_addr); | |
| p_iphdr->ip_len = htons(40); | |
| p_iphdr->ip_sum = cksum((uint16_t*)p_iphdr, 20); | |
| p_tcphdr->th_sport = htons(src_port); | |
| p_tcphdr->th_dport = htons(dst_port); | |
| p_tcphdr->th_seq = htonl(0x10000000); | |
| p_tcphdr->th_ack = 0; | |
| p_tcphdr->th_flags = TH_SYN; | |
| checksum_transport(p_iphdr, 40); | |
| // inject 54 bytes | |
| if (is_null) { | |
| result = pcap_inject(handler, p_pkt + 10, 44); | |
| } else { | |
| result = pcap_inject(handler, p_pkt, 54); | |
| } | |
| if(result == -1){ | |
| cerr << "failed to inject packet" << endl; | |
| } | |
| // generate SYN+ACK packet | |
| p_iphdr->ip_src.s_addr = htonl(dst_addr); | |
| p_iphdr->ip_dst.s_addr = htonl(src_addr); | |
| p_iphdr->ip_len = htons(40); | |
| p_iphdr->ip_sum = 0; | |
| p_iphdr->ip_sum = cksum((uint16_t*)p_iphdr, 20); | |
| p_tcphdr->th_sport = htons(dst_port); | |
| p_tcphdr->th_dport = htons(src_port); | |
| p_tcphdr->th_seq = htonl(0x10000000); | |
| p_tcphdr->th_ack = htonl(0x10000001); | |
| p_tcphdr->th_flags = TH_SYN | TH_ACK; | |
| checksum_transport(p_iphdr, 40); | |
| // inject 54 bytes | |
| if (is_null) { | |
| result = pcap_inject(handler, p_pkt + 10, 44); | |
| } else { | |
| result = pcap_inject(handler, p_pkt, 54); | |
| } | |
| if(result == -1){ | |
| cerr << "failed to inject packet" << endl; | |
| } | |
| // generate ACK packet | |
| p_iphdr->ip_src.s_addr = htonl(src_addr); | |
| p_iphdr->ip_dst.s_addr = htonl(dst_addr); | |
| p_iphdr->ip_len = htons(40); | |
| p_iphdr->ip_sum = 0; | |
| p_iphdr->ip_sum = cksum((uint16_t*)p_iphdr, 20); | |
| p_tcphdr->th_sport = htons(src_port); | |
| p_tcphdr->th_dport = htons(dst_port); | |
| p_tcphdr->th_seq = htonl(0x10000001); | |
| p_tcphdr->th_ack = htonl(0x10000001); | |
| p_tcphdr->th_flags = TH_ACK; | |
| checksum_transport(p_iphdr, 40); | |
| // inject 54 bytes | |
| if (is_null) { | |
| result = pcap_inject(handler, p_pkt + 10, 44); | |
| } else { | |
| result = pcap_inject(handler, p_pkt, 54); | |
| } | |
| if(result == -1){ | |
| cerr << "failed to inject packet" << endl; | |
| } | |
| // generate DATA from src | |
| p_iphdr->ip_src.s_addr = htonl(src_addr); | |
| p_iphdr->ip_dst.s_addr = htonl(dst_addr); | |
| p_iphdr->ip_len = htons(1426); | |
| p_iphdr->ip_sum = 0; | |
| p_iphdr->ip_sum = cksum((uint16_t*)p_iphdr, 20); | |
| p_tcphdr->th_sport = htons(src_port); | |
| p_tcphdr->th_dport = htons(dst_port); | |
| p_tcphdr->th_seq = htonl(0x10000001); | |
| p_tcphdr->th_ack = htonl(0x10000001); | |
| p_tcphdr->th_flags = TH_ACK; | |
| checksum_transport(p_iphdr, 1426); | |
| // inject 1440 bytes | |
| if (is_null) { | |
| result = pcap_inject(handler, p_pkt + 10, 1430); | |
| } else { | |
| result = pcap_inject(handler, p_pkt, 1440); | |
| } | |
| if(result == -1){ | |
| cerr << "failed to inject packet" << endl; | |
| } | |
| // generate DATA from dst | |
| p_iphdr->ip_src.s_addr = htonl(dst_addr); | |
| p_iphdr->ip_dst.s_addr = htonl(src_addr); | |
| p_iphdr->ip_len = htons(1426); | |
| p_iphdr->ip_sum = 0; | |
| p_iphdr->ip_sum = cksum((uint16_t*)p_iphdr, 20); | |
| p_tcphdr->th_sport = htons(dst_port); | |
| p_tcphdr->th_dport = htons(src_port); | |
| p_tcphdr->th_seq = htonl(0x10000001); | |
| p_tcphdr->th_ack = htonl(0x10000001 + 1386); | |
| p_tcphdr->th_flags = TH_ACK; | |
| checksum_transport(p_iphdr, 1426); | |
| // inject 1440 bytes | |
| if (is_null) { | |
| result = pcap_inject(handler, p_pkt + 10, 1430); | |
| } else { | |
| result = pcap_inject(handler, p_pkt, 1440); | |
| } | |
| if (result == -1){ | |
| cerr << "failed to inject packet" << endl; | |
| } | |
| i++; | |
| if (i % 100000 == 0 || i >= limit) { | |
| timeval etime; | |
| double st, et; | |
| gettimeofday(&etime, NULL); | |
| st = stime.tv_sec + (double)stime.tv_usec / 1000000; | |
| et = etime.tv_sec + (double)etime.tv_usec / 1000000; | |
| cout << i << " TCP sessions were created\n" | |
| << i / (et - st) << " sessions / sec" << endl; | |
| if (i >= limit) { | |
| exit(0); | |
| } | |
| } | |
| gettimeofday(&t1, NULL); | |
| double dt0 = t0.tv_sec + (double)t0.tv_usec / 1000000; | |
| double dt1 = t1.tv_sec + (double)t1.tv_usec / 1000000; | |
| double wtime = interval - (dt1 - dt0); | |
| double sec = floor(wtime); | |
| timespec tsp; | |
| //cout << wtime << endl; | |
| tsp.tv_sec = (time_t)sec; | |
| tsp.tv_nsec = (wtime - sec) * 1000000000; | |
| nanosleep(&tsp, NULL); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| void | |
| open_pcap() | |
| { | |
| char errbuf[PCAP_ERRBUF_SIZE]; | |
| if (dev == "") { | |
| char *d = pcap_lookupdev(errbuf); | |
| if (d == NULL) { | |
| cerr << "Couldn't find default device: " << errbuf << endl; | |
| exit(1); | |
| } | |
| dev = d; | |
| } | |
| handler = pcap_create(dev.c_str(), errbuf); | |
| if (handler == NULL) { | |
| cerr << "Couldn't open device " << dev << ": " << errbuf << endl; | |
| exit(1); | |
| } | |
| pcap_set_snaplen(handler, 0); | |
| pcap_set_promisc(handler, 1); | |
| pcap_set_buffer_size(handler, 4096 * 1000); | |
| pcap_set_timeout(handler, 1000); | |
| if (pcap_activate(handler) != 0) { | |
| pcap_perror(handler, (char*)"Activate"); | |
| exit(1); | |
| } | |
| } | |
| int | |
| main(int argc, char *argv[]) | |
| { | |
| int opt; | |
| const char *optstr = "i:n:r:h"; | |
| while ((opt = getopt(argc, argv, optstr)) != -1) { | |
| switch (opt) { | |
| case 'i': | |
| dev = optarg; | |
| break; | |
| case 'n': | |
| limit = atoi(optarg); | |
| break; | |
| case 'r': | |
| persec = atoi(optarg); | |
| break; | |
| case 'h': | |
| default: | |
| cout << argv[0] << " -i [dev] -n [num session]" << endl; | |
| return 0; | |
| } | |
| } | |
| if (dev == "lo0") { | |
| is_null = true; | |
| } | |
| open_pcap(); | |
| init_tcpkt(); | |
| gen_pkt(); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment