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); }
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(); } }