[openssh-commits] [openssh] 01/01: upstream commit

git+noreply at mindrot.org git+noreply at mindrot.org
Fri Jul 15 14:20:14 AEST 2016


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

djm pushed a commit to branch master
in repository openssh.

commit ed877ef653847d056bb433975d731b7a1132a979
Author: djm at openbsd.org <djm at openbsd.org>
Date:   Fri Jul 15 00:24:30 2016 +0000

    upstream commit
    
    Add a ProxyJump ssh_config(5) option and corresponding -J
    ssh(1) command-line flag to allow simplified indirection through a SSH
    bastion or "jump host".
    
    These options construct a proxy command that connects to the
    specified jump host(s) (more than one may be specified) and uses
    port-forwarding to establish a connection to the next destination.
    
    This codifies the safest way of indirecting connections through SSH
    servers and makes it easy to use.
    
    ok markus@
    
    Upstream-ID: fa899cb8b26d889da8f142eb9774c1ea36b04397
---
 misc.c       | 63 +++++++++++++++++++++++++++++++++++++++-
 misc.h       |  3 +-
 readconf.c   | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 readconf.h   |  8 ++++-
 ssh.1        | 24 +++++++++++++--
 ssh.c        | 77 +++++++++++++++++++++++++++++++++++++++---------
 ssh_config.5 | 28 ++++++++++++++++--
 7 files changed, 271 insertions(+), 27 deletions(-)

diff --git a/misc.c b/misc.c
index 9d59ca6..9421b4d 100644
--- a/misc.c
+++ b/misc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: misc.c,v 1.104 2016/04/06 06:42:17 djm Exp $ */
+/* $OpenBSD: misc.c,v 1.105 2016/07/15 00:24:30 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  * Copyright (c) 2005,2006 Damien Miller.  All rights reserved.
@@ -451,6 +451,67 @@ colon(char *cp)
 	return NULL;
 }
 
+/*
+ * Parse a [user@]host[:port] string.
+ * Caller must free returned user and host.
+ * Any of the pointer return arguments may be NULL (useful for syntax checking).
+ * If user was not specified then *userp will be set to NULL.
+ * If port was not specified then *portp will be -1.
+ * Returns 0 on success, -1 on failure.
+ */
+int
+parse_user_host_port(const char *s, char **userp, char **hostp, int *portp)
+{
+	char *sdup, *cp, *tmp;
+	char *user = NULL, *host = NULL;
+	int port = -1, ret = -1;
+
+	if (userp != NULL)
+		*userp = NULL;
+	if (hostp != NULL)
+		*hostp = NULL;
+	if (portp != NULL)
+		*portp = -1;
+
+	if ((sdup = tmp = strdup(s)) == NULL)
+		return -1;
+	/* Extract optional username */
+	if ((cp = strchr(tmp, '@')) != NULL) {
+		*cp = '\0';
+		if (*tmp == '\0')
+			goto out;
+		if ((user = strdup(tmp)) == NULL)
+			goto out;
+		tmp = cp + 1;
+	}
+	/* Extract mandatory hostname */
+	if ((cp = hpdelim(&tmp)) == NULL || *cp == '\0')
+		goto out;
+	host = xstrdup(cleanhostname(cp));
+	/* Convert and verify optional port */
+	if (tmp != NULL && *tmp != '\0') {
+		if ((port = a2port(tmp)) <= 0)
+			goto out;
+	}
+	/* Success */
+	if (userp != NULL) {
+		*userp = user;
+		user = NULL;
+	}
+	if (hostp != NULL) {
+		*hostp = host;
+		host = NULL;
+	}
+	if (portp != NULL)
+		*portp = port;
+	ret = 0;
+ out:
+	free(sdup);
+	free(user);
+	free(host);
+	return ret;
+}
+
 /* function to assist building execv() arguments */
 void
 addargs(arglist *args, char *fmt, ...)
