1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
|
/*
* local-proxy.c: Unix implementation of platform_new_connection(),
* supporting an OpenSSH-like proxy command.
*/
#include <stdio.h>
#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include "tree234.h"
#include "putty.h"
#include "network.h"
#include "proxy/proxy.h"
char *platform_setup_local_proxy(Socket *socket, const char *cmd)
{
/*
* Create the pipes to the proxy command, and spawn the proxy
* command process.
*/
int to_cmd_pipe[2], from_cmd_pipe[2], cmd_err_pipe[2];
if (pipe(to_cmd_pipe) < 0 ||
pipe(from_cmd_pipe) < 0 ||
pipe(cmd_err_pipe) < 0) {
return dupprintf("pipe: %s", strerror(errno));
}
cloexec(to_cmd_pipe[1]);
cloexec(from_cmd_pipe[0]);
cloexec(cmd_err_pipe[0]);
int pid = fork();
if (pid == 0) {
close(0);
close(1);
dup2(to_cmd_pipe[0], 0);
dup2(from_cmd_pipe[1], 1);
close(to_cmd_pipe[0]);
close(from_cmd_pipe[1]);
dup2(cmd_err_pipe[1], 2);
noncloexec(0);
noncloexec(1);
execl("/bin/sh", "sh", "-c", cmd, (void *)NULL);
_exit(255);
}
if (pid < 0) {
return dupprintf("fork: %s", strerror(errno));
}
close(to_cmd_pipe[0]);
close(from_cmd_pipe[1]);
close(cmd_err_pipe[1]);
setup_fd_socket(socket, from_cmd_pipe[0], to_cmd_pipe[1], cmd_err_pipe[0]);
return NULL;
}
Socket *platform_new_connection(SockAddr *addr, const char *hostname,
int port, bool privport,
bool oobinline, bool nodelay, bool keepalive,
Plug *plug, Conf *conf, Interactor *itr)
{
switch (conf_get_int(conf, CONF_proxy_type)) {
case PROXY_CMD: {
DeferredSocketOpener *opener = local_proxy_opener(
addr, port, plug, conf, itr);
Socket *socket = make_deferred_fd_socket(opener, addr, port, plug);
local_proxy_opener_set_socket(opener, socket);
return socket;
}
case PROXY_FUZZ: {
char *cmd = format_telnet_command(addr, port, conf, NULL);
int outfd = open("/dev/null", O_WRONLY);
if (outfd == -1) {
sfree(cmd);
return new_error_socket_fmt(
plug, "/dev/null: %s", strerror(errno));
}
int infd = open(cmd, O_RDONLY);
if (infd == -1) {
Socket *toret = new_error_socket_fmt(
plug, "%s: %s", cmd, strerror(errno));
sfree(cmd);
close(outfd);
return toret;
}
sfree(cmd);
return make_fd_socket(infd, outfd, -1, addr, port, plug);
}
default:
return NULL;
}
}
Socket *platform_start_subprocess(const char *cmd, Plug *plug,
const char *prefix)
{
Socket *socket = make_deferred_fd_socket(
null_deferred_socket_opener(),
sk_nonamelookup("<local command>"), 0, plug);
char *err = platform_setup_local_proxy(socket, cmd);
fd_socket_set_psb_prefix(socket, prefix);
if (err) {
sk_close(socket);
socket = new_error_socket_fmt(plug, "%s", err);
sfree(err);
}
return socket;
}
|