From a15d107dde68f6173cfb1a590320cb108d4dd0f5 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 21 Feb 2006 07:46:41 +0000 Subject: Peter Su added support for SOCKS4 proxies. Enable this by setting the proxy type to the already provided type CURLPROXY_SOCKS4. I added a --socks4 option that works like the current --socks5 option but instead use the socks4 protocol. --- lib/url.c | 197 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 192 insertions(+), 5 deletions(-) (limited to 'lib/url.c') diff --git a/lib/url.c b/lib/url.c index fe0dc3c25..c7aad213a 100644 --- a/lib/url.c +++ b/lib/url.c @@ -1809,6 +1809,191 @@ ConnectionStore(struct SessionHandle *data, return i; } +/* +* This function logs in to a SOCKS4 proxy and sends the specifies the final +* desitination server. +* +* Reference : +* http://socks.permeo.com/protocol/socks4.protocol +* +* Note : +* Nonsupport "SOCKS 4A (Simple Extension to SOCKS 4 Protocol)" +* Nonsupport "Identification Protocol (RFC1413)" +*/ +static int handleSock4Proxy(struct connectdata *conn) +{ + unsigned char socksreq[600]; /* room for large user/pw (255 max each) */ + int result; + CURLcode code; + curl_socket_t sock = conn->sock[FIRSTSOCKET]; + struct SessionHandle *data = conn->data; + + Curl_nonblock(sock, FALSE); + + /* + * Compose socks4 request + * + * Request format + * + * +----+----+----+----+----+----+----+----+----+----+....+----+ + * | VN | CD | DSTPORT | DSTIP | USERID |NULL| + * +----+----+----+----+----+----+----+----+----+----+....+----+ + * # of bytes: 1 1 2 4 variable 1 + */ + + socksreq[0] = 4; /* version (SOCKS4) */ + socksreq[1] = 1; /* connect */ + *((unsigned short*)&socksreq[2]) = htons(conn->remote_port); + + /* DNS resolve */ + { + struct Curl_dns_entry *dns; + Curl_addrinfo *hp=NULL; + int rc; + + rc = Curl_resolv(conn, conn->host.name, (int)conn->remote_port, &dns); + + if(rc == CURLRESOLV_ERROR) + return 1; + + if(rc == CURLRESOLV_PENDING) + /* this requires that we're in "wait for resolve" state */ + rc = Curl_wait_for_resolv(conn, &dns); + + /* + * We cannot use 'hostent' as a struct that Curl_resolv() returns. It + * returns a Curl_addrinfo pointer that may not always look the same. + */ + if(dns) + hp=dns->addr; + if (hp) { + char buf[64]; + unsigned short ip[4]; + Curl_printable_address(hp, buf, sizeof(buf)); + + if(4 == sscanf( buf, "%hu.%hu.%hu.%hu", + &ip[0], &ip[1], &ip[2], &ip[3])) { + /* Set DSTIP */ + socksreq[4] = (unsigned char)ip[0]; + socksreq[5] = (unsigned char)ip[1]; + socksreq[6] = (unsigned char)ip[2]; + socksreq[7] = (unsigned char)ip[3]; + } + else + hp = NULL; /* fail! */ + + Curl_resolv_unlock(conn->data, dns); /* not used anymore from now on */ + + } + if(!hp) { + failf(conn->data, "Failed to resolve \"%s\" for SOCKS4 connect.\n", + conn->host.name); + return 1; + } + } + + /* + * Make connection + */ + { + ssize_t actualread; + ssize_t written; + int packetsize = 9; /* request data size (include NULL) */ + + /* Send request */ + code = Curl_write(conn, sock, (char *)socksreq, packetsize, &written); + if ((code != CURLE_OK) || (written != packetsize)) { + failf(conn->data, "Failed to send SOCKS4 connect request.\n"); + return 1; + } + + packetsize = 8; /* receive data size */ + + /* Receive response */ + result = Curl_read(conn, sock, (char *)socksreq, packetsize, &actualread); + if ((result != CURLE_OK) || (actualread != packetsize)) { + failf(conn->data, "Failed to receive SOCKS4 connect request ack.\n"); + return 1; + } + + /* + * Response format + * + * +----+----+----+----+----+----+----+----+ + * | VN | CD | DSTPORT | DSTIP | + * +----+----+----+----+----+----+----+----+ + * # of bytes: 1 1 2 4 + * + * VN is the version of the reply code and should be 0. CD is the result + * code with one of the following values: + * + * 90: request granted + * 91: request rejected or failed + * 92: request rejected becasue SOCKS server cannot connect to + * identd on the client + * 93: request rejected because the client program and identd + * report different user-ids + */ + + /* wrong version ? */ + if (socksreq[0] != 0) { + failf(conn->data, + "SOCKS4 reply has wrong version, version should be 4.\n"); + return 1; + } + + /* Result */ + switch(socksreq[1]) + { + case 90: + infof(data, "SOCKS4 request granted.\n"); + break; + case 91: + failf(conn->data, + "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" + ", request rejected or failed.\n", + (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 1; + case 92: + failf(conn->data, + "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" + ", request rejected becasue SOCKS server cannot connect to " + "identd on the client.\n", + (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 1; + case 93: + failf(conn->data, + "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" + ", request rejected because the client program and identd " + "report different user-ids.\n", + (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 1; + default : + failf(conn->data, + "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" + ", Unknown.\n", + (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 1; + } + } + + Curl_nonblock(sock, TRUE); + + return 0; /* Proxy was successful! */ +} + /* * This function logs in to a SOCKS5 proxy and sends the specifies the final * desitination server. @@ -2052,16 +2237,18 @@ static CURLcode ConnectPlease(struct connectdata *conn, Curl_store_ip_addr(conn); - if (conn->data->set.proxytype == CURLPROXY_SOCKS5) { + switch(conn->data->set.proxytype) { + case CURLPROXY_SOCKS5: return handleSock5Proxy(conn->proxyuser, conn->proxypasswd, conn) ? CURLE_COULDNT_CONNECT : CURLE_OK; - } - else if (conn->data->set.proxytype == CURLPROXY_HTTP) { + case CURLPROXY_HTTP: /* do nothing here. handled later. */ - } - else { + break; + case CURLPROXY_SOCKS4: + return handleSock4Proxy(conn) ? CURLE_COULDNT_CONNECT : CURLE_OK; + default: failf(conn->data, "unknown proxytype option given"); return CURLE_COULDNT_CONNECT; } -- cgit v1.2.3