Skip to content

Instantly share code, notes, and snippets.

@ytakano
Last active August 29, 2015 14:07
Show Gist options
  • Select an option

  • Save ytakano/55f78e1b335646457936 to your computer and use it in GitHub Desktop.

Select an option

Save ytakano/55f78e1b335646457936 to your computer and use it in GitHub Desktop.
TCP Session Generator
#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