socks: support unix sockets for socks proxy

Usage:
  curl -x "socks5h://localhost/run/tor/socks" "https://example.com"

Updated runtests.pl to run a socksd server listening on unix socket

Added tests test1467 test1468

Added documentation for proxy command line option and socks proxy
options

Closes #8668
This commit is contained in:
Balakrishnan Balasubramanian 2022-05-19 15:33:22 +02:00 committed by Daniel Stenberg
parent ee52bead4d
commit dfa84a0450
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
12 changed files with 240 additions and 23 deletions

View file

@ -147,6 +147,10 @@ static void conn_free(struct connectdata *conn);
# error READBUFFER_SIZE is too small
#endif
#ifdef USE_UNIX_SOCKETS
#define UNIX_SOCKET_PREFIX "localhost"
#endif
/*
* get_protocol_family()
*
@ -2407,13 +2411,18 @@ static CURLcode parse_proxy(struct Curl_easy *data,
int port = -1;
char *proxyuser = NULL;
char *proxypasswd = NULL;
char *host;
char *host = NULL;
bool sockstype;
CURLUcode uc;
struct proxy_info *proxyinfo;
CURLU *uhp = curl_url();
CURLcode result = CURLE_OK;
char *scheme = NULL;
#ifdef USE_UNIX_SOCKETS
char *path = NULL;
bool is_unix_proxy = FALSE;
#endif
if(!uhp) {
result = CURLE_OUT_OF_MEMORY;
@ -2538,21 +2547,54 @@ static CURLcode parse_proxy(struct Curl_easy *data,
result = CURLE_OUT_OF_MEMORY;
goto error;
}
Curl_safefree(proxyinfo->host.rawalloc);
proxyinfo->host.rawalloc = host;
if(host[0] == '[') {
/* this is a numerical IPv6, strip off the brackets */
size_t len = strlen(host);
host[len-1] = 0; /* clear the trailing bracket */
host++;
zonefrom_url(uhp, data, conn);
#ifdef USE_UNIX_SOCKETS
if(sockstype && strcasecompare(UNIX_SOCKET_PREFIX, host)) {
uc = curl_url_get(uhp, CURLUPART_PATH, &path, CURLU_URLDECODE);
if(uc) {
result = CURLE_OUT_OF_MEMORY;
goto error;
}
/* path will be "/", if no path was was found */
if(strcmp("/", path)) {
is_unix_proxy = TRUE;
free(host);
host = aprintf(UNIX_SOCKET_PREFIX"%s", path);
if(!host) {
result = CURLE_OUT_OF_MEMORY;
goto error;
}
Curl_safefree(proxyinfo->host.rawalloc);
proxyinfo->host.rawalloc = host;
proxyinfo->host.name = host;
host = NULL;
}
}
proxyinfo->host.name = host;
if(!is_unix_proxy) {
#endif
Curl_safefree(proxyinfo->host.rawalloc);
proxyinfo->host.rawalloc = host;
if(host[0] == '[') {
/* this is a numerical IPv6, strip off the brackets */
size_t len = strlen(host);
host[len-1] = 0; /* clear the trailing bracket */
host++;
zonefrom_url(uhp, data, conn);
}
proxyinfo->host.name = host;
host = NULL;
#ifdef USE_UNIX_SOCKETS
}
#endif
error:
free(proxyuser);
free(proxypasswd);
free(host);
free(scheme);
#ifdef USE_UNIX_SOCKETS
free(path);
#endif
curl_url_cleanup(uhp);
return result;
}
@ -3384,25 +3426,35 @@ static CURLcode resolve_server(struct Curl_easy *data,
struct Curl_dns_entry *hostaddr = NULL;
#ifdef USE_UNIX_SOCKETS
if(conn->unix_domain_socket) {
char *unix_path = NULL;
if(conn->unix_domain_socket)
unix_path = conn->unix_domain_socket;
#ifndef CURL_DISABLE_PROXY
else if(conn->socks_proxy.host.name
&& !strncmp(UNIX_SOCKET_PREFIX"/",
conn->socks_proxy.host.name, sizeof(UNIX_SOCKET_PREFIX)))
unix_path = conn->socks_proxy.host.name + sizeof(UNIX_SOCKET_PREFIX) - 1;
#endif
if(unix_path) {
/* Unix domain sockets are local. The host gets ignored, just use the
* specified domain socket address. Do not cache "DNS entries". There is
* no DNS involved and we already have the filesystem path available */
const char *path = conn->unix_domain_socket;
hostaddr = calloc(1, sizeof(struct Curl_dns_entry));
if(!hostaddr)
result = CURLE_OUT_OF_MEMORY;
else {
bool longpath = FALSE;
hostaddr->addr = Curl_unix2addr(path, &longpath,
hostaddr->addr = Curl_unix2addr(unix_path, &longpath,
conn->bits.abstract_unix_socket);
if(hostaddr->addr)
hostaddr->inuse++;
else {
/* Long paths are not supported for now */
if(longpath) {
failf(data, "Unix socket path too long: '%s'", path);
failf(data, "Unix socket path too long: '%s'", unix_path);
result = CURLE_COULDNT_RESOLVE_HOST;
}
else