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.
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.
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.
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.
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.
.\" * | (__| |_| | _ <| |___
.\" * \___|\___/|_| \_\_____|
.\" *
-.\" * 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
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"
# error READBUFFER_SIZE is too small
#endif
+#ifdef USE_UNIX_SOCKETS
+#define UNIX_SOCKET_PREFIX "localhost"
+#endif
+
/*
* get_protocol_family()
*
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;
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;
+ }
+ }
+
+ 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
}
- proxyinfo->host.name = host;
+#endif
error:
free(proxyuser);
free(proxypasswd);
+ free(host);
free(scheme);
+#ifdef USE_UNIX_SOCKETS
+ free(path);
+#endif
curl_url_cleanup(uhp);
return result;
}
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
- `%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
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 \
--- /dev/null
+<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\r
+Host: %HOSTIP:%HTTPPORT\r
+User-Agent: curl/%VERSION\r
+Accept: */*\r
+\r
+</protocol>
+</verify>
+</testcase>
--- /dev/null
+<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\r
+Host: this.is.a.host.name:%HTTPPORT\r
+User-Agent: curl/%VERSION\r
+Accept: */*\r
+\r
+</protocol>
+<socks>
+atyp 3 => this.is.a.host.name
+</socks>
+</verify>
+</testcase>
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;
'tftp' => \&verifyftp,
'ssh' => \&verifyssh,
'socks' => \&verifysocks,
+ 'socks5unix' => \&verifysocks,
'gopher' => \&verifyhttp,
'httptls' => \&verifyhttptls,
'dict' => \&verifyftp,
# 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;
$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)) {
logmsg "* Unix socket paths:\n";
if($http_unix) {
logmsg sprintf("* HTTP-Unix:%s\n", $HTTPUNIXPATH);
+ logmsg sprintf("* Socks-Unix:%s\n", $SOCKSUNIXPATH);
}
}
}
# 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;
$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);
}
$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: