-/* $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@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
#include <sys/wait.h>
#include <sys/un.h>
+#include <net/if.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <errno.h>
#include <fcntl.h>
#include <glob.h>
+#include <ifaddrs.h>
#include <netdb.h>
#include <paths.h>
#include <pwd.h>
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.
*/
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;
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) {
.\" (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
.Cm canonical ,
.Cm final ,
.Cm exec ,
+.Cm localnetwork ,
.Cm host ,
.Cm originalhost ,
.Cm user ,
.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