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:
parent
ee52bead4d
commit
dfa84a0450
@ -14,6 +14,9 @@ specified or http:// will be treated as HTTP proxy. Use socks4://, socks4a://,
|
||||
socks5:// or socks5h:// to request a specific SOCKS version to be used.
|
||||
(Added in 7.21.7)
|
||||
|
||||
Unix domain sockets are supported for socks proxy. Set localhost for the host
|
||||
part. e.g. socks5h://localhost/path/to/socket.sock
|
||||
|
||||
HTTPS proxy support via https:// protocol prefix was added in 7.52.0 for
|
||||
OpenSSL, GnuTLS and NSS.
|
||||
|
||||
|
||||
@ -10,6 +10,9 @@ Use the specified SOCKS4 proxy. If the port number is not specified, it is
|
||||
assumed at port 1080. Using this socket type make curl resolve the host name
|
||||
and passing the address on to the proxy.
|
||||
|
||||
To specify proxy on a unix domain socket, use localhost for host, e.g.
|
||||
socks4://localhost/path/to/socket.sock
|
||||
|
||||
This option overrides any previous use of --proxy, as they are mutually
|
||||
exclusive.
|
||||
|
||||
|
||||
@ -9,6 +9,9 @@ See-also: socks4 socks5 socks5-hostname
|
||||
Use the specified SOCKS4a proxy. If the port number is not specified, it is
|
||||
assumed at port 1080. This asks the proxy to resolve the host name.
|
||||
|
||||
To specify proxy on a unix domain socket, use localhost for host, e.g.
|
||||
socks4a://localhost/path/to/socket.sock
|
||||
|
||||
This option overrides any previous use of --proxy, as they are mutually
|
||||
exclusive.
|
||||
|
||||
|
||||
@ -9,6 +9,9 @@ See-also: socks5 socks4a
|
||||
Use the specified SOCKS5 proxy (and let the proxy resolve the host name). If
|
||||
the port number is not specified, it is assumed at port 1080.
|
||||
|
||||
To specify proxy on a unix domain socket, use localhost for host, e.g.
|
||||
socks5h://localhost/path/to/socket.sock
|
||||
|
||||
This option overrides any previous use of --proxy, as they are mutually
|
||||
exclusive.
|
||||
|
||||
|
||||
@ -9,6 +9,9 @@ See-also: socks5-hostname socks4a
|
||||
Use the specified SOCKS5 proxy - but resolve the host name locally. If the
|
||||
port number is not specified, it is assumed at port 1080.
|
||||
|
||||
To specify proxy on a unix domain socket, use localhost for host, e.g.
|
||||
socks5://localhost/path/to/socket.sock
|
||||
|
||||
This option overrides any previous use of --proxy, as they are mutually
|
||||
exclusive.
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
.\" * | (__| |_| | _ <| |___
|
||||
.\" * \___|\___/|_| \_\_____|
|
||||
.\" *
|
||||
.\" * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
.\" * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
.\" *
|
||||
.\" * This software is licensed as described in the file COPYING, which
|
||||
.\" * you should have received as part of this distribution. The terms
|
||||
@ -73,6 +73,9 @@ use of a proxy, even if there is an environment variable set for it.
|
||||
A proxy host string can also include protocol scheme (http://) and embedded
|
||||
user + password.
|
||||
|
||||
Unix domain sockets are supported for socks proxies since 7.84.0. Set
|
||||
localhost for the host part. e.g. socks5h://localhost/path/to/socket.sock
|
||||
|
||||
The application does not have to keep the string around after setting this
|
||||
option.
|
||||
.SH "Environment variables"
|
||||
|
||||
80
lib/url.c
80
lib/url.c
@ -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
|
||||
|
||||
@ -128,6 +128,7 @@ Available substitute variables include:
|
||||
- `%HTTPTLS6PORT` - IPv6 port number of the HTTP TLS server
|
||||
- `%HTTPTLSPORT` - Port number of the HTTP TLS server
|
||||
- `%HTTPUNIXPATH` - Path to the Unix socket of the HTTP server
|
||||
- `%SOCKSUNIXPATH` - Absolute Path to the Unix socket of the SOCKS server
|
||||
- `%IMAP6PORT` - IPv6 port number of the IMAP server
|
||||
- `%IMAPPORT` - Port number of the IMAP server
|
||||
- `%MQTTPORT` - Port number of the MQTT server
|
||||
|
||||
@ -185,7 +185,7 @@ test1432 test1433 test1434 test1435 test1436 test1437 test1438 test1439 \
|
||||
test1440 test1441 test1442 test1443 test1444 test1445 test1446 test1447 \
|
||||
test1448 test1449 test1450 test1451 test1452 test1453 test1454 test1455 \
|
||||
test1456 test1457 test1458 test1459 test1460 test1461 test1462 test1463 \
|
||||
test1464 test1465 test1466 \
|
||||
test1464 test1465 test1466 test1467 test1468 \
|
||||
\
|
||||
test1500 test1501 test1502 test1503 test1504 test1505 test1506 test1507 \
|
||||
test1508 test1509 test1510 test1511 test1512 test1513 test1514 test1515 \
|
||||
|
||||
59
tests/data/test1467
Normal file
59
tests/data/test1467
Normal file
@ -0,0 +1,59 @@
|
||||
<testcase>
|
||||
<info>
|
||||
<keywords>
|
||||
HTTP
|
||||
HTTP GET
|
||||
SOCKS5
|
||||
</keywords>
|
||||
</info>
|
||||
|
||||
#
|
||||
# Server-side
|
||||
<reply>
|
||||
<data>
|
||||
HTTP/1.1 200 OK
|
||||
Date: Tue, 09 Nov 2010 14:49:00 GMT
|
||||
Server: test-server/fake
|
||||
Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
|
||||
ETag: "21025-dc7-39462498"
|
||||
Accept-Ranges: bytes
|
||||
Content-Length: 6
|
||||
Connection: close
|
||||
Content-Type: text/html
|
||||
Funny-head: yesyes
|
||||
|
||||
-foo-
|
||||
</data>
|
||||
</reply>
|
||||
|
||||
#
|
||||
# Client-side
|
||||
<client>
|
||||
<features>
|
||||
proxy
|
||||
unix-sockets
|
||||
</features>
|
||||
<server>
|
||||
http
|
||||
socks5unix
|
||||
</server>
|
||||
<name>
|
||||
HTTP GET via SOCKS5 proxy via unix sockets
|
||||
</name>
|
||||
<command>
|
||||
--socks5 localhost%SOCKSUNIXPATH http://%HOSTIP:%HTTPPORT/%TESTNUMBER
|
||||
</command>
|
||||
</client>
|
||||
|
||||
#
|
||||
# Verify data after the test has been "shot"
|
||||
<verify>
|
||||
<protocol>
|
||||
GET /%TESTNUMBER HTTP/1.1
|
||||
Host: %HOSTIP:%HTTPPORT
|
||||
User-Agent: curl/%VERSION
|
||||
Accept: */*
|
||||
|
||||
</protocol>
|
||||
</verify>
|
||||
</testcase>
|
||||
63
tests/data/test1468
Normal file
63
tests/data/test1468
Normal file
@ -0,0 +1,63 @@
|
||||
<testcase>
|
||||
<info>
|
||||
<keywords>
|
||||
HTTP
|
||||
HTTP GET
|
||||
SOCKS5
|
||||
SOCKS5h
|
||||
</keywords>
|
||||
</info>
|
||||
|
||||
#
|
||||
# Server-side
|
||||
<reply>
|
||||
<data>
|
||||
HTTP/1.1 200 OK
|
||||
Date: Tue, 09 Nov 2010 14:49:00 GMT
|
||||
Server: test-server/fake
|
||||
Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
|
||||
ETag: "21025-dc7-39462498"
|
||||
Accept-Ranges: bytes
|
||||
Content-Length: 6
|
||||
Connection: close
|
||||
Content-Type: text/html
|
||||
Funny-head: yesyes
|
||||
|
||||
-foo-
|
||||
</data>
|
||||
</reply>
|
||||
|
||||
#
|
||||
# Client-side
|
||||
<client>
|
||||
<features>
|
||||
proxy
|
||||
unix-sockets
|
||||
</features>
|
||||
<server>
|
||||
http
|
||||
socks5unix
|
||||
</server>
|
||||
<name>
|
||||
HTTP GET with host name using SOCKS5h via unix sockets
|
||||
</name>
|
||||
<command>
|
||||
http://this.is.a.host.name:%HTTPPORT/%TESTNUMBER --proxy socks5h://localhost%SOCKSUNIXPATH
|
||||
</command>
|
||||
</client>
|
||||
|
||||
#
|
||||
# Verify data after the test has been "shot"
|
||||
<verify>
|
||||
<protocol>
|
||||
GET /%TESTNUMBER HTTP/1.1
|
||||
Host: this.is.a.host.name:%HTTPPORT
|
||||
User-Agent: curl/%VERSION
|
||||
Accept: */*
|
||||
|
||||
</protocol>
|
||||
<socks>
|
||||
atyp 3 => this.is.a.host.name
|
||||
</socks>
|
||||
</verify>
|
||||
</testcase>
|
||||
@ -162,6 +162,7 @@ my $SMBPORT=$noport; # SMB server port
|
||||
my $SMBSPORT=$noport; # SMBS server port
|
||||
my $TELNETPORT=$noport; # TELNET server port with negotiation
|
||||
my $HTTPUNIXPATH; # HTTP server Unix domain socket path
|
||||
my $SOCKSUNIXPATH; # socks server Unix domain socket path
|
||||
|
||||
my $use_external_proxy = 0;
|
||||
my $proxy_address;
|
||||
@ -1435,6 +1436,7 @@ my %protofunc = ('http' => \&verifyhttp,
|
||||
'tftp' => \&verifyftp,
|
||||
'ssh' => \&verifyssh,
|
||||
'socks' => \&verifysocks,
|
||||
'socks5unix' => \&verifysocks,
|
||||
'gopher' => \&verifyhttp,
|
||||
'httptls' => \&verifyhttptls,
|
||||
'dict' => \&verifyftp,
|
||||
@ -2379,7 +2381,7 @@ sub runmqttserver {
|
||||
# Start the socks server
|
||||
#
|
||||
sub runsocksserver {
|
||||
my ($id, $verbose, $ipv6) = @_;
|
||||
my ($id, $verbose, $ipv6, $is_unix) = @_;
|
||||
my $ip=$HOSTIP;
|
||||
my $proto = 'socks';
|
||||
my $ipvnum = 4;
|
||||
@ -2411,12 +2413,21 @@ sub runsocksserver {
|
||||
$logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum);
|
||||
|
||||
# start our socks server, get commands from the FTP cmd file
|
||||
my $cmd="server/socksd".exe_ext('SRV').
|
||||
" --port 0 ".
|
||||
" --pidfile $pidfile".
|
||||
" --portfile $portfile".
|
||||
" --backend $HOSTIP".
|
||||
" --config $FTPDCMD";
|
||||
my $cmd="";
|
||||
if($is_unix) {
|
||||
$cmd="server/socksd".exe_ext('SRV').
|
||||
" --pidfile $pidfile".
|
||||
" --unix-socket $SOCKSUNIXPATH".
|
||||
" --backend $HOSTIP".
|
||||
" --config $FTPDCMD";
|
||||
} else {
|
||||
$cmd="server/socksd".exe_ext('SRV').
|
||||
" --port 0 ".
|
||||
" --pidfile $pidfile".
|
||||
" --portfile $portfile".
|
||||
" --backend $HOSTIP".
|
||||
" --config $FTPDCMD";
|
||||
}
|
||||
my ($sockspid, $pid2) = startnew($cmd, $pidfile, 30, 0);
|
||||
|
||||
if($sockspid <= 0 || !pidexists($sockspid)) {
|
||||
@ -3337,6 +3348,7 @@ sub checksystem {
|
||||
logmsg "* Unix socket paths:\n";
|
||||
if($http_unix) {
|
||||
logmsg sprintf("* HTTP-Unix:%s\n", $HTTPUNIXPATH);
|
||||
logmsg sprintf("* Socks-Unix:%s\n", $SOCKSUNIXPATH);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3397,6 +3409,7 @@ sub subVariables {
|
||||
|
||||
# server Unix domain socket paths
|
||||
$$thing =~ s/${prefix}HTTPUNIXPATH/$HTTPUNIXPATH/g;
|
||||
$$thing =~ s/${prefix}SOCKSUNIXPATH/$SOCKSUNIXPATH/g;
|
||||
|
||||
# client IP addresses
|
||||
$$thing =~ s/${prefix}CLIENT6IP/$CLIENT6IP/g;
|
||||
@ -5273,6 +5286,16 @@ sub startservers {
|
||||
$run{'socks'}="$pid $pid2";
|
||||
}
|
||||
}
|
||||
elsif($what eq "socks5unix") {
|
||||
if(!$run{'socks5unix'}) {
|
||||
($pid, $pid2) = runsocksserver("2", $verbose, "", "unix");
|
||||
if($pid <= 0) {
|
||||
return "failed starting socks5unix server";
|
||||
}
|
||||
printf ("* pid socks5unix => %d %d\n", $pid, $pid2) if($verbose);
|
||||
$run{'socks5unix'}="$pid $pid2";
|
||||
}
|
||||
}
|
||||
elsif($what eq "mqtt" ) {
|
||||
if(!$run{'mqtt'}) {
|
||||
($pid, $pid2) = runmqttserver("", $verbose);
|
||||
@ -5867,6 +5890,7 @@ if ($gdbthis) {
|
||||
}
|
||||
|
||||
$HTTPUNIXPATH = "http$$.sock"; # HTTP server Unix domain socket path
|
||||
$SOCKSUNIXPATH = $pwd."/socks$$.sock"; # HTTP server Unix domain socket path, absolute path
|
||||
|
||||
#######################################################################
|
||||
# clear and create logging directory:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user