xref: /freebsd/crypto/openssh/ssh-keyscan.c (revision 9768746b)
1 /* $OpenBSD: ssh-keyscan.c,v 1.149 2022/12/26 19:16:03 jmc Exp $ */
2 /*
3  * Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
4  *
5  * Modification and redistribution in source and binary forms is
6  * permitted provided that due credit is given to the author and the
7  * OpenBSD project by leaving this copyright notice intact.
8  */
9 
10 #include "includes.h"
11 
12 #include <sys/types.h>
13 #include "openbsd-compat/sys-queue.h"
14 #include <sys/resource.h>
15 #ifdef HAVE_SYS_TIME_H
16 # include <sys/time.h>
17 #endif
18 
19 #include <netinet/in.h>
20 #include <arpa/inet.h>
21 
22 #ifdef WITH_OPENSSL
23 #include <openssl/bn.h>
24 #endif
25 
26 #include <netdb.h>
27 #include <errno.h>
28 #ifdef HAVE_POLL_H
29 #include <poll.h>
30 #endif
31 #include <stdarg.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <signal.h>
35 #include <string.h>
36 #include <unistd.h>
37 
38 #include "xmalloc.h"
39 #include "ssh.h"
40 #include "sshbuf.h"
41 #include "sshkey.h"
42 #include "cipher.h"
43 #include "kex.h"
44 #include "compat.h"
45 #include "myproposal.h"
46 #include "packet.h"
47 #include "dispatch.h"
48 #include "log.h"
49 #include "atomicio.h"
50 #include "misc.h"
51 #include "hostfile.h"
52 #include "ssherr.h"
53 #include "ssh_api.h"
54 #include "dns.h"
55 #include "addr.h"
56 
57 /* Flag indicating whether IPv4 or IPv6.  This can be set on the command line.
58    Default value is AF_UNSPEC means both IPv4 and IPv6. */
59 int IPv4or6 = AF_UNSPEC;
60 
61 int ssh_port = SSH_DEFAULT_PORT;
62 
63 #define KT_DSA		(1)
64 #define KT_RSA		(1<<1)
65 #define KT_ECDSA	(1<<2)
66 #define KT_ED25519	(1<<3)
67 #define KT_XMSS		(1<<4)
68 #define KT_ECDSA_SK	(1<<5)
69 #define KT_ED25519_SK	(1<<6)
70 
71 #define KT_MIN		KT_DSA
72 #define KT_MAX		KT_ED25519_SK
73 
74 int get_cert = 0;
75 int get_keytypes = KT_RSA|KT_ECDSA|KT_ED25519|KT_ECDSA_SK|KT_ED25519_SK;
76 
77 int hash_hosts = 0;		/* Hash hostname on output */
78 
79 int print_sshfp = 0;		/* Print SSHFP records instead of known_hosts */
80 
81 int found_one = 0;		/* Successfully found a key */
82 
83 #define MAXMAXFD 256
84 
85 /* The number of seconds after which to give up on a TCP connection */
86 int timeout = 5;
87 
88 int maxfd;
89 #define MAXCON (maxfd - 10)
90 
91 extern char *__progname;
92 struct pollfd *read_wait;
93 int ncon;
94 
95 /*
96  * Keep a connection structure for each file descriptor.  The state
97  * associated with file descriptor n is held in fdcon[n].
98  */
99 typedef struct Connection {
100 	u_char c_status;	/* State of connection on this file desc. */
101 #define CS_UNUSED 0		/* File descriptor unused */
102 #define CS_CON 1		/* Waiting to connect/read greeting */
103 #define CS_SIZE 2		/* Waiting to read initial packet size */
104 #define CS_KEYS 3		/* Waiting to read public key packet */
105 	int c_fd;		/* Quick lookup: c->c_fd == c - fdcon */
106 	int c_plen;		/* Packet length field for ssh packet */
107 	int c_len;		/* Total bytes which must be read. */
108 	int c_off;		/* Length of data read so far. */
109 	int c_keytype;		/* Only one of KT_* */
110 	sig_atomic_t c_done;	/* SSH2 done */
111 	char *c_namebase;	/* Address to free for c_name and c_namelist */
112 	char *c_name;		/* Hostname of connection for errors */
113 	char *c_namelist;	/* Pointer to other possible addresses */
114 	char *c_output_name;	/* Hostname of connection for output */
115 	char *c_data;		/* Data read from this fd */
116 	struct ssh *c_ssh;	/* SSH-connection */
117 	struct timespec c_ts;	/* Time at which connection gets aborted */
118 	TAILQ_ENTRY(Connection) c_link;	/* List of connections in timeout order. */
119 } con;
120 
121 TAILQ_HEAD(conlist, Connection) tq;	/* Timeout Queue */
122 con *fdcon;
123 
124 static void keyprint(con *c, struct sshkey *key);
125 
126 static int
127 fdlim_get(int hard)
128 {
129 #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)
130 	struct rlimit rlfd;
131 
132 	if (getrlimit(RLIMIT_NOFILE, &rlfd) == -1)
133 		return (-1);
134 	if ((hard ? rlfd.rlim_max : rlfd.rlim_cur) == RLIM_INFINITY)
135 		return SSH_SYSFDMAX;
136 	else
137 		return hard ? rlfd.rlim_max : rlfd.rlim_cur;
138 #else
139 	return SSH_SYSFDMAX;
140 #endif
141 }
142 
143 static int
144 fdlim_set(int lim)
145 {
146 #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
147 	struct rlimit rlfd;
148 #endif
149 
150 	if (lim <= 0)
151 		return (-1);
152 #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
153 	if (getrlimit(RLIMIT_NOFILE, &rlfd) == -1)
154 		return (-1);
155 	rlfd.rlim_cur = lim;
156 	if (setrlimit(RLIMIT_NOFILE, &rlfd) == -1)
157 		return (-1);
158 #elif defined (HAVE_SETDTABLESIZE)
159 	setdtablesize(lim);
160 #endif
161 	return (0);
162 }
163 
164 /*
165  * This is an strsep function that returns a null field for adjacent
166  * separators.  This is the same as the 4.4BSD strsep, but different from the
167  * one in the GNU libc.
168  */
169 static char *
170 xstrsep(char **str, const char *delim)
171 {
172 	char *s, *e;
173 
174 	if (!**str)
175 		return (NULL);
176 
177 	s = *str;
178 	e = s + strcspn(s, delim);
179 
180 	if (*e != '\0')
181 		*e++ = '\0';
182 	*str = e;
183 
184 	return (s);
185 }
186 
187 /*
188  * Get the next non-null token (like GNU strsep).  Strsep() will return a
189  * null token for two adjacent separators, so we may have to loop.
190  */
191 static char *
192 strnnsep(char **stringp, char *delim)
193 {
194 	char *tok;
195 
196 	do {
197 		tok = xstrsep(stringp, delim);
198 	} while (tok && *tok == '\0');
199 	return (tok);
200 }
201 
202 
203 static int
204 key_print_wrapper(struct sshkey *hostkey, struct ssh *ssh)
205 {
206 	con *c;
207 
208 	if ((c = ssh_get_app_data(ssh)) != NULL)
209 		keyprint(c, hostkey);
210 	/* always abort key exchange */
211 	return -1;
212 }
213 
214 static int
215 ssh2_capable(int remote_major, int remote_minor)
216 {
217 	switch (remote_major) {
218 	case 1:
219 		if (remote_minor == 99)
220 			return 1;
221 		break;
222 	case 2:
223 		return 1;
224 	default:
225 		break;
226 	}
227 	return 0;
228 }
229 
230 static void
231 keygrab_ssh2(con *c)
232 {
233 	char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT };
234 	int r;
235 
236 	switch (c->c_keytype) {
237 	case KT_DSA:
238 		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
239 		    "ssh-dss-cert-v01@openssh.com" : "ssh-dss";
240 		break;
241 	case KT_RSA:
242 		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
243 		    "rsa-sha2-512-cert-v01@openssh.com,"
244 		    "rsa-sha2-256-cert-v01@openssh.com,"
245 		    "ssh-rsa-cert-v01@openssh.com" :
246 		    "rsa-sha2-512,"
247 		    "rsa-sha2-256,"
248 		    "ssh-rsa";
249 		break;
250 	case KT_ED25519:
251 		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
252 		    "ssh-ed25519-cert-v01@openssh.com" : "ssh-ed25519";
253 		break;
254 	case KT_XMSS:
255 		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
256 		    "ssh-xmss-cert-v01@openssh.com" : "ssh-xmss@openssh.com";
257 		break;
258 	case KT_ECDSA:
259 		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
260 		    "ecdsa-sha2-nistp256-cert-v01@openssh.com,"
261 		    "ecdsa-sha2-nistp384-cert-v01@openssh.com,"
262 		    "ecdsa-sha2-nistp521-cert-v01@openssh.com" :
263 		    "ecdsa-sha2-nistp256,"
264 		    "ecdsa-sha2-nistp384,"
265 		    "ecdsa-sha2-nistp521";
266 		break;
267 	case KT_ECDSA_SK:
268 		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
269 		    "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com" :
270 		    "sk-ecdsa-sha2-nistp256@openssh.com";
271 		break;
272 	case KT_ED25519_SK:
273 		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
274 		    "sk-ssh-ed25519-cert-v01@openssh.com" :
275 		    "sk-ssh-ed25519@openssh.com";
276 		break;
277 	default:
278 		fatal("unknown key type %d", c->c_keytype);
279 		break;
280 	}
281 	if ((r = kex_setup(c->c_ssh, myproposal)) != 0) {
282 		free(c->c_ssh);
283 		fprintf(stderr, "kex_setup: %s\n", ssh_err(r));
284 		exit(1);
285 	}
286 #ifdef WITH_OPENSSL
287 	c->c_ssh->kex->kex[KEX_DH_GRP1_SHA1] = kex_gen_client;
288 	c->c_ssh->kex->kex[KEX_DH_GRP14_SHA1] = kex_gen_client;
289 	c->c_ssh->kex->kex[KEX_DH_GRP14_SHA256] = kex_gen_client;
290 	c->c_ssh->kex->kex[KEX_DH_GRP16_SHA512] = kex_gen_client;
291 	c->c_ssh->kex->kex[KEX_DH_GRP18_SHA512] = kex_gen_client;
292 	c->c_ssh->kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
293 	c->c_ssh->kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
294 # ifdef OPENSSL_HAS_ECC
295 	c->c_ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_client;
296 # endif
297 #endif
298 	c->c_ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client;
299 	c->c_ssh->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_client;
300 	ssh_set_verify_host_key_callback(c->c_ssh, key_print_wrapper);
301 	/*
302 	 * do the key-exchange until an error occurs or until
303 	 * the key_print_wrapper() callback sets c_done.
304 	 */
305 	ssh_dispatch_run(c->c_ssh, DISPATCH_BLOCK, &c->c_done);
306 }
307 
308 static void
309 keyprint_one(const char *host, struct sshkey *key)
310 {
311 	char *hostport = NULL, *hashed = NULL;
312 	const char *known_host;
313 
314 	found_one = 1;
315 
316 	if (print_sshfp) {
317 		export_dns_rr(host, key, stdout, 0);
318 		return;
319 	}
320 
321 	hostport = put_host_port(host, ssh_port);
322 	lowercase(hostport);
323 	if (hash_hosts && (hashed = host_hash(hostport, NULL, 0)) == NULL)
324 		fatal("host_hash failed");
325 	known_host = hash_hosts ? hashed : hostport;
326 	if (!get_cert)
327 		fprintf(stdout, "%s ", known_host);
328 	sshkey_write(key, stdout);
329 	fputs("\n", stdout);
330 	free(hashed);
331 	free(hostport);
332 }
333 
334 static void
335 keyprint(con *c, struct sshkey *key)
336 {
337 	char *hosts = c->c_output_name ? c->c_output_name : c->c_name;
338 	char *host, *ohosts;
339 
340 	if (key == NULL)
341 		return;
342 	if (get_cert || (!hash_hosts && ssh_port == SSH_DEFAULT_PORT)) {
343 		keyprint_one(hosts, key);
344 		return;
345 	}
346 	ohosts = hosts = xstrdup(hosts);
347 	while ((host = strsep(&hosts, ",")) != NULL)
348 		keyprint_one(host, key);
349 	free(ohosts);
350 }
351 
352 static int
353 tcpconnect(char *host)
354 {
355 	struct addrinfo hints, *ai, *aitop;
356 	char strport[NI_MAXSERV];
357 	int gaierr, s = -1;
358 
359 	snprintf(strport, sizeof strport, "%d", ssh_port);
360 	memset(&hints, 0, sizeof(hints));
361 	hints.ai_family = IPv4or6;
362 	hints.ai_socktype = SOCK_STREAM;
363 	if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) {
364 		error("getaddrinfo %s: %s", host, ssh_gai_strerror(gaierr));
365 		return -1;
366 	}
367 	for (ai = aitop; ai; ai = ai->ai_next) {
368 		s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
369 		if (s == -1) {
370 			error("socket: %s", strerror(errno));
371 			continue;
372 		}
373 		if (set_nonblock(s) == -1)
374 			fatal_f("set_nonblock(%d)", s);
375 		if (connect(s, ai->ai_addr, ai->ai_addrlen) == -1 &&
376 		    errno != EINPROGRESS)
377 			error("connect (`%s'): %s", host, strerror(errno));
378 		else
379 			break;
380 		close(s);
381 		s = -1;
382 	}
383 	freeaddrinfo(aitop);
384 	return s;
385 }
386 
387 static int
388 conalloc(const char *iname, const char *oname, int keytype)
389 {
390 	char *namebase, *name, *namelist;
391 	int s;
392 
393 	namebase = namelist = xstrdup(iname);
394 
395 	do {
396 		name = xstrsep(&namelist, ",");
397 		if (!name) {
398 			free(namebase);
399 			return (-1);
400 		}
401 	} while ((s = tcpconnect(name)) < 0);
402 
403 	if (s >= maxfd)
404 		fatal("conalloc: fdno %d too high", s);
405 	if (fdcon[s].c_status)
406 		fatal("conalloc: attempt to reuse fdno %d", s);
407 
408 	debug3_f("oname %s kt %d", oname, keytype);
409 	fdcon[s].c_fd = s;
410 	fdcon[s].c_status = CS_CON;
411 	fdcon[s].c_namebase = namebase;
412 	fdcon[s].c_name = name;
413 	fdcon[s].c_namelist = namelist;
414 	fdcon[s].c_output_name = xstrdup(oname);
415 	fdcon[s].c_data = (char *) &fdcon[s].c_plen;
416 	fdcon[s].c_len = 4;
417 	fdcon[s].c_off = 0;
418 	fdcon[s].c_keytype = keytype;
419 	monotime_ts(&fdcon[s].c_ts);
420 	fdcon[s].c_ts.tv_sec += timeout;
421 	TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link);
422 	read_wait[s].fd = s;
423 	read_wait[s].events = POLLIN;
424 	ncon++;
425 	return (s);
426 }
427 
428 static void
429 confree(int s)
430 {
431 	if (s >= maxfd || fdcon[s].c_status == CS_UNUSED)
432 		fatal("confree: attempt to free bad fdno %d", s);
433 	free(fdcon[s].c_namebase);
434 	free(fdcon[s].c_output_name);
435 	if (fdcon[s].c_status == CS_KEYS)
436 		free(fdcon[s].c_data);
437 	fdcon[s].c_status = CS_UNUSED;
438 	fdcon[s].c_keytype = 0;
439 	if (fdcon[s].c_ssh) {
440 		ssh_packet_close(fdcon[s].c_ssh);
441 		free(fdcon[s].c_ssh);
442 		fdcon[s].c_ssh = NULL;
443 	} else
444 		close(s);
445 	TAILQ_REMOVE(&tq, &fdcon[s], c_link);
446 	read_wait[s].fd = -1;
447 	read_wait[s].events = 0;
448 	ncon--;
449 }
450 
451 static void
452 contouch(int s)
453 {
454 	TAILQ_REMOVE(&tq, &fdcon[s], c_link);
455 	monotime_ts(&fdcon[s].c_ts);
456 	fdcon[s].c_ts.tv_sec += timeout;
457 	TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link);
458 }
459 
460 static int
461 conrecycle(int s)
462 {
463 	con *c = &fdcon[s];
464 	int ret;
465 
466 	ret = conalloc(c->c_namelist, c->c_output_name, c->c_keytype);
467 	confree(s);
468 	return (ret);
469 }
470 
471 static void
472 congreet(int s)
473 {
474 	int n = 0, remote_major = 0, remote_minor = 0;
475 	char buf[256], *cp;
476 	char remote_version[sizeof buf];
477 	size_t bufsiz;
478 	con *c = &fdcon[s];
479 
480 	/* send client banner */
481 	n = snprintf(buf, sizeof buf, "SSH-%d.%d-OpenSSH-keyscan\r\n",
482 	    PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2);
483 	if (n < 0 || (size_t)n >= sizeof(buf)) {
484 		error("snprintf: buffer too small");
485 		confree(s);
486 		return;
487 	}
488 	if (atomicio(vwrite, s, buf, n) != (size_t)n) {
489 		error("write (%s): %s", c->c_name, strerror(errno));
490 		confree(s);
491 		return;
492 	}
493 
494 	/*
495 	 * Read the server banner as per RFC4253 section 4.2.  The "SSH-"
496 	 * protocol identification string may be preceeded by an arbitrarily
497 	 * large banner which we must read and ignore.  Loop while reading
498 	 * newline-terminated lines until we have one starting with "SSH-".
499 	 * The ID string cannot be longer than 255 characters although the
500 	 * preceeding banner lines may (in which case they'll be discarded
501 	 * in multiple iterations of the outer loop).
502 	 */
503 	for (;;) {
504 		memset(buf, '\0', sizeof(buf));
505 		bufsiz = sizeof(buf);
506 		cp = buf;
507 		while (bufsiz-- &&
508 		    (n = atomicio(read, s, cp, 1)) == 1 && *cp != '\n') {
509 			if (*cp == '\r')
510 				*cp = '\n';
511 			cp++;
512 		}
513 		if (n != 1 || strncmp(buf, "SSH-", 4) == 0)
514 			break;
515 	}
516 	if (n == 0) {
517 		switch (errno) {
518 		case EPIPE:
519 			error("%s: Connection closed by remote host", c->c_name);
520 			break;
521 		case ECONNREFUSED:
522 			break;
523 		default:
524 			error("read (%s): %s", c->c_name, strerror(errno));
525 			break;
526 		}
527 		conrecycle(s);
528 		return;
529 	}
530 	if (cp >= buf + sizeof(buf)) {
531 		error("%s: greeting exceeds allowable length", c->c_name);
532 		confree(s);
533 		return;
534 	}
535 	if (*cp != '\n' && *cp != '\r') {
536 		error("%s: bad greeting", c->c_name);
537 		confree(s);
538 		return;
539 	}
540 	*cp = '\0';
541 	if ((c->c_ssh = ssh_packet_set_connection(NULL, s, s)) == NULL)
542 		fatal("ssh_packet_set_connection failed");
543 	ssh_packet_set_timeout(c->c_ssh, timeout, 1);
544 	ssh_set_app_data(c->c_ssh, c);	/* back link */
545 	c->c_ssh->compat = 0;
546 	if (sscanf(buf, "SSH-%d.%d-%[^\n]\n",
547 	    &remote_major, &remote_minor, remote_version) == 3)
548 		compat_banner(c->c_ssh, remote_version);
549 	if (!ssh2_capable(remote_major, remote_minor)) {
550 		debug("%s doesn't support ssh2", c->c_name);
551 		confree(s);
552 		return;
553 	}
554 	fprintf(stderr, "%c %s:%d %s\n", print_sshfp ? ';' : '#',
555 	    c->c_name, ssh_port, chop(buf));
556 	keygrab_ssh2(c);
557 	confree(s);
558 }
559 
560 static void
561 conread(int s)
562 {
563 	con *c = &fdcon[s];
564 	size_t n;
565 
566 	if (c->c_status == CS_CON) {
567 		congreet(s);
568 		return;
569 	}
570 	n = atomicio(read, s, c->c_data + c->c_off, c->c_len - c->c_off);
571 	if (n == 0) {
572 		error("read (%s): %s", c->c_name, strerror(errno));
573 		confree(s);
574 		return;
575 	}
576 	c->c_off += n;
577 
578 	if (c->c_off == c->c_len)
579 		switch (c->c_status) {
580 		case CS_SIZE:
581 			c->c_plen = htonl(c->c_plen);
582 			c->c_len = c->c_plen + 8 - (c->c_plen & 7);
583 			c->c_off = 0;
584 			c->c_data = xmalloc(c->c_len);
585 			c->c_status = CS_KEYS;
586 			break;
587 		default:
588 			fatal("conread: invalid status %d", c->c_status);
589 			break;
590 		}
591 
592 	contouch(s);
593 }
594 
595 static void
596 conloop(void)
597 {
598 	struct timespec seltime, now;
599 	con *c;
600 	int i;
601 
602 	monotime_ts(&now);
603 	c = TAILQ_FIRST(&tq);
604 
605 	if (c && timespeccmp(&c->c_ts, &now, >))
606 		timespecsub(&c->c_ts, &now, &seltime);
607 	else
608 		timespecclear(&seltime);
609 
610 	while (ppoll(read_wait, maxfd, &seltime, NULL) == -1) {
611 		if (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK)
612 			continue;
613 		error("poll error");
614 	}
615 
616 	for (i = 0; i < maxfd; i++) {
617 		if (read_wait[i].revents & (POLLHUP|POLLERR|POLLNVAL))
618 			confree(i);
619 		else if (read_wait[i].revents & (POLLIN|POLLHUP))
620 			conread(i);
621 	}
622 
623 	c = TAILQ_FIRST(&tq);
624 	while (c && timespeccmp(&c->c_ts, &now, <)) {
625 		int s = c->c_fd;
626 
627 		c = TAILQ_NEXT(c, c_link);
628 		conrecycle(s);
629 	}
630 }
631 
632 static void
633 do_one_host(char *host)
634 {
635 	char *name = strnnsep(&host, " \t\n");
636 	int j;
637 
638 	if (name == NULL)
639 		return;
640 	for (j = KT_MIN; j <= KT_MAX; j *= 2) {
641 		if (get_keytypes & j) {
642 			while (ncon >= MAXCON)
643 				conloop();
644 			conalloc(name, *host ? host : name, j);
645 		}
646 	}
647 }
648 
649 static void
650 do_host(char *host)
651 {
652 	char daddr[128];
653 	struct xaddr addr, end_addr;
654 	u_int masklen;
655 
656 	if (host == NULL)
657 		return;
658 	if (addr_pton_cidr(host, &addr, &masklen) != 0) {
659 		/* Assume argument is a hostname */
660 		do_one_host(host);
661 	} else {
662 		/* Argument is a CIDR range */
663 		debug("CIDR range %s", host);
664 		end_addr = addr;
665 		if (addr_host_to_all1s(&end_addr, masklen) != 0)
666 			goto badaddr;
667 		/*
668 		 * Note: we deliberately include the all-zero/ones addresses.
669 		 */
670 		for (;;) {
671 			if (addr_ntop(&addr, daddr, sizeof(daddr)) != 0) {
672  badaddr:
673 				error("Invalid address %s", host);
674 				return;
675 			}
676 			debug("CIDR expand: address %s", daddr);
677 			do_one_host(daddr);
678 			if (addr_cmp(&addr, &end_addr) == 0)
679 				break;
680 			addr_increment(&addr);
681 		};
682 	}
683 }
684 
685 void
686 sshfatal(const char *file, const char *func, int line, int showfunc,
687     LogLevel level, const char *suffix, const char *fmt, ...)
688 {
689 	va_list args;
690 
691 	va_start(args, fmt);
692 	sshlogv(file, func, line, showfunc, level, suffix, fmt, args);
693 	va_end(args);
694 	cleanup_exit(255);
695 }
696 
697 static void
698 usage(void)
699 {
700 	fprintf(stderr,
701 	    "usage: %s [-46cDHv] [-f file] [-p port] [-T timeout] [-t type]\n"
702 	    "\t\t   [host | addrlist namelist]\n",
703 	    __progname);
704 	exit(1);
705 }
706 
707 int
708 main(int argc, char **argv)
709 {
710 	int debug_flag = 0, log_level = SYSLOG_LEVEL_INFO;
711 	int opt, fopt_count = 0, j;
712 	char *tname, *cp, *line = NULL;
713 	size_t linesize = 0;
714 	FILE *fp;
715 
716 	extern int optind;
717 	extern char *optarg;
718 
719 	__progname = ssh_get_progname(argv[0]);
720 	seed_rng();
721 	TAILQ_INIT(&tq);
722 
723 	/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
724 	sanitise_stdfd();
725 
726 	if (argc <= 1)
727 		usage();
728 
729 	while ((opt = getopt(argc, argv, "cDHv46p:T:t:f:")) != -1) {
730 		switch (opt) {
731 		case 'H':
732 			hash_hosts = 1;
733 			break;
734 		case 'c':
735 			get_cert = 1;
736 			break;
737 		case 'D':
738 			print_sshfp = 1;
739 			break;
740 		case 'p':
741 			ssh_port = a2port(optarg);
742 			if (ssh_port <= 0) {
743 				fprintf(stderr, "Bad port '%s'\n", optarg);
744 				exit(1);
745 			}
746 			break;
747 		case 'T':
748 			timeout = convtime(optarg);
749 			if (timeout == -1 || timeout == 0) {
750 				fprintf(stderr, "Bad timeout '%s'\n", optarg);
751 				usage();
752 			}
753 			break;
754 		case 'v':
755 			if (!debug_flag) {
756 				debug_flag = 1;
757 				log_level = SYSLOG_LEVEL_DEBUG1;
758 			}
759 			else if (log_level < SYSLOG_LEVEL_DEBUG3)
760 				log_level++;
761 			else
762 				fatal("Too high debugging level.");
763 			break;
764 		case 'f':
765 			if (strcmp(optarg, "-") == 0)
766 				optarg = NULL;
767 			argv[fopt_count++] = optarg;
768 			break;
769 		case 't':
770 			get_keytypes = 0;
771 			tname = strtok(optarg, ",");
772 			while (tname) {
773 				int type = sshkey_type_from_name(tname);
774 
775 				switch (type) {
776 				case KEY_DSA:
777 					get_keytypes |= KT_DSA;
778 					break;
779 				case KEY_ECDSA:
780 					get_keytypes |= KT_ECDSA;
781 					break;
782 				case KEY_RSA:
783 					get_keytypes |= KT_RSA;
784 					break;
785 				case KEY_ED25519:
786 					get_keytypes |= KT_ED25519;
787 					break;
788 				case KEY_XMSS:
789 					get_keytypes |= KT_XMSS;
790 					break;
791 				case KEY_ED25519_SK:
792 					get_keytypes |= KT_ED25519_SK;
793 					break;
794 				case KEY_ECDSA_SK:
795 					get_keytypes |= KT_ECDSA_SK;
796 					break;
797 				case KEY_UNSPEC:
798 				default:
799 					fatal("Unknown key type \"%s\"", tname);
800 				}
801 				tname = strtok(NULL, ",");
802 			}
803 			break;
804 		case '4':
805 			IPv4or6 = AF_INET;
806 			break;
807 		case '6':
808 			IPv4or6 = AF_INET6;
809 			break;
810 		default:
811 			usage();
812 		}
813 	}
814 	if (optind == argc && !fopt_count)
815 		usage();
816 
817 	log_init("ssh-keyscan", log_level, SYSLOG_FACILITY_USER, 1);
818 
819 	maxfd = fdlim_get(1);
820 	if (maxfd < 0)
821 		fatal("%s: fdlim_get: bad value", __progname);
822 	if (maxfd > MAXMAXFD)
823 		maxfd = MAXMAXFD;
824 	if (MAXCON <= 0)
825 		fatal("%s: not enough file descriptors", __progname);
826 	if (maxfd > fdlim_get(0))
827 		fdlim_set(maxfd);
828 	fdcon = xcalloc(maxfd, sizeof(con));
829 	read_wait = xcalloc(maxfd, sizeof(struct pollfd));
830 	for (j = 0; j < maxfd; j++)
831 		read_wait[j].fd = -1;
832 
833 	for (j = 0; j < fopt_count; j++) {
834 		if (argv[j] == NULL)
835 			fp = stdin;
836 		else if ((fp = fopen(argv[j], "r")) == NULL)
837 			fatal("%s: %s: %s", __progname, argv[j], strerror(errno));
838 
839 		while (getline(&line, &linesize, fp) != -1) {
840 			/* Chomp off trailing whitespace and comments */
841 			if ((cp = strchr(line, '#')) == NULL)
842 				cp = line + strlen(line) - 1;
843 			while (cp >= line) {
844 				if (*cp == ' ' || *cp == '\t' ||
845 				    *cp == '\n' || *cp == '#')
846 					*cp-- = '\0';
847 				else
848 					break;
849 			}
850 
851 			/* Skip empty lines */
852 			if (*line == '\0')
853 				continue;
854 
855 			do_host(line);
856 		}
857 
858 		if (ferror(fp))
859 			fatal("%s: %s: %s", __progname, argv[j], strerror(errno));
860 
861 		fclose(fp);
862 	}
863 	free(line);
864 
865 	while (optind < argc)
866 		do_host(argv[optind++]);
867 
868 	while (ncon > 0)
869 		conloop();
870 
871 	return found_one ? 0 : 1;
872 }
873