mirror of git://anongit.mindrot.org/openssh.git
upstream: allow ssh-keyscan(1) to accept CIDR address ranges, e.g.
ssh-keyscan 192.168.0.0/24 If a CIDR range is passed, then it will be expanded to all possible addresses in the range including the all-0s and all-1s addresses. bz#976 feedback/ok markus@ OpenBSD-Commit-ID: ce6c5211f936ac0053fd4a2ddb415277931e6c4b
This commit is contained in:
parent
64af420930
commit
1192588546
73
addr.c
73
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>
|
* Copyright (c) 2004-2008 Damien Miller <djm@mindrot.org>
|
||||||
|
@ -227,6 +227,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
|
int
|
||||||
addr_cmp(const struct xaddr *a, const struct xaddr *b)
|
addr_cmp(const struct xaddr *a, const struct xaddr *b)
|
||||||
{
|
{
|
||||||
|
@ -278,6 +300,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'
|
* Test whether host portion of address 'a', as determined by 'masklen'
|
||||||
* is all zeros.
|
* is all zeros.
|
||||||
|
@ -297,6 +342,32 @@ addr_host_is_all0s(const struct xaddr *a, u_int masklen)
|
||||||
return addr_is_all0s(&tmp_result);
|
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'.
|
* Parse string address 'p' into 'n'.
|
||||||
* Returns 0 on success, -1 on failure.
|
* Returns 0 on success, -1 on failure.
|
||||||
|
|
4
addr.h
4
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_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_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_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_cmp(const struct xaddr *a, const struct xaddr *b);
|
||||||
int addr_is_all0s(const struct xaddr *n);
|
int addr_is_all0s(const struct xaddr *n);
|
||||||
int addr_host_is_all0s(const struct xaddr *n, u_int masklen);
|
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,
|
int addr_netmatch(const struct xaddr *host, const struct xaddr *net,
|
||||||
u_int masklen);
|
u_int masklen);
|
||||||
|
void addr_increment(struct xaddr *a);
|
||||||
#endif /* _ADDR_H */
|
#endif /* _ADDR_H */
|
||||||
|
|
|
@ -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>.
|
.\" 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
|
.\" permitted provided that due credit is given to the author and the
|
||||||
.\" OpenBSD project by leaving this copyright notice intact.
|
.\" OpenBSD project by leaving this copyright notice intact.
|
||||||
.\"
|
.\"
|
||||||
.Dd $Mdocdate: June 3 2022 $
|
.Dd $Mdocdate: October 28 2022 $
|
||||||
.Dt SSH-KEYSCAN 1
|
.Dt SSH-KEYSCAN 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
|
@ -44,6 +44,11 @@ For scanning, one does not need
|
||||||
login access to the machines that are being scanned, nor does the
|
login access to the machines that are being scanned, nor does the
|
||||||
scanning process involve any encryption.
|
scanning process involve any encryption.
|
||||||
.Pp
|
.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:
|
The options are as follows:
|
||||||
.Bl -tag -width Ds
|
.Bl -tag -width Ds
|
||||||
.It Fl 4
|
.It Fl 4
|
||||||
|
@ -73,9 +78,16 @@ If
|
||||||
is supplied instead of a filename,
|
is supplied instead of a filename,
|
||||||
.Nm
|
.Nm
|
||||||
will read from the standard input.
|
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
|
.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
|
.Ed
|
||||||
.It Fl H
|
.It Fl H
|
||||||
Hash all hostnames and addresses in the output.
|
Hash all hostnames and addresses in the output.
|
||||||
|
@ -138,6 +150,10 @@ Print the RSA host key for machine
|
||||||
.Pp
|
.Pp
|
||||||
.Dl $ ssh-keyscan -t rsa hostname
|
.Dl $ ssh-keyscan -t rsa hostname
|
||||||
.Pp
|
.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
|
Find all hosts from the file
|
||||||
.Pa ssh_hosts
|
.Pa ssh_hosts
|
||||||
which have new or different keys from those in the sorted file
|
which have new or different keys from those in the sorted file
|
||||||
|
|
|
@ -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>.
|
* Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
|
||||||
*
|
*
|
||||||
|
@ -52,6 +52,7 @@
|
||||||
#include "ssherr.h"
|
#include "ssherr.h"
|
||||||
#include "ssh_api.h"
|
#include "ssh_api.h"
|
||||||
#include "dns.h"
|
#include "dns.h"
|
||||||
|
#include "addr.h"
|
||||||
|
|
||||||
/* Flag indicating whether IPv4 or IPv6. This can be set on the command line.
|
/* Flag indicating whether IPv4 or IPv6. This can be set on the command line.
|
||||||
Default value is AF_UNSPEC means both IPv4 and IPv6. */
|
Default value is AF_UNSPEC means both IPv4 and IPv6. */
|
||||||
|
@ -384,7 +385,7 @@ tcpconnect(char *host)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
conalloc(char *iname, char *oname, int keytype)
|
conalloc(const char *iname, const char *oname, int keytype)
|
||||||
{
|
{
|
||||||
char *namebase, *name, *namelist;
|
char *namebase, *name, *namelist;
|
||||||
int s;
|
int s;
|
||||||
|
@ -629,7 +630,7 @@ conloop(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
do_host(char *host)
|
do_one_host(char *host)
|
||||||
{
|
{
|
||||||
char *name = strnnsep(&host, " \t\n");
|
char *name = strnnsep(&host, " \t\n");
|
||||||
int j;
|
int j;
|
||||||
|
@ -645,6 +646,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
|
void
|
||||||
sshfatal(const char *file, const char *func, int line, int showfunc,
|
sshfatal(const char *file, const char *func, int line, int showfunc,
|
||||||
LogLevel level, const char *suffix, const char *fmt, ...)
|
LogLevel level, const char *suffix, const char *fmt, ...)
|
||||||
|
|
Loading…
Reference in New Issue