local-proxy.c 3.2 KB

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