diff --git a/misc.h b/misc.h
index 01432ba..7c76a6a 100644
--- a/misc.h
+++ b/misc.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: misc.h,v 1.56 2016/04/06 06:42:17 djm Exp $ */
+/* $OpenBSD: misc.h,v 1.57 2016/07/15 00:24:30 djm Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo at cs.hut.fi>
@@ -49,6 +49,7 @@ char	*put_host_port(const char *, u_short);
 char	*hpdelim(char **);
 char	*cleanhostname(char *);
 char	*colon(char *);
+int	 parse_user_host_port(const char *, char **, char **, int *);
 long	 convtime(const char *);
 char	*tilde_expand_filename(const char *, uid_t);
 char	*percent_expand(const char *, ...) __attribute__((__sentinel__));
diff --git a/readconf.c b/readconf.c
index 9dcc383..cb2999d 100644
--- a/readconf.c
+++ b/readconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: readconf.c,v 1.256 2016/06/03 04:09:38 dtucker Exp $ */
+/* $OpenBSD: readconf.c,v 1.257 2016/07/15 00:24:30 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo at cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo at cs.hut.fi>, Espoo, Finland
@@ -170,7 +170,7 @@ typedef enum {
 	oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
 	oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
 	oFingerprintHash, oUpdateHostkeys, oHostbasedKeyTypes,
-	oPubkeyAcceptedKeyTypes,
+	oPubkeyAcceptedKeyTypes, oProxyJump,
 	oIgnoredUnknownOption, oDeprecated, oUnsupported
 } OpCodes;
 
@@ -295,6 +295,7 @@ static struct {
 	{ "hostbasedkeytypes", oHostbasedKeyTypes },
 	{ "pubkeyacceptedkeytypes", oPubkeyAcceptedKeyTypes },
 	{ "ignoreunknown", oIgnoreUnknown },
+	{ "proxyjump", oProxyJump },
 
 	{ NULL, oBadOption }
 };
@@ -1121,6 +1122,9 @@ parse_char_array:
 
 	case oProxyCommand:
 		charptr = &options->proxy_command;
+		/* Ignore ProxyCommand if ProxyJump already specified */
+		if (options->jump_host != NULL)
+			charptr = &options->jump_host; /* Skip below */
 parse_command:
 		if (s == NULL)
 			fatal("%.200s line %d: Missing argument.", filename, linenum);
@@ -1129,6 +1133,18 @@ parse_command:
 			*charptr = xstrdup(s + len);
 		return 0;
 
+	case oProxyJump:
+		if (s == NULL) {
+			fatal("%.200s line %d: Missing argument.",
+			    filename, linenum);
+		}
+		len = strspn(s, WHITESPACE "=");
+		if (parse_jump(s + len, options, *activep) == -1) {
+			fatal("%.200s line %d: Invalid ProxyJump \"%s\"",
+			    filename, linenum, s + len);
+		}
+		return 0;
+
 	case oPort:
 		intptr = &options->port;
 parse_int:
@@ -1789,6 +1805,10 @@ initialize_options(Options * options)
 	options->hostname = NULL;
 	options->host_key_alias = NULL;
 	options->proxy_command = NULL;
+	options->jump_user = NULL;
+	options->jump_host = NULL;
+	options->jump_port = -1;
+	options->jump_extra = NULL;
 	options->user = NULL;
 	options->escape_char = -1;
 	options->num_system_hostfiles = 0;
@@ -2261,6 +2281,44 @@ parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remo
 	return (0);
 }
 
+int
+parse_jump(const char *s, Options *o, int active)
+{
+	char *orig, *sdup, *cp;
+	char *host = NULL, *user = NULL;
+	int ret = -1, port = -1;
+
+	active &= o->proxy_command == NULL && o->jump_host == NULL;
+
+	orig = sdup = xstrdup(s);
+	while ((cp = strsep(&sdup, ",")) && cp != NULL) {
+		if (active) {
+			/* First argument and configuration is active */
+			if (parse_user_host_port(cp, &user, &host, &port) != 0)
+				goto out;
+		} else {
+			/* Subsequent argument or inactive configuration */
+			if (parse_user_host_port(cp, NULL, NULL, NULL) != 0)
+				goto out;
+		}
+		active = 0; /* only check syntax for subsequent hosts */
+	}
+	/* success */
+	free(orig);
+	o->jump_user = user;
+	o->jump_host = host;
+	o->jump_port = port;
+	o->proxy_command = xstrdup("none");
+	user = host = NULL;
+	if ((cp = strchr(s, ',')) != NULL && cp[1] != '\0')
+		o->jump_extra = xstrdup(cp + 1);
+	ret = 0;
+ out:
+	free(user);
+	free(host);
+	return ret;
+}
+
 /* XXX the following is a near-vebatim copy from servconf.c; refactor */
 static const char *
 fmt_multistate_int(int val, const struct multistate *m)
@@ -2412,7 +2470,7 @@ void
 dump_client_config(Options *o, const char *host)
 {
 	int i;
-	char vbuf[5];
+	char buf[8];
 
 	/* This is normally prepared in ssh_kex2 */
 	if (kex_assemble_names(KEX_DEFAULT_PK_ALG, &o->hostkeyalgorithms) != 0)
@@ -2490,7 +2548,6 @@ dump_client_config(Options *o, const char *host)
 	dump_cfg_string(oMacs, o->macs ? o->macs : KEX_CLIENT_MAC);
 	dump_cfg_string(oPKCS11Provider, o->pkcs11_provider);
 	dump_cfg_string(oPreferredAuthentications, o->preferred_authentications);
-	dump_cfg_string(oProxyCommand, o->proxy_command);
 	dump_cfg_string(oPubkeyAcceptedKeyTypes, o->pubkey_key_types);
 	dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys);
 	dump_cfg_string(oXAuthLocation, o->xauth_location);
@@ -2551,8 +2608,8 @@ dump_client_config(Options *o, const char *host)
 	if (o->escape_char == SSH_ESCAPECHAR_NONE)
 		printf("escapechar none\n");
 	else {
-		vis(vbuf, o->escape_char, VIS_WHITE, 0);
-		printf("escapechar %s\n", vbuf);
+		vis(buf, o->escape_char, VIS_WHITE, 0);
+		printf("escapechar %s\n", buf);
 	}
 
 	/* oIPQoS */
@@ -2566,4 +2623,30 @@ dump_client_config(Options *o, const char *host)
 	/* oStreamLocalBindMask */
 	printf("streamlocalbindmask 0%o\n",
 	    o->fwd_opts.streamlocal_bind_mask);
+
+	/* oProxyCommand / oProxyJump */
+	if (o->jump_host == NULL)
+		dump_cfg_string(oProxyCommand, o->proxy_command);
+	else {
+		/* Check for numeric addresses */
+		i = strchr(o->jump_host, ':') != NULL ||
+		    strspn(o->jump_host, "1234567890.") == strlen(o->jump_host);
+		snprintf(buf, sizeof(buf), "%d", o->jump_port);
+		printf("proxyjump %s%s%s%s%s%s%s%s%s\n",
+		    /* optional user */
+		    o->jump_user == NULL ? "" : o->jump_user,
+		    o->jump_user == NULL ? "" : "@",
+		    /* opening [ if hostname is numeric */
+		    i ? "[" : "",
+		    /* mandatory hostname */
+		    o->jump_host,
+		    /* closing ] if hostname is numeric */
+		    i ? "]" : "",
+		    /* optional port number */
+		    o->jump_port <= 0 ? "" : ":",
+		    o->jump_port <= 0 ? "" : buf,
+		    /* optional additional jump spec */
+		    o->jump_extra == NULL ? "" : ",",
+		    o->jump_extra == NULL ? "" : o->jump_extra);
+	}
 }
