"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 }