ProxyCommand that returns a socket
Igor Bukanov
igor at mir2.org
Fri Jun 21 15:55:43 EST 2013
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. */
More information about the openssh-unix-dev
mailing list