diff --git a/readconf.h b/readconf.h
index a8b0b91..cef55f7 100644
--- a/readconf.h
+++ b/readconf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: readconf.h,v 1.116 2016/06/03 03:14:41 dtucker Exp $ */
+/* $OpenBSD: readconf.h,v 1.117 2016/07/15 00:24:30 djm Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo at cs.hut.fi>
@@ -163,6 +163,11 @@ typedef struct {
 	char   *hostbased_key_types;
 	char   *pubkey_key_types;
 
+	char   *jump_user;
+	char   *jump_host;
+	int	jump_port;
+	char   *jump_extra;
+
 	char	*ignored_unknown; /* Pattern list of unknown tokens to ignore */
 }       Options;
 
@@ -198,6 +203,7 @@ int	 process_config_line(Options *, struct passwd *, const char *,
 int	 read_config_file(const char *, struct passwd *, const char *,
     const char *, Options *, int);
 int	 parse_forward(struct Forward *, const char *, int, int);
+int	 parse_jump(const char *, Options *, int);
 int	 default_ssh_port(void);
 int	 option_clear_or_none(const char *);
 void	 dump_client_config(Options *o, const char *host);
diff --git a/ssh.1 b/ssh.1
index 32949b0..f3492b4 100644
--- a/ssh.1
+++ b/ssh.1
@@ -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.1,v 1.374 2016/06/29 17:14:28 jmc Exp $
-.Dd $Mdocdate: June 29 2016 $
+.\" $OpenBSD: ssh.1,v 1.375 2016/07/15 00:24:30 djm Exp $
+.Dd $Mdocdate: July 15 2016 $
 .Dt SSH 1
 .Os
 .Sh NAME
@@ -52,6 +52,7 @@
 .Op Fl F Ar configfile
 .Op Fl I Ar pkcs11
 .Op Fl i Ar identity_file
+.Oo Fl J Ar user Ns @ Oc Ns Ar host Ns Op : Ns Ar port
 .Op Fl L Ar address
 .Op Fl l Ar login_name
 .Op Fl m Ar mac_spec
@@ -312,6 +313,24 @@ by appending
 .Pa -cert.pub
 to identity filenames.
 .Pp
+.It Fl J Xo
+.Sm off
+.Oo Ar jump_user @ Oc
+.Ar jump_host
+.Ns Op : Ns Ar jump_port
+.Sm on
+.Xc
+Connect to the target host by first making a
+.Nm
+connection to
+.Ar jump_host
+and then establishing a TCP forward to the ultimate destination from
+there.
+Multiple jump hops may be specified separated by comma characters.
+This is a shortcut to specify a
+.Cm ProxyJump
+configuration directive.
+.Pp
 .It Fl K
 Enables GSSAPI-based authentication and forwarding (delegation) of GSSAPI
 credentials to the server.
@@ -523,6 +542,7 @@ For full details of the options listed below, and their possible values, see
 .It PreferredAuthentications
 .It Protocol
 .It ProxyCommand
+.It ProxyJump
 .It ProxyUseFdpass
 .It PubkeyAcceptedKeyTypes
 .It PubkeyAuthentication
diff --git a/ssh.c b/ssh.c
index e7d4fd9..a9b6853 100644
--- a/ssh.c
+++ b/ssh.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh.c,v 1.442 2016/06/03 04:09:39 dtucker Exp $ */
+/* $OpenBSD: ssh.c,v 1.443 2016/07/15 00:24:30 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo at cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo at cs.hut.fi>, Espoo, Finland
@@ -330,7 +330,7 @@ resolve_addr(const char *name, int port, char *caddr, size_t clen)
  * NB. this function must operate with a options having undefined members.
  */
 static int
-check_follow_cname(char **namep, const char *cname)
+check_follow_cname(int direct, char **namep, const char *cname)
 {
 	int i;
 	struct allowed_cname *rule;
@@ -342,9 +342,9 @@ check_follow_cname(char **namep, const char *cname)
 		return 0;
 	/*
 	 * Don't attempt to canonicalize names that will be interpreted by
-	 * a proxy unless the user specifically requests so.
+	 * a proxy or jump host unless the user specifically requests so.
 	 */
-	if (!option_clear_or_none(options.proxy_command) &&
+	if (!direct &&
 	    options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS)
 		return 0;
 	debug3("%s: check \"%s\" CNAME \"%s\"", __func__, *namep, cname);
@@ -371,7 +371,7 @@ check_follow_cname(char **namep, const char *cname)
 static struct addrinfo *
 resolve_canonicalize(char **hostp, int port)
 {
-	int i, ndots;
+	int i, direct, ndots;
 	char *cp, *fullhost, newname[NI_MAXHOST];
 	struct addrinfo *addrs;
 
@@ -382,7 +382,9 @@ resolve_canonicalize(char **hostp, int port)
 	 * Don't attempt to canonicalize names that will be interpreted by
 	 * a proxy unless the user specifically requests so.
 	 */
-	if (!option_clear_or_none(options.proxy_command) &&
+	direct = option_clear_or_none(options.proxy_command) &&
+	    options.jump_host == NULL;
+	if (!direct &&
 	    options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS)
 		return NULL;
 
@@ -437,7 +439,7 @@ resolve_canonicalize(char **hostp, int port)
 		/* Remove trailing '.' */
 		fullhost[strlen(fullhost) - 1] = '\0';
 		/* Follow CNAME if requested */
-		if (!check_follow_cname(&fullhost, newname)) {
+		if (!check_follow_cname(direct, &fullhost, newname)) {
 			debug("Canonicalized hostname \"%s\" => \"%s\"",
 			    *hostp, fullhost);
 		}
@@ -510,7 +512,7 @@ int
 main(int ac, char **av)
 {
 	struct ssh *ssh = NULL;
-	int i, r, opt, exit_status, use_syslog, config_test = 0;
+	int i, r, opt, exit_status, use_syslog, direct, config_test = 0;
 	char *p, *cp, *line, *argv0, buf[PATH_MAX], *host_arg, *logfile;
 	char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
 	char cname[NI_MAXHOST], uidstr[32], *conn_hash_hex;
@@ -603,7 +605,7 @@ main(int ac, char **av)
 
  again:
 	while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx"
-	    "ACD:E:F:GI:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) {
+	    "ACD:E:F:GI:J:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) {
 		switch (opt) {
 		case '1':
 			options.protocol = SSH_PROTO_1;
@@ -728,6 +730,15 @@ main(int ac, char **av)
 			fprintf(stderr, "no support for PKCS#11.\n");
 #endif
 			break;
+		case 'J':
+			if (options.jump_host != NULL)
+				fatal("Only a single -J option permitted");
+			if (options.proxy_command != NULL)
+				fatal("Cannot specify -J with ProxyCommand");
+			if (parse_jump(optarg, &options, 1) == -1)
+				fatal("Invalid -J argument");
+			options.proxy_command = xstrdup("none");
+			break;
 		case 't':
 			if (options.request_tty == REQUEST_TTY_YES)
 				options.request_tty = REQUEST_TTY_FORCE;
@@ -739,8 +750,10 @@ main(int ac, char **av)
 				debug_flag = 1;
 				options.log_level = SYSLOG_LEVEL_DEBUG1;
 			} else {
-				if (options.log_level < SYSLOG_LEVEL_DEBUG3)
+				if (options.log_level < SYSLOG_LEVEL_DEBUG3) {
+					debug_flag++;
 					options.log_level++;
+				}
 			}
 			break;
 		case 'V':
@@ -1038,9 +1051,10 @@ main(int ac, char **av)
 	 * has specifically requested canonicalisation for this case via
 	 * CanonicalizeHostname=always
 	 */
-	if (addrs == NULL && options.num_permitted_cnames != 0 &&
-	    (option_clear_or_none(options.proxy_command) ||
-            options.canonicalize_hostname == SSH_CANONICALISE_ALWAYS)) {
+	direct = option_clear_or_none(options.proxy_command) &&
+	    options.jump_host == NULL;
+	if (addrs == NULL && options.num_permitted_cnames != 0 && (direct ||
+	    options.canonicalize_hostname == SSH_CANONICALISE_ALWAYS)) {
 		if ((addrs = resolve_host(host, options.port,
 		    option_clear_or_none(options.proxy_command),
 		    cname, sizeof(cname))) == NULL) {
@@ -1048,7 +1062,7 @@ main(int ac, char **av)
 			if (option_clear_or_none(options.proxy_command))
 				cleanup_exit(255); /* logged in resolve_host */
 		} else
-			check_follow_cname(&host, cname);
+			check_follow_cname(direct, &host, cname);
 	}
 
 	/*
@@ -1073,6 +1087,41 @@ main(int ac, char **av)
 	/* Fill configuration defaults. */
 	fill_default_options(&options);
 
+	/*
+	 * If ProxyJump option specified, then construct a ProxyCommand now.
+	 */
+	if (options.jump_host != NULL) {
+		char port_s[8];
+
+		/* Consistency check */
+		if (options.proxy_command != NULL)
+			fatal("inconsistent options: ProxyCommand+ProxyJump");
+		/* Never use FD passing for ProxyJump */
+		options.proxy_use_fdpass = 0;
+		snprintf(port_s, sizeof(port_s), "%d", options.jump_port);
+		xasprintf(&options.proxy_command,
+		    "ssh%s%s%s%s%s%s%s%s%s%.*s -W %%h:%%p %s",
+		    /* Optional "-l user" argument if jump_user set */
+		    options.jump_user == NULL ? "" : " -l ",
+		    options.jump_user == NULL ? "" : options.jump_user,
+		    /* Optional "-p port" argument if jump_port set */
+		    options.jump_port <= 0 ? "" : " -p ",
+		    options.jump_port <= 0 ? "" : port_s,
+		    /* Optional additional jump hosts ",..." */
+		    options.jump_extra == NULL ? "" : " -J ",
+		    options.jump_extra == NULL ? "" : options.jump_extra,
+		    /* Optional "-F" argumment if -F specified */
+		    config == NULL ? "" : " -F ",
+		    config == NULL ? "" : config,
+		    /* Optional "-v" arguments if -v set */
+		    debug_flag ? " -" : "",
+		    debug_flag, "vvv",
+		    /* Mandatory hostname */
+		    options.jump_host);
+		debug("Setting implicit ProxyCommand from ProxyJump: %s",
+		    options.proxy_command);
+	}
+
 	if (options.port == 0)
 		options.port = default_ssh_port();
 	channel_set_af(options.address_family);
diff --git a/ssh_config.5 b/ssh_config.5
index 45fe892..8605770 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.232 2016/05/04 14:29:58 markus Exp $
-.Dd $Mdocdate: May 4 2016 $
+.\" $OpenBSD: ssh_config.5,v 1.233 2016/07/15 00:24:30 djm Exp $
+.Dd $Mdocdate: July 15 2016 $
 .Dt SSH_CONFIG 5
 .Os
 .Sh NAME
@@ -1358,6 +1358,30 @@ For example, the following directive would connect via an HTTP proxy at
 .Bd -literal -offset 3n
 ProxyCommand /usr/bin/nc -X connect -x 192.0.2.0:8080 %h %p
 .Ed
+.It Cm ProxyJump
+Specifies one or more jump proxies as
+.Xo
+.Sm off
+.Oo Ar user @ Oc
+.Ar host
+.Ns Op : Ns Ar port
+.Sm on
+.Xc .
+Multiple proxies may be separated by comma characters.
+Setting this option will cause
+.Xr ssh 1
+to connect to the target host by first making a
+.Xr ssh 1
+connection to the specified
+.Cm ProxyJump
+host and then establishing a
+a TCP forwarding to the ultimate target from there.
+.Pp
+Note that this option will compete with the
+.Cm ProxyCommand
+option - whichever is specified first will prevent later instances of the
+other from taking effect.
+.Pp
 .It Cm ProxyUseFdpass
 Specifies that
 .Cm ProxyCommand

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


More information about the openssh-commits mailing list