Example #1
0
int main(int argc, char **argv) {
	char buf[4096];
	pid_t chld_listener=-1, chld_sender=-1;
	uint8_t status=0, msg_type=0, ecount=0;
	size_t msg_len=0;
	struct sigaction chsa;
	uint8_t *ptr=NULL;
	int lports=IPC_BINDPORT_START;
	uint8_t all_done=0;
	char verbose_level[4];
	drone_t *c=NULL;

	ident=IDENT_MASTER;
	ident_name_ptr=IDENT_MASTER_NAME;

	CLEAR(buf);

	s=(settings_t *)xmalloc(sizeof(settings_t));
	memset(s, 0, sizeof(settings_t));
	s->vi=(interface_info_t *)xmalloc(sizeof(interface_info_t));
	memset(s->vi, 0, sizeof(interface_info_t));

	s->forked=0; /* not required, for clarity */

	/* s->display=&display_builtin; */

	getconfig_argv(argc, argv);

	if (s->interface_str == NULL) {
		if (get_default_route_interface(&s->interface_str) != 1) {
			MSG(M_WARN, "Can't find default route, and matching device, using default interface `%s'", DEFAULT_NETDEV);
			s->interface_str=xstrdup(DEFAULT_NETDEV);
		}
		if (s->verbose > 1) {
			MSG(M_VERB, "Using interface %s", s->interface_str);
		}
	}

	if (!(GET_OVERRIDE())) {
		/* let the listener tell us then, the user didnt request a specific address */
		CLEAR(s->vi->myaddr_s); CLEAR(s->vi->hwaddr_s);
		sprintf(s->vi->myaddr_s, "0.0.0.0");
		sprintf(s->vi->hwaddr_s, "00:00:00:00:00:00");
		memset(&s->vi->myaddr, 0, sizeof(s->vi->myaddr));
		memset(&s->vi->hwaddr, 0, sizeof(s->vi->hwaddr));
        }
	else {
		/* complete the information we need like hwaddr, cause its impossible to specify that currently */
		if (s->verbose > 1) MSG(M_DBG2, "Spoofing from `%s [%s]'", s->vi->myaddr_s, s->vi->hwaddr_s);

		/* the ip info is already filled in, so just complete the rest */
		CLEAR(s->vi->hwaddr_s);
		sprintf(s->vi->hwaddr_s, "00:00:00:00:00:00");
		memset(&s->vi->hwaddr, 0, sizeof(s->vi->hwaddr));
	}
	s->vi->mtu=0; /* the listener HAS to tell us this, seeing as how the real limitation is there */

	time(&(s->s_time));

	if (s->forklocal) {
		if (s->verbose > 5) MSG(M_DBG2, "children will be forked, setting up signal handler for them");

		memset(&chsa, 0, sizeof(chsa));
		chsa.sa_handler=&child_dead;
		if (sigaction(SIGCHLD, &chsa, NULL) < 0) {
			MSG(M_ERR, "Cant register SIGCHLD handler");
			terminate(TERM_ERROR);
		}
	}

	arc4random_stir();

	if (init_modules() < 0) {
		MSG(M_ERR, "Can't initialize module structures, quiting");
		terminate(TERM_ERROR);
	}

	if (ipc_init() < 0) {
		MSG(M_ERR, "Cant initialize IPC, quiting");
		terminate(TERM_ERROR);
	}

	if (s->verbose > 0) {
		char low[32], high[32];
		uint32_t ips=0;

		CLEAR(low); CLEAR(high);
		ips=ntohl(s->_low_ip);
		snprintf(low, sizeof(low) -1, "%s", inet_ntoa((*(struct in_addr *)&ips)));
		ips=ntohl(s->_high_ip);
		snprintf(high, sizeof(high) -1, "%s", inet_ntoa((*(struct in_addr *)&ips)));

		MSG(M_VERB, "Scanning: %s -> %s : %s from %s [%s] at %u pps", low, high, (s->mode == MODE_ARPSCAN ? "Arp" : s->port_str), s->vi->myaddr_s, s->vi->hwaddr_s, s->pps);
	}

	if (s->verbose > 3) MSG(M_DBG1, "Main process id is %d", getpid());

	snprintf(verbose_level, sizeof(verbose_level) -1, "%d", s->verbose);

	/* initialize senders */
	if ((s->forklocal & FORK_LOCAL_SENDER) == FORK_LOCAL_SENDER) {
		if (s->drone_str == NULL) {
			s->drone_str=xstrdup(DEF_SENDER);
			if (s->verbose > 5) MSG(M_DBG2, "Added default sender to drone list `%s'", s->drone_str);
		}
		else {
			char newstr[128];

			CLEAR(newstr);
			snprintf(newstr, sizeof(newstr) -1, "%s,%s", s->drone_str, DEF_SENDER);
			xfree(s->drone_str);
			s->drone_str=xstrdup(newstr);
		}

		chld_sender=fork();
		if (chld_sender < 0) {
			MSG(M_ERR, "Can't fork sender: %s", strerror(errno));
			terminate(TERM_ERROR);
		}
		if (chld_sender == 0) {
			char *argz[5];
			char *envz[2];

			argz[0]=SENDERNAME;
			argz[1]=s->mod_dir;
			argz[2]=verbose_level;
			argz[3]=s->interface_str;
			argz[4]=NULL;

			envz[0]='\0';

			execve(SENDER_PATH, argz, envz);
			MSG(M_ERR, "execve %s fails", SENDER_PATH);
			terminate(TERM_ERROR);
		}
		child_running++;
		s->forklocal &= ~(FORK_LOCAL_SENDER);
	}
	else if (s->verbose > 5) {
		MSG(M_DBG2, "No local sender will be forked");
	}

	/* initialize listeners */
	if ((s->forklocal & FORK_LOCAL_LISTENER) == FORK_LOCAL_LISTENER) {
		if (s->drone_str == NULL) {
			s->drone_str=xstrdup(DEF_LISTENER);
			if (s->verbose > 5) MSG(M_DBG2, "Adding default listener to drone list");
		}
		else {
			char newstr[128];

			CLEAR(newstr);
			snprintf(newstr, sizeof(newstr) -1, "%s,%s", s->drone_str, DEF_LISTENER);
			xfree(s->drone_str);
			s->drone_str=xstrdup(newstr);
		}

		chld_listener=fork();
		if (chld_listener < 0) {
			MSG(M_ERR, "Can't fork listener: %s", strerror(errno));
			terminate(TERM_ERROR);
		}
		if (chld_listener == 0) {
			char *argz[7];
			char *envz[2];
			char mtu[8];

			CLEAR(mtu);
			snprintf(mtu, sizeof(mtu) -1, "%u", s->vi->mtu);

			argz[0]=LISTENERNAME;
			argz[1]=s->mod_dir;
			argz[2]=verbose_level;
			argz[3]=s->interface_str;
			argz[4]=s->vi->myaddr_s;
			argz[5]=s->vi->hwaddr_s;
			argz[6]=NULL;

			envz[0]='\0';

			execve(LISTENER_PATH, argz, envz);
			MSG(M_ERR, "execve %s fails", LISTENER_PATH);
			terminate(TERM_ERROR);
		}
		child_running++;
		s->forklocal &= ~(FORK_LOCAL_LISTENER);
	}
	else if (s->verbose > 5) {
		MSG(M_DBG2, "No local listener will be forked");
	}

	/* we need these modules cause we are hardcoded as a output conduit for now XXX */
	if (init_output_modules() < 0) {
		MSG(M_ERR, "Can't initialize output module structures, quiting");
		terminate(TERM_ERROR);
	}
	if (init_report_modules() < 0) {
		MSG(M_ERR, "Can't initialize report module structures, quiting");
		terminate(TERM_ERROR);
	}

	if (s->verbose > 2) MSG(M_DBG1, "drones: %s", s->drone_str);

	if (parse_drone_list((const char *)s->drone_str) < 0) {
		terminate(TERM_ERROR);
	}
	else if (s->verbose > 5) {
		MSG(M_DBG1, "Drone list `%s' parsed correctly", s->drone_str);
	}

	/* do stuff to figure out if there are working drones */
	if (s->verbose > 4) MSG(M_DBG1, "Drone list is %d big, connecting to them.", s->dlh->size);

	do {
		uint8_t *dummy=NULL;
		struct sockaddr_in lbind;

		c=s->dlh->head;

		if (c == NULL) {
			MSG(M_ERR, "no drones?, thats not going to work");
			terminate(TERM_ERROR);
		}

		for (c=s->dlh->head ; c != NULL ; c=c->next) {
			if (s->verbose > 6) MSG(M_DBG1, "THIS NODE -> status: %d type: %s host: %s port: %d socket: %d (%d out of %d ready)", c->status, (c->type == DRONE_TYPE_SENDER ? "Sender" : "Listener") , inet_ntoa(c->dsa.sin_addr), ntohs(c->dsa.sin_port), c->s, all_done, s->dlh->size);

			if (ecount > MAX_ERRORS) {
				MSG(M_ERR, "Too many errors, exiting now");
				terminate(TERM_ERROR);
			}

			switch (c->status) {

				/* connect to it */
				case DRONE_STATUS_UNKNOWN:
					memset(&lbind, 0, sizeof(lbind));
					lbind.sin_port=htons(lports++);

					if (c->s == -1 && create_client_socket(c, (struct sockaddr_in *)&lbind) < 0) {
						c->s=-1;
						usleep(50000);
						ecount++;
					}
					else {
						c->status=DRONE_STATUS_CONNECTED;
					}
					break;

				/* find out what it is */
				case DRONE_STATUS_CONNECTED:
					c->type=DRONE_TYPE_UNKNOWN;
					if (send_message(c->s, MSG_IDENT, MSG_STATUS_OK, dummy, 0) < 0) {
						ecount++;
						MSG(M_ERR, "Cant ident message node, marking as dead");
						if (ecount > MAX_ERRORS) {
							mark_dead(c);
							break;
						}
					}
					else {
						if (get_singlemessage(c->s, &msg_type, &status, &ptr, &msg_len) != 1) {
							MSG(M_ERR, "Unexpected message response from fd %d, marking as dead", c->s);
							mark_dead(c);
						}
						switch (msg_type) {
							case MSG_IDENTSENDER:
								c->type=DRONE_TYPE_SENDER;
								s->senders++;
								break;
							case MSG_IDENTLISTENER:
								c->type=DRONE_TYPE_LISTENER;
								s->listeners++;
								break;
							default:
								MSG(M_ERR, "Unknown drone type from message %s", strmsgtype(msg_type));
								c->type=DRONE_TYPE_UNKNOWN;
						}

						if (send_message(c->s, MSG_ACK, MSG_STATUS_OK, dummy, 0) < 0) {
							MSG(M_ERR, "Cant ack ident message from node on fd %d, marking as dead", c->s);
							mark_dead(c);
						}

						c->status=DRONE_STATUS_IDENT;
					}
					break;

				/* wait for it to say its ready */
				case DRONE_STATUS_IDENT:
					if (get_singlemessage(c->s, &msg_type, &status, &ptr, &msg_len) != 1) {
						MSG(M_ERR, "Unexpected message reply from drone on fd %d, marking as dead", c->s);
						mark_dead(c);
					}
					else if (msg_type == MSG_READY) {
						c->status=DRONE_STATUS_READY;
						if (s->verbose > 3) MSG(M_DBG1, "drone on fd %d is ready", c->s);
						if (c->type == DRONE_TYPE_LISTENER) {
							union {
								listener_info_t *l;
								uint8_t *ptr;
							} l_u;
							struct in_addr ia;

							if (msg_len != sizeof(listener_info_t)) {
								MSG(M_ERR, "Listener didnt send me the correct information, marking dead");
								mark_dead(c);
							}
							l_u.ptr=ptr;
							s->vi->myaddr.sin_addr.s_addr=l_u.l->myaddr;
							ia.s_addr=s->vi->myaddr.sin_addr.s_addr;
							s->vi->mtu=l_u.l->mtu;
							memcpy(s->vi->hwaddr, l_u.l->hwaddr, THE_ONLY_SUPPORTED_HWADDR_LEN);
							snprintf(s->vi->hwaddr_s, sizeof(s->vi->hwaddr_s) -1, "%.02x:%.02x:%.02x:%.02x:%.02x:%.02x", l_u.l->hwaddr[0], l_u.l->hwaddr[1], l_u.l->hwaddr[2], l_u.l->hwaddr[3], l_u.l->hwaddr[4], l_u.l->hwaddr[5]);
							snprintf(s->vi->myaddr_s, sizeof(s->vi->myaddr_s) -1, "%s", inet_ntoa(ia));

							if (s->verbose > 2) MSG(M_DBG1, "Listener info gave me the following address information `%s [%s]' with mtu %u", s->vi->myaddr_s, s->vi->hwaddr_s, s->vi->mtu);
						}
					}
					else {
						MSG(M_ERR, "drone isnt ready on fd %d, marking as dead", c->s);
						mark_dead(c);
					}
					break;

				case DRONE_STATUS_READY:
					all_done++;
					break;

				case DRONE_STATUS_DEAD:
					all_done++;
					MSG(M_WARN, "Dead drone in list on fd %d", c->s);
					break;

			} /* switch node status */
		} /* step though list */
	} while (all_done < s->dlh->size);

	/* XXX remove this and fix */
	if (s->senders == 0 && GET_SENDDRONE()) {
		/* XXX */
		MSG(M_ERR, "No senders for scan, giving up and rudley disconnecting from other drones without warning");
		terminate(TERM_ERROR);
	}

	if (s->listeners == 0 && GET_LISTENDRONE()) {
		/* XXX */
		MSG(M_ERR, "No listeners for scan, giving up and rudley disconnecting from other drones without warning");
		terminate(TERM_ERROR);
	}

	if (s->verbose > 5) MSG(M_DBG2, "Running scan");
	run_mode();

	time(&(s->e_time));

	if (s->verbose > 4) MSG(M_DBG2, "Main shuting down output modules");
	fini_output_modules();
	fini_report_modules();
	if (s->verbose > 4) MSG(M_DBG2, "Main exiting");

	terminate(TERM_NORMAL);
}
Example #2
0
int getconfig_argv(int argc, char ** argv) {
	int ch=0;
	char conffile[512];

#define OPTS	\
		"b:" "B:" "c" "d:" "D" "e:" "E" "F" "G:" "h" "H" "i:" "I" "j:" "l:" "L:" "m:" "M:" "o:" "p:" "P:" "q:" "Q" \
		"r:" "R:" "s:" "S" "t:" "T:" "u:" "U" "w:" "W:" "v" "V" "z" "Z:"

#ifdef WITH_LONGOPTS
	const struct option long_opts[]={
		{"broken-crc",		1, NULL, 'b'},
		{"source-port",		1, NULL, 'B'},
		{"proc-duplicates",	0, NULL, 'c'},
		{"delay-type",		1, NULL, 'd'},
		{"no-defpayload",	0, NULL, 'D'},
		{"enable-modules",	1, NULL, 'e'},
		{"show-errors",		0, NULL, 'E'},
		{"try-frags",		0, NULL, 'F'},
		{"payload-group",	1, NULL, 'G'},
		{"help",		0, NULL, 'h'},
		{"do-dns",		0, NULL, 'H'},
		{"interface",		1, NULL, 'i'},
		{"immediate",		0, NULL, 'I'},
		{"ignore-seq",		1, NULL, 'j'},
		{"logfile",		1, NULL, 'l'},
		{"packet-timeout",	1, NULL, 'L'},
		{"mode",		1, NULL, 'm'},
		{"module-dir",		1, NULL, 'M'},
		{"format",		1, NULL, 'o'},
		{"ports",		1, NULL, 'p'},
		{"pcap-filter",		1, NULL, 'P'},
		{"covertness",		1, NULL, 'q'},
		{"quiet",		0, NULL, 'Q'},
		{"pps",			1, NULL, 'r'},
		{"repeats",		1, NULL, 'R'},
		{"source-addr",		1, NULL, 's'},
		{"no-shuffle",		0, NULL, 'S'},
		{"ip-ttl",		1, NULL, 't'},
		{"ip-tos",		1, NULL, 'T'},
		{"debug",		1, NULL, 'u'},
		{"no-openclosed",	0, NULL, 'U'},
		{"savefile",		1, NULL, 'w'},
		{"fingerprint",		1, NULL, 'W'},
		{"verbose",		1, NULL, 'v'}, /* this is different in the long / short opts */
		{"version",		0, NULL, 'V'},
		{"sniff",		0, NULL, 'z'},
		{"drone-str",		1, NULL, 'Z'},
		{NULL,			0, NULL,  0 }
	};
#endif /* LONG OPTION SUPPORT */

	scan_setdefaults();

	snprintf(conffile, sizeof(conffile) -1, CONF_FILE, s->profile);
	if (readconf(conffile) < 0) {
		return -1;
	}

#ifdef WITH_LONGOPTS
	while ((ch=getopt_long(argc, argv, OPTS, long_opts, NULL)) != -1) {
#else
	while ((ch=getopt(argc, argv, OPTS)) != -1) {
#endif
		switch (ch) {
			case 'b':
				if (scan_setbroken(optarg) < 0) {
					usage();
				}
				break;

			case 'B':
				if (scan_setsrcp(atoi(optarg)) < 0) {
					usage();
				}
				break;

			case 'c':
				if (scan_setprocdups(1) < 0) {
					usage();
				}
				break;

			case 'D': /* set no default payload */
				if (scan_setdefpayload(0) < 0) {
					usage();
				}
				break;

			case 'd':
				if (scan_setdelaytype(atoi(optarg)) < 0) {
					usage();
				}
				break;

			case 'e': /* enable modules */
				if (scan_setenablemodule(optarg) < 0) {
					usage();
				}
				break;

			case 'E': /* report and listen for non open/closed responses */
				if (scan_setprocerrors(1) < 0) {
					usage();
				}
				break;

			case 'F': /* fragment packets if possible */
				if (scan_settryfrags(1) < 0) {
					usage();
				}
				break;

			case 'G':
				if (scan_setpayload_grp(atoi(optarg)) < 0) {
					usage();
				}
				break;

			case 'h': /* help */
				usage();
				break;

			case 'H': /* resolve ip addresses into names during reporting phase */
				if (scan_setdodns(1) < 0) {
					usage();
				}
				break;

			case 'i': /* interface name */
				if (scan_setinterface(optarg) < 0) {
					usage();
				}
				break;

			case 'I':
				if (scan_setimmediate(1) < 0) {
					usage();
				}
				break;

			case 'j': /* ignore sequence numbers during tcp scanning */
				if (scan_setignoreseq(optarg) < 0) {
					usage();
				}
				break;

			case 'L': /* how long to wait for replies after done sending */
				if (scan_setrecvtimeout(atoi(optarg)) < 0) {
					usage();
				}
				break;

			case 'l': /* log to file, not tty */
				if ((s->_stdout=fopen(optarg, "a+")) == NULL) {
					terminate("logfile `%s' cant be opened", optarg);
				}
				s->_stderr=s->_stdout;
				break;

			case 'm': /* scan mode, tcp udp, etc */
				if (scan_setoptmode(optarg) < 0) {
					usage();
				}
				break;

			case 'M': /* module directory base */
				if (scan_setmoddir(optarg) < 0) {
					usage();
				}
				break;

			case 'o': /* report format string */
				if (scan_setformat(optarg) < 0) {
					usage();
				}
				break;
			

			case 'p': /* Global ports to scan */
				if (scan_setgports(optarg) < 0) {
					usage();
				}
				break;

			case 'P': /* pcap filter to use, like "! port 162" */
				if (scan_setpcapfilter(optarg) < 0) {
					usage();
				}
				break;

			case 'q': /* covertness */
				if (scan_setcovertness(atoi(optarg)) < 0) {
					usage();
				}
				break;

			case 'Q':
				if (scan_setreportquiet(1) < 0) {
					usage();
				}
				break;

			case 'r': /* rate of scan */
				if (scan_setpps(optarg) < 0) {
					usage();
				}
				break;

			case 'R': /* repeat scan n times */
				if (scan_setrepeats(atoi(optarg)) < 0) {
					usage();
				}
				break;

			case 's': /* set source ip address to optarg */
				if (scan_setsrcaddr(optarg) < 0) {
					usage();
				}
				break;

			case 'S': /* do not shuffle ports */
				if (scan_setshuffle(1) < 0) {
					usage();
				}
				break;

			case 't': /* ttl on outgoing IP datagrams */
				if (scan_setttl(optarg) < 0) {
					usage();
				}
				break;

			case 'T': /* TOS on outgoing IP datagram */
				if (scan_settos(atoi(optarg)) < 0) {
					usage();
				}
				break;

			case 'u': /* debug mask */
				if (scan_setdebug(optarg) < 0) {
					usage();
				}
				break;

			case 'U': /* do NOT translate Open/Closed in output, display as is */
				if (scan_settrans(0) < 0) {
					usage();
				}
				break;

			case 'v': /* verbose */
				if (optarg != NULL) {
					if (scan_setverbose(atoi(optarg)) < 0) usage();
				}
				else if (scan_setverboseinc() < 0) {
					usage();
				}
				break;

			case 'V':
				display_version();
				break;

			case 'w': /* write to pcap logfile optarg */
				if (scan_setsavefile(optarg) < 0) {
					usage();
				}
				break;

			case 'W': /* what stack to pretend to have */
				if (scan_setfingerprint(atoi(optarg)) < 0) {
					usage();
				}
				break;

			case 'z': /* im too lazy to run tcpdump mode */
				if (scan_setsniff(1) < 0) {
					usage();
				}
				break;

			case 'Z': /* used for cluster scanning */
				if (scan_setdronestring(optarg) < 0) {
					usage();
				}
				break;

			default:
				usage();
				break;
		} /* switch option */
	} /* getopt loop */

	/* its not set if its null, so set it, otherwise it is */
	if (s->mod_dir == NULL) {
		scan_setmoddir(MODULE_DIR);
	}

	s->argv_ext=fifo_init();

	for (; optind < argc; optind++) {
		fifo_push(s->argv_ext, xstrdup(argv[optind]));
	}

	return 1;
}


void do_targets(void) {
	union {
		void *ptr;
		char *str;
	} s_u;
	char *estr=NULL;

	for (s_u.ptr=fifo_pop(s->argv_ext); s_u.ptr != NULL; s_u.ptr=fifo_pop(s->argv_ext)) {
		if (workunit_add(s_u.str, &estr) < 0) {
			if (access(s_u.str, R_OK) == 0) {
				FILE *rfile=NULL;
				char lbuf[2048];
				char *tok=NULL, *rent=NULL;

				CLEAR(lbuf);

				rfile=fopen(s_u.str, "r");
				if (rfile == NULL) {
					continue;
				}

				while (fgets(lbuf, sizeof(lbuf) -1, rfile) != NULL) {
					for (tok=strtok_r(lbuf, "\t\r\n\v\f ", &rent); tok != NULL; tok=strtok_r(NULL, "\t\r\n\v\f ", &rent)) {
						if (workunit_add(tok, &estr) < 0) {
							ERR("cant add workunit `%s' from file `%s': %s", tok, s_u.str, estr);
						}
					}
				}

				fclose(rfile);
			}
			else {
				ERR("cant add workunit for argument `%s': %s", s_u.str, estr != NULL ? estr : ""); /* bad hostname? */
			}
		}
	}

	/* if we are not a drone */
	if (!(GET_LISTENDRONE() || GET_SENDDRONE())) {
		if (s->num_hosts < 1) {
			INF("What should i scan? I've got nothing to do.\n");
			usage();
			uexit(0);
		}
	}

	return;
}

static void usage(void) {

	INF("%s (version %s)\n"
   //xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
	"USAGE: %s [Options] Target List (ex. X.X.X.X/YY:S-E)\n"
	"-b, --broken-crc Broken CRC sums on [T]ransport, [N]etwork, or both[TN].\n"
	"-B, --source-port Source port.\n"
	"-c, --proc-duplicates Process duplicate replies.\n"
	"-d, --delay-type Delay type `%s'.\n"
	"-D, --no-defpayload  Only probe known protocols.\n"
	"-e, --enable-module  A comma separated list of modules to activate.\n"
	"-E, --proc-errors Process `non-open' responses. (ICMP errors, TCP RST, etc.).\n"
	"-G, --payload-group Group number TCP/UDP payload type selection (default all).\n"
	"-h, --help Help.\n"
	"-H, --do-dns Resolve hostnames during the reporting phase.\n"
	"-i, --interface Optional interface name, like eth0 or fxp1.\n"
	"-I, --immediate Display things as we find them.\n"
	"-j, --ignore-seq Ignore `A'll, 'R'eset sequence numbers for TCP header\n"
	"\t\tvalidation.\n"
	"-l, --logfile Write to this file not my terminal.\n"
	"-L, --packet-timeout Wait this long for packets to come back, default\n"
	"\t\tis %d secs.\n"
	"-m, --mode Scan mode, TCP/SYN scan is default, options are [U]DP, [T]CP,\n"
	"\t\tand [sf]TCP Connect. For -mT you can also specify tcp flags\n"
	"\t\tlike -mTsFpU for example that would send TCP SYN packets with\n"
	"\t\t(NO Syn|FIN|NO Push|URG)\n"
	"-M, --module-dir Modules directory.\n"
	"-o, --format Reply format, see man page for format specification\n"
	"-p, --ports Global ports to scan, if not specified in target options.\n"
	"-P, --pcap-filter Extra pcap filter string for reciever.\n"
	"-q, --covertness Covertness value from 0 to 255.\n"
	"-Q, --quiet Disable output to the screen.\n"
	"-r, --pps Packets per second in total, not per host.\n"
	"-R, --repeats Repeat packet scan N times.\n"
	"-s, --source-addr Source address for packets, `r' for random.\n"
	"-S, --no-shuffle Do not shuffle ports.\n"
	"-t, --ip-ttl Set TTL on sent packets for example, 62, 6-16 or r64-128.\n"
	"-T, --ip-tos Set TOS on sent packets.\n"
	"-u, --debug Enable debug messages. According to user provided mask.\n"
	"-U, --no-openclosed Don't say open or closed in output.\n"
	"-w, --safefile Write pcap file of recieved packets.\n"
	"-W, --fingerprint Stack to pretend to have OS fingerprints:\n"
	"\t\t0=cisco(def) 1=openbsd 2=WindowsXP 3=p0fsendsyn 4=FreeBSD\n"
	"\t\t5=nmap 6=linux 7:strangetcp\n"
	"-v, --verbose Verbose output. Support for up to -vvvvv, for really verbose.\n"
	"-V, --version Display version\n"
	"-z, --sniff Display packet parsing information.\n"
	"-Z, --drone-str Undocumented feature.\n\n"
	"Examples:\n"
	"Address ranges are CIDR like 1.2.3.4/8 for all of 1.?.?.?\n"
	"if you omit the CIDR mask then /32 is implied.\n"
	"Port ranges are like 1-4096 with 53 only scanning one port,\n"
	"`a' for all 65k and `p' for 1-1024\n"
	"%s -i eth1 -Ir 160 -E 192.168.1.0/24:1-4000 gateway:a\n\n"
	"Type `man %s` for more information about usage.",
	PROGNAME, VERSION, PROGNAME, delay_getopts(), DEF_SCANTIMEOUT, PROGNAME, PROGNAME);

	uexit(0);
}
void run_scan(void) {
	uint8_t msg_type=0, status=0, *ptr=NULL;
	size_t wk_len=0, msg_len=0;
	xpoll_t spdf[4]; /* XXX dynamic */
	union {
		uint8_t *cr;
		void *ptr;
	} w_k;
	drone_t *c=NULL;

	rfifo=fifo_init();

	if (GET_DOCONNECT()) {
		pri_work=fifo_init();
		state_tbl=TBLINIT(111);
	}

	if (s->ss->mode == MODE_TCPSCAN) s->ss->syn_key=arc4random();

	for (c=s->dlh->head  ; c != NULL ; c=c->next) {
		if (c->type == DRONE_TYPE_LISTENER && c->status == DRONE_STATUS_READY) {
			if ((w_k.ptr=get_lp_workunit(&wk_len)) != NULL) {
				if (s->verbose > 2) {
					if (s->verbose > 5) {
						MSG(M_DBG2, "Got listener workunit of size %d :]", wk_len);
					}
					MSG(M_DBG1, "sending workunit to listener");
				}

				if (send_message(c->s, MSG_WORKUNIT, MSG_STATUS_OK, w_k.cr, wk_len) < 0) {
					MSG(M_ERR, "Cant Send Workunit to listener on fd %d", c->s);
					mark_dead(c, DRONE_STATUS_DEAD);
				}

				if (c->s == -1) PANIC("WOW!!!!");

				if (get_singlemessage(c->s, &msg_type, &status, &ptr, &msg_len) != 1) {
					MSG(M_ERR, "Unexpected sequence of messages from listener on fd %d, marking dead", c->s);
					mark_dead(c, DRONE_STATUS_DEAD);
				}

				if (status != MSG_STATUS_OK) {
					MSG(M_ERR, "bad status `%d' from listener on fd %d, marking as dead", status, c->s);
					mark_dead(c, DRONE_STATUS_DEAD);
				}

				if (msg_type != MSG_READY) {
					MSG(M_ERR, "bad message `%s' from listener on fd %d, marking as dead", strmsgtype(msg_type), c->s);
					mark_dead(c, DRONE_STATUS_DEAD);
				}

				else if (s->verbose > 3) {
					MSG(M_DBG1, "Sent workunits to listener on fd %d", c->s);
				}
			}
		}
	}

	if (s->listeners == 0) {
		MSG(M_ERR, "Not enough listeners to run scan, bailing out");
		return;
	}

	while (1) {
		int readorwrite=0, breakout=0, pret=0;
		uint32_t d_offset=0;

		c=s->dlh->head;
		assert(s->dlh->size <= sizeof(spdf)); /* XXX */

		/* write loop */
		for (c=s->dlh->head, d_offset=0 ; c != NULL ; c=c->next, d_offset++) {
			if (c->type == DRONE_TYPE_SENDER) {
				void *pw_ptr=NULL;

				if (GET_DOCONNECT()) {
					while ((pw_ptr=fifo_pop(pri_work)) != NULL) {
						if (send_message(c->s, MSG_WORKUNIT, MSG_STATUS_OK, pw_ptr, sizeof(send_pri_workunit_t)) < 0) {
							MSG(M_ERR, "Cant send priority workunit to sender on fd %d, marking dead", c->s);
							mark_dead(c, DRONE_STATUS_DEAD);
						}
					}
				}

				if (c->status == DRONE_STATUS_READY) {
					/* get to work! */
					w_k.cr=NULL;
					if ((w_k.ptr=get_sp_workunit(&wk_len)) != NULL) {
						if (s->verbose > 2) {
							if (s->verbose > 5) {
								MSG(M_DBG2, "Got workunit of size %d :]", wk_len);
							}
							MSG(M_DBG1, "sending workunit to sender");
						}

						if (send_message(c->s, MSG_WORKUNIT, MSG_STATUS_OK, w_k.cr, wk_len) < 0) {
							MSG(M_ERR, "Cant Send Workunit to sender on fd %d", c->s);
							mark_dead(c, DRONE_STATUS_DEAD);
						}
						else if (s->verbose > 3) {
							MSG(M_DBG1, "Sent workunits to senders");
						}
						c->status=DRONE_STATUS_WORKING;
						readorwrite=1;
					}
					else {
						if (s->verbose > 3) MSG(M_DBG1, "Marking sender on fd %d as done, no more workunits to send", c->s);
						send_message(c->s, MSG_QUIT, MSG_STATUS_OK, ptr, 0);
						mark_dead(c, DRONE_STATUS_DONE);
					}
				}
			}
			spdf[d_offset].fd=c->s;
		}
		if (!(s->senders)) {
			breakout++;
			break;
		}

		if ((pret=xpoll(&spdf[0], s->dlh->size, -1)) < 0) {
			MSG(M_ERR, "Poll drone fd's fail: %s", strerror(errno));
		}

		for (c=s->dlh->head, d_offset=0 ; c != NULL ; c=c->next, d_offset++) {
			c->s_rw=0;
			if (c->status != DRONE_STATUS_DEAD && c->status != DRONE_STATUS_DONE) {
				c->s_rw=spdf[d_offset].rw;
			}
			if (spdf[d_offset].rw & XPOLL_READABLE) {
				if (s->verbose > 4) MSG(M_DBG1, "Socket type %s is readable", (c->type == DRONE_TYPE_LISTENER) ? "Listener" : "Sender");
			}
		}

		/* read loop */
		for (c=s->dlh->head, d_offset=0 ; c != NULL ; c=c->next, d_offset++) {
			if (c->status != DRONE_STATUS_DEAD && c->status != DRONE_STATUS_DONE && c->s_rw & XPOLL_READABLE) {
				int getret=0;
				if (s->verbose > 5) MSG(M_DBG2, "Reading file descriptor %d type %s and %d senders left", c->s, (c->type == DRONE_TYPE_SENDER ? "Sender" : "Listener"), s->senders);

				if (recv_messages(c->s) < 0) {
					MSG(M_ERR, "Cant recieve messages from fd %d, marking as dead", c->s);
					mark_dead(c, DRONE_STATUS_DEAD);
					continue;
				}

				while (1) {
					if (c->status == DRONE_STATUS_DONE || c->status == DRONE_STATUS_DEAD) break;
					getret=get_message(c->s, &msg_type, &status, &ptr, &msg_len);
					if (getret < 1) break;
					if (msg_type == MSG_ERROR || status != MSG_STATUS_OK) {
						MSG(M_ERR, "Drone on fd %d is dead, closing socket and marking dead", c->s);
						mark_dead(c, DRONE_STATUS_DEAD);
						break;
					}
					else if (msg_type == MSG_WORKDONE && c->type == DRONE_TYPE_SENDER) {
						if (s->verbose > 5) MSG(M_DBG2, "Setting sender back to ready state after workdone message");
						c->status=DRONE_STATUS_READY;
					}
					else if (msg_type == MSG_OUTPUT && c->type == DRONE_TYPE_LISTENER) {
						if (s->ss->mode == MODE_TCPSCAN || s->ss->mode == MODE_UDPSCAN) {
							if (msg_len < sizeof(ip_report_t)) {
								MSG(M_ERR, "Unknown report format from listener");
							}
							else {
								handle_ipoutput(ptr);
							}
						}
						else if (s->ss->mode == MODE_ARPSCAN) {
							handle_arpoutput(ptr);
						}

					}
					else {
						MSG(M_ERR, "Unhandled message from `%s' drone message type `%s' with status %d", (c->type == DRONE_TYPE_SENDER ? "Sender" : "Listener"), strmsgtype(msg_type), status);
					}
					if (getret == 0) break;
				} /* multiple message read loop */
			} /* readable fd */
		}
		if (breakout) break;
	}

	if (s->verbose > 3) MSG(M_DBG1, "###### Waiting for listener packet timeout %d seconds", s->ss->recv_timeout);

	if (1) {
		unsigned int remain=s->ss->recv_timeout;

		while (1) {
			remain=sleep(remain);
			if (remain == 0) {
				break;
			}
		}
	}

	while (1) {
		uint32_t d_offset=0;
		int pret=0;

		for (c=s->dlh->head ; c != NULL ; c=c->next) {
			if (c->type != DRONE_TYPE_LISTENER) {
				if (s->verbose > 7) MSG(M_DBG2, "skipping drone type %d", c->type);
				continue;
			}
			if (c->status == DRONE_STATUS_DEAD) {
				if (s->verbose > 5) MSG(M_DBG2, "skipping dead drone type %d", c->type);
				continue;
			}

			if (c->status == DRONE_STATUS_READY && !(GET_LISTENDRONE())) {
				if (send_message(c->s, MSG_TERMINATE, MSG_STATUS_OK, NULL, 0) < 0) {
					MSG(M_ERR, "Can't tell listener to quit, this scan is useless");
					mark_dead(c, DRONE_STATUS_DEAD);
					continue;
				}
				if (s->verbose > 6) MSG(M_DBG2, "Told listener on fd %d to go into reporting mode", c->s);
				c->status=DRONE_STATUS_WORKING;
			}
		}

		for (c=s->dlh->head, d_offset=0 ; c != NULL ; c=c->next, d_offset++) {
			spdf[d_offset].fd=c->s;
		}

		if (s->listeners && (pret=xpoll(&spdf[0], s->dlh->size, -1)) < 0) {
			MSG(M_ERR, "Poll drone fd's fail: %s", strerror(errno));
		}

		for (c=s->dlh->head, d_offset=0 ; c != NULL ; c=c->next, d_offset++) {
			c->s_rw=0;
			if (c->status != DRONE_STATUS_DEAD) c->s_rw=spdf[d_offset].rw;
			if (spdf[d_offset].rw & XPOLL_READABLE) {
				if (s->verbose > 7) MSG(M_DBG1, "Socket type %s is readable", (c->type == DRONE_TYPE_LISTENER) ? "Listener" : "Sender");
			}
		}

		for (c=s->dlh->head ; c != NULL ; c=c->next) {
			if (c->status != DRONE_STATUS_DEAD && c->status != DRONE_STATUS_DONE && c->s_rw & XPOLL_READABLE) {
				int getret=0;

				if (recv_messages(c->s) < 0) {
					MSG(M_ERR, "read fd %d fails, marking as dead", c->s);
					mark_dead(c, DRONE_STATUS_DEAD);
					continue;
				}

				while (1) {
					if (c->status == DRONE_STATUS_DONE || c->status == DRONE_STATUS_DEAD) break;
					getret=get_message(c->s, &msg_type, &status, &ptr, &msg_len);
					if (getret < 1) break;
					if (s->verbose > 5) MSG(M_DBG2, "Got message type `%s [%d]' from a Listener Drone with status %d and %p data", strmsgtype(msg_type), msg_type, status, ptr);
					if (msg_type == MSG_ERROR || status != MSG_STATUS_OK) {
						MSG(M_ERR, "Got bad message from listener on fd %d, marking as dead", c->s);
						mark_dead(c, DRONE_STATUS_DEAD);
						continue;
					}
					else if (msg_type == MSG_OUTPUT) {
						if (s->ss->mode == MODE_TCPSCAN || s->ss->mode == MODE_UDPSCAN) {
							if (msg_len < sizeof(ip_report_t)) {
								MSG(M_ERR, "Unknown report format from listener on fd %d", c->s);
							}
							else {
								handle_ipoutput(ptr);
							}
						}
						else if (s->ss->mode == MODE_ARPSCAN) {
							handle_arpoutput(ptr);
						}
					}
					else if (msg_type == MSG_QUIT) {
						mark_dead(c, DRONE_STATUS_DONE);
					}
					else {
						MSG(M_ERR, "Unknown message from listener %d on fd %d, marking as dead", msg_type, c->s);
						/* hrmm, welp i dont get this drone, lets stop talking to him */
						mark_dead(c, DRONE_STATUS_DEAD);
					}
					if (getret == 0) break;
				} /* while messages are read */
			}
		} /* for reading listeners */
		if (s->listeners == 0) break;
	}

	if (s->ss->mode == MODE_UDPSCAN || s->ss->mode == MODE_TCPSCAN) {
		do_report();
	}
	else if (s->ss->mode == MODE_ARPSCAN) {
		do_arpreport();
	}
		
}