Based on Maxim Perenesenko's patch, we now do SOCKS5 operations and let the

proxy do the host name resolving and only if --socks5ip (or
CURLOPT_SOCKS5_RESOLVE_LOCAL) is used we resolve the host name locally and
pass on the IP address only to the proxy.
This commit is contained in:
Daniel Stenberg 2008-01-04 23:01:00 +00:00
parent fcc485092a
commit 2e42b0a252
9 changed files with 158 additions and 40 deletions

View File

@ -6,6 +6,12 @@
Changelog
Daniel S (4 Jan 2008)
- Based on Maxim Perenesenko's patch, we now do SOCKS5 operations and let the
proxy do the host name resolving and only if --socks5ip (or
CURLOPT_SOCKS5_RESOLVE_LOCAL) is used we resolve the host name locally and
pass on the IP address only to the proxy.
Yang Tse (3 Jan 2008)
- Modified test harness to allow SCP, SFTP and SOCKS4 tests to run with
OpenSSH 2.9.9, SunSSH 1.0 or later versions. SOCKS5 tests need OpenSSH

View File

@ -1,8 +1,8 @@
Curl and libcurl 7.17.2
Public curl releases: 103
Command line options: 124
curl_easy_setopt() options: 148
Command line options: 125
curl_easy_setopt() options: 149
Public functions in libcurl: 55
Public web site mirrors: 42
Known libcurl bindings: 36
@ -14,6 +14,7 @@ This release includes the following changes:
o CURLOPT_PROXY_TRANSFER_MODE was added
o --no-keep-alive was added
o --socks4a added (proxy type CURLPROXY_SOCKS4A for libcurl)
o --socks5ip added (CURLOPT_SOCKS5_RESOLVE_LOCAL for libcurl)
This release includes the following bugfixes:
@ -42,6 +43,7 @@ This release includes the following bugfixes:
o bad connection re-use check with environment variable-activated proxy use
o --libcurl now generates a return statement as well
o socklen_t is no longer used in the public includes
o SOCKS5 uses now let the proxy resolve the host names by default
This release includes the following known bugs:
@ -63,6 +65,6 @@ advice from friends like these:
Robin Johnson, Michal Marek, Ates Goral, Andres Garcia, Rob Crittenden,
Emil Romanus, Alessandro Vesely, Ray Pekowski, Spacen Jasset, Andrew Moise,
Gilles Blanc, David Wright, Vikram Saxena, Mateusz Loskot, Gary Maxwell,
Dmitry Kurochkin, Mohun Biswas, Richard Atterer
Dmitry Kurochkin, Mohun Biswas, Richard Atterer, Maxim Perenesenko
Thanks! (and sorry if I forgot to mention someone)

View File

@ -1084,8 +1084,19 @@ mutually exclusive.
If this option is used several times, the last one will be used.
.IP "--socks5 <host[:port]>"
Use the specified SOCKS5 proxy. If the port number is not specified, it is
assumed at port 1080. (Added in 7.11.1)
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. (Added in
7.11.1)
This option overrides any previous use of \fI-x/--proxy\fP, as they are
mutually exclusive.
If this option is used several times, the last one will be used. (This option
was previously wrongly documented and used as --socks without the number
appended.)
.IP "--socks5ip <host[:port]>"
Use the specified SOCKS5 proxy - but resolve the host name locally. If the
port number is not specified, it is assumed at port 1080. (Added in 7.17.2)
This option overrides any previous use of \fI-x/--proxy\fP, as they are
mutually exclusive.

View File

