[openssh-commits] [openssh] 04/05: upstream: add a "match localnetwork" predicate.

git+noreply at mindrot.org git+noreply at mindrot.org
Mon Jul 17 14:54:06 AEST 2023


This is an automated email from the git hooks/post-receive script.

djm pushed a commit to branch master
in repository openssh.

commit 3071d85a47061c1bdaf11a0ac233b501ecba862c
Author: djm at openbsd.org <djm at openbsd.org>
Date:   Mon Jul 17 04:04:36 2023 +0000

    upstream: add a "match localnetwork" predicate.
    
    This allows matching on the addresses of available network interfaces
    and may be used to vary the effective client configuration based on
    network location (e.g. to use a ProxyJump when not on a particular
    network).
    
    ok markus@
    
    OpenBSD-Commit-ID: cffb6ff9a3803abfc52b5cad0aa190c5e424c139
---
 readconf.c   | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 ssh_config.5 | 16 +++++++++++--
 2 files changed, 87 insertions(+), 6 deletions(-)

diff --git a/readconf.c b/readconf.c
index bb3bf767..28f6acce 100644
--- a/readconf.c
+++ b/readconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: readconf.c,v 1.377 2023/06/21 05:10:26 djm Exp $ */
+/* $OpenBSD: readconf.c,v 1.378 2023/07/17 04:04:36 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo at cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo at cs.hut.fi>, Espoo, Finland
@@ -20,6 +20,7 @@
 #include <sys/wait.h>
 #include <sys/un.h>
 
+#include <net/if.h>
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
@@ -28,6 +29,9 @@
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
+#ifdef HAVE_IFADDRS_H
+# include <ifaddrs.h>
+#endif
 #include <limits.h>
 #include <netdb.h>
 #ifdef HAVE_PATHS_H
@@ -576,6 +580,60 @@ execute_in_shell(const char *cmd)
 	return WEXITSTATUS(status);
 }
 
+/*
+ * Check whether a local network interface address appears in CIDR pattern-
+ * list 'addrlist'. Returns 1 if matched or 0 otherwise.
+ */
+static int
+check_match_ifaddrs(const char *addrlist)
+{
+	struct ifaddrs *ifa, *ifaddrs = NULL;
+	int r, found = 0;
+	char addr[NI_MAXHOST];
+	socklen_t salen;
+
+	if (getifaddrs(&ifaddrs) != 0) {
+		error("match localnetwork: getifaddrs failed: %s",
+		    strerror(errno));
+		return 0;
+	}
+	for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
+		if (ifa->ifa_addr == NULL || ifa->ifa_name == NULL ||
+		    (ifa->ifa_flags & IFF_UP) == 0)
+			continue;
+		switch (ifa->ifa_addr->sa_family) {
+		case AF_INET:
+			salen = sizeof(struct sockaddr_in);
+			break;
+		case AF_INET6:
+			salen = sizeof(struct sockaddr_in6);
+			break;
+		case AF_LINK:
+			/* ignore */
+			continue;
+		default:
+			debug2_f("interface %s: unsupported address family %d",
+			    ifa->ifa_name, ifa->ifa_addr->sa_family);
+			continue;
+		}
+		if ((r = getnameinfo(ifa->ifa_addr, salen, addr, sizeof(addr),
+		    NULL, 0, NI_NUMERICHOST)) != 0) {
+			debug2_f("interface %s getnameinfo failed: %s",
+			    ifa->ifa_name, gai_strerror(r));
+			continue;
+		}
+		debug3_f("interface %s addr %s", ifa->ifa_name, addr);
+		if (addr_match_cidr_list(addr, addrlist) == 1) {
+			debug3_f("matched interface %s: address %s in %s",
+			    ifa->ifa_name, addr, addrlist);
+			found = 1;
+			break;
+		}
+	}
+	freeifaddrs(ifaddrs);
+	return found;
+}
+
 /*
  * Parse and execute a Match directive.
  */
@@ -680,6 +738,15 @@ match_cfg_line(Options *options, char **condition, struct passwd *pw,
 			r = match_pattern_list(pw->pw_name, arg, 0) == 1;
 			if (r == (negate ? 1 : 0))
 				this_result = result = 0;
+		} else if (strcasecmp(attrib, "localnetwork") == 0) {
+			if (addr_match_cidr_list(NULL, arg) == -1) {
+				/* Error already printed */
+				result = -1;
+				goto out;
+			}
+			r = check_match_ifaddrs(arg) == 1;
+			if (r == (negate ? 1 : 0))
+				this_result = result = 0;
 		} else if (strcasecmp(attrib, "exec") == 0) {
 			char *conn_hash_hex, *keyalias;
 
@@ -733,9 +800,11 @@ match_cfg_line(Options *options, char **condition, struct passwd *pw,
 			result = -1;
 			goto out;
 		}
-		debug3("%.200s line %d: %smatched '%s \"%.100s\"' ",
-		    filename, linenum, this_result ? "": "not ",
-		    oattrib, criteria);
+		debug3("%.200s line %d: %smatched '%s%s%.100s%s' ",
+		    filename, linenum, this_result ? "": "not ", oattrib,
+		    criteria == NULL ? "" : " \"",
+		    criteria == NULL ? "" : criteria,
+		    criteria == NULL ? "" : "\"");
 		free(criteria);
 	}
 	if (attributes == 0) {
diff --git a/ssh_config.5 b/ssh_config.5
index 0b7d4d19..3d18fb2a 100644
--- a/ssh_config.5
+++ b/ssh_config.5
@@ -33,8 +33,8 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.\" $OpenBSD: ssh_config.5,v 1.380 2023/03/27 03:56:11 dtucker Exp $
-.Dd $Mdocdate: March 27 2023 $
+.\" $OpenBSD: ssh_config.5,v 1.381 2023/07/17 04:04:36 djm Exp $
+.Dd $Mdocdate: July 17 2023 $
 .Dt SSH_CONFIG 5
 .Os
 .Sh NAME
@@ -141,6 +141,7 @@ The available criteria keywords are:
 .Cm canonical ,
 .Cm final ,
 .Cm exec ,
+.Cm localnetwork ,
 .Cm host ,
 .Cm originalhost ,
 .Cm user ,
@@ -195,6 +196,17 @@ accept the tokens described in the
 .Sx TOKENS
 section.
 .Pp
+The
+.Cm localnetwork
+keyword matches the addresses of active local network interfaces against the
+supplied list of networks in CIDR format.
+This may be convenient for varying the effective configuration on devices that
+roam between networks.
+Note that network address is not a trustworthy criteria in many
+situations (e.g. when the network is automatically configured using DHCP)
+and so caution should be applied if using it to control security-sensitive
+configuration.
+.Pp
 The other keywords' criteria must be single entries or comma-separated
 lists and may use the wildcard and negation operators described in the
 .Sx PATTERNS

-- 
To stop receiving notification emails like this one, please contact
djm at mindrot.org.


More information about the openssh-commits mailing list