├── README.md └── src ├── flood.c └── include └── csum.h /README.md: -------------------------------------------------------------------------------- 1 | # Packet Flooder/Generator 2 | ## Newer Packet Sequence Program (Faster) 3 | I would recommend checking out my newer Packet Sequence program [here](https://github.com/gamemann/Packet-Sequence). This newer tool takes my Packet Flooding/Generator tool to the next level by making it so you can define sequences with more features such as sourcing out as specific IP/CIDR ranges. It is still under development, but I'm making great progress and hope to implement functionality that'll allow it to operate as a network monitoring tool. 4 | 5 | This tool is also **a lot** more faster than this Packet Flooder tool because I've moved as much instructions outside of the while loop (for sending packets) as possible. With that said, I've added command line support for replacing values in the first sequence. The only thing it does not include is native IPIP support. Other than that, it is overall a better solution than this program. 6 | 7 | ## Description 8 | This is a packet flooder/generator tool made in C that supports sending TCP, UDP, IPIP, and ICMP packets. This program also supports many features including randomizing each packet's characteristics such as its source IP, port, and more. This tool is also multithreaded by using `pthreads`. My goal is to achieve the highest packets per second rate with this tool while also being able to use neat features like randomizing payload, source IPs, and more. 9 | 10 | **Note** - Please use this tool at your own risk. I am not responsible for any damage done and do not support using this tool for illegal operations such as targeted (D)DoS attacks. This tool was primarily made for pen-testing. 11 | 12 | ## Why Did I Make This? 13 | I've been learning how to mitigate (D)DoS attacks against my Anycast network and wanted to do pen-testing using different characteristics in each packet. I figured I'd make a pen-testing tool I can use to test out my (D)DoS mitigation methods on firewalls I make in the future and present (including my [XDP Firewall](https://github.com/gamemann/XDP-Firewall)). 14 | 15 | ## Compiling 16 | I use GCC to compile this program. You must add `-lpthread` at the end of the command when compiling via GCC. 17 | 18 | Here's an example: 19 | 20 | ``` 21 | git clone https://github.com/gamemann/Packet-Flooder.git 22 | cd Packet-Flooder 23 | gcc -g src/flood.c -o flood -lpthread 24 | ``` 25 | 26 | ## Usage 27 | Here's output from the `--help` flag that goes over the program's command line usage: 28 | 29 | ``` 30 | ./flood --help 31 | Usage for: ./flood: 32 | --dev -i => Interface name to bind to. 33 | --src -s => Source address (0/unset = random/spoof). 34 | --dst -d => Destination IP to send packets to. 35 | --port -p => Destination port (0/unset = random port). 36 | --sport => Source port (0/unset = random port). 37 | --internal => When set, if no source IP is specified, it will randomize the source IP from the 10.0.0.0/8 range. 38 | --interval => Interval between sending packets in micro seconds. 39 | --threads -t => Amount of threads to spawn (default is host's CPU count). 40 | --count -c => The maximum packet count allowed sent. 41 | --time => Amount of time in seconds to run tool for. 42 | --smac => Source MAC address in xx:xx:xx:xx:xx:xx format. 43 | --dmac => Destination MAC address in xx:xx:xx:xx:xx:xx format. 44 | --payload => The payload to send. Format is in hexadecimal. Example: FF FF FF FF 49. 45 | --verbose -v => Print how much data we've sent each time. 46 | --nostats => Do not track PPS and bandwidth. This may increase performance. 47 | --urg => Set the URG flag for TCP packets. 48 | --ack => Set the ACK flag for TCP packets. 49 | --psh => Set the PSH flag for TCP packets. 50 | --rst => Set the RST flag for TCP packets. 51 | --syn => Set the SYN flag for TCP packets. 52 | --fin => Set the FIN flag for TCP packets. 53 | --min => Minimum payload length. 54 | --max => Maximum payload length. 55 | --tcp => Send TCP packets. 56 | --icmp => Send ICMP packets. 57 | --icmptype => The ICMP type to send when --icmp is specified. 58 | --icmpcode => The ICMP code to send when --icmp is specified. 59 | --ipip => Add outer IP header in IPIP format. 60 | --ipipsrc => When IPIP is specified, use this as outer IP header's source address. 61 | --ipipdst => When IPIP is specified, use this as outer IP header's destination address. 62 | --nocsum => Do not calculate the IP header's checksum. Useful for checksum offloading on the hardware which'll result in better performance. 63 | --nocsum4 => Do not calculate the layer 4's checksum (e.g. TCP/UDP). It will leave the checksum field as 0 in the headers. 64 | --minttl => The minimum TTL (Time-To-Live) range for a packet. 65 | --maxttl => The maximum TTL (Time-To-Live) range for a packet. 66 | --tos => The TOS (Type Of Service) to set on each packet. 67 | --help -h => Show help menu information. 68 | ``` 69 | 70 | Example: 71 | 72 | ``` 73 | ./flood --dev ens18 --dst 10.50.0.4 --port 80 -t 1 --interval 100000 --tcp --min 1200 --max 1200 -v 74 | ``` 75 | 76 | ## Credits 77 | * [Christian Deacon](https://www.linkedin.com/in/christian-deacon-902042186/) - Created program. -------------------------------------------------------------------------------- /src/flood.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "include/csum.h" 26 | 27 | #define MAX_PCKT_LENGTH 0xFFFF 28 | 29 | // Global variables. 30 | uint8_t cont = 1; 31 | time_t startTime; 32 | volatile uint64_t pcktCount = 0; 33 | volatile uint64_t totalData = 0; 34 | 35 | // Thread structure. 36 | struct pthread_info 37 | { 38 | char *interface; 39 | char *sIP; 40 | char *dIP; 41 | uint16_t port; 42 | uint16_t sport; 43 | uint64_t interval; 44 | uint16_t min; 45 | uint16_t max; 46 | uint64_t pcktCountMax; 47 | time_t seconds; 48 | uint8_t payload[MAX_PCKT_LENGTH]; 49 | char *payloadStr; 50 | uint16_t payloadLength; 51 | int tcp; 52 | int icmp; 53 | int verbose; 54 | int internal; 55 | int nostats; 56 | int tcp_urg; 57 | int tcp_ack; 58 | int tcp_psh; 59 | int tcp_rst; 60 | int tcp_syn; 61 | int tcp_fin; 62 | int icmp_type; 63 | int icmp_code; 64 | int ipip; 65 | int help; 66 | char *ipipsrc; 67 | char *ipipdst; 68 | uint8_t sMAC[ETH_ALEN]; 69 | uint8_t dMAC[ETH_ALEN]; 70 | uint16_t threads; 71 | int nocsum; 72 | int nocsum4; 73 | uint8_t minTTL; 74 | uint8_t maxTTL; 75 | uint8_t tos; 76 | 77 | time_t startingTime; 78 | uint16_t id; 79 | } g_info; 80 | 81 | void signalHndl(int tmp) 82 | { 83 | cont = 0; 84 | } 85 | 86 | void GetGatewayMAC(uint8_t *MAC) 87 | { 88 | char cmd[] = "ip neigh | grep \"$(ip -4 route list 0/0|cut -d' ' -f3) \"|cut -d' ' -f5|tr '[a-f]' '[A-F]'"; 89 | 90 | FILE *fp = popen(cmd, "r"); 91 | 92 | if (fp != NULL) 93 | { 94 | char line[18]; 95 | 96 | if (fgets(line, sizeof(line), fp) != NULL) 97 | { 98 | sscanf(line, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &MAC[0], &MAC[1], &MAC[2], &MAC[3], &MAC[4], &MAC[5]); 99 | } 100 | 101 | pclose(fp); 102 | } 103 | } 104 | 105 | uint16_t randNum(uint16_t min, uint16_t max, unsigned int seed) 106 | { 107 | return (rand_r(&seed) % (max - min + 1)) + min; 108 | } 109 | 110 | void *threadHndl(void *data) 111 | { 112 | // Pass info. 113 | struct pthread_info *info = (struct pthread_info *)data; 114 | 115 | // Create sockaddr_ll struct. 116 | struct sockaddr_ll sin; 117 | 118 | // Fill out sockaddr_ll struct. 119 | sin.sll_family = PF_PACKET; 120 | sin.sll_ifindex = if_nametoindex(info->interface); 121 | sin.sll_protocol = htons(ETH_P_IP); 122 | sin.sll_halen = ETH_ALEN; 123 | 124 | // Initialize socket FD. 125 | int sockfd; 126 | 127 | // Attempt to create socket. 128 | if ((sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW)) < 0) 129 | { 130 | perror("socket"); 131 | 132 | pthread_exit(NULL); 133 | } 134 | 135 | if (info->sMAC[0] == 0 && info->sMAC[1] == 0 && info->sMAC[2] == 0 && info->sMAC[3] == 0 && info->sMAC[4] == 0 && info->sMAC[5] == 0) 136 | { 137 | // Receive the interface's MAC address (the source MAC). 138 | struct ifreq ifr; 139 | strcpy(ifr.ifr_name, info->interface); 140 | 141 | // Attempt to get MAC address. 142 | if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) != 0) 143 | { 144 | perror("ioctl"); 145 | 146 | pthread_exit(NULL); 147 | } 148 | 149 | // Copy source MAC to necessary variables. 150 | memcpy(info->sMAC, ifr.ifr_addr.sa_data, ETH_ALEN); 151 | } 152 | 153 | memcpy(sin.sll_addr, info->sMAC, ETH_ALEN); 154 | 155 | // Attempt to bind socket. 156 | if (bind(sockfd, (struct sockaddr *)&sin, sizeof(sin)) != 0) 157 | { 158 | perror("bind"); 159 | 160 | pthread_exit(NULL); 161 | } 162 | 163 | // Loop. 164 | while (1) 165 | { 166 | // Create rand_r() seed. 167 | unsigned int seed; 168 | 169 | uint16_t offset = 0; 170 | 171 | if (info->nostats) 172 | { 173 | seed = time(NULL) ^ getpid() ^ pthread_self(); 174 | } 175 | else 176 | { 177 | seed = (unsigned int)(pcktCount + info->id); 178 | } 179 | 180 | // Get source port (random). 181 | uint16_t srcPort; 182 | 183 | // Check if source port is 0 (random). 184 | if (info->sport == 0) 185 | { 186 | srcPort = randNum(1024, 65535, seed); 187 | } 188 | else 189 | { 190 | srcPort = info->sport; 191 | } 192 | 193 | // Get destination port. 194 | uint16_t dstPort; 195 | 196 | // Check if port is 0 (random). 197 | if (info->port == 0) 198 | { 199 | dstPort = randNum(10, 65535, seed); 200 | } 201 | else 202 | { 203 | dstPort = info->port; 204 | } 205 | 206 | char IP[32]; 207 | 208 | if (info->sIP == NULL) 209 | { 210 | // Spoof source IP as any IP address. 211 | uint8_t tmp[4]; 212 | 213 | if (info->internal) 214 | { 215 | tmp[0] = randNum(10, 10, seed); 216 | tmp[1] = randNum(0, 254, seed + 1); 217 | tmp[2] = randNum(0, 254, seed + 2); 218 | tmp[3] = randNum(0, 254, seed + 3); 219 | } 220 | else 221 | { 222 | tmp[0] = randNum(1, 254, seed); 223 | tmp[1] = randNum(0, 254, seed + 1); 224 | tmp[2] = randNum(0, 254, seed + 2); 225 | tmp[3] = randNum(0, 254, seed + 3); 226 | } 227 | 228 | sprintf(IP, "%d.%d.%d.%d", tmp[0], tmp[1], tmp[2], tmp[3]); 229 | } 230 | else 231 | { 232 | memcpy(IP, info->sIP, strlen(info->sIP)); 233 | } 234 | 235 | // Initialize packet buffer. 236 | char buffer[MAX_PCKT_LENGTH]; 237 | 238 | // Create ethernet header. 239 | struct ethhdr *eth = (struct ethhdr *)(buffer); 240 | 241 | // Fill out ethernet header. 242 | eth->h_proto = htons(ETH_P_IP); 243 | memcpy(eth->h_source, info->sMAC, ETH_ALEN); 244 | memcpy(eth->h_dest, info->dMAC, ETH_ALEN); 245 | 246 | // Increase offset. 247 | offset += sizeof(struct ethhdr); 248 | 249 | // Create outer IP header if enabled. 250 | struct iphdr *oiph = NULL; 251 | 252 | if (info->ipip) 253 | { 254 | oiph = (struct iphdr *)(buffer + offset); 255 | 256 | // Fill out header. 257 | oiph->ihl = 5; 258 | oiph->version = 4; 259 | oiph->protocol = IPPROTO_IPIP; 260 | oiph->id = 0; 261 | oiph->frag_off = 0; 262 | oiph->saddr = inet_addr(info->ipipsrc); 263 | oiph->daddr = inet_addr(info->ipipdst); 264 | oiph->tos = info->tos; 265 | 266 | oiph->ttl = (uint8_t) randNum(info->minTTL, info->maxTTL, seed); 267 | 268 | // Increase offset. 269 | offset += sizeof(struct iphdr); 270 | } 271 | 272 | // Create IP header. 273 | struct iphdr *iph = (struct iphdr *)(buffer + offset); 274 | 275 | // Fill out IP header. 276 | iph->ihl = 5; 277 | iph->version = 4; 278 | 279 | // Check for TCP. 280 | if (info->tcp) 281 | { 282 | iph->protocol = IPPROTO_TCP; 283 | } 284 | else if (info->icmp) 285 | { 286 | iph->protocol = IPPROTO_ICMP; 287 | } 288 | else 289 | { 290 | iph->protocol = IPPROTO_UDP; 291 | } 292 | 293 | iph->id = 0; 294 | iph->frag_off = 0; 295 | iph->saddr = inet_addr(IP); 296 | iph->daddr = inet_addr(info->dIP); 297 | iph->tos = info->tos; 298 | 299 | iph->ttl = (uint8_t) randNum(info->minTTL, info->maxTTL, seed); 300 | 301 | // Increase offset. 302 | offset += sizeof(struct iphdr); 303 | 304 | // Calculate payload length and payload. 305 | uint16_t dataLen; 306 | 307 | // Initialize payload. 308 | uint16_t l4header; 309 | 310 | switch (iph->protocol) 311 | { 312 | case IPPROTO_UDP: 313 | l4header = sizeof(struct udphdr); 314 | 315 | break; 316 | 317 | case IPPROTO_TCP: 318 | l4header = sizeof(struct tcphdr); 319 | 320 | break; 321 | 322 | case IPPROTO_ICMP: 323 | l4header = sizeof(struct icmphdr); 324 | 325 | break; 326 | } 327 | 328 | // Increase offset. 329 | offset += l4header; 330 | 331 | unsigned char *data = (unsigned char *)(buffer + offset); 332 | 333 | // Check for custom payload. 334 | if (info->payloadLength > 0) 335 | { 336 | dataLen = info->payloadLength; 337 | 338 | for (uint16_t i = 0; i < info->payloadLength; i++) 339 | { 340 | *data = info->payload[i]; 341 | *data++; 342 | } 343 | } 344 | else 345 | { 346 | dataLen = randNum(info->min, info->max, seed); 347 | 348 | // Fill out payload with random characters. 349 | for (uint16_t i = 0; i < dataLen; i++) 350 | { 351 | *data = rand_r(&seed); 352 | *data++; 353 | } 354 | } 355 | 356 | // Decrease offset since we're going back to fill in L4 layer. 357 | offset -= l4header; 358 | 359 | // Check protocol. 360 | if (iph->protocol == IPPROTO_TCP) 361 | { 362 | // Create TCP header. 363 | struct tcphdr *tcph = (struct tcphdr *)(buffer + offset); 364 | 365 | // Fill out TCP header. 366 | tcph->doff = 5; 367 | tcph->source = htons(srcPort); 368 | tcph->dest = htons(dstPort); 369 | tcph->ack_seq = 0; 370 | tcph->seq = 0; 371 | 372 | // Check for each flag. 373 | if (info->tcp_urg) 374 | { 375 | tcph->urg = 1; 376 | } 377 | 378 | if (info->tcp_ack) 379 | { 380 | tcph->ack = 1; 381 | } 382 | 383 | if (info->tcp_psh) 384 | { 385 | tcph->psh = 1; 386 | } 387 | 388 | if (info->tcp_rst) 389 | { 390 | tcph->rst = 1; 391 | } 392 | 393 | if (info->tcp_syn) 394 | { 395 | tcph->syn = 1; 396 | } 397 | 398 | if (info->tcp_fin) 399 | { 400 | tcph->fin = 1; 401 | } 402 | 403 | // Calculate TCP header checksum. 404 | tcph->check = 0; 405 | 406 | if (!info->nocsum4) 407 | { 408 | tcph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, sizeof(struct tcphdr) + dataLen, IPPROTO_TCP, csum_partial(tcph, sizeof(struct tcphdr) + dataLen, 0)); 409 | } 410 | } 411 | else if (iph->protocol == IPPROTO_ICMP) 412 | { 413 | // Create ICMP header. 414 | struct icmphdr *icmph = (struct icmphdr *)(buffer + offset); 415 | 416 | // Fill out ICMP header. 417 | icmph->type = info->icmp_type; 418 | icmph->code = info->icmp_code; 419 | 420 | // Calculate ICMP header's checksum. 421 | icmph->checksum = 0; 422 | 423 | if (!info->nocsum4) 424 | { 425 | icmph->checksum = icmp_csum((uint16_t *)icmph, sizeof(struct icmphdr) + dataLen); 426 | } 427 | } 428 | else 429 | { 430 | // Create UDP header. 431 | struct udphdr *udph = (struct udphdr *)(buffer + offset); 432 | 433 | // Fill out UDP header. 434 | udph->source = htons(srcPort); 435 | udph->dest = htons(dstPort); 436 | udph->len = htons(sizeof(struct udphdr) + dataLen); 437 | 438 | // Calculate UDP header checksum. 439 | udph->check = 0; 440 | 441 | if (!info->nocsum4) 442 | { 443 | udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, sizeof(struct udphdr) + dataLen, IPPROTO_UDP, csum_partial(udph, sizeof(struct udphdr) + dataLen, 0)); 444 | } 445 | } 446 | 447 | uint16_t pcktlen = 0; 448 | 449 | // Calculate length and checksum of IP headers. 450 | pcktlen = sizeof(struct iphdr) + l4header + dataLen; 451 | 452 | iph->tot_len = htons(pcktlen); 453 | 454 | if (!info->nocsum) 455 | { 456 | update_iph_checksum(iph); 457 | } 458 | 459 | if (oiph != NULL) 460 | { 461 | // Add length of additional IP header (20 bytes). 462 | pcktlen += sizeof(struct iphdr); 463 | 464 | oiph->tot_len = htons(pcktlen); 465 | 466 | if (!info->nocsum) 467 | { 468 | update_iph_checksum(oiph); 469 | } 470 | } 471 | 472 | // Initialize variable that represents how much data we've sent. 473 | uint16_t sent; 474 | 475 | // Attempt to send data. 476 | if ((sent = sendto(sockfd, buffer, pcktlen + sizeof(struct ethhdr), 0, (struct sockaddr *)&sin, sizeof(sin))) < 0) 477 | { 478 | perror("send"); 479 | 480 | continue; 481 | } 482 | 483 | // Add onto stats if enabled. 484 | if (!info->nostats) 485 | { 486 | __sync_add_and_fetch(&totalData, sent); 487 | } 488 | 489 | if (!info->nostats || info->pcktCountMax > 0) 490 | { 491 | // Check packet count. 492 | if (__sync_add_and_fetch(&pcktCount, 1) >= info->pcktCountMax && info->pcktCountMax > 0) 493 | { 494 | cont = 0; 495 | 496 | break; 497 | } 498 | } 499 | 500 | // Verbose mode. 501 | if (info->verbose) 502 | { 503 | fprintf(stdout, "Sent %d bytes to destination. (%" PRIu64 "/%" PRIu64 ")\n", sent, pcktCount, info->pcktCountMax); 504 | } 505 | 506 | // Check time elasped. 507 | if (info->seconds > 0) 508 | { 509 | time_t timeNow = time(NULL); 510 | 511 | if (timeNow >= (info->startingTime + info->seconds)) 512 | { 513 | cont = 0; 514 | 515 | break; 516 | } 517 | } 518 | 519 | // Check if we should wait between packets. 520 | if (info->interval > 0) 521 | { 522 | usleep(info->interval); 523 | } 524 | } 525 | 526 | // Close socket. 527 | close(sockfd); 528 | 529 | // Free information. 530 | free(info); 531 | 532 | // Exit thread. 533 | pthread_exit(NULL); 534 | } 535 | 536 | // Command line options. 537 | static struct option longoptions[] = 538 | { 539 | {"dev", required_argument, NULL, 'i'}, 540 | {"src", required_argument, NULL, 's'}, 541 | {"dst", required_argument, NULL, 'd'}, 542 | {"port", required_argument, NULL, 'p'}, 543 | {"sport", required_argument, NULL, 14}, 544 | {"interval", required_argument, NULL, 1}, 545 | {"threads", required_argument, NULL, 't'}, 546 | {"min", required_argument, NULL, 2}, 547 | {"max", required_argument, NULL, 3}, 548 | {"count", required_argument, NULL, 'c'}, 549 | {"time", required_argument, NULL, 6}, 550 | {"smac", required_argument, NULL, 7}, 551 | {"dmac", required_argument, NULL, 8}, 552 | {"payload", required_argument, NULL, 10}, 553 | {"verbose", no_argument, &g_info.verbose, 'v'}, 554 | {"tcp", no_argument, &g_info.tcp, 4}, 555 | {"icmp", no_argument, &g_info.icmp, 4}, 556 | {"ipip", no_argument, &g_info.ipip, 4}, 557 | {"internal", no_argument, &g_info.internal, 5}, 558 | {"nostats", no_argument, &g_info.nostats, 9}, 559 | {"urg", no_argument, &g_info.tcp_urg, 11}, 560 | {"ack", no_argument, &g_info.tcp_ack, 11}, 561 | {"psh", no_argument, &g_info.tcp_psh, 11}, 562 | {"rst", no_argument, &g_info.tcp_rst, 11}, 563 | {"syn", no_argument, &g_info.tcp_syn, 11}, 564 | {"fin", no_argument, &g_info.tcp_fin, 11}, 565 | {"icmptype", required_argument, NULL, 12}, 566 | {"icmpcode", required_argument, NULL, 13}, 567 | {"ipipsrc", required_argument, NULL, 15}, 568 | {"ipipdst", required_argument, NULL, 16}, 569 | {"nocsum", no_argument, &g_info.nocsum, 17}, 570 | {"nocsum4", no_argument, &g_info.nocsum4, 18}, 571 | {"minttl", required_argument, NULL, 19}, 572 | {"maxttl", required_argument, NULL, 20}, 573 | {"tos", required_argument, NULL, 21}, 574 | {"help", no_argument, &g_info.help, 'h'}, 575 | {NULL, 0, NULL, 0} 576 | }; 577 | 578 | void parse_command_line(int argc, char *argv[]) 579 | { 580 | int c = -1; 581 | 582 | // Parse command line. 583 | while (optind < argc) 584 | { 585 | if ((c = getopt_long(argc, argv, "i:d:t:vhs:p:c:", longoptions, NULL)) != -1) 586 | { 587 | switch(c) 588 | { 589 | case 'i': 590 | g_info.interface = optarg; 591 | 592 | break; 593 | 594 | case 's': 595 | g_info.sIP = optarg; 596 | 597 | break; 598 | 599 | case 'd': 600 | g_info.dIP = optarg; 601 | 602 | break; 603 | 604 | case 'p': 605 | g_info.port = atoi(optarg); 606 | 607 | break; 608 | 609 | case 14: 610 | g_info.sport = atoi(optarg); 611 | 612 | break; 613 | 614 | case 1: 615 | g_info.interval = strtoll(optarg, NULL, 10); 616 | 617 | break; 618 | 619 | case 't': 620 | g_info.threads = atoi(optarg); 621 | 622 | break; 623 | 624 | case 2: 625 | g_info.min = atoi(optarg); 626 | 627 | break; 628 | 629 | case 3: 630 | g_info.max = atoi(optarg); 631 | 632 | break; 633 | 634 | case 'c': 635 | g_info.pcktCountMax = strtoll(optarg, NULL, 10); 636 | 637 | break; 638 | 639 | case 6: 640 | g_info.seconds = strtoll(optarg, NULL, 10); 641 | 642 | break; 643 | 644 | case 7: 645 | sscanf(optarg, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &g_info.sMAC[0], &g_info.sMAC[1], &g_info.sMAC[2], &g_info.sMAC[3], &g_info.sMAC[4], &g_info.sMAC[5]); 646 | 647 | break; 648 | 649 | case 8: 650 | sscanf(optarg, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &g_info.dMAC[0], &g_info.dMAC[1], &g_info.dMAC[2], &g_info.dMAC[3], &g_info.dMAC[4], &g_info.dMAC[5]); 651 | 652 | break; 653 | 654 | case 10: 655 | g_info.payloadStr = optarg; 656 | 657 | break; 658 | 659 | case 12: 660 | g_info.icmp_type = atoi(optarg); 661 | 662 | break; 663 | 664 | case 13: 665 | g_info.icmp_code = atoi(optarg); 666 | 667 | break; 668 | 669 | case 15: 670 | g_info.ipipsrc = optarg; 671 | 672 | break; 673 | 674 | case 16: 675 | g_info.ipipdst = optarg; 676 | 677 | break; 678 | 679 | case 17: 680 | g_info.nocsum = 1; 681 | 682 | break; 683 | 684 | case 18: 685 | g_info.nocsum4 = 1; 686 | 687 | break; 688 | 689 | case 19: 690 | g_info.minTTL = (uint8_t) atoi(optarg); 691 | 692 | break; 693 | 694 | case 20: 695 | g_info.maxTTL = (uint8_t) atoi(optarg); 696 | 697 | break; 698 | 699 | case 21: 700 | g_info.tos = (uint8_t) atoi(optarg); 701 | 702 | break; 703 | 704 | case 'v': 705 | g_info.verbose = 1; 706 | 707 | break; 708 | 709 | case 'h': 710 | g_info.help = 1; 711 | 712 | break; 713 | 714 | case '?': 715 | fprintf(stderr, "Missing argument.\n"); 716 | 717 | break; 718 | } 719 | } 720 | else 721 | { 722 | optind++; 723 | } 724 | } 725 | } 726 | 727 | int main(int argc, char *argv[]) 728 | { 729 | // Set defaults. 730 | g_info.threads = get_nprocs(); 731 | memset(g_info.sMAC, 0, ETH_ALEN); 732 | memset(g_info.dMAC, 0, ETH_ALEN); 733 | g_info.minTTL = 64; 734 | g_info.maxTTL = 64; 735 | g_info.interval = 1000000; 736 | g_info.tos = 0; 737 | 738 | g_info.startingTime = time(NULL); 739 | 740 | // Parse the command line. 741 | parse_command_line(argc, argv); 742 | 743 | // Check if help flag is set. If so, print help information. 744 | if (g_info.help) 745 | { 746 | fprintf(stdout, "Usage for: %s:\n" \ 747 | "--dev -i => Interface name to bind to.\n" \ 748 | "--src -s => Source address (0/unset = random/spoof).\n" 749 | "--dst -d => Destination IP to send packets to.\n" \ 750 | "--port -p => Destination port (0/unset = random port).\n" \ 751 | "--sport => Source port (0/unset = random port).\n" \ 752 | "--internal => When set, if no source IP is specified, it will randomize the source IP from the 10.0.0.0/8 range.\n" \ 753 | "--interval => Interval between sending packets in micro seconds.\n" \ 754 | "--threads -t => Amount of threads to spawn (default is host's CPU count).\n" \ 755 | "--count -c => The maximum packet count allowed sent.\n" \ 756 | "--time => Amount of time in seconds to run tool for.\n" \ 757 | "--smac => Source MAC address in xx:xx:xx:xx:xx:xx format.\n" \ 758 | "--dmac => Destination MAC address in xx:xx:xx:xx:xx:xx format.\n" \ 759 | "--payload => The payload to send. Format is in hexadecimal. Example: FF FF FF FF 49.\n" \ 760 | "--verbose -v => Print how much data we've sent each time.\n" \ 761 | "--nostats => Do not track PPS and bandwidth. This may increase performance.\n" \ 762 | "--urg => Set the URG flag for TCP packets.\n" \ 763 | "--ack => Set the ACK flag for TCP packets.\n" \ 764 | "--psh => Set the PSH flag for TCP packets.\n" \ 765 | "--rst => Set the RST flag for TCP packets.\n" \ 766 | "--syn => Set the SYN flag for TCP packets.\n" \ 767 | "--fin => Set the FIN flag for TCP packets.\n" \ 768 | "--min => Minimum payload length.\n" \ 769 | "--max => Maximum payload length.\n" \ 770 | "--tcp => Send TCP packets.\n" \ 771 | "--icmp => Send ICMP packets.\n" \ 772 | "--icmptype => The ICMP type to send when --icmp is specified.\n" \ 773 | "--icmpcode => The ICMP code to send when --icmp is specified.\n" \ 774 | "--ipip => Add outer IP header in IPIP format.\n" \ 775 | "--ipipsrc => When IPIP is specified, use this as outer IP header's source address.\n" \ 776 | "--ipipdst => When IPIP is specified, use this as outer IP header's destination address.\n" \ 777 | "--nocsum => Do not calculate the IP header's checksum. Useful for checksum offloading on the hardware which'll result in better performance.\n" \ 778 | "--nocsum4 => Do not calculate the layer 4's checksum (e.g. TCP/UDP). It will leave the checksum field as 0 in the headers.\n" \ 779 | "--minttl => The minimum TTL (Time-To-Live) range for a packet.\n" \ 780 | "--maxttl => The maximum TTL (Time-To-Live) range for a packet.\n" \ 781 | "--tos => The TOS (Type Of Service) to set on each packet.\n" \ 782 | "--help -h => Show help menu information.\n", argv[0]); 783 | 784 | exit(0); 785 | } 786 | 787 | // Check if interface argument was set. 788 | if (g_info.interface == NULL) 789 | { 790 | fprintf(stderr, "Missing --dev option.\n"); 791 | 792 | exit(1); 793 | } 794 | 795 | // Check if destination IP argument was set. 796 | if (g_info.dIP == NULL) 797 | { 798 | fprintf(stderr, "Missing --dst option\n"); 799 | 800 | exit(1); 801 | } 802 | 803 | // Create pthreads. 804 | pthread_t pid[g_info.threads]; 805 | 806 | // Print information. 807 | fprintf(stdout, "Launching against %s:%d (0 = random) from interface %s. Thread count => %d and Interval => %" PRIu64 " micro seconds.\n", g_info.dIP, g_info.port, g_info.interface, g_info.threads, g_info.interval); 808 | 809 | // Start time. 810 | startTime = time(NULL); 811 | 812 | // Loop thread each thread. 813 | for (uint16_t i = 0; i < g_info.threads; i++) 814 | { 815 | // Create new pthread_info struct to pass to thread and copy g_info to it. 816 | struct pthread_info *info = malloc(sizeof(struct pthread_info)); 817 | memcpy(info, &g_info, sizeof(struct pthread_info)); 818 | 819 | // Check for inputted destination MAC. 820 | if (info->dMAC[0] == 0 && info->dMAC[1] == 0 && info->dMAC[2] == 0 && info->dMAC[3] == 0 && info->dMAC[4] == 0 && info->dMAC[5] == 0) 821 | { 822 | // Get destination MAC address (gateway MAC). 823 | GetGatewayMAC(info->dMAC); 824 | } 825 | else 826 | { 827 | memcpy(info->dMAC, info->dMAC, ETH_ALEN); 828 | } 829 | 830 | memcpy(info->sMAC, info->sMAC, ETH_ALEN); 831 | 832 | // Do custom payload if set. 833 | if (info->payloadStr != NULL) 834 | { 835 | // Split argument by space. 836 | char *split; 837 | 838 | // Create temporary string. 839 | char *str = malloc((strlen(info->payloadStr) + 1) * sizeof(char)); 840 | strcpy(str, info->payloadStr); 841 | 842 | split = strtok(str, " "); 843 | 844 | while (split != NULL) 845 | { 846 | sscanf(split, "%2hhx", &info->payload[info->payloadLength]); 847 | 848 | info->payloadLength++; 849 | split = strtok(NULL, " "); 850 | } 851 | 852 | // Free temporary string. 853 | free(str); 854 | } 855 | 856 | // Create thread. 857 | if (pthread_create(&pid[i], NULL, threadHndl, (void *)info) != 0) 858 | { 859 | fprintf(stderr, "Error spawning thread %" PRIu16 "...\n", i); 860 | } 861 | } 862 | 863 | // Signal. 864 | signal(SIGINT, signalHndl); 865 | 866 | // Loop! 867 | while (cont) 868 | { 869 | sleep(1); 870 | } 871 | 872 | // End time. 873 | time_t endTime = time(NULL); 874 | 875 | // Wait a second for cleanup. 876 | sleep(1); 877 | 878 | // Statistics 879 | time_t totalTime = endTime - startTime; 880 | 881 | fprintf(stdout, "Finished in %lu seconds.\n\n", totalTime); 882 | 883 | if (!g_info.nostats) 884 | { 885 | uint64_t pps = pcktCount / (uint64_t)totalTime; 886 | uint64_t MBTotal = totalData / 1000000; 887 | uint64_t MBsp = (totalData / (uint64_t)totalTime) / 1000000; 888 | uint64_t mbTotal = totalData / 125000; 889 | uint64_t mbps = (totalData / (uint64_t)totalTime) / 125000; 890 | 891 | // Print statistics. 892 | fprintf(stdout, "Packets Total => %" PRIu64 ".\nPackets Per Second => %" PRIu64 ".\n\n", pcktCount, pps); 893 | fprintf(stdout, "Megabytes Total => %" PRIu64 ".\nMegabytes Per Second => %" PRIu64 ".\n\n", MBTotal, MBsp); 894 | fprintf(stdout, "Megabits Total => %" PRIu64 ".\nMegabits Per Second => %" PRIu64 ".\n\n", mbTotal, mbps); 895 | } 896 | 897 | // Exit program successfully. 898 | exit(0); 899 | } -------------------------------------------------------------------------------- /src/include/csum.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 dreae 2 | // 3 | // This file is part of compressor. 4 | // 5 | // compressor is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // compressor is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with compressor. If not, see . 17 | 18 | #pragma once 19 | 20 | #include 21 | 22 | #ifndef REDIRECT_HEADER 23 | 24 | #include 25 | 26 | #endif 27 | 28 | #ifndef __BPF__ 29 | 30 | #include 31 | 32 | #ifndef unlikely 33 | #define unlikely(x) __builtin_expect(!!(x), 0) 34 | #endif 35 | 36 | struct pseudo_hdr 37 | { 38 | unsigned long saddr; // 4 bytes 39 | unsigned long daddr; // 4 bytes 40 | unsigned char reserved; // 1 byte 41 | unsigned char proto; // 1 byte 42 | unsigned short len; // 2 bytes 43 | 44 | }; 45 | 46 | /* 47 | * Checksums for x86-64 48 | * Copyright 2002 by Andi Kleen, SuSE Labs 49 | * with some code from asm-x86/checksum.h 50 | */ 51 | 52 | static inline unsigned add32_with_carry(unsigned a, unsigned b) 53 | { 54 | asm("addl %2,%0\n\t" 55 | "adcl $0,%0" 56 | : "=r" (a) 57 | : "0" (a), "rm" (b)); 58 | return a; 59 | } 60 | 61 | static inline unsigned short from32to16(unsigned a) 62 | { 63 | unsigned short b = a >> 16; 64 | asm("addw %w2,%w0\n\t" 65 | "adcw $0,%w0\n" 66 | : "=r" (b) 67 | : "0" (b), "r" (a)); 68 | return b; 69 | } 70 | 71 | /* 72 | * Do a 64-bit checksum on an arbitrary memory area. 73 | * Returns a 32bit checksum. 74 | * 75 | * This isn't as time critical as it used to be because many NICs 76 | * do hardware checksumming these days. 77 | * 78 | * Things tried and found to not make it faster: 79 | * Manual Prefetching 80 | * Unrolling to an 128 bytes inner loop. 81 | * Using interleaving with more registers to break the carry chains. 82 | */ 83 | static unsigned do_csum(const unsigned char *buff, unsigned len) 84 | { 85 | unsigned odd, count; 86 | unsigned long result = 0; 87 | 88 | if (unlikely(len == 0)) 89 | return result; 90 | odd = 1 & (unsigned long) buff; 91 | if (unlikely(odd)) { 92 | result = *buff << 8; 93 | len--; 94 | buff++; 95 | } 96 | count = len >> 1; /* nr of 16-bit words.. */ 97 | if (count) { 98 | if (2 & (unsigned long) buff) { 99 | result += *(unsigned short *)buff; 100 | count--; 101 | len -= 2; 102 | buff += 2; 103 | } 104 | count >>= 1; /* nr of 32-bit words.. */ 105 | if (count) { 106 | unsigned long zero; 107 | unsigned count64; 108 | if (4 & (unsigned long) buff) { 109 | result += *(unsigned int *) buff; 110 | count--; 111 | len -= 4; 112 | buff += 4; 113 | } 114 | count >>= 1; /* nr of 64-bit words.. */ 115 | 116 | /* main loop using 64byte blocks */ 117 | zero = 0; 118 | count64 = count >> 3; 119 | while (count64) { 120 | asm("addq 0*8(%[src]),%[res]\n\t" 121 | "adcq 1*8(%[src]),%[res]\n\t" 122 | "adcq 2*8(%[src]),%[res]\n\t" 123 | "adcq 3*8(%[src]),%[res]\n\t" 124 | "adcq 4*8(%[src]),%[res]\n\t" 125 | "adcq 5*8(%[src]),%[res]\n\t" 126 | "adcq 6*8(%[src]),%[res]\n\t" 127 | "adcq 7*8(%[src]),%[res]\n\t" 128 | "adcq %[zero],%[res]" 129 | : [res] "=r" (result) 130 | : [src] "r" (buff), [zero] "r" (zero), 131 | "[res]" (result)); 132 | buff += 64; 133 | count64--; 134 | } 135 | 136 | /* last up to 7 8byte blocks */ 137 | count %= 8; 138 | while (count) { 139 | asm("addq %1,%0\n\t" 140 | "adcq %2,%0\n" 141 | : "=r" (result) 142 | : "m" (*(unsigned long *)buff), 143 | "r" (zero), "0" (result)); 144 | --count; 145 | buff += 8; 146 | } 147 | result = add32_with_carry(result>>32, 148 | result&0xffffffff); 149 | 150 | if (len & 4) { 151 | result += *(unsigned int *) buff; 152 | buff += 4; 153 | } 154 | } 155 | if (len & 2) { 156 | result += *(unsigned short *) buff; 157 | buff += 2; 158 | } 159 | } 160 | if (len & 1) 161 | result += *buff; 162 | result = add32_with_carry(result>>32, result & 0xffffffff); 163 | if (unlikely(odd)) { 164 | result = from32to16(result); 165 | result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); 166 | } 167 | return result; 168 | } 169 | 170 | /* 171 | * computes the checksum of a memory block at buff, length len, 172 | * and adds in "sum" (32-bit) 173 | * 174 | * returns a 32-bit number suitable for feeding into itself 175 | * or csum_tcpudp_magic 176 | * 177 | * this function must be called with even lengths, except 178 | * for the last fragment, which may be odd 179 | * 180 | * it's best to have buff aligned on a 64-bit boundary 181 | */ 182 | static inline __wsum csum_partial(const void *buff, int len, __wsum sum) 183 | { 184 | return (__wsum)add32_with_carry(do_csum((const unsigned char *)buff, len), 185 | (__u32)sum); 186 | } 187 | 188 | /** 189 | * csum_fold - Fold and invert a 32bit checksum. 190 | * sum: 32bit unfolded sum 191 | * 192 | * Fold a 32bit running checksum to 16bit and invert it. This is usually 193 | * the last step before putting a checksum into a packet. 194 | * Make sure not to mix with 64bit checksums. 195 | */ 196 | static inline __sum16 csum_fold(__wsum sum) 197 | { 198 | asm(" addl %1,%0\n" 199 | " adcl $0xffff,%0" 200 | : "=r" (sum) 201 | : "r" ((__u32)sum << 16), 202 | "0" ((__u32)sum & 0xffff0000)); 203 | return (__sum16)(~(__u32)sum >> 16); 204 | } 205 | 206 | 207 | /* 208 | * This is a version of ip_compute_csum() optimized for IP headers, 209 | * which always checksum on 4 octet boundaries. 210 | * 211 | * By Jorge Cwik , adapted for linux by 212 | * Arnt Gulbrandsen. 213 | */ 214 | 215 | 216 | /** 217 | * ip_fast_csum - Compute the IPv4 header checksum efficiently. 218 | * iph: ipv4 header 219 | * ihl: length of header / 4 220 | */ 221 | static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl) 222 | { 223 | unsigned int sum; 224 | 225 | asm(" movl (%1), %0\n" 226 | " subl $4, %2\n" 227 | " jbe 2f\n" 228 | " addl 4(%1), %0\n" 229 | " adcl 8(%1), %0\n" 230 | " adcl 12(%1), %0\n" 231 | "1: adcl 16(%1), %0\n" 232 | " lea 4(%1), %1\n" 233 | " decl %2\n" 234 | " jne 1b\n" 235 | " adcl $0, %0\n" 236 | " movl %0, %2\n" 237 | " shrl $16, %0\n" 238 | " addw %w2, %w0\n" 239 | " adcl $0, %0\n" 240 | " notl %0\n" 241 | "2:" 242 | /* Since the input registers which are loaded with iph and ihl 243 | are modified, we must also specify them as outputs, or gcc 244 | will assume they contain their original values. */ 245 | : "=r" (sum), "=r" (iph), "=r" (ihl) 246 | : "1" (iph), "2" (ihl) 247 | : "memory"); 248 | return (__sum16)sum; 249 | } 250 | 251 | /** 252 | * csum_tcpup_nofold - Compute an IPv4 pseudo header checksum. 253 | * @saddr: source address 254 | * @daddr: destination address 255 | * @len: length of packet 256 | * @proto: ip protocol of packet 257 | * @sum: initial sum to be added in (32bit unfolded) 258 | * 259 | * Returns the pseudo header checksum the input data. Result is 260 | * 32bit unfolded. 261 | */ 262 | static inline __wsum 263 | csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len, 264 | __u8 proto, __wsum sum) 265 | { 266 | asm(" addl %1, %0\n" 267 | " adcl %2, %0\n" 268 | " adcl %3, %0\n" 269 | " adcl $0, %0\n" 270 | : "=r" (sum) 271 | : "g" (daddr), "g" (saddr), 272 | "g" ((len + proto)<<8), "0" (sum)); 273 | return sum; 274 | } 275 | 276 | 277 | /** 278 | * csum_tcpup_magic - Compute an IPv4 pseudo header checksum. 279 | * @saddr: source address 280 | * @daddr: destination address 281 | * @len: length of packet 282 | * @proto: ip protocol of packet 283 | * @sum: initial sum to be added in (32bit unfolded) 284 | * 285 | * Returns the 16bit pseudo header checksum the input data already 286 | * complemented and ready to be filled in. 287 | */ 288 | static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, 289 | __u32 len, __u8 proto, 290 | __wsum sum) 291 | { 292 | return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum)); 293 | } 294 | 295 | #endif 296 | 297 | static __always_inline uint16_t csum_fold_helper(uint32_t csum) { 298 | uint32_t r = csum << 16 | csum >> 16; 299 | csum = ~csum; 300 | csum -= r; 301 | return (uint16_t)(csum >> 16); 302 | } 303 | 304 | static __always_inline uint32_t csum_add(uint32_t addend, uint32_t csum) { 305 | uint32_t res = csum; 306 | res += addend; 307 | return (res + (res < addend)); 308 | } 309 | 310 | static __always_inline uint32_t csum_sub(uint32_t addend, uint32_t csum) { 311 | return csum_add(csum, ~addend); 312 | } 313 | 314 | 315 | static __always_inline void update_iph_checksum(struct iphdr *iph) { 316 | #ifndef __BPF__ 317 | iph->check = 0; 318 | iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); 319 | #else 320 | uint16_t *next_iph_u16 = (uint16_t *)iph; 321 | uint32_t csum = 0; 322 | iph->check = 0; 323 | #pragma clang loop unroll(full) 324 | for (uint32_t i = 0; i < sizeof(*iph) >> 1; i++) { 325 | csum += *next_iph_u16++; 326 | } 327 | 328 | iph->check = ~((csum & 0xffff) + (csum >> 16)); 329 | #endif 330 | } 331 | 332 | static __always_inline uint16_t csum_diff4(uint32_t from, uint32_t to, uint16_t csum) { 333 | uint32_t tmp = csum_sub(from, ~((uint32_t)csum)); 334 | return csum_fold_helper(csum_add(to, tmp)); 335 | } 336 | 337 | uint16_t tcp_checksum(const void *buff, size_t len, uint32_t *src_addr, uint32_t *dest_addr) 338 | { 339 | const uint16_t *buf=buff; 340 | uint32_t sum; 341 | size_t length=len; 342 | 343 | // Calculate the sum // 344 | sum = 0; 345 | while (len > 1) 346 | { 347 | sum += *buf++; 348 | if (sum & 0x80000000) 349 | sum = (sum & 0xFFFF) + (sum >> 16); 350 | len -= 2; 351 | } 352 | 353 | if ( len & 1 ) 354 | // Add the padding if the packet lenght is odd // 355 | sum += *((uint8_t *)buf); 356 | 357 | // Add the pseudo-header // 358 | sum += *(src_addr++); 359 | sum += *src_addr; 360 | sum += *(dest_addr++); 361 | sum += *dest_addr; 362 | sum += htons(IPPROTO_TCP); 363 | sum += htons(length); 364 | 365 | // Add the carries // 366 | while (sum >> 16) 367 | sum = (sum & 0xFFFF) + (sum >> 16); 368 | 369 | // Return the one's complement of sum // 370 | return ( (uint16_t)(~sum) ); 371 | } 372 | 373 | uint16_t icmp_csum (uint16_t *addr, int len) 374 | { 375 | int count = len; 376 | register uint32_t sum = 0; 377 | uint16_t answer = 0; 378 | 379 | // Sum up 2-byte values until none or only one byte left. 380 | while (count > 1) 381 | { 382 | sum += *(addr++); 383 | count -= 2; 384 | } 385 | 386 | // Add left-over byte, if any. 387 | if (count > 0) 388 | { 389 | sum += *(uint8_t *) addr; 390 | } 391 | 392 | // Fold 32-bit sum into 16 bits; we lose information by doing this, 393 | // increasing the chances of a collision. 394 | // sum = (lower 16 bits) + (upper 16 bits shifted right 16 bits) 395 | while (sum >> 16) 396 | { 397 | sum = (sum & 0xffff) + (sum >> 16); 398 | } 399 | 400 | // Checksum is one's compliment of sum. 401 | answer = ~sum; 402 | 403 | return (answer); 404 | } 405 | 406 | --------------------------------------------------------------------------------