aboutsummaryrefslogtreecommitdiff
path: root/lib/socks.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/socks.c')
-rw-r--r--lib/socks.c110
1 files changed, 85 insertions, 25 deletions
diff --git a/lib/socks.c b/lib/socks.c
index 5146b0dc4..90ec1f215 100644
--- a/lib/socks.c
+++ b/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 */
+
+ 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;
+ }
- code = Curl_write(conn, sock, (char *)socksreq, packetsize, &written);
- if((code != CURLE_OK) || (written != packetsize)) {
- failf(data, "Failed to send SOCKS5 connect request.");
+ 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);