@ -21,7 +21,7 @@
.\" * $Id$
.\" **************************************************************************
.\"
.TH curl_easy_setopt 3 "30 Aug 2007" "libcurl 7.17.0" "libcurl Manual"
.TH curl_easy_setopt 3 "4 Jan 2008" "libcurl 7.17.2" "libcurl Manual"
.SH NAME
curl_easy_setopt \- set options for a curl easy handle
.SH SYNOPSIS
@ -433,11 +433,19 @@ Pass a long with this option to set type of the proxy. Available options for
this are \fICURLPROXY_HTTP\fP, \fICURLPROXY_SOCKS4\fP (added in 7.15.2),
\fICURLPROXY_SOCKS5\fP and \fICURLPROXY_SOCKS4A\fP (added in 7.17.2). The HTTP
type is default. (Added in 7.10)
See also \fIURLOPT_SOCKS5_RESOLVE_LOCAL\fP.
.IP CURLOPT_HTTPPROXYTUNNEL
Set the parameter to non-zero to get the library to tunnel all operations
through a given HTTP proxy. There is a big difference between using a proxy
and to tunnel through it. If you don't know what this means, you probably
don't want this tunneling option.
.IP CURLOPT_SOCKS5_RESOLVE_LOCAL
Set the parameter to 1 to get the library to resolve the host name locally
instead of passing it to the proxy to resolve, when using a SOCKS5 proxy.
Note that libcurl before 7.17.2 always resolved the host name locally even
when SOCKS5 was used. (Added in 7.17.2)
.IP CURLOPT_INTERFACE
Pass a char * as parameter. This set the interface name to use as outgoing
network interface. The name can be an interface name, an IP address or a host

View File

@ -1172,6 +1172,11 @@ typedef enum {
/* set transfer mode (;type=<a|i>) when doing FTP via an HTTP proxy */
CINIT(PROXY_TRANSFER_MODE, LONG, 166),
/* Set using of SOCKS5 to resolve host names locally instead of sending them
to the proxy to let it resolve them. Valid only if CURLOPT_PROXYTYPE ==
CURLPROXY_SOCKS5, otherwise ignored. */
CINIT(SOCKS5_RESOLVE_LOCAL, LONG, 167),
CURLOPT_LASTENTRY /* the last unused */
} CURLoption;

View File

