|
Lines 45-50
Link Here
|
| 45 |
#include "atomicio.h" |
45 |
#include "atomicio.h" |
| 46 |
#include "misc.h" |
46 |
#include "misc.h" |
| 47 |
#include "hostfile.h" |
47 |
#include "hostfile.h" |
|
|
48 |
#include "canohost.h" |
| 48 |
|
49 |
|
| 49 |
/* Flag indicating whether IPv4 or IPv6. This can be set on the command line. |
50 |
/* Flag indicating whether IPv4 or IPv6. This can be set on the command line. |
| 50 |
Default value is AF_UNSPEC means both IPv4 and IPv6. */ |
51 |
Default value is AF_UNSPEC means both IPv4 and IPv6. */ |
|
Lines 61-66
Link Here
|
| 61 |
|
62 |
|
| 62 |
int hash_hosts = 0; /* Hash hostname on output */ |
63 |
int hash_hosts = 0; /* Hash hostname on output */ |
| 63 |
|
64 |
|
|
|
65 |
int log_all_failures = 0; /* list all hosts checked */ |
| 66 |
|
| 64 |
#define MAXMAXFD 256 |
67 |
#define MAXMAXFD 256 |
| 65 |
|
68 |
|
| 66 |
/* The number of seconds after which to give up on a TCP connection */ |
69 |
/* The number of seconds after which to give up on a TCP connection */ |
|
Lines 70-75
Link Here
|
| 70 |
#define MAXCON (maxfd - 10) |
73 |
#define MAXCON (maxfd - 10) |
| 71 |
|
74 |
|
| 72 |
extern char *__progname; |
75 |
extern char *__progname; |
|
|
76 |
extern int connclosed; |
| 73 |
fd_set *read_wait; |
77 |
fd_set *read_wait; |
| 74 |
size_t read_wait_nfdset; |
78 |
size_t read_wait_nfdset; |
| 75 |
int ncon; |
79 |
int ncon; |
|
Lines 92-97
Link Here
|
| 92 |
int c_len; /* Total bytes which must be read. */ |
96 |
int c_len; /* Total bytes which must be read. */ |
| 93 |
int c_off; /* Length of data read so far. */ |
97 |
int c_off; /* Length of data read so far. */ |
| 94 |
int c_keytype; /* Only one of KT_RSA1, KT_DSA, or KT_RSA */ |
98 |
int c_keytype; /* Only one of KT_RSA1, KT_DSA, or KT_RSA */ |
|
|
99 |
int c_connclosed; /* = 1 if previous closed connection */ |
| 95 |
char *c_namebase; /* Address to free for c_name and c_namelist */ |
100 |
char *c_namebase; /* Address to free for c_name and c_namelist */ |
| 96 |
char *c_name; /* Hostname of connection for errors */ |
101 |
char *c_name; /* Hostname of connection for errors */ |
| 97 |
char *c_namelist; /* Pointer to other possible addresses */ |
102 |
char *c_namelist; /* Pointer to other possible addresses */ |
|
Lines 243-248
Link Here
|
| 243 |
{ |
248 |
{ |
| 244 |
int j; |
249 |
int j; |
| 245 |
|
250 |
|
|
|
251 |
/* |
| 252 |
* New fd and socket. Clear the possibly cached IP-address of the |
| 253 |
* remote host (kex.c:canonical_host_ip) of the previous socket. Also |
| 254 |
* ensure that the packet_read_seqnr():Connection closed ..." flag is |
| 255 |
* clear (called by dispatch_run()). |
| 256 |
*/ |
| 257 |
clear_cached_addr(); |
| 258 |
connclosed = 0; |
| 259 |
|
| 246 |
packet_set_connection(c->c_fd, c->c_fd); |
260 |
packet_set_connection(c->c_fd, c->c_fd); |
| 247 |
enable_compat20(); |
261 |
enable_compat20(); |
| 248 |
myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = c->c_keytype == KT_DSA? |
262 |
myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = c->c_keytype == KT_DSA? |
|
Lines 296-303
Link Here
|
| 296 |
memset(&hints, 0, sizeof(hints)); |
310 |
memset(&hints, 0, sizeof(hints)); |
| 297 |
hints.ai_family = IPv4or6; |
311 |
hints.ai_family = IPv4or6; |
| 298 |
hints.ai_socktype = SOCK_STREAM; |
312 |
hints.ai_socktype = SOCK_STREAM; |
| 299 |
if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) |
313 |
if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) { |
| 300 |
fatal("getaddrinfo %s: %s", host, ssh_gai_strerror(gaierr)); |
314 |
error("getaddrinfo %s: %s", host, ssh_gai_strerror(gaierr)); |
|
|
315 |
s = -1; |
| 316 |
return s; |
| 317 |
} |
| 301 |
for (ai = aitop; ai; ai = ai->ai_next) { |
318 |
for (ai = aitop; ai; ai = ai->ai_next) { |
| 302 |
s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); |
319 |
s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); |
| 303 |
if (s < 0) { |
320 |
if (s < 0) { |
|
Lines 349-354
Link Here
|
| 349 |
fdcon[s].c_len = 4; |
366 |
fdcon[s].c_len = 4; |
| 350 |
fdcon[s].c_off = 0; |
367 |
fdcon[s].c_off = 0; |
| 351 |
fdcon[s].c_keytype = keytype; |
368 |
fdcon[s].c_keytype = keytype; |
|
|
369 |
fdcon[s].c_connclosed = 0; |
| 352 |
gettimeofday(&fdcon[s].c_tv, NULL); |
370 |
gettimeofday(&fdcon[s].c_tv, NULL); |
| 353 |
fdcon[s].c_tv.tv_sec += timeout; |
371 |
fdcon[s].c_tv.tv_sec += timeout; |
| 354 |
TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link); |
372 |
TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link); |
|
Lines 388-395
Link Here
|
| 388 |
{ |
406 |
{ |
| 389 |
con *c = &fdcon[s]; |
407 |
con *c = &fdcon[s]; |
| 390 |
int ret; |
408 |
int ret; |
|
|
409 |
char *name; |
| 391 |
|
410 |
|
| 392 |
ret = conalloc(c->c_namelist, c->c_output_name, c->c_keytype); |
411 |
/* |
|
|
412 |
* If "connclosed" isn't set, do the next host from c->c_namelist. Else, |
| 413 |
* restore the original string in c->c_namebase and redo the current |
| 414 |
* host. |
| 415 |
*/ |
| 416 |
name = c->c_namelist; /* do next in list ?? */ |
| 417 |
if (connclosed != 0) { |
| 418 |
if (name && *name != '\0') /* restore separator, if any */ |
| 419 |
*(name - 1) = ','; |
| 420 |
name = c->c_namebase; /* redo current */ |
| 421 |
} |
| 422 |
ret = conalloc(name, c->c_output_name, c->c_keytype); |
| 393 |
confree(s); |
423 |
confree(s); |
| 394 |
return (ret); |
424 |
return (ret); |
| 395 |
} |
425 |
} |
|
Lines 422-427
Link Here
|
| 422 |
error("%s: Connection closed by remote host", c->c_name); |
452 |
error("%s: Connection closed by remote host", c->c_name); |
| 423 |
break; |
453 |
break; |
| 424 |
case ECONNREFUSED: |
454 |
case ECONNREFUSED: |
|
|
455 |
if (log_all_failures) |
| 456 |
error("%s: Connection refused by remote host", c->c_name); |
| 425 |
break; |
457 |
break; |
| 426 |
default: |
458 |
default: |
| 427 |
error("read (%s): %s", c->c_name, strerror(errno)); |
459 |
error("read (%s): %s", c->c_name, strerror(errno)); |
|
Lines 443-456
Link Here
|
| 443 |
datafellows = 0; |
475 |
datafellows = 0; |
| 444 |
if (c->c_keytype != KT_RSA1) { |
476 |
if (c->c_keytype != KT_RSA1) { |
| 445 |
if (!ssh2_capable(remote_major, remote_minor)) { |
477 |
if (!ssh2_capable(remote_major, remote_minor)) { |
|
|
478 |
if (log_all_failures) |
| 479 |
logit("%s doesn't support ssh2", c->c_name); |
| 480 |
else |
| 446 |
debug("%s doesn't support ssh2", c->c_name); |
481 |
debug("%s doesn't support ssh2", c->c_name); |
| 447 |
confree(s); |
482 |
confree(s); |
| 448 |
return; |
483 |
return; |
| 449 |
} |
484 |
} |
| 450 |
} else if (remote_major != 1) { |
485 |
} else if (remote_major != 1) { |
|
|
486 |
if (log_all_failures) |
| 487 |
logit("%s doesn't support ssh1", c->c_name); |
| 488 |
else |
| 451 |
debug("%s doesn't support ssh1", c->c_name); |
489 |
debug("%s doesn't support ssh1", c->c_name); |
| 452 |
confree(s); |
490 |
confree(s); |
| 453 |
return; |
491 |
return; |
| 454 |
} |
492 |
} |
| 455 |
fprintf(stderr, "# %s %s\n", c->c_name, chop(buf)); |
493 |
fprintf(stderr, "# %s %s\n", c->c_name, chop(buf)); |
| 456 |
n = snprintf(buf, sizeof buf, "SSH-%d.%d-OpenSSH-keyscan\r\n", |
494 |
n = snprintf(buf, sizeof buf, "SSH-%d.%d-OpenSSH-keyscan\r\n", |
|
Lines 466-478
Link Here
|
| 466 |
confree(s); |
504 |
confree(s); |
| 467 |
return; |
505 |
return; |
| 468 |
} |
506 |
} |
| 469 |
if (c->c_keytype != KT_RSA1) { |
507 |
if (c->c_keytype == KT_RSA1) { |
| 470 |
keyprint(c, keygrab_ssh2(c)); |
508 |
c->c_status = CS_SIZE; |
| 471 |
confree(s); |
509 |
contouch(s); |
| 472 |
return; |
510 |
return; |
| 473 |
} |
511 |
} |
| 474 |
c->c_status = CS_SIZE; |
512 |
/* |
| 475 |
contouch(s); |
513 |
* Read and print one of the ssh2 keys for this host. |
|
|
514 |
*/ |
| 515 |
keyprint(c, keygrab_ssh2(c)); |
| 516 |
|
| 517 |
/* |
| 518 |
* We're done with this host if the `packet.c:packet_read_seqnr()' |
| 519 |
* function was able to complete its data read. |
| 520 |
*/ |
| 521 |
if (connclosed == 0) { |
| 522 |
confree(s); |
| 523 |
} |
| 524 |
/* |
| 525 |
* We're also done with this host if the `packet.c:packet_read_seqnr()' |
| 526 |
* function received an EOF while attempting to read data (probably |
| 527 |
* caused by the LoginGraceTime being exceeded on the host) and if this |
| 528 |
* is the second time this has occurred for this host. |
| 529 |
*/ |
| 530 |
else if (c->c_connclosed) { |
| 531 |
confree(s); |
| 532 |
connclosed = -1; /* conrecycle other active sockets */ |
| 533 |
} |
| 534 |
/* |
| 535 |
* Else, give this host one and only one more chance with this key. We |
| 536 |
* don't know if this timeout was caused because of slow responses by |
| 537 |
* previous hosts or the host itself (or both (:@{)). This host and all |
| 538 |
* other hosts that currently have open sockets will be `conrecycled()'. |
| 539 |
*/ |
| 540 |
else { |
| 541 |
connclosed = s; |
| 542 |
} |
| 476 |
} |
543 |
} |
| 477 |
|
544 |
|
| 478 |
static void |
545 |
static void |
|
Lines 550-569
Link Here
|
| 550 |
if (FD_ISSET(i, e)) { |
617 |
if (FD_ISSET(i, e)) { |
| 551 |
error("%s: exception!", fdcon[i].c_name); |
618 |
error("%s: exception!", fdcon[i].c_name); |
| 552 |
confree(i); |
619 |
confree(i); |
| 553 |
} else if (FD_ISSET(i, r)) |
620 |
} else if (FD_ISSET(i, r)) { |
| 554 |
conread(i); |
621 |
conread(i); |
|
|
622 |
/* |
| 623 |
* Break if the read attempt in the `packet.c:packet_read_seqnr()' |
| 624 |
* function failed because the remote host closed the connection before |
| 625 |
* the packet data read was complete. The closure probably occurred |
| 626 |
* because the LoginGraceTime was exceeded on the remote `sshd' server. |
| 627 |
* All hosts that currently have a viable "fdcon[s]" entry will be |
| 628 |
* recycled below to negate the time used waiting for the current |
| 629 |
* "fdcon[i]"th host to respond. This is a very kludgy way to do this. |
| 630 |
*/ |
| 631 |
if (connclosed) |
| 632 |
break; |
| 633 |
} |
| 555 |
} |
634 |
} |
| 556 |
xfree(r); |
635 |
xfree(r); |
| 557 |
xfree(e); |
636 |
xfree(e); |
| 558 |
|
637 |
|
|
|
638 |
/* |
| 639 |
* If we have the "connclosed" condition, the "fdcon[connclosed]" entry |
| 640 |
* has to be freed now since the socket has already been closed by the |
| 641 |
* `packet.c:packet_close()' function. We will use the new fd as a |
| 642 |
* termination condition in the while loop below. |
| 643 |
*/ |
| 644 |
i = -1; |
| 645 |
if (connclosed > 0) { |
| 646 |
char *iname, *oname; |
| 647 |
int keytype; |
| 648 |
|
| 649 |
c = &fdcon[connclosed]; |
| 650 |
iname = c->c_namelist; |
| 651 |
if (iname && *iname != '\0') |
| 652 |
*(iname - 1) = ','; |
| 653 |
iname = xstrdup (c->c_namebase); |
| 654 |
oname = xstrdup (c->c_output_name); |
| 655 |
keytype = c->c_keytype; |
| 656 |
confree (connclosed); |
| 657 |
i = conalloc (iname, oname, keytype); |
| 658 |
/* |
| 659 |
* Flag this entry as having caused a "connclosed" condition - once. |
| 660 |
*/ |
| 661 |
if (i >= 0) |
| 662 |
fdcon[i].c_connclosed = 1; |
| 663 |
xfree (iname); |
| 664 |
xfree (oname); |
| 665 |
} |
| 666 |
|
| 667 |
/* |
| 668 |
* Loop through the remaining TAILQ entries. If we have a "connclosed" |
| 669 |
* condition, recycle all of them using the current host name. Else, |
| 670 |
* if they have timed out, recycle them using the next name in the list. |
| 671 |
*/ |
| 559 |
c = TAILQ_FIRST(&tq); |
672 |
c = TAILQ_FIRST(&tq); |
| 560 |
while (c && (c->c_tv.tv_sec < now.tv_sec || |
673 |
while (c && (connclosed || |
| 561 |
(c->c_tv.tv_sec == now.tv_sec && c->c_tv.tv_usec < now.tv_usec))) { |
674 |
(c->c_tv.tv_sec < now.tv_sec || |
|
|
675 |
(c->c_tv.tv_sec == now.tv_sec && |
| 676 |
c->c_tv.tv_usec < now.tv_usec)))) { |
| 562 |
int s = c->c_fd; |
677 |
int s = c->c_fd; |
|
|
678 |
/* |
| 679 |
* If i >= 0, fdcon[i] should be the first of any new allocations that |
| 680 |
* were made as a result of the call(s) to conrecycle() below or to |
| 681 |
* conalloc() above. |
| 682 |
*/ |
| 683 |
if (s == i) |
| 684 |
break; |
| 685 |
|
| 686 |
/* |
| 687 |
* If requested and if not recycling because of "connclosed", list this |
| 688 |
* host as a connection time out. |
| 689 |
*/ |
| 690 |
if (log_all_failures && connclosed == 0) |
| 691 |
logit("%s: Connection timed out.", c->c_name); |
| 692 |
|
| 693 |
/* |
| 694 |
* Save fd of first new allocation. If we encounter it again, we'll |
| 695 |
* know that we've cycled through all of the original queue. |
| 696 |
*/ |
| 697 |
s = conrecycle(s); |
| 698 |
if (i < 0) |
| 699 |
i = s; |
| 563 |
|
700 |
|
| 564 |
c = TAILQ_NEXT(c, c_link); |
701 |
c = TAILQ_NEXT(c, c_link); |
| 565 |
conrecycle(s); |
|
|
| 566 |
} |
702 |
} |
|
|
703 |
connclosed = 0; |
| 567 |
} |
704 |
} |
| 568 |
|
705 |
|
| 569 |
static void |
706 |
static void |
|
Lines 583-588
Link Here
|
| 583 |
} |
720 |
} |
| 584 |
} |
721 |
} |
| 585 |
|
722 |
|
|
|
723 |
/* |
| 724 |
* Convert general remote aborts to continues while the `dispatch_run()' |
| 725 |
* function is being executed. |
| 726 |
*/ |
| 727 |
void |
| 728 |
cleanup_exit(int i) |
| 729 |
{ |
| 730 |
if (nonfatal_fatal) |
| 731 |
longjmp(kexjmp, -1); |
| 732 |
else |
| 733 |
exit(i); |
| 734 |
} |
| 735 |
|
| 586 |
void |
736 |
void |
| 587 |
fatal(const char *fmt,...) |
737 |
fatal(const char *fmt,...) |
| 588 |
{ |
738 |
{ |
|
Lines 601-607
Link Here
|
| 601 |
usage(void) |
751 |
usage(void) |
| 602 |
{ |
752 |
{ |
| 603 |
fprintf(stderr, |
753 |
fprintf(stderr, |
| 604 |
"usage: %s [-46Hv] [-f file] [-p port] [-T timeout] [-t type]\n" |
754 |
"usage: %s [-46HLv] [-f file] [-p port] [-T timeout] [-t type]\n" |
| 605 |
"\t\t [host | addrlist namelist] ...\n", |
755 |
"\t\t [host | addrlist namelist] ...\n", |
| 606 |
__progname); |
756 |
__progname); |
| 607 |
exit(1); |
757 |
exit(1); |
|
Lines 630-640
Link Here
|
| 630 |
if (argc <= 1) |
780 |
if (argc <= 1) |
| 631 |
usage(); |
781 |
usage(); |
| 632 |
|
782 |
|
| 633 |
while ((opt = getopt(argc, argv, "Hv46p:T:t:f:")) != -1) { |
783 |
while ((opt = getopt(argc, argv, "HLv46p:T:t:f:")) != -1) { |
| 634 |
switch (opt) { |
784 |
switch (opt) { |
| 635 |
case 'H': |
785 |
case 'H': |
| 636 |
hash_hosts = 1; |
786 |
hash_hosts = 1; |
| 637 |
break; |
787 |
break; |
|
|
788 |
case 'L': |
| 789 |
log_all_failures = 1; |
| 790 |
break; |
| 638 |
case 'p': |
791 |
case 'p': |
| 639 |
ssh_port = a2port(optarg); |
792 |
ssh_port = a2port(optarg); |
| 640 |
if (ssh_port <= 0) { |
793 |
if (ssh_port <= 0) { |
|
Lines 715-721
Link Here
|
| 715 |
fdlim_set(maxfd); |
868 |
fdlim_set(maxfd); |
| 716 |
fdcon = xcalloc(maxfd, sizeof(con)); |
869 |
fdcon = xcalloc(maxfd, sizeof(con)); |
| 717 |
|
870 |
|
| 718 |
read_wait_nfdset = howmany(maxfd, NFDBITS); |
871 |
read_wait_nfdset = howmany(maxfd + 1, NFDBITS); |
| 719 |
read_wait = xcalloc(read_wait_nfdset, sizeof(fd_mask)); |
872 |
read_wait = xcalloc(read_wait_nfdset, sizeof(fd_mask)); |
| 720 |
|
873 |
|
| 721 |
for (j = 0; j < fopt_count; j++) { |
874 |
for (j = 0; j < fopt_count; j++) { |