"Fossies" - the Fresh Open Source Software Archive

Member "scanssh-2.1/connecter.c" (30 Nov 2004, 18054 Bytes) of package /linux/privat/old/scanssh-2.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /*
    2  * Copyright 2000-2004 (c) Niels Provos <provos@citi.umich.edu>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. The name of the author may not be used to endorse or promote products
   14  *    derived from this software without specific prior written permission.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   26  */
   27 
   28 #include <sys/types.h>
   29 
   30 #ifdef HAVE_CONFIG_H
   31 #include "config.h"
   32 #endif
   33 
   34 #include <sys/tree.h>
   35 #include <sys/queue.h>
   36 #include <sys/socket.h>
   37 #include <sys/time.h>
   38 #include <netinet/in.h>
   39 
   40 #include <stdlib.h>
   41 #include <stdio.h>
   42 #include <unistd.h>
   43 #include <netdb.h>
   44 #include <errno.h>
   45 #include <string.h>
   46 #include <signal.h>
   47 #include <fcntl.h>
   48 #include <ctype.h>
   49 #include <err.h>
   50 
   51 #include <event.h>
   52 #include <dnet.h>
   53 
   54 #include "scanssh.h"
   55 #include "socks.h"
   56 
   57 #ifdef DEBUG
   58 extern int debug;
   59 #define DFPRINTF(x) if (debug) fprintf x
   60 #else
   61 #define DFPRINTF(x)
   62 #endif
   63 
   64 
   65 /* Global imports */
   66 
   67 extern struct queue_list readyqueue;
   68 extern int ssh_sendident;
   69 extern char *ssh_ipalias;
   70 
   71 extern struct scanner **ss_scanners;
   72 extern int ss_nscanners;
   73 
   74 extern struct socksq socks_host;
   75 
   76 extern rand_t *ss_rand;
   77 
   78 /* Local globals */
   79 int scan_nhosts;        /* Number of hosts that we are scanning */
   80 
   81 #define HTTP_SCAN   "HEAD /index.html HTTP/1.0\n\n"
   82 
   83 void ssh_init(struct bufferevent *bev, struct argument *arg);
   84 void ssh_finalize(struct bufferevent *bev, struct argument *arg);
   85 void ssh_readcb(struct bufferevent *bev, void *parameter);
   86 void ssh_writecb(struct bufferevent *bev, void *parameter);
   87 void ssh_errorcb(struct bufferevent *bev, short what, void *parameter);
   88 
   89 void socks_init(struct bufferevent *bev, struct argument *arg);
   90 void socks_finalize(struct bufferevent *bev, struct argument *arg);
   91 
   92 void socks5_readcb(struct bufferevent *bev, void *parameter);
   93 void socks5_writecb(struct bufferevent *bev, void *parameter);
   94 void socks5_errorcb(struct bufferevent *bev, short what, void *parameter);
   95 
   96 void socks4_readcb(struct bufferevent *bev, void *parameter);
   97 void socks4_writecb(struct bufferevent *bev, void *parameter);
   98 void socks4_errorcb(struct bufferevent *bev, short what, void *parameter);
   99 
  100 void http_init(struct bufferevent *bev, struct argument *arg);
  101 void http_finalize(struct bufferevent *bev, struct argument *arg);
  102 void http_readcb(struct bufferevent *bev, void *parameter);
  103 void http_writecb(struct bufferevent *bev, void *parameter);
  104 void http_errorcb(struct bufferevent *bev, short what, void *parameter);
  105 
  106 void http_connect_readcb(struct bufferevent *bev, void *parameter);
  107 void http_connect_writecb(struct bufferevent *bev, void *parameter);
  108 
  109 void telnet_init(struct bufferevent *bev, struct argument *arg);
  110 void telnet_finalize(struct bufferevent *bev, struct argument *arg);
  111 void telnet_readcb(struct bufferevent *bev, void *parameter);
  112 void telnet_writecb(struct bufferevent *bev, void *parameter);
  113 void telnet_errorcb(struct bufferevent *bev, short what, void *parameter);
  114 
  115 struct scanner scanners[] = {
  116     {
  117         "ssh",
  118         "finds versions for SSH, Web and SMTP servers",
  119         ssh_init,
  120         ssh_finalize,
  121         ssh_readcb,
  122         ssh_writecb,
  123         ssh_errorcb
  124     },
  125     {
  126         "socks5",
  127         "detects SOCKS v5 proxy",
  128         socks_init,
  129         socks_finalize,
  130         socks5_readcb,
  131         socks5_writecb,
  132         socks5_errorcb
  133     },
  134     {
  135         "socks4",
  136         "detects SOCKS v4 proxy",
  137         socks_init,
  138         socks_finalize,
  139         socks4_readcb,
  140         socks4_writecb,
  141         socks4_errorcb
  142     },
  143     {
  144         "http-proxy",
  145         "detects HTTP get proxy",
  146         http_init,
  147         http_finalize,
  148         http_readcb,
  149         http_writecb,
  150         http_errorcb
  151     },
  152     {
  153         "http-connect",
  154         "detects HTTP connect proxy",
  155         http_init,
  156         http_finalize,
  157         http_connect_readcb,
  158         http_connect_writecb,
  159         http_errorcb
  160     },
  161     {
  162         "telnet-proxy",
  163         "detects telnet proxy",
  164         telnet_init,
  165         telnet_finalize,
  166         telnet_readcb,
  167         telnet_writecb,
  168         telnet_errorcb
  169     },
  170     {
  171         NULL, NULL, NULL, NULL
  172     }
  173 };
  174 
  175 void
  176 scanner_print(char *pre)
  177 {
  178     struct scanner *myscan = &scanners[0];
  179 
  180     while (myscan->name != NULL) {
  181         fprintf(stderr, "%s%12s\t%s\n",
  182             pre, myscan->name, myscan->description);
  183         myscan++;
  184     }
  185 }
  186 
  187 struct scanner *
  188 scanner_find(char *scanner)
  189 {
  190     struct scanner *myscan = &scanners[0];
  191 
  192     while (myscan->name != NULL) {
  193         if (strcmp(myscan->name, scanner) == 0)
  194             return (myscan);
  195         myscan++;
  196     }
  197 
  198     return (NULL);
  199 }
  200 
  201 #define SSH_DIDWRITE    0x0001
  202 #define SSH_GOTREAD 0x0002
  203 
  204 struct ssh_state {
  205     int nlines;
  206     char *firstline;
  207 };
  208 
  209 void 
  210 ssh_init(struct bufferevent *bev, struct argument *arg)
  211 {
  212     if ((arg->a_state = calloc(1, sizeof(struct ssh_state))) == NULL)
  213         err(1, "%s: calloc", __func__);
  214 
  215     arg->a_flags = 0;
  216 }
  217 
  218 void 
  219 ssh_finalize(struct bufferevent *bev, struct argument *arg)
  220 {
  221     struct ssh_state *state = arg->a_state;
  222 
  223     if (state->firstline)
  224         free(state->firstline);
  225     free(arg->a_state);
  226     arg->a_state = NULL;
  227     arg->a_flags = 0;
  228 }
  229 
  230 int
  231 ssh_process_line(struct evbuffer *input, struct argument *arg)
  232 {
  233     struct ssh_state *state = arg->a_state;
  234     while (1) {
  235         size_t off = 0;
  236         char *p = EVBUFFER_DATA(input);
  237 
  238         while (off < EVBUFFER_LENGTH(input)) {
  239             if (*p == '\r') {
  240                 *p = '\0';
  241             } else if (*p == '\n') {
  242                 *p = '\0';
  243                 break;
  244             }
  245             p++;
  246             off++;
  247         }
  248 
  249         if (off == EVBUFFER_LENGTH(input))
  250             return (-1);
  251 
  252         off++;
  253         p = EVBUFFER_DATA(input);
  254 
  255         state->nlines++;
  256         if (state->firstline == NULL && isprint(*p))
  257             state->firstline = strdup(p);
  258 
  259         if (strncmp(p, "SSH-", 4) == 0) {
  260             postres(arg, p);
  261             return (1);
  262         } else if (strncasecmp(p, "Server: ", 8) == 0) {
  263             postres(arg, p + 8);
  264             return (1);
  265         }
  266 
  267         if (state->nlines > 50) {
  268             postres(arg, "<error: too many lines>");
  269             return (0);
  270         }
  271 
  272         evbuffer_drain(input, off);
  273     }
  274 }
  275 
  276 void
  277 ssh_readcb(struct bufferevent *bev, void *parameter)
  278 {
  279     struct argument *arg = parameter;
  280     int res;
  281 
  282     DFPRINTF((stderr, "%s: called\n", __func__));
  283 
  284     if ((res = ssh_process_line(EVBUFFER_INPUT(bev), arg)) == -1)
  285         return;
  286 
  287     if (res == 0) {
  288         ssh_errorcb(bev, EVBUFFER_READ | EVBUFFER_TIMEOUT, arg);
  289         return;
  290     }
  291 
  292     arg->a_flags |= SSH_GOTREAD;
  293     if (!ssh_sendident || (arg->a_flags & SSH_DIDWRITE))
  294         scanhost_return(bev, arg, 1);
  295     return;
  296 }
  297 
  298 void
  299 ssh_writecb(struct bufferevent *bev, void *parameter)
  300 {
  301     struct argument *arg = parameter;
  302 
  303     DFPRINTF((stderr, "%s: called\n", __func__));
  304 
  305     if (!ssh_sendident || (arg->a_flags & SSH_DIDWRITE)) {
  306         if (arg->a_flags & SSH_GOTREAD)
  307             scanhost_return(bev, arg, 1);
  308         return;
  309     }
  310 
  311     if (arg->a_ports[0].port == 80)
  312         bufferevent_write(bev, HTTP_SCAN, strlen(HTTP_SCAN));
  313     else
  314         bufferevent_write(bev, SSHMAPVERSION, sizeof(SSHMAPVERSION));
  315     arg->a_flags |= SSH_DIDWRITE;
  316 }
  317 
  318 void
  319 ssh_errorcb(struct bufferevent *bev, short what, void *parameter)
  320 {
  321     struct argument *arg = parameter;
  322     struct ssh_state *state = arg->a_state;
  323     int success = 0;
  324 
  325     if (state->firstline) {
  326         postres(arg, state->firstline);
  327         success = 1;
  328     } else {
  329         postres(arg, "<ssh error on %s:%s%s%s: %s>",
  330             what & EV_READ ? "read" : "write",
  331             what & EVBUFFER_ERROR ? " EV_ERROR" : "",
  332             what & EVBUFFER_EOF ? " EV_EOF" : "",
  333             what & EVBUFFER_TIMEOUT ? " EV_TIMEOUT" : "",
  334             strerror(errno));
  335         success = 0;
  336     }
  337     scanhost_return(bev, arg, success);
  338 }
  339 
  340 /* Either connect or bind */
  341 
  342 int
  343 make_socket_ai(int (*f)(int, const struct sockaddr *, socklen_t),
  344     struct addrinfo *ai)
  345 {
  346         struct linger linger;
  347         int fd, on = 1;
  348 
  349         /* Create listen socket */
  350         fd = socket(AF_INET, SOCK_STREAM, 0);
  351         if (fd == -1) {
  352                 warn("socket");
  353                 return (-1);
  354         }
  355 
  356         if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
  357                 warn("fcntl(O_NONBLOCK)");
  358                 goto out;
  359         }
  360 
  361         if (fcntl(fd, F_SETFD, 1) == -1) {
  362                 warn("fcntl(F_SETFD)");
  363                 goto out;
  364         }
  365 
  366         setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on));
  367         setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(on));
  368         linger.l_onoff = 1;
  369         linger.l_linger = 5;
  370         setsockopt(fd, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger));
  371 
  372         if ((f)(fd, ai->ai_addr, ai->ai_addrlen) == -1) {
  373         if (errno != EINPROGRESS) {
  374             warn("%s", __func__);
  375             goto out;
  376         }
  377         }
  378 
  379     return (fd);
  380 
  381  out:
  382     close(fd);
  383     return (-1);
  384 }
  385 
  386 int
  387 make_socket(int (*f)(int, const struct sockaddr *, socklen_t),
  388     char *address, uint16_t port)
  389 {
  390         struct addrinfo ai, *aitop;
  391         char strport[NI_MAXSERV];
  392     int fd;
  393     
  394         memset(&ai, 0, sizeof (ai));
  395         ai.ai_family = AF_INET;
  396         ai.ai_socktype = SOCK_STREAM;
  397         ai.ai_flags = f != connect ? AI_PASSIVE : 0;
  398         snprintf(strport, sizeof (strport), "%d", port);
  399         if (getaddrinfo(address, strport, &ai, &aitop) != 0) {
  400                 warn("getaddrinfo");
  401                 return (-1);
  402         }
  403         
  404     fd = make_socket_ai(f, aitop);
  405 
  406     freeaddrinfo(aitop);
  407 
  408     return (fd);
  409 }
  410 
  411 int
  412 scanhost_check_socketerror(struct argument *arg, short what)
  413 {
  414     int error;
  415     socklen_t errsz = sizeof(error);
  416     int fd = arg->a_fd;
  417 
  418     if (what == EV_TIMEOUT) {
  419         postres(arg, "<timeout>");
  420         goto error;
  421     }
  422 
  423     /* Check if the connection completed */
  424     if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &errsz) == -1) {
  425         warn("%s: getsockopt for %d", __func__, fd);
  426         postres(arg, "<error: getsockopt>");
  427         goto error;
  428     }
  429 
  430     if (error) {
  431         if (error == ECONNREFUSED) {
  432             postres(arg, "<refused>");
  433         } else {
  434             warnx("%s: getsockopt: %s", __func__, strerror(error));
  435             postres(arg, "<errror: getsockopt>");
  436         }
  437         goto error;
  438     }
  439 
  440     return (0);
  441 
  442  error:
  443     scanhost_return(NULL, arg, 0);
  444     return (-1);
  445 }
  446 
  447 struct bufferevent *
  448 scanhost_postconnect_setup(struct argument *arg)
  449 {
  450     struct bufferevent *bev = NULL;
  451     int fuzz;
  452 
  453     /* We successfully connected to the host */
  454 
  455     bev = bufferevent_new(arg->a_fd,
  456         arg->a_scanner->readcb,
  457         arg->a_scanner->writecb,
  458         arg->a_scanner->errorcb, arg);
  459     if (bev == NULL) {
  460         warnx("%s: bufferevent_new", __func__);
  461         postres(arg, "<error: memory>");
  462         goto error;
  463     }
  464 
  465     fuzz = rand_uint16(ss_rand) % 10;
  466     bufferevent_settimeout(bev, SHORTWAIT + fuzz, SHORTWAIT + fuzz);
  467     bufferevent_enable(bev, EV_READ|EV_WRITE);
  468 
  469     (*arg->a_scanner->init)(bev, arg);
  470 
  471     return (bev);
  472 
  473  error:
  474     scanhost_return(NULL, arg, 0);
  475     return (NULL);
  476 }
  477 
  478 void
  479 scanhost_connectcb(int fd, short what, void *parameter)
  480 {
  481     struct argument *arg = parameter;
  482 
  483     if (scanhost_check_socketerror(arg, what) == -1)
  484         return;
  485 
  486     scanhost_postconnect_setup(arg);
  487 }
  488 
  489 static void
  490 socks_readcb(struct bufferevent *bev, void *parameter)
  491 {
  492     struct argument *arg = parameter;
  493     struct bufferevent *newbev = NULL;
  494     struct socks4_cmd reply;
  495     
  496     DFPRINTF((stderr, "%s: called\n", __func__));
  497 
  498     if (EVBUFFER_LENGTH(bev->input) < sizeof(reply))
  499         goto error;
  500 
  501     bufferevent_read(bev, &reply, sizeof(reply));
  502     DFPRINTF((stderr, "Version: %d, Reply: %d\n",
  503              reply.version, reply.command));
  504 
  505     if (0 != reply.version)
  506         goto error;
  507 
  508     switch (reply.command) {
  509     case SOCKS4_RESP_SUCCESS:
  510         break;
  511     case SOCKS4_RESP_FAILURE:
  512         postres(arg, "<socks error: server failure>");
  513         goto done;
  514     case SOCKS4_RESP_NOIDENT:
  515         postres(arg, "<socks error: no ident>");
  516         goto done;
  517     case SOCKS4_RESP_BADIDENT:
  518         postres(arg, "<socks error: bad ident>");
  519         goto done;
  520     default:
  521         postres(arg, "<socks error: response>");
  522         goto done;
  523     }
  524 
  525     /* We need to unregister the event's first due to a bug in libevent */
  526     bufferevent_disable(bev, EV_READ|EV_WRITE);
  527 
  528     /* Call the original connect callback to take care of the rest */
  529     if ((newbev = scanhost_postconnect_setup(arg)) != NULL) {
  530         evbuffer_add_buffer(newbev->input, bev->input);
  531         /*
  532          * If we have more data buffered, the we need to append it
  533          * to the new read buffer and if necessary call the read
  534          * callback.
  535          * Unfortunately, this assumes a lot about the internals of
  536          * libevent.
  537          */
  538         if (EVBUFFER_LENGTH(newbev->input))
  539             newbev->readcb(newbev, newbev->cbarg);
  540     }
  541 
  542     bufferevent_free(bev);
  543     return;
  544 
  545  error:
  546     postres(arg, "<socks read error>");
  547 
  548  done:
  549     bufferevent_free(bev);
  550     scanhost_return(NULL, arg, 0);
  551 }
  552 
  553 static void
  554 socks_writecb(struct bufferevent *bev, void *parameter)
  555 {
  556     struct argument *arg = parameter;
  557     struct socks4_cmd cmd;
  558 
  559     DFPRINTF((stderr, "%s: called\n", __func__));
  560 
  561     if (arg->a_flags != 0)
  562         return;
  563 
  564     /* Connect to the remote server */
  565     memset(&cmd, 0, sizeof(cmd));
  566     cmd.version = SOCKS_VERSION4;
  567     cmd.command = SOCKS_CMD_CONNECT;
  568     cmd.dstport = htons(arg->a_ports[0].port);
  569     memcpy(&cmd.address.s_addr, &arg->addr.addr_ip,
  570         sizeof(struct in_addr));
  571 
  572     bufferevent_write(bev, &cmd, sizeof(cmd));
  573     bufferevent_write(bev, SSHUSERAGENT, sizeof(SSHUSERAGENT));
  574 
  575     arg->a_flags = SOCKS_WAITING_COMMANDRESPONSE;
  576     bufferevent_enable(bev, EV_READ);
  577 }
  578 
  579 void
  580 socks_errorcb(struct bufferevent *bev, short what, void *parameter)
  581 {
  582     struct argument *arg = parameter;
  583 
  584     DFPRINTF((stderr, "%s: called\n", __func__));
  585 
  586     postres(arg, "<socks error on %s:%s%s%s: %s>",
  587         what & EV_READ ? "read" : "write",
  588         what & EVBUFFER_ERROR ? " EV_ERROR" : "",
  589         what & EVBUFFER_EOF ? " EV_EOF" : "",
  590         what & EVBUFFER_TIMEOUT ? " EV_TIMEOUT" : "",
  591         strerror(errno));
  592     bufferevent_free(bev),
  593     scanhost_return(NULL, arg, -1);
  594 }
  595 
  596 void
  597 scanhost_socks_connectcb(int fd, short what, void *parameter)
  598 {
  599     struct argument *arg = parameter;
  600     struct bufferevent *bev = NULL;
  601 
  602     if (scanhost_check_socketerror(arg, what) == -1)
  603         return;
  604 
  605     /* We successfully connected to the host */
  606 
  607     bev = bufferevent_new(arg->a_fd, socks_readcb, socks_writecb,
  608         socks_errorcb, arg);
  609     if (bev == NULL) {
  610         warnx("%s: bufferevent_new", __func__);
  611         postres(arg, "<error: memory>");
  612         goto error;
  613     }
  614 
  615     bufferevent_settimeout(bev, 30, 30);
  616     bufferevent_disable(bev, EV_READ);
  617     bufferevent_enable(bev, EV_WRITE);
  618 
  619     arg->a_flags = 0;   
  620 
  621     return;
  622 
  623  error:
  624     scanhost_return(NULL, arg, 0);
  625     return;
  626 }
  627 
  628 int
  629 scanhost(struct argument *arg)
  630 {
  631     struct timeval tv;
  632     uint16_t port = arg->a_ports[0].port;
  633     void (*cb)(int, short, void *);
  634 
  635     arg->a_flags = 0;
  636     if (TAILQ_FIRST(&socks_host) == NULL) {
  637         arg->a_fd = make_socket(connect, addr_ntoa(&arg->addr), port);
  638         if (arg->a_fd == -1)
  639             return (-1);
  640 
  641         cb = scanhost_connectcb;
  642     } else {
  643         struct socks_host *single_host = TAILQ_FIRST(&socks_host);
  644 
  645         /* Rotate the entries around */
  646         TAILQ_REMOVE(&socks_host, single_host, next);
  647         TAILQ_INSERT_TAIL(&socks_host, single_host, next);
  648 
  649         arg->a_fd = make_socket(connect,
  650             addr_ntoa(&single_host->host), single_host->port);
  651         if (arg->a_fd == -1)
  652             return (-1);
  653         cb = scanhost_socks_connectcb;
  654     }
  655 
  656     event_set(&arg->ev, arg->a_fd, EV_WRITE, cb, arg);
  657 
  658     timerclear(&tv);
  659     tv.tv_sec = LONGWAIT;
  660     event_add(&arg->ev, &tv);
  661 
  662     return (0);
  663 }
  664 
  665 /*
  666  * Success parameter:
  667  * -2 - scanner timeout, stop scanning and go to next host.
  668  * -1 - scanner reset?, stop scanning, go to next port.
  669  *  0 - current scanner failed, continue with next scanner
  670  *  1 - current scanner succeeded, stop scanning and report success
  671  */
  672 
  673 void
  674 scanhost_return(struct bufferevent *bev, struct argument *arg, int success)
  675 {
  676     int done = 0;
  677 
  678     if (bev != NULL) {
  679         (*arg->a_scanner->finalize)(bev, arg);
  680         bufferevent_free(bev);
  681     }
  682 
  683     close(arg->a_fd);
  684     arg->a_fd = -1;
  685     scan_nhosts--;
  686 
  687     /*
  688      * If we had success we remove the port, otherwise we attempt to
  689      * use a different scanner on it.
  690      */
  691     arg->a_scanneroff++;
  692     if (success == -2) {
  693         printres(arg, arg->a_ports[0].port, "<timeout>");
  694 
  695         /* timeout - host is down */
  696         while (arg->a_nports)
  697             ports_remove(arg, arg->a_ports[0].port);
  698 
  699     } else if (success == -1) {
  700         /* reset? */
  701         printres(arg, arg->a_ports[0].port, "<refused>");
  702         done = 1;
  703 
  704     } else if (bev != NULL && !success &&
  705         arg->a_scanneroff < ss_nscanners) {
  706         arg->a_scanner = ss_scanners[arg->a_scanneroff];
  707     } else {
  708         printres(arg, arg->a_ports[0].port, arg->a_res);
  709         done = 1;
  710     }
  711 
  712     if (done) {
  713         arg->a_scanneroff = 0;
  714         arg->a_scanner = ss_scanners[0];
  715         ports_remove(arg, arg->a_ports[0].port);
  716     }
  717 
  718     if (arg->a_nports == 0) {
  719         argument_free(arg);
  720         if (TAILQ_FIRST(&readyqueue) == NULL && 
  721             !probe_haswork() && !scan_nhosts) {
  722             struct timeval tv;
  723             timerclear(&tv);
  724             event_loopexit(&tv);
  725             return;
  726         }
  727         goto done;
  728     }
  729 
  730     /* 
  731      * Insert at the beginning of the list, so that hosts get completed
  732      * faster.  Otherwise, insertion at the end of a list causes the list
  733      * to grow longer and longer without completing hosts.
  734      */
  735     TAILQ_INSERT_HEAD(&readyqueue, arg, a_next);
  736 
  737  done:
  738     /* Cause another host to be contacted */
  739     scanhost_fromlist();
  740 }
  741 
  742 void
  743 scanhost_ready(struct argument *arg)
  744 {
  745     TAILQ_INSERT_TAIL(&readyqueue, arg, a_next);
  746     scanhost_fromlist();
  747 }
  748 
  749 void
  750 scanhost_fromlist(void)
  751 {
  752     extern int max_scanqueue_size;
  753     struct argument *arg;
  754     while (scan_nhosts < max_scanqueue_size &&
  755         (arg = TAILQ_FIRST(&readyqueue)) != NULL) {
  756 
  757         /* Out of file descriptors, we need to try again later */
  758         if (scanhost(arg) == -1) {
  759             TAILQ_REMOVE(&readyqueue, arg, a_next);
  760             TAILQ_INSERT_TAIL(&readyqueue, arg, a_next);
  761             break;
  762         }
  763 
  764         TAILQ_REMOVE(&readyqueue, arg, a_next);
  765         scan_nhosts++;
  766     }
  767 }