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
This commit is contained in:
parent
5c02dd1262
commit
ed877ef653
63
misc.c
63
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, ...)
|
||||
|
|
3
misc.h
3
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@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__));
|
||||
|
|
95
readconf.c
95
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@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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@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);
|
||||
|
|
24
ssh.1
24
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
|
||||
|
|
77
ssh.c
77
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@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@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);
|
||||
|
|
28
ssh_config.5
28
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
|
||||
|
|
Loading…
Reference in New Issue