mirror of
https://github.com/PowerShell/openssh-portable.git
synced 2025-07-29 16:54:51 +02:00
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) 2000 Markus Friedl. All rights reserved.
|
||||||
* Copyright (c) 2005,2006 Damien Miller. All rights reserved.
|
* Copyright (c) 2005,2006 Damien Miller. All rights reserved.
|
||||||
@ -451,6 +451,67 @@ colon(char *cp)
|
|||||||
return NULL;
|
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 */
|
/* function to assist building execv() arguments */
|
||||||
void
|
void
|
||||||
addargs(arglist *args, char *fmt, ...)
|
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>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
@ -49,6 +49,7 @@ char *put_host_port(const char *, u_short);
|
|||||||
char *hpdelim(char **);
|
char *hpdelim(char **);
|
||||||
char *cleanhostname(char *);
|
char *cleanhostname(char *);
|
||||||
char *colon(char *);
|
char *colon(char *);
|
||||||
|
int parse_user_host_port(const char *, char **, char **, int *);
|
||||||
long convtime(const char *);
|
long convtime(const char *);
|
||||||
char *tilde_expand_filename(const char *, uid_t);
|
char *tilde_expand_filename(const char *, uid_t);
|
||||||
char *percent_expand(const char *, ...) __attribute__((__sentinel__));
|
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>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||||
@ -170,7 +170,7 @@ typedef enum {
|
|||||||
oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
|
oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
|
||||||
oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
|
oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
|
||||||
oFingerprintHash, oUpdateHostkeys, oHostbasedKeyTypes,
|
oFingerprintHash, oUpdateHostkeys, oHostbasedKeyTypes,
|
||||||
oPubkeyAcceptedKeyTypes,
|
oPubkeyAcceptedKeyTypes, oProxyJump,
|
||||||
oIgnoredUnknownOption, oDeprecated, oUnsupported
|
oIgnoredUnknownOption, oDeprecated, oUnsupported
|
||||||
} OpCodes;
|
} OpCodes;
|
||||||
|
|
||||||
@ -295,6 +295,7 @@ static struct {
|
|||||||
{ "hostbasedkeytypes", oHostbasedKeyTypes },
|
{ "hostbasedkeytypes", oHostbasedKeyTypes },
|
||||||
{ "pubkeyacceptedkeytypes", oPubkeyAcceptedKeyTypes },
|
{ "pubkeyacceptedkeytypes", oPubkeyAcceptedKeyTypes },
|
||||||
{ "ignoreunknown", oIgnoreUnknown },
|
{ "ignoreunknown", oIgnoreUnknown },
|
||||||
|
{ "proxyjump", oProxyJump },
|
||||||
|
|
||||||
{ NULL, oBadOption }
|
{ NULL, oBadOption }
|
||||||
};
|
};
|
||||||
@ -1121,6 +1122,9 @@ parse_char_array:
|
|||||||
|
|
||||||
case oProxyCommand:
|
case oProxyCommand:
|
||||||
charptr = &options->proxy_command;
|
charptr = &options->proxy_command;
|
||||||
|
/* Ignore ProxyCommand if ProxyJump already specified */
|
||||||
|
if (options->jump_host != NULL)
|
||||||
|
charptr = &options->jump_host; /* Skip below */
|
||||||
parse_command:
|
parse_command:
|
||||||
if (s == NULL)
|
if (s == NULL)
|
||||||
fatal("%.200s line %d: Missing argument.", filename, linenum);
|
fatal("%.200s line %d: Missing argument.", filename, linenum);
|
||||||
@ -1129,6 +1133,18 @@ parse_command:
|
|||||||
*charptr = xstrdup(s + len);
|
*charptr = xstrdup(s + len);
|
||||||
return 0;
|
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:
|
case oPort:
|
||||||
intptr = &options->port;
|
intptr = &options->port;
|
||||||
parse_int:
|
parse_int:
|
||||||
@ -1789,6 +1805,10 @@ initialize_options(Options * options)
|
|||||||
options->hostname = NULL;
|
options->hostname = NULL;
|
||||||
options->host_key_alias = NULL;
|
options->host_key_alias = NULL;
|
||||||
options->proxy_command = 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->user = NULL;
|
||||||
options->escape_char = -1;
|
options->escape_char = -1;
|
||||||
options->num_system_hostfiles = 0;
|
options->num_system_hostfiles = 0;
|
||||||
@ -2261,6 +2281,44 @@ parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remo
|
|||||||
return (0);
|
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 */
|
/* XXX the following is a near-vebatim copy from servconf.c; refactor */
|
||||||
static const char *
|
static const char *
|
||||||
fmt_multistate_int(int val, const struct multistate *m)
|
fmt_multistate_int(int val, const struct multistate *m)
|
||||||
@ -2412,7 +2470,7 @@ void
|
|||||||
dump_client_config(Options *o, const char *host)
|
dump_client_config(Options *o, const char *host)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
char vbuf[5];
|
char buf[8];
|
||||||
|
|
||||||
/* This is normally prepared in ssh_kex2 */
|
/* This is normally prepared in ssh_kex2 */
|
||||||
if (kex_assemble_names(KEX_DEFAULT_PK_ALG, &o->hostkeyalgorithms) != 0)
|
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(oMacs, o->macs ? o->macs : KEX_CLIENT_MAC);
|
||||||
dump_cfg_string(oPKCS11Provider, o->pkcs11_provider);
|
dump_cfg_string(oPKCS11Provider, o->pkcs11_provider);
|
||||||
dump_cfg_string(oPreferredAuthentications, o->preferred_authentications);
|
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(oPubkeyAcceptedKeyTypes, o->pubkey_key_types);
|
||||||
dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys);
|
dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys);
|
||||||
dump_cfg_string(oXAuthLocation, o->xauth_location);
|
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)
|
if (o->escape_char == SSH_ESCAPECHAR_NONE)
|
||||||
printf("escapechar none\n");
|
printf("escapechar none\n");
|
||||||
else {
|
else {
|
||||||
vis(vbuf, o->escape_char, VIS_WHITE, 0);
|
vis(buf, o->escape_char, VIS_WHITE, 0);
|
||||||
printf("escapechar %s\n", vbuf);
|
printf("escapechar %s\n", buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* oIPQoS */
|
/* oIPQoS */
|
||||||
@ -2566,4 +2623,30 @@ dump_client_config(Options *o, const char *host)
|
|||||||
/* oStreamLocalBindMask */
|
/* oStreamLocalBindMask */
|
||||||
printf("streamlocalbindmask 0%o\n",
|
printf("streamlocalbindmask 0%o\n",
|
||||||
o->fwd_opts.streamlocal_bind_mask);
|
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>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
@ -163,6 +163,11 @@ typedef struct {
|
|||||||
char *hostbased_key_types;
|
char *hostbased_key_types;
|
||||||
char *pubkey_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 */
|
char *ignored_unknown; /* Pattern list of unknown tokens to ignore */
|
||||||
} Options;
|
} Options;
|
||||||
|
|
||||||
@ -198,6 +203,7 @@ int process_config_line(Options *, struct passwd *, const char *,
|
|||||||
int read_config_file(const char *, struct passwd *, const char *,
|
int read_config_file(const char *, struct passwd *, const char *,
|
||||||
const char *, Options *, int);
|
const char *, Options *, int);
|
||||||
int parse_forward(struct Forward *, const char *, int, int);
|
int parse_forward(struct Forward *, const char *, int, int);
|
||||||
|
int parse_jump(const char *, Options *, int);
|
||||||
int default_ssh_port(void);
|
int default_ssh_port(void);
|
||||||
int option_clear_or_none(const char *);
|
int option_clear_or_none(const char *);
|
||||||
void dump_client_config(Options *o, const char *host);
|
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
|
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
.\" 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 $
|
.\" $OpenBSD: ssh.1,v 1.375 2016/07/15 00:24:30 djm Exp $
|
||||||
.Dd $Mdocdate: June 29 2016 $
|
.Dd $Mdocdate: July 15 2016 $
|
||||||
.Dt SSH 1
|
.Dt SSH 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -52,6 +52,7 @@
|
|||||||
.Op Fl F Ar configfile
|
.Op Fl F Ar configfile
|
||||||
.Op Fl I Ar pkcs11
|
.Op Fl I Ar pkcs11
|
||||||
.Op Fl i Ar identity_file
|
.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 address
|
||||||
.Op Fl l Ar login_name
|
.Op Fl l Ar login_name
|
||||||
.Op Fl m Ar mac_spec
|
.Op Fl m Ar mac_spec
|
||||||
@ -312,6 +313,24 @@ by appending
|
|||||||
.Pa -cert.pub
|
.Pa -cert.pub
|
||||||
to identity filenames.
|
to identity filenames.
|
||||||
.Pp
|
.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
|
.It Fl K
|
||||||
Enables GSSAPI-based authentication and forwarding (delegation) of GSSAPI
|
Enables GSSAPI-based authentication and forwarding (delegation) of GSSAPI
|
||||||
credentials to the server.
|
credentials to the server.
|
||||||
@ -523,6 +542,7 @@ For full details of the options listed below, and their possible values, see
|
|||||||
.It PreferredAuthentications
|
.It PreferredAuthentications
|
||||||
.It Protocol
|
.It Protocol
|
||||||
.It ProxyCommand
|
.It ProxyCommand
|
||||||
|
.It ProxyJump
|
||||||
.It ProxyUseFdpass
|
.It ProxyUseFdpass
|
||||||
.It PubkeyAcceptedKeyTypes
|
.It PubkeyAcceptedKeyTypes
|
||||||
.It PubkeyAuthentication
|
.It PubkeyAuthentication
|
||||||
|
75
ssh.c
75
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>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
* 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.
|
* NB. this function must operate with a options having undefined members.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
check_follow_cname(char **namep, const char *cname)
|
check_follow_cname(int direct, char **namep, const char *cname)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct allowed_cname *rule;
|
struct allowed_cname *rule;
|
||||||
@ -342,9 +342,9 @@ check_follow_cname(char **namep, const char *cname)
|
|||||||
return 0;
|
return 0;
|
||||||
/*
|
/*
|
||||||
* Don't attempt to canonicalize names that will be interpreted by
|
* 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)
|
options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS)
|
||||||
return 0;
|
return 0;
|
||||||
debug3("%s: check \"%s\" CNAME \"%s\"", __func__, *namep, cname);
|
debug3("%s: check \"%s\" CNAME \"%s\"", __func__, *namep, cname);
|
||||||
@ -371,7 +371,7 @@ check_follow_cname(char **namep, const char *cname)
|
|||||||
static struct addrinfo *
|
static struct addrinfo *
|
||||||
resolve_canonicalize(char **hostp, int port)
|
resolve_canonicalize(char **hostp, int port)
|
||||||
{
|
{
|
||||||
int i, ndots;
|
int i, direct, ndots;
|
||||||
char *cp, *fullhost, newname[NI_MAXHOST];
|
char *cp, *fullhost, newname[NI_MAXHOST];
|
||||||
struct addrinfo *addrs;
|
struct addrinfo *addrs;
|
||||||
|
|
||||||
@ -382,7 +382,9 @@ resolve_canonicalize(char **hostp, int port)
|
|||||||
* Don't attempt to canonicalize names that will be interpreted by
|
* Don't attempt to canonicalize names that will be interpreted by
|
||||||
* a proxy unless the user specifically requests so.
|
* 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)
|
options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@ -437,7 +439,7 @@ resolve_canonicalize(char **hostp, int port)
|
|||||||
/* Remove trailing '.' */
|
/* Remove trailing '.' */
|
||||||
fullhost[strlen(fullhost) - 1] = '\0';
|
fullhost[strlen(fullhost) - 1] = '\0';
|
||||||
/* Follow CNAME if requested */
|
/* Follow CNAME if requested */
|
||||||
if (!check_follow_cname(&fullhost, newname)) {
|
if (!check_follow_cname(direct, &fullhost, newname)) {
|
||||||
debug("Canonicalized hostname \"%s\" => \"%s\"",
|
debug("Canonicalized hostname \"%s\" => \"%s\"",
|
||||||
*hostp, fullhost);
|
*hostp, fullhost);
|
||||||
}
|
}
|
||||||
@ -510,7 +512,7 @@ int
|
|||||||
main(int ac, char **av)
|
main(int ac, char **av)
|
||||||
{
|
{
|
||||||
struct ssh *ssh = NULL;
|
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 *p, *cp, *line, *argv0, buf[PATH_MAX], *host_arg, *logfile;
|
||||||
char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
|
char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
|
||||||
char cname[NI_MAXHOST], uidstr[32], *conn_hash_hex;
|
char cname[NI_MAXHOST], uidstr[32], *conn_hash_hex;
|
||||||
@ -603,7 +605,7 @@ main(int ac, char **av)
|
|||||||
|
|
||||||
again:
|
again:
|
||||||
while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx"
|
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) {
|
switch (opt) {
|
||||||
case '1':
|
case '1':
|
||||||
options.protocol = SSH_PROTO_1;
|
options.protocol = SSH_PROTO_1;
|
||||||
@ -728,6 +730,15 @@ main(int ac, char **av)
|
|||||||
fprintf(stderr, "no support for PKCS#11.\n");
|
fprintf(stderr, "no support for PKCS#11.\n");
|
||||||
#endif
|
#endif
|
||||||
break;
|
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':
|
case 't':
|
||||||
if (options.request_tty == REQUEST_TTY_YES)
|
if (options.request_tty == REQUEST_TTY_YES)
|
||||||
options.request_tty = REQUEST_TTY_FORCE;
|
options.request_tty = REQUEST_TTY_FORCE;
|
||||||
@ -739,9 +750,11 @@ main(int ac, char **av)
|
|||||||
debug_flag = 1;
|
debug_flag = 1;
|
||||||
options.log_level = SYSLOG_LEVEL_DEBUG1;
|
options.log_level = SYSLOG_LEVEL_DEBUG1;
|
||||||
} else {
|
} else {
|
||||||
if (options.log_level < SYSLOG_LEVEL_DEBUG3)
|
if (options.log_level < SYSLOG_LEVEL_DEBUG3) {
|
||||||
|
debug_flag++;
|
||||||
options.log_level++;
|
options.log_level++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 'V':
|
case 'V':
|
||||||
fprintf(stderr, "%s, %s\n",
|
fprintf(stderr, "%s, %s\n",
|
||||||
@ -1038,8 +1051,9 @@ main(int ac, char **av)
|
|||||||
* has specifically requested canonicalisation for this case via
|
* has specifically requested canonicalisation for this case via
|
||||||
* CanonicalizeHostname=always
|
* CanonicalizeHostname=always
|
||||||
*/
|
*/
|
||||||
if (addrs == NULL && options.num_permitted_cnames != 0 &&
|
direct = option_clear_or_none(options.proxy_command) &&
|
||||||
(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)) {
|
options.canonicalize_hostname == SSH_CANONICALISE_ALWAYS)) {
|
||||||
if ((addrs = resolve_host(host, options.port,
|
if ((addrs = resolve_host(host, options.port,
|
||||||
option_clear_or_none(options.proxy_command),
|
option_clear_or_none(options.proxy_command),
|
||||||
@ -1048,7 +1062,7 @@ main(int ac, char **av)
|
|||||||
if (option_clear_or_none(options.proxy_command))
|
if (option_clear_or_none(options.proxy_command))
|
||||||
cleanup_exit(255); /* logged in resolve_host */
|
cleanup_exit(255); /* logged in resolve_host */
|
||||||
} else
|
} 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 configuration defaults. */
|
||||||
fill_default_options(&options);
|
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)
|
if (options.port == 0)
|
||||||
options.port = default_ssh_port();
|
options.port = default_ssh_port();
|
||||||
channel_set_af(options.address_family);
|
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
|
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
.\" 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 $
|
.\" $OpenBSD: ssh_config.5,v 1.233 2016/07/15 00:24:30 djm Exp $
|
||||||
.Dd $Mdocdate: May 4 2016 $
|
.Dd $Mdocdate: July 15 2016 $
|
||||||
.Dt SSH_CONFIG 5
|
.Dt SSH_CONFIG 5
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -1358,6 +1358,30 @@ For example, the following directive would connect via an HTTP proxy at
|
|||||||
.Bd -literal -offset 3n
|
.Bd -literal -offset 3n
|
||||||
ProxyCommand /usr/bin/nc -X connect -x 192.0.2.0:8080 %h %p
|
ProxyCommand /usr/bin/nc -X connect -x 192.0.2.0:8080 %h %p
|
||||||
.Ed
|
.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
|
.It Cm ProxyUseFdpass
|
||||||
Specifies that
|
Specifies that
|
||||||
.Cm ProxyCommand
|
.Cm ProxyCommand
|
||||||
|
Loading…
x
Reference in New Issue
Block a user