"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. For more information about "connecter.c" see the Fossies "Dox" file reference documentation.

    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 }