You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
192 lines
5.3 KiB
192 lines
5.3 KiB
From fdd93b1e9545b66d1b3a2a1ec24d4c8613ee43fb Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= <mgorny@gentoo.org>
|
|
Date: Sat, 24 Jan 2015 23:59:21 +0100
|
|
Subject: [PATCH] Support SOCKSv5 proxy
|
|
|
|
Support using a SOCKSv5 proxy specified as DISTCC_SOCKS_PROXY.
|
|
The variable can either a hostname, a host:port pair or an absolute path
|
|
to a UNIX socket. When SOCKS is used, the hostname is passed to
|
|
the proxy and therefore the name resolution is done remotely.
|
|
---
|
|
src/clinet.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
|
|
1 file changed, 135 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/src/clinet.c b/src/clinet.c
|
|
index 010a884..4773d8b 100644
|
|
--- a/src/clinet.c
|
|
+++ b/src/clinet.c
|
|
@@ -31,6 +31,7 @@
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
+#include <stddef.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
@@ -42,8 +43,10 @@
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
|
|
+#include <arpa/inet.h>
|
|
#include <netinet/in.h>
|
|
#include <netinet/tcp.h>
|
|
+#include <sys/un.h>
|
|
|
|
#include <netdb.h>
|
|
|
|
@@ -161,7 +164,7 @@ out_failed:
|
|
/**
|
|
* Open a socket to a tcp remote host with the specified port.
|
|
**/
|
|
-int dcc_connect_by_name(const char *host, int port, int *p_fd)
|
|
+static int dcc_connect_by_name_real(const char *host, int port, int *p_fd)
|
|
{
|
|
struct addrinfo hints;
|
|
struct addrinfo *res;
|
|
@@ -201,7 +204,7 @@ int dcc_connect_by_name(const char *host, int port, int *p_fd)
|
|
*
|
|
* @todo Don't try for too long to connect.
|
|
**/
|
|
-int dcc_connect_by_name(const char *host, int port, int *p_fd)
|
|
+static int dcc_connect_by_name_real(const char *host, int port, int *p_fd)
|
|
{
|
|
struct sockaddr_in sock_out;
|
|
struct hostent *hp;
|
|
@@ -224,3 +227,133 @@ int dcc_connect_by_name(const char *host, int port, int *p_fd)
|
|
}
|
|
|
|
#endif /* not ENABLE_RFC2553 */
|
|
+
|
|
+static int dcc_connect_via_socks5(const char *host, int port, int *p_fd, const char *proxy)
|
|
+{
|
|
+ int ret;
|
|
+ char *proxy_host, *proxy_it;
|
|
+ int proxy_port;
|
|
+ char buf[262];
|
|
+ int host_length;
|
|
+ struct sockaddr_in addr_buf;
|
|
+ int skip_bytes;
|
|
+
|
|
+ host_length = strlen(host);
|
|
+ if (host_length > 255) {
|
|
+ rs_log_error("hostname \"%s\" too long for SOCKSv5 (over 255 chars)", host);
|
|
+ return EXIT_CONNECT_FAILED;
|
|
+ }
|
|
+
|
|
+ if (proxy[0] == '/') { /* UNIX socket */
|
|
+ struct sockaddr_un unix_addr;
|
|
+
|
|
+ if (strlen(proxy) >= sizeof(unix_addr.sun_path))
|
|
+ {
|
|
+ rs_log_error("UNIX socket path \"%s\" too long", proxy);
|
|
+ return EXIT_CONNECT_FAILED;
|
|
+ }
|
|
+
|
|
+ unix_addr.sun_family = AF_UNIX;
|
|
+ strcpy(unix_addr.sun_path, proxy);
|
|
+
|
|
+ ret = dcc_connect_by_addr((struct sockaddr *) &unix_addr,
|
|
+ offsetof(struct sockaddr_un, sun_path) + strlen(proxy) + 1,
|
|
+ p_fd);
|
|
+
|
|
+ } else { /* hostname? IP address? */
|
|
+ proxy_host = strdup(proxy);
|
|
+ if (proxy_host == NULL) return EXIT_OUT_OF_MEMORY;
|
|
+
|
|
+ proxy_it = strrchr(proxy_host, ':');
|
|
+ if (proxy_it) {
|
|
+ *(proxy_it++) = 0;
|
|
+ proxy_port = atoi(proxy_it);
|
|
+
|
|
+ if (proxy_port <= 0) {
|
|
+ rs_log_error("invalid proxy port \"%s\"", proxy_it);
|
|
+ free(proxy_host);
|
|
+ return EXIT_CONNECT_FAILED;
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+ proxy_port = 1080;
|
|
+
|
|
+ ret = dcc_connect_by_name_real(proxy_host, proxy_port, p_fd);
|
|
+ free(proxy_host);
|
|
+ }
|
|
+
|
|
+ if (ret != 0)
|
|
+ return ret;
|
|
+
|
|
+ /* connected to proxy, now identifier/method selection */
|
|
+ buf[0] = 0x05; /* SOCKSv5 */
|
|
+ buf[1] = 0x01; /* one method */
|
|
+ buf[2] = 0x00; /* NO AUTHENTICATION REQUIRED */
|
|
+ ret = dcc_writex(*p_fd, buf, 3);
|
|
+ if (ret != 0)
|
|
+ return ret;
|
|
+
|
|
+ /* wait for method selection */
|
|
+ ret = dcc_readx(*p_fd, buf, 2);
|
|
+ if (ret != 0)
|
|
+ return ret;
|
|
+ if (buf[0] != 0x05 || buf[1] != 0x00) { /* version, method */
|
|
+ rs_log_error("invalid proxy reply (version 0x%02x, method 0x%02x)",
|
|
+ buf[0], buf[1]);
|
|
+ return EXIT_CONNECT_FAILED;
|
|
+ }
|
|
+
|
|
+ /* send connect request */
|
|
+ buf[0] = 0x05; /* SOCKSv5 */
|
|
+ buf[1] = 0x01; /* CONNECT command */
|
|
+ buf[2] = 0x00; /* reserved */
|
|
+ buf[3] = 0x03; /* DOMAINNAME address type */
|
|
+ buf[4] = host_length;
|
|
+ memcpy(&buf[5], host, host_length);
|
|
+ addr_buf.sin_port = htons(port);
|
|
+ memcpy(&buf[5 + host_length], &addr_buf.sin_port, 2);
|
|
+ ret = dcc_writex(*p_fd, buf, 7 + host_length);
|
|
+ if (ret != 0)
|
|
+ return ret;
|
|
+
|
|
+ /* wait for the connection */
|
|
+ /* read first 4 bytes of reply + 2 extra bytes we know will be there */
|
|
+ ret = dcc_readx(*p_fd, buf, 6);
|
|
+ if (ret != 0)
|
|
+ return ret;
|
|
+ if (buf[0] != 0x05 || buf[2] != 0x00) { /* version, reserved */
|
|
+ rs_log_error("invalid proxy reply (version 0x%02x, reserved 0x%02x)",
|
|
+ buf[0], buf[2]);
|
|
+ return EXIT_CONNECT_FAILED;
|
|
+ }
|
|
+ if (buf[1] != 0x00) { /* reply */
|
|
+ rs_log_error("proxy connection failed, reason=0x%02x", buf[1]);
|
|
+ return EXIT_CONNECT_FAILED;
|
|
+ }
|
|
+
|
|
+ /* now read the remaining (packet size - 6) bytes */
|
|
+ switch (buf[3]) { /* address type */
|
|
+ case 0x01: skip_bytes = 4; break; /* IPv4 */
|
|
+ case 0x03: skip_bytes = buf[4] + 1; break; /* hostname with length field */
|
|
+ case 0x04: skip_bytes = 16; break; /* IPv6 */
|
|
+ default:
|
|
+ rs_log_error("invalid proxy reply (address type 0x%02x)", buf[3]);
|
|
+ return EXIT_CONNECT_FAILED;
|
|
+ }
|
|
+ ret = dcc_readx(*p_fd, buf, skip_bytes);
|
|
+ if (ret != 0)
|
|
+ return ret;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int dcc_connect_by_name(const char *host, int port, int *p_fd)
|
|
+{
|
|
+ const char *proxy;
|
|
+
|
|
+ proxy = getenv("DISTCC_SOCKS_PROXY");
|
|
+ if (proxy)
|
|
+ return dcc_connect_via_socks5(host, port, p_fd, proxy);
|
|
+ else
|
|
+ return dcc_connect_by_name_real(host, port, p_fd);
|
|
+}
|
|
--
|
|
2.3.0
|
|
|