@ -390,6 +390,17 @@ CURLcode Curl_SOCKS5(const char *proxy_name,
curl_socket_t sock = conn->sock[sockindex];
struct SessionHandle *data = conn->data;
long timeout;
bool socks5_resolve_local = data->set.socks5_resolve_local;
const size_t hostname_len = strlen(hostname);
int packetsize = 0;
/* RFC1928 chapter 5 specifies max 255 chars for domain name in packet */
if(!socks5_resolve_local && hostname_len > 255)
{
infof(conn->data,"SOCKS5: server resolving disabled for hostnames of "
"length > 255 [actual len=%d]\n", hostname_len);
socks5_resolve_local = TRUE;
}
/* get timeout */
if(data->set.timeout && data->set.connecttimeout) {
@ -553,13 +564,26 @@ CURLcode Curl_SOCKS5(const char *proxy_name,
socksreq[0] = 5; /* version (SOCKS5) */
socksreq[1] = 1; /* connect */
socksreq[2] = 0; /* must be zero */
socksreq[3] = 1; /* IPv4 = 1 */
{
if(!socks5_resolve_local) {
packetsize = 5 + hostname_len + 2;
socksreq[3] = 3; /* ATYP: domain name = 3 */
socksreq[4] = (char) hostname_len; /* address length */
memcpy(&socksreq[5], hostname, hostname_len); /* address bytes w/o NULL */
*((unsigned short*)&socksreq[hostname_len+5]) =
htons((unsigned short)remote_port);
}
else {
struct Curl_dns_entry *dns;
Curl_addrinfo *hp=NULL;
int rc = Curl_resolv(conn, hostname, remote_port, &dns);
packetsize = 10;
socksreq[3] = 1; /* IPv4 = 1 */
if(rc == CURLRESOLV_ERROR)
return CURLE_COULDNT_RESOLVE_HOST;
@ -595,40 +619,76 @@ CURLcode Curl_SOCKS5(const char *proxy_name,
hostname);
return CURLE_COULDNT_RESOLVE_HOST;
}
*((unsigned short*)&socksreq[8]) = htons((unsigned short)remote_port);
}
*((unsigned short*)&socksreq[8]) = htons((unsigned short)remote_port);
code = Curl_write(conn, sock, (char *)socksreq, packetsize, &written);
if((code != CURLE_OK) || (written != packetsize)) {
failf(data, "Failed to send SOCKS5 connect request.");
return CURLE_COULDNT_CONNECT;
}
{
const int packetsize = 10;
packetsize = 10; /* minimum packet size is 10 */
code = Curl_write(conn, sock, (char *)socksreq, packetsize, &written);
if((code != CURLE_OK) || (written != packetsize)) {
failf(data, "Failed to send SOCKS5 connect request.");
result = blockread_all(conn, sock, (char *)socksreq, packetsize,
&actualread, timeout);
if((result != CURLE_OK) || (actualread != packetsize)) {
failf(data, "Failed to receive SOCKS5 connect request ack.");
return CURLE_COULDNT_CONNECT;
}
if(socksreq[0] != 5) { /* version */
failf(data,
"SOCKS5 reply has wrong version, version should be 5.");
return CURLE_COULDNT_CONNECT;
}
if(socksreq[1] != 0) { /* Anything besides 0 is an error */
failf(data,
"Can't complete SOCKS5 connection to %d.%d.%d.%d:%d. (%d)",
(unsigned char)socksreq[4], (unsigned char)socksreq[5],
(unsigned char)socksreq[6], (unsigned char)socksreq[7],
(unsigned int)ntohs(*(unsigned short*)(&socksreq[8])),
socksreq[1]);
return CURLE_COULDNT_CONNECT;
}
}
result = blockread_all(conn, sock, (char *)socksreq, packetsize,
/* Fix: in general, returned BND.ADDR is variable length parameter by RFC
1928, so the reply packet should be read until the end to avoid errors at
subsequent protocol level.
+----+-----+-------+------+----------+----------+
|VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
+----+-----+-------+------+----------+----------+
| 1 | 1 | X'00' | 1 | Variable | 2 |
+----+-----+-------+------+----------+----------+
ATYP:
o IP v4 address: X'01', BND.ADDR = 4 byte
o domain name: X'03', BND.ADDR = [ 1 byte length, string ]
o IP v6 address: X'04', BND.ADDR = 16 byte
*/
/* Calculate real packet size */
if(socksreq[3] == 3) {
/* domain name */
int addrlen = (int) socksreq[4];
packetsize = 5 + addrlen + 2;
}
else if(socksreq[3] == 4) {
/* IPv6 */
packetsize = 4 + 16 + 2;
}
/* At this point we already read first 10 bytes */
if(packetsize > 10) {
packetsize -= 10;
result = blockread_all(conn, sock, (char *)&socksreq[10], packetsize,
&actualread, timeout);
if((result != CURLE_OK) || (actualread != packetsize)) {
failf(data, "Failed to receive SOCKS5 connect request ack.");
return CURLE_COULDNT_CONNECT;
}
if(socksreq[0] != 5) { /* version */
failf(data,
"SOCKS5 reply has wrong version, version should be 5.");
return CURLE_COULDNT_CONNECT;
}
if(socksreq[1] != 0) { /* Anything besides 0 is an error */
failf(data,
"Can't complete SOCKS5 connection to %d.%d.%d.%d:%d. (%d)",
(unsigned char)socksreq[4], (unsigned char)socksreq[5],
(unsigned char)socksreq[6], (unsigned char)socksreq[7],
(unsigned int)ntohs(*(unsigned short*)(&socksreq[8])),
socksreq[1]);
return CURLE_COULDNT_CONNECT;
}
}
Curl_nonblock(sock, TRUE);

View File

@ -2054,6 +2054,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
}
break;
case CURLOPT_SOCKS5_RESOLVE_LOCAL:
/*
* Enable or disable using of SOCKS5 proxy server to resolve domain names
* instead of using platform API like gethostbyname_r etc
*/
data->set.socks5_resolve_local = (bool)(0 != va_arg(param, long));
break;
default:
/* unknown tag and its companion, just ignore: */
result = CURLE_FAILED_INIT; /* correct this */

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2008, 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
@ -1441,7 +1441,9 @@ struct UserDefined {
long new_directory_perms; /* Permissions to use when creating remote dirs */
bool proxy_transfer_mode; /* set transfer mode (;type=<a|i>) when doing FTP
via an HTTP proxy */
bool socks5_resolve_local; /* resolve host names locally even if a SOCKS5
proxy in use. Valid only if CURLOPT_PROXYTYPE
== CURLPROXY_SOCKS5, otherwise ignored. */
char *str[STRING_LAST]; /* array of strings, pointing to allocated memory */
};

View File

@ -480,6 +480,8 @@ struct Configurable {
bool raw;
bool post301;
bool nokeepalive;
bool socks5_resolve_local; /* don't use SOCKS5 proxy server to resolve
domain names */
struct OutStruct *outs;
};
@ -713,7 +715,8 @@ static void help(void)
" -S/--show-error Show error. With -s, make curl show errors when they occur",
" --socks4 <host[:port]> Use SOCKS4 proxy on given host + port",
" --socks4a <host[:port]> Use SOCKS4a proxy on given host + port",
" --socks5 <host[:port]> Use SOCKS5 proxy on given host + port",
" --socks5 <host[:port]> Use SOCKS5 proxy and let the proxy resolve names",
" --socks5ip <host[:port]> Use SOCKS5 proxy on given host + port",
" --stderr <file> Where to redirect stderr. - means stdout",
" -t/--telnet-option <OPT=val> Set telnet option",
" --trace <file> Write a debug trace to the given file",
@ -1514,10 +1517,10 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
{"*z", "disable-eprt", FALSE},
{"$a", "ftp-ssl", FALSE},
{"$b", "ftp-pasv", FALSE},
{"$c", "socks5", TRUE},
{"$c", "socks", TRUE}, /* this is how the option was documented but
we prefer the --socks5 version for explicit
version */
{"$c", "socks5ip", TRUE},
{"$c", "socks", TRUE}, /* this is how the option once was documented
but we prefer the --socks5 version for
explicit version */
{"$d", "tcp-nodelay",FALSE},
{"$e", "proxy-digest", FALSE},
{"$f", "proxy-basic", FALSE},
@ -1544,6 +1547,7 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
{"$#", "raw", FALSE},
{"$0", "post301", FALSE},
{"$1", "no-keep-alive", FALSE},
{"$2", "socks5", TRUE},
{"0", "http1.0", FALSE},
{"1", "tlsv1", FALSE},
@ -1900,9 +1904,11 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
free(config->ftpport);
config->ftpport = NULL;
break;
case 'c': /* --socks5 specifies a socks5 proxy to use */
case 'c': /* --socks5ip specifies a socks5 proxy to use, but resolves
the name locally and passes on the resolved address */
GetStr(&config->socksproxy, nextarg);
config->socksver = CURLPROXY_SOCKS5;
config->socks5_resolve_local = TRUE;
break;
case 't': /* --socks4 specifies a socks4 proxy to use */
GetStr(&config->socksproxy, nextarg);
@ -1912,6 +1918,12 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
GetStr(&config->socksproxy, nextarg);
config->socksver = CURLPROXY_SOCKS4A;
break;
case '2': /* --socks5 specifies a socks5 proxy and enables name resolving
with the proxy */
GetStr(&config->socksproxy, nextarg);
config->socksver = CURLPROXY_SOCKS5;
config->socks5_resolve_local = FALSE;
break;
case 'd': /* --tcp-nodelay option */
config->tcp_nodelay ^= TRUE;
break;
@ -4340,7 +4352,7 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
my_setopt(curl, CURLOPT_SSH_PUBLIC_KEYFILE, config->pubkey);
/* SSH host key md5 checking allows us to fail if we are
* not talking to who we think we should
* not talking to who we think we should
*/
my_setopt(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5, config->hostpubmd5);
@ -4497,6 +4509,10 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
if(config->socksproxy) {
my_setopt(curl, CURLOPT_PROXY, config->socksproxy);
my_setopt(curl, CURLOPT_PROXYTYPE, config->socksver);
if(config->socksver==CURLPROXY_SOCKS5)
/* added in 7.17.2 */
my_setopt(curl, CURLOPT_SOCKS5_RESOLVE_LOCAL,
config->socks5_resolve_local);
}
/* curl 7.13.0 */