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:
110
lib/socks.c
110
lib/socks.c
@@ -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);
|
||||
|
Reference in New Issue
Block a user