summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--ssh-keyscan.175
-rw-r--r--ssh-keyscan.c320
3 files changed, 302 insertions, 98 deletions
diff --git a/ChangeLog b/ChangeLog
index edd7662f2..6ebbabc04 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -138,6 +138,9 @@
138 - jakob@cvs.openbsd.org 2001/08/03 10:31:30 138 - jakob@cvs.openbsd.org 2001/08/03 10:31:30
139 [ssh-add.c ssh-agent.c ssh-keyscan.c] 139 [ssh-add.c ssh-agent.c ssh-keyscan.c]
140 improve usage(). ok markus@ 140 improve usage(). ok markus@
141 - markus@cvs.openbsd.org 2001/08/05 23:18:20
142 [ssh-keyscan.1 ssh-keyscan.c]
143 ssh 2 support; from wayned@users.sourceforge.net
141 144
14220010803 14520010803
143 - (djm) Fix interrupted read in entropy gatherer. Spotted by markus@ on 146 - (djm) Fix interrupted read in entropy gatherer. Spotted by markus@ on
@@ -6248,4 +6251,4 @@
6248 - Wrote replacements for strlcpy and mkdtemp 6251 - Wrote replacements for strlcpy and mkdtemp
6249 - Released 1.0pre1 6252 - Released 1.0pre1
6250 6253
6251$Id: ChangeLog,v 1.1462 2001/08/06 22:06:35 mouring Exp $ 6254$Id: ChangeLog,v 1.1463 2001/08/06 22:41:30 mouring Exp $
diff --git a/ssh-keyscan.1 b/ssh-keyscan.1
index 80119aa21..b348bc252 100644
--- a/ssh-keyscan.1
+++ b/ssh-keyscan.1
@@ -1,4 +1,4 @@
1.\" $OpenBSD: ssh-keyscan.1,v 1.9 2001/08/02 18:37:35 mpech Exp $ 1.\" $OpenBSD: ssh-keyscan.1,v 1.10 2001/08/05 23:18:20 markus Exp $
2.\" 2.\"
3.\" Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>. 3.\" Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
4.\" 4.\"
@@ -14,9 +14,13 @@
14.Nd gather ssh public keys 14.Nd gather ssh public keys
15.Sh SYNOPSIS 15.Sh SYNOPSIS
16.Nm ssh-keyscan 16.Nm ssh-keyscan
17.Op Fl t Ar timeout 17.Op Fl v46
18.Op Ar -- | host | addrlist namelist 18.Op Fl p Ar port
19.Op Fl f Ar files ... 19.Op Fl T Ar timeout
20.Op Fl t Ar type
21.Op Fl f Ar file
22.Op Ar host | addrlist namelist
23.Op Ar ...
20.Sh DESCRIPTION 24.Sh DESCRIPTION
21.Nm 25.Nm
22is a utility for gathering the public ssh host keys of a number of 26is a utility for gathering the public ssh host keys of a number of
@@ -37,14 +41,28 @@ any encryption.
37.Pp 41.Pp
38The options are as follows: 42The options are as follows:
39.Bl -tag -width Ds 43.Bl -tag -width Ds
40.It Fl t 44.It Fl p Ar port
45Port to connect to on the remote host.
46.It Fl T
41Set the timeout for connection attempts. If 47Set the timeout for connection attempts. If
42.Pa timeout 48.Pa timeout
43seconds have elapsed since a connection was initiated to a host or since the 49seconds have elapsed since a connection was initiated to a host or since the
44last time anything was read from that host, then the connection is 50last time anything was read from that host, then the connection is
45closed and the host in question considered unavailable. Default is 5 51closed and the host in question considered unavailable. Default is 5
46seconds. 52seconds.
47.It Fl f 53.It Fl t Ar type
54Specifies the type of the key to fetch from the following hosts.
55The possible values are
56.Dq rsa1
57for protocol version 1 and
58.Dq rsa
59or
60.Dq dsa
61for protocol version 2.
62Multiple values may be specified by separating them with commas.
63The default is
64.Dq rsa1 .
65.It Fl f Ar filename
48Read hosts or 66Read hosts or
49.Pa addrlist namelist 67.Pa addrlist namelist
50pairs from this file, one per line. 68pairs from this file, one per line.
@@ -55,6 +73,19 @@ is supplied instead of a filename,
55will read hosts or 73will read hosts or
56.Pa addrlist namelist 74.Pa addrlist namelist
57pairs from the standard input. 75pairs from the standard input.
76.It Fl v
77Verbose mode.
78Causes
79.Nm
80to print debugging messages about its progress.
81.It Fl 4
82Forces
83.Nm
84to use IPv4 addresses only.
85.It Fl 6
86Forces
87.Nm
88to use IPv6 addresses only.
58.El 89.El
59.Sh SECURITY 90.Sh SECURITY
60If you make an ssh_known_hosts file using 91If you make an ssh_known_hosts file using
@@ -67,7 +98,10 @@ On the other hand, if your security model allows such a risk,
67can help you detect tampered keyfiles or man in the middle attacks which 98can help you detect tampered keyfiles or man in the middle attacks which
68have begun after you created your ssh_known_hosts file. 99have begun after you created your ssh_known_hosts file.
69.Sh EXAMPLES 100.Sh EXAMPLES
70Print the host key for machine 101.Pp
102Print the
103.Pa rsa1
104host key for machine
71.Pa hostname : 105.Pa hostname :
72.Bd -literal 106.Bd -literal
73ssh-keyscan hostname 107ssh-keyscan hostname
@@ -78,20 +112,36 @@ Find all hosts from the file
78which have new or different keys from those in the sorted file 112which have new or different keys from those in the sorted file
79.Pa ssh_known_hosts : 113.Pa ssh_known_hosts :
80.Bd -literal 114.Bd -literal
81$ ssh-keyscan -f ssh_hosts | sort -u - ssh_known_hosts | \e\ 115ssh-keyscan -t rsa,dsa -f ssh_hosts | \e\
82 diff ssh_known_hosts - 116 sort -u - ssh_known_hosts | diff ssh_known_hosts -
83.Ed 117.Ed
84.Sh FILES 118.Sh FILES
85.Pa Input format: 119.Pa Input format:
120.Bd -literal
861.2.3.4,1.2.4.4 name.my.domain,name,n.my.domain,n,1.2.3.4,1.2.4.4 1211.2.3.4,1.2.4.4 name.my.domain,name,n.my.domain,n,1.2.3.4,1.2.4.4
122.Ed
87.Pp 123.Pp
88.Pa Output format: 124.Pa Output format for rsa1 keys:
125.Bd -literal
89host-or-namelist bits exponent modulus 126host-or-namelist bits exponent modulus
127.Ed
128.Pp
129.Pa Output format for rsa and dsa keys:
130.Bd -literal
131host-or-namelist keytype base64-encoded-key
132.Ed
133.Pp
134Where
135.Pa keytype
136is either
137.Dq ssh-rsa
138or
139.Dq ssh-dsa .
90.Pp 140.Pp
91.Pa /etc/ssh_known_hosts 141.Pa /etc/ssh_known_hosts
92.Sh BUGS 142.Sh BUGS
93It generates "Connection closed by remote host" messages on the consoles 143It generates "Connection closed by remote host" messages on the consoles
94of all the machines it scans. 144of all the machines it scans if the server is older than version 2.9.
95This is because it opens a connection to the ssh port, reads the public 145This is because it opens a connection to the ssh port, reads the public
96key, and drops the connection as soon as it gets the key. 146key, and drops the connection as soon as it gets the key.
97.Sh SEE ALSO 147.Sh SEE ALSO
@@ -99,3 +149,6 @@ key, and drops the connection as soon as it gets the key.
99.Xr sshd 8 149.Xr sshd 8
100.Sh AUTHORS 150.Sh AUTHORS
101David Mazieres <dm@lcs.mit.edu> 151David Mazieres <dm@lcs.mit.edu>
152wrote the initial version, and
153Wayne Davison <wayned@users.sourceforge.net>
154added support for protocol version 2.
diff --git a/ssh-keyscan.c b/ssh-keyscan.c
index 9908baac4..5a992515e 100644
--- a/ssh-keyscan.c
+++ b/ssh-keyscan.c
@@ -7,7 +7,7 @@
7 */ 7 */
8 8
9#include "includes.h" 9#include "includes.h"
10RCSID("$OpenBSD: ssh-keyscan.c,v 1.25 2001/08/03 10:31:30 jakob Exp $"); 10RCSID("$OpenBSD: ssh-keyscan.c,v 1.26 2001/08/05 23:18:20 markus Exp $");
11 11
12#if defined(HAVE_SYS_QUEUE_H) && !defined(HAVE_BOGUS_SYS_QUEUE_H) 12#if defined(HAVE_SYS_QUEUE_H) && !defined(HAVE_BOGUS_SYS_QUEUE_H)
13#include <sys/queue.h> 13#include <sys/queue.h>
@@ -18,18 +18,37 @@ RCSID("$OpenBSD: ssh-keyscan.c,v 1.25 2001/08/03 10:31:30 jakob Exp $");
18 18
19#include <openssl/bn.h> 19#include <openssl/bn.h>
20 20
21#include <setjmp.h>
21#include "xmalloc.h" 22#include "xmalloc.h"
22#include "ssh.h" 23#include "ssh.h"
23#include "ssh1.h" 24#include "ssh1.h"
24#include "key.h" 25#include "key.h"
26#include "kex.h"
27#include "compat.h"
28#include "myproposal.h"
29#include "packet.h"
30#include "dispatch.h"
25#include "buffer.h" 31#include "buffer.h"
26#include "bufaux.h" 32#include "bufaux.h"
27#include "log.h" 33#include "log.h"
28#include "atomicio.h" 34#include "atomicio.h"
35#include "misc.h"
29 36
30static int argno = 1; /* Number of argument currently being parsed */ 37/* Flag indicating whether IPv4 or IPv6. This can be set on the command line.
38 Default value is AF_UNSPEC means both IPv4 and IPv6. */
39#ifdef IPV4_DEFAULT
40int IPv4or6 = AF_INET;
41#else
42int IPv4or6 = AF_UNSPEC;
43#endif
31 44
32int family = AF_UNSPEC; /* IPv4, IPv6 or both */ 45int ssh_port = SSH_DEFAULT_PORT;
46
47#define KT_RSA1 1
48#define KT_DSA 2
49#define KT_RSA 4
50
51int get_keytypes = KT_RSA1; /* Get only RSA1 keys by default */
33 52
34#define MAXMAXFD 256 53#define MAXMAXFD 256
35 54
@@ -47,6 +66,8 @@ char *__progname;
47fd_set *read_wait; 66fd_set *read_wait;
48size_t read_wait_size; 67size_t read_wait_size;
49int ncon; 68int ncon;
69int nonfatal_fatal = 0;
70jmp_buf kexjmp;
50 71
51/* 72/*
52 * Keep a connection structure for each file descriptor. The state 73 * Keep a connection structure for each file descriptor. The state
@@ -62,11 +83,13 @@ typedef struct Connection {
62 int c_plen; /* Packet length field for ssh packet */ 83 int c_plen; /* Packet length field for ssh packet */
63 int c_len; /* Total bytes which must be read. */ 84 int c_len; /* Total bytes which must be read. */
64 int c_off; /* Length of data read so far. */ 85 int c_off; /* Length of data read so far. */
86 int c_keytype; /* Only one of KT_RSA1, KT_DSA, or KT_RSA */
65 char *c_namebase; /* Address to free for c_name and c_namelist */ 87 char *c_namebase; /* Address to free for c_name and c_namelist */
66 char *c_name; /* Hostname of connection for errors */ 88 char *c_name; /* Hostname of connection for errors */
67 char *c_namelist; /* Pointer to other possible addresses */ 89 char *c_namelist; /* Pointer to other possible addresses */
68 char *c_output_name; /* Hostname of connection for output */ 90 char *c_output_name; /* Hostname of connection for output */
69 char *c_data; /* Data read from this fd */ 91 char *c_data; /* Data read from this fd */
92 Kex *c_kex; /* The key-exchange struct for ssh2 */
70 struct timeval c_tv; /* Time at which connection gets aborted */ 93 struct timeval c_tv; /* Time at which connection gets aborted */
71 TAILQ_ENTRY(Connection) c_link; /* List of connections in timeout order. */ 94 TAILQ_ENTRY(Connection) c_link; /* List of connections in timeout order. */
72} con; 95} con;
@@ -262,8 +285,8 @@ strnnsep(char **stringp, char *delim)
262 return (tok); 285 return (tok);
263} 286}
264 287
265static void 288static Key *
266keyprint(char *host, char *output_name, char *kd, int len) 289keygrab_ssh1(con *c)
267{ 290{
268 static Key *rsa; 291 static Key *rsa;
269 static Buffer msg; 292 static Buffer msg;
@@ -272,12 +295,12 @@ keyprint(char *host, char *output_name, char *kd, int len)
272 buffer_init(&msg); 295 buffer_init(&msg);
273 rsa = key_new(KEY_RSA1); 296 rsa = key_new(KEY_RSA1);
274 } 297 }
275 buffer_append(&msg, kd, len); 298 buffer_append(&msg, c->c_data, c->c_plen);
276 buffer_consume(&msg, 8 - (len & 7)); /* padding */ 299 buffer_consume(&msg, 8 - (c->c_plen & 7)); /* padding */
277 if (buffer_get_char(&msg) != (int) SSH_SMSG_PUBLIC_KEY) { 300 if (buffer_get_char(&msg) != (int) SSH_SMSG_PUBLIC_KEY) {
278 error("%s: invalid packet type", host); 301 error("%s: invalid packet type", c->c_name);
279 buffer_clear(&msg); 302 buffer_clear(&msg);
280 return; 303 return NULL;
281 } 304 }
282 buffer_consume(&msg, 8); /* cookie */ 305 buffer_consume(&msg, 8); /* cookie */
283 306
@@ -290,10 +313,70 @@ keyprint(char *host, char *output_name, char *kd, int len)
290 (void) buffer_get_int(&msg); 313 (void) buffer_get_int(&msg);
291 buffer_get_bignum(&msg, rsa->rsa->e); 314 buffer_get_bignum(&msg, rsa->rsa->e);
292 buffer_get_bignum(&msg, rsa->rsa->n); 315 buffer_get_bignum(&msg, rsa->rsa->n);
316
293 buffer_clear(&msg); 317 buffer_clear(&msg);
294 318
295 fprintf(stdout, "%s ", output_name ? output_name : host); 319 return (rsa);
296 key_write(rsa, stdout); 320}
321
322static int
323hostjump(Key *hostkey)
324{
325 longjmp(kexjmp, (int)hostkey);
326}
327
328static int
329ssh2_capable(int remote_major, int remote_minor)
330{
331 switch (remote_major) {
332 case 1:
333 if (remote_minor == 99)
334 return 1;
335 break;
336 case 2:
337 return 1;
338 default:
339 break;
340 }
341 return 0;
342}
343
344static Key *
345keygrab_ssh2(con *c)
346{
347 int j;
348
349 packet_set_connection(c->c_fd, c->c_fd);
350 enable_compat20();
351 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = c->c_keytype == KT_DSA?
352 "ssh-dss": "ssh-rsa";
353 c->c_kex = kex_setup(myproposal);
354 c->c_kex->verify_host_key = hostjump;
355
356 if (!(j = setjmp(kexjmp))) {
357 nonfatal_fatal = 1;
358 dispatch_run(DISPATCH_BLOCK, &c->c_kex->done, c->c_kex);
359 fprintf(stderr, "Impossible! dispatch_run() returned!\n");
360 exit(1);
361 }
362 nonfatal_fatal = 0;
363 xfree(c->c_kex);
364 c->c_kex = NULL;
365 packet_close();
366 if (j < 0)
367 j = 0;
368
369 return (Key*)(j);
370}
371
372static void
373keyprint(con *c, Key *key)
374{
375 if (!key)
376 return;
377
378 fprintf(stdout, "%s ", c->c_output_name ? c->c_output_name : c->c_name);
379 key_write(key, stdout);
297 fputs("\n", stdout); 380 fputs("\n", stdout);
298} 381}
299 382
@@ -304,9 +387,9 @@ tcpconnect(char *host)
304 char strport[NI_MAXSERV]; 387 char strport[NI_MAXSERV];
305 int gaierr, s = -1; 388 int gaierr, s = -1;
306 389
307 snprintf(strport, sizeof strport, "%d", SSH_DEFAULT_PORT); 390 snprintf(strport, sizeof strport, "%d", ssh_port);
308 memset(&hints, 0, sizeof(hints)); 391 memset(&hints, 0, sizeof(hints));
309 hints.ai_family = family; 392 hints.ai_family = IPv4or6;
310 hints.ai_socktype = SOCK_STREAM; 393 hints.ai_socktype = SOCK_STREAM;
311 if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) 394 if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0)
312 fatal("getaddrinfo %s: %s", host, gai_strerror(gaierr)); 395 fatal("getaddrinfo %s: %s", host, gai_strerror(gaierr));
@@ -331,7 +414,7 @@ tcpconnect(char *host)
331} 414}
332 415
333static int 416static int
334conalloc(char *iname, char *oname) 417conalloc(char *iname, char *oname, int keytype)
335{ 418{
336 int s; 419 int s;
337 char *namebase, *name, *namelist; 420 char *namebase, *name, *namelist;
@@ -360,6 +443,7 @@ conalloc(char *iname, char *oname)
360 fdcon[s].c_data = (char *) &fdcon[s].c_plen; 443 fdcon[s].c_data = (char *) &fdcon[s].c_plen;
361 fdcon[s].c_len = 4; 444 fdcon[s].c_len = 4;
362 fdcon[s].c_off = 0; 445 fdcon[s].c_off = 0;
446 fdcon[s].c_keytype = keytype;
363 gettimeofday(&fdcon[s].c_tv, NULL); 447 gettimeofday(&fdcon[s].c_tv, NULL);
364 fdcon[s].c_tv.tv_sec += timeout; 448 fdcon[s].c_tv.tv_sec += timeout;
365 TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link); 449 TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link);
@@ -379,6 +463,7 @@ confree(int s)
379 if (fdcon[s].c_status == CS_KEYS) 463 if (fdcon[s].c_status == CS_KEYS)
380 xfree(fdcon[s].c_data); 464 xfree(fdcon[s].c_data);
381 fdcon[s].c_status = CS_UNUSED; 465 fdcon[s].c_status = CS_UNUSED;
466 fdcon[s].c_keytype = 0;
382 TAILQ_REMOVE(&tq, &fdcon[s], c_link); 467 TAILQ_REMOVE(&tq, &fdcon[s], c_link);
383 FD_CLR(s, read_wait); 468 FD_CLR(s, read_wait);
384 ncon--; 469 ncon--;
@@ -398,21 +483,16 @@ conrecycle(int s)
398{ 483{
399 int ret; 484 int ret;
400 con *c = &fdcon[s]; 485 con *c = &fdcon[s];
401 char *iname, *oname;
402 486
403 iname = xstrdup(c->c_namelist); 487 ret = conalloc(c->c_namelist, c->c_output_name, c->c_keytype);
404 oname = xstrdup(c->c_output_name);
405 confree(s); 488 confree(s);
406 ret = conalloc(iname, oname);
407 xfree(iname);
408 xfree(oname);
409 return (ret); 489 return (ret);
410} 490}
411 491
412static void 492static void
413congreet(int s) 493congreet(int s)
414{ 494{
415 char buf[80], *cp; 495 char buf[256], *cp;
416 size_t bufsiz; 496 size_t bufsiz;
417 int n = 0; 497 int n = 0;
418 con *c = &fdcon[s]; 498 con *c = &fdcon[s];
@@ -434,12 +514,34 @@ congreet(int s)
434 } 514 }
435 *cp = '\0'; 515 *cp = '\0';
436 fprintf(stderr, "# %s %s\n", c->c_name, buf); 516 fprintf(stderr, "# %s %s\n", c->c_name, buf);
437 n = snprintf(buf, sizeof buf, "SSH-1.5-OpenSSH-keyscan\r\n"); 517 if (c->c_keytype != KT_RSA1) {
518 int remote_major, remote_minor;
519 char remote_version[sizeof buf];
520
521 if (sscanf(buf, "SSH-%d.%d-%[^\n]\n",
522 &remote_major, &remote_minor, remote_version) == 3)
523 compat_datafellows(remote_version);
524 else
525 datafellows = 0;
526 if (!ssh2_capable(remote_major, remote_minor)) {
527 debug("%s doesn't support ssh2", c->c_name);
528 confree(s);
529 return;
530 }
531 }
532 n = snprintf(buf, sizeof buf, "SSH-%d.%d-OpenSSH-keyscan\r\n",
533 c->c_keytype == KT_RSA1? PROTOCOL_MAJOR_1 : PROTOCOL_MAJOR_2,
534 c->c_keytype == KT_RSA1? PROTOCOL_MINOR_1 : PROTOCOL_MINOR_2);
438 if (atomicio(write, s, buf, n) != n) { 535 if (atomicio(write, s, buf, n) != n) {
439 error("write (%s): %s", c->c_name, strerror(errno)); 536 error("write (%s): %s", c->c_name, strerror(errno));
440 confree(s); 537 confree(s);
441 return; 538 return;
442 } 539 }
540 if (c->c_keytype != KT_RSA1) {
541 keyprint(c, keygrab_ssh2(c));
542 confree(s);
543 return;
544 }
443 c->c_status = CS_SIZE; 545 c->c_status = CS_SIZE;
444 contouch(s); 546 contouch(s);
445} 547}
@@ -472,7 +574,7 @@ conread(int s)
472 c->c_status = CS_KEYS; 574 c->c_status = CS_KEYS;
473 break; 575 break;
474 case CS_KEYS: 576 case CS_KEYS:
475 keyprint(c->c_name, c->c_output_name, c->c_data, c->c_plen); 577 keyprint(c, keygrab_ssh1(c));
476 confree(s); 578 confree(s);
477 return; 579 return;
478 break; 580 break;
@@ -536,86 +638,128 @@ conloop(void)
536 } 638 }
537} 639}
538 640
539static char * 641static void
540nexthost(int argc, char **argv) 642do_host(char *host)
541{ 643{
542 static Linebuf *lb; 644 char *name = strnnsep(&host, " \t\n");
543 645 int j;
544 for (;;) { 646
545 if (!lb) { 647 for (j = KT_RSA1; j <= KT_RSA; j *= 2) {
546 if (argno >= argc) 648 if (get_keytypes & j) {
547 return (NULL); 649 while (ncon >= MAXCON)
548 if (argv[argno][0] != '-') 650 conloop();
549 return (argv[argno++]); 651 conalloc(name, *host ? host : name, j);
550 if (!strcmp(argv[argno], "--")) {
551 if (++argno >= argc)
552 return (NULL);
553 return (argv[argno++]);
554 } else if (!strncmp(argv[argno], "-f", 2)) {
555 char *fname;
556
557 if (argv[argno][2])
558 fname = &argv[argno++][2];
559 else if (++argno >= argc) {
560 error("missing filename for `-f'");
561 return (NULL);
562 } else
563 fname = argv[argno++];
564 if (!strcmp(fname, "-"))
565 fname = NULL;
566 lb = Linebuf_alloc(fname, error);
567 } else
568 error("ignoring invalid/misplaced option `%s'",
569 argv[argno++]);
570 } else {
571 char *line;
572
573 line = Linebuf_getline(lb);
574 if (line)
575 return (line);
576 Linebuf_free(lb);
577 lb = NULL;
578 } 652 }
579 } 653 }
580} 654}
581 655
582static void 656static void
657fatal_callback(void *arg)
658{
659 if (nonfatal_fatal)
660 longjmp(kexjmp, -1);
661}
662
663static void
583usage(void) 664usage(void)
584{ 665{
585 fprintf(stderr, "Usage: %s [options] [ host | addrlist namelist ]\n", 666 fprintf(stderr, "Usage: %s [options] host ...\n",
586 __progname); 667 __progname);
587 fprintf(stderr, "Options:\n"); 668 fprintf(stderr, "Options:\n");
588 fprintf(stderr, " -t timeout Set connection timeout.\n");
589 fprintf(stderr, " -f file Read hosts or addresses from file.\n"); 669 fprintf(stderr, " -f file Read hosts or addresses from file.\n");
670 fprintf(stderr, " -p port Connect to the specified port.\n");
671 fprintf(stderr, " -t keytype Specify the host key type.\n");
672 fprintf(stderr, " -T timeout Set connection timeout.\n");
673 fprintf(stderr, " -v Verbose; display verbose debugging messages.\n");
674 fprintf(stderr, " -4 Use IPv4 only.\n");
675 fprintf(stderr, " -6 Use IPv6 only.\n");
590 exit(1); 676 exit(1);
591} 677}
592 678
593int 679int
594main(int argc, char **argv) 680main(int argc, char **argv)
595{ 681{
596 char *host = NULL; 682 int debug_flag = 0, log_level = SYSLOG_LEVEL_INFO;
683 int opt, fopt_count = 0;
684 char *tname;
685
686 extern int optind;
687 extern char *optarg;
597 688
598 __progname = get_progname(argv[0]); 689 __progname = get_progname(argv[0]);
599 TAILQ_INIT(&tq); 690 TAILQ_INIT(&tq);
600 691
601 if (argc <= argno) 692 if (argc <= 1)
602 usage(); 693 usage();
603 694
604 if (argv[1][0] == '-' && argv[1][1] == 't') { 695 while ((opt = getopt(argc, argv, "v46p:T:t:f:")) != -1) {
605 argno++; 696 switch (opt) {
606 if (argv[1][2]) 697 case 'p':
607 timeout = atoi(&argv[1][2]); 698 ssh_port = a2port(optarg);
608 else { 699 if (ssh_port == 0) {
609 if (argno >= argc) 700 fprintf(stderr, "Bad port '%s'\n", optarg);
701 exit(1);
702 }
703 break;
704 case 'T':
705 timeout = atoi(optarg);
706 if (timeout <= 0)
610 usage(); 707 usage();
611 timeout = atoi(argv[argno++]); 708 break;
612 } 709 case 'v':
613 if (timeout <= 0) 710 if (!debug_flag) {
711 debug_flag = 1;
712 log_level = SYSLOG_LEVEL_DEBUG1;
713 }
714 else if (log_level < SYSLOG_LEVEL_DEBUG3)
715 log_level++;
716 else
717 fatal("Too high debugging level.");
718 break;
719 case 'f':
720 if (strcmp(optarg, "-") == 0)
721 optarg = NULL;
722 argv[fopt_count++] = optarg;
723 break;
724 case 't':
725 get_keytypes = 0;
726 tname = strtok(optarg, ",");
727 while (tname) {
728 int type = key_type_from_name(tname);
729 switch (type) {
730 case KEY_RSA1:
731 get_keytypes |= KT_RSA1;
732 break;
733 case KEY_DSA:
734 get_keytypes |= KT_DSA;
735 break;
736 case KEY_RSA:
737 get_keytypes |= KT_RSA;
738 break;
739 case KEY_UNSPEC:
740 fatal("unknown key type %s\n", tname);
741 }
742 tname = strtok(NULL, ",");
743 }
744 break;
745 case '4':
746 IPv4or6 = AF_INET;
747 break;
748 case '6':
749 IPv4or6 = AF_INET6;
750 break;
751 case '?':
752 default:
614 usage(); 753 usage();
754 }
615 } 755 }
616 if (argc <= argno) 756 if (optind == argc && !fopt_count)
617 usage(); 757 usage();
618 758
759 log_init("ssh-keyscan", log_level, SYSLOG_FACILITY_USER, 1);
760 fatal_add_cleanup(fatal_callback, NULL);
761
762
619 maxfd = fdlim_get(1); 763 maxfd = fdlim_get(1);
620 if (maxfd < 0) 764 if (maxfd < 0)
621 fatal("%s: fdlim_get: bad value", __progname); 765 fatal("%s: fdlim_get: bad value", __progname);
@@ -632,18 +776,22 @@ main(int argc, char **argv)
632 read_wait = xmalloc(read_wait_size); 776 read_wait = xmalloc(read_wait_size);
633 memset(read_wait, 0, read_wait_size); 777 memset(read_wait, 0, read_wait_size);
634 778
635 do { 779 if (fopt_count) {
636 while (ncon < MAXCON) { 780 Linebuf *lb;
637 char *name; 781 char *line;
638 782 int j;
639 host = nexthost(argc, argv); 783
640 if (host == NULL) 784 for (j = 0; j < fopt_count; j++) {
641 break; 785 lb = Linebuf_alloc(argv[j], error);
642 name = strnnsep(&host, " \t\n"); 786 while ((line = Linebuf_getline(lb)) != NULL)
643 conalloc(name, *host ? host : name); 787 do_host(line);
788 Linebuf_free(lb);
644 } 789 }
645 conloop(); 790 }
646 } while (host); 791
792 while (optind < argc)
793 do_host(argv[optind++]);
794
647 while (ncon > 0) 795 while (ncon > 0)
648 conloop(); 796 conloop();
649 797