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