ProxyCommand that returns a socket
Damien Miller
djm at mindrot.org
Wed Aug 21 02:49:29 EST 2013
... and it's committed - it will be in snapshots dated 20130821 and later,
and will be released in openssh-6.4 later this year.
-d
On Fri, 21 Jun 2013, Igor Bukanov wrote:
> Thanks, I think this is exactly what I was looking for!
>
> On 21 June 2013 02:01, Damien Miller <djm at mindrot.org> wrote:
> > On Thu, 20 Jun 2013, Igor Bukanov wrote:
> >
> >> Hello,
> >>
> >> My usage of ProxyCommand just calls the nc utility with various
> >> parameters. That in turn after the initial setup just copies copies
> >> the data from the network socket to stdin/stdout. This useless coping
> >> can be avoided if ssh has an option to receive the socket from the
> >> proxy command. I suppose it can improve network error reporting as ssh
> >> would talk directly to the network socket rather than a proxy, right?
> >
> > I have a patch that adds a ProxyUseFdpass that might do what you want.
> >
> > When ProxyUseFdpass=yes, the ProxyCommand is expected to pass back a
> > connected socket and exit. ssh will then use this socket directly.
> >
> > This is somewhat more optional for cases where the proxy is only
> > needed at the beginning of the connection.
> >
> > Index: readconf.c
> > ===================================================================
> > RCS file: /var/cvs/openssh/readconf.c,v
> > retrieving revision 1.184
> > diff -u -p -r1.184 readconf.c
> > --- readconf.c 5 Jun 2013 22:22:47 -0000 1.184
> > +++ readconf.c 21 Jun 2013 00:00:29 -0000
> > @@ -137,7 +137,7 @@ typedef enum {
> > oHashKnownHosts,
> > oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
> > oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication,
> > - oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown,
> > + oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
> > oIgnoredUnknownOption, oDeprecated, oUnsupported
> > } OpCodes;
> >
> > @@ -249,6 +249,7 @@ static struct {
> > { "kexalgorithms", oKexAlgorithms },
> > { "ipqos", oIPQoS },
> > { "requesttty", oRequestTTY },
> > + { "proxyusefdpass", oProxyUseFdpass },
> > { "ignoreunknown", oIgnoreUnknown },
> >
> > { NULL, oBadOption }
> > @@ -1074,6 +1075,10 @@ parse_int:
> > charptr = &options->ignored_unknown;
> > goto parse_string;
> >
> > + case oProxyUseFdpass:
> > + intptr = &options->proxy_use_fdpass;
> > + goto parse_flag;
> > +
> > case oDeprecated:
> > debug("%s line %d: Deprecated option \"%s\"",
> > filename, linenum, keyword);
> > @@ -1235,6 +1240,7 @@ initialize_options(Options * options)
> > options->ip_qos_interactive = -1;
> > options->ip_qos_bulk = -1;
> > options->request_tty = -1;
> > + options->proxy_use_fdpass = -1;
> > options->ignored_unknown = NULL;
> > }
> >
> > @@ -1387,6 +1393,8 @@ fill_default_options(Options * options)
> > options->ip_qos_bulk = IPTOS_THROUGHPUT;
> > if (options->request_tty == -1)
> > options->request_tty = REQUEST_TTY_AUTO;
> > + if (options->proxy_use_fdpass == -1)
> > + options->proxy_use_fdpass = 0;
> > /* options->local_command should not be set by default */
> > /* options->proxy_command should not be set by default */
> > /* options->user will be set in the main program if appropriate */
> > Index: readconf.h
> > ===================================================================
> > RCS file: /var/cvs/openssh/readconf.h,v
> > retrieving revision 1.87
> > diff -u -p -r1.87 readconf.h
> > --- readconf.h 16 May 2013 10:30:03 -0000 1.87
> > +++ readconf.h 21 Jun 2013 00:00:29 -0000
> > @@ -138,6 +138,8 @@ typedef struct {
> >
> > int request_tty;
> >
> > + int proxy_use_fdpass;
> > +
> > char *ignored_unknown; /* Pattern list of unknown tokens to ignore */
> > } Options;
> >
> > Index: ssh_config.5
> > ===================================================================
> > RCS file: /var/cvs/openssh/ssh_config.5,v
> > retrieving revision 1.164
> > diff -u -p -r1.164 ssh_config.5
> > --- ssh_config.5 16 May 2013 10:30:32 -0000 1.164
> > +++ ssh_config.5 21 Jun 2013 00:00:29 -0000
> > @@ -931,6 +931,14 @@ For example, the following directive wou
> > .Bd -literal -offset 3n
> > ProxyCommand /usr/bin/nc -X connect -x 192.0.2.0:8080 %h %p
> > .Ed
> > +.It Cm ProxyUseFdpass
> > +Specifies that the a
> > +.Cm ProxyCommand
> > +will pass a connected file descriptor back to
> > +.Nm ssh
> > +instead of continuing to execute and pass data.
> > +The default is
> > +.Dq no .
> > .It Cm PubkeyAuthentication
> > Specifies whether to try public key authentication.
> > The argument to this keyword must be
> > Index: sshconnect.c
> > ===================================================================
> > RCS file: /var/cvs/openssh/sshconnect.c,v
> > retrieving revision 1.211
> > diff -u -p -r1.211 sshconnect.c
> > --- sshconnect.c 1 Jun 2013 21:31:19 -0000 1.211
> > +++ sshconnect.c 21 Jun 2013 00:00:29 -0000
> > @@ -59,6 +59,7 @@
> > #include "misc.h"
> > #include "dns.h"
> > #include "roaming.h"
> > +#include "monitor_fdpass.h"
> > #include "ssh2.h"
> > #include "version.h"
> >
> > @@ -78,16 +79,113 @@ extern uid_t original_effective_uid;
> > static int show_other_keys(struct hostkeys *, Key *);
> > static void warn_changed_key(Key *);
> >
> > +/* Expand a proxy command */
> > +static char *
> > +expand_proxy_command(const char *proxy_command, const char *user,
> > + const char *host, int port)
> > +{
> > + char *tmp, *ret, strport[NI_MAXSERV];
> > +
> > + snprintf(strport, sizeof strport, "%hu", port);
> > + xasprintf(&tmp, "exec %s", proxy_command);
> > + ret = percent_expand(tmp, "h", host, "p", strport,
> > + "r", options.user, (char *)NULL);
> > + free(tmp);
> > + return ret;
> > +}
> > +
> > +/*
> > + * Connect to the given ssh server using a proxy command that passes a
> > + * a connected fd back to us.
> > + */
> > +static int
> > +ssh_proxy_fdpass_connect(const char *host, u_short port,
> > + const char *proxy_command)
> > +{
> > + char *command_string;
> > + int sp[2], sock;
> > + pid_t pid;
> > + char *shell;
> > +
> > + if ((shell = getenv("SHELL")) == NULL)
> > + shell = _PATH_BSHELL;
> > +
> > + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) < 0)
> > + fatal("Could not create socketpair to communicate with "
> > + "proxy dialer: %.100s", strerror(errno));
> > +
> > + command_string = expand_proxy_command(proxy_command, options.user,
> > + host, port);
> > + debug("Executing proxy dialer command: %.500s", command_string);
> > +
> > + /* Fork and execute the proxy command. */
> > + if ((pid = fork()) == 0) {
> > + char *argv[10];
> > +
> > + /* Child. Permanently give up superuser privileges. */
> > + permanently_drop_suid(original_real_uid);
> > +
> > + close(sp[1]);
> > + /* Redirect stdin and stdout. */
> > + if (sp[0] != 0) {
> > + if (dup2(sp[0], 0) < 0)
> > + perror("dup2 stdin");
> > + }
> > + if (sp[0] != 1) {
> > + if (dup2(sp[0], 1) < 0)
> > + perror("dup2 stdout");
> > + }
> > + if (sp[0] >= 2)
> > + close(sp[0]);
> > +
> > + /*
> > + * Stderr is left as it is so that error messages get
> > + * printed on the user's terminal.
> > + */
> > + argv[0] = shell;
> > + argv[1] = "-c";
> > + argv[2] = command_string;
> > + argv[3] = NULL;
> > +
> > + /*
> > + * Execute the proxy command.
> > + * Note that we gave up any extra privileges above.
> > + */
> > + execv(argv[0], argv);
> > + perror(argv[0]);
> > + exit(1);
> > + }
> > + /* Parent. */
> > + if (pid < 0)
> > + fatal("fork failed: %.100s", strerror(errno));
> > + close(sp[0]);
> > + free(command_string);
> > +
> > + if ((sock = mm_receive_fd(sp[1])) == -1)
> > + fatal("proxy dialer did not pass back a connection");
> > +
> > + while (waitpid(pid, NULL, 0) == -1)
> > + if (errno != EINTR)
> > + fatal("Couldn't wait for child: %s", strerror(errno));
> > +
> > + /* Set the connection file descriptors. */
> > + packet_set_connection(sock, sock);
> > + packet_set_timeout(options.server_alive_interval,
> > + options.server_alive_count_max);
> > +
> > + return 0;
> > +}
> > +
> > /*
> > * Connect to the given ssh server using a proxy command.
> > */
> > static int
> > ssh_proxy_connect(const char *host, u_short port, const char *proxy_command)
> > {
> > - char *command_string, *tmp;
> > + char *command_string;
> > int pin[2], pout[2];
> > pid_t pid;
> > - char *shell, strport[NI_MAXSERV];
> > + char *shell;
> >
> > if (!strcmp(proxy_command, "-")) {
> > packet_set_connection(STDIN_FILENO, STDOUT_FILENO);
> > @@ -96,29 +194,19 @@ ssh_proxy_connect(const char *host, u_sh
> > return 0;
> > }
> >
> > + if (options.proxy_use_fdpass)
> > + return ssh_proxy_fdpass_connect(host, port, proxy_command);
> > +
> > if ((shell = getenv("SHELL")) == NULL || *shell == '\0')
> > shell = _PATH_BSHELL;
> >
> > - /* Convert the port number into a string. */
> > - snprintf(strport, sizeof strport, "%hu", port);
> > -
> > - /*
> > - * Build the final command string in the buffer by making the
> > - * appropriate substitutions to the given proxy command.
> > - *
> > - * Use "exec" to avoid "sh -c" processes on some platforms
> > - * (e.g. Solaris)
> > - */
> > - xasprintf(&tmp, "exec %s", proxy_command);
> > - command_string = percent_expand(tmp, "h", host, "p", strport,
> > - "r", options.user, (char *)NULL);
> > - free(tmp);
> > -
> > /* Create pipes for communicating with the proxy. */
> > if (pipe(pin) < 0 || pipe(pout) < 0)
> > fatal("Could not create pipes to communicate with the proxy: %.100s",
> > strerror(errno));
> >
> > + command_string = expand_proxy_command(proxy_command, options.user,
> > + host, port);
> > debug("Executing proxy command: %.500s", command_string);
> >
> > /* Fork and execute the proxy command. */
> _______________________________________________
> openssh-unix-dev mailing list
> openssh-unix-dev at mindrot.org
> https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
>
More information about the openssh-unix-dev
mailing list