summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.bin/ssh/addr.c73
-rw-r--r--usr.bin/ssh/addr.h4
-rw-r--r--usr.bin/ssh/ssh-keyscan.124
-rw-r--r--usr.bin/ssh/ssh-keyscan.c43
4 files changed, 136 insertions, 8 deletions
diff --git a/usr.bin/ssh/addr.c b/usr.bin/ssh/addr.c
index 8774764ce58..056f15903c5 100644
--- a/usr.bin/ssh/addr.c
+++ b/usr.bin/ssh/addr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: addr.c,v 1.5 2022/04/29 04:55:07 djm Exp $ */
+/* $OpenBSD: addr.c,v 1.6 2022/10/28 02:29:34 djm Exp $ */
/*
* Copyright (c) 2004-2008 Damien Miller <djm@mindrot.org>
@@ -224,6 +224,28 @@ addr_and(struct xaddr *dst, const struct xaddr *a, const struct xaddr *b)
}
int
+addr_or(struct xaddr *dst, const struct xaddr *a, const struct xaddr *b)
+{
+ int i;
+
+ if (dst == NULL || a == NULL || b == NULL || a->af != b->af)
+ return (-1);
+
+ memcpy(dst, a, sizeof(*dst));
+ switch (a->af) {
+ case AF_INET:
+ dst->v4.s_addr |= b->v4.s_addr;
+ return (0);
+ case AF_INET6:
+ for (i = 0; i < 4; i++)
+ dst->addr32[i] |= b->addr32[i];
+ return (0);
+ default:
+ return (-1);
+ }
+}
+
+int
addr_cmp(const struct xaddr *a, const struct xaddr *b)
{
int i;
@@ -274,6 +296,29 @@ addr_is_all0s(const struct xaddr *a)
}
}
+/* Increment the specified address. Note, does not do overflow checking */
+void
+addr_increment(struct xaddr *a)
+{
+ int i;
+ uint32_t n;
+
+ switch (a->af) {
+ case AF_INET:
+ a->v4.s_addr = htonl(ntohl(a->v4.s_addr) + 1);
+ break;
+ case AF_INET6:
+ for (i = 0; i < 4; i++) {
+ /* Increment with carry */
+ n = ntohl(a->addr32[3 - i]) + 1;
+ a->addr32[3 - i] = htonl(n);
+ if (n != 0)
+ break;
+ }
+ break;
+ }
+}
+
/*
* Test whether host portion of address 'a', as determined by 'masklen'
* is all zeros.
@@ -293,6 +338,32 @@ addr_host_is_all0s(const struct xaddr *a, u_int masklen)
return addr_is_all0s(&tmp_result);
}
+#if 0
+int
+addr_host_to_all0s(struct xaddr *a, u_int masklen)
+{
+ struct xaddr tmp_mask;
+
+ if (addr_netmask(a->af, masklen, &tmp_mask) == -1)
+ return (-1);
+ if (addr_and(a, a, &tmp_mask) == -1)
+ return (-1);
+ return (0);
+}
+#endif
+
+int
+addr_host_to_all1s(struct xaddr *a, u_int masklen)
+{
+ struct xaddr tmp_mask;
+
+ if (addr_hostmask(a->af, masklen, &tmp_mask) == -1)
+ return (-1);
+ if (addr_or(a, a, &tmp_mask) == -1)
+ return (-1);
+ return (0);
+}
+
/*
* Parse string address 'p' into 'n'.
* Returns 0 on success, -1 on failure.
diff --git a/usr.bin/ssh/addr.h b/usr.bin/ssh/addr.h
index 5eff0262859..180e9fdc644 100644
--- a/usr.bin/ssh/addr.h
+++ b/usr.bin/ssh/addr.h
@@ -52,9 +52,13 @@ int addr_sa_pton(const char *h, const char *s, struct sockaddr *sa,
int addr_pton_cidr(const char *p, struct xaddr *n, u_int *l);
int addr_ntop(const struct xaddr *n, char *p, size_t len);
int addr_and(struct xaddr *dst, const struct xaddr *a, const struct xaddr *b);
+int addr_or(struct xaddr *dst, const struct xaddr *a, const struct xaddr *b);
int addr_cmp(const struct xaddr *a, const struct xaddr *b);
int addr_is_all0s(const struct xaddr *n);
int addr_host_is_all0s(const struct xaddr *n, u_int masklen);
+int addr_host_to_all0s(struct xaddr *a, u_int masklen);
+int addr_host_to_all1s(struct xaddr *a, u_int masklen);
int addr_netmatch(const struct xaddr *host, const struct xaddr *net,
u_int masklen);
+void addr_increment(struct xaddr *a);
#endif /* _ADDR_H */
diff --git a/usr.bin/ssh/ssh-keyscan.1 b/usr.bin/ssh/ssh-keyscan.1
index 4eb0bea0916..ca4feea2a9e 100644
--- a/usr.bin/ssh/ssh-keyscan.1
+++ b/usr.bin/ssh/ssh-keyscan.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: ssh-keyscan.1,v 1.46 2022/06/03 04:00:15 dtucker Exp $
+.\" $OpenBSD: ssh-keyscan.1,v 1.47 2022/10/28 02:29:34 djm Exp $
.\"
.\" Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
.\"
@@ -6,7 +6,7 @@
.\" permitted provided that due credit is given to the author and the
.\" OpenBSD project by leaving this copyright notice intact.
.\"
-.Dd $Mdocdate: June 3 2022 $
+.Dd $Mdocdate: October 28 2022 $
.Dt SSH-KEYSCAN 1
.Os
.Sh NAME
@@ -44,6 +44,11 @@ For scanning, one does not need
login access to the machines that are being scanned, nor does the
scanning process involve any encryption.
.Pp
+Hosts to be scanned may be specified by hostname, address or by CIDR
+network range (e.g. 192.168.16/28).
+If a network range is specified, then all addresses in that range will
+be scanned.
+.Pp
The options are as follows:
.Bl -tag -width Ds
.It Fl 4
@@ -73,9 +78,16 @@ If
is supplied instead of a filename,
.Nm
will read from the standard input.
-Input is expected in the format:
+Names read from a file must start with an address, hostname or CIDR network
+range to be scanned.
+Addresses and hostnames may optionally be followed by comma-separated name
+or address aliases that will be copied to the output.
+For example:
.Bd -literal
-1.2.3.4,1.2.4.4 name.my.domain,name,n.my.domain,n,1.2.3.4,1.2.4.4
+192.168.11.0/24
+10.20.1.1
+happy.example.org
+10.0.0.1,sad.example.org
.Ed
.It Fl H
Hash all hostnames and addresses in the output.
@@ -138,6 +150,10 @@ Print the RSA host key for machine
.Pp
.Dl $ ssh-keyscan -t rsa hostname
.Pp
+Search a network range, printing all supported key types:
+.Pp
+.Dl $ ssh-keyscan 192.168.0.64/25
+.Pp
Find all hosts from the file
.Pa ssh_hosts
which have new or different keys from those in the sorted file
diff --git a/usr.bin/ssh/ssh-keyscan.c b/usr.bin/ssh/ssh-keyscan.c
index 225884e2180..6794b157e13 100644
--- a/usr.bin/ssh/ssh-keyscan.c
+++ b/usr.bin/ssh/ssh-keyscan.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-keyscan.c,v 1.146 2022/08/19 04:02:46 dtucker Exp $ */
+/* $OpenBSD: ssh-keyscan.c,v 1.147 2022/10/28 02:29:34 djm Exp $ */
/*
* Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
*
@@ -44,6 +44,7 @@
#include "ssherr.h"
#include "ssh_api.h"
#include "dns.h"
+#include "addr.h"
/* Flag indicating whether IPv4 or IPv6. This can be set on the command line.
Default value is AF_UNSPEC means both IPv4 and IPv6. */
@@ -364,7 +365,7 @@ tcpconnect(char *host)
}
static int
-conalloc(char *iname, char *oname, int keytype)
+conalloc(const char *iname, const char *oname, int keytype)
{
char *namebase, *name, *namelist;
int s;
@@ -609,7 +610,7 @@ conloop(void)
}
static void
-do_host(char *host)
+do_one_host(char *host)
{
char *name = strnnsep(&host, " \t\n");
int j;
@@ -625,6 +626,42 @@ do_host(char *host)
}
}
+static void
+do_host(char *host)
+{
+ char daddr[128];
+ struct xaddr addr, end_addr;
+ u_int masklen;
+
+ if (host == NULL)
+ return;
+ if (addr_pton_cidr(host, &addr, &masklen) != 0) {
+ /* Assume argument is a hostname */
+ do_one_host(host);
+ } else {
+ /* Argument is a CIDR range */
+ debug("CIDR range %s", host);
+ end_addr = addr;
+ if (addr_host_to_all1s(&end_addr, masklen) != 0)
+ goto badaddr;
+ /*
+ * Note: we deliberately include the all-zero/ones addresses.
+ */
+ for (;;) {
+ if (addr_ntop(&addr, daddr, sizeof(daddr)) != 0) {
+ badaddr:
+ error("Invalid address %s", host);
+ return;
+ }
+ debug("CIDR expand: address %s", daddr);
+ do_one_host(daddr);
+ if (addr_cmp(&addr, &end_addr) == 0)
+ break;
+ addr_increment(&addr);
+ };
+ }
+}
+
void
sshfatal(const char *file, const char *func, int line, int showfunc,
LogLevel level, const char *suffix, const char *fmt